Date: Mon, 12 Jul 2021 19:33:31 GMT From: Warner Losh <imp@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Subject: git: d765d5c2c309 - stable/13 - config_intrhook: provide config_intrhook_drain Message-ID: <202107121933.16CJXVKw016935@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by imp: URL: https://cgit.FreeBSD.org/src/commit/?id=d765d5c2c30971f109723ea4af6245e8dd201d3a commit d765d5c2c30971f109723ea4af6245e8dd201d3a Author: Warner Losh <imp@FreeBSD.org> AuthorDate: 2021-03-11 15:42:09 +0000 Commit: Warner Losh <imp@FreeBSD.org> CommitDate: 2021-07-12 19:30:55 +0000 config_intrhook: provide config_intrhook_drain config_intrhook_drain will remove the hook from the list as config_intrhook_disestablish does if the hook hasn't been called. If it has, config_intrhook_drain will wait for the hook to be disestablished in the normal course (or expedited, it's up to the driver to decide how and when to call config_intrhook_disestablish). This is intended for removable devices that use config_intrhook and might be attached early in boot, but that may be removed before the kernel can call the config_intrhook or before it ends. To prevent all races, the detach routine will need to call config_intrhook_train. Sponsored by: Netflix, Inc Reviewed by: jhb, mav, gde (in D29006 for man page) Differential Revision: https://reviews.freebsd.org/D29005 (cherry picked from commit e52368365db3c0a696b37bfc09d08b7093b41b57) --- share/man/man9/Makefile | 1 + share/man/man9/config_intrhook.9 | 21 ++++++++++++++++- sys/kern/subr_autoconf.c | 50 +++++++++++++++++++++++++++++++++++++--- sys/sys/kernel.h | 5 ++++ 4 files changed, 73 insertions(+), 4 deletions(-) diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile index 0b025df78061..8bf3b7c22f74 100644 --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -859,6 +859,7 @@ MLINKS+=condvar.9 cv_broadcast.9 \ condvar.9 cv_wait_unlock.9 \ condvar.9 cv_wmesg.9 MLINKS+=config_intrhook.9 config_intrhook_disestablish.9 \ + config_intrhook.9 config_intrhook_drain.9 \ config_intrhook.9 config_intrhook_establish.9 \ config_intrhook.9 config_intrhook_oneshot.9 MLINKS+=contigmalloc.9 contigmalloc_domainset.9 \ diff --git a/share/man/man9/config_intrhook.9 b/share/man/man9/config_intrhook.9 index 0414ad88218a..6892a089b00f 100644 --- a/share/man/man9/config_intrhook.9 +++ b/share/man/man9/config_intrhook.9 @@ -26,7 +26,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 10, 2017 +.Dd March 8, 2021 .Dt CONFIG_INTRHOOK 9 .Os .Sh NAME @@ -40,6 +40,8 @@ but before root is mounted .Fn config_intrhook_establish "struct intr_config_hook *hook" .Ft void .Fn config_intrhook_disestablish "struct intr_config_hook *hook" +.Ft int +.Fn config_intrhook_drain "struct intr_config_hook *hook" .Ft void .Fn config_intrhook_oneshot "ich_func_t func" "void *arg" .Sh DESCRIPTION @@ -55,6 +57,23 @@ The function removes the entry from the hook queue. .Pp The +.Fn config_intrhook_drain +function removes the entry from the hook queue in a safe way. +If the hook is not currently active it removes +.Fa hook +from the hook queue and returns +.Vt ICHS_QUEUED . +If the hook is active, it waits for the hook to complete before returning +.Vt ICHS_RUNNING . +If the hook has previously completed, it returns +.Vt ICHS_DONE . +Because a +.Vt config_intrhook +is undefined prior to +.Fn config_intrhook_establish , +this function may only be called after that function has returned. +.Pp +The .Fn config_intrhook_oneshot function schedules a function to be run as described for .Fn config_intrhook_establish ; diff --git a/sys/kern/subr_autoconf.c b/sys/kern/subr_autoconf.c index 6a998a533801..77c48485e1da 100644 --- a/sys/kern/subr_autoconf.c +++ b/sys/kern/subr_autoconf.c @@ -138,6 +138,7 @@ run_interrupt_driven_config_hooks() while (next_to_notify != NULL) { hook_entry = next_to_notify; next_to_notify = TAILQ_NEXT(hook_entry, ich_links); + hook_entry->ich_state = ICHS_RUNNING; mtx_unlock(&intr_config_hook_lock); (*hook_entry->ich_func)(hook_entry->ich_arg); mtx_lock(&intr_config_hook_lock); @@ -199,6 +200,7 @@ config_intrhook_establish(struct intr_config_hook *hook) TAILQ_INSERT_TAIL(&intr_config_hook_list, hook, ich_links); if (next_to_notify == NULL) next_to_notify = hook; + hook->ich_state = ICHS_QUEUED; mtx_unlock(&intr_config_hook_lock); if (cold == 0) /* @@ -226,12 +228,11 @@ config_intrhook_oneshot(ich_func_t func, void *arg) config_intrhook_establish(&ohook->och_hook); } -void -config_intrhook_disestablish(struct intr_config_hook *hook) +static void +config_intrhook_disestablish_locked(struct intr_config_hook *hook) { struct intr_config_hook *hook_entry; - mtx_lock(&intr_config_hook_lock); TAILQ_FOREACH(hook_entry, &intr_config_hook_list, ich_links) if (hook_entry == hook) break; @@ -245,8 +246,51 @@ config_intrhook_disestablish(struct intr_config_hook *hook) TSRELEASE("config hooks"); /* Wakeup anyone watching the list */ + hook->ich_state = ICHS_DONE; wakeup(&intr_config_hook_list); +} + +void +config_intrhook_disestablish(struct intr_config_hook *hook) +{ + mtx_lock(&intr_config_hook_lock); + config_intrhook_disestablish_locked(hook); + mtx_unlock(&intr_config_hook_lock); +} + +int +config_intrhook_drain(struct intr_config_hook *hook) +{ + mtx_lock(&intr_config_hook_lock); + + /* + * The config hook has completed, so just return. + */ + if (hook->ich_state == ICHS_DONE) { + mtx_unlock(&intr_config_hook_lock); + return (ICHS_DONE); + } + + /* + * The config hook hasn't started running, just call disestablish. + */ + if (hook->ich_state == ICHS_QUEUED) { + config_intrhook_disestablish_locked(hook); + mtx_unlock(&intr_config_hook_lock); + return (ICHS_QUEUED); + } + + /* + * The config hook is running, so wait for it to complete and return. + */ + while (hook->ich_state != ICHS_DONE) { + if (msleep(&intr_config_hook_list, &intr_config_hook_lock, + 0, "confhd", hz) == EWOULDBLOCK) { + // XXX do I whine? + } + } mtx_unlock(&intr_config_hook_lock); + return (ICHS_RUNNING); } #ifdef DDB diff --git a/sys/sys/kernel.h b/sys/sys/kernel.h index 181036c98a6a..3e48a57e0f83 100644 --- a/sys/sys/kernel.h +++ b/sys/sys/kernel.h @@ -467,12 +467,17 @@ typedef void (*ich_func_t)(void *_arg); struct intr_config_hook { TAILQ_ENTRY(intr_config_hook) ich_links; + uintptr_t ich_state; +#define ICHS_QUEUED 0x1 +#define ICHS_RUNNING 0x2 +#define ICHS_DONE 0x3 ich_func_t ich_func; void *ich_arg; }; int config_intrhook_establish(struct intr_config_hook *hook); void config_intrhook_disestablish(struct intr_config_hook *hook); +int config_intrhook_drain(struct intr_config_hook *hook); void config_intrhook_oneshot(ich_func_t _func, void *_arg); #endif /* !_SYS_KERNEL_H_*/
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202107121933.16CJXVKw016935>