summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2013-02-27 07:34:09 +0000
committerkib <kib@FreeBSD.org>2013-02-27 07:34:09 +0000
commit4bffdc6be720eb93176e86c7b9c1c54e8749ebb5 (patch)
tree8df71fb8d7a1a41ceafe22fe0100b2ffb83a0935
parent85115264a0ce0884fa30a442870f1a689aa87c58 (diff)
downloadFreeBSD-src-4bffdc6be720eb93176e86c7b9c1c54e8749ebb5.zip
FreeBSD-src-4bffdc6be720eb93176e86c7b9c1c54e8749ebb5.tar.gz
Make recursive getblk() slightly more useful. Keep the buffer state
intact if getblk() is done on the already owned buffer. Exit from brelse() early when the lock recursion is detected, otherwise brelse() might prematurely destroy the buffer under some circumstances. Sponsored by: The FreeBSD Foundation Noted by: mckusick Tested by: pho MFC after: 2 weeks
-rw-r--r--sys/kern/vfs_bio.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c
index 6393399..f9b4dbb 100644
--- a/sys/kern/vfs_bio.c
+++ b/sys/kern/vfs_bio.c
@@ -1268,6 +1268,15 @@ brelse(struct buf *bp)
KASSERT(!(bp->b_flags & (B_CLUSTER|B_PAGING)),
("brelse: inappropriate B_PAGING or B_CLUSTER bp %p", bp));
+ if (BUF_LOCKRECURSED(bp)) {
+ /*
+ * Do not process, in particular, do not handle the
+ * B_INVAL/B_RELBUF and do not release to free list.
+ */
+ BUF_UNLOCK(bp);
+ return;
+ }
+
if (bp->b_flags & B_MANAGED) {
bqrelse(bp);
return;
@@ -1444,12 +1453,6 @@ brelse(struct buf *bp)
brelvp(bp);
}
- if (BUF_LOCKRECURSED(bp)) {
- /* do not release to free list */
- BUF_UNLOCK(bp);
- return;
- }
-
/* enqueue */
mtx_lock(&bqlock);
/* Handle delayed bremfree() processing. */
@@ -2681,6 +2684,9 @@ loop:
/* We timed out or were interrupted. */
else if (error)
return (NULL);
+ /* If recursed, assume caller knows the rules. */
+ else if (BUF_LOCKRECURSED(bp))
+ goto end;
/*
* The buffer is locked. B_CACHE is cleared if the buffer is
@@ -2864,6 +2870,7 @@ loop:
}
CTR4(KTR_BUF, "getblk(%p, %ld, %d) = %p", vp, (long)blkno, size, bp);
BUF_ASSERT_HELD(bp);
+end:
KASSERT(bp->b_bufobj == bo,
("bp %p wrong b_bufobj %p should be %p", bp, bp->b_bufobj, bo));
return (bp);
OpenPOWER on IntegriCloud