Module Name: src Committed By: riastradh Date: Mon May 22 14:58:33 UTC 2023
Modified Files: src/sys/dev/dkwedge: dk.c Log Message: dk(4): Use config_attach_pseudo_acquire to create wedges. This way, indexing of the dkwedges array coincides with numbering of autoconf dk(4) instances. As a side effect, this plugs a race in dkwedge_add with concurrent drvctl -r. There are a lot of such races in dk(4) left -- to be addressed with more device references. To generate a diff of this commit: cvs rdiff -u -r1.158 -r1.159 src/sys/dev/dkwedge/dk.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/dkwedge/dk.c diff -u src/sys/dev/dkwedge/dk.c:1.158 src/sys/dev/dkwedge/dk.c:1.159 --- src/sys/dev/dkwedge/dk.c:1.158 Sat May 13 10:11:36 2023 +++ src/sys/dev/dkwedge/dk.c Mon May 22 14:58:32 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: dk.c,v 1.158 2023/05/13 10:11:36 riastradh Exp $ */ +/* $NetBSD: dk.c,v 1.159 2023/05/22 14:58:32 riastradh Exp $ */ /*- * Copyright (c) 2004, 2005, 2006, 2007 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: dk.c,v 1.158 2023/05/13 10:11:36 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: dk.c,v 1.159 2023/05/22 14:58:32 riastradh Exp $"); #ifdef _KERNEL_OPT #include "opt_dkwedge.h" @@ -99,6 +99,8 @@ static int dkwedge_match(device_t, cfdat static void dkwedge_attach(device_t, device_t, void *); static int dkwedge_detach(device_t, int); +static void dk_set_geometry(struct dkwedge_softc *, struct disk *); + static void dkstart(struct dkwedge_softc *); static void dkiodone(struct buf *); static void dkrestart(void *); @@ -190,9 +192,34 @@ dkwedge_match(device_t parent, cfdata_t static void dkwedge_attach(device_t parent, device_t self, void *aux) { + struct dkwedge_softc *sc = aux; + struct disk *pdk = sc->sc_parent; + int unit = device_unit(self); + + KASSERTMSG(unit >= 0, "unit=%d", unit); if (!pmf_device_register(self, NULL, NULL)) aprint_error_dev(self, "couldn't establish power handler\n"); + + mutex_enter(&pdk->dk_openlock); + rw_enter(&dkwedges_lock, RW_WRITER); + KASSERTMSG(unit < ndkwedges, "unit=%d ndkwedges=%u", unit, ndkwedges); + KASSERTMSG(sc == dkwedges[unit], "sc=%p dkwedges[%d]=%p", + sc, unit, dkwedges[unit]); + KASSERTMSG(sc->sc_dev == NULL, "sc=%p sc->sc_dev=%p", sc, sc->sc_dev); + sc->sc_dev = self; + rw_exit(&dkwedges_lock); + mutex_exit(&pdk->dk_openlock); + + disk_init(&sc->sc_dk, device_xname(sc->sc_dev), NULL); + mutex_enter(&pdk->dk_openlock); + dk_set_geometry(sc, pdk); + mutex_exit(&pdk->dk_openlock); + disk_attach(&sc->sc_dk); + + /* Disk wedge is ready for use! */ + device_set_private(self, sc); + sc->sc_state = DKW_STATE_RUNNING; } /* @@ -364,6 +391,7 @@ dkwedge_add(struct dkwedge_info *dkw) u_int unit; int error; dev_t pdev; + device_t dev __diagused; dkw->dkw_parent[sizeof(dkw->dkw_parent) - 1] = '\0'; pdk = disk_find(dkw->dkw_parent); @@ -393,8 +421,11 @@ dkwedge_add(struct dkwedge_info *dkw) break; if (dkwedge_size(lsc) > dkw->dkw_size) break; + if (lsc->sc_dev == NULL) + break; sc = lsc; + device_acquire(sc->sc_dev); dkwedge_size_increase(sc, dkw->dkw_size); dk_set_geometry(sc, pdk); @@ -477,7 +508,7 @@ dkwedge_add(struct dkwedge_info *dkw) sc->sc_cfdata.cf_name = dk_cd.cd_name; sc->sc_cfdata.cf_atname = dk_ca.ca_name; /* sc->sc_cfdata.cf_unit set below */ - sc->sc_cfdata.cf_fstate = FSTATE_STAR; + sc->sc_cfdata.cf_fstate = FSTATE_NOTFOUND; /* use chosen cf_unit */ /* Insert the larval wedge into the array. */ rw_enter(&dkwedges_lock, RW_WRITER); @@ -538,7 +569,7 @@ dkwedge_add(struct dkwedge_info *dkw) * This should never fail, unless we're almost totally out of * memory. */ - if ((sc->sc_dev = config_attach_pseudo(&sc->sc_cfdata)) == NULL) { + if ((dev = config_attach_pseudo_acquire(&sc->sc_cfdata, sc)) == NULL) { aprint_error("%s%u: unable to attach pseudo-device\n", sc->sc_cfdata.cf_name, sc->sc_cfdata.cf_unit); @@ -559,19 +590,7 @@ dkwedge_add(struct dkwedge_info *dkw) return ENOMEM; } - /* - * XXX Really ought to make the disk_attach() and the changing - * of state to RUNNING atomic. - */ - - disk_init(&sc->sc_dk, device_xname(sc->sc_dev), NULL); - mutex_enter(&pdk->dk_openlock); - dk_set_geometry(sc, pdk); - mutex_exit(&pdk->dk_openlock); - disk_attach(&sc->sc_dk); - - /* Disk wedge is ready for use! */ - sc->sc_state = DKW_STATE_RUNNING; + KASSERT(dev == sc->sc_dev); announce: /* Announce our arrival. */ @@ -586,11 +605,12 @@ announce: strlcpy(dkw->dkw_devname, device_xname(sc->sc_dev), sizeof(dkw->dkw_devname)); + device_release(sc->sc_dev); return 0; } /* - * dkwedge_find: + * dkwedge_find_acquire: * * Lookup a disk wedge based on the provided information. * NOTE: We look up the wedge based on the wedge devname, @@ -598,10 +618,11 @@ announce: * * Return NULL if the wedge is not found, otherwise return * the wedge's softc. Assign the wedge's unit number to unitp - * if unitp is not NULL. + * if unitp is not NULL. The wedge's sc_dev is referenced and + * must be released by device_release or equivalent. */ static struct dkwedge_softc * -dkwedge_find(struct dkwedge_info *dkw, u_int *unitp) +dkwedge_find_acquire(struct dkwedge_info *dkw, u_int *unitp) { struct dkwedge_softc *sc = NULL; u_int unit; @@ -611,8 +632,10 @@ dkwedge_find(struct dkwedge_info *dkw, u rw_enter(&dkwedges_lock, RW_READER); for (unit = 0; unit < ndkwedges; unit++) { if ((sc = dkwedges[unit]) != NULL && + sc->sc_dev != NULL && strcmp(device_xname(sc->sc_dev), dkw->dkw_devname) == 0 && strcmp(sc->sc_parent->dk_name, dkw->dkw_parent) == 0) { + device_acquire(sc->sc_dev); break; } } @@ -646,10 +669,10 @@ dkwedge_del1(struct dkwedge_info *dkw, i struct dkwedge_softc *sc = NULL; /* Find our softc. */ - if ((sc = dkwedge_find(dkw, NULL)) == NULL) + if ((sc = dkwedge_find_acquire(dkw, NULL)) == NULL) return ESRCH; - return config_detach(sc->sc_dev, flags); + return config_detach_release(sc->sc_dev, flags); } /* @@ -660,26 +683,16 @@ dkwedge_del1(struct dkwedge_info *dkw, i static int dkwedge_detach(device_t self, int flags) { - struct dkwedge_softc *sc = NULL; - u_int unit; - int bmaj, cmaj, rc; + struct dkwedge_softc *const sc = device_private(self); + const u_int unit = device_unit(self); + int bmaj, cmaj, error; - rw_enter(&dkwedges_lock, RW_WRITER); - for (unit = 0; unit < ndkwedges; unit++) { - if ((sc = dkwedges[unit]) != NULL && sc->sc_dev == self) - break; - } - if (unit == ndkwedges) - rc = ENXIO; - else if ((rc = disk_begindetach(&sc->sc_dk, /*lastclose*/NULL, self, - flags)) == 0) { - /* Mark the wedge as dying. */ - sc->sc_state = DKW_STATE_DYING; - } - rw_exit(&dkwedges_lock); + error = disk_begindetach(&sc->sc_dk, /*lastclose*/NULL, self, flags); + if (error) + return error; - if (rc != 0) - return rc; + /* Mark the wedge as dying. */ + sc->sc_state = DKW_STATE_DYING; pmf_device_deregister(self); @@ -1147,6 +1160,8 @@ dkwedge_read(struct disk *pdk, struct vn * dkwedge_lookup: * * Look up a dkwedge_softc based on the provided dev_t. + * + * Caller must guarantee the wedge is referenced. */ static struct dkwedge_softc * dkwedge_lookup(dev_t dev)