summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authormckusick <mckusick@FreeBSD.org>2002-10-18 01:29:59 +0000
committermckusick <mckusick@FreeBSD.org>2002-10-18 01:29:59 +0000
commitbe6aa51161630ed8a0ed7ec35ada58df12bc0677 (patch)
tree6b53730e28da101ae4a5437b5db2675993293fa1 /sys
parent0af0d22682bd7c7945dec2667a87357a9346f82d (diff)
downloadFreeBSD-src-be6aa51161630ed8a0ed7ec35ada58df12bc0677.zip
FreeBSD-src-be6aa51161630ed8a0ed7ec35ada58df12bc0677.tar.gz
When the number of dirty buffers rises too high, the buf_daemon runs
to help clean up. After selecting a potential buffer to write, this patch has it acquire a lock on the vnode that owns the buffer before trying to write it. The vnode lock is necessary to avoid a race with some other process holding the vnode locked and trying to flush its dirty buffers. In particular, if the vnode in question is a snapshot file, then the race can lead to a deadlock. To avoid slowing down the buf_daemon, it does a non-blocking lock request when trying to lock the vnode. If it fails to get the lock it skips over the buffer and continues down its queue looking for buffers to flush. Sponsored by: DARPA & NAI Labs.
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/vfs_bio.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c
index d53e532..4c25621 100644
--- a/sys/kern/vfs_bio.c
+++ b/sys/kern/vfs_bio.c
@@ -2042,6 +2042,8 @@ buf_daemon()
static int
flushbufqueues(void)
{
+ struct thread *td = curthread;
+ struct vnode *vp;
struct buf *bp;
int r = 0;
@@ -2070,9 +2072,21 @@ flushbufqueues(void)
bp = TAILQ_FIRST(&bufqueues[QUEUE_DIRTY]);
continue;
}
- vfs_bio_awrite(bp);
- ++r;
- break;
+ /*
+ * We must hold the lock on a vnode before writing
+ * one of its buffers. Otherwise we may confuse, or
+ * in the case of a snapshot vnode, deadlock the
+ * system. Rather than blocking waiting for the
+ * vnode, we just push on to the next buffer.
+ */
+ if ((vp = bp->b_vp) == NULL ||
+ vn_lock(vp, LK_EXCLUSIVE | LK_NOWAIT, td) == 0) {
+ vfs_bio_awrite(bp);
+ ++r;
+ if (vp != NULL)
+ VOP_UNLOCK(vp, 0, td);
+ break;
+ }
}
bp = TAILQ_NEXT(bp, b_freelist);
}
OpenPOWER on IntegriCloud