Make the buffer cache code MP-safe.

This commit is contained in:
pk 2003-02-05 21:38:38 +00:00
parent 09843e3b7e
commit 338f31f581
19 changed files with 263 additions and 137 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: fd.c,v 1.102 2003/01/30 16:33:50 hannken Exp $ */
/* $NetBSD: fd.c,v 1.103 2003/02/05 21:38:38 pk Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -2104,17 +2104,18 @@ fdformat(dev, finfo, p)
struct ne7_fd_formb *finfo;
struct proc *p;
{
int rv = 0, s;
int rv = 0;
struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
struct fd_type *type = fd->sc_type;
struct buf *bp;
/* set up a buffer header for fdstrategy() */
bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
if (bp == 0)
bp = (struct buf *)pool_get(&bufpool, PR_NOWAIT);
if (bp == NULL)
return (ENOBUFS);
memset((void *)bp, 0, sizeof(struct buf));
simple_lock_init(&bp->b_interlock);
bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
bp->b_proc = p;
bp->b_dev = dev;
@ -2159,23 +2160,8 @@ fdformat(dev, finfo, p)
fdstrategy(bp);
/* ...and wait for it to complete */
s = splbio();
while (!(bp->b_flags & B_DONE)) {
rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
if (rv == EWOULDBLOCK)
break;
}
splx(s);
if (rv == EWOULDBLOCK) {
/* timed out */
rv = EIO;
biodone(bp);
}
if (bp->b_flags & B_ERROR) {
rv = bp->b_error;
}
free(bp, M_TEMP);
rv = biowait(bp);
pool_put(&bufpool, bp);
return (rv);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ata_raid.c,v 1.1 2003/01/27 18:21:27 thorpej Exp $ */
/* $NetBSD: ata_raid.c,v 1.2 2003/02/05 21:38:40 pk Exp $ */
/*
* Copyright (c) 2003 Wasabi Systems, Inc.
@ -296,6 +296,7 @@ ata_raid_config_block_rw(struct vnode *vp, daddr_t blkno, void *buf,
int error;
bp = pool_get(&bufpool, PR_WAITOK);
simple_lock_init(&bp->b_interlock);
LIST_INIT(&bp->b_dep);
bp->b_vp = vp;

View File

@ -1,4 +1,4 @@
/* $NetBSD: ccd.c,v 1.81 2003/01/25 23:09:58 kleink Exp $ */
/* $NetBSD: ccd.c,v 1.82 2003/02/05 21:38:39 pk Exp $ */
/*-
* Copyright (c) 1996, 1997, 1998, 1999 The NetBSD Foundation, Inc.
@ -90,7 +90,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ccd.c,v 1.81 2003/01/25 23:09:58 kleink Exp $");
__KERNEL_RCSID(0, "$NetBSD: ccd.c,v 1.82 2003/02/05 21:38:39 pk Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -802,6 +802,7 @@ ccdbuffer(cs, bp, bn, addr, bcount)
cbp = CCD_GETBUF();
if (cbp == NULL)
return (NULL);
simple_lock_init(&cbp->cb_buf.b_interlock);
cbp->cb_buf.b_flags = bp->b_flags | B_CALL;
cbp->cb_buf.b_iodone = ccdiodone;
cbp->cb_buf.b_proc = bp->b_proc;

View File

@ -1,4 +1,4 @@
/* $NetBSD: cgd.c,v 1.6 2003/02/02 20:55:16 bouyer Exp $ */
/* $NetBSD: cgd.c,v 1.7 2003/02/05 21:38:40 pk Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.6 2003/02/02 20:55:16 bouyer Exp $");
__KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.7 2003/02/05 21:38:40 pk Exp $");
#include <sys/types.h>
#include <sys/param.h>
@ -307,6 +307,7 @@ cgdstart(struct dk_softc *dksc, struct buf *bp)
disk_unbusy(&dksc->sc_dkdev, 0, (bp->b_flags & B_READ));
return;
}
simple_lock_init(&cbp->cb_buf.b_interlock);
cbp->cb_buf.b_data = newaddr;
cbp->cb_buf.b_flags = bp->b_flags | B_CALL;
cbp->cb_buf.b_iodone = cgdiodone;

View File

@ -1,4 +1,4 @@
/* $NetBSD: fd.c,v 1.36 2003/01/25 23:18:46 kleink Exp $ */
/* $NetBSD: fd.c,v 1.37 2003/02/05 21:38:41 pk Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -92,7 +92,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.36 2003/01/25 23:18:46 kleink Exp $");
__KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.37 2003/02/05 21:38:41 pk Exp $");
#include "rnd.h"
#include "opt_ddb.h"
@ -1486,9 +1486,12 @@ fdformat(dev, finfo, p)
struct buf *bp;
/* set up a buffer header for fdstrategy() */
bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT|M_ZERO);
if(bp == 0)
bp = (struct buf *)pool_get(&bufpool, PR_NOWAIT);
if (bp == NULL)
return ENOBUFS;
memset((void *)bp, 0, sizeof(struct buf));
simple_lock_init(&bp->b_interlock);
bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
bp->b_proc = p;
bp->b_dev = dev;
@ -1512,23 +1515,8 @@ fdformat(dev, finfo, p)
fdstrategy(bp);
/* ...and wait for it to complete */
s = splbio();
while (!(bp->b_flags & B_DONE)) {
rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
if (rv == EWOULDBLOCK)
break;
}
splx(s);
if (rv == EWOULDBLOCK) {
/* timed out */
rv = EIO;
biodone(bp);
}
if(bp->b_flags & B_ERROR) {
rv = bp->b_error;
}
free(bp, M_TEMP);
rv = biowait(bp);
pool_put(&bufpool, bp);
return rv;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: rf_netbsdkintf.c,v 1.153 2003/02/01 06:23:40 thorpej Exp $ */
/* $NetBSD: rf_netbsdkintf.c,v 1.154 2003/02/05 21:38:40 pk Exp $ */
/*-
* Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
* All rights reserved.
@ -111,7 +111,7 @@
***********************************************************/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: rf_netbsdkintf.c,v 1.153 2003/02/01 06:23:40 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: rf_netbsdkintf.c,v 1.154 2003/02/05 21:38:40 pk Exp $");
#include <sys/param.h>
#include <sys/errno.h>
@ -1835,6 +1835,12 @@ rf_DispatchKernelIO(queue, req)
}
#endif
raidbp = pool_get(&raidframe_cbufpool, PR_NOWAIT);
if (raidbp == NULL) {
bp->b_flags |= B_ERROR;
bp->b_error = ENOMEM;
return (ENOMEM);
}
simple_lock_init(&raidbp->rf_buf.b_interlock);
/*
* context for raidiodone

View File

@ -1,4 +1,4 @@
/* $NetBSD: cd.c,v 1.177 2003/02/03 23:50:59 thorpej Exp $ */
/* $NetBSD: cd.c,v 1.178 2003/02/05 21:38:41 pk Exp $ */
/*-
* Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
@ -54,7 +54,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: cd.c,v 1.177 2003/02/03 23:50:59 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: cd.c,v 1.178 2003/02/05 21:38:41 pk Exp $");
#include "rnd.h"
@ -647,6 +647,7 @@ cdstrategy(bp)
}
/* Set up the IOP to the bounce buffer. */
simple_lock_init(&nbp->b_interlock);
nbp->b_error = 0;
nbp->b_proc = bp->b_proc;
nbp->b_vp = NULLVP;

View File

@ -1,4 +1,4 @@
/* $NetBSD: vnd.c,v 1.90 2003/01/25 23:09:59 kleink Exp $ */
/* $NetBSD: vnd.c,v 1.91 2003/02/05 21:38:39 pk Exp $ */
/*-
* Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
@ -98,7 +98,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: vnd.c,v 1.90 2003/01/25 23:09:59 kleink Exp $");
__KERNEL_RCSID(0, "$NetBSD: vnd.c,v 1.91 2003/02/05 21:38:39 pk Exp $");
#if defined(_KERNEL_OPT)
#include "fs_nfs.h"
@ -490,6 +490,7 @@ vndstrategy(bp)
s = splbio();
nbp = VND_GETBUF(vnd);
splx(s);
simple_lock_init(&nbp->vb_buf.b_interlock);
nbp->vb_buf.b_flags = flags;
nbp->vb_buf.b_bcount = sz;
nbp->vb_buf.b_bufsize = round_page((ulong)addr + sz)

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_physio.c,v 1.54 2003/01/18 10:06:28 thorpej Exp $ */
/* $NetBSD: kern_physio.c,v 1.55 2003/02/05 21:38:42 pk Exp $ */
/*-
* Copyright (c) 1994 Christopher G. Demetriou
@ -42,7 +42,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_physio.c,v 1.54 2003/01/18 10:06:28 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_physio.c,v 1.55 2003/02/05 21:38:42 pk Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -275,6 +275,7 @@ getphysbuf()
bp = pool_get(&bufpool, PR_WAITOK);
splx(s);
memset(bp, 0, sizeof(*bp));
simple_lock_init(&bp->b_interlock);
return(bp);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: vfs_bio.c,v 1.86 2003/01/18 10:06:37 thorpej Exp $ */
/* $NetBSD: vfs_bio.c,v 1.87 2003/02/05 21:38:42 pk Exp $ */
/*-
* Copyright (c) 1994 Christopher G. Demetriou
@ -51,7 +51,7 @@
#include "opt_softdep.h"
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: vfs_bio.c,v 1.86 2003/01/18 10:06:37 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: vfs_bio.c,v 1.87 2003/02/05 21:38:42 pk Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -102,27 +102,35 @@ struct bio_ops bioops; /* I/O operation notification */
TAILQ_HEAD(bqueues, buf) bufqueues[BQUEUES];
int needbuffer;
/*
* Buffer queue lock.
* Take this lock first if also taking some buffer's b_interlock.
*/
struct simplelock bqueue_slock = SIMPLELOCK_INITIALIZER;
/*
* Buffer pool for I/O buffers.
*/
struct pool bufpool;
/*
* bread()/breadn() helper.
*/
static __inline struct buf *bio_doread(struct vnode *, daddr_t, int,
struct ucred *, int);
int count_lock_queue(void);
/*
* Insq/Remq for the buffer free lists.
* Call with buffer queue locked.
*/
#define binsheadfree(bp, dp) TAILQ_INSERT_HEAD(dp, bp, b_freelist)
#define binstailfree(bp, dp) TAILQ_INSERT_TAIL(dp, bp, b_freelist)
static __inline struct buf *bio_doread __P((struct vnode *, daddr_t, int,
struct ucred *, int));
int count_lock_queue __P((void));
void
bremfree(bp)
struct buf *bp;
{
int s = splbio();
struct bqueues *dp = NULL;
/*
@ -140,7 +148,6 @@ bremfree(bp)
panic("bremfree: lost tail");
}
TAILQ_REMOVE(dp, bp, b_freelist);
splx(s);
}
/*
@ -168,6 +175,7 @@ bufinit()
for (i = 0; i < nbuf; i++) {
bp = &buf[i];
memset((char *)bp, 0, sizeof(*bp));
simple_lock_init(&bp->b_interlock);
bp->b_dev = NODEV;
bp->b_vnbufs.le_next = NOLIST;
LIST_INIT(&bp->b_dep);
@ -206,7 +214,7 @@ bio_doread(vp, blkno, size, cred, async)
/*
* If buffer does not have data valid, start a read.
* Note that if buffer is B_INVAL, getblk() won't return it.
* Therefore, it's valid if it's I/O has completed or been delayed.
* Therefore, it's valid if its I/O has completed or been delayed.
*/
if (!ISSET(bp->b_flags, (B_DONE | B_DELWRI))) {
/* Start I/O for the buffer. */
@ -307,6 +315,8 @@ bwrite(bp)
struct vnode *vp;
struct mount *mp;
KASSERT(ISSET(bp->b_flags, B_BUSY));
vp = bp->b_vp;
if (vp != NULL) {
if (vp->v_type == VBLK)
@ -345,6 +355,7 @@ bwrite(bp)
wasdelayed = ISSET(bp->b_flags, B_DELWRI);
s = splbio();
simple_lock(&bp->b_interlock);
CLR(bp->b_flags, (B_READ | B_DONE | B_ERROR | B_DELWRI));
@ -358,7 +369,8 @@ bwrite(bp)
p->p_stats->p_ru.ru_oublock++;
/* Initiate disk write. Make sure the appropriate party is charged. */
bp->b_vp->v_numoutput++;
V_INCR_NUMOUTPUT(bp->b_vp);
simple_unlock(&bp->b_interlock);
splx(s);
VOP_STRATEGY(bp);
@ -407,6 +419,8 @@ bdwrite(bp)
const struct bdevsw *bdev;
int s;
KASSERT(ISSET(bp->b_flags, B_BUSY));
/* If this is a tape block, write the block now. */
/* XXX NOTE: the memory filesystem usurpes major device */
/* XXX number 4095, which is a bad idea. */
@ -425,6 +439,7 @@ bdwrite(bp)
* (3) Make sure it's on its vnode's correct block list.
*/
s = splbio();
simple_lock(&bp->b_interlock);
if (!ISSET(bp->b_flags, B_DELWRI)) {
SET(bp->b_flags, B_DELWRI);
@ -434,6 +449,7 @@ bdwrite(bp)
/* Otherwise, the "write" is done, so mark and release the buffer. */
CLR(bp->b_flags, B_NEEDCOMMIT|B_DONE);
simple_unlock(&bp->b_interlock);
splx(s);
brelse(bp);
@ -446,8 +462,15 @@ void
bawrite(bp)
struct buf *bp;
{
int s;
KASSERT(ISSET(bp->b_flags, B_BUSY));
s = splbio();
simple_lock(&bp->b_interlock);
SET(bp->b_flags, B_ASYNC);
simple_unlock(&bp->b_interlock);
splx(s);
VOP_BWRITE(bp);
}
@ -462,7 +485,10 @@ bdirty(bp)
struct proc *p = l->l_proc;
int s;
KASSERT(ISSET(bp->b_flags, B_BUSY));
s = splbio();
simple_lock(&bp->b_interlock);
CLR(bp->b_flags, B_AGE);
@ -472,6 +498,7 @@ bdirty(bp)
reassignbuf(bp, bp->b_vp);
}
simple_unlock(&bp->b_interlock);
splx(s);
}
@ -488,15 +515,17 @@ brelse(bp)
KASSERT(ISSET(bp->b_flags, B_BUSY));
/* Block disk interrupts. */
s = splbio();
simple_lock(&bqueue_slock);
simple_lock(&bp->b_interlock);
/* Wake up any processes waiting for any buffer to become free. */
if (needbuffer) {
needbuffer = 0;
wakeup(&needbuffer);
}
/* Block disk interrupts. */
s = splbio();
/* Wake up any proceeses waiting for _this_ buffer to become free. */
if (ISSET(bp->b_flags, B_WANTED)) {
CLR(bp->b_flags, B_WANTED|B_AGE);
@ -584,6 +613,8 @@ already_queued:
SET(bp->b_flags, B_CACHE);
/* Allow disk interrupts. */
simple_unlock(&bp->b_interlock);
simple_unlock(&bqueue_slock);
splx(s);
}
@ -629,17 +660,21 @@ getblk(vp, blkno, size, slpflag, slptimeo)
int s, err;
start:
s = splbio();
simple_lock(&bqueue_slock);
bp = incore(vp, blkno);
if (bp != NULL) {
s = splbio();
simple_lock(&bp->b_interlock);
if (ISSET(bp->b_flags, B_BUSY)) {
simple_unlock(&bqueue_slock);
if (curproc == uvm.pagedaemon_proc) {
simple_unlock(&bp->b_interlock);
splx(s);
return NULL;
}
SET(bp->b_flags, B_WANTED);
err = tsleep(bp, slpflag | (PRIBIO + 1), "getblk",
slptimeo);
err = ltsleep(bp, slpflag | (PRIBIO + 1) | PNORELOCK,
"getblk", slptimeo, &bp->b_interlock);
splx(s);
if (err)
return (NULL);
@ -652,17 +687,20 @@ start:
#endif
SET(bp->b_flags, B_BUSY);
bremfree(bp);
splx(s);
} else {
if ((bp = getnewbuf(slpflag, slptimeo)) == NULL)
if ((bp = getnewbuf(slpflag, slptimeo)) == NULL) {
simple_unlock(&bqueue_slock);
splx(s);
goto start;
}
binshash(bp, BUFHASH(vp, blkno));
bp->b_blkno = bp->b_lblkno = bp->b_rawblkno = blkno;
s = splbio();
bgetvp(vp, bp);
splx(s);
}
simple_unlock(&bp->b_interlock);
simple_unlock(&bqueue_slock);
splx(s);
allocbuf(bp, size);
return (bp);
}
@ -675,11 +713,18 @@ geteblk(size)
int size;
{
struct buf *bp;
int s;
s = splbio();
simple_lock(&bqueue_slock);
while ((bp = getnewbuf(0, 0)) == 0)
;
SET(bp->b_flags, B_INVAL);
binshash(bp, &invalhash);
simple_unlock(&bqueue_slock);
simple_unlock(&bp->b_interlock);
splx(s);
allocbuf(bp, size);
return (bp);
}
@ -717,12 +762,18 @@ allocbuf(bp, size)
int amt;
/* find a buffer */
s = splbio();
simple_lock(&bqueue_slock);
while ((nbp = getnewbuf(0, 0)) == NULL)
;
SET(nbp->b_flags, B_INVAL);
binshash(nbp, &invalhash);
simple_unlock(&nbp->b_interlock);
simple_unlock(&bqueue_slock);
splx(s);
/* and steal its pages, up to the amount we need */
amt = min(nbp->b_bufsize, (desired_size - bp->b_bufsize));
pagemove((nbp->b_data + nbp->b_bufsize - amt),
@ -738,7 +789,6 @@ allocbuf(bp, size)
if (nbp->b_bufsize < 0)
panic("allocbuf: negative bufsize");
#endif
brelse(nbp);
}
@ -750,13 +800,17 @@ allocbuf(bp, size)
*/
if (bp->b_bufsize > desired_size) {
s = splbio();
simple_lock(&bqueue_slock);
if ((nbp = TAILQ_FIRST(&bufqueues[BQ_EMPTY])) == NULL) {
/* No free buffer head */
simple_unlock(&bqueue_slock);
splx(s);
goto out;
}
/* No need to lock nbp since it came from the empty queue */
bremfree(nbp);
SET(nbp->b_flags, B_BUSY);
SET(nbp->b_flags, B_BUSY | B_INVAL);
simple_unlock(&bqueue_slock);
splx(s);
/* move the page to it and note this change */
@ -765,7 +819,6 @@ allocbuf(bp, size)
nbp->b_bufsize = bp->b_bufsize - desired_size;
bp->b_bufsize = desired_size;
nbp->b_bcount = 0;
SET(nbp->b_flags, B_INVAL);
/* release the newly-filled buffer and leave */
brelse(nbp);
@ -779,24 +832,28 @@ out:
* Find a buffer which is available for use.
* Select something from a free list.
* Preference is to AGE list, then LRU list.
*
* Called with buffer queues locked.
* Return buffer locked.
*/
struct buf *
getnewbuf(slpflag, slptimeo)
int slpflag, slptimeo;
{
struct buf *bp;
int s;
start:
s = splbio();
LOCK_ASSERT(simple_lock_held(&bqueue_slock));
if ((bp = TAILQ_FIRST(&bufqueues[BQ_AGE])) != NULL ||
(bp = TAILQ_FIRST(&bufqueues[BQ_LRU])) != NULL) {
simple_lock(&bp->b_interlock);
bremfree(bp);
} else {
/* wait for a free buffer of any kind */
needbuffer = 1;
tsleep(&needbuffer, slpflag|(PRIBIO+1), "getnewbuf", slptimeo);
splx(s);
ltsleep(&needbuffer, slpflag|(PRIBIO+1),
"getnewbuf", slptimeo, &bqueue_slock);
return (NULL);
}
@ -808,7 +865,7 @@ start:
*/
CLR(bp->b_flags, B_VFLUSH);
SET(bp->b_flags, B_AGE);
splx(s);
simple_unlock(&bp->b_interlock);
goto start;
}
@ -820,12 +877,12 @@ start:
* (since we might sleep while starting the write).
*/
if (ISSET(bp->b_flags, B_DELWRI)) {
splx(s);
/*
* This buffer has gone through the LRU, so make sure it gets
* reused ASAP.
*/
SET(bp->b_flags, B_AGE);
simple_unlock(&bp->b_interlock);
bawrite(bp);
return (NULL);
}
@ -833,7 +890,6 @@ start:
/* disassociate us from our vnode, if we had one... */
if (bp->b_vp)
brelvp(bp);
splx(s);
if (LIST_FIRST(&bp->b_dep) != NULL && bioops.io_deallocate)
(*bioops.io_deallocate)(bp);
@ -859,21 +915,25 @@ int
biowait(bp)
struct buf *bp;
{
int s;
int s, error;
s = splbio();
simple_lock(&bp->b_interlock);
while (!ISSET(bp->b_flags, B_DONE | B_DELWRI))
tsleep(bp, PRIBIO + 1, "biowait", 0);
splx(s);
ltsleep(bp, PRIBIO + 1, "biowait", 0, &bp->b_interlock);
/* check for interruption of I/O (e.g. via NFS), then errors. */
if (ISSET(bp->b_flags, B_EINTR)) {
CLR(bp->b_flags, B_EINTR);
return (EINTR);
error = EINTR;
} else if (ISSET(bp->b_flags, B_ERROR))
return (bp->b_error ? bp->b_error : EIO);
error = bp->b_error ? bp->b_error : EIO;
else
return (0);
error = 0;
simple_unlock(&bp->b_interlock);
splx(s);
return (error);
}
/*
@ -898,6 +958,7 @@ biodone(bp)
{
int s = splbio();
simple_lock(&bp->b_interlock);
if (ISSET(bp->b_flags, B_DONE))
panic("biodone already");
SET(bp->b_flags, B_DONE); /* note that it's done */
@ -908,15 +969,22 @@ biodone(bp)
if (!ISSET(bp->b_flags, B_READ)) /* wake up reader */
vwakeup(bp);
if (ISSET(bp->b_flags, B_CALL)) { /* if necessary, call out */
/*
* If necessary, call out. Unlock the buffer before calling
* iodone() as the buffer isn't valid any more when it return.
*/
if (ISSET(bp->b_flags, B_CALL)) {
CLR(bp->b_flags, B_CALL); /* but note callout done */
simple_unlock(&bp->b_interlock);
(*bp->b_iodone)(bp);
} else {
if (ISSET(bp->b_flags, B_ASYNC)) /* if async, release */
if (ISSET(bp->b_flags, B_ASYNC)) { /* if async, release */
simple_unlock(&bp->b_interlock);
brelse(bp);
else { /* or just wakeup the buffer */
} else { /* or just wakeup the buffer */
CLR(bp->b_flags, B_WANTED);
wakeup(bp);
simple_unlock(&bp->b_interlock);
}
}
@ -932,8 +1000,10 @@ count_lock_queue()
struct buf *bp;
int n = 0;
simple_lock(&bqueue_slock);
TAILQ_FOREACH(bp, &bufqueues[BQ_LOCKED], b_freelist)
n++;
simple_unlock(&bqueue_slock);
return (n);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: vfs_subr.c,v 1.186 2003/02/01 06:23:45 thorpej Exp $ */
/* $NetBSD: vfs_subr.c,v 1.187 2003/02/05 21:38:42 pk Exp $ */
/*-
* Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
@ -82,7 +82,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.186 2003/02/01 06:23:45 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.187 2003/02/05 21:38:42 pk Exp $");
#include "opt_ddb.h"
#include "opt_compat_netbsd.h"
@ -158,6 +158,9 @@ struct simplelock mntvnode_slock = SIMPLELOCK_INITIALIZER;
struct simplelock vnode_free_list_slock = SIMPLELOCK_INITIALIZER;
struct simplelock spechash_slock = SIMPLELOCK_INITIALIZER;
/* XXX - gross; single global lock to protect v_numoutput */
struct simplelock global_v_numoutput_slock = SIMPLELOCK_INITIALIZER;
/*
* These define the root filesystem and device.
*/
@ -640,12 +643,18 @@ vwakeup(bp)
struct vnode *vp;
if ((vp = bp->b_vp) != NULL) {
/* XXX global lock hack
* can't use v_interlock here since this is called
* in interrupt context from biodone().
*/
simple_lock(&global_v_numoutput_slock);
if (--vp->v_numoutput < 0)
panic("vwakeup: neg numoutput, vp %p", vp);
if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) {
vp->v_flag &= ~VBWAIT;
wakeup((caddr_t)&vp->v_numoutput);
}
simple_unlock(&global_v_numoutput_slock);
}
}
@ -691,10 +700,12 @@ vinvalbuf(vp, flags, cred, p, slpflag, slptimeo)
restart:
for (bp = LIST_FIRST(&vp->v_cleanblkhd); bp; bp = nbp) {
nbp = LIST_NEXT(bp, b_vnbufs);
simple_lock(&bp->b_interlock);
if (bp->b_flags & B_BUSY) {
bp->b_flags |= B_WANTED;
error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1),
"vinvalbuf", slptimeo);
error = ltsleep((caddr_t)bp,
slpflag | (PRIBIO + 1) | PNORELOCK,
"vinvalbuf", slptimeo, &bp->b_interlock);
if (error) {
splx(s);
return (error);
@ -702,15 +713,18 @@ restart:
goto restart;
}
bp->b_flags |= B_BUSY | B_INVAL | B_VFLUSH;
simple_unlock(&bp->b_interlock);
brelse(bp);
}
for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
nbp = LIST_NEXT(bp, b_vnbufs);
simple_lock(&bp->b_interlock);
if (bp->b_flags & B_BUSY) {
bp->b_flags |= B_WANTED;
error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1),
"vinvalbuf", slptimeo);
error = ltsleep((caddr_t)bp,
slpflag | (PRIBIO + 1) | PNORELOCK,
"vinvalbuf", slptimeo, &bp->b_interlock);
if (error) {
splx(s);
return (error);
@ -727,10 +741,12 @@ restart:
printf("buffer still DELWRI\n");
#endif
bp->b_flags |= B_BUSY | B_VFLUSH;
simple_unlock(&bp->b_interlock);
VOP_BWRITE(bp);
goto restart;
}
bp->b_flags |= B_BUSY | B_INVAL | B_VFLUSH;
simple_unlock(&bp->b_interlock);
brelse(bp);
}
@ -773,10 +789,11 @@ restart:
nbp = LIST_NEXT(bp, b_vnbufs);
if (bp->b_lblkno < lbn)
continue;
simple_lock(&bp->b_interlock);
if (bp->b_flags & B_BUSY) {
bp->b_flags |= B_WANTED;
error = tsleep(bp, slpflag | (PRIBIO + 1),
"vtruncbuf", slptimeo);
error = ltsleep(bp, slpflag | (PRIBIO + 1) | PNORELOCK,
"vtruncbuf", slptimeo, &bp->b_interlock);
if (error) {
splx(s);
return (error);
@ -784,6 +801,7 @@ restart:
goto restart;
}
bp->b_flags |= B_BUSY | B_INVAL | B_VFLUSH;
simple_unlock(&bp->b_interlock);
brelse(bp);
}
@ -791,10 +809,11 @@ restart:
nbp = LIST_NEXT(bp, b_vnbufs);
if (bp->b_lblkno < lbn)
continue;
simple_lock(&bp->b_interlock);
if (bp->b_flags & B_BUSY) {
bp->b_flags |= B_WANTED;
error = tsleep(bp, slpflag | (PRIBIO + 1),
"vtruncbuf", slptimeo);
error = ltsleep(bp, slpflag | (PRIBIO + 1) | PNORELOCK,
"vtruncbuf", slptimeo, &bp->b_interlock);
if (error) {
splx(s);
return (error);
@ -802,6 +821,7 @@ restart:
goto restart;
}
bp->b_flags |= B_BUSY | B_INVAL | B_VFLUSH;
simple_unlock(&bp->b_interlock);
brelse(bp);
}
@ -826,11 +846,15 @@ loop:
s = splbio();
for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
nbp = LIST_NEXT(bp, b_vnbufs);
if ((bp->b_flags & B_BUSY))
simple_lock(&bp->b_interlock);
if ((bp->b_flags & B_BUSY)) {
simple_unlock(&bp->b_interlock);
continue;
}
if ((bp->b_flags & B_DELWRI) == 0)
panic("vflushbuf: not dirty, bp %p", bp);
bp->b_flags |= B_BUSY | B_VFLUSH;
simple_unlock(&bp->b_interlock);
splx(s);
/*
* Wait for I/O associated with indirect blocks to complete,
@ -846,10 +870,13 @@ loop:
splx(s);
return;
}
simple_lock(&global_v_numoutput_slock);
while (vp->v_numoutput) {
vp->v_flag |= VBWAIT;
tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "vflushbuf", 0);
ltsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "vflushbuf", 0,
&global_v_numoutput_slock);
}
simple_unlock(&global_v_numoutput_slock);
splx(s);
if (!LIST_EMPTY(&vp->v_dirtyblkhd)) {
vprint("vflushbuf: dirty", vp);

View File

@ -1,4 +1,4 @@
/* $NetBSD: genfs_vnops.c,v 1.70 2003/01/21 00:01:14 christos Exp $ */
/* $NetBSD: genfs_vnops.c,v 1.71 2003/02/05 21:38:42 pk Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: genfs_vnops.c,v 1.70 2003/01/21 00:01:14 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: genfs_vnops.c,v 1.71 2003/02/05 21:38:42 pk Exp $");
#include "opt_nfsserver.h"
@ -653,6 +653,7 @@ genfs_getpages(void *v)
s = splbio();
mbp = pool_get(&bufpool, PR_WAITOK);
splx(s);
simple_lock_init(&mbp->b_interlock);
mbp->b_bufsize = totalbytes;
mbp->b_data = (void *)kva;
mbp->b_resid = mbp->b_bcount = bytes;
@ -786,6 +787,7 @@ genfs_getpages(void *v)
s = splbio();
bp = pool_get(&bufpool, PR_WAITOK);
splx(s);
simple_lock_init(&bp->b_interlock);
bp->b_data = (char *)kva + offset - startoffset;
bp->b_resid = bp->b_bcount = iobytes;
bp->b_flags = B_BUSY|B_READ|B_CALL|B_ASYNC;
@ -1067,7 +1069,9 @@ genfs_putpages(void *v)
error = 0;
s = splbio();
simple_lock(&global_v_numoutput_slock);
wasclean = (vp->v_numoutput == 0);
simple_unlock(&global_v_numoutput_slock);
splx(s);
off = startoff;
if (endoff == 0 || flags & PGO_ALLPAGES) {
@ -1341,10 +1345,16 @@ genfs_putpages(void *v)
splx(s);
if (!wasclean && !async) {
s = splbio();
/*
* XXX - we want simple_unlock(&global_v_numoutput_slock);
* but the slot in ltsleep() is taken!
* XXX - try to recover from missed wakeups with a timeout..
* must think of something better.
*/
while (vp->v_numoutput != 0) {
vp->v_flag |= VBWAIT;
UVM_UNLOCK_AND_WAIT(&vp->v_numoutput, slock, FALSE,
"genput2", 0);
"genput2", hz);
simple_lock(slock);
}
splx(s);
@ -1390,8 +1400,11 @@ genfs_gop_write(struct vnode *vp, struct vm_page **pgs, int npages, int flags)
UVMPAGER_MAPIN_WRITE | UVMPAGER_MAPIN_WAITOK);
s = splbio();
simple_lock(&global_v_numoutput_slock);
vp->v_numoutput += 2;
simple_unlock(&global_v_numoutput_slock);
mbp = pool_get(&bufpool, PR_WAITOK);
simple_lock_init(&mbp->b_interlock);
UVMHIST_LOG(ubchist, "vp %p mbp %p num now %d bytes 0x%x",
vp, mbp, vp->v_numoutput, bytes);
splx(s);
@ -1428,11 +1441,12 @@ genfs_gop_write(struct vnode *vp, struct vm_page **pgs, int npages, int flags)
bp = mbp;
} else {
s = splbio();
vp->v_numoutput++;
V_INCR_NUMOUTPUT(vp);
bp = pool_get(&bufpool, PR_WAITOK);
UVMHIST_LOG(ubchist, "vp %p bp %p num now %d",
vp, bp, vp->v_numoutput, 0);
splx(s);
simple_lock_init(&bp->b_interlock);
bp->b_data = (char *)kva +
(vaddr_t)(offset - pg->offset);
bp->b_resid = bp->b_bcount = iobytes;
@ -1635,10 +1649,11 @@ genfs_compat_gop_write(struct vnode *vp, struct vm_page **pgs, int npages,
error = VOP_WRITE(vp, &uio, 0, cred);
s = splbio();
vp->v_numoutput++;
V_INCR_NUMOUTPUT(vp);
bp = pool_get(&bufpool, PR_WAITOK);
splx(s);
simple_lock_init(&bp->b_interlock);
bp->b_flags = B_BUSY | B_WRITE | B_AGE;
bp->b_vp = vp;
bp->b_lblkno = offset >> vp->v_mount->mnt_fs_bshift;

View File

@ -1,4 +1,4 @@
/* $NetBSD: buf.h,v 1.56 2003/02/01 21:07:02 erh Exp $ */
/* $NetBSD: buf.h,v 1.57 2003/02/05 21:38:43 pk Exp $ */
/*-
* Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
@ -82,6 +82,7 @@
#include <sys/pool.h>
#include <sys/queue.h>
#include <sys/lock.h>
struct buf;
struct mount;
@ -158,6 +159,7 @@ struct buf {
TAILQ_ENTRY(buf) b_actq; /* Device driver queue when active. */
struct proc *b_proc; /* Associated proc if B_PHYS set. */
volatile long b_flags; /* B_* flags. */
struct simplelock b_interlock; /* Lock for b_flags changes */
int b_error; /* Errno value. */
long b_bufsize; /* Allocated buffer size. */
long b_bcount; /* Valid bytes in buffer. */

View File

@ -1,4 +1,4 @@
/* $NetBSD: vnode.h,v 1.102 2003/02/01 06:23:52 thorpej Exp $ */
/* $NetBSD: vnode.h,v 1.103 2003/02/05 21:38:43 pk Exp $ */
/*
* Copyright (c) 1989, 1993
@ -156,6 +156,18 @@ struct vnode {
#define VSIZENOTSET ((voff_t)-1)
/*
* Use a global lock for all v_numoutput updates.
* Define a convenience macro to increment by one.
* Note: the only place where v_numoutput is decremented is in vwakeup().
*/
extern struct simplelock global_v_numoutput_slock;
#define V_INCR_NUMOUTPUT(vp) do { \
simple_lock(&global_v_numoutput_slock); \
(vp)->v_numoutput++; \
simple_unlock(&global_v_numoutput_slock); \
} while (/*CONSTCOND*/ 0)
/*
* Valid states for the fingerprint flag - if signed exec is being used
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: ffs_softdep.c,v 1.43 2003/02/01 06:23:52 thorpej Exp $ */
/* $NetBSD: ffs_softdep.c,v 1.44 2003/02/05 21:38:43 pk Exp $ */
/*
* Copyright 1998 Marshall Kirk McKusick. All Rights Reserved.
@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ffs_softdep.c,v 1.43 2003/02/01 06:23:52 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: ffs_softdep.c,v 1.44 2003/02/05 21:38:43 pk Exp $");
#include <sys/param.h>
#include <sys/buf.h>
@ -5226,14 +5226,17 @@ drain_output(vp, islocked)
if (!islocked)
ACQUIRE_LOCK(&lk);
simple_lock(&global_v_numoutput_slock);
while (vp->v_numoutput) {
int s;
vp->v_flag |= VBWAIT;
s = FREE_LOCK_INTERLOCKED(&lk);
tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "drainvp", 0);
ltsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "drainvp", 0,
&global_v_numoutput_slock);
ACQUIRE_LOCK_INTERLOCKED(&lk, s);
}
simple_unlock(&global_v_numoutput_slock);
if (!islocked)
FREE_LOCK(&lk);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ffs_vnops.c,v 1.53 2003/01/29 03:06:40 simonb Exp $ */
/* $NetBSD: ffs_vnops.c,v 1.54 2003/02/05 21:38:44 pk Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@ -36,7 +36,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.53 2003/01/29 03:06:40 simonb Exp $");
__KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.54 2003/02/05 21:38:44 pk Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -306,10 +306,13 @@ ffs_fsync(v)
}
if (ap->a_flags & FSYNC_WAIT) {
simple_lock(&global_v_numoutput_slock);
while (vp->v_numoutput > 0) {
vp->v_flag |= VBWAIT;
tsleep(&vp->v_numoutput, PRIBIO + 1, "fsync_range", 0);
ltsleep(&vp->v_numoutput, PRIBIO + 1, "fsync_range", 0,
&global_v_numoutput_slock);
}
simple_unlock(&global_v_numoutput_slock);
}
splx(s);
@ -398,11 +401,13 @@ loop:
goto loop;
}
if (ap->a_flags & FSYNC_WAIT) {
simple_lock(&global_v_numoutput_slock);
while (vp->v_numoutput) {
vp->v_flag |= VBWAIT;
(void) tsleep(&vp->v_numoutput, PRIBIO + 1,
"ffsfsync", 0);
(void) ltsleep(&vp->v_numoutput, PRIBIO + 1,
"ffsfsync", 0, &global_v_numoutput_slock);
}
simple_unlock(&global_v_numoutput_slock);
splx(s);
if (ap->a_flags & FSYNC_DATAONLY)

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_bio.c,v 1.56 2003/01/24 21:55:26 fvdl Exp $ */
/* $NetBSD: lfs_bio.c,v 1.57 2003/02/05 21:38:45 pk Exp $ */
/*-
* Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
@ -71,7 +71,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_bio.c,v 1.56 2003/01/24 21:55:26 fvdl Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_bio.c,v 1.57 2003/02/05 21:38:45 pk Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -641,10 +641,11 @@ lfs_newbuf(struct lfs *fs, struct vnode *vp, daddr_t daddr, size_t size)
if (bp == NULL)
panic("bp is NULL after malloc in lfs_newbuf");
#endif
simple_lock_init(&bp->b_interlock);
s = splbio();
bgetvp(vp, bp);
splx(s);
bp->b_saveaddr = (caddr_t)fs;
bp->b_bufsize = size;
bp->b_bcount = size;

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_segment.c,v 1.99 2003/02/01 06:23:53 thorpej Exp $ */
/* $NetBSD: lfs_segment.c,v 1.100 2003/02/05 21:38:45 pk Exp $ */
/*-
* Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
@ -71,7 +71,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_segment.c,v 1.99 2003/02/01 06:23:53 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_segment.c,v 1.100 2003/02/05 21:38:45 pk Exp $");
#define ivndebug(vp,str) printf("ino %d: %s\n",VTOI(vp)->i_number,(str))
@ -1492,6 +1492,7 @@ lookahead_pagemove(struct buf **bpp, int nblocks, size_t *size)
#define BQUEUES 4 /* XXX */
#define BQ_EMPTY 3 /* XXX */
extern TAILQ_HEAD(bqueues, buf) bufqueues[BQUEUES];
extern struct simplelock bqueue_slock;
#define BUFHASH(dvp, lbn) \
(&bufhashtbl[((long)(dvp) / sizeof(*(dvp)) + (int)(lbn)) & bufhash])
@ -1527,7 +1528,9 @@ lfs_newclusterbuf(struct lfs *fs, struct vnode *vp, daddr_t addr, int n)
/* Get an empty buffer header, or maybe one with something on it */
s = splbio();
simple_lock(&bqueue_slock);
if((bp = bufqueues[BQ_EMPTY].tqh_first) != NULL) {
simple_lock(&bp->b_interlock);
bremfree(bp);
/* clear out various other fields */
bp->b_flags = B_BUSY;
@ -1546,12 +1549,12 @@ lfs_newclusterbuf(struct lfs *fs, struct vnode *vp, daddr_t addr, int n)
if (bp->b_vp)
brelvp(bp);
}
splx(s);
while (!bp)
bp = getnewbuf(0, 0);
s = splbio();
bgetvp(vp, bp);
binshash(bp,&invalhash);
simple_unlock(&bp->b_interlock);
simple_unlock(&bqueue_slock);
splx(s);
bp->b_bcount = 0;
bp->b_blkno = bp->b_lblkno = addr;
@ -1917,7 +1920,7 @@ lfs_writeseg(struct lfs *fs, struct segment *sp)
cl->bpp[cl->bufcount++] = bp;
vp = bp->b_vp;
s = splbio();
++vp->v_numoutput;
V_INCR_NUMOUTPUT(vp);
splx(s);
/*
@ -1972,7 +1975,7 @@ lfs_writeseg(struct lfs *fs, struct segment *sp)
wakeup(vp);
}
s = splbio();
++cbp->b_vp->v_numoutput;
V_INCR_NUMOUTPUT(cbp->b_vp);
splx(s);
/*
* In order to include the summary in a clustered block,
@ -2046,7 +2049,7 @@ lfs_writesuper(struct lfs *fs, daddr_t daddr)
vop_strategy_a.a_desc = VDESC(vop_strategy);
vop_strategy_a.a_bp = bp;
s = splbio();
++bp->b_vp->v_numoutput;
V_INCR_NUMOUTPUT(bp->b_vp);
splx(s);
++fs->lfs_iocount;
(strategy)(&vop_strategy_a);

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm_swap.c,v 1.75 2003/02/01 06:23:55 thorpej Exp $ */
/* $NetBSD: uvm_swap.c,v 1.76 2003/02/05 21:38:46 pk Exp $ */
/*
* Copyright (c) 1995, 1996, 1997 Matthew R. Green
@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uvm_swap.c,v 1.75 2003/02/01 06:23:55 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: uvm_swap.c,v 1.76 2003/02/05 21:38:46 pk Exp $");
#include "fs_nfs.h"
#include "opt_uvmhist.h"
@ -1168,7 +1168,7 @@ swstrategy(bp)
*/
if ((bp->b_flags & B_READ) == 0) {
vwakeup(bp); /* kills one 'v_numoutput' on drum */
vp->v_numoutput++; /* put it on swapdev */
V_INCR_NUMOUTPUT(vp); /* put it on swapdev */
}
/*
@ -1286,6 +1286,7 @@ sw_reg_strategy(sdp, bp, bn)
* cast pointers between the two structure easily.
*/
getvndbuf(nbp);
simple_lock_init(&nbp->vb_buf.b_interlock);
nbp->vb_buf.b_flags = bp->b_flags | B_CALL;
nbp->vb_buf.b_bcount = sz;
nbp->vb_buf.b_bufsize = sz;
@ -1368,7 +1369,7 @@ sw_reg_start(sdp)
"sw_reg_start: bp %p vp %p blkno %p cnt %lx",
bp, bp->b_vp, bp->b_blkno, bp->b_bcount);
if ((bp->b_flags & B_READ) == 0)
bp->b_vp->v_numoutput++;
V_INCR_NUMOUTPUT(bp->b_vp);
VOP_STRATEGY(bp);
}
@ -1698,6 +1699,7 @@ uvm_swap_io(pps, startslot, npages, flags)
* /dev/drum's vnode [swapdev_vp].
*/
simple_lock_init(&bp->b_interlock);
bp->b_flags = B_BUSY | B_NOCACHE | (flags & (B_READ|B_ASYNC));
bp->b_proc = &proc0; /* XXX */
bp->b_vnbufs.le_next = NOLIST;
@ -1714,7 +1716,7 @@ uvm_swap_io(pps, startslot, npages, flags)
if (write) {
s = splbio();
swapdev_vp->v_numoutput++;
V_INCR_NUMOUTPUT(swapdev_vp);
splx(s);
}