mtd/fs/jffs2 fs.c,1.34,1.35 gc.c,1.129,1.130 os-linux.h,1.38,1.39

David Woodhouse dwmw2 at infradead.org
Mon Nov 24 06:51:21 EST 2003


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

Modified Files:
	fs.c gc.c os-linux.h 
Log Message:
Remove penultimate reference to struct inode in core code

Index: fs.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/fs.c,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -r1.34 -r1.35
--- fs.c	3 Nov 2003 17:33:54 -0000	1.34
+++ fs.c	24 Nov 2003 11:51:18 -0000	1.35
@@ -514,3 +514,72 @@
 
 	return ret;
 }
+
+void jffs2_gc_release_inode(struct jffs2_sb_info *c,
+				   struct jffs2_inode_info *f)
+{
+	iput(OFNI_EDONI_2SFFJ(f));
+}
+
+struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
+						     int inum, int nlink)
+{
+	struct inode *inode;
+	struct jffs2_inode_cache *ic;
+	if (!nlink) {
+		/* The inode has zero nlink but its nodes weren't yet marked
+		   obsolete. This has to be because we're still waiting for 
+		   the final (close() and) iput() to happen.
+
+		   There's a possibility that the final iput() could have 
+		   happened while we were contemplating. In order to ensure
+		   that we don't cause a new read_inode() (which would fail)
+		   for the inode in question, we use ilookup() in this case
+		   instead of iget().
+
+		   The nlink can't _become_ zero at this point because we're 
+		   holding the alloc_sem, and jffs2_do_unlink() would also
+		   need that while decrementing nlink on any inode.
+		*/
+		inode = ilookup(OFNI_BS_2SFFJ(c), inum);
+		if (!inode) {
+			D1(printk(KERN_DEBUG "ilookup() failed for ino #%u; inode is probably deleted.\n",
+				  inum));
+
+			spin_lock(&c->inocache_lock);
+			ic = jffs2_get_ino_cache(c, inum);
+			if (!ic) {
+				D1(printk(KERN_DEBUG "Inode cache for ino #%u is gone.\n", inum));
+				spin_unlock(&c->inocache_lock);
+				return NULL;
+			}
+			if (ic->state != INO_STATE_CHECKEDABSENT) {
+				/* Wait for progress. Don't just loop */
+				D1(printk(KERN_DEBUG "Waiting for ino #%u in state %d\n",
+					  ic->ino, ic->state));
+				sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
+			} else {
+				spin_unlock(&c->inocache_lock);
+			}
+
+			return NULL;
+		}
+	} else {
+		/* Inode has links to it still; they're not going away because
+		   jffs2_do_unlink() would need the alloc_sem and we have it.
+		   Just iget() it, and if read_inode() is necessary that's OK.
+		*/
+		inode = iget(OFNI_BS_2SFFJ(c), inum);
+		if (!inode)
+			return ERR_PTR(-ENOMEM);
+	}
+	if (is_bad_inode(inode)) {
+		printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. nlink %d\n",
+		       inum, nlink);
+		/* NB. This will happen again. We need to do something appropriate here. */
+		iput(inode);
+		return ERR_PTR(-EIO);
+	}
+
+	return JFFS2_INODE_INFO(inode);
+}

Index: gc.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/gc.c,v
retrieving revision 1.129
retrieving revision 1.130
diff -u -r1.129 -r1.130
--- gc.c	20 Nov 2003 16:40:14 -0000	1.129
+++ gc.c	24 Nov 2003 11:51:18 -0000	1.130
@@ -36,7 +36,7 @@
 				       struct jffs2_inode_info *f, struct jffs2_full_dnode *fn,
 				       uint32_t start, uint32_t end);
 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_info *f);
 
 /* Called with erase_completion_lock held */
 static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c)
@@ -112,10 +112,11 @@
  */
 int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
 {
+	struct jffs2_inode_info *f;
 	struct jffs2_inode_cache *ic;
 	struct jffs2_eraseblock *jeb;
 	struct jffs2_raw_node_ref *raw;
-	int ret = 0;
+	int ret = 0, inum, nlink;
 
 	if (down_interruptible(&c->alloc_sem))
 		return -EINTR;
@@ -249,7 +250,9 @@
 
 	ic = jffs2_raw_ref_to_ic(raw);
 
-	/* We need to hold the inocache */
+	/* We need to hold the inocache. Either the erase_completion_lock or
+	   the inocache_lock are sufficient; we trade down since the inocache_lock 
+	   causes less contention. */
 	spin_lock(&c->inocache_lock);
 
 	spin_unlock(&c->erase_completion_lock);
@@ -343,14 +346,26 @@
 		/* Fall through if it wanted us to, with inocache_lock held */
 	}
 
-	/* FIXME: We still have the inocache_lock held. This is ugly.
-	   It's done to prevent the fairly unlikely race where the
-	   gcblock is entirely obsoleted by the final close of a file
-	   which had the only valid nodes in the block, followed by
-	   erasure, followed by freeing of the ic because the erased
-	   block(s) held _all_ the nodes of that inode.... never been
-	   seen but it's vaguely possible. */
-	ret = jffs2_garbage_collect_live(c, jeb, raw, ic);
+	/* Prevent the fairly unlikely race where the gcblock is
+	   entirely obsoleted by the final close of a file which had
+	   the only valid nodes in the block, followed by erasure,
+	   followed by freeing of the ic because the erased block(s)
+	   held _all_ the nodes of that inode.... never been seen but
+	   it's vaguely possible. */
+
+	inum = ic->ino;
+	nlink = ic->nlink;
+	spin_unlock(&c->inocache_lock);
+
+	f = jffs2_gc_fetch_inode(c, inum, nlink);
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+	if (!f)
+		return 0;
+
+	ret = jffs2_garbage_collect_live(c, jeb, raw, f);
+
+	jffs2_gc_release_inode(c, f);
 
  release_sem:
 	up(&c->alloc_sem);
@@ -374,78 +389,14 @@
 }
 
 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_info *f)
 {
-	struct jffs2_inode_info *f;
 	struct jffs2_node_frag *frag;
 	struct jffs2_full_dnode *fn = NULL;
 	struct jffs2_full_dirent *fd;
 	uint32_t start = 0, end = 0, nrfrags = 0;
-	struct inode *inode;
 	int ret = 0;
 
-	if (!ic->nlink) {
-		int inum = ic->ino;
-
-		spin_unlock(&c->inocache_lock);
-
-		/* The inode has zero nlink but its nodes weren't yet marked
-		   obsolete. This has to be because we're still waiting for 
-		   the final (close() and) iput() to happen.
-
-		   There's a possibility that the final iput() could have 
-		   happened while we were contemplating. In order to ensure
-		   that we don't cause a new read_inode() (which would fail)
-		   for the inode in question, we use ilookup() in this case
-		   instead of iget().
-
-		   The nlink can't _become_ zero at this point because we're 
-		   holding the alloc_sem, and jffs2_do_unlink() would also
-		   need that while decrementing nlink on any inode.
-		*/
-		inode = ilookup(OFNI_BS_2SFFJ(c), inum);
-		if (!inode) {
-			D1(printk(KERN_DEBUG "ilookup() failed for ino #%u; inode is probably deleted.\n",
-				  inum));
-
-			spin_lock(&c->inocache_lock);
-			ic = jffs2_get_ino_cache(c, inum);
-			if (!ic) {
-				D1(printk(KERN_DEBUG "Inode cache for ino #%u is gone.\n", inum));
-				spin_unlock(&c->inocache_lock);
-				return 0;
-			}
-			if (ic->state != INO_STATE_CHECKEDABSENT) {
-				/* Wait for progress. Don't just loop */
-				D1(printk(KERN_DEBUG "Waiting for ino #%u in state %d\n",
-					  ic->ino, ic->state));
-				sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
-			} else {
-				spin_unlock(&c->inocache_lock);
-			}
-
-			return 0;
-		}
-	} else {
-		spin_unlock(&c->inocache_lock);
-
-		/* Inode has links to it still; they're not going away because
-		   jffs2_do_unlink() would need the alloc_sem and we have it.
-		   Just iget() it, and if read_inode() is necessary that's OK.
-		*/
-		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. */
-		ret = -EIO;
-		goto put_out;
-	}
-
-	f = JFFS2_INODE_INFO(inode);
 	down(&f->sem);
 
 	/* Now we have the lock for this inode. Check that it's still the one at the head
@@ -486,10 +437,10 @@
 	}
 	if (fn) {
 		if (ref_flags(raw) == REF_PRISTINE) {
-			ret = jffs2_garbage_collect_pristine(c, ic, raw);
+			ret = jffs2_garbage_collect_pristine(c, f->inocache, raw);
 			if (!ret) {
 				/* Urgh. Return it sensibly. */
-				frag->node->raw = ic->nodes;
+				frag->node->raw = f->inocache->nodes;
 			}	
 			if (ret != -EBADFD)
 				goto upnout;
@@ -526,8 +477,6 @@
 	}
  upnout:
 	up(&f->sem);
- put_out:
-	iput(inode);
 
 	return ret;
 }

Index: os-linux.h
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/os-linux.h,v
retrieving revision 1.38
retrieving revision 1.39
diff -u -r1.38 -r1.39
--- os-linux.h	20 Nov 2003 16:40:35 -0000	1.38
+++ os-linux.h	24 Nov 2003 11:51:18 -0000	1.39
@@ -175,6 +175,11 @@
 void jffs2_write_super (struct super_block *);
 int jffs2_remount_fs (struct super_block *, int *, char *);
 int jffs2_do_fill_super(struct super_block *sb, void *data, int silent);
+void jffs2_gc_release_inode(struct jffs2_sb_info *c,
+			    struct jffs2_inode_info *f);
+struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
+					      int inum, int nlink);
+     
 
 /* writev.c */
 int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct iovec *vecs, 




More information about the linux-mtd-cvs mailing list