summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorpk <pk@NetBSD.org>1997-12-02 13:54:48 +0000
committerpk <pk@NetBSD.org>1997-12-02 13:54:48 +0000
commit1743d97bd7f12d0ad2cfa4d2d946302e8dfcac4a (patch)
tree292d01cc67dcc0331e071511f6047e7ce1b7e622 /sys/dev
parent5d1352c448313f5c3305756cc6494094029344c7 (diff)
Pull over fixes from vm_swap.c:
- guard against synchronous I/O completion - avoid race conditions - use bgetvp/brelvp to properly maintain the vnode holdcount and clean/dirty buffer lists.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/vnd.c131
-rw-r--r--sys/dev/vndvar.h3
2 files changed, 86 insertions, 48 deletions
diff --git a/sys/dev/vnd.c b/sys/dev/vnd.c
index 9ef7f4168e8..83e0d430416 100644
--- a/sys/dev/vnd.c
+++ b/sys/dev/vnd.c
@@ -1,4 +1,4 @@
-/* $NetBSD: vnd.c,v 1.50 1997/10/20 00:11:03 fvdl Exp $ */
+/* $NetBSD: vnd.c,v 1.51 1997/12/02 13:54:50 pk Exp $ */
/*-
* Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
@@ -140,6 +140,8 @@ struct vndxfer {
struct buf *vx_bp; /* Pointer to parent buffer */
int vx_error;
int vx_pending; /* # of pending aux buffers */
+ int vx_flags;
+#define VX_BUSY 1
};
struct vndbuf {
@@ -311,9 +313,8 @@ vndstrategy(bp)
{
int unit = vndunit(bp->b_dev);
struct vnd_softc *vnd = &vnd_softc[unit];
- struct vndbuf *nbp;
struct vndxfer *vnx;
- int bn, bsize, resid;
+ int s, bn, bsize, resid;
caddr_t addr;
int sz, flags, error, wlabel;
struct disklabel *lp;
@@ -378,14 +379,16 @@ vndstrategy(bp)
/* Allocate a header for this transfer and link it to the buffer */
vnx = getvndxfer();
+ vnx->vx_flags = VX_BUSY;
vnx->vx_error = 0;
vnx->vx_pending = 0;
vnx->vx_bp = bp;
for (resid = bp->b_resid; resid; resid -= sz) {
+ struct vndbuf *nbp;
struct vnode *vp;
daddr_t nbn;
- int off, s, nra, dolock = 0;
+ int off, nra, dolock = 0;
nra = 0;
/*
@@ -415,17 +418,9 @@ vndstrategy(bp)
* a hassle (in the write case).
*/
if (error) {
- vnx->vx_error = error;
s = splbio();
- if (vnx->vx_pending == 0) {
- bp->b_error = error;
- bp->b_flags |= B_ERROR;
- putvndxfer(vnx);
- splx(s);
- goto done;
- }
- splx(s);
- return;
+ vnx->vx_error = error;
+ goto out;
}
#ifdef DEBUG
@@ -450,15 +445,11 @@ vndstrategy(bp)
nbp->vb_buf.b_bcount = sz;
nbp->vb_buf.b_bufsize = bp->b_bufsize;
nbp->vb_buf.b_error = 0;
- if (vp->v_type == VBLK || vp->v_type == VCHR)
- nbp->vb_buf.b_dev = vp->v_rdev;
- else
- nbp->vb_buf.b_dev = NODEV;
nbp->vb_buf.b_data = addr;
nbp->vb_buf.b_blkno = nbn + btodb(off);
nbp->vb_buf.b_proc = bp->b_proc;
nbp->vb_buf.b_iodone = vndiodone;
- nbp->vb_buf.b_vp = vp;
+ nbp->vb_buf.b_vp = NULLVP;
nbp->vb_buf.b_rcred = vnd->sc_cred; /* XXX crdup? */
nbp->vb_buf.b_wcred = vnd->sc_cred; /* XXX crdup? */
if (bp->b_dirtyend == 0) {
@@ -489,16 +480,32 @@ vndstrategy(bp)
*/
nbp->vb_buf.b_cylin = nbp->vb_buf.b_blkno;
s = splbio();
+ if (vnx->vx_error != 0) {
+ putvndbuf(nbp);
+ goto out;
+ }
vnx->vx_pending++;
+ bgetvp(vp, &nbp->vb_buf);
disksort(&vnd->sc_tab, &nbp->vb_buf);
- if (vnd->sc_tab.b_active < vnd->sc_maxactive) {
- vnd->sc_tab.b_active++;
- vndstart(vnd);
- }
+ vndstart(vnd);
splx(s);
bn += sz;
addr += sz;
}
+
+ s = splbio();
+
+out: /* Arrive here at splbio */
+ vnx->vx_flags &= ~VX_BUSY;
+ if (vnx->vx_pending == 0) {
+ if (vnx->vx_error != 0) {
+ bp->b_error = vnx->vx_error;
+ bp->b_flags |= B_ERROR;
+ }
+ putvndxfer(vnx);
+ biodone(bp);
+ }
+ splx(s);
return;
done:
@@ -515,27 +522,39 @@ void
vndstart(vnd)
register struct vnd_softc *vnd;
{
- register struct buf *bp;
+ struct buf *bp;
/*
* Dequeue now since lower level strategy routine might
* queue using same links
*/
- bp = vnd->sc_tab.b_actf;
- vnd->sc_tab.b_actf = bp->b_actf;
+
+ if ((vnd->sc_flags & VNF_BUSY) != 0)
+ return;
+
+ vnd->sc_flags |= VNF_BUSY;
+
+ while (vnd->sc_tab.b_active < vnd->sc_maxactive) {
+ bp = vnd->sc_tab.b_actf;
+ if (bp == NULL)
+ break;
+ vnd->sc_tab.b_actf = bp->b_actf;
+ vnd->sc_tab.b_active++;
#ifdef DEBUG
- if (vnddebug & VDB_IO)
- printf("vndstart(%ld): bp %p vp %p blkno 0x%x addr %p cnt 0x%lx\n",
- (long) (vnd-vnd_softc), bp, bp->b_vp, bp->b_blkno,
- bp->b_data, bp->b_bcount);
+ if (vnddebug & VDB_IO)
+ printf("vndstart(%ld): bp %p vp %p blkno 0x%x addr %p cnt 0x%lx\n",
+ (long) (vnd-vnd_softc), bp, bp->b_vp, bp->b_blkno,
+ bp->b_data, bp->b_bcount);
#endif
- /* Instrumentation. */
- disk_busy(&vnd->sc_dkdev);
+ /* Instrumentation. */
+ disk_busy(&vnd->sc_dkdev);
- if ((bp->b_flags & B_READ) == 0)
- bp->b_vp->v_numoutput++;
- VOP_STRATEGY(bp);
+ if ((bp->b_flags & B_READ) == 0)
+ bp->b_vp->v_numoutput++;
+ VOP_STRATEGY(bp);
+ }
+ vnd->sc_flags &= ~VNF_BUSY;
}
void
@@ -570,30 +589,48 @@ vndiodone(bp)
#endif
vnx->vx_error = vbp->vb_buf.b_error;
}
+
+ if (vbp->vb_buf.b_vp != NULLVP)
+ brelvp(&vbp->vb_buf);
+
putvndbuf(vbp);
/*
* Wrap up this transaction if it has run to completion or, in
* case of an error, when all auxiliary buffers have returned.
*/
- if (pbp->b_resid == 0 || (vnx->vx_error && vnx->vx_pending == 0)) {
+ if (vnx->vx_error != 0) {
+ pbp->b_flags |= B_ERROR;
+ pbp->b_error = vnx->vx_error;
+ if ((vnx->vx_flags & VX_BUSY) == 0 && vnx->vx_pending == 0) {
- if (vnx->vx_error != 0) {
- pbp->b_flags |= B_ERROR;
- pbp->b_error = vnx->vx_error;
+#ifdef DEBUG
+ if (vnddebug & VDB_IO)
+ printf("vndiodone: pbp %p iodone: error %d\n",
+ pbp, vnx->vx_error);
+#endif
+ putvndxfer(vnx);
+ biodone(pbp);
}
- putvndxfer(vnx);
+ } else if (pbp->b_resid == 0) {
+
+#ifdef DIAGNOSTIC
+ if (vnx->vx_pending != 0)
+ panic("swiodone: vnx pending: %d", vnx->vx_pending);
+#endif
+
+ if ((vnx->vx_flags & VX_BUSY) == 0) {
#ifdef DEBUG
- if (vnddebug & VDB_IO)
- printf("vndiodone: pbp %p iodone\n", pbp);
+ if (vnddebug & VDB_IO)
+ printf("vndiodone: pbp %p iodone\n", pbp);
#endif
- biodone(pbp);
+ putvndxfer(vnx);
+ biodone(pbp);
+ }
}
- if (vnd->sc_tab.b_actf)
- vndstart(vnd);
- else
- vnd->sc_tab.b_active--;
+ vnd->sc_tab.b_active--;
+ vndstart(vnd);
splx(s);
}
diff --git a/sys/dev/vndvar.h b/sys/dev/vndvar.h
index 5338318b672..fe9ce1f800c 100644
--- a/sys/dev/vndvar.h
+++ b/sys/dev/vndvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: vndvar.h,v 1.2 1997/10/09 07:47:50 jtc Exp $ */
+/* $NetBSD: vndvar.h,v 1.3 1997/12/02 13:54:48 pk Exp $ */
/*-
* Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
@@ -126,6 +126,7 @@ struct vnd_softc {
#define VNF_LABELLING 0x04 /* unit is currently being labelled */
#define VNF_WANTED 0x08 /* someone is waiting to obtain a lock */
#define VNF_LOCKED 0x10 /* unit is locked */
+#define VNF_BUSY 0x20 /* unit is busy */
/*
* Before you can use a unit, it must be configured with VNDIOCSET.