Module Name: src Committed By: dyoung Date: Thu Apr 30 20:34:08 UTC 2009
Modified Files: src/sys/dev: vnd.c Log Message: Flesh out vnd_detach(). Let the system detach vnd(4) at shutdown. Stop vnd_ioctl(VNDIOCCLR) from racing with vndopen() to call vndclear(). To generate a diff of this commit: cvs rdiff -u -r1.198 -r1.199 src/sys/dev/vnd.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/vnd.c diff -u src/sys/dev/vnd.c:1.198 src/sys/dev/vnd.c:1.199 --- src/sys/dev/vnd.c:1.198 Thu Apr 30 16:38:12 2009 +++ src/sys/dev/vnd.c Thu Apr 30 20:34:08 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: vnd.c,v 1.198 2009/04/30 16:38:12 dyoung Exp $ */ +/* $NetBSD: vnd.c,v 1.199 2009/04/30 20:34:08 dyoung Exp $ */ /*- * Copyright (c) 1996, 1997, 1998, 2008 The NetBSD Foundation, Inc. @@ -130,7 +130,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: vnd.c,v 1.198 2009/04/30 16:38:12 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vnd.c,v 1.199 2009/04/30 20:34:08 dyoung Exp $"); #if defined(_KERNEL_OPT) #include "fs_nfs.h" @@ -198,6 +198,7 @@ void vndattach(int); static void vndclear(struct vnd_softc *, int); +static int vnddoclear(struct vnd_softc *, int, int, bool); static int vndsetcred(struct vnd_softc *, kauth_cred_t); static void vndthrottle(struct vnd_softc *, struct vnode *); static void vndiodone(struct buf *); @@ -246,8 +247,8 @@ static void vnd_attach(device_t, device_t, void *); static int vnd_detach(device_t, int); -CFATTACH_DECL_NEW(vnd, sizeof(struct vnd_softc), - vnd_match, vnd_attach, vnd_detach, NULL); +CFATTACH_DECL3_NEW(vnd, sizeof(struct vnd_softc), + vnd_match, vnd_attach, vnd_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN); extern struct cfdriver vnd_cd; static struct vnd_softc *vnd_spawn(int); @@ -289,9 +290,14 @@ static int vnd_detach(device_t self, int flags) { + int error; struct vnd_softc *sc = device_private(self); - if (sc->sc_flags & VNF_INITED) - return EBUSY; + + if (sc->sc_flags & VNF_INITED) { + error = vnddoclear(sc, 0, -1, (flags & DETACH_FORCE) != 0); + if (error != 0) + return error; + } pmf_device_deregister(self); bufq_free(sc->sc_tab); @@ -350,6 +356,9 @@ if ((error = vndlock(sc)) != 0) return error; + if ((sc->sc_flags & VNF_CLEARING) != 0) + return ENXIO; + lp = sc->sc_dkdev.dk_label; part = DISKPART(dev); @@ -948,10 +957,55 @@ return VOP_GETATTR(vnd->sc_vp, va, l->l_cred); } +static int +vnddoclear(struct vnd_softc *vnd, int pmask, int minor, bool force) +{ + int error; + + if ((error = vndlock(vnd)) != 0) + return error; + + /* + * Don't unconfigure if any other partitions are open + * or if both the character and block flavors of this + * partition are open. + */ + if (((vnd->sc_dkdev.dk_openmask & ~pmask) || + ((vnd->sc_dkdev.dk_bopenmask & pmask) && + (vnd->sc_dkdev.dk_copenmask & pmask))) && !force) { + vndunlock(vnd); + return EBUSY; + } + + /* + * XXX vndclear() might call vndclose() implicitly; + * release lock to avoid recursion + * + * Set VNF_CLEARING to prevent vndopen() from + * sneaking in after we vndunlock(). + */ + vnd->sc_flags |= VNF_CLEARING; + vndunlock(vnd); + vndclear(vnd, minor); +#ifdef DEBUG + if (vnddebug & VDB_INIT) + printf("vndioctl: CLRed\n"); +#endif + + /* Destroy the xfer and buffer pools. */ + pool_destroy(&vnd->sc_vxpool); + + /* Detach the disk. */ + disk_detach(&vnd->sc_dkdev); + + return 0; +} + /* ARGSUSED */ static int vndioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) { + bool force; int unit = vndunit(dev); struct vnd_softc *vnd; struct vnd_ioctl *vio; @@ -1274,40 +1328,13 @@ return error; case VNDIOCCLR: - if ((error = vndlock(vnd)) != 0) - return error; - - /* - * Don't unconfigure if any other partitions are open - * or if both the character and block flavors of this - * partition are open. - */ part = DISKPART(dev); pmask = (1 << part); - if (((vnd->sc_dkdev.dk_openmask & ~pmask) || - ((vnd->sc_dkdev.dk_bopenmask & pmask) && - (vnd->sc_dkdev.dk_copenmask & pmask))) && - !(vio->vnd_flags & VNDIOF_FORCE)) { - vndunlock(vnd); - return EBUSY; - } + force = (vio->vnd_flags & VNDIOF_FORCE) != 0; - /* - * XXX vndclear() might call vndclose() implicitly; - * release lock to avoid recursion - */ - vndunlock(vnd); - vndclear(vnd, minor(dev)); -#ifdef DEBUG - if (vnddebug & VDB_INIT) - printf("vndioctl: CLRed\n"); -#endif - - /* Destroy the xfer and buffer pools. */ - pool_destroy(&vnd->sc_vxpool); + if ((error = vnddoclear(vnd, pmask, minor(dev), force)) != 0) + return error; - /* Detach the disk. */ - disk_detach(&vnd->sc_dkdev); break; #ifdef COMPAT_30