more locks..

Paul Kranenburg <[email protected]>
Newsgroups gmane.os.netbsd.devel.smp
Message-ID <[email protected]>
I've looked into making several kernel modules MP-safer. Attached is
a set of diffs for the buffer cache (mostly vfs_bio.c) for your
inspection.  With this patch, my 2-cpu machine can run the buffer cache
code concurrently, although I didn't push it very hard (just ffs & lfs
on a scsi disk).

Note that the patch omits bunch of files that need trivial changes, such
as initing a buffer's simple lock.

-pk
DIFF (text/plain, 17.2 KB)
Index: sys/buf.h
===================================================================
RCS file: /cvsroot/src/sys/sys/buf.h,v
retrieving revision 1.56
diff -u -r1.56 buf.h
--- sys/buf.h	2003/02/01 21:07:02	1.56
+++ sys/buf.h	2003/02/02 22:27:07
@@ -82,6 +82,7 @@
 
 #include <sys/pool.h>
 #include <sys/queue.h>
+#include <sys/lock.h>
 
 struct buf;
 struct mount;
@@ -158,6 +159,7 @@
 	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. */
Index: kern/vfs_bio.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_bio.c,v
retrieving revision 1.86
diff -u -r1.86 vfs_bio.c
--- kern/vfs_bio.c	2003/01/18 10:06:37	1.86
+++ kern/vfs_bio.c	2003/02/02 22:27:17
@@ -103,26 +103,35 @@
 int needbuffer;
 
 /*
+ * Buffer queue lock.
+ * Take this lock first if also taking some buffer's b_interlock.
+ */
+struct simplelock bqueue_slock = SIMPLELOCK_INITIALIZER;
+extern struct simplelock global_v_numoutput_slock;/*XXX*/
+
+/*
  * 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 +149,6 @@
 			panic("bremfree: lost tail");
 	}
 	TAILQ_REMOVE(dp, bp, b_freelist);
-	splx(s);
 }
 
 /*
@@ -168,6 +176,7 @@
 	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 +215,7 @@
 	/*
 	 * 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 +316,8 @@
 	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 +356,7 @@
 	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 +370,10 @@
 		p->p_stats->p_ru.ru_oublock++;
 
 	/* Initiate disk write.  Make sure the appropriate party is charged. */
+	simple_lock(&global_v_numoutput_slock);
 	bp->b_vp->v_numoutput++;
+	simple_unlock(&global_v_numoutput_slock);
+	simple_unlock(&bp->b_interlock);
 	splx(s);
 
 	VOP_STRATEGY(bp);
@@ -407,6 +422,8 @@
 	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 +442,7 @@
 	 *	(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 +452,7 @@
 
 	/* 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 +465,15 @@
 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 +488,10 @@
 	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 +501,7 @@
 		reassignbuf(bp, bp->b_vp);
 	}
 
+	simple_unlock(&bp->b_interlock);
 	splx(s);
 }
 
@@ -488,15 +518,17 @@
 
 	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 +616,8 @@
 	SET(bp->b_flags, B_CACHE);
 
 	/* Allow disk interrupts. */
+	simple_unlock(&bp->b_interlock);
+	simple_unlock(&bqueue_slock);
 	splx(s);
 }
 
@@ -629,17 +663,21 @@
 	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 +690,20 @@
 #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 +716,18 @@
 	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 +765,18 @@
 		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 +792,6 @@
 		if (nbp->b_bufsize < 0)
 			panic("allocbuf: negative bufsize");
 #endif
-
 		brelse(nbp);
 	}
 
@@ -750,13 +803,17 @@
 	 */
 	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 +822,6 @@
 		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 +835,28 @@
  * 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 +868,7 @@
 		 */
 		CLR(bp->b_flags, B_VFLUSH);
 		SET(bp->b_flags, B_AGE);
-		splx(s);
+		simple_unlock(&bp->b_interlock);
 		goto start;
 	}
 
@@ -820,12 +880,12 @@
 	 * (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 +893,6 @@
 	/* 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 +918,25 @@
 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 +961,7 @@
 {
 	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 */
@@ -910,12 +974,15 @@
 
 	if (ISSET(bp->b_flags, B_CALL)) {	/* if necessary, call out */
 		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);
+			simple_unlock(&bp->b_interlock);
 			wakeup(bp);
 		}
 	}
@@ -932,8 +999,10 @@
 	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);
 }
 
Index: kern/vfs_subr.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_subr.c,v
retrieving revision 1.186
diff -u -r1.186 vfs_subr.c
--- kern/vfs_subr.c	2003/02/01 06:23:45	1.186
+++ kern/vfs_subr.c	2003/02/02 22:27:36
@@ -158,6 +158,9 @@
 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 @@
 	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 @@
 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 @@
 			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 @@
 			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 @@
 		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 @@
 			goto restart;
 		}
 		bp->b_flags |= B_BUSY | B_INVAL | B_VFLUSH;
+		simple_unlock(&bp->b_interlock);
 		brelse(bp);
 	}
 
@@ -791,10 +809,11 @@
 		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 @@
 			goto restart;
 		}
 		bp->b_flags |= B_BUSY | B_INVAL | B_VFLUSH;
+		simple_unlock(&bp->b_interlock);
 		brelse(bp);
 	}
 
@@ -826,11 +846,15 @@
 	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 @@
 		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);
Index: ufs/lfs/lfs_bio.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/lfs/lfs_bio.c,v
retrieving revision 1.56
diff -u -r1.56 lfs_bio.c
--- ufs/lfs/lfs_bio.c	2003/01/24 21:55:26	1.56
+++ ufs/lfs/lfs_bio.c	2003/02/02 22:27:41
@@ -641,10 +641,11 @@
 	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;
Index: ufs/lfs/lfs_segment.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/lfs/lfs_segment.c,v
retrieving revision 1.99
diff -u -r1.99 lfs_segment.c
--- ufs/lfs/lfs_segment.c	2003/02/01 06:23:53	1.99
+++ ufs/lfs/lfs_segment.c	2003/02/02 22:27:59
@@ -1492,6 +1492,7 @@
 #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 @@
 
 	/* 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 @@
 		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;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.