mtd/fs/jffs2/ecos/src file-ecos.c,1.6,1.7 fs-ecos.c,1.11,1.12 os-ecos.h,1.8,1.9

David Woodhouse dwmw2 at infradead.org
Mon Nov 24 08:44:01 EST 2003


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

Modified Files:
	file-ecos.c fs-ecos.c os-ecos.h 
Log Message:
Fix refcount leaks, remove all references to struct inode in core code

Index: file-ecos.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/ecos/src/file-ecos.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- file-ecos.c	20 Nov 2003 16:41:58 -0000	1.6
+++ file-ecos.c	24 Nov 2003 13:43:58 -0000	1.7
@@ -41,7 +41,6 @@
 		ClearPageError(pg);
 	}
 
-	flush_dcache_page(pg);
 	kunmap(pg);
 
 	D1(printk(KERN_DEBUG "readpage finished\n"));
@@ -55,18 +54,6 @@
 	return ret;
 }
 
-
-//int jffs2_readpage (struct file *filp, struct page *pg)
-int jffs2_readpage (struct inode *d_inode, struct page *pg)
-{
-	//	struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode);
-	int ret;
-	
-	//	down(&f->sem);
-	ret = jffs2_do_readpage_unlock(d_inode, pg);
-	//	up(&f->sem);
-	return ret;
-}
 
 //int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, unsigned end)
 int jffs2_prepare_write (struct inode *d_inode, struct page *pg, unsigned start, unsigned end)

Index: fs-ecos.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/ecos/src/fs-ecos.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- fs-ecos.c	20 Nov 2003 16:41:58 -0000	1.11
+++ fs-ecos.c	24 Nov 2003 13:43:58 -0000	1.12
@@ -79,6 +79,9 @@
 static int jffs2_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
 static int jffs2_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t * pos, int whence);
 
+
+static int jffs2_read_inode (struct inode *inode);
+
 //==========================================================================
 // Filesystem table entries
 
@@ -160,25 +163,6 @@
 //==========================================================================
 // Ref count and nlink management
 
-// -------------------------------------------------------------------------
-// dec_refcnt()
-// Decrment the reference count on an inode. If this makes the ref count
-// zero, then this inode can be freed.
-
-static int dec_refcnt(struct inode *node)
-{
-	int err = ENOERR;
-	node->i_count--;
-
-	// In JFFS2 inode's are temporary in ram structures that are free'd when the usage i_count drops to 0
-	// The i_nlink however is managed by JFFS2 and is unrelated to usage
-	if (node->i_count == 0) {
-		// This inode is not in use, so delete it.
-		iput(node);
-	}
-
-	return err;
-}
 
 // FIXME: This seems like real cruft. Wouldn't it be better just to do the
 // right thing?
@@ -221,6 +205,9 @@
 {
 	D2(printf("init_dirsearch name = %s\n", name));
 	D2(printf("init_dirsearch dir = %x\n", dir));
+
+	/* Increase inode refcount since find_entry will decrease it again */
+	dir->i_count++;
 	ds->dir = dir;
 	ds->path = name;
 	ds->node = dir;
@@ -325,6 +312,8 @@
 // Main interface to directory search code. This is used in all file
 // level operations to locate the object named by the pathname.
 
+// Returns with use count incremented on both the sought object and 
+// the directory it was found in.
 static int jffs2_find(jffs2_dirsearch * d)
 {
 	int err;
@@ -345,8 +334,8 @@
 		if (d->last)
 			return ENOERR;
 
-		// every inode traversed in the find is temporary and should be free'd
-		//iput(d->dir);
+		// Drop the directory we were using.
+		iput(d->dir);
 
 		// Update dirsearch object to search next directory.
 		d->dir = d->node;
@@ -438,7 +427,6 @@
 static int jffs2_read_super(struct super_block *sb)
 {
 	struct jffs2_sb_info *c;
-	struct inode *root_i;
 	Cyg_ErrNo err;
 	cyg_uint32 len;
 	cyg_io_flash_getconfig_devsize_t ds;
@@ -477,19 +465,18 @@
 		return -err;
 
 	D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n"));
-	root_i = iget(sb, 1);
-	if (is_bad_inode(root_i)) {
+	sb->s_root = iget(sb, 1);
+	if (!sb->s_root) {
 		D1(printk(KERN_WARNING "get root inode failed\n"));
-		err = EIO;
+		err = -ENOMEM;
 		goto out_nodes;
 	}
-
-	D1(printk(KERN_DEBUG "jffs2_read_super(): d_alloc_root()\n"));
-	sb->s_root = d_alloc_root(root_i);
-	if (!sb->s_root) {
-		err = ENOMEM;
+	if (is_bad_inode(sb->s_root)) {
+		D1(printk(KERN_WARNING "get root inode failed\n"));
+		err = EIO;
 		goto out_root_i;
 	}
+
 	sb->s_blocksize = PAGE_CACHE_SIZE;
 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
 	sb->s_magic = JFFS2_SUPER_MAGIC;
@@ -497,7 +484,7 @@
 	return 0;
 
       out_root_i:
-	iput(root_i);
+	iput(sb->s_root);
       out_nodes:
 	jffs2_free_ino_caches(c);
 	jffs2_free_raw_node_refs(c);
@@ -508,7 +495,7 @@
 
 static int jffs2_mount(cyg_fstab_entry * fste, cyg_mtab_entry * mte)
 {
-	extern cyg_mtab_entry cyg_mtab[], cyg_mtab_end;
+	extern cyg_mtab_entry mtab[], mtab_end;
 	struct super_block *jffs2_sb = NULL;
 	struct jffs2_sb_info *c;
 	cyg_mtab_entry *m;
@@ -524,10 +511,10 @@
 	// Iterate through the mount table to see if we're mounted
 	// FIXME: this should be done better - perhaps if the superblock
 	// can be stored as an inode in the icache.
-	for (m = &cyg_mtab[0]; m != &cyg_mtab_end; m++) {
+	for (m = &mtab[0]; m != &mtab_end; m++) {
 		// stop if there are more than the configured maximum
-		if (m - &cyg_mtab[0] >= CYGNUM_FILEIO_MTAB_MAX) {
-			m = &cyg_mtab_end;
+		if (m - &mtab[0] >= CYGNUM_FILEIO_MTAB_MAX) {
+			m = &mtab_end;
 			break;
 		}
 		if (m->valid && strcmp(m->fsname, "jffs2") == 0 &&
@@ -593,10 +580,18 @@
 	// Only really umount if this is the only mount
 	if (jffs2_sb->s_mount_count == 1) {
 
-		if (root->i_cache_next != NULL)	// root icount was set to 1 on mount
+		if (root->i_cache_next != NULL)	{
+			struct inode *inode = root->i_cache_next;
+			printf("Refuse to unmount.\n");
+			while (inode) {
+				printf("Ino #%u has use count %d\n",
+				       inode->i_ino, inode->i_count);
+				inode = inode->i_cache_next;
+			}
+			// root icount was set to 1 on mount
 			return EBUSY;
-                
-		dec_refcnt(root);	// Time to free the root inode
+                }
+		iput(root);	// Time to free the root inode
 
 		//Clear root inode
 		//root_i = NULL;
@@ -677,13 +672,26 @@
 		// The node exists. If the O_CREAT and O_EXCL bits are set, we
 		// must fail the open.
 
-		if ((mode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+		if ((mode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) {
+			iput(ds.node);
 			err = EEXIST;
-		else
+		} else
 			node = ds.node;
 	}
 
-	if (err == ENOERR && (mode & O_TRUNC)) {
+	// Finished with the directory now 
+	iput(ds.dir);
+
+	if (err != ENOERR)
+		return err;
+
+	// Check that we actually have a file here
+	if (S_ISDIR(node->i_mode)) {
+		iput(node);
+		return EISDIR;
+	}
+
+	if (mode & O_TRUNC) {
 		struct jffs2_inode_info *f = JFFS2_INODE_INFO(node);
 		struct jffs2_sb_info *c = JFFS2_SB_INFO(node->i_sb);
 		// If the O_TRUNC bit is set we must clean out the file data.
@@ -694,17 +702,7 @@
 		node->i_ctime = node->i_mtime = cyg_timestamp();
 	}
 
-	if (err != ENOERR)
-		return err;
-
-	// Check that we actually have a file here
-	if (S_ISDIR(node->i_mode))
-		return EISDIR;
-
-	node->i_count++;	// Count successful open
-
-	// Initialize the file object
-
+	// Initialise the file object
 	file->f_flag |= mode & CYG_FILE_MODE_MASK;
 	file->f_type = CYG_FILE_TYPE_FILE;
 	file->f_ops = &jffs2_fileops;
@@ -736,12 +734,17 @@
 
 	err = jffs2_find(&ds);
 
-	if (err != ENOERR)
+	if (err != ENOERR) {
+		iput(ds.dir);
 		return err;
+	}
 
 	// Cannot unlink directories, use rmdir() instead
-	if (S_ISDIR(ds.node->i_mode))
+	if (S_ISDIR(ds.node->i_mode)) {
+		iput(ds.dir);
+		iput(ds.node);
 		return EPERM;
+	}
 
 	// Delete it from its directory
 
@@ -759,8 +762,10 @@
 	this.hash = end_name_hash(hash);
 
 	err = jffs2_unlink(ds.dir, ds.node, &this);
+	iput(ds.dir);
+	iput(ds.node);
 
-	return err;
+	return -err;
 }
 
 // -------------------------------------------------------------------------
@@ -803,22 +808,18 @@
 			this.len = hashname - (const char *) this.name;
 			this.hash = end_name_hash(hash);
 
-			err = jffs2_mkdir(ds.dir, &this, 0, &node);
-
-			if (err != 0)
-				return ENOSPC;
-
+			err = -jffs2_mkdir(ds.dir, &this, 0, &node);
 		}
-		// If this was not the last element, then and intermediate
+		// If this was not the last element, then an intermediate
 		// directory does not exist.
 	} else {
 		// If there we no error, something already exists with that
 		// name, so we cannot create another one.
-
+		iput(ds.node);
 		if (err == ENOERR)
 			err = EEXIST;
 	}
-
+	iput(ds.dir);
 	return err;
 }
 
@@ -843,12 +844,17 @@
 
 	err = jffs2_find(&ds);
 
-	if (err != ENOERR)
+	if (err != ENOERR) {
+		iput(ds.dir);
 		return err;
+	}
 
 	// Check that this is actually a directory.
-	if (!S_ISDIR(ds.node->i_mode))
+	if (!S_ISDIR(ds.node->i_mode)) {
+		iput(ds.dir);
+		iput(ds.node);
 		return EPERM;
+	}
 
 	// Delete the entry. 
 	hashname = ds.name;
@@ -866,9 +872,9 @@
 
 	err = jffs2_rmdir(ds.dir, ds.node, &this);
 
-	return err;
-
-	return ENOERR;
+	iput(ds.dir);
+	iput(ds.node);
+	return -err;
 }
 
 // -------------------------------------------------------------------------
@@ -891,23 +897,33 @@
 
 	err = jffs2_find(&ds1);
 
-	if (err != ENOERR)
+	if (err != ENOERR) {
+		iput(ds1.dir);
 		return err;
+	}
 
 	init_dirsearch(&ds2, (struct inode *) dir2, name2);
 
 	err = jffs2_find(&ds2);
 
 	// Allow through renames to non-existent objects.
-	if (ds2.last && err == ENOENT)
-		ds2.node = NULL, err = ENOERR;
+	if (ds2.last && err == ENOENT) {
+		ds2.node = NULL;
+		err = ENOERR;
+	}
 
-	if (err != ENOERR)
+	if (err != ENOERR) {
+		iput(ds1.dir);
+		iput(ds1.node);
+		iput(ds2.dir);
 		return err;
+	}
 
 	// Null rename, just return
-	if (ds1.node == ds2.node)
-		return ENOERR;
+	if (ds1.node == ds2.node) {
+		err = ENOERR;
+		goto out;
+	}
 
 	hashname = ds1.name;
 	this1.name = hashname;
@@ -939,33 +955,43 @@
 	if (ds2.node) {
 		// Check that we are renaming like-for-like
 
-		if (!S_ISDIR(ds1.node->i_mode) && S_ISDIR(ds2.node->i_mode))
-			return EISDIR;
+		if (!S_ISDIR(ds1.node->i_mode) && S_ISDIR(ds2.node->i_mode)) {
+			err = EISDIR;
+			goto out;
+		}
 
-		if (S_ISDIR(ds1.node->i_mode) && !S_ISDIR(ds2.node->i_mode))
-			return ENOTDIR;
+		if (S_ISDIR(ds1.node->i_mode) && !S_ISDIR(ds2.node->i_mode)) {
+			err = ENOTDIR;
+			goto out;
+		}
 
 		// Now delete the destination directory entry
 
-		err = jffs2_unlink(ds2.dir, ds2.node, &this2);
+		err = -jffs2_unlink(ds2.dir, ds2.node, &this2);
 
 		if (err != 0)
-			return err;
+			goto out;
 
 	}
 	// Now we know that there is no clashing node at the destination,
 	// make a new direntry at the destination and delete the old entry
 	// at the source.
 
-	err = jffs2_rename(ds1.dir, ds1.node, &this1, ds2.dir, &this2);
+	err = -jffs2_rename(ds1.dir, ds1.node, &this1, ds2.dir, &this2);
 
 	// Update directory times
-	if (err == 0)
+	if (!err)
 		ds1.dir->i_ctime =
 		    ds1.dir->i_mtime =
 		    ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp();
-
-	return err;
+ out:
+	iput(ds1.dir);
+	iput(ds1.node);
+	iput(ds2.dir);
+	if (ds2.node)
+		iput(ds2.node);
+ 
+	return -err;
 }
 
 // -------------------------------------------------------------------------
@@ -992,23 +1018,37 @@
 
 	err = jffs2_find(&ds1);
 
-	if (err != ENOERR)
+	if (err != ENOERR) {
+		iput(ds1.dir);
 		return err;
+	}
 
 	init_dirsearch(&ds2, (struct inode *) dir2, name2);
 
 	err = jffs2_find(&ds2);
 
 	// Don't allow links to existing objects
-	if (err == ENOERR)
+	if (err == ENOERR) {
+		iput(ds1.dir);
+		iput(ds1.node);
+		iput(ds2.dir);
+		iput(ds2.node);
 		return EEXIST;
+	}
 
 	// Allow through links to non-existing terminal objects
-	if (ds2.last && err == ENOENT)
-		ds2.node = NULL, err = ENOERR;
+	if (ds2.last && err == ENOENT) {
+		iput(ds2.node);
+		ds2.node = NULL;
+		err = ENOERR;
+	}
 
-	if (err != ENOERR)
+	if (err != ENOERR) {
+		iput(ds1.dir);
+		iput(ds1.node);
+		iput(ds2.dir);
 		return err;
+	}
 
 	// Now we know that there is no existing node at the destination,
 	// make a new direntry at the destination.
@@ -1032,7 +1072,11 @@
 		ds1.node->i_ctime =
 		    ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp();
 
-	return err;
+	iput(ds1.dir);
+	iput(ds1.node);
+	iput(ds2.dir);
+
+	return -err;
 }
 
 // -------------------------------------------------------------------------
@@ -1053,14 +1097,16 @@
 
 	err = jffs2_find(&ds);
 
+	iput(ds.dir);
+
 	if (err != ENOERR)
 		return err;
 
 	// check it is really a directory.
-	if (!S_ISDIR(ds.node->i_mode))
+	if (!S_ISDIR(ds.node->i_mode)) {
+		iput(ds.node);
 		return ENOTDIR;
-
-	ds.node->i_count++;	// Count successful open
+	}
 
 	// Initialize the file object, setting the f_ops field to a
 	// special set of file ops.
@@ -1096,6 +1142,8 @@
 		init_dirsearch(&ds, (struct inode *) dir, name);
 
 		err = jffs2_find(&ds);
+		iput(ds.dir);
+		iput((struct inode *)dir);
 
 		if (err != ENOERR)
 			return err;
@@ -1104,10 +1152,6 @@
 		if (!S_ISDIR(ds.node->i_mode))
 			return ENOTDIR;
 
-		// Increment ref count to keep this directory in existance
-		// while it is the current cdir.
-		ds.node->i_count++;
-
 		// Pass it out
 		*dir_out = (cyg_dir) ds.node;
 	} else {
@@ -1118,7 +1162,7 @@
 		struct inode *node = (struct inode *) dir;
 
 		// Just decrement directory reference count.
-		dec_refcnt(node);
+		iput(node);
 	}
 
 	return ENOERR;
@@ -1141,6 +1185,7 @@
 	init_dirsearch(&ds, (struct inode *) dir, name);
 
 	err = jffs2_find(&ds);
+	iput(ds.dir);
 
 	if (err != ENOERR)
 		return err;
@@ -1157,7 +1202,7 @@
 	buf->st_mtime = ds.node->i_mtime;
 	buf->st_ctime = ds.node->i_ctime;
 
-	return err;
+	iput(ds.node);
 
 	return ENOERR;
 }
@@ -1179,6 +1224,7 @@
 	init_dirsearch(&ds, (struct inode *) dir, name);
 
 	err = jffs2_find(&ds);
+	iput(ds.dir);
 
 	if (err != ENOERR)
 		return err;
@@ -1191,9 +1237,9 @@
 	default:
 		err = EINVAL;
 	}
-	return err;
 
-	return ENOERR;
+	iput(ds.node);
+	return err;
 }
 
 // -------------------------------------------------------------------------
@@ -1445,7 +1491,7 @@
 
 	D2(printf("jffs2_fo_close\n"));
 
-	dec_refcnt(node);
+	iput(node);
 
 	fp->f_data = 0;		// zero data pointer
 
@@ -1630,7 +1676,7 @@
 //
 //==========================================================================
 
-struct page *read_cache_page(unsigned long index,
+static struct page *read_cache_page(unsigned long index,
 			     int (*filler) (void *, struct page *), void *data)
 {
 	// Only called in gc.c jffs2_garbage_collect_dnode
@@ -1656,7 +1702,7 @@
 	return gc_page;
 }
 
-void page_cache_release(struct page *pg)
+static void page_cache_release(struct page *pg)
 {
 
 	// Only called in gc.c jffs2_garbage_collect_dnode
@@ -1666,7 +1712,34 @@
 	free(pg);
 }
 
-struct inode *new_inode(struct super_block *sb)
+unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, 
+				   struct jffs2_inode_info *f, 
+				   unsigned long offset,
+				   unsigned long *priv)
+{
+	struct inode *inode = OFNI_EDONI_2SFFJ(f);
+	struct page *pg;
+
+	pg = read_cache_page(offset >> PAGE_CACHE_SHIFT, 
+			     (void *)jffs2_do_readpage_unlock, inode);
+	if (IS_ERR(pg))
+		return (void *)pg;
+	
+	*priv = (unsigned long)pg;
+	return kmap(pg);
+}
+
+void jffs2_gc_release_page(struct jffs2_sb_info *c,
+			   unsigned char *ptr,
+			   unsigned long *priv)
+{
+	struct page *pg = (void *)*priv;
+
+	kunmap(pg);
+	page_cache_release(pg);
+}
+
+static struct inode *new_inode(struct super_block *sb)
 {
 
 	// Only called in write.c jffs2_new_inode
@@ -1723,10 +1796,6 @@
 
 struct inode *iget(struct super_block *sb, cyg_uint32 ino)
 {
-
-	// Substitute for iget drops straight through to reading the 
-	// inode from disk if it is not in the inode cache
-
 	// Called in super.c jffs2_read_super, dir.c jffs2_lookup,
 	// and gc.c jffs2_garbage_collect_pass
 
@@ -1747,29 +1816,39 @@
 		return 0;
 
 	inode->i_ino = ino;
-	jffs2_read_inode(inode);
 	inode->i_count = 1;
+	if (jffs2_read_inode(inode)) {
+		printf("jffs2_read_inode() failed\n");
+		iput(inode);
+		inode = NULL;
+	}
 	return inode;
 }
 
+// -------------------------------------------------------------------------
+// Decrement the reference count on an inode. If this makes the ref count
+// zero, then this inode can be freed.
+
 void iput(struct inode *i)
 {
 
-	// Called in dec_refcnt, jffs2_find 
+	// Called in jffs2_find 
 	// (and jffs2_open and jffs2_ops_mkdir?)
 	// super.c jffs2_read_super,
 	// and gc.c jffs2_garbage_collect_pass
 
 	struct inode *cached_inode;
 
-	D2(printf
-	   ("free iput inode %x $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n", i));
-	if (i && i->i_count) {
-		/* Added by dwmw2. iget/iput in Linux track the use count,
-		   don't just unconditionally free it */
-		printf("iput called for used inode\n");
-		return;
+	if (!i) {
+		printf("iput() called with NULL inode\n");
+		// and let it fault... 
 	}
+	     
+	i->i_count--;
+
+	if (i->i_count)
+		return;
+
 	if (i != NULL) {
 		// Remove from the icache
 		for (cached_inode = i->i_sb->s_root; cached_inode != NULL;
@@ -2026,13 +2105,11 @@
 
 	inode->i_size = 0;
 
-	insert_inode_hash(inode);
-
 	return inode;
 }
 
 
-void jffs2_read_inode (struct inode *inode)
+static int jffs2_read_inode (struct inode *inode)
 {
 	struct jffs2_inode_info *f;
 	struct jffs2_sb_info *c;
@@ -2051,7 +2128,7 @@
 	if (ret) {
 		make_bad_inode(inode);
 		up(&f->sem);
-		return;
+		return ret;
 	}
 	inode->i_mode = jemode_to_cpu(latest_node.mode);
 	inode->i_uid = je16_to_cpu(latest_node.uid);
@@ -2065,4 +2142,76 @@
 	up(&f->sem);
 
 	D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n"));
+	return 0;
 }
+
+
+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: os-ecos.h
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/ecos/src/os-ecos.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- os-ecos.h	20 Nov 2003 16:41:58 -0000	1.8
+++ os-ecos.h	24 Nov 2003 13:43:58 -0000	1.9
@@ -228,6 +228,21 @@
 //int jffs2_commit_write (struct file *, struct page *, unsigned, unsigned);
 int jffs2_commit_write (struct inode *d_inode, struct page *pg, unsigned start, unsigned end);
 
+/* fs.c */
+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);
+
+unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, 
+				   struct jffs2_inode_info *f, 
+				   unsigned long offset,
+				   unsigned long *priv);
+void jffs2_gc_release_page(struct jffs2_sb_info *c,
+			   unsigned char *pg,
+			   unsigned long *priv);
+     
+
 #ifndef CONFIG_JFFS2_FS_NAND
 #define jffs2_can_mark_obsolete(c) (1)
 #define jffs2_cleanmarker_oob(c) (0)
@@ -248,7 +263,6 @@
 #endif
 struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri);
 void jffs2_clear_inode (struct inode *inode);
-void jffs2_read_inode (struct inode *inode);
 
 static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
 {




More information about the linux-mtd-cvs mailing list