diff options
author | 2001-03-20 17:30:07 +0000 | |
---|---|---|
committer | 2001-03-20 17:30:07 +0000 | |
commit | ab8f7c4d4284e1c856eafbbaa1a41110ef6b86b4 (patch) | |
tree | 7ac49b9634f51a6b0b0a263557d156277f60409a | |
parent | indent (diff) | |
download | wireguard-openbsd-ab8f7c4d4284e1c856eafbbaa1a41110ef6b86b4.tar.xz wireguard-openbsd-ab8f7c4d4284e1c856eafbbaa1a41110ef6b86b4.zip |
Make fsync a bit more reliable; From Free/NetBSD. art@ ok.
-rw-r--r-- | sys/sys/buf.h | 3 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vnops.c | 38 |
2 files changed, 25 insertions, 16 deletions
diff --git a/sys/sys/buf.h b/sys/sys/buf.h index 7c5e8f69938..46b5cc8c0fe 100644 --- a/sys/sys/buf.h +++ b/sys/sys/buf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: buf.h,v 1.20 2001/02/24 19:07:07 csapuntz Exp $ */ +/* $OpenBSD: buf.h,v 1.21 2001/03/20 17:30:07 gluk Exp $ */ /* $NetBSD: buf.h,v 1.25 1997/04/09 21:12:17 mycroft Exp $ */ /* @@ -150,6 +150,7 @@ struct buf { #define B_WRITEINPROG 0x01000000 /* Write in progress. */ #define B_XXX 0x02000000 /* Debugging flag. */ #define B_VFLUSH 0x04000000 /* Buffer is being synced. */ +#define B_SCANNED 0x08000000 /* Block already pushed during sync */ /* * This structure describes a clustered I/O. It is stored in the b_saveaddr 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) |