svn commit: r220282 - head/sys/ufs/ffs

Jeff Roberson jeff at FreeBSD.org
Sat Apr 2 21:52:59 UTC 2011


Author: jeff
Date: Sat Apr  2 21:52:58 2011
New Revision: 220282
URL: http://svn.freebsd.org/changeset/base/220282

Log:
  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

Modified:
  head/sys/ufs/ffs/ffs_softdep.c

Modified: head/sys/ufs/ffs/ffs_softdep.c
==============================================================================
--- head/sys/ufs/ffs/ffs_softdep.c	Sat Apr  2 16:02:25 2011	(r220281)
+++ head/sys/ufs/ffs/ffs_softdep.c	Sat Apr  2 21:52:58 2011	(r220282)
@@ -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)


More information about the svn-src-head mailing list