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