summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_alq.c
diff options
context:
space:
mode:
authorlstewart <lstewart@FreeBSD.org>2010-03-31 03:58:57 +0000
committerlstewart <lstewart@FreeBSD.org>2010-03-31 03:58:57 +0000
commita8e85cee7aa26a304807b703744149be09d26f47 (patch)
treea5d93631a6f5cf7d245cfcbcf5d430981db1230a /sys/kern/kern_alq.c
parentf0058daed26efcfe07be7a2ef7c9253d0b0d2d77 (diff)
downloadFreeBSD-src-a8e85cee7aa26a304807b703744149be09d26f47.zip
FreeBSD-src-a8e85cee7aa26a304807b703744149be09d26f47.tar.gz
Add support for ALQ(9) to be compiled and loaded as a kernel module.
Sponsored by: FreeBSD Foundation Reviewed by: dwmalone, jeff, rpaulo, rwatson Approved by: kmacy (mentor) MFC after: 1 month
Diffstat (limited to 'sys/kern/kern_alq.c')
-rw-r--r--sys/kern/kern_alq.c84
1 files changed, 83 insertions, 1 deletions
diff --git a/sys/kern/kern_alq.c b/sys/kern/kern_alq.c
index a4ece79..20d4fee 100644
--- a/sys/kern/kern_alq.c
+++ b/sys/kern/kern_alq.c
@@ -1,7 +1,13 @@
/*-
* Copyright (c) 2002, Jeffrey Roberson <jeff@freebsd.org>
+ * Copyright (c) 2008-2009, Lawrence Stewart <lstewart@freebsd.org>
+ * Copyright (c) 2009-2010, The FreeBSD Foundation
* All rights reserved.
*
+ * Portions of this software were developed at the Centre for Advanced
+ * Internet Architectures, Swinburne University of Technology, Melbourne,
+ * Australia by Lawrence Stewart under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -27,6 +33,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_mac.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
@@ -180,9 +188,16 @@ ald_daemon(void)
ALD_LOCK();
for (;;) {
- while ((alq = LIST_FIRST(&ald_active)) == NULL)
+ while ((alq = LIST_FIRST(&ald_active)) == NULL &&
+ !ald_shutingdown)
msleep(&ald_active, &ald_mtx, PWAIT, "aldslp", 0);
+ /* Don't shutdown until all active ALQs are flushed. */
+ if (ald_shutingdown && alq == NULL) {
+ ALD_UNLOCK();
+ break;
+ }
+
ALQ_LOCK(alq);
ald_deactivate(alq);
ALD_UNLOCK();
@@ -192,6 +207,8 @@ ald_daemon(void)
wakeup(alq);
ALD_LOCK();
}
+
+ kproc_exit(0);
}
static void
@@ -200,14 +217,29 @@ ald_shutdown(void *arg, int howto)
struct alq *alq;
ALD_LOCK();
+
+ /* Ensure no new queues can be created. */
ald_shutingdown = 1;
+ /* Shutdown all ALQs prior to terminating the ald_daemon. */
while ((alq = LIST_FIRST(&ald_queues)) != NULL) {
LIST_REMOVE(alq, aq_link);
ALD_UNLOCK();
alq_shutdown(alq);
ALD_LOCK();
}
+
+ /* At this point, all ALQs are flushed and shutdown. */
+
+ /*
+ * Wake ald_daemon so that it exits. It won't be able to do
+ * anything until we msleep because we hold the ald_mtx.
+ */
+ wakeup(&ald_active);
+
+ /* Wait for ald_daemon to exit. */
+ msleep(ald_proc, &ald_mtx, PWAIT, "aldslp", 0);
+
ALD_UNLOCK();
}
@@ -510,3 +542,53 @@ alq_close(struct alq *alq)
free(alq->aq_entbuf, M_ALD);
free(alq, M_ALD);
}
+
+static int
+alq_load_handler(module_t mod, int what, void *arg)
+{
+ int ret;
+
+ ret = 0;
+
+ switch (what) {
+ case MOD_LOAD:
+ case MOD_SHUTDOWN:
+ break;
+
+ case MOD_QUIESCE:
+ ALD_LOCK();
+ /* Only allow unload if there are no open queues. */
+ if (LIST_FIRST(&ald_queues) == NULL) {
+ ald_shutingdown = 1;
+ ALD_UNLOCK();
+ ald_shutdown(NULL, 0);
+ mtx_destroy(&ald_mtx);
+ } else {
+ ALD_UNLOCK();
+ ret = EBUSY;
+ }
+ break;
+
+ case MOD_UNLOAD:
+ /* If MOD_QUIESCE failed we must fail here too. */
+ if (ald_shutingdown == 0)
+ ret = EBUSY;
+ break;
+
+ default:
+ ret = EINVAL;
+ break;
+ }
+
+ return (ret);
+}
+
+static moduledata_t alq_mod =
+{
+ "alq",
+ alq_load_handler,
+ NULL
+};
+
+DECLARE_MODULE(alq, alq_mod, SI_SUB_SMP, SI_ORDER_ANY);
+MODULE_VERSION(alq, 1);
OpenPOWER on IntegriCloud