diff options
| author | dyoung <dyoung@NetBSD.org> | 2009-04-30 20:34:08 +0000 |
|---|---|---|
| committer | dyoung <dyoung@NetBSD.org> | 2009-04-30 20:34:08 +0000 |
| commit | c968789de1bdcd642155ef3713d70b5de07b4c82 (patch) | |
| tree | c58a211b050256f7af765a0f3b336a02c7b2225b /sys/dev | |
| parent | 3c1f169a5912afbef3d04ac250f2414331966e30 (diff) | |
Flesh out vnd_detach(). Let the system detach vnd(4) at shutdown. Stop
vnd_ioctl(VNDIOCCLR) from racing with vndopen() to call vndclear().
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/vnd.c | 99 |
1 files changed, 63 insertions, 36 deletions
diff --git a/sys/dev/vnd.c b/sys/dev/vnd.c index a4dd4d18577..68064a01870 100644 --- a/sys/dev/vnd.c +++ b/sys/dev/vnd.c @@ -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 @@ struct vndxfer { 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 int vnd_match(device_t, cfdata_t, void *); 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 @@ vnd_attach(device_t parent, device_t self, void *aux) 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 @@ vndopen(dev_t dev, int flags, int mode, struct lwp *l) 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 @@ vnd_cget(struct lwp *l, int unit, int *un, struct vattr *va) 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 @@ unlock_and_exit: 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 |
