diff options
author | Grigoriy Orlov <gluk@cvs.openbsd.org> | 2001-03-20 17:30:08 +0000 |
---|---|---|
committer | Grigoriy Orlov <gluk@cvs.openbsd.org> | 2001-03-20 17:30:08 +0000 |
commit | 57df2a5ec51b941f5c14e1829ce5e22c31352daf (patch) | |
tree | a191ddcf813a0b773b947cd6ea4ab584424ceb37 /sys/ufs/ffs/ffs_vnops.c | |
parent | a6409494c2542b1a6513a2f771408d1d1b3fe49d (diff) |
Make fsync a bit more reliable; From Free/NetBSD. art@ ok.
Diffstat (limited to 'sys/ufs/ffs/ffs_vnops.c')
-rw-r--r-- | sys/ufs/ffs/ffs_vnops.c | 38 |
1 files changed, 23 insertions, 15 deletions
diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c index c4319c8d537..3044ee611fb 100644 --- a/sys/ufs/ffs/ffs_vnops.c +++ b/sys/ufs/ffs/ffs_vnops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ffs_vnops.c,v 1.14 2001/03/09 23:09:18 gluk Exp $ */ +/* $OpenBSD: ffs_vnops.c,v 1.15 2001/03/20 17:30:07 gluk Exp $ */ /* $NetBSD: ffs_vnops.c,v 1.7 1996/05/11 18:27:24 mycroft Exp $ */ /* @@ -266,37 +266,45 @@ ffs_fsync(v) /* * Flush all dirty buffers associated with a vnode */ - passes = NIADDR; + passes = NIADDR + 1; skipmeta = 0; if (ap->a_waitfor == MNT_WAIT) skipmeta = 1; -loop: s = splbio(); -loop2: - for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { - nbp = bp->b_vnbufs.le_next; - if ((bp->b_flags & B_BUSY)) +loop: + for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; + bp = LIST_NEXT(bp, b_vnbufs)) + bp->b_flags &= ~B_SCANNED; + for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { + nbp = LIST_NEXT(bp, b_vnbufs); + if (bp->b_flags & (B_BUSY | B_SCANNED)) continue; if ((bp->b_flags & B_DELWRI) == 0) panic("ffs_fsync: not dirty"); if (skipmeta && bp->b_lblkno < 0) continue; bremfree(bp); - bp->b_flags |= B_BUSY; + bp->b_flags |= B_BUSY | B_SCANNED; splx(s); /* - * Wait for I/O associated with indirect blocks to complete, - * since there is no way to quickly wait for them below. + * On our final pass through, do all I/O synchronously + * so that we can find out if our flush is failing + * because of write errors. */ - if (bp->b_vp == vp || ap->a_waitfor != MNT_WAIT) + if (passes > 0 || ap->a_waitfor != MNT_WAIT) (void) bawrite(bp); else if ((error = bwrite(bp)) != 0) return (error); - goto loop; + s = splbio(); + /* + * Since we may have slept during the I/O, we need + * to start from a known point. + */ + nbp = LIST_FIRST(&vp->v_dirtyblkhd); } if (skipmeta) { skipmeta = 0; - goto loop2; + goto loop; } if (ap->a_waitfor == MNT_WAIT) { vwaitforio(vp, 0, "ffs_fsync", 0); @@ -309,7 +317,7 @@ loop2: if ((error = softdep_sync_metadata(ap)) != 0) return (error); s = splbio(); - if (vp->v_dirtyblkhd.lh_first) { + if (!LIST_EMPTY(&vp->v_dirtyblkhd)) { /* * Block devices associated with filesystems may * have new I/O requests posted for them even if @@ -320,7 +328,7 @@ loop2: */ if (passes > 0) { passes -= 1; - goto loop2; + goto loop; } #ifdef DIAGNOSTIC if (vp->v_type != VBLK) |