diff options
author | lstewart <lstewart@FreeBSD.org> | 2010-03-31 03:58:57 +0000 |
---|---|---|
committer | lstewart <lstewart@FreeBSD.org> | 2010-03-31 03:58:57 +0000 |
commit | a8e85cee7aa26a304807b703744149be09d26f47 (patch) | |
tree | a5d93631a6f5cf7d245cfcbcf5d430981db1230a /sys/kern | |
parent | f0058daed26efcfe07be7a2ef7c9253d0b0d2d77 (diff) | |
download | FreeBSD-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')
-rw-r--r-- | sys/kern/kern_alq.c | 84 |
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); |