Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys driver(9): New devsw members d_cfdriver, d_devtounit.



details:   https://anonhg.NetBSD.org/src/rev/4c41194fe8cc
branches:  trunk
changeset: 364492:4c41194fe8cc
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Mon Mar 28 12:33:50 2022 +0000

description:
driver(9): New devsw members d_cfdriver, d_devtounit.

If set, then bdev_open/cdev_open will use d_devtounit to map the
dev_t to an autoconf instance (e.g., /dev/wd0a -> wd0) and hold a
reference with device_lookup_acquire across the call to d_open.

This guarantees that the autoconf instance cannot be detached while
the devsw's d_open function is trying to open it (and also that the
autoconf instance has finished *_attach before anyone can open it).

Of course, if the underlying hardware has gone away, there will be
I/O errors, but this avoids software synchronization bugs between
open and detach for drivers that opt into it.  It's up to the driver
and bus to figure out how to deal with I/O errors from operations on
hardware that has gone away while the software hasn't finished
notifying everything that it's gone yet.

XXX kernel ABI change to struct bdevsw/cdevsw requires bump

diffstat:

 sys/kern/subr_devsw.c |  53 +++++++++++++++++++++++++++++++++++++++++++++++---
 sys/sys/conf.h        |   6 ++++-
 2 files changed, 54 insertions(+), 5 deletions(-)

diffs (133 lines):

diff -r 140800c3aa80 -r 4c41194fe8cc sys/kern/subr_devsw.c
--- a/sys/kern/subr_devsw.c     Mon Mar 28 12:33:41 2022 +0000
+++ b/sys/kern/subr_devsw.c     Mon Mar 28 12:33:50 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: subr_devsw.c,v 1.40 2022/03/28 12:33:32 riastradh Exp $        */
+/*     $NetBSD: subr_devsw.c,v 1.41 2022/03/28 12:33:50 riastradh Exp $        */
 
 /*-
  * Copyright (c) 2001, 2002, 2007, 2008 The NetBSD Foundation, Inc.
@@ -69,7 +69,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_devsw.c,v 1.40 2022/03/28 12:33:32 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_devsw.c,v 1.41 2022/03/28 12:33:50 riastradh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_dtrace.h"
@@ -89,6 +89,7 @@
 #include <sys/localcount.h>
 #include <sys/pserialize.h>
 #include <sys/xcall.h>
+#include <sys/device.h>
 
 #ifdef DEVSW_DEBUG
 #define        DPRINTF(x)      printf x
@@ -895,16 +896,38 @@
 {
        const struct bdevsw *d;
        struct localcount *lc;
-       int rv, mpflag;
+       device_t dv = NULL/*XXXGCC*/;
+       int unit, rv, mpflag;
 
        d = bdevsw_lookup_acquire(dev, &lc);
        if (d == NULL)
                return ENXIO;
 
+       if (d->d_devtounit) {
+               /*
+                * If the device node corresponds to an autoconf device
+                * instance, acquire a reference to it so that during
+                * d_open, device_lookup is stable.
+                *
+                * XXX This should also arrange to instantiate cloning
+                * pseudo-devices if appropriate, but that requires
+                * reviewing them all to find and verify a common
+                * pattern.
+                */
+               if ((unit = (*d->d_devtounit)(dev)) == -1)
+                       return ENXIO;
+               if ((dv = device_lookup_acquire(d->d_cfdriver, unit)) == NULL)
+                       return ENXIO;
+       }
+
        DEV_LOCK(d);
        rv = (*d->d_open)(dev, flag, devtype, l);
        DEV_UNLOCK(d);
 
+       if (d->d_devtounit) {
+               device_release(dv);
+       }
+
        bdevsw_release(d, lc);
 
        return rv;
@@ -1050,16 +1073,38 @@
 {
        const struct cdevsw *d;
        struct localcount *lc;
-       int rv, mpflag;
+       device_t dv = NULL/*XXXGCC*/;
+       int unit, rv, mpflag;
 
        d = cdevsw_lookup_acquire(dev, &lc);
        if (d == NULL)
                return ENXIO;
 
+       if (d->d_devtounit) {
+               /*
+                * If the device node corresponds to an autoconf device
+                * instance, acquire a reference to it so that during
+                * d_open, device_lookup is stable.
+                *
+                * XXX This should also arrange to instantiate cloning
+                * pseudo-devices if appropriate, but that requires
+                * reviewing them all to find and verify a common
+                * pattern.
+                */
+               if ((unit = (*d->d_devtounit)(dev)) == -1)
+                       return ENXIO;
+               if ((dv = device_lookup_acquire(d->d_cfdriver, unit)) == NULL)
+                       return ENXIO;
+       }
+
        DEV_LOCK(d);
        rv = (*d->d_open)(dev, flag, devtype, l);
        DEV_UNLOCK(d);
 
+       if (d->d_devtounit) {
+               device_release(dv);
+       }
+
        cdevsw_release(d, lc);
 
        return rv;
diff -r 140800c3aa80 -r 4c41194fe8cc sys/sys/conf.h
--- a/sys/sys/conf.h    Mon Mar 28 12:33:41 2022 +0000
+++ b/sys/sys/conf.h    Mon Mar 28 12:33:50 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: conf.h,v 1.155 2022/03/28 12:33:22 riastradh Exp $     */
+/*     $NetBSD: conf.h,v 1.156 2022/03/28 12:33:50 riastradh Exp $     */
 
 /*-
  * Copyright (c) 1990, 1993
@@ -76,6 +76,8 @@
        int             (*d_dump)(dev_t, daddr_t, void *, size_t);
        int             (*d_psize)(dev_t);
        int             (*d_discard)(dev_t, off_t, off_t);
+       int             (*d_devtounit)(dev_t);
+       struct cfdriver *d_cfdriver;
        int             d_flag;
 };
 
@@ -94,6 +96,8 @@
        paddr_t         (*d_mmap)(dev_t, off_t, int);
        int             (*d_kqfilter)(dev_t, struct knote *);
        int             (*d_discard)(dev_t, off_t, off_t);
+       int             (*d_devtounit)(dev_t);
+       struct cfdriver *d_cfdriver;
        int             d_flag;
 };
 



Home | Main Index | Thread Index | Old Index