summaryrefslogtreecommitdiffstats
path: root/sys/ufs
diff options
context:
space:
mode:
authorjeff <jeff@FreeBSD.org>2011-04-02 21:52:58 +0000
committerjeff <jeff@FreeBSD.org>2011-04-02 21:52:58 +0000
commitf31f8adf99a6b94f4ba76e98633b2c3c4944cb09 (patch)
tree573cd71d0e066a3b1f3e6ac9dc25b47f39e241d8 /sys/ufs
parent4999e5953738c2b40e3c525eb6f707134d5434d8 (diff)
downloadFreeBSD-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.c23
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)
OpenPOWER on IntegriCloud