summaryrefslogtreecommitdiffstats
path: root/sys/ufs/ffs
diff options
context:
space:
mode:
authortegge <tegge@FreeBSD.org>2006-05-06 20:51:31 +0000
committertegge <tegge@FreeBSD.org>2006-05-06 20:51:31 +0000
commitd79b4cb4753523aa7f2394b74deffe49e0f0eff4 (patch)
tree61d0b9838aac78b049052fd0625b8fd92b884f4f /sys/ufs/ffs
parenta75e2eb7ff3c599a450406736b161660ed1204cb (diff)
downloadFreeBSD-src-d79b4cb4753523aa7f2394b74deffe49e0f0eff4.zip
FreeBSD-src-d79b4cb4753523aa7f2394b74deffe49e0f0eff4.tar.gz
ffs_syncvnode() might skip some of the blocks due to them being locked,
assuming them to be inflight write buffers. This is not always the case. bufdaemon might hold the buffer lock and give up writing the buffer due to it having dependencies, the file system being suspended or the vnode lock being held by another thread. When bufdaemon decides to write the buffer there is still a window before bufobj_wref() has been called, allowing other threads to believe that the vnode has no dirty buffers or inflight writes. Try harder to flush first block of new subdirectory to get rid of MKDIR_BODY dependency.
Diffstat (limited to 'sys/ufs/ffs')
-rw-r--r--sys/ufs/ffs/ffs_softdep.c46
1 files changed, 46 insertions, 0 deletions
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c
index 4771460..959fe6a 100644
--- a/sys/ufs/ffs/ffs_softdep.c
+++ b/sys/ufs/ffs/ffs_softdep.c
@@ -5501,6 +5501,7 @@ flush_pagedep_deps(pvp, mp, diraddhdp)
int error = 0;
struct buf *bp;
ino_t inum;
+ struct worklist *wk;
ump = VFSTOUFS(mp);
while ((dap = LIST_FIRST(diraddhdp)) != NULL) {
@@ -5545,8 +5546,53 @@ flush_pagedep_deps(pvp, mp, diraddhdp)
}
VI_LOCK(vp);
drain_output(vp);
+ /*
+ * If first block is still dirty with a D_MKDIR
+ * dependency then it needs to be written now.
+ */
+ for (;;) {
+ error = 0;
+ bp = gbincore(&vp->v_bufobj, 0);
+ if (bp == NULL)
+ break; /* First block not present */
+ error = BUF_LOCK(bp,
+ LK_EXCLUSIVE |
+ LK_SLEEPFAIL |
+ LK_INTERLOCK,
+ VI_MTX(vp));
+ VI_LOCK(vp);
+ if (error == ENOLCK)
+ continue; /* Slept, retry */
+ if (error != 0)
+ break; /* Failed */
+ if ((bp->b_flags & B_DELWRI) == 0) {
+ BUF_UNLOCK(bp);
+ break; /* Buffer not dirty */
+ }
+ for (wk = LIST_FIRST(&bp->b_dep);
+ wk != NULL;
+ wk = LIST_NEXT(wk, wk_list))
+ if (wk->wk_type == D_MKDIR)
+ break;
+ if (wk == NULL)
+ BUF_UNLOCK(bp); /* Dependency gone */
+ else {
+ /*
+ * D_MKDIR dependency remains,
+ * must write buffer to stable
+ * storage.
+ */
+ VI_UNLOCK(vp);
+ bremfree(bp);
+ error = bwrite(bp);
+ VI_LOCK(vp);
+ }
+ break;
+ }
VI_UNLOCK(vp);
vput(vp);
+ if (error != 0)
+ break; /* Flushing of first block failed */
ACQUIRE_LOCK(&lk);
/*
* If that cleared dependencies, go on to next.
OpenPOWER on IntegriCloud