summaryrefslogtreecommitdiffstats
path: root/sys/ufs/ffs/ffs_vnops.c
diff options
context:
space:
mode:
authormckusick <mckusick@FreeBSD.org>1999-03-02 04:04:31 +0000
committermckusick <mckusick@FreeBSD.org>1999-03-02 04:04:31 +0000
commit421edf71f1c11fc1f4e4eebde19e73440f5ebcb4 (patch)
treef7a7ec5c1003926102a7c6c0fa6a68c2807f7171 /sys/ufs/ffs/ffs_vnops.c
parentdd79f1e6154b7bb83ec464b5b26b02cd1039fa3e (diff)
downloadFreeBSD-src-421edf71f1c11fc1f4e4eebde19e73440f5ebcb4.zip
FreeBSD-src-421edf71f1c11fc1f4e4eebde19e73440f5ebcb4.tar.gz
When fsync'ing a file on a filesystem using soft updates, we first try
to write all the dirty blocks. If some of those blocks have dependencies, they will be remarked dirty when the I/O completes. On systems with really fast I/O systems, it is possible to get in an infinite loop trying to flush the buffers, because the I/O finishes before we can get all the dirty buffers off the v_dirtyblkhd list and into the I/O queue. (The previous algorithm looped over the v_dirtyblkhd list writing out buffers until the list emptied.) So, now we mark each buffer that we try to write so that we can distinguish the ones that are being remarked dirty from those that we have not yet tried to flush. Once we have tried to push every buffer once, we then push any associated metadata that is causing the remaining buffers to be redirtied. Submitted by: Matthew Dillon <dillon@apollo.backplane.com>
Diffstat (limited to 'sys/ufs/ffs/ffs_vnops.c')
-rw-r--r--sys/ufs/ffs/ffs_vnops.c28
1 files changed, 18 insertions, 10 deletions
diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c
index 1823c0f..c44b133 100644
--- a/sys/ufs/ffs/ffs_vnops.c
+++ b/sys/ufs/ffs/ffs_vnops.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)ffs_vnops.c 8.15 (Berkeley) 5/14/95
- * $Id: ffs_vnops.c,v 1.53 1998/10/31 15:31:27 peter Exp $
+ * $Id: ffs_vnops.c,v 1.54 1999/01/07 16:14:17 bde Exp $
*/
#include <sys/param.h>
@@ -142,9 +142,11 @@ ffs_fsync(ap)
skipmeta = 0;
if (ap->a_waitfor == MNT_WAIT)
skipmeta = 1;
-loop:
s = splbio();
-loop2:
+loop:
+ for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp;
+ bp = TAILQ_NEXT(bp, b_vnbufs))
+ bp->b_flags &= ~B_SCANNED;
for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
nbp = TAILQ_NEXT(bp, b_vnbufs);
/*
@@ -152,7 +154,7 @@ loop2:
* or if it's already scheduled, skip to the next
* buffer
*/
- if ((bp->b_flags & B_BUSY) ||
+ if ((bp->b_flags & (B_BUSY | B_SCANNED)) ||
((skipmeta == 1) && (bp->b_lblkno < 0)))
continue;
if ((bp->b_flags & B_DELWRI) == 0)
@@ -162,6 +164,7 @@ loop2:
* asked to wait for everything, or it's not a file or BDEV,
* start the IO on this buffer immediatly.
*/
+ bp->b_flags |= B_SCANNED;
if (((bp->b_vp != vp) || (ap->a_waitfor == MNT_WAIT)) ||
((vp->v_type != VREG) && (vp->v_type != VBLK))) {
@@ -174,18 +177,19 @@ loop2:
if ((bp->b_flags & B_CLUSTEROK) &&
ap->a_waitfor != MNT_WAIT) {
(void) vfs_bio_awrite(bp);
- splx(s);
} else {
bremfree(bp);
bp->b_flags |= B_BUSY;
splx(s);
(void) bawrite(bp);
+ s = splbio();
}
} else {
bremfree(bp);
bp->b_flags |= B_BUSY;
splx(s);
(void) bwrite(bp);
+ s = splbio();
}
} else if ((vp->v_type == VREG) && (bp->b_lblkno >= lbn)) {
/*
@@ -194,13 +198,17 @@ loop2:
*/
bremfree(bp);
bp->b_flags |= B_BUSY | B_INVAL | B_NOCACHE;
- brelse(bp);
splx(s);
+ brelse(bp);
+ s = splbio();
} else {
vfs_bio_awrite(bp);
- splx(s);
}
- goto loop;
+ /*
+ * Since we may have slept during the I/O, we need
+ * to start from a known point.
+ */
+ nbp = TAILQ_FIRST(&vp->v_dirtyblkhd);
}
/*
* If we were asked to do this synchronously, then go back for
@@ -208,7 +216,7 @@ loop2:
*/
if (skipmeta) {
skipmeta = 0;
- goto loop2; /* stay within the splbio() */
+ goto loop;
}
if (ap->a_waitfor == MNT_WAIT) {
@@ -238,7 +246,7 @@ loop2:
*/
if (passes > 0) {
passes -= 1;
- goto loop2;
+ goto loop;
}
#ifdef DIAGNOSTIC
if (vp->v_type != VBLK)
OpenPOWER on IntegriCloud