summaryrefslogtreecommitdiffstats
path: root/sys/fs/specfs
diff options
context:
space:
mode:
authordillon <dillon@FreeBSD.org>2001-01-29 08:19:28 +0000
committerdillon <dillon@FreeBSD.org>2001-01-29 08:19:28 +0000
commit11fb1bf637e4db643890410e5d278f03dd5e77cc (patch)
treebe48f4b30197a40114239fbad89c6775cdfbd3da /sys/fs/specfs
parentd3da30dfac030371f0675bc892beccee6e602a9e (diff)
downloadFreeBSD-src-11fb1bf637e4db643890410e5d278f03dd5e77cc.zip
FreeBSD-src-11fb1bf637e4db643890410e5d278f03dd5e77cc.tar.gz
This patch reestablishes the spec_fsync() guarentee that synchronous
fsyncs, which typically occur during unmounting, will drain all dirty buffers even if it takes multiple passes to do so. The guarentee was mangled by the last patch which solved a problem due to -current disabling interrupts while holding giant (which caused an infinite spin loop waiting for I/O to complete). -stable does not have either patch, but has a similar bug in the original spec_fsync() code which is triggered by a bug in the softupdates umount code, a fix for which will be committed to -current as soon as Kirk stamps it. Then both solutions will be MFC'd to -stable. -stable currently suffers from a combination of the softupdates bug and a small window of opportunity in the original spec_fsync() code, and -stable also suffers from the spin-loop bug but since interrupts are enabled the spin resolves itself in a few milliseconds.
Diffstat (limited to 'sys/fs/specfs')
-rw-r--r--sys/fs/specfs/spec_vnops.c23
1 files changed, 16 insertions, 7 deletions
diff --git a/sys/fs/specfs/spec_vnops.c b/sys/fs/specfs/spec_vnops.c
index ba46558..6b33df4 100644
--- a/sys/fs/specfs/spec_vnops.c
+++ b/sys/fs/specfs/spec_vnops.c
@@ -347,10 +347,12 @@ spec_fsync(ap)
struct buf *bp;
struct buf *nbp;
int s;
+ int maxretry = 10000; /* large, arbitrarily chosen */
if (!vn_isdisk(vp, NULL))
return (0);
+loop1:
/*
* MARK/SCAN initialization to avoid infinite loops
*/
@@ -364,7 +366,7 @@ spec_fsync(ap)
/*
* Flush all dirty buffers associated with a block device.
*/
-loop:
+loop2:
s = splbio();
for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
nbp = TAILQ_NEXT(bp, b_vnbufs);
@@ -384,20 +386,27 @@ loop:
splx(s);
bawrite(bp);
}
- goto loop;
+ goto loop2;
}
+
+ /*
+ * If synchronous the caller expects us to completely resolve all
+ * dirty buffers in the system. Wait for in-progress I/O to
+ * complete (which could include background bitmap writes), then
+ * retry if dirty blocks still exist.
+ */
if (ap->a_waitfor == MNT_WAIT) {
while (vp->v_numoutput) {
vp->v_flag |= VBWAIT;
(void) tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "spfsyn", 0);
}
-#ifdef DIAGNOSTIC
if (!TAILQ_EMPTY(&vp->v_dirtyblkhd)) {
- vprint("spec_fsync: dirty", vp);
- splx(s);
- goto loop;
+ if (--maxretry != 0) {
+ splx(s);
+ goto loop1;
+ }
+ vprint("spec_fsync: giving up on dirty", vp);
}
-#endif
}
splx(s);
return (0);
OpenPOWER on IntegriCloud