diff options
author | jeff <jeff@FreeBSD.org> | 2011-04-02 21:52:58 +0000 |
---|---|---|
committer | jeff <jeff@FreeBSD.org> | 2011-04-02 21:52:58 +0000 |
commit | f31f8adf99a6b94f4ba76e98633b2c3c4944cb09 (patch) | |
tree | 573cd71d0e066a3b1f3e6ac9dc25b47f39e241d8 /sys/ufs | |
parent | 4999e5953738c2b40e3c525eb6f707134d5434d8 (diff) | |
download | FreeBSD-src-f31f8adf99a6b94f4ba76e98633b2c3c4944cb09.zip FreeBSD-src-f31f8adf99a6b94f4ba76e98633b2c3c4944cb09.tar.gz |
Fix problems that manifested from filesystem full conditions:
- In softdep_revert_mkdir() find the dotaddref before we attempt to cancel
the jaddref so we can make assumptions about where the dotaddref is on
the list. cancel_jaddref() does not always remove items from the list
anymore.
- Always set GOINGAWAY on an inode in softdep_freefile() if DEPCOMPLETE
was never set. This ensures that dependencies will continue to be
processed on the inowait/bufwait list and is more an artifact of
the structure of the code than a pure ordering problem.
- Always set DEPCOMPLETE on canceled jaddrefs so that they can be freed
appropriately. This normally occurs when the refs are added to the
journal but if they are canceled before this point the state would
never be set and the dependency could never be freed.
Reported by: pho
Tested by: pho
Diffstat (limited to 'sys/ufs')
-rw-r--r-- | sys/ufs/ffs/ffs_softdep.c | 23 |
1 files changed, 14 insertions, 9 deletions
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index 6120400..1a56c8a 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -3501,10 +3501,14 @@ cancel_jaddref(jaddref, inodedep, wkhd) * us so that it is consistent with the in-memory reference. This * ensures that inode nlink rollbacks always have the correct link. */ - if (needsj == 0) + if (needsj == 0) { for (inoref = TAILQ_NEXT(&jaddref->ja_ref, if_deps); inoref; - inoref = TAILQ_NEXT(inoref, if_deps)) + inoref = TAILQ_NEXT(inoref, if_deps)) { + if (inoref->if_state & GOINGAWAY) + break; inoref->if_nlink--; + } + } jsegdep = inoref_jseg(&jaddref->ja_ref); if (jaddref->ja_state & NEWBLOCK) move_newblock_dep(jaddref, inodedep); @@ -3522,6 +3526,7 @@ cancel_jaddref(jaddref, inodedep, wkhd) if (jaddref->ja_state & DEPCOMPLETE) remove_from_journal(&jaddref->ja_list); } + jaddref->ja_state |= (GOINGAWAY | DEPCOMPLETE); /* * Leave NEWBLOCK jaddrefs on the inodedep so handle_workitem_remove * can arrange for them to be freed with the bitmap. Otherwise we @@ -3535,7 +3540,6 @@ cancel_jaddref(jaddref, inodedep, wkhd) free_jaddref(jaddref); return (needsj); } - jaddref->ja_state |= GOINGAWAY; /* * Leave the head of the list for jsegdeps for fast merging. */ @@ -4071,6 +4075,7 @@ softdep_revert_mkdir(dp, ip) { struct inodedep *inodedep; struct jaddref *jaddref; + struct jaddref *dotaddref; struct vnode *dvp; dvp = ITOV(dp); @@ -4090,12 +4095,12 @@ softdep_revert_mkdir(dp, ip) inoreflst); KASSERT(jaddref->ja_parent == dp->i_number, ("softdep_revert_mkdir: addref parent mismatch")); + dotaddref = (struct jaddref *)TAILQ_PREV(&jaddref->ja_ref, + inoreflst, if_deps); cancel_jaddref(jaddref, inodedep, &inodedep->id_inowait); - jaddref = (struct jaddref *)TAILQ_LAST(&inodedep->id_inoreflst, - inoreflst); - KASSERT(jaddref->ja_parent == ip->i_number, + KASSERT(dotaddref->ja_parent == ip->i_number, ("softdep_revert_mkdir: dot addref parent mismatch")); - cancel_jaddref(jaddref, inodedep, &inodedep->id_inowait); + cancel_jaddref(dotaddref, inodedep, &inodedep->id_inowait); } FREE_LOCK(&lk); } @@ -5734,14 +5739,14 @@ softdep_freefile(pvp, ino, mode) clear_unlinked_inodedep(inodedep); /* Re-acquire inodedep as we've dropped lk. */ inodedep_lookup(pvp->v_mount, ino, 0, &inodedep); - if (inodedep && (inodedep->id_state & DEPCOMPLETE) == 0) - inodedep->id_state |= GOINGAWAY; } if (inodedep == NULL || check_inode_unwritten(inodedep)) { FREE_LOCK(&lk); handle_workitem_freefile(freefile); return; } + if (inodedep && (inodedep->id_state & DEPCOMPLETE) == 0) + inodedep->id_state |= GOINGAWAY; WORKLIST_INSERT(&inodedep->id_inowait, &freefile->fx_list); FREE_LOCK(&lk); if (ip->i_number == ino) |