mtd/fs/jffs2 gc.c,1.120,1.121 readinode.c,1.111,1.112

David Woodhouse dwmw2 at infradead.org
Sat Nov 1 11:28:15 EST 2003


Update of /home/cvs/mtd/fs/jffs2
In directory phoenix.infradead.org:/tmp/cvs-serv32633

Modified Files:
	gc.c readinode.c 
Log Message:
Fix clear_inode race in 2.5.

Index: gc.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/gc.c,v
retrieving revision 1.120
retrieving revision 1.121
diff -u -r1.120 -r1.121
--- gc.c	31 Oct 2003 14:55:02 -0000	1.120
+++ gc.c	1 Nov 2003 16:28:13 -0000	1.121
@@ -273,41 +273,37 @@
 		   we're at it, so we set the state accordingly */
 		if (ref_flags(raw) == REF_PRISTINE)
 			ic->state = INO_STATE_GC;
-		else if (ic->nlink) {
+		else {
 			D1(printk(KERN_DEBUG "Ino #%u is absent but node not REF_PRISTINE. Reading.\n", 
 				  inum));
-		} else {
-			D1(printk(KERN_WARNING "Waiting for currently-being-deleted ino #%u to go away.\n",
-				  inum));
-			goto wait;
 		}
 		break;
 
 	case INO_STATE_PRESENT:
-	case INO_STATE_UNCHECKED:
-		/* It's in-core or hasn't been checked. GC must iget() it. */
+		/* It's in-core. GC must iget() it. */
 		break;
 
+	case INO_STATE_UNCHECKED:
 	case INO_STATE_CHECKING:
+	case INO_STATE_GC:
 		/* Should never happen. We should have finished checking
-		   by the time we actually start doing any GC. */
+		   by the time we actually start doing any GC, and since 
+		   we're holding the alloc_sem, no other garbage collection 
+		   can happen.
+		*/
+		printk(KERN_CRIT "Inode #%u already in state %d in jffs2_garbage_collect_pass()!\n",
+		       ic->state);
+		up(&c->alloc_sem);
+		spin_unlock(&c->inocache_lock);
 		BUG();
 
-	
-	case INO_STATE_GC:
-		/* Should never happen. We are holding the alloc_sem, 
-		   no other garbage collection can happen. Note that we
-		   do depend on this later when deciding to do a simple
-		   node copy */
-		BUG();
-			 
 	case INO_STATE_READING:
 		/* Someone's currently trying to read it. We must wait for
 		   them to finish and then go through the full iget() route
 		   to do the GC. However, sometimes read_inode() needs to get
 		   the alloc_sem() (for marking nodes invalid) so we must
 		   drop the alloc_sem before sleeping. */
-	wait:
+
 		up(&c->alloc_sem);
 		D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() waiting for ino #%u in state %d\n",
 			  inum, ic->state));
@@ -323,7 +319,6 @@
 		   A: Small enough that I don't care :) 
 		*/
 		return 0;
-
 	}
 
 	spin_unlock(&c->inocache_lock);
@@ -368,7 +363,7 @@
 
 
 static int jffs2_garbage_collect_live(struct jffs2_sb_info *c,  struct jffs2_eraseblock *jeb,
-			       struct jffs2_raw_node_ref *raw, struct jffs2_inode_cache *ic)
+				      struct jffs2_raw_node_ref *raw, struct jffs2_inode_cache *ic)
 {
 	struct jffs2_inode_info *f;
 	struct jffs2_node_frag *frag;
@@ -378,9 +373,21 @@
 	struct inode *inode;
 	int ret = 0;
 
-	inode = iget(OFNI_BS_2SFFJ(c), ic->ino);
-	if (!inode)
-		return -ENOMEM;
+	if (!ic->nlink) {
+		/* Only GC from it if it's still actually in the
+		   icache and hasn't been deleted while we were
+		   pondering it. */
+		inode = ifind(OFNI_BS_2SFFJ(c), ic->ino);
+		if (!inode) {
+			D1(printk(KERN_WARNING "ifind failed for ino #%u; inode is deleted. Skipping.\n",
+				  ic->ino));
+			return 0;
+		}
+	else {
+		inode = iget(OFNI_BS_2SFFJ(c), ic->ino);
+		if (!inode)
+			return -ENOMEM;
+	}
 	if (is_bad_inode(inode)) {
 		printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. nlink %d, state %d\n", ic->ino, ic->nlink, ic->state);
 		/* NB. This will happen again. We need to do something appropriate here. */

Index: readinode.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/readinode.c,v
retrieving revision 1.111
retrieving revision 1.112
diff -u -r1.111 -r1.112
--- readinode.c	31 Oct 2003 14:54:01 -0000	1.111
+++ readinode.c	1 Nov 2003 16:28:13 -0000	1.112
@@ -663,24 +663,10 @@
 void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
 {
 	struct jffs2_full_dirent *fd, *fds;
-	/* I don't think we care about the potential race due to reading this
-	   without f->sem. It can never get undeleted. */
-	int deleted = f->inocache && !f->inocache->nlink;
-
-	/* If it's a deleted inode, grab the alloc_sem. This prevents
-	   jffs2_garbage_collect_pass() from deciding that it wants to
-	   garbage collect one of the nodes we're just about to mark 
-	   obsolete -- by the time we drop alloc_sem and return, all
-	   the nodes are marked obsolete, and jffs2_g_c_pass() won't
-	   call iget() for the inode in question.
-
-	   We also used to do this to keep the temporary BUG() in 
-	   jffs2_mark_node_obsolete() from triggering. 
-	*/
-	if(deleted)
-		down(&c->alloc_sem);
+	int deleted;
 
 	down(&f->sem);
+	deleted = f->inocache && !f->inocache->nlink;
 
 	if (f->metadata) {
 		if (deleted)
@@ -702,7 +688,4 @@
 		jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
 
 	up(&f->sem);
-
-	if(deleted)
-		up(&c->alloc_sem);
 }




More information about the linux-mtd-cvs mailing list