svn commit: r328963 - user/jeff/numa/sys/kern

Jeff Roberson jeff at FreeBSD.org
Wed Feb 7 01:24:50 UTC 2018


Author: jeff
Date: Wed Feb  7 01:24:49 2018
New Revision: 328963
URL: https://svnweb.freebsd.org/changeset/base/328963

Log:
  The buf queue may change while the buf is locked.  This can only occur when
  it is being pushed from a per-cpu queue to the cleanq.  Detect this
  condition in bufqueue_acquire().
  
  Reported by:	pho

Modified:
  user/jeff/numa/sys/kern/vfs_bio.c

Modified: user/jeff/numa/sys/kern/vfs_bio.c
==============================================================================
--- user/jeff/numa/sys/kern/vfs_bio.c	Wed Feb  7 00:50:40 2018	(r328962)
+++ user/jeff/numa/sys/kern/vfs_bio.c	Wed Feb  7 01:24:49 2018	(r328963)
@@ -1309,6 +1309,7 @@ static struct bufqueue *
 bufqueue(struct buf *bp)
 {
 	struct bufdomain *bd;
+	int cpu;
 
 	switch (bp->b_qindex) {
 	case QUEUE_NONE:
@@ -1326,10 +1327,37 @@ bufqueue(struct buf *bp)
 		panic("bufqueue(%p): Unhandled type %d\n", bp, bp->b_qindex);
 	}
 	bd = &bdclean[bp->b_domain];
-	if (bp->b_cpu > mp_maxid)
+	/* cpu may be changed by bd_flush().  Read it only once. */
+	cpu = bp->b_cpu;
+	if (cpu > mp_maxid)
 		return (&bd->bd_cleanq);
-	return (&bd->bd_cpuq[bp->b_cpu]);
+	return (&bd->bd_cpuq[cpu]);
+}
 
+/*
+ * Return the locked bufqueue that bp is a member of.
+ */
+static struct bufqueue *
+bufqueue_acquire(struct buf *bp)
+{
+	struct bufqueue *bq, *nbq;
+
+	/*
+	 * bp can be pushed from a per-cpu queue to the
+	 * cleanq while we're waiting on the lock.  Retry
+	 * if the queues don't match.
+	 */
+	bq = bufqueue(bp);
+	BQ_LOCK(bq);
+	for (;;) {
+		nbq = bufqueue(bp);
+		if (bq == nbq)
+			break;
+		BQ_UNLOCK(bq);
+		BQ_LOCK(nbq);
+		bq = nbq;
+	}
+	return (bq);
 }
 
 /*
@@ -1358,8 +1386,7 @@ binsfree(struct buf *bp, int qindex)
 			BUF_UNLOCK(bp);
 			return;
 		}
-		bq = bufqueue(bp);
-		BQ_LOCK(bq);
+		bq = bufqueue_acquire(bp);
 		bq_remove(bq, bp);
 		BQ_UNLOCK(bq);
 	}
@@ -1647,8 +1674,7 @@ bremfreef(struct buf *bp)
 {
 	struct bufqueue *bq;
 
-	bq = bufqueue(bp);
-	BQ_LOCK(bq);
+	bq = bufqueue_acquire(bp);
 	bq_remove(bq, bp);
 	BQ_UNLOCK(bq);
 }


More information about the svn-src-user mailing list