changeset 1881:9558d3d305bf

Merge from public MTD repository
author asl
date Sat, 22 Jan 2005 17:14:48 +0000
parents f1b7f56dba25
children 34ebc3d61174
files packages/fs/jffs2/current/ChangeLog packages/fs/jffs2/current/cdl/jffs2.cdl packages/fs/jffs2/current/doc/README.Locking packages/fs/jffs2/current/doc/readme.txt packages/fs/jffs2/current/include/linux/jffs2.h packages/fs/jffs2/current/include/linux/jffs2_fs_sb.h packages/fs/jffs2/current/src/build.c packages/fs/jffs2/current/src/compr.c packages/fs/jffs2/current/src/compr_zlib.c packages/fs/jffs2/current/src/erase.c packages/fs/jffs2/current/src/fs-ecos.c packages/fs/jffs2/current/src/gc.c packages/fs/jffs2/current/src/nodelist.c packages/fs/jffs2/current/src/nodelist.h packages/fs/jffs2/current/src/nodemgmt.c packages/fs/jffs2/current/src/pushpull.h packages/fs/jffs2/current/src/read.c packages/fs/jffs2/current/src/readinode.c packages/fs/jffs2/current/src/scan.c packages/fs/jffs2/current/src/write.c packages/fs/jffs2/current/tests/jffs2_1.c packages/fs/jffs2/current/tests/jffs2_2.c packages/fs/jffs2/current/tests/romfileio1.c
diffstat 23 files changed, 251 insertions(+), 512 deletions(-) [+]
line wrap: on
line diff
--- a/packages/fs/jffs2/current/ChangeLog
+++ b/packages/fs/jffs2/current/ChangeLog
@@ -1,3 +1,7 @@
+2005-01-22  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* Merge from public MTD.
+	
 2004-11-14  Per Hedblom  <perhedblom@abem.se>
             Andrew Lunn  <andrew.lunn@ascom.ch> 
 	
--- a/packages/fs/jffs2/current/cdl/jffs2.cdl
+++ b/packages/fs/jffs2/current/cdl/jffs2.cdl
@@ -4,7 +4,7 @@
 #
 #      JFFS2 Filesystem configuration data
 #
-#      $Id: jffs2.cdl,v 1.16 2004/11/11 20:48:54 lunn Exp $
+#      $Id: jffs2.cdl,v 1.18 2005/01/22 16:01:12 lunn Exp $
 #
 # ====================================================================
 #####ECOSGPLCOPYRIGHTBEGIN####
--- a/packages/fs/jffs2/current/doc/README.Locking
+++ b/packages/fs/jffs2/current/doc/README.Locking
@@ -1,4 +1,4 @@
-	$Id: README.Locking,v 1.6 2003/11/02 19:27:54 dwmw2 Exp $
+	$Id: README.Locking,v 1.11 2004/11/24 09:25:09 dedekind Exp $
 
 	JFFS2 LOCKING DOCUMENTATION
 	---------------------------
@@ -99,18 +99,53 @@ pointer when the garbage collection thre
 GC thread locks it, sends the signal, then unlocks it - while the GC
 thread itself locks it, zeroes c->gc_task, then unlocks on the exit path.
 
+
+	inocache_lock spinlock
+	----------------------
+
+This spinlock protects the hashed list (c->inocache_list) of the
+in-core jffs2_inode_cache objects (each inode in JFFS2 has the
+correspondent jffs2_inode_cache object). So, the inocache_lock
+has to be locked while walking the c->inocache_list hash buckets.
+
+Note, the f->sem guarantees that the correspondent jffs2_inode_cache
+will not be removed. So, it is allowed to access it without locking
+the inocache_lock spinlock. 
+
+Ordering constraints: 
+
+	c->erase_completion_lock and c->inocache_lock has special ordering:
+	1. c->erase_completion_lock (must be locked first)
+	2. c->inocache_lock
+
+
 	erase_free_sem
 	--------------
 
-This semaphore is only used by the erase code which frees obsolete
+This semaphore is used by the erase code which frees obsolete
 node references and the jffs2_garbage_collect_deletion_dirent()
 function. The latter function on NAND flash must read _obsolete_ nodes
 to determine whether the 'deletion dirent' under consideration can be
 discarded or whether it is still required to show that an inode has
 been unlinked. Because reading from the flash may sleep, the
-erase_completion_lock cannot be held, so an alternative, more
+erase_completion_lock can not be held, so an alternative, more
 heavyweight lock was required to prevent the erase code from freeing
 the jffs2_raw_node_ref structures in question while the garbage
 collection code is looking at them.
 
-Suggestions for alternative solutions to this problem would be welcomed.
+The erase_free_sem mutex is also used in the jffs2_mark_node_obsolete()
+function which manipulates obsolete nodes (which may be removed
+from the list and freed any time) and may sleep (since it reads flash).
+
+
+	wbuf_sem
+	--------
+
+This read/write semaphore protects against concurrent access to the
+write-behind buffer ('wbuf') used for flash chips where we must write
+in blocks. It protects both the contents of the wbuf and the metadata
+which indicates which flash region (if any) is currently covered by 
+the buffer.
+
+Ordering constraints:
+	Lock wbuf_sem last, after the alloc_sem or and f->sem.
--- a/packages/fs/jffs2/current/doc/readme.txt
+++ b/packages/fs/jffs2/current/doc/readme.txt
@@ -15,13 +15,18 @@ io/flash/current/src/flash.c
 
 devs/flash/intel/strata/current/src/flash_program_buf.c
 
-to allow byte aligned rather than word aligned writes, and to ensure overwriting an existing
-word is successful (these are supplied in jffs2/current/src).
+to allow byte aligned rather than word aligned writes, and to ensure
+overwriting an existing word is successful (these are supplied in
+jffs2/current/src).
 
 
-Two test files are included fileio1.c (which performs the same tests as used for eCos RamFS),
-and romfileio1.c (tests as eCos RomFS).
+Three test files are included jffs2_1.c (which performs the same tests
+as used for eCos RamFS), jffs2_2.c (tests is seeking works) and jffs2_3.c
+(garbage collection and memory leak detection)
 
-romfileio1.c requires that a jffs2 filesystem image jffs2.img is present at the desired mount point.
-This image was prepared on Linux with the tools originating with JFFS2 source from
-www.infradead.org
\ No newline at end of file
+jffs2_2.c requires that a jffs2 filesystem image jffs2.img is present
+at the desired mount point.  This image was prepared on Linux with the
+tools originating with JFFS2 source from www.infradead.org. Note that
+this image is little endian and will only work on little endian
+targets. For big endian targets it will be necassary to generate a new
+image.
--- a/packages/fs/jffs2/current/include/linux/jffs2.h
+++ b/packages/fs/jffs2/current/include/linux/jffs2.h
@@ -3,12 +3,12 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in the 
  * jffs2 directory.
  *
- * $Id: jffs2.h,v 1.33 2004/05/25 11:31:55 havasi Exp $
+ * $Id: jffs2.h,v 1.34 2004/11/16 20:36:14 dwmw2 Exp $
  *
  */
 
--- a/packages/fs/jffs2/current/include/linux/jffs2_fs_sb.h
+++ b/packages/fs/jffs2/current/include/linux/jffs2_fs_sb.h
@@ -1,4 +1,4 @@
-/* $Id: jffs2_fs_sb.h,v 1.46 2004/11/03 12:57:39 jwboyer Exp $ */
+/* $Id: jffs2_fs_sb.h,v 1.48 2004/11/20 10:41:12 dwmw2 Exp $ */
 
 #ifndef _JFFS2_FS_SB
 #define _JFFS2_FS_SB
@@ -11,6 +11,7 @@
 #include <linux/timer.h>
 #include <linux/wait.h>
 #include <linux/list.h>
+#include <linux/rwsem.h>
 
 #define JFFS2_SB_FLAG_RO 1
 #define JFFS2_SB_FLAG_MOUNTING 2
@@ -35,9 +36,7 @@ struct jffs2_sb_info {
 
 	struct semaphore alloc_sem;	/* Used to protect all the following 
 					   fields, and also to protect against
-					   out-of-order writing of nodes.
-					   And GC.
-					*/
+					   out-of-order writing of nodes. And GC. */
 	uint32_t cleanmarker_size;	/* Size of an _inline_ CLEANMARKER
 					 (i.e. zero for OOB CLEANMARKER */
 
@@ -103,6 +102,8 @@ struct jffs2_sb_info {
 	uint32_t wbuf_pagesize;
 	struct jffs2_inodirty *wbuf_inodes;
 
+	struct rw_semaphore wbuf_sem;	/* Protects the write buffer */
+
 	/* Information about out-of-band area usage... */
 	struct nand_oobinfo *oobinfo;
 	uint32_t badblock_pos;
--- a/packages/fs/jffs2/current/src/build.c
+++ b/packages/fs/jffs2/current/src/build.c
@@ -3,17 +3,19 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: build.c,v 1.55 2003/10/28 17:02:44 dwmw2 Exp $
+ * $Id: build.c,v 1.69 2004/12/16 20:22:18 dmarlin Exp $
  *
  */
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/mtd/mtd.h>
 #include "nodelist.h"
 
 static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *, struct jffs2_full_dirent **);
@@ -62,6 +64,7 @@ static inline void jffs2_build_inode_pas
 		if (!child_ic) {
 			printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
 				  fd->name, fd->ino, ic->ino);
+			jffs2_mark_node_obsolete(c, fd->raw);
 			continue;
 		}
 
@@ -88,6 +91,7 @@ static int jffs2_build_filesystem(struct
 	int ret;
 	int i;
 	struct jffs2_inode_cache *ic;
+	struct jffs2_full_dirent *fd;
 	struct jffs2_full_dirent *dead_fds = NULL;
 
 	/* First, scan the medium and build all the inode caches with
@@ -95,13 +99,11 @@ static int jffs2_build_filesystem(struct
 
 	c->flags |= JFFS2_SB_FLAG_MOUNTING;
 	ret = jffs2_scan_medium(c);
-	c->flags &= ~JFFS2_SB_FLAG_MOUNTING;
-
 	if (ret)
-		return ret;
+		goto exit;
 
 	D1(printk(KERN_DEBUG "Scanned flash completely\n"));
-	D1(jffs2_dump_block_lists(c));
+	D2(jffs2_dump_block_lists(c));
 
 	/* Now scan the directory tree, increasing nlink according to every dirent found. */
 	for_each_inode(i, c, ic) {
@@ -114,6 +116,8 @@ static int jffs2_build_filesystem(struct
 			cond_resched();
 		}
 	}
+	c->flags &= ~JFFS2_SB_FLAG_MOUNTING;
+
 	D1(printk(KERN_DEBUG "Pass 1 complete\n"));
 
 	/* Next, scan for inodes with nlink == 0 and remove them. If
@@ -135,9 +139,7 @@ static int jffs2_build_filesystem(struct
 	D1(printk(KERN_DEBUG "Pass 2a starting\n"));
 
 	while (dead_fds) {
-		struct jffs2_inode_cache *ic;
-		struct jffs2_full_dirent *fd = dead_fds;
-
+		fd = dead_fds;
 		dead_fds = fd->next;
 
 		ic = jffs2_get_ino_cache(c, fd->ino);
@@ -152,7 +154,6 @@ static int jffs2_build_filesystem(struct
 	
 	/* Finally, we can scan again and free the dirent structs */
 	for_each_inode(i, c, ic) {
-		struct jffs2_full_dirent *fd;
 		D1(printk(KERN_DEBUG "Pass 3: ino #%u, ic %p, nodes %p\n", ic->ino, ic, ic->nodes));
 
 		while(ic->scan_dents) {
@@ -164,11 +165,24 @@ static int jffs2_build_filesystem(struct
 		cond_resched();
 	}
 	D1(printk(KERN_DEBUG "Pass 3 complete\n"));
-	D1(jffs2_dump_block_lists(c));
+	D2(jffs2_dump_block_lists(c));
 
 	/* Rotate the lists by some number to ensure wear levelling */
 	jffs2_rotate_lists(c);
 
+	ret = 0;
+
+exit:
+	if (ret) {
+		for_each_inode(i, c, ic) {
+			while(ic->scan_dents) {
+				fd = ic->scan_dents;
+				ic->scan_dents = fd->next;
+				jffs2_free_full_dirent(fd);
+			}
+		}
+	}
+
 	return ret;
 }
 
@@ -179,9 +193,12 @@ static void jffs2_build_remove_unlinked_
 
 	D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino));
 	
-	for (raw = ic->nodes; raw != (void *)ic; raw = raw->next_in_ino) {
+	raw = ic->nodes;
+	while (raw != (void *)ic) {
+		struct jffs2_raw_node_ref *next = raw->next_in_ino;
 		D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", ref_offset(raw)));
 		jffs2_mark_node_obsolete(c, raw);
+		raw = next;
 	}
 
 	if (ic->scan_dents) {
@@ -297,7 +314,12 @@ int jffs2_do_mount_fs(struct jffs2_sb_in
 
 	c->free_size = c->flash_size;
 	c->nr_blocks = c->flash_size / c->sector_size;
-	c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL);
+#ifndef __ECOS
+ 	if (c->mtd->flags & MTD_NO_VIRTBLOCKS)
+		c->blocks = vmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks);
+	else
+#endif
+		c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL);
 	if (!c->blocks)
 		return -ENOMEM;
 	for (i=0; i<c->nr_blocks; i++) {
@@ -310,6 +332,7 @@ int jffs2_do_mount_fs(struct jffs2_sb_in
 		c->blocks[i].used_size = 0;
 		c->blocks[i].first_node = NULL;
 		c->blocks[i].last_node = NULL;
+		c->blocks[i].bad_count = 0;
 	}
 
 	init_MUTEX(&c->alloc_sem);
@@ -336,7 +359,13 @@ int jffs2_do_mount_fs(struct jffs2_sb_in
 		D1(printk(KERN_DEBUG "build_fs failed\n"));
 		jffs2_free_ino_caches(c);
 		jffs2_free_raw_node_refs(c);
-		kfree(c->blocks);
+#ifndef __ECOS
+		if (c->mtd->flags & MTD_NO_VIRTBLOCKS) 
+                    vfree(c->blocks);
+		else 
+#endif
+                    kfree(c->blocks);
+		
 		return -EIO;
 	}
 
--- a/packages/fs/jffs2/current/src/compr.c
+++ b/packages/fs/jffs2/current/src/compr.c
@@ -9,13 +9,13 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr.c,v 1.42 2004/08/07 21:56:08 dwmw2 Exp $
+ * $Id: compr.c,v 1.43 2005/01/12 22:34:35 gleixner Exp $
  *
  */
 
 #include "compr.h"
 
-static spinlock_t jffs2_compressor_list_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(jffs2_compressor_list_lock);
 
 /* Available compressors are on this list */
 static LIST_HEAD(jffs2_compressor_list);
--- a/packages/fs/jffs2/current/src/compr_zlib.c
+++ b/packages/fs/jffs2/current/src/compr_zlib.c
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr_zlib.c,v 1.28 2004/06/23 16:34:40 havasi Exp $
+ * $Id: compr_zlib.c,v 1.29 2004/11/16 20:36:11 dwmw2 Exp $
  *
  */
 
--- a/packages/fs/jffs2/current/src/erase.c
+++ b/packages/fs/jffs2/current/src/erase.c
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: erase.c,v 1.64 2004/11/12 15:25:14 jwboyer Exp $
+ * $Id: erase.c,v 1.69 2004/12/06 10:17:48 dedekind Exp $
  *
  */
 
@@ -47,6 +47,7 @@ void jffs2_erase_block(struct jffs2_sb_i
 #else /* Linux */
 	struct erase_info *instr;
 
+	D1(printk(KERN_DEBUG "jffs2_erase_block(): erase block %#x (range %#x-%#x)\n", jeb->offset, jeb->offset, jeb->offset + c->sector_size));
 	instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL);
 	if (!instr) {
 		printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n");
@@ -387,7 +388,7 @@ static void jffs2_mark_erased_block(stru
 		jeb->dirty_size = 0;
 		jeb->wasted_size = 0;
 	} else {
-		struct iovec vecs[1];
+		struct kvec vecs[1];
 		struct jffs2_unknown_node marker = {
 			.magic =	cpu_to_je16(JFFS2_MAGIC_BITMASK),
 			.nodetype =	cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER),
--- a/packages/fs/jffs2/current/src/fs-ecos.c
+++ b/packages/fs/jffs2/current/src/fs-ecos.c
@@ -8,7 +8,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: fs-ecos.c,v 1.39 2004/11/11 12:46:17 dwmw2 Exp $
+ * $Id: fs-ecos.c,v 1.41 2005/01/22 16:01:12 lunn Exp $
  *
  */
 
--- a/packages/fs/jffs2/current/src/gc.c
+++ b/packages/fs/jffs2/current/src/gc.c
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: gc.c,v 1.137 2004/07/20 13:44:55 dwmw2 Exp $
+ * $Id: gc.c,v 1.144 2004/12/21 11:18:50 dwmw2 Exp $
  *
  */
 
@@ -103,7 +103,7 @@ static struct jffs2_eraseblock *jffs2_fi
 		ret->wasted_size = 0;
 	}
 
-	D1(jffs2_dump_block_lists(c));
+	D2(jffs2_dump_block_lists(c));
 	return ret;
 }
 
@@ -134,7 +134,7 @@ int jffs2_garbage_collect_pass(struct jf
 		if (c->checked_ino > c->highest_ino) {
 			printk(KERN_CRIT "Checked all inodes but still 0x%x bytes of unchecked space?\n",
 			       c->unchecked_size);
-			D1(jffs2_dump_block_lists(c));
+			D2(jffs2_dump_block_lists(c));
 			spin_unlock(&c->erase_completion_lock);
 			BUG();
 		}
@@ -602,7 +602,7 @@ static int jffs2_garbage_collect_pristin
 			printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", nraw->flash_offset);
                         jffs2_free_raw_node_ref(nraw);
 		}
-		if (!retried && (nraw == jffs2_alloc_raw_node_ref())) {
+		if (!retried && (nraw = jffs2_alloc_raw_node_ref())) {
 			/* Try to reallocate space and retry */
 			uint32_t dummy;
 			struct jffs2_eraseblock *jeb = &c->blocks[phys_ofs / c->sector_size];
@@ -628,6 +628,7 @@ static int jffs2_garbage_collect_pristin
 			jffs2_free_raw_node_ref(nraw);
 		}
 
+		jffs2_free_raw_node_ref(nraw);
 		if (!ret)
 			ret = -EIO;
 		goto out_node;
@@ -637,10 +638,12 @@ static int jffs2_garbage_collect_pristin
 
 	/* Link into per-inode list. This is safe because of the ic
 	   state being INO_STATE_GC. Note that if we're doing this
-	   for an inode which is in-code, the 'nraw' pointer is then
+	   for an inode which is in-core, the 'nraw' pointer is then
 	   going to be fetched from ic->nodes by our caller. */
+	spin_lock(&c->erase_completion_lock);
         nraw->next_in_ino = ic->nodes;
         ic->nodes = nraw;
+	spin_unlock(&c->erase_completion_lock);
 
 	jffs2_mark_node_obsolete(c, raw);
 	D1(printk(KERN_DEBUG "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", ref_offset(raw)));
@@ -828,7 +831,7 @@ static int jffs2_garbage_collect_deletio
 				continue;
 			}
 			if (retlen != rawlen) {
-				printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %zd) reading header from obsolete node at %08x\n",
+				printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %u) reading header from obsolete node at %08x\n",
 				       retlen, rawlen, ref_offset(raw));
 				continue;
 			}
--- a/packages/fs/jffs2/current/src/nodelist.c
+++ b/packages/fs/jffs2/current/src/nodelist.c
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodelist.c,v 1.86 2003/10/31 15:37:51 dwmw2 Exp $
+ * $Id: nodelist.c,v 1.92 2005/01/19 19:22:00 tpoynor Exp $
  *
  */
 
@@ -92,42 +92,53 @@ static void jffs2_free_full_dirent_list(
 	}
 }
 
+/* Returns first valid node after 'ref'. May return 'ref' */
+static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_ref *ref)
+{
+	while (ref && ref->next_in_ino) {
+		if (!ref_obsolete(ref))
+			return ref;
+		D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref_offset(ref)));
+		ref = ref->next_in_ino;
+	}
+	return NULL;
+}
 
 /* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated
    with this ino, returning the former in order of version */
 
-int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode_info *f,
+int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
 			  struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp,
 			  uint32_t *highest_version, uint32_t *latest_mctime,
 			  uint32_t *mctime_ver)
 {
-	struct jffs2_raw_node_ref *ref = f->inocache->nodes;
+	struct jffs2_raw_node_ref *ref, *valid_ref;
 	struct jffs2_tmp_dnode_info *tn, *ret_tn = NULL;
 	struct jffs2_full_dirent *fd, *ret_fd = NULL;
-
 	union jffs2_node_union node;
 	size_t retlen;
 	int err;
 
 	*mctime_ver = 0;
-
-	D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%lu\n", ino));
-	if (!f->inocache->nodes) {
-		printk(KERN_WARNING "Eep. no nodes for ino #%lu\n", (unsigned long)ino);
-	}
+	
+	D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%u\n", f->inocache->ino));
 
 	spin_lock(&c->erase_completion_lock);
 
-	for (ref = f->inocache->nodes; ref && ref->next_in_ino; ref = ref->next_in_ino) {
-		/* Work out whether it's a data node or a dirent node */
-		if (ref_obsolete(ref)) {
-			/* FIXME: On NAND flash we may need to read these */
-			D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref_offset(ref)));
-			continue;
-		}
+	valid_ref = jffs2_first_valid_node(f->inocache->nodes);
+
+	if (!valid_ref && (f->inocache->ino != 1))
+		printk(KERN_WARNING "Eep. No valid nodes for ino #%u\n", f->inocache->ino);
+
+	while (valid_ref) {
 		/* We can hold a pointer to a non-obsolete node without the spinlock,
 		   but _obsolete_ nodes may disappear at any time, if the block
-		   they're in gets erased */
+		   they're in gets erased. So if we mark 'ref' obsolete while we're
+		   not holding the lock, it can go away immediately. For that reason,
+		   we find the next valid node first, before processing 'ref'.
+		*/
+		ref = valid_ref;
+		valid_ref = jffs2_first_valid_node(ref->next_in_ino);
 		spin_unlock(&c->erase_completion_lock);
 
 		cond_resched();
@@ -183,7 +194,6 @@ int jffs2_get_inode_nodes(struct jffs2_s
 				err = -ENOMEM;
 				goto free_out;
 			}
-			memset(fd,0,sizeof(struct jffs2_full_dirent) + node.d.nsize+1);
 			fd->raw = ref;
 			fd->version = je32_to_cpu(node.d.version);
 			fd->ino = je32_to_cpu(node.d.ino);
@@ -221,6 +231,7 @@ int jffs2_get_inode_nodes(struct jffs2_s
 			}
 			fd->nhash = full_name_hash(fd->name, node.d.nsize);
 			fd->next = NULL;
+			fd->name[node.d.nsize] = '\0';
 				/* Wheee. We now have a complete jffs2_full_dirent structure, with
 				   the name in it and everything. Link it into the list 
 				*/
@@ -479,6 +490,8 @@ void jffs2_add_ino_cache (struct jffs2_s
 {
 	struct jffs2_inode_cache **prev;
 	D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino));
+	BUG_ON(!new->ino);
+
 	spin_lock(&c->inocache_lock);
 	
 	prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE];
--- a/packages/fs/jffs2/current/src/nodelist.h
+++ b/packages/fs/jffs2/current/src/nodelist.h
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodelist.h,v 1.120 2004/10/07 15:11:54 havasi Exp $
+ * $Id: nodelist.h,v 1.126 2004/11/19 15:06:29 dedekind Exp $
  *
  */
 
@@ -107,16 +107,6 @@ struct jffs2_raw_node_ref
 #define ref_obsolete(ref)	(((ref)->flash_offset & 3) == REF_OBSOLETE)
 #define mark_ref_normal(ref)    do { (ref)->flash_offset = ref_offset(ref) | REF_NORMAL; } while(0)
 
-/* 
-   Used for keeping track of deletion nodes &c, which can only be marked
-   as obsolete when the node which they mark as deleted has actually been 
-   removed from the flash.
-*/
-struct jffs2_raw_node_ref_list {
-	struct jffs2_raw_node_ref *rew;
-	struct jffs2_raw_node_ref_list *next;
-};
-
 /* For each inode in the filesystem, we need to keep a record of
    nlink, because it would be a PITA to scan the whole directory tree
    at read_inode() time to calculate it, and to keep sufficient information
@@ -148,13 +138,6 @@ struct jffs2_inode_cache {
 
 #define INOCACHE_HASHSIZE 128
 
-struct jffs2_scan_info {
-	struct jffs2_full_dirent *dents;
-	struct jffs2_tmp_dnode_info *tmpnodes;
-	/* Latest i_size info */
-	uint32_t version;
-	uint32_t isize;
-};
 /*
   Larger representation of a raw node, kept in-core only when the 
   struct inode for this particular ino is instantiated.
@@ -163,12 +146,11 @@ struct jffs2_scan_info {
 struct jffs2_full_dnode
 {
 	struct jffs2_raw_node_ref *raw;
-	uint32_t ofs; /* Don't really need this, but optimisation */
+	uint32_t ofs; /* The offset to which the data of this node belongs */
 	uint32_t size;
 	uint32_t frags; /* Number of fragments which currently refer
 			to this node. When this reaches zero, 
-			the node is obsolete.
-		     */
+			the node is obsolete.  */
 };
 
 /* 
@@ -193,6 +175,7 @@ struct jffs2_full_dirent
 	unsigned char type;
 	unsigned char name[0];
 };
+
 /*
   Fragments - used to build a map of which raw node to obtain 
   data from for each part of the ino
@@ -202,7 +185,7 @@ struct jffs2_node_frag
 	struct rb_node rb;
 	struct jffs2_full_dnode *node; /* NULL for holes */
 	uint32_t size;
-	uint32_t ofs; /* Don't really need this, but optimisation */
+	uint32_t ofs; /* The offset to which this fragment belongs */
 };
 
 struct jffs2_eraseblock
@@ -221,14 +204,6 @@ struct jffs2_eraseblock
 	struct jffs2_raw_node_ref *last_node;
 
 	struct jffs2_raw_node_ref *gc_node;	/* Next node to be garbage collected */
-
-	/* For deletia. When a dirent node in this eraseblock is
-	   deleted by a node elsewhere, that other node can only 
-	   be marked as obsolete when this block is actually erased.
-	   So we keep a list of the nodes to mark as obsolete when
-	   the erase is completed.
-	*/
-	// MAYBE	struct jffs2_raw_node_ref_list *deletia;
 };
 
 #define ACCT_SANITY_CHECK(c, jeb) do { \
@@ -396,9 +371,9 @@ static inline struct jffs2_node_frag *fr
 #define frag_erase(frag, list) rb_erase(&frag->rb, list);
 
 /* nodelist.c */
-D1(void jffs2_print_frag_list(struct jffs2_inode_info *f));
+D2(void jffs2_print_frag_list(struct jffs2_inode_info *f));
 void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list);
-int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode_info *f,
+int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
 			  struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp,
 			  uint32_t *highest_version, uint32_t *latest_mctime,
 			  uint32_t *mctime_ver);
--- a/packages/fs/jffs2/current/src/nodemgmt.c
+++ b/packages/fs/jffs2/current/src/nodemgmt.c
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodemgmt.c,v 1.109 2004/10/07 15:08:47 havasi Exp $
+ * $Id: nodemgmt.c,v 1.115 2004/11/22 11:07:21 dwmw2 Exp $
  *
  */
 
@@ -399,6 +399,17 @@ void jffs2_mark_node_obsolete(struct jff
 	}
 	jeb = &c->blocks[blocknr];
 
+	if (jffs2_can_mark_obsolete(c) && !jffs2_is_readonly(c) &&
+	    !(c->flags & JFFS2_SB_FLAG_MOUNTING)) {
+		/* Hm. This may confuse static lock analysis. If any of the above 
+		   three conditions is false, we're going to return from this 
+		   function without actually obliterating any nodes or freeing
+		   any jffs2_raw_node_refs. So we don't need to stop erases from
+		   happening, or protect against people holding an obsolete
+		   jffs2_raw_node_ref without the erase_completion_lock. */
+		down(&c->erase_free_sem);
+	}
+
 	spin_lock(&c->erase_completion_lock);
 
 	if (ref_flags(ref) == REF_UNCHECKED) {
@@ -463,6 +474,7 @@ void jffs2_mark_node_obsolete(struct jff
 		   marked obsolete on the flash at the time they _became_
 		   obsolete, there was probably a reason for that. */
 		spin_unlock(&c->erase_completion_lock);
+		/* We didn't lock the erase_free_sem */
 		return;
 	}
 
@@ -515,61 +527,87 @@ void jffs2_mark_node_obsolete(struct jff
 
 	spin_unlock(&c->erase_completion_lock);
 
-	if (!jffs2_can_mark_obsolete(c))
+	if (!jffs2_can_mark_obsolete(c) || jffs2_is_readonly(c)) {
+		/* We didn't lock the erase_free_sem */
 		return;
-	if (jffs2_is_readonly(c))
-		return;
+	}
+
+	/* The erase_free_sem is locked, and has been since before we marked the node obsolete
+	   and potentially put its eraseblock onto the erase_pending_list. Thus, we know that
+	   the block hasn't _already_ been erased, and that 'ref' itself hasn't been freed yet
+	   by jffs2_free_all_node_refs() in erase.c. Which is nice. */
 
 	D1(printk(KERN_DEBUG "obliterating obsoleted node at 0x%08x\n", ref_offset(ref)));
 	ret = jffs2_flash_read(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n);
 	if (ret) {
 		printk(KERN_WARNING "Read error reading from obsoleted node at 0x%08x: %d\n", ref_offset(ref), ret);
-		return;
+		goto out_erase_sem;
 	}
 	if (retlen != sizeof(n)) {
 		printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen);
-		return;
+		goto out_erase_sem;
 	}
 	if (PAD(je32_to_cpu(n.totlen)) != PAD(ref_totlen(c, jeb, ref))) {
 		printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen from node ref (0x%08x)\n", je32_to_cpu(n.totlen), ref_totlen(c, jeb, ref));
-		return;
+		goto out_erase_sem;
 	}
 	if (!(je16_to_cpu(n.nodetype) & JFFS2_NODE_ACCURATE)) {
 		D1(printk(KERN_DEBUG "Node at 0x%08x was already marked obsolete (nodetype 0x%04x)\n", ref_offset(ref), je16_to_cpu(n.nodetype)));
-		return;
+		goto out_erase_sem;
 	}
 	/* XXX FIXME: This is ugly now */
 	n.nodetype = cpu_to_je16(je16_to_cpu(n.nodetype) & ~JFFS2_NODE_ACCURATE);
 	ret = jffs2_flash_write(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n);
 	if (ret) {
 		printk(KERN_WARNING "Write error in obliterating obsoleted node at 0x%08x: %d\n", ref_offset(ref), ret);
-		return;
+		goto out_erase_sem;
 	}
 	if (retlen != sizeof(n)) {
 		printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen);
-		return;
+		goto out_erase_sem;
 	}
 
 	/* Nodes which have been marked obsolete no longer need to be
-	   associated with any inode. Remove them from the per-inode list */
+	   associated with any inode. Remove them from the per-inode list.
+	   
+	   Note we can't do this for NAND at the moment because we need 
+	   obsolete dirent nodes to stay on the lists, because of the
+	   horridness in jffs2_garbage_collect_deletion_dirent(). Also
+	   because we delete the inocache, and on NAND we need that to 
+	   stay around until all the nodes are actually erased, in order
+	   to stop us from giving the same inode number to another newly
+	   created inode. */
 	if (ref->next_in_ino) {
 		struct jffs2_inode_cache *ic;
 		struct jffs2_raw_node_ref **p;
 
+		spin_lock(&c->erase_completion_lock);
+
 		ic = jffs2_raw_ref_to_ic(ref);
 		for (p = &ic->nodes; (*p) != ref; p = &((*p)->next_in_ino))
 			;
 
 		*p = ref->next_in_ino;
 		ref->next_in_ino = NULL;
+
+		if (ic->nodes == (void *)ic) {
+			D1(printk(KERN_DEBUG "inocache for ino #%u is all gone now. Freeing\n", ic->ino));
+			jffs2_del_ino_cache(c, ic);
+			jffs2_free_inode_cache(ic);
+		}
+
+		spin_unlock(&c->erase_completion_lock);
 	}
 
 
 	/* Merge with the next node in the physical list, if there is one
-	   and if it's also obsolete. */
-	if (ref->next_phys && ref_obsolete(ref->next_phys) ) {
+	   and if it's also obsolete and if it doesn't belong to any inode */
+	if (ref->next_phys && ref_obsolete(ref->next_phys) &&
+	    !ref->next_phys->next_in_ino) {
 		struct jffs2_raw_node_ref *n = ref->next_phys;
 		
+		spin_lock(&c->erase_completion_lock);
+
 		ref->__totlen += n->__totlen;
 		ref->next_phys = n->next_phys;
                 if (jeb->last_node == n) jeb->last_node = ref;
@@ -577,7 +615,8 @@ void jffs2_mark_node_obsolete(struct jff
 			/* gc will be happy continuing gc on this node */
 			jeb->gc_node=ref;
 		}
-		BUG_ON(n->next_in_ino);
+		spin_unlock(&c->erase_completion_lock);
+
 		jffs2_free_raw_node_ref(n);
 	}
 	
@@ -585,11 +624,13 @@ void jffs2_mark_node_obsolete(struct jff
 	   and that one is obsolete */
 	if (ref != jeb->first_node ) {
 		struct jffs2_raw_node_ref *p = jeb->first_node;
-		
+
+		spin_lock(&c->erase_completion_lock);
+
 		while (p->next_phys != ref)
 			p = p->next_phys;
 		
-		if (ref_obsolete(p) ) {
+		if (ref_obsolete(p) && !ref->next_in_ino) {
 			p->__totlen += ref->__totlen;
 			if (jeb->last_node == ref) {
 				jeb->last_node = p;
@@ -601,10 +642,13 @@ void jffs2_mark_node_obsolete(struct jff
 			p->next_phys = ref->next_phys;
 			jffs2_free_raw_node_ref(ref);
 		}
+		spin_unlock(&c->erase_completion_lock);
 	}
+ out_erase_sem:
+	up(&c->erase_free_sem);
 }
 
-#if CONFIG_JFFS2_FS_DEBUG > 0
+#if CONFIG_JFFS2_FS_DEBUG >= 2
 void jffs2_dump_block_lists(struct jffs2_sb_info *c)
 {
 
--- a/packages/fs/jffs2/current/src/pushpull.h
+++ b/packages/fs/jffs2/current/src/pushpull.h
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001, 2002 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: pushpull.h,v 1.9 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: pushpull.h,v 1.10 2004/11/16 20:36:11 dwmw2 Exp $
  *
  */
 
--- a/packages/fs/jffs2/current/src/read.c
+++ b/packages/fs/jffs2/current/src/read.c
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: read.c,v 1.36 2004/05/25 11:12:32 havasi Exp $
+ * $Id: read.c,v 1.38 2004/11/16 20:36:12 dwmw2 Exp $
  *
  */
 
@@ -174,7 +174,7 @@ int jffs2_read_inode_range(struct jffs2_
 			if (frag) {
 				D1(printk(KERN_NOTICE "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f->inocache->ino, frag->ofs, offset));
 				holesize = min(holesize, frag->ofs - offset);
-				D1(jffs2_print_frag_list(f));
+				D2(jffs2_print_frag_list(f));
 			}
 			D1(printk(KERN_DEBUG "Filling non-frag hole from %d-%d\n", offset, offset+holesize));
 			memset(buf, 0, holesize);
--- a/packages/fs/jffs2/current/src/readinode.c
+++ b/packages/fs/jffs2/current/src/readinode.c
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: readinode.c,v 1.113 2003/11/03 13:20:33 dwmw2 Exp $
+ * $Id: readinode.c,v 1.117 2004/11/20 18:06:54 dwmw2 Exp $
  *
  */
 
@@ -22,7 +22,7 @@
 
 static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag);
 
-#if CONFIG_JFFS2_FS_DEBUG >= 1
+#if CONFIG_JFFS2_FS_DEBUG >= 2
 static void jffs2_print_fragtree(struct rb_root *list, int permitbug)
 {
 	struct jffs2_node_frag *this = frag_first(list);
@@ -56,7 +56,9 @@ void jffs2_print_frag_list(struct jffs2_
 		printk(KERN_DEBUG "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
 	}
 }
+#endif
 
+#if CONFIG_JFFS2_FS_DEBUG >= 1
 static int jffs2_sanitycheck_fragtree(struct jffs2_inode_info *f)
 {
 	struct jffs2_node_frag *frag;
@@ -225,7 +227,7 @@ static int jffs2_add_frag_to_fragtree(st
 		   If so, both 'this' and the new node get marked REF_NORMAL so
 		   the GC can take a look.
 		*/
-		if ((lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) {
+		if (lastend && (lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) {
 			if (this->node)
 				mark_ref_normal(this->node->raw);
 			mark_ref_normal(newfrag->node->raw);
@@ -510,7 +512,7 @@ static int jffs2_do_read_inode_internal(
 	D1(printk(KERN_DEBUG "jffs2_do_read_inode_internal(): ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink));
 
 	/* Grab all nodes relevant to this ino */
-	ret = jffs2_get_inode_nodes(c, f->inocache->ino, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver);
+	ret = jffs2_get_inode_nodes(c, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver);
 
 	if (ret) {
 		printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %u returned %d\n", f->inocache->ino, ret);
--- a/packages/fs/jffs2/current/src/scan.c
+++ b/packages/fs/jffs2/current/src/scan.c
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: scan.c,v 1.113 2004/11/03 12:57:39 jwboyer Exp $
+ * $Id: scan.c,v 1.115 2004/11/17 12:59:08 dedekind Exp $
  *
  */
 #include <linux/kernel.h>
@@ -160,11 +160,8 @@ int jffs2_scan_medium(struct jffs2_sb_in
 
 		case BLK_STATE_PARTDIRTY:
                         /* Some data, but not full. Dirty list. */
-                        /* Except that we want to remember the block with most free space,
-                           and stick it in the 'nextblock' position to start writing to it.
-                           Later when we do snapshots, this must be the most recent block,
-                           not the one with most free space.
-                        */
+                        /* We want to remember the block with most free space
+                           and stick it in the 'nextblock' position to start writing to it. */
                         if (jeb->free_size > min_free(c) && 
 			    (!c->nextblock || c->nextblock->free_size < jeb->free_size)) {
                                 /* Better candidate for the next writes to go to */
--- a/packages/fs/jffs2/current/src/write.c
+++ b/packages/fs/jffs2/current/src/write.c
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: write.c,v 1.85 2004/07/13 08:58:25 dwmw2 Exp $
+ * $Id: write.c,v 1.87 2004/11/16 20:36:12 dwmw2 Exp $
  *
  */
 
@@ -213,8 +213,10 @@ struct jffs2_full_dnode *jffs2_write_dno
 	jffs2_add_physical_node_ref(c, raw);
 
 	/* Link into per-inode list */
+	spin_lock(&c->erase_completion_lock);
 	raw->next_in_ino = f->inocache->nodes;
 	f->inocache->nodes = raw;
+	spin_unlock(&c->erase_completion_lock);
 
 	D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x(%d) with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n",
 		  flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize), 
@@ -333,8 +335,10 @@ struct jffs2_full_dirent *jffs2_write_di
 	raw->flash_offset |= REF_PRISTINE;
 	jffs2_add_physical_node_ref(c, raw);
 
+	spin_lock(&c->erase_completion_lock);
 	raw->next_in_ino = f->inocache->nodes;
 	f->inocache->nodes = raw;
+	spin_unlock(&c->erase_completion_lock);
 
 	if (retried) {
 		ACCT_SANITY_CHECK(c,NULL);
--- a/packages/fs/jffs2/current/tests/jffs2_1.c
+++ b/packages/fs/jffs2/current/tests/jffs2_1.c
@@ -654,15 +654,11 @@ int main( int argc, char **argv )
     err = chdir( "/" );
     if( err < 0 ) SHOW_RESULT( chdir, err );
     checkcwd( "/" );
-#ifdef CYGOPT_FS_JFFS2_GCTHREAD    
-    diag_printf("<INFO>: Letting garbage collect thread run\n");
-    cyg_thread_delay(2*100);
-#endif
     
     diag_printf("<INFO>: umount /jffs2\n");    
     err = umount( "/jffs2" );
     if( err < 0 ) SHOW_RESULT( umount, err );    
-
+    
     diag_printf("<INFO>: umount /\n");    
     err = umount( "/" );
     if( err < 0 ) SHOW_RESULT( umount, err );    
--- a/packages/fs/jffs2/current/tests/jffs2_2.c
+++ b/packages/fs/jffs2/current/tests/jffs2_2.c
@@ -45,7 +45,7 @@
 // Contributors:        asl
 // Date:                2004-03-29
 // Purpose:             Test fseek on a filesystem
-// Description:         This test uses the jffs2 to check out the fseek
+// Description:         This test uses the ramfs to check out the fseek
 //                      operation on a filesystem.
 //                      
 //                      
deleted file mode 100644
--- a/packages/fs/jffs2/current/tests/romfileio1.c
+++ /dev/null
@@ -1,370 +0,0 @@
-//==========================================================================
-//
-//      fileio1.c
-//
-//      Test fileio system
-//
-//==========================================================================
-//####ECOSGPLCOPYRIGHTBEGIN####
-// -------------------------------------------
-// This file is part of eCos, the Embedded Configurable Operating System.
-// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
-//
-// eCos is free software; you can redistribute it and/or modify it under
-// the terms of the GNU General Public License as published by the Free
-// Software Foundation; either version 2 or (at your option) any later version.
-//
-// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
-// WARRANTY; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-// for more details.
-//
-// You should have received a copy of the GNU General Public License along
-// with eCos; if not, write to the Free Software Foundation, Inc.,
-// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
-//
-// As a special exception, if other files instantiate templates or use macros
-// or inline functions from this file, or you compile this file and link it
-// with other works to produce a work based on this file, this file does not
-// by itself cause the resulting work to be covered by the GNU General Public
-// License. However the source code for this file must still be made available
-// in accordance with section (3) of the GNU General Public License.
-//
-// This exception does not invalidate any other reasons why a work based on
-// this file might be covered by the GNU General Public License.
-//
-// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
-// at http://sources.redhat.com/ecos/ecos-license/
-// -------------------------------------------
-//####ECOSGPLCOPYRIGHTEND####
-//==========================================================================
-//#####DESCRIPTIONBEGIN####
-//
-// Author(s):           nickg
-// Contributors:        nickg, richard.panton@3glab.com
-// Date:                2000-05-25
-// Purpose:             Test fileio system
-// Description:         This test uses the testfs to check out the initialization
-//                      and basic operation of the fileio system
-//
-//####DESCRIPTIONEND####
-//
-//==========================================================================
-
-#include <pkgconf/hal.h>
-#include <pkgconf/kernel.h>
-#include <pkgconf/io_fileio.h>
-
-#include <cyg/kernel/ktypes.h>         // base kernel types
-#include <cyg/infra/cyg_trac.h>        // tracing macros
-#include <cyg/infra/cyg_ass.h>         // assertion macros
-#include <cyg/io/flash.h>
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <string.h>
-#include <dirent.h>
-
-#include <cyg/fileio/fileio.h>
-
-#include <cyg/infra/testcase.h>
-#include <cyg/infra/diag.h>            // HAL polled output
-
-#include <pkgconf/fs_jffs2.h>	// Address of JFFS2
-
-//==========================================================================
-
-/* MTAB_ENTRY( jffs2_mte1,
-                   "/",
-                   "jffs2",
-                   "",
-                   (CYG_ADDRWORD) CYGNUM_FS_JFFS2_BASE_ADDRESS ); */
-
-
-//==========================================================================
-
-#define SHOW_RESULT( _fn, _res ) \
-diag_printf("<FAIL>: " #_fn "() returned %d %s\n", _res, _res<0?strerror(errno):"");
-
-#define CHKFAIL_TYPE( _fn, _res, _type ) { \
-if ( _res != -1 ) \
-    diag_printf("<FAIL>: " #_fn "() returned %d (expected -1)\n", _res); \
-else if ( errno != _type ) \
-    diag_printf("<FAIL>: " #_fn "() failed with errno %d (%s),\n    expected %d (%s)\n", errno, strerror(errno), _type, strerror(_type) ); \
-}
-
-//==========================================================================
-
-#define IOSIZE  100
-
-#define LONGNAME1       "long_file_name_that_should_take_up_more_than_one_directory_entry_1"
-#define LONGNAME2       "long_file_name_that_should_take_up_more_than_one_directory_entry_2"
-
-
-//==========================================================================
-
-#ifndef CYGPKG_LIBC_STRING
-
-char *strcat( char *s1, const char *s2 )
-{
-    char *s = s1;
-    while( *s1 ) s1++;
-    while( (*s1++ = *s2++) != 0);
-    return s;
-}
-
-#endif
-
-//==========================================================================
-
-static void listdir( char *name, int statp )
-{
-    int err;
-    DIR *dirp;
-    
-    diag_printf("<INFO>: reading directory %s\n",name);
-    
-    dirp = opendir( name );
-    if( dirp == NULL ) SHOW_RESULT( opendir, -1 );
-
-    for(;;)
-    {
-        struct dirent *entry = readdir( dirp );
-        
-        if( entry == NULL )
-            break;
-
-        diag_printf("<INFO>: entry %14s",entry->d_name);
-        if( statp )
-        {
-            char fullname[PATH_MAX];
-            struct stat sbuf;
-
-            if( name[0] )
-            {
-                strcpy(fullname, name );
-                if( !(name[0] == '/' && name[1] == 0 ) )
-                    strcat(fullname, "/" );
-            }
-            else fullname[0] = 0;
-            
-            strcat(fullname, entry->d_name );
-            
-            err = stat( fullname, &sbuf );
-            if( err < 0 )
-            {
-                if( errno == ENOSYS )
-                    diag_printf(" <no status available>");
-                else SHOW_RESULT( stat, err );
-            }
-            else
-            {
-                diag_printf(" [mode %08x ino %08x nlink %d size %d]",
-                            sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,sbuf.st_size);
-            }
-        }
-
-        diag_printf("\n");
-    }
-
-    err = closedir( dirp );
-    if( err < 0 ) SHOW_RESULT( stat, err );
-}
-
-//==========================================================================
-
-static void copyfile( char *name2, char *name1 )
-{
-
-    int err;
-    char buf[IOSIZE];
-    int fd1, fd2;
-    ssize_t done, wrote;
-
-    diag_printf("<INFO>: copy file %s -> %s\n",name2,name1);
-
-    err = access( name1, F_OK );
-    if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
-
-    err = access( name2, F_OK );
-    if( err != 0 ) SHOW_RESULT( access, err );
-    
-    fd1 = open( name1, O_WRONLY|O_CREAT );
-    if( fd1 < 0 ) SHOW_RESULT( open, fd1 );
-
-    fd2 = open( name2, O_RDONLY );
-    if( fd2 < 0 ) SHOW_RESULT( open, fd2 );
-    
-    for(;;)
-    {
-        done = read( fd2, buf, IOSIZE );
-        if( done < 0 ) SHOW_RESULT( read, done );
-
-        if( done == 0 ) break;
-
-        wrote = write( fd1, buf, done );
-        if( wrote != done ) SHOW_RESULT( write, wrote );
-
-        if( wrote != done ) break;
-    }
-
-    err = close( fd1 );
-    if( err < 0 ) SHOW_RESULT( close, err );
-
-    err = close( fd2 );
-    if( err < 0 ) SHOW_RESULT( close, err );
-    
-}
-
-//==========================================================================
-
-static void comparefiles( char *name2, char *name1 )
-{
-    int err;
-    char buf1[IOSIZE];
-    char buf2[IOSIZE];
-    int fd1, fd2;
-    ssize_t done1, done2;
-    int i;
-
-    diag_printf("<INFO>: compare files %s == %s\n",name2,name1);
-
-    err = access( name1, F_OK );
-    if( err != 0 ) SHOW_RESULT( access, err );
-
-    err = access( name1, F_OK );
-    if( err != 0 ) SHOW_RESULT( access, err );
-    
-    fd1 = open( name1, O_RDONLY );
-    if( fd1 < 0 ) SHOW_RESULT( open, fd1 );
-
-    fd2 = open( name2, O_RDONLY );
-    if( fd2 < 0 ) SHOW_RESULT( open, fd2 );
-    
-    for(;;)
-    {
-        done1 = read( fd1, buf1, IOSIZE );
-        if( done1 < 0 ) SHOW_RESULT( read, done1 );
-
-        done2 = read( fd2, buf2, IOSIZE );
-        if( done2 < 0 ) SHOW_RESULT( read, done2 );
-
-        if( done1 != done2 )
-            diag_printf("Files different sizes\n");
-        
-        if( done1 == 0 ) break;
-
-        for( i = 0; i < done1; i++ )
-            if( buf1[i] != buf2[i] )
-            {
-                diag_printf("buf1[%d](%02x) != buf1[%d](%02x)\n",i,buf1[i],i,buf2[i]);
-                CYG_TEST_FAIL("Data in files not equal\n");
-            }
-    }
-
-    err = close( fd1 );
-    if( err < 0 ) SHOW_RESULT( close, err );
-
-    err = close( fd2 );
-    if( err < 0 ) SHOW_RESULT( close, err );
-    
-}
-
-//==========================================================================
-// main
-
-int main( int argc, char **argv )
-{
-    int err;
-    //    char address[16];
-
-    CYG_TEST_INIT();
-
-    // --------------------------------------------------------------
-
-    err = mount( CYGDAT_IO_FLASH_BLOCK_DEVICE_NAME_1, "/", "jffs2" );
-    if ( err != ENOERR ) SHOW_RESULT( chdir, err );
-    
-    diag_printf("<INFO>: JFFS2 root follows\n");
-    diag_printf("<INFO>: Note that dev cannot be stat()ed\n");
-    listdir( "/", true );
-
-    diag_printf("<INFO>: cd /etc\n" );
-    err = chdir( "/etc" );
-    if ( err < 0 ) SHOW_RESULT( chdir, err );
-
-    diag_printf("<INFO>: JFFS2 list of '' follows\n");
-    listdir( "", true );
-
-    diag_printf("<INFO>: JFFS2 list of /etc follows\n");
-    listdir( "/etc", true );
-
-    //diag_printf("<INFO>: JFFS2 list of . follows\n");
-    //listdir( ".", true );
-    
-    err = mount( "", "/var", "ramfs" );
-    if( err < 0 ) SHOW_RESULT( mount, err );    
-
-    copyfile( "/etc/passwd", "/var/passwd_copy" );
-
-    comparefiles( "/etc/passwd", "/var/passwd_copy" );
-    
-    diag_printf("<INFO>: JFFS2 list of / follows\n");
-    diag_printf("<INFO>: Note that /var now gives stat() info for RAMFS\n");
-    listdir( "/", true );
-
-    diag_printf("<INFO>: Mount JFFS2 again onto /mnt\n");
-    //sprintf( address, "%p", (void*)CYGNUM_FS_JFFS2_BASE_ADDRESS );
-    err = mount( CYGDAT_IO_FLASH_BLOCK_DEVICE_NAME_1, "/mnt", "jffs2" );
-    if( err < 0 ) SHOW_RESULT( mount, err );    
-
-    comparefiles( "/etc/passwd", "/mnt/etc/passwd" );
-
-
-    err = mkdir( "/foo", 0 );
-    CHKFAIL_TYPE( mkdir, err, EROFS );
-
-    err = rename( "/var", "/tmp" );	// RAMFS is mounted here
-    CHKFAIL_TYPE( rename, err, EXDEV );
-
-    err = rename( "/var/passwd_copy", "/mnt/etc/passwd_copy" );
-    CHKFAIL_TYPE( rename, err, EXDEV );
-
-    err = rename( "/etc", "/tmp" );
-    CHKFAIL_TYPE( rename, err, EROFS );
-
-    diag_printf("<INFO>: cd /etc\n");
-    err = chdir( "/etc" );
-    if( err < 0 ) SHOW_RESULT( chdir, err );
-
-    err = chdir( "/mnt/etc" );
-    if( err < 0 ) SHOW_RESULT( chdir, err );
-
-    //listdir( ".", true );
-
-    diag_printf("<INFO>: unlink /tmp\n");        
-    err = unlink( "/tmp" );
-    CHKFAIL_TYPE( unlink, err, EROFS );
-
-    diag_printf("<INFO>: mount random area\n");
-    //sprintf(address, "%p", (void*)(CYGNUM_FS_JFFS2_BASE_ADDRESS + 0x20000));
-    err = mount( "", "/tmp", "jffs2" );
-    SHOW_RESULT( mount, err );
-
-    err = umount( "/mnt" );
-    if( err < 0 ) SHOW_RESULT( umount, err );    
-
-    err = umount( "/var" );
-    if( err < 0 ) SHOW_RESULT( umount, err );    
-
-    err = umount( "/" );
-    if( err < 0 ) SHOW_RESULT( umount, err );    
-
-
-    CYG_TEST_PASS_FINISH("fileio1");
-}
-
-// -------------------------------------------------------------------------
-// EOF fileio1.c