summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgluk <gluk@openbsd.org>2001-03-20 17:30:07 +0000
committergluk <gluk@openbsd.org>2001-03-20 17:30:07 +0000
commitab8f7c4d4284e1c856eafbbaa1a41110ef6b86b4 (patch)
tree7ac49b9634f51a6b0b0a263557d156277f60409a
parentindent (diff)
downloadwireguard-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.h3
-rw-r--r--sys/ufs/ffs/ffs_vnops.c38
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)