diff options
Diffstat (limited to 'sys/fs/specfs/spec_vnops.c')
| -rw-r--r-- | sys/fs/specfs/spec_vnops.c | 23 |
1 files changed, 16 insertions, 7 deletions
diff --git a/sys/fs/specfs/spec_vnops.c b/sys/fs/specfs/spec_vnops.c index ba4655852c7a..6b33df4777f9 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); |
