diff options
author | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2007-09-15 19:22:19 +0000 |
---|---|---|
committer | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2007-09-15 19:22:19 +0000 |
commit | 1048dee18994bd356dfb09463e60f9821548f834 (patch) | |
tree | 03c94ee72b9ce47147e46463c1f1eb079fdfa6b0 | |
parent | 288752b760425fddc6fe00d317697ef966764b4c (diff) |
Allow to pull out an usb stick with ffs filesystem while mounted
and a file is written onto the stick. Without these fixes the
machine panics or hangs.
The usb fix calls the callback when the stick is pulled out to free
the associated buffers. Otherwise we have busy buffers for ever
and the automatic unmount will panic.
The change in the scsi layer prevents passing down further dirty
buffers to usb after the stick has been deactivated.
In vfs the automatic unmount has moved from the function vgonel()
to vop_generic_revoke(). Both are called when the sd device's vnode
is removed. In vgonel() the VXLOCK is already held which can cause
a deadlock. So call dounmount() earlier.
ok krw@, I like this marco@, tested by ian@
-rw-r--r-- | sys/dev/usb/umass.c | 11 | ||||
-rw-r--r-- | sys/kern/vfs_default.c | 14 | ||||
-rw-r--r-- | sys/kern/vfs_subr.c | 18 | ||||
-rw-r--r-- | sys/scsi/sd.c | 35 | ||||
-rw-r--r-- | sys/scsi/sdvar.h | 3 |
5 files changed, 55 insertions, 26 deletions
diff --git a/sys/dev/usb/umass.c b/sys/dev/usb/umass.c index 294c7bdd1b8..0752071aeae 100644 --- a/sys/dev/usb/umass.c +++ b/sys/dev/usb/umass.c @@ -1,4 +1,4 @@ -/* $OpenBSD: umass.c,v 1.52 2007/06/14 10:11:16 mbalmer Exp $ */ +/* $OpenBSD: umass.c,v 1.53 2007/09/15 19:22:18 bluhm Exp $ */ /* $NetBSD: umass.c,v 1.116 2004/06/30 05:53:46 mycroft Exp $ */ /* @@ -669,6 +669,15 @@ umass_detach(struct device *self, int flags) /* Wait for processes to go away. */ usb_detach_wait(&sc->sc_dev); } + + /* Free the buffers via callback. */ + if (sc->transfer_state != TSTATE_IDLE && sc->transfer_priv) { + sc->transfer_state = TSTATE_IDLE; + sc->transfer_cb(sc, sc->transfer_priv, + sc->transfer_datalen, + STATUS_WIRE_FAILED); + sc->transfer_priv = NULL; + } splx(s); scbus = sc->bus; diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c index b36090ffcb7..df06e7a0358 100644 --- a/sys/kern/vfs_default.c +++ b/sys/kern/vfs_default.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_default.c,v 1.34 2007/06/01 23:47:56 deraadt Exp $ */ +/* $OpenBSD: vfs_default.c,v 1.35 2007/09/15 19:22:18 bluhm Exp $ */ /* * Portions of this code are: @@ -68,6 +68,18 @@ vop_generic_revoke(void *v) vp = ap->a_vp; + if (vp->v_type == VBLK && vp->v_specinfo != 0) { + struct mount *mp = vp->v_specmountpoint; + + /* + * If we have a mount point associated with the vnode, we must + * flush it out now, as to not leave a dangling zombie mount + * point laying around in VFS. + */ + if (mp != NULL && !vfs_busy(mp, VB_WRITE|VB_WAIT)) + dounmount(mp, MNT_FORCE | MNT_DOOMED, p, NULL); + } + if (vp->v_flag & VALIASED) { /* * If a vgone (or vclean) is already in progress, diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 7f192fc9767..752b7bbc652 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_subr.c,v 1.156 2007/09/07 15:00:20 art Exp $ */ +/* $OpenBSD: vfs_subr.c,v 1.157 2007/09/15 19:22:18 bluhm Exp $ */ /* $NetBSD: vfs_subr.c,v 1.53 1996/04/22 01:39:13 christos Exp $ */ /* @@ -1006,8 +1006,6 @@ vgonel(struct vnode *vp, struct proc *p) { struct vnode *vq; struct vnode *vx; - struct mount *mp; - int flags; /* * If a vgone (or vclean) is already in progress, @@ -1061,20 +1059,6 @@ vgonel(struct vnode *vp, struct proc *p) vx->v_flag &= ~VALIASED; vp->v_flag &= ~VALIASED; } - - /* - * If we have a mount point associated with the vnode, we must - * flush it out now, as to not leave a dangling zombie mount - * point laying around in VFS. - */ - mp = vp->v_specmountpoint; - if (mp != NULL) { - if (!vfs_busy(mp, VB_WRITE|VB_WAIT)) { - flags = MNT_FORCE | MNT_DOOMED; - dounmount(mp, flags, p, NULL); - } - } - FREE(vp->v_specinfo, M_VNODE); vp->v_specinfo = NULL; } diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c index 37253fd686b..ea85c9bb31a 100644 --- a/sys/scsi/sd.c +++ b/sys/scsi/sd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sd.c,v 1.136 2007/06/23 19:19:49 krw Exp $ */ +/* $OpenBSD: sd.c,v 1.137 2007/09/15 19:22:18 bluhm Exp $ */ /* $NetBSD: sd.c,v 1.111 1997/04/02 02:29:41 mycroft Exp $ */ /*- @@ -257,6 +257,7 @@ sdattach(struct device *parent, struct device *self, void *aux) int sdactivate(struct device *self, enum devact act) { + struct sd_softc *sd = (struct sd_softc *)self; int rv = 0; switch (act) { @@ -264,9 +265,8 @@ sdactivate(struct device *self, enum devact act) break; case DVACT_DEACTIVATE: - /* - * Nothing to do; we key off the device's DVF_ACTIVATE. - */ + sd->flags |= SDF_DYING; + sd_kill_buffers(sd); break; } @@ -320,6 +320,10 @@ sdopen(dev_t dev, int flag, int fmt, struct proc *p) sd = sdlookup(unit); if (sd == NULL) return (ENXIO); + if (sd->flags & SDF_DYING) { + device_unref(&sd->sc_dev); + return (ENXIO); + } sc_link = sd->sc_link; SC_DEBUG(sc_link, SDEV_DB1, @@ -443,7 +447,11 @@ sdclose(dev_t dev, int flag, int fmt, struct proc *p) sd = sdlookup(DISKUNIT(dev)); if (sd == NULL) - return ENXIO; + return (ENXIO); + if (sd->flags & SDF_DYING) { + device_unref(&sd->sc_dev); + return (ENXIO); + } if ((error = sdlock(sd)) != 0) { device_unref(&sd->sc_dev); @@ -499,6 +507,10 @@ sdstrategy(struct buf *bp) bp->b_error = ENXIO; goto bad; } + if (sd->flags & SDF_DYING) { + bp->b_error = ENXIO; + goto bad; + } SC_DEBUG(sd->sc_link, SDEV_DB2, ("sdstrategy: %ld bytes @ blk %d\n", bp->b_bcount, bp->b_blkno)); @@ -598,6 +610,9 @@ sdstart(void *v) int nblks, cmdlen, error; struct partition *p; + if (sd->flags & SDF_DYING) + return; + SC_DEBUG(sc_link, SDEV_DB2, ("sdstart\n")); splassert(IPL_BIO); @@ -827,7 +842,11 @@ sdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) sd = sdlookup(DISKUNIT(dev)); if (sd == NULL) - return ENXIO; + return (ENXIO); + if (sd->flags & SDF_DYING) { + device_unref(&sd->sc_dev); + return (ENXIO); + } SC_DEBUG(sd->sc_link, SDEV_DB2, ("sdioctl 0x%lx\n", cmd)); @@ -1140,6 +1159,10 @@ sdsize(dev_t dev) sd = sdlookup(DISKUNIT(dev)); if (sd == NULL) return -1; + if (sd->flags & SDF_DYING) { + size = -1; + goto exit; + } part = DISKPART(dev); omask = sd->sc_dk.dk_openmask & (1 << part); diff --git a/sys/scsi/sdvar.h b/sys/scsi/sdvar.h index b82666ba5f2..e525098edaa 100644 --- a/sys/scsi/sdvar.h +++ b/sys/scsi/sdvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sdvar.h,v 1.11 2007/06/23 19:19:49 krw Exp $ */ +/* $OpenBSD: sdvar.h,v 1.12 2007/09/15 19:22:18 bluhm Exp $ */ /* $NetBSD: sdvar.h,v 1.7 1998/08/17 00:49:03 mycroft Exp $ */ /*- @@ -68,6 +68,7 @@ struct sd_softc { #define SDF_ANCIENT 0x10 /* disk is ancient; for minphys */ #define SDF_DIRTY 0x20 /* disk is dirty; needs cache flush */ #define SDF_FLUSHING 0x40 /* flushing, for sddone() */ +#define SDF_DYING 0x80 /* dying, when deactivated */ struct scsi_link *sc_link; /* contains our targ, lun, etc. */ struct disk_parms { u_long heads; /* number of heads */ |