Module Name: src Committed By: riastradh Date: Mon Mar 28 12:38:15 UTC 2022
Modified Files: src/sys/kern: subr_autoconf.c src/sys/sys: device.h Log Message: autoconf(9): New function config_detach_commit. When a driver's .ca_detach function has committed to detaching -- it definitely won't back out with EBUSY, for instance -- it can call this to wake all pending calls to device_lookup_acquire and make them fail immediately. This is necessary to break a deadlock if the device_lookup_acquire calls happen inside I/O operations which the driver's .ca_detach function waits for the completion of -- without config_detach_commit, I/O operations would be stuck in device_lookup_acquire waiting for .ca_detach and .ca_detach would be stuck waiting for I/O operations to return. Most drivers won't need to call this: for autoconf drivers used the traditional way by devsw for userland device nodes, the .ca_detach routine uses vdevgone, and we will arrange to make vdevgone call config_detach_commit automagically in such drivers anyway. XXX kernel ABI change to struct device requires bump -- later change will make struct device opaque to ABI, but we're not there yet To generate a diff of this commit: cvs rdiff -u -r1.298 -r1.299 src/sys/kern/subr_autoconf.c cvs rdiff -u -r1.180 -r1.181 src/sys/sys/device.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/subr_autoconf.c diff -u src/sys/kern/subr_autoconf.c:1.298 src/sys/kern/subr_autoconf.c:1.299 --- src/sys/kern/subr_autoconf.c:1.298 Mon Mar 28 12:33:41 2022 +++ src/sys/kern/subr_autoconf.c Mon Mar 28 12:38:15 2022 @@ -1,4 +1,4 @@ -/* $NetBSD: subr_autoconf.c,v 1.298 2022/03/28 12:33:41 riastradh Exp $ */ +/* $NetBSD: subr_autoconf.c,v 1.299 2022/03/28 12:38:15 riastradh Exp $ */ /* * Copyright (c) 1996, 2000 Christopher G. Demetriou @@ -77,7 +77,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.298 2022/03/28 12:33:41 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.299 2022/03/28 12:38:15 riastradh Exp $"); #ifdef _KERNEL_OPT #include "opt_ddb.h" @@ -2039,10 +2039,17 @@ config_detach(device_t dev, int flags) * If it was possible to detach the device, ensure that the * device is deactivated. */ - if (rv == 0) - dev->dv_flags &= ~DVF_ACTIVE; - else if ((flags & DETACH_FORCE) == 0) { - /* Detach failed -- likely EBUSY. */ + if (rv == 0) { + config_detach_commit(dev); + dev->dv_flags &= ~DVF_ACTIVE; /* XXXSMP */ + } else if ((flags & DETACH_FORCE) == 0) { + /* + * Detach failed -- likely EBUSY. Driver must not have + * called config_detach_commit. + */ + KASSERTMSG(!dev->dv_detached, + "%s committed to detaching and then backed out", + device_xname(dev)); goto out; } else { panic("config_detach: forced detach of %s failed (%d)", @@ -2059,7 +2066,8 @@ config_detach(device_t dev, int flags) * responsibility of .ca_detach to ensure anything with open * references will be interrupted and release them promptly, * not block indefinitely. All new attempts to acquire - * references will block until dv_detaching clears. + * references will fail, as config_detach_commit has arranged + * by now. */ mutex_enter(&config_misc_lock); localcount_drain(dev->dv_localcount, @@ -2133,6 +2141,30 @@ out: return rv; } +/* + * config_detach_commit(dev) + * + * Issued by a driver's .ca_detach routine to notify anyone + * waiting in device_lookup_acquire that the driver is committed + * to detaching the device, which allows device_lookup_acquire to + * wake up and fail immediately. + * + * Safe to call multiple times -- idempotent. Must be called + * during config_detach_enter/exit. Safe to use with + * device_lookup because the device is not actually removed from + * the table until after config_detach_exit. + */ +void +config_detach_commit(device_t dev) +{ + + mutex_enter(&config_misc_lock); + KASSERT(dev->dv_detaching == curlwp); + dev->dv_detached = true; + cv_broadcast(&config_misc_cv); + mutex_exit(&config_misc_lock); +} + int config_detach_children(device_t parent, int flags) { @@ -2640,7 +2672,8 @@ device_lookup_acquire(cfdriver_t cd, int mutex_enter(&alldevs_lock); retry: if (unit < 0 || unit >= cd->cd_ndevs || (dv = cd->cd_devs[unit]) == NULL || - dv->dv_del_gen != 0) { + dv->dv_del_gen != 0 || + dv->dv_detached) { dv = NULL; } else { /* Index: src/sys/sys/device.h diff -u src/sys/sys/device.h:1.180 src/sys/sys/device.h:1.181 --- src/sys/sys/device.h:1.180 Mon Mar 28 12:33:41 2022 +++ src/sys/sys/device.h Mon Mar 28 12:38:15 2022 @@ -1,4 +1,4 @@ -/* $NetBSD: device.h,v 1.180 2022/03/28 12:33:41 riastradh Exp $ */ +/* $NetBSD: device.h,v 1.181 2022/03/28 12:38:15 riastradh Exp $ */ /* * Copyright (c) 2021 The NetBSD Foundation, Inc. @@ -281,6 +281,7 @@ struct device { struct lwp *dv_attaching; /* thread not yet finished in attach */ struct lwp *dv_detaching; /* detach lock (config_misc_lock/cv) */ + bool dv_detached; /* config_misc_lock */ size_t dv_activity_count; void (**dv_activity_handlers)(device_t, devactive_t); @@ -631,6 +632,7 @@ device_t config_attach_pseudo(cfdata_t); int config_detach(device_t, int); int config_detach_children(device_t, int flags); +void config_detach_commit(device_t); bool config_detach_all(int); int config_deactivate(device_t); void config_defer(device_t, void (*)(device_t));