This is the mail archive of the ecos-patches@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Latest JFFS2


... imported without prejudice from MTD :-)

-- 
Gary Thomas <gary@mlbassoc.com>
MLB Associates
Index: fs/jffs2/current/ChangeLog
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/fs/jffs2/current/ChangeLog,v
retrieving revision 1.21
diff -u -5 -p -r1.21 ChangeLog
--- fs/jffs2/current/ChangeLog	25 Nov 2003 16:41:08 -0000	1.21
+++ fs/jffs2/current/ChangeLog	11 Dec 2003 23:28:09 -0000
@@ -1,5 +1,20 @@
+2003-11-26  David Woodhouse  <dwmw2@redhat.com>
+
+	JFFS2 cleanup and import of newer code. Remove last vestiges of
+	Linuxisms such as 'struct inode' from the core code, leaving eCos
+	with no excuse, and renaming the eCos 'struct inode' to make that
+	point. Fix i_count handling throughout. Clean up remaining Linuxisms
+	such as 'struct qstr' to the point where jffs2port.h can be removed.
+	Add skeleton for background garbage-collect thread. Fix compression
+	so that it's actually called, and even with the right pointers. Turn
+	on -Werror again. Zero tolerance is a good thing. Make the i_mode
+	conversion functions non-inline to avoid warnings. Fix namespace
+	pollution (of all but ^jffs2_* at least). Move physical flash I/O
+	functions into separate file flashio.c for relatively easy
+	substitution. Various other cruftectomy.
+
 2003-11-25  Andrew Lunn  <andrew.lunn@ascom.ch>
 
 	* src/fs-ecos.c: ARM gcc 3.2.3 is also broken. Complain with any
 	ARM gcc 3.2 compiler.
 
Index: fs/jffs2/current/cdl/jffs2.cdl
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/fs/jffs2/current/cdl/jffs2.cdl,v
retrieving revision 1.12
diff -u -5 -p -r1.12 jffs2.cdl
--- fs/jffs2/current/cdl/jffs2.cdl	21 Nov 2003 19:05:24 -0000	1.12
+++ fs/jffs2/current/cdl/jffs2.cdl	11 Dec 2003 23:28:08 -0000
@@ -2,11 +2,11 @@
 #
 #      jffs2.cdl
 #
 #      JFFS2 Filesystem configuration data
 #
-#      $Id: jffs2.cdl,v 1.6 2003/11/20 16:41:57 dwmw2 Exp $
+#      $Id: jffs2.cdl,v 1.13 2003/11/29 00:30:30 dwmw2 Exp $
 #
 # ====================================================================
 #####ECOSGPLCOPYRIGHTBEGIN####
 ## -------------------------------------------
 ## This file is part of eCos, the Embedded Configurable Operating System.
@@ -70,11 +70,34 @@ cdl_package CYGPKG_FS_JFFS2 {
     requires       CYGPKG_CRC
 
     implements     CYGINT_IO_FILEIO_FS      
 
     compile        -library=libextras.a fs-ecos.c
-    compile        build.c scan.c malloc-ecos.c nodelist.c nodemgmt.c readinode.c erase.c dir-ecos.c write.c gc.c read.c compr.c file-ecos.c
+    compile        build.c scan.c malloc-ecos.c nodelist.c nodemgmt.c readinode.c dir-ecos.c read.c compr.c
+    # This could be overridden by an alternative direct I/O method.
+    compile        flashio.c
+
+    cdl_option CYGOPT_FS_JFFS2_GCTHREAD {
+	display         "Support garbage-collection background thread"
+	flavor          bool
+	compile         gcthread.c
+# Leave this off till it's been implemented. And don't implement it till
+# icache locking has been made thread-safe.
+ 	requires        CYGPKG_KERNEL && 0
+        description     "
+            Enable background garbage collection thread, for making 
+	    free space ahead of time."
+    }
+
+    cdl_option CYGOPT_FS_JFFS2_WRITE {
+	display         "Include write support for JFFS2"
+	flavor          bool
+	compile		gc.c write.c erase.c
+	default_value   1
+        description     "
+            Enable writing to JFFS2 file systems; not only reading."
+    }
 
     cdl_option CYGOPT_FS_JFFS2_NAND {
 	display         "Support for NAND flash"
 	flavor          bool
 	define          CONFIG_JFFS2_FS_NAND
@@ -164,32 +187,19 @@ cdl_package CYGPKG_FS_JFFS2 {
 
     cdl_option CYGPKG_FS_JFFS2_CFLAGS_ADD {
 	display "Additional compiler flags"
 	flavor  data
 	no_define
-	# We add -D__ECOS to trigger eCos-specific code in places.
-	# We add -Werror because I find it useful.
+	# We add '-D__ECOS' to trigger eCos-specific code in places.
+	# We add '-nostdinc -iwithprefix include' to avoid picking up
+	#    native <linux/*.h> include files when building on Linux.
 	default_value { "-D__ECOS -nostdinc -iwithprefix include" }
 	description   "
 	    This option modifies the set of compiler flags for
             building the JFFS2 package.
             These flags are used in addition
             to the set of global flags."
-        }
-
-    cdl_option CYGPKG_FS_JFFS2_CFLAGS_REMOVE {
-	display "Suppressed compiler flags"
-	flavor  data
-	no_define
-	# We remove -Wpointer-arith so that some of the hacky Linux-compat code 
-	# (in file.c) compiled. We can probably remove it when that's replaced
-	# properly.
-	default_value { "-Wpointer-arith" }
-	description   "
-	    This option modifies the set of compiler flags for
-            building the JFFS2 package. These flags are removed from
-            the set of global flags if present."
         }
 
     # ----------------------------------------------------------------
     # Tests
 
Index: fs/jffs2/current/src/compr.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/fs/jffs2/current/src/compr.c,v
retrieving revision 1.4
diff -u -5 -p -r1.4 compr.c
--- fs/jffs2/current/src/compr.c	20 Nov 2003 16:52:36 -0000	1.4
+++ fs/jffs2/current/src/compr.c	11 Dec 2003 23:28:08 -0000
@@ -5,20 +5,21 @@
  *
  * Created by Arjan van de Ven <arjanv@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr.c,v 1.29 2003/11/20 16:40:35 dwmw2 Exp $
+ * $Id: compr.c,v 1.33 2003/11/28 17:22:54 dwmw2 Exp $
  *
  */
 
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/jffs2.h>
+#include "nodelist.h"
 
 int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
 void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
 int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
 void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
@@ -52,46 +53,47 @@ unsigned char jffs2_compress(unsigned ch
 	int ret;
 
 	*cpage_out = kmalloc(*cdatalen, GFP_KERNEL);
 	if (!*cpage_out) {
 		printk(KERN_WARNING "No memory for compressor allocation. Compression failed\n");
-		return JFFS2_COMPR_NONE;
+		goto out;
 	}
 
 #ifdef JFFS2_USE_ZLIB
-	ret = jffs2_zlib_compress(data_in, cpage_out, datalen, cdatalen);
+	ret = jffs2_zlib_compress(data_in, *cpage_out, datalen, cdatalen);
 	if (!ret) {
 		return JFFS2_COMPR_ZLIB;
 	}
 #endif
 #ifdef JFFS2_USE_DYNRUBIN
-	ret = jffs2_dynrubin_compress(data_in, cpage_out, datalen, cdatalen);
+	ret = jffs2_dynrubin_compress(data_in, *cpage_out, datalen, cdatalen);
 	if (!ret) {
 		return JFFS2_COMPR_DYNRUBIN;
 	}
 #endif
 #ifdef JFFS2_USE_RUBINMIPS
-	ret = jffs2_rubinmips_compress(data_in, cpage_out, datalen, cdatalen);
+	ret = jffs2_rubinmips_compress(data_in, *cpage_out, datalen, cdatalen);
 	if (!ret) {
 		return JFFS2_COMPR_RUBINMIPS;
 	}
 #endif
 #ifdef JFFS2_USE_RTIME
 	/* rtime does manage to recompress already-compressed data */
-	ret = jffs2_rtime_compress(data_in, cpage_out, datalen, cdatalen);
+	ret = jffs2_rtime_compress(data_in, *cpage_out, datalen, cdatalen);
 	if (!ret) {
 		return JFFS2_COMPR_RTIME;
 	}
 #endif
 	kfree(*cpage_out);
 #endif /* Compression */
+ out:
 	*cpage_out = data_in;
 	*datalen = *cdatalen;
 	return JFFS2_COMPR_NONE; /* We failed to compress */
 }
 
-void jffs2_free_comprbuf(unsigned char *orig, unsigned char *comprbuf)
+void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
 {
 	if (orig != comprbuf)
 		kfree(comprbuf);
 }
 
Index: fs/jffs2/current/src/compr_zlib.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/fs/jffs2/current/src/compr_zlib.c,v
retrieving revision 1.5
diff -u -5 -p -r1.5 compr_zlib.c
--- fs/jffs2/current/src/compr_zlib.c	20 Nov 2003 16:52:36 -0000	1.5
+++ fs/jffs2/current/src/compr_zlib.c	11 Dec 2003 23:28:08 -0000
@@ -5,22 +5,20 @@
  *
  * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr_zlib.c,v 1.24 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: compr_zlib.c,v 1.25 2003/12/03 09:25:43 dwmw2 Exp $
  *
  */
 
 #if !defined(__KERNEL__) && !defined(__ECOS)
 #error "The userspace support got too messy and was removed. Update your mkfs.jffs2"
 #endif
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/zlib.h>
 #include <linux/zutil.h>
 #include <asm/semaphore.h>
 #include "nodelist.h"
@@ -37,10 +35,13 @@
 static DECLARE_MUTEX(deflate_sem);
 static DECLARE_MUTEX(inflate_sem);
 static z_stream inf_strm, def_strm;
 
 #ifdef __KERNEL__ /* Linux-only */
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+
 int __init jffs2_zlib_init(void)
 {
 	def_strm.workspace = vmalloc(zlib_deflate_workspacesize());
 	if (!def_strm.workspace) {
 		printk(KERN_WARNING "Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize());
Index: fs/jffs2/current/src/dir-ecos.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/fs/jffs2/current/src/dir-ecos.c,v
retrieving revision 1.4
diff -u -5 -p -r1.4 dir-ecos.c
--- fs/jffs2/current/src/dir-ecos.c	20 Nov 2003 16:52:36 -0000	1.4
+++ fs/jffs2/current/src/dir-ecos.c	11 Dec 2003 23:28:08 -0000
@@ -1,60 +1,57 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: dir-ecos.c,v 1.4 2003/11/20 16:41:58 dwmw2 Exp $
+ * $Id: dir-ecos.c,v 1.10 2003/11/26 15:55:35 dwmw2 Exp $
  *
  */
 
 #include <linux/kernel.h>
 #include <linux/crc32.h>
 #include "nodelist.h"
 
 /***********************************************************************/
 
-
-/* We keep the dirent list sorted in increasing order of name hash,
-   and we use the same hash function as the dentries. Makes this 
-   nice and simple
-*/
-struct inode *jffs2_lookup(struct inode *dir_i, struct qstr *d_name)
+/* Takes length argument because it can be either NUL-terminated or '/'-terminated */
+struct _inode *jffs2_lookup(struct _inode *dir_i, const unsigned char *d_name, int namelen)
 {
 	struct jffs2_inode_info *dir_f;
 	struct jffs2_sb_info *c;
 	struct jffs2_full_dirent *fd = NULL, *fd_list;
 	uint32_t ino = 0;
-	struct inode *inode = NULL;
+	uint32_t hash = full_name_hash(d_name, namelen);
+	struct _inode *inode = NULL;
 
 	D1(printk("jffs2_lookup()\n"));
 
 	dir_f = JFFS2_INODE_INFO(dir_i);
 	c = JFFS2_SB_INFO(dir_i->i_sb);
 
 	down(&dir_f->sem);
 
 	/* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */
-	for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= d_name->hash; fd_list = fd_list->next) {
-		if (fd_list->nhash == d_name->hash && 
+	for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= hash; fd_list = fd_list->next) {
+		if (fd_list->nhash == hash && 
 		    (!fd || fd_list->version > fd->version) &&
-		    strlen(fd_list->name) == d_name->len &&
-		    !strncmp(fd_list->name, d_name->name, d_name->len)) {
+		    strlen(fd_list->name) == namelen &&
+		    !strncmp(fd_list->name, d_name, namelen)) {
 			fd = fd_list;
 		}
 	}
 	if (fd)
 		ino = fd->ino;
 	up(&dir_f->sem);
 	if (ino) {
-		inode = iget(dir_i->i_sb, ino);
+		inode = jffs2_iget(dir_i->i_sb, ino);
 		if (!inode) {
-			printk("iget() failed for ino #%u\n", ino);
+			printk("jffs2_iget() failed for ino #%u\n", ino);
 			return (ERR_PTR(-EIO));
 		}
 	}
 
 	return inode;
@@ -62,17 +59,17 @@ struct inode *jffs2_lookup(struct inode 
 
 /***********************************************************************/
 
 
 
-int jffs2_create(struct inode *dir_i, struct qstr *d_name, int mode,
-                 struct inode **new_i)
+int jffs2_create(struct _inode *dir_i, const unsigned char *d_name, int mode,
+                 struct _inode **new_i)
 {
 	struct jffs2_raw_inode *ri;
 	struct jffs2_inode_info *f, *dir_f;
 	struct jffs2_sb_info *c;
-	struct inode *inode;
+	struct _inode *inode;
 	int ret;
 
 	ri = jffs2_alloc_raw_inode();
 	if (!ri)
 		return -ENOMEM;
@@ -91,16 +88,15 @@ int jffs2_create(struct inode *dir_i, st
 
 	f = JFFS2_INODE_INFO(inode);
 	dir_f = JFFS2_INODE_INFO(dir_i);
 
 	ret = jffs2_do_create(c, dir_f, f, ri, 
-			      d_name->name, d_name->len);
+			      d_name, strlen(d_name));
 
 	if (ret) {
-		jffs2_clear_inode(inode);
-		make_bad_inode(inode);
-		iput(inode);
+		inode->i_nlink = 0;
+		jffs2_iput(inode);
 		jffs2_free_raw_inode(ri);
 		return ret;
 	}
 
 	jffs2_free_raw_inode(ri);
@@ -112,52 +108,52 @@ int jffs2_create(struct inode *dir_i, st
 }
 
 /***********************************************************************/
 
 
-int jffs2_unlink(struct inode *dir_i, struct inode *d_inode, struct qstr *d_name)
+int jffs2_unlink(struct _inode *dir_i, struct _inode *d_inode, const unsigned char *d_name)
 {
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb);
 	struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
 	struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(d_inode);
 	int ret;
 
-	ret = jffs2_do_unlink(c, dir_f, d_name->name, 
-			       d_name->len, dead_f);
+	ret = jffs2_do_unlink(c, dir_f, d_name, 
+			       strlen(d_name), dead_f);
 	if (dead_f->inocache)
 		d_inode->i_nlink = dead_f->inocache->nlink;
 	return ret;
 }
 /***********************************************************************/
 
 
-int jffs2_link (struct inode *old_d_inode, struct inode *dir_i, struct qstr *d_name)
+int jffs2_link (struct _inode *old_d_inode, struct _inode *dir_i, const unsigned char *d_name)
 {
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(old_d_inode->i_sb);
 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_d_inode);
 	struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
 	int ret;
 
 	/* XXX: This is ugly */
 	uint8_t type = (old_d_inode->i_mode & S_IFMT) >> 12;
 	if (!type) type = DT_REG;
 
-	ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, d_name->name, d_name->len);
+	ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, d_name, strlen(d_name));
 
 	if (!ret) {
 		down(&f->sem);
 		old_d_inode->i_nlink = ++f->inocache->nlink;
 		up(&f->sem);
 	}
 	return ret;
 }
 
-int jffs2_mkdir (struct inode *dir_i, struct qstr *d_name, int mode, struct inode **new_i)
+int jffs2_mkdir (struct _inode *dir_i, const unsigned char *d_name, int mode)
 {
 	struct jffs2_inode_info *f, *dir_f;
 	struct jffs2_sb_info *c;
-	struct inode *inode;
+	struct _inode *inode;
 	struct jffs2_raw_inode *ri;
 	struct jffs2_raw_dirent *rd;
 	struct jffs2_full_dnode *fn;
 	struct jffs2_full_dirent *fd;
 	int namelen;
@@ -173,11 +169,11 @@ int jffs2_mkdir (struct inode *dir_i, st
 	c = JFFS2_SB_INFO(dir_i->i_sb);
 
 	/* Try to reserve enough space for both node and dirent. 
 	 * Just the node will do for now, though 
 	 */
-	namelen = d_name->len;
+	namelen = strlen(d_name);
 	ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL);
 
 	if (ret) {
 		jffs2_free_raw_inode(ri);
 		return ret;
@@ -202,11 +198,12 @@ int jffs2_mkdir (struct inode *dir_i, st
 
 	if (IS_ERR(fn)) {
 		/* Eeek. Wave bye bye */
 		up(&f->sem);
 		jffs2_complete_reservation(c);
-		jffs2_clear_inode(inode);
+		inode->i_nlink = 0;
+		jffs2_iput(inode);
 		return PTR_ERR(fn);
 	}
 	/* No data here. Only a metadata node, which will be 
 	   obsoleted by the first data write
 	*/
@@ -215,19 +212,21 @@ int jffs2_mkdir (struct inode *dir_i, st
 
 	jffs2_complete_reservation(c);
 	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
 	if (ret) {
 		/* Eep. */
-		jffs2_clear_inode(inode);
+		inode->i_nlink = 0;
+		jffs2_iput(inode);
 		return ret;
 	}
 	
 	rd = jffs2_alloc_raw_dirent();
 	if (!rd) {
 		/* Argh. Now we treat it like a normal delete */
 		jffs2_complete_reservation(c);
-		jffs2_clear_inode(inode);
+		inode->i_nlink = 0;
+		jffs2_iput(inode);
 		return -ENOMEM;
 	}
 
 	dir_f = JFFS2_INODE_INFO(dir_i);
 	down(&dir_f->sem);
@@ -242,35 +241,36 @@ int jffs2_mkdir (struct inode *dir_i, st
 	rd->ino = cpu_to_je32(inode->i_ino);
 	rd->mctime = cpu_to_je32(cyg_timestamp());
 	rd->nsize = namelen;
 	rd->type = DT_DIR;
 	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
-	rd->name_crc = cpu_to_je32(crc32(0, d_name->name, namelen));
+	rd->name_crc = cpu_to_je32(crc32(0, d_name, namelen));
 
-	fd = jffs2_write_dirent(c, dir_f, rd, d_name->name, namelen, phys_ofs, ALLOC_NORMAL);
+	fd = jffs2_write_dirent(c, dir_f, rd, d_name, namelen, phys_ofs, ALLOC_NORMAL);
 	
 	jffs2_complete_reservation(c);
 	jffs2_free_raw_dirent(rd);
 	
 	if (IS_ERR(fd)) {
 		/* dirent failed to write. Delete the inode normally 
 		   as if it were the final unlink() */
 		up(&dir_f->sem);
-		jffs2_clear_inode(inode);
+		inode->i_nlink = 0;
+		jffs2_iput(inode);
 		return PTR_ERR(fd);
 	}
 
 	/* Link the fd into the inode's list, obsoleting an old
 	   one if necessary. */
 	jffs2_add_fd_to_list(c, fd, &dir_f->dents);
 	up(&dir_f->sem);
 
-	*new_i = inode;
+	jffs2_iput(inode);
 	return 0;
 }
 
-int jffs2_rmdir (struct inode *dir_i, struct inode *d_inode, struct qstr *d_name)
+int jffs2_rmdir (struct _inode *dir_i, struct _inode *d_inode, const unsigned char *d_name)
 {
 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode);
 	struct jffs2_full_dirent *fd;
 
 	for (fd = f->dents ; fd; fd = fd->next) {
@@ -278,12 +278,12 @@ int jffs2_rmdir (struct inode *dir_i, st
 			return EPERM; //-ENOTEMPTY;
 	}
 	return jffs2_unlink(dir_i, d_inode, d_name);
 }
 
-int jffs2_rename (struct inode *old_dir_i, struct inode *d_inode, struct qstr *old_d_name,
-                        struct inode *new_dir_i, struct qstr *new_d_name)
+int jffs2_rename (struct _inode *old_dir_i, struct _inode *d_inode, const unsigned char *old_d_name,
+		  struct _inode *new_dir_i, const unsigned char *new_d_name)
 {
 	int ret;
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
 	struct jffs2_inode_info *victim_f = NULL;
 	uint8_t type;
@@ -329,11 +329,11 @@ int jffs2_rename (struct inode *old_dir_
 	type = (d_inode->i_mode & S_IFMT) >> 12;
 	if (!type) type = DT_REG;
 
 	ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), 
 			    d_inode->i_ino, type,
-			    new_d_name->name, new_d_name->len);
+			    new_d_name, strlen(new_d_name));
 
 	if (ret)
 		return ret;
 
 	if (victim_f) {
@@ -347,11 +347,11 @@ int jffs2_rename (struct inode *old_dir_
 		}
 	}
 
 	/* Unlink the original */
 	ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), 
-		      old_d_name->name, old_d_name->len, NULL);
+		      old_d_name, strlen(old_d_name), NULL);
 
 	if (ret) {
 		/* Oh shit. We really ought to make a single node which can do both atomically */
 		struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode);
 		down(&f->sem);
Index: fs/jffs2/current/src/erase.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/fs/jffs2/current/src/erase.c,v
retrieving revision 1.5
diff -u -5 -p -r1.5 erase.c
--- fs/jffs2/current/src/erase.c	20 Nov 2003 16:52:36 -0000	1.5
+++ fs/jffs2/current/src/erase.c	11 Dec 2003 23:28:08 -0000
@@ -5,11 +5,11 @@
  *
  * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: erase.c,v 1.57 2003/11/04 14:46:13 dwmw2 Exp $
+ * $Id: erase.c,v 1.58 2003/11/26 13:02:46 dwmw2 Exp $
  *
  */
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -279,15 +279,10 @@ static void jffs2_free_all_node_refs(str
 		/* else it was a non-inode node or already removed, so don't bother */
 
 		jffs2_free_raw_node_ref(ref);
 	}
 	jeb->last_node = NULL;
-}
-
-void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
-{
-	OFNI_BS_2SFFJ(c)->s_dirt = 1;
 }
 
 static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
 	struct jffs2_raw_node_ref *marker_ref = NULL;
Index: fs/jffs2/current/src/fs-ecos.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/fs/jffs2/current/src/fs-ecos.c,v
retrieving revision 1.15
diff -u -5 -p -r1.15 fs-ecos.c
--- fs/jffs2/current/src/fs-ecos.c	25 Nov 2003 16:41:08 -0000	1.15
+++ fs/jffs2/current/src/fs-ecos.c	11 Dec 2003 23:28:08 -0000
@@ -1,34 +1,33 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
  * Created by Dominic Ostrowski <dominic.ostrowski@3glab.com>
  * Contributors: David Woodhouse, Nick Garnett, Richard Panton.
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: fs-ecos.c,v 1.11 2003/11/20 16:41:58 dwmw2 Exp $
+ * $Id: fs-ecos.c,v 1.33 2003/12/02 10:43:03 dwmw2 Exp $
  *
  */
 
 #include <linux/types.h>
 #include <linux/stat.h>
 #include <linux/kernel.h>
-#include "jffs2port.h"
 #include <linux/jffs2.h>
 #include <linux/jffs2_fs_sb.h>
 #include <linux/jffs2_fs_i.h>
 #include <linux/pagemap.h>
+#include <linux/crc32.h>
 #include "nodelist.h"
 
 #include <errno.h>
 #include <string.h>
 #include <cyg/io/io.h>
 #include <cyg/io/config_keys.h>
-#include <cyg/io/flash.h>
 
 #if (__GNUC__ == 3) && (__GNUC_MINOR__ == 2) && defined (__ARM_ARCH_4__)
 #error This compiler is known to be broken. Please see:
 #error http://ecos.sourceware.org/ml/ecos-patches/2003-08/msg00006.html
 #endif
@@ -38,396 +37,399 @@
 
 // Filesystem operations
 static int jffs2_mount(cyg_fstab_entry * fste, cyg_mtab_entry * mte);
 static int jffs2_umount(cyg_mtab_entry * mte);
 static int jffs2_open(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
-                      int mode, cyg_file * fte);
+		      int mode, cyg_file * fte);
+#ifdef CYGOPT_FS_JFFS2_WRITE
 static int jffs2_ops_unlink(cyg_mtab_entry * mte, cyg_dir dir,
-                            const char *name);
+			    const char *name);
 static int jffs2_ops_mkdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name);
 static int jffs2_ops_rmdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name);
 static int jffs2_ops_rename(cyg_mtab_entry * mte, cyg_dir dir1,
-                            const char *name1, cyg_dir dir2, const char *name2);
+			    const char *name1, cyg_dir dir2, const char *name2);
 static int jffs2_ops_link(cyg_mtab_entry * mte, cyg_dir dir1, const char *name1,
-                          cyg_dir dir2, const char *name2, int type);
+			  cyg_dir dir2, const char *name2, int type);
+#endif
 static int jffs2_opendir(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
-                         cyg_file * fte);
+			 cyg_file * fte);
 static int jffs2_chdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
-                       cyg_dir * dir_out);
+		       cyg_dir * dir_out);
 static int jffs2_stat(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
-                      struct stat *buf);
+		      struct stat *buf);
 static int jffs2_getinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
-                         int key, void *buf, int len);
+			 int key, void *buf, int len);
 static int jffs2_setinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
-                         int key, void *buf, int len);
+			 int key, void *buf, int len);
 
 // File operations
 static int jffs2_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
+#ifdef CYGOPT_FS_JFFS2_WRITE
 static int jffs2_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
+#endif
 static int jffs2_fo_lseek(struct CYG_FILE_TAG *fp, off_t * pos, int whence);
 static int jffs2_fo_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
-                          CYG_ADDRWORD data);
+			  CYG_ADDRWORD data);
 static int jffs2_fo_fsync(struct CYG_FILE_TAG *fp, int mode);
 static int jffs2_fo_close(struct CYG_FILE_TAG *fp);
 static int jffs2_fo_fstat(struct CYG_FILE_TAG *fp, struct stat *buf);
 static int jffs2_fo_getinfo(struct CYG_FILE_TAG *fp, int key, void *buf,
-                            int len);
+			    int len);
 static int jffs2_fo_setinfo(struct CYG_FILE_TAG *fp, int key, void *buf,
-                            int len);
+			    int len);
 
 // Directory operations
 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);
+static void jffs2_clear_inode (struct _inode *inode);
+
 //==========================================================================
 // Filesystem table entries
 
 // -------------------------------------------------------------------------
 // Fstab entry.
 // This defines the entry in the filesystem table.
 // For simplicity we use _FILESYSTEM synchronization for all accesses since
 // we should never block in any filesystem operations.
 
+#ifdef CYGOPT_FS_JFFS2_WRITE
+FSTAB_ENTRY(jffs2_fste, "jffs2", 0,
+	    CYG_SYNCMODE_FILE_FILESYSTEM | CYG_SYNCMODE_IO_FILE,
+	    jffs2_mount,
+	    jffs2_umount,
+	    jffs2_open,
+	    jffs2_ops_unlink,
+	    jffs2_ops_mkdir,
+	    jffs2_ops_rmdir,
+	    jffs2_ops_rename,
+	    jffs2_ops_link,
+	    jffs2_opendir,
+	    jffs2_chdir, jffs2_stat, jffs2_getinfo, jffs2_setinfo);
+#else
 FSTAB_ENTRY(jffs2_fste, "jffs2", 0,
-            CYG_SYNCMODE_FILE_FILESYSTEM | CYG_SYNCMODE_IO_FILESYSTEM,
-            jffs2_mount,
-            jffs2_umount,
-            jffs2_open,
-            jffs2_ops_unlink,
-            jffs2_ops_mkdir,
-            jffs2_ops_rmdir,
-            jffs2_ops_rename,
-            jffs2_ops_link,
-            jffs2_opendir,
-            jffs2_chdir, jffs2_stat, jffs2_getinfo, jffs2_setinfo);
+	    CYG_SYNCMODE_FILE_FILESYSTEM | CYG_SYNCMODE_IO_FILE,
+	    jffs2_mount,
+	    jffs2_umount,
+	    jffs2_open,
+	    (cyg_fsop_unlink *)cyg_fileio_erofs,
+	    (cyg_fsop_mkdir *)cyg_fileio_erofs,
+	    (cyg_fsop_rmdir *)cyg_fileio_erofs,
+	    (cyg_fsop_rename *)cyg_fileio_erofs,
+	    (cyg_fsop_link *)cyg_fileio_erofs,
+	    jffs2_opendir,
+	    jffs2_chdir, jffs2_stat, jffs2_getinfo, jffs2_setinfo);
+#endif
 
 // -------------------------------------------------------------------------
 // File operations.
 // This set of file operations are used for normal open files.
 
 static cyg_fileops jffs2_fileops = {
-        jffs2_fo_read,
-        jffs2_fo_write,
-        jffs2_fo_lseek,
-        jffs2_fo_ioctl,
-        cyg_fileio_seltrue,
-        jffs2_fo_fsync,
-        jffs2_fo_close,
-        jffs2_fo_fstat,
-        jffs2_fo_getinfo,
-        jffs2_fo_setinfo
+	jffs2_fo_read,
+#ifdef CYGOPT_FS_JFFS2_WRITE
+	jffs2_fo_write,
+#else
+	(cyg_fileop_write *) cyg_fileio_erofs,
+#endif
+	jffs2_fo_lseek,
+	jffs2_fo_ioctl,
+	cyg_fileio_seltrue,
+	jffs2_fo_fsync,
+	jffs2_fo_close,
+	jffs2_fo_fstat,
+	jffs2_fo_getinfo,
+	jffs2_fo_setinfo
 };
 
 // -------------------------------------------------------------------------
 // Directory file operations.
 // This set of operations are used for open directories. Most entries
 // point to error-returning stub functions. Only the read, lseek and
 // close entries are functional.
 
 static cyg_fileops jffs2_dirops = {
-        jffs2_fo_dirread,
-        (cyg_fileop_write *) cyg_fileio_enosys,
-        jffs2_fo_dirlseek,
-        (cyg_fileop_ioctl *) cyg_fileio_enosys,
-        cyg_fileio_seltrue,
-        (cyg_fileop_fsync *) cyg_fileio_enosys,
-        jffs2_fo_close,
-        (cyg_fileop_fstat *) cyg_fileio_enosys,
-        (cyg_fileop_getinfo *) cyg_fileio_enosys,
-        (cyg_fileop_setinfo *) cyg_fileio_enosys
+	jffs2_fo_dirread,
+	(cyg_fileop_write *) cyg_fileio_enosys,
+	jffs2_fo_dirlseek,
+	(cyg_fileop_ioctl *) cyg_fileio_enosys,
+	cyg_fileio_seltrue,
+	(cyg_fileop_fsync *) cyg_fileio_enosys,
+	jffs2_fo_close,
+	(cyg_fileop_fstat *) cyg_fileio_enosys,
+	(cyg_fileop_getinfo *) cyg_fileio_enosys,
+	(cyg_fileop_setinfo *) cyg_fileio_enosys
 };
 
 //==========================================================================
 // STATIC VARIABLES !!!
 
-static char read_write_buffer[PAGE_CACHE_SIZE]; //avoids malloc when user may be under memory pressure
-static char gc_buffer[PAGE_CACHE_SIZE]; //avoids malloc when user may be under memory pressure
+static unsigned char gc_buffer[PAGE_CACHE_SIZE];	//avoids malloc when user may be under memory pressure
 static unsigned char n_fs_mounted = 0;  // a counter to track the number of jffs2 instances mounted
 
 //==========================================================================
 // Directory operations
 
 struct jffs2_dirsearch {
-        struct inode *dir;      // directory to search
-        const char *path;       // path to follow
-        struct inode *node;     // Node found
-        const char *name;       // last name fragment used
-        int namelen;            // name fragment length
-        cyg_bool last;          // last name in path?
+	struct _inode *dir;	// directory to search
+	const char *path;	// path to follow
+	struct _inode *node;	// Node found
+	const char *name;	// last name fragment used
+	int namelen;		// name fragment length
+	cyg_bool last;		// last name in path?
 };
 
 typedef struct jffs2_dirsearch jffs2_dirsearch;
 
 //==========================================================================
 // 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?
-static void icache_evict(struct inode *root_i, struct inode *i)
+static void icache_evict(struct _inode *root_i, struct _inode *i)
 {
-        struct inode *cached_inode;
-        struct inode *next_inode;
+	struct _inode *this = root_i, *next;
 
-        D2(printf("icache_evict\n"));
-        // If this is an absolute search path from the root,
-        // remove all cached inodes with i_count of zero (these are only 
-        // held where needed for dotdot filepaths)
-        if (i == root_i) {
-                for (cached_inode = root_i; cached_inode != NULL;
-                     cached_inode = next_inode) {
-                        next_inode = cached_inode->i_cache_next;
-                        if (cached_inode->i_count == 0) {
-                                cached_inode->i_cache_prev->i_cache_next = cached_inode->i_cache_next;  // Previous entry points ahead of us
-                                if (cached_inode->i_cache_next != NULL)
-                                        cached_inode->i_cache_next->i_cache_prev = cached_inode->i_cache_prev;  // Next entry points behind us
-                                jffs2_clear_inode(cached_inode);
-                                D2(printf
-                                   ("free icache_evict inode %x $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n",
-                                    cached_inode));
-                                free(cached_inode);
-                        }
-                }
-        }
+ restart:
+	D2(printf("icache_evict\n"));
+	// If this is an absolute search path from the root,
+	// remove all cached inodes with i_count of zero (these are only 
+	// held where needed for dotdot filepaths)
+	while (this) {
+		next = this->i_cache_next;
+		if (this != i && this->i_count == 0) {
+			struct _inode *parent = this->i_parent;
+			if (this->i_cache_next)
+				this->i_cache_next->i_cache_prev = this->i_cache_prev;
+			if (this->i_cache_prev)
+				this->i_cache_prev->i_cache_next = this->i_cache_next;
+			jffs2_clear_inode(this);
+			memset(this, 0x5a, sizeof(*this));
+			free(this);
+			if (parent && parent != this) {
+				parent->i_count--;
+				this = root_i;
+				goto restart;
+			}
+		}
+		this = next;
+	}
 }
 
 //==========================================================================
 // Directory search
 
 // -------------------------------------------------------------------------
 // init_dirsearch()
 // Initialize a dirsearch object to start a search
 
 static void init_dirsearch(jffs2_dirsearch * ds,
-                           struct inode *dir, const char *name)
+			   struct _inode *dir, const char *name)
 {
-        D2(printf("init_dirsearch name = %s\n", name));
-        D2(printf("init_dirsearch dir = %x\n", dir));
-        ds->dir = dir;
-        ds->path = name;
-        ds->node = dir;
-        ds->name = name;
-        ds->namelen = 0;
-        ds->last = false;
+	D2(printf("init_dirsearch name = %s\n", name));
+	D2(printf("init_dirsearch dir = %x\n", dir));
+
+	dir->i_count++;
+	ds->dir = dir;
+	ds->path = name;
+	ds->node = dir;
+	ds->name = name;
+	ds->namelen = 0;
+	ds->last = false;
 }
 
 // -------------------------------------------------------------------------
 // find_entry()
 // Search a single directory for the next name in a path and update the
 // dirsearch object appropriately.
 
 static int find_entry(jffs2_dirsearch * ds)
 {
-        unsigned long hash;
-        struct qstr this;
-        unsigned int c;
-        const char *hashname;
-
-        struct inode *dir = ds->dir;
-        const char *name = ds->path;
-        const char *n = name;
-        char namelen = 0;
-        struct inode *d;
-
-        D2(printf("find_entry\n"));
-
-        // check that we really have a directory
-        if (!S_ISDIR(dir->i_mode))
-                return ENOTDIR;
-
-        // Isolate the next element of the path name. 
-        while (*n != '\0' && *n != '/')
-                n++, namelen++;
-
-        // If we terminated on a NUL, set last flag.
-        if (*n == '\0')
-                ds->last = true;
-
-        // update name in dirsearch object
-        ds->name = name;
-        ds->namelen = namelen;
-
-        if (name[0] == '.')
-                switch (namelen) {
-                default:
-                        break;
-                case 2:
-                        // Dot followed by not Dot, treat as any other name 
-                        if (name[1] != '.')
-                                break;
-                        // Dot Dot 
-                        // Move back up the search path
-                        D2(printf("find_entry found ..\n"));
-                        ds->node = ds->dir->i_parent;
-                        if (ds->dir->i_count == 0) {
-                                iput(ds->dir);  // This inode may be evicted
-                                ds->dir = NULL;
-                        }
-                        return ENOERR;
-                case 1:
-                        // Dot is consumed
-                        D2(printf("find_entry found .\n"));
-                        ds->node = ds->dir;
-                        return ENOERR;
-                }
-        // Here we have the name and its length set up.
-        // Search the directory for a matching entry
-
-        hashname = name;
-        this.name = hashname;
-        c = *(const unsigned char *) hashname;
-
-        hash = init_name_hash();
-        do {
-                hashname++;
-                hash = partial_name_hash(c, hash);
-                c = *(const unsigned char *) hashname;
-        } while (c && (c != '/'));
-        this.len = hashname - (const char *) this.name;
-        this.hash = end_name_hash(hash);
-
-        D2(printf("find_entry for name = %s\n", ds->path));
-        d = jffs2_lookup(dir, &this);
-        D2(printf("find_entry got dir = %x\n", d));
-
-        if (d == NULL)
-                return ENOENT;
-
-        // The back path for dotdot to follow
-        d->i_parent = dir;
-        // pass back the node we have found
-        ds->node = d;
-
-        return ENOERR;
+	struct _inode *dir = ds->dir;
+	const char *name = ds->path;
+	const char *n = name;
+	char namelen = 0;
+	struct _inode *d;
+
+	D2(printf("find_entry\n"));
+
+	// check that we really have a directory
+	if (!S_ISDIR(dir->i_mode))
+		return ENOTDIR;
+
+	// Isolate the next element of the path name. 
+	while (*n != '\0' && *n != '/')
+		n++, namelen++;
+
+	// If we terminated on a NUL, set last flag.
+	if (*n == '\0')
+		ds->last = true;
+
+	// update name in dirsearch object
+	ds->name = name;
+	ds->namelen = namelen;
+
+	if (name[0] == '.')
+		switch (namelen) {
+		default:
+			break;
+		case 2:
+			// Dot followed by not Dot, treat as any other name 
+			if (name[1] != '.')
+				break;
+			// Dot Dot 
+			// Move back up the search path
+			D2(printf("find_entry found ..\n"));
+			ds->dir = ds->node;
+			ds->node = ds->dir->i_parent;
+			ds->node->i_count++;
+			return ENOERR;
+		case 1:
+			// Dot is consumed
+			D2(printf("find_entry found .\n"));
+			ds->node = ds->dir;
+			ds->dir->i_count++;
+			return ENOERR;
+		}
+
+	// Here we have the name and its length set up.
+	// Search the directory for a matching entry
+
+	D2(printf("find_entry for name = %s\n", ds->path));
+	d = jffs2_lookup(dir, name, namelen);
+	D2(printf("find_entry got dir = %x\n", d));
+
+	if (d == NULL)
+		return ENOENT;
+
+	// If it's a new directory inode, increase refcount on its parent
+	if (S_ISDIR(d->i_mode) && !d->i_parent) {
+		d->i_parent = dir;
+		dir->i_count++;
+	}
+
+	// pass back the node we have found
+	ds->node = d;
+	return ENOERR;
 
 }
 
 // -------------------------------------------------------------------------
 // jffs2_find()
 // 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;
+	int err;
 
-        D2(printf("jffs2_find for path =%s\n", d->path));
-        // Short circuit empty paths
-        if (*(d->path) == '\0')
-                return ENOERR;
-
-        // iterate down directory tree until we find the object
-        // we want.
-        for (;;) {
-                err = find_entry(d);
-
-                if (err != ENOERR)
-                        return err;
-
-                if (d->last)
-                        return ENOERR;
-
-                // every inode traversed in the find is temporary and should be free'd
-                //iput(d->dir);
-
-                // Update dirsearch object to search next directory.
-                d->dir = d->node;
-                d->path += d->namelen;
-                if (*(d->path) == '/')
-                        d->path++;      // skip dirname separators
-        }
+	D2(printf("jffs2_find for path =%s\n", d->path));
+
+	// Short circuit empty paths
+	if (*(d->path) == '\0') {
+		d->node->i_count++;
+		return ENOERR;
+	}
+
+	// iterate down directory tree until we find the object
+	// we want.
+	for (;;) {
+		err = find_entry(d);
+
+		if (err != ENOERR)
+			return err;
+
+		if (d->last)
+			return ENOERR;
+
+		/* We're done with it, although it we found a subdir that
+		   will have caused the refcount to have been increased */
+		jffs2_iput(d->dir);
+
+		// Update dirsearch object to search next directory.
+		d->dir = d->node;
+		d->path += d->namelen;
+		if (*(d->path) == '/')
+			d->path++;	// skip dirname separators
+	}
 }
 
 //==========================================================================
 // Pathconf support
 // This function provides support for pathconf() and fpathconf().
 
-static int jffs2_pathconf(struct inode *node, struct cyg_pathconf_info *info)
+static int jffs2_pathconf(struct _inode *node, struct cyg_pathconf_info *info)
 {
-        int err = ENOERR;
-        D2(printf("jffs2_pathconf\n"));
+	int err = ENOERR;
+	D2(printf("jffs2_pathconf\n"));
 
-        switch (info->name) {
-        case _PC_LINK_MAX:
-                info->value = LINK_MAX;
-                break;
-
-        case _PC_MAX_CANON:
-                info->value = -1;       // not supported
-                err = EINVAL;
-                break;
-
-        case _PC_MAX_INPUT:
-                info->value = -1;       // not supported
-                err = EINVAL;
-                break;
-
-        case _PC_NAME_MAX:
-                info->value = NAME_MAX;
-                break;
-
-        case _PC_PATH_MAX:
-                info->value = PATH_MAX;
-                break;
-
-        case _PC_PIPE_BUF:
-                info->value = -1;       // not supported
-                err = EINVAL;
-                break;
-
-        case _PC_ASYNC_IO:
-                info->value = -1;       // not supported
-                err = EINVAL;
-                break;
-
-        case _PC_CHOWN_RESTRICTED:
-                info->value = -1;       // not supported
-                err = EINVAL;
-                break;
-
-        case _PC_NO_TRUNC:
-                info->value = 0;
-                break;
-
-        case _PC_PRIO_IO:
-                info->value = 0;
-                break;
-
-        case _PC_SYNC_IO:
-                info->value = 0;
-                break;
-
-        case _PC_VDISABLE:
-                info->value = -1;       // not supported
-                err = EINVAL;
-                break;
-
-        default:
-                err = EINVAL;
-                break;
-        }
+	switch (info->name) {
+	case _PC_LINK_MAX:
+		info->value = LINK_MAX;
+		break;
+
+	case _PC_MAX_CANON:
+		info->value = -1;	// not supported
+		err = EINVAL;
+		break;
+
+	case _PC_MAX_INPUT:
+		info->value = -1;	// not supported
+		err = EINVAL;
+		break;
+
+	case _PC_NAME_MAX:
+		info->value = NAME_MAX;
+		break;
+
+	case _PC_PATH_MAX:
+		info->value = PATH_MAX;
+		break;
+
+	case _PC_PIPE_BUF:
+		info->value = -1;	// not supported
+		err = EINVAL;
+		break;
+
+	case _PC_ASYNC_IO:
+		info->value = -1;	// not supported
+		err = EINVAL;
+		break;
+
+	case _PC_CHOWN_RESTRICTED:
+		info->value = -1;	// not supported
+		err = EINVAL;
+		break;
+
+	case _PC_NO_TRUNC:
+		info->value = 0;
+		break;
+
+	case _PC_PRIO_IO:
+		info->value = 0;
+		break;
+
+	case _PC_SYNC_IO:
+		info->value = 0;
+		break;
+
+	case _PC_VDISABLE:
+		info->value = -1;	// not supported
+		err = EINVAL;
+		break;
+
+	default:
+		err = EINVAL;
+		break;
+	}
 
-        return err;
+	return err;
 }
 
 //==========================================================================
 // Filesystem operations
 
@@ -435,787 +437,756 @@ static int jffs2_pathconf(struct inode *
 // jffs2_mount()
 // Process a mount request. This mainly creates a root for the
 // filesystem.
 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;
-        cyg_io_flash_getconfig_blocksize_t bs;
-
-        D1(printk(KERN_DEBUG "jffs2: read_super\n"));
-
-        c = JFFS2_SB_INFO(sb);
-
-        len = sizeof (ds);
-        err = cyg_io_get_config(sb->s_dev,
-                                CYG_IO_GET_CONFIG_FLASH_DEVSIZE, &ds, &len);
-        if (err != ENOERR) {
-                D1(printf
-                   ("jffs2: cyg_io_get_config failed to get dev size: %d\n",
-                    err));
-                return err;
-        }
-        len = sizeof (bs);
-        bs.offset = 0;
-        err = cyg_io_get_config(sb->s_dev,
-                                CYG_IO_GET_CONFIG_FLASH_BLOCKSIZE, &bs, &len);
-        if (err != ENOERR) {
-                D1(printf
-                   ("jffs2: cyg_io_get_config failed to get block size: %d\n",
-                    err));
-                return err;
-        }
+	struct jffs2_sb_info *c;
+	Cyg_ErrNo err;
+	cyg_uint32 len;
+	cyg_io_flash_getconfig_devsize_t ds;
+	cyg_io_flash_getconfig_blocksize_t bs;
+
+	D1(printk(KERN_DEBUG "jffs2: read_super\n"));
+
+	c = JFFS2_SB_INFO(sb);
+
+	len = sizeof (ds);
+	err = cyg_io_get_config(sb->s_dev,
+				CYG_IO_GET_CONFIG_FLASH_DEVSIZE, &ds, &len);
+	if (err != ENOERR) {
+		D1(printf
+		   ("jffs2: cyg_io_get_config failed to get dev size: %d\n",
+		    err));
+		return err;
+	}
+	len = sizeof (bs);
+	bs.offset = 0;
+	err = cyg_io_get_config(sb->s_dev,
+				CYG_IO_GET_CONFIG_FLASH_BLOCKSIZE, &bs, &len);
+	if (err != ENOERR) {
+		D1(printf
+		   ("jffs2: cyg_io_get_config failed to get block size: %d\n",
+		    err));
+		return err;
+	}
+
+	c->sector_size = bs.block_size;
+	c->flash_size = ds.dev_size;
+	c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
+
+	err = jffs2_do_mount_fs(c);
+	if (err)
+		return -err;
+
+	D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n"));
+	sb->s_root = jffs2_iget(sb, 1);
+	if (IS_ERR(sb->s_root)) {
+		D1(printk(KERN_WARNING "get root inode failed\n"));
+		err = PTR_ERR(sb->s_root);
+		sb->s_root = NULL;
+		goto out_nodes;
+	}
 
-        c->sector_size = bs.block_size;
-        c->flash_size = ds.dev_size;
-        c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
-
-        err = jffs2_do_mount_fs(c);
-        if (err)
-                return -err;
-
-        D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n"));
-        root_i = iget(sb, 1);
-        if (is_bad_inode(root_i)) {
-                D1(printk(KERN_WARNING "get root inode failed\n"));
-                err = EIO;
-                goto out_nodes;
-        }
+	return 0;
 
-        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;
-                goto out_root_i;
-        }
-        sb->s_blocksize = PAGE_CACHE_SIZE;
-        sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
-        sb->s_magic = JFFS2_SUPER_MAGIC;
-
-        return 0;
-
-      out_root_i:
-        iput(root_i);
       out_nodes:
-        jffs2_free_ino_caches(c);
-        jffs2_free_raw_node_refs(c);
-        free(c->blocks);
+	jffs2_free_ino_caches(c);
+	jffs2_free_raw_node_refs(c);
+	free(c->blocks);
 
-        return err;
+	return err;
 }
 
 static int jffs2_mount(cyg_fstab_entry * fste, cyg_mtab_entry * mte)
 {
-        extern cyg_mtab_entry cyg_mtab[], cyg_mtab_end;
-        struct super_block *jffs2_sb = NULL;
-        struct jffs2_sb_info *c;
-        cyg_mtab_entry *m;
-        cyg_io_handle_t t;
-        Cyg_ErrNo err;
-
-        D2(printf("jffs2_mount\n"));
-
-        err = cyg_io_lookup(mte->devname, &t);
-        if (err != ENOERR)
-                return -err;
-
-        // 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++) {
-                // stop if there are more than the configured maximum
-                if (m - &cyg_mtab[0] >= CYGNUM_FILEIO_MTAB_MAX) {
-                        m = &cyg_mtab_end;
-                        break;
-                }
-                if (m->valid && strcmp(m->fsname, "jffs2") == 0 &&
-                    strcmp(m->devname, mte->devname) == 0) {
-                        jffs2_sb = (struct super_block *) m->data;
-                }
-        }
-
-        if (jffs2_sb == NULL) {
-                jffs2_sb = malloc(sizeof (struct super_block));
-
-                if (jffs2_sb == NULL)
-                        return ENOMEM;
-
-                c = JFFS2_SB_INFO(jffs2_sb);
-                memset(jffs2_sb, 0, sizeof (struct super_block));
-                jffs2_sb->s_dev = t;
-
-                c->inocache_list = malloc(sizeof(struct jffs2_inode_cache *) * INOCACHE_HASHSIZE);
-                if (!c->inocache_list) {
-                        free(jffs2_sb);
-                        return ENOMEM;
-                }
-                memset(c->inocache_list, 0, sizeof(struct jffs2_inode_cache *) * INOCACHE_HASHSIZE);
+	extern cyg_mtab_entry cyg_mtab[], cyg_mtab_end;
+	struct super_block *jffs2_sb = NULL;
+	struct jffs2_sb_info *c;
+	cyg_mtab_entry *m;
+	cyg_io_handle_t t;
+	Cyg_ErrNo err;
+
+	D2(printf("jffs2_mount\n"));
+
+	err = cyg_io_lookup(mte->devname, &t);
+	if (err != ENOERR)
+		return -err;
+
+	// 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++) {
+		// stop if there are more than the configured maximum
+		if (m - &cyg_mtab[0] >= CYGNUM_FILEIO_MTAB_MAX) {
+			m = &cyg_mtab_end;
+			break;
+		}
+		if (m->valid && strcmp(m->fsname, "jffs2") == 0 &&
+		    strcmp(m->devname, mte->devname) == 0) {
+			jffs2_sb = (struct super_block *) m->data;
+		}
+	}
+
+	if (jffs2_sb == NULL) {
+		jffs2_sb = malloc(sizeof (struct super_block));
+
+		if (jffs2_sb == NULL)
+			return ENOMEM;
+
+		c = JFFS2_SB_INFO(jffs2_sb);
+		memset(jffs2_sb, 0, sizeof (struct super_block));
+		jffs2_sb->s_dev = t;
+
+		c->inocache_list = malloc(sizeof(struct jffs2_inode_cache *) * INOCACHE_HASHSIZE);
+		if (!c->inocache_list) {
+			free(jffs2_sb);
+			return ENOMEM;
+		}
+		memset(c->inocache_list, 0, sizeof(struct jffs2_inode_cache *) * INOCACHE_HASHSIZE);
                 if (n_fs_mounted++ == 0)
                         jffs2_create_slab_caches(); // No error check, cannot fail
 
-                err = jffs2_read_super(jffs2_sb);
+		err = jffs2_read_super(jffs2_sb);
 
-                if (err) {
+		if (err) {
                         if (--n_fs_mounted == 0)
                                 jffs2_destroy_slab_caches();
                         
-                        free(jffs2_sb);
-                        free(c->inocache_list);
-                        return err;
-                }
-
-                jffs2_sb->s_root->i_parent = jffs2_sb->s_root;  // points to itself, no dotdot paths above mountpoint
-                jffs2_sb->s_root->i_cache_prev = NULL;  // root inode, so always null
-                jffs2_sb->s_root->i_cache_next = NULL;
-                jffs2_sb->s_root->i_count = 1;  // Ensures the root inode is always in ram until umount
-
-                D2(printf("jffs2_mount erasing pending blocks\n"));
-                jffs2_erase_pending_blocks(c,0);
-        }
-        mte->data = (CYG_ADDRWORD) jffs2_sb;
+			free(jffs2_sb);
+			free(c->inocache_list);
+			return err;
+		}
+
+		jffs2_sb->s_root->i_parent = jffs2_sb->s_root;	// points to itself, no dotdot paths above mountpoint
+		jffs2_sb->s_root->i_cache_prev = NULL;	// root inode, so always null
+		jffs2_sb->s_root->i_cache_next = NULL;
+		jffs2_sb->s_root->i_count = 1;	// Ensures the root inode is always in ram until umount
+
+		D2(printf("jffs2_mount erasing pending blocks\n"));
+#ifdef CYGOPT_FS_JFFS2_WRITE
+		if (!jffs2_is_readonly(c))
+		    jffs2_erase_pending_blocks(c,0);
+#endif
+#ifdef CYGOPT_FS_JFFS2_GCTHREAD
+		jffs2_start_garbage_collect_thread(c);
+#endif
+	}
+	mte->data = (CYG_ADDRWORD) jffs2_sb;
 
-        jffs2_sb->s_mount_count++;
-        mte->root = (cyg_dir) jffs2_sb->s_root;
-        D2(printf("jffs2_mounted superblock at %x\n", mte->root));
+	jffs2_sb->s_mount_count++;
+	mte->root = (cyg_dir) jffs2_sb->s_root;
+	D2(printf("jffs2_mounted superblock at %x\n", mte->root));
 
-        return ENOERR;
+	return ENOERR;
 }
 
+extern cyg_dir cyg_cdir_dir;
+extern cyg_mtab_entry *cyg_cdir_mtab_entry;
+
 // -------------------------------------------------------------------------
 // jffs2_umount()
 // Unmount the filesystem. 
 
 static int jffs2_umount(cyg_mtab_entry * mte)
 {
-        struct inode *root = (struct inode *) mte->root;
-        struct super_block *jffs2_sb = root->i_sb;
-        struct jffs2_sb_info *c = JFFS2_SB_INFO(jffs2_sb);
-
-        D2(printf("jffs2_umount\n"));
-
-        // 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
-                        return EBUSY;
-                
-                dec_refcnt(root);       // Time to free the root inode
-
-                //Clear root inode
-                //root_i = NULL;
-
-                // Clean up the super block and root inode
-                jffs2_free_ino_caches(c);
-                jffs2_free_raw_node_refs(c);
-                free(c->blocks);
-                free(c->inocache_list);
-                free(jffs2_sb);
-                // Clear superblock & root pointer
-                mte->root = CYG_DIR_NULL;
+	struct _inode *root = (struct _inode *) mte->root;
+	struct super_block *jffs2_sb = root->i_sb;
+	struct jffs2_sb_info *c = JFFS2_SB_INFO(jffs2_sb);
+
+	D2(printf("jffs2_umount\n"));
+
+	// Only really umount if this is the only mount
+	if (jffs2_sb->s_mount_count == 1) {
+		icache_evict(root, NULL);
+		if (root->i_cache_next != NULL)	{
+			struct _inode *inode = root;
+			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;
+                }
+		if (root->i_count == 2 &&
+		    cyg_cdir_mtab_entry == mte &&
+		    cyg_cdir_dir == (cyg_dir)root &&
+		    !strcmp(mte->name, "/")) {
+			/* If we were mounted on root, there's no
+			   way for the cwd to change out and free 
+			   the file system for unmounting. So we hack
+			   it -- if cwd is '/' we unset it. Perhaps
+			   we should allow chdir(NULL) to unset
+			   cyg_cdir_dir? */
+			cyg_cdir_dir = CYG_DIR_NULL;
+			jffs2_iput(root);
+		}
+		/* Argh. The fileio code sets this; never clears it */
+		if (cyg_cdir_mtab_entry == mte)
+			cyg_cdir_mtab_entry = NULL;
+
+		if (root->i_count != 1) {
+			printf("Ino #1 has use count %d\n",
+			       root->i_count);
+			return EBUSY;
+		}
+#ifdef CYGOPT_FS_JFFS2_GCTHREAD
+		jffs2_stop_garbage_collect_thread(c);
+#endif
+		jffs2_iput(root);	// Time to free the root inode
+		free(root);
+		//Clear root inode
+		//root_i = NULL;
+
+		// Clean up the super block and root inode
+		jffs2_free_ino_caches(c);
+		jffs2_free_raw_node_refs(c);
+		free(c->blocks);
+		free(c->inocache_list);
+		free(jffs2_sb);
+		// Clear superblock & root pointer
+		mte->root = CYG_DIR_NULL;
                 mte->data = 0;
-                mte->fs->data = 0;      // fstab entry, visible to all mounts. No current mount
-                // That's all folks.
-                D2(printf("jffs2_umount No current mounts\n"));
-        } else {
-                jffs2_sb->s_mount_count--;
+		mte->fs->data = 0;	// fstab entry, visible to all mounts. No current mount
+		// That's all folks.
+		D2(printf("jffs2_umount No current mounts\n"));
+	} else {
+		jffs2_sb->s_mount_count--;
         }
         if (--n_fs_mounted == 0)
                 jffs2_destroy_slab_caches();        
-        return ENOERR;
+	return ENOERR;
 }
 
 // -------------------------------------------------------------------------
 // jffs2_open()
 // Open a file for reading or writing.
 
 static int jffs2_open(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
-                      int mode, cyg_file * file)
+		      int mode, cyg_file * file)
 {
 
-        jffs2_dirsearch ds;
-        struct inode *node = NULL;
-        int err;
-
-        D2(printf("jffs2_open\n"));
-
-        icache_evict((struct inode *) mte->root, (struct inode *) dir);
-
-        init_dirsearch(&ds, (struct inode *) dir, name);
-
-        err = jffs2_find(&ds);
+	jffs2_dirsearch ds;
+	struct _inode *node = NULL;
+	int err;
 
-        if (err == ENOENT) {
-                if (ds.last && (mode & O_CREAT)) {
-                        unsigned long hash;
-                        struct qstr this;
-                        unsigned int c;
-                        const char *hashname;
+	D2(printf("jffs2_open\n"));
 
-                        // No node there, if the O_CREAT bit is set then we must
-                        // create a new one. The dir and name fields of the dirsearch
-                        // object will have been updated so we know where to put it.
+	/* If no chdir has been called and we were the first file system
+	   mounted, we get called with dir == NULL. Deal with it */
+	if (!dir)
+		dir = mte->root;
 
-                        hashname = ds.name;
-                        this.name = hashname;
-                        c = *(const unsigned char *) hashname;
-
-                        hash = init_name_hash();
-                        do {
-                                hashname++;
-                                hash = partial_name_hash(c, hash);
-                                c = *(const unsigned char *) hashname;
-                        } while (c && (c != '/'));
-                        this.len = hashname - (const char *) this.name;
-                        this.hash = end_name_hash(hash);
-
-                        err = jffs2_create(ds.dir, &this, S_IRUGO|S_IXUGO|S_IWUSR|S_IFREG, &node);
-
-                        if (err != 0) {
-                                //Possible orphaned inode on the flash - but will be gc'd
-                                return err;
-                        }
-
-                        err = ENOERR;
-                }
-        } else if (err == ENOERR) {
-                // 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))
-                        err = EEXIST;
-                else
-                        node = ds.node;
-        }
+#ifndef CYGOPT_FS_JFFS2_WRITE
+	if (mode & (O_CREAT|O_TRUNC|O_WRONLY))
+		return EROFS;
+#endif
+	init_dirsearch(&ds, (struct _inode *) dir, name);
 
-        if (err == ENOERR && (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.
-
-                node->i_size = 0;
-                jffs2_truncate_fraglist(c, &f->fragtree, 0);
-                // Update file times
-                node->i_ctime = node->i_mtime = cyg_timestamp();
-        }
+	err = jffs2_find(&ds);
 
-        if (err != ENOERR)
-                return err;
+	if (err == ENOENT) {
+#ifdef CYGOPT_FS_JFFS2_WRITE
+		if (ds.last && (mode & O_CREAT)) {
 
-        // Check that we actually have a file here
-        if (S_ISDIR(node->i_mode))
-                return EISDIR;
+			// No node there, if the O_CREAT bit is set then we must
+			// create a new one. The dir and name fields of the dirsearch
+			// object will have been updated so we know where to put it.
 
-        node->i_count++;        // Count successful open
+			err = jffs2_create(ds.dir, ds.name, S_IRUGO|S_IXUGO|S_IWUSR|S_IFREG, &node);
 
-        // Initialize the file object
+			if (err != 0) {
+				//Possible orphaned inode on the flash - but will be gc'd
+				return err;
+			}
 
-        file->f_flag |= mode & CYG_FILE_MODE_MASK;
-        file->f_type = CYG_FILE_TYPE_FILE;
-        file->f_ops = &jffs2_fileops;
-        file->f_offset = (mode & O_APPEND) ? node->i_size : 0;
-        file->f_data = (CYG_ADDRWORD) node;
-        file->f_xops = 0;
+			err = ENOERR;
+		}
+#endif
+	} else if (err == ENOERR) {
+		// 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)) {
+			jffs2_iput(ds.node);
+			err = EEXIST;
+		} else
+			node = ds.node;
+	}
+
+	// Finished with the directory now 
+	jffs2_iput(ds.dir);
+
+	if (err != ENOERR)
+		return err;
+
+	// Check that we actually have a file here
+	if (S_ISDIR(node->i_mode)) {
+		jffs2_iput(node);
+		return EISDIR;
+	}
+
+#ifndef CYGOPT_FS_JFFS2_WRITE
+	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.
+
+		node->i_size = 0;
+		jffs2_truncate_fraglist(c, &f->fragtree, 0);
+		// Update file times
+		node->i_ctime = node->i_mtime = cyg_timestamp();
+	}
+#endif
+	// Initialise the file object
+	file->f_flag |= mode & CYG_FILE_MODE_MASK;
+	file->f_type = CYG_FILE_TYPE_FILE;
+	file->f_ops = &jffs2_fileops;
+	file->f_offset = (mode & O_APPEND) ? node->i_size : 0;
+	file->f_data = (CYG_ADDRWORD) node;
+	file->f_xops = 0;
 
-        return ENOERR;
+	return ENOERR;
 }
 
+#ifdef CYGOPT_FS_JFFS2_WRITE
 // -------------------------------------------------------------------------
 // jffs2_ops_unlink()
 // Remove a file link from its directory.
 
 static int jffs2_ops_unlink(cyg_mtab_entry * mte, cyg_dir dir, const char *name)
 {
-        unsigned long hash;
-        struct qstr this;
-        unsigned int c;
-        const char *hashname;
-        jffs2_dirsearch ds;
-        int err;
-
-        D2(printf("jffs2_ops_unlink\n"));
+	jffs2_dirsearch ds;
+	int err;
 
-        icache_evict((struct inode *) mte->root, (struct inode *) dir);
+	D2(printf("jffs2_ops_unlink\n"));
 
-        init_dirsearch(&ds, (struct inode *) dir, name);
+	init_dirsearch(&ds, (struct _inode *) dir, name);
 
-        err = jffs2_find(&ds);
+	err = jffs2_find(&ds);
 
-        if (err != ENOERR)
-                return err;
+	if (err != ENOERR) {
+		jffs2_iput(ds.dir);
+		return err;
+	}
 
-        // Cannot unlink directories, use rmdir() instead
-        if (S_ISDIR(ds.node->i_mode))
-                return EPERM;
+	// Cannot unlink directories, use rmdir() instead
+	if (S_ISDIR(ds.node->i_mode)) {
+		jffs2_iput(ds.dir);
+		jffs2_iput(ds.node);
+		return EPERM;
+	}
 
-        // Delete it from its directory
+	// Delete it from its directory
 
-        hashname = ds.name;
-        this.name = hashname;
-        c = *(const unsigned char *) hashname;
+	err = jffs2_unlink(ds.dir, ds.node, ds.name);
+	jffs2_iput(ds.dir);
+	jffs2_iput(ds.node);
 
-        hash = init_name_hash();
-        do {
-                hashname++;
-                hash = partial_name_hash(c, hash);
-                c = *(const unsigned char *) hashname;
-        } while (c && (c != '/'));
-        this.len = hashname - (const char *) this.name;
-        this.hash = end_name_hash(hash);
-
-        err = jffs2_unlink(ds.dir, ds.node, &this);
-
-        return err;
+	return -err;
 }
 
 // -------------------------------------------------------------------------
 // jffs2_ops_mkdir()
 // Create a new directory.
 
 static int jffs2_ops_mkdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name)
 {
-        jffs2_dirsearch ds;
-        struct inode *node = NULL;
-        int err;
-
-        D2(printf("jffs2_ops_mkdir\n"));
-
-        icache_evict((struct inode *) mte->root, (struct inode *) dir);
-
-        init_dirsearch(&ds, (struct inode *) dir, name);
-
-        err = jffs2_find(&ds);
-
-        if (err == ENOENT) {
-                if (ds.last) {
-                        unsigned long hash;
-                        struct qstr this;
-                        unsigned int c;
-                        const char *hashname;
-                        // The entry does not exist, and it is the last element in
-                        // the pathname, so we can create it here.
-
-                        hashname = ds.name;
-                        this.name = hashname;
-                        c = *(const unsigned char *) hashname;
-
-                        hash = init_name_hash();
-                        do {
-                                hashname++;
-                                hash = partial_name_hash(c, hash);
-                                c = *(const unsigned char *) hashname;
-                        } while (c && (c != '/'));
-                        this.len = hashname - (const char *) this.name;
-                        this.hash = end_name_hash(hash);
+	jffs2_dirsearch ds;
+	int err;
 
-                        err = jffs2_mkdir(ds.dir, &this, 0, &node);
+	D2(printf("jffs2_ops_mkdir\n"));
 
-                        if (err != 0)
-                                return ENOSPC;
+	init_dirsearch(&ds, (struct _inode *) dir, name);
 
-                }
-                // If this was not the last element, then and intermediate
-                // directory does not exist.
-        } else {
-                // If there we no error, something already exists with that
-                // name, so we cannot create another one.
-
-                if (err == ENOERR)
-                        err = EEXIST;
-        }
+	err = jffs2_find(&ds);
 
-        return err;
+	if (err == ENOENT) {
+		if (ds.last) {
+			// The entry does not exist, and it is the last element in
+			// the pathname, so we can create it here.
+
+			err = -jffs2_mkdir(ds.dir, ds.name, S_IRUGO|S_IXUGO|S_IWUSR);
+		}
+		// 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.
+		jffs2_iput(ds.node);
+		if (err == ENOERR)
+			err = EEXIST;
+	}
+	jffs2_iput(ds.dir);
+	return err;
 }
 
 // -------------------------------------------------------------------------
 // jffs2_ops_rmdir()
 // Remove a directory.
 
 static int jffs2_ops_rmdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name)
 {
-        unsigned long hash;
-        struct qstr this;
-        unsigned int c;
-        const char *hashname;
-        jffs2_dirsearch ds;
-        int err;
+	jffs2_dirsearch ds;
+	int err;
 
-        D2(printf("jffs2_ops_rmdir\n"));
+	D2(printf("jffs2_ops_rmdir\n"));
 
-        icache_evict((struct inode *) mte->root, (struct inode *) dir);
+	init_dirsearch(&ds, (struct _inode *) dir, name);
 
-        init_dirsearch(&ds, (struct inode *) dir, name);
+	err = jffs2_find(&ds);
 
-        err = jffs2_find(&ds);
+	if (err != ENOERR) {
+		jffs2_iput(ds.dir);
+		return err;
+	}
 
-        if (err != ENOERR)
-                return err;
+	// Check that this is actually a directory.
+	if (!S_ISDIR(ds.node->i_mode)) {
+		jffs2_iput(ds.dir);
+		jffs2_iput(ds.node);
+		return EPERM;
+	}
 
-        // Check that this is actually a directory.
-        if (!S_ISDIR(ds.node->i_mode))
-                return EPERM;
+	err = jffs2_rmdir(ds.dir, ds.node, ds.name);
 
-        // Delete the entry. 
-        hashname = ds.name;
-        this.name = hashname;
-        c = *(const unsigned char *) hashname;
-
-        hash = init_name_hash();
-        do {
-                hashname++;
-                hash = partial_name_hash(c, hash);
-                c = *(const unsigned char *) hashname;
-        } while (c && (c != '/'));
-        this.len = hashname - (const char *) this.name;
-        this.hash = end_name_hash(hash);
-
-        err = jffs2_rmdir(ds.dir, ds.node, &this);
-
-        return err;
-
-        return ENOERR;
+	jffs2_iput(ds.dir);
+	jffs2_iput(ds.node);
+	return -err;
 }
 
 // -------------------------------------------------------------------------
 // jffs2_ops_rename()
 // Rename a file/dir.
 
 static int jffs2_ops_rename(cyg_mtab_entry * mte, cyg_dir dir1,
-                            const char *name1, cyg_dir dir2, const char *name2)
+			    const char *name1, cyg_dir dir2, const char *name2)
 {
-        unsigned long hash;
-        struct qstr this1, this2;
-        unsigned int c;
-        const char *hashname;
-        jffs2_dirsearch ds1, ds2;
-        int err;
-
-        D2(printf("jffs2_ops_rename\n"));
-
-        init_dirsearch(&ds1, (struct inode *) dir1, name1);
-
-        err = jffs2_find(&ds1);
-
-        if (err != ENOERR)
-                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 (err != ENOERR)
-                return err;
-
-        // Null rename, just return
-        if (ds1.node == ds2.node)
-                return ENOERR;
-
-        hashname = ds1.name;
-        this1.name = hashname;
-        c = *(const unsigned char *) hashname;
-
-        hash = init_name_hash();
-        do {
-                hashname++;
-                hash = partial_name_hash(c, hash);
-                c = *(const unsigned char *) hashname;
-        } while (c && (c != '/'));
-        this1.len = hashname - (const char *) this1.name;
-        this1.hash = end_name_hash(hash);
-
-        hashname = ds2.name;
-        this2.name = hashname;
-        c = *(const unsigned char *) hashname;
-
-        hash = init_name_hash();
-        do {
-                hashname++;
-                hash = partial_name_hash(c, hash);
-                c = *(const unsigned char *) hashname;
-        } while (c && (c != '/'));
-        this2.len = hashname - (const char *) this2.name;
-        this2.hash = end_name_hash(hash);
-
-        // First deal with any entry that is at the destination
-        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))
-                        return ENOTDIR;
-
-                // Now delete the destination directory entry
+	jffs2_dirsearch ds1, ds2;
+	int err;
 
-                err = jffs2_unlink(ds2.dir, ds2.node, &this2);
+	D2(printf("jffs2_ops_rename\n"));
 
-                if (err != 0)
-                        return err;
+	init_dirsearch(&ds1, (struct _inode *) dir1, name1);
 
-        }
-        // 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);
-
-        // Update directory times
-        if (err == 0)
-                ds1.dir->i_ctime =
-                    ds1.dir->i_mtime =
-                    ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp();
-
-        return err;
+	err = jffs2_find(&ds1);
+
+	if (err != ENOERR) {
+		jffs2_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 (err != ENOERR) {
+		jffs2_iput(ds1.dir);
+		jffs2_iput(ds1.node);
+		jffs2_iput(ds2.dir);
+		return err;
+	}
+
+	// Null rename, just return
+	if (ds1.node == ds2.node) {
+		err = ENOERR;
+		goto out;
+	}
+
+	// First deal with any entry that is at the destination
+	if (ds2.node) {
+		// Check that we are renaming like-for-like
+
+		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)) {
+			err = ENOTDIR;
+			goto out;
+		}
+
+		// Now delete the destination directory entry
+		/* Er, what happened to atomicity of rename()? */
+		err = -jffs2_unlink(ds2.dir, ds2.node, ds2.name);
+
+		if (err != 0)
+			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, ds1.name, ds2.dir, ds2.name);
+
+	// Update directory times
+	if (!err)
+		ds1.dir->i_ctime =
+		    ds1.dir->i_mtime =
+		    ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp();
+ out:
+	jffs2_iput(ds1.dir);
+	jffs2_iput(ds1.node);
+	if (S_ISDIR(ds1.node->i_mode)) {
+		/* Renamed a directory to elsewhere... so fix up its
+		   i_parent pointer and the i_counts of its old and
+		   new parents. */
+		jffs2_iput(ds1.node->i_parent);
+		ds1.node->i_parent = ds2.dir;
+		/* We effectively increase its use count by not... */
+	} else {
+		jffs2_iput(ds2.dir); /* ... doing this */
+	}
+	if (ds2.node)
+		jffs2_iput(ds2.node);
+ 
+	return -err;
 }
 
 // -------------------------------------------------------------------------
 // jffs2_ops_link()
 // Make a new directory entry for a file.
 
 static int jffs2_ops_link(cyg_mtab_entry * mte, cyg_dir dir1, const char *name1,
-                          cyg_dir dir2, const char *name2, int type)
+			  cyg_dir dir2, const char *name2, int type)
 {
-        unsigned long hash;
-        struct qstr this;
-        unsigned int c;
-        const char *hashname;
-        jffs2_dirsearch ds1, ds2;
-        int err;
-
-        D2(printf("jffs2_ops_link\n"));
+	jffs2_dirsearch ds1, ds2;
+	int err;
 
-        // Only do hard links for now in this filesystem
-        if (type != CYG_FSLINK_HARD)
-                return EINVAL;
+	D2(printf("jffs2_ops_link\n"));
 
-        init_dirsearch(&ds1, (struct inode *) dir1, name1);
+	// Only do hard links for now in this filesystem
+	if (type != CYG_FSLINK_HARD)
+		return EINVAL;
 
-        err = jffs2_find(&ds1);
+	init_dirsearch(&ds1, (struct _inode *) dir1, name1);
 
-        if (err != ENOERR)
-                return err;
+	err = jffs2_find(&ds1);
 
-        init_dirsearch(&ds2, (struct inode *) dir2, name2);
+	if (err != ENOERR) {
+		jffs2_iput(ds1.dir);
+		return err;
+	}
 
-        err = jffs2_find(&ds2);
+	init_dirsearch(&ds2, (struct _inode *) dir2, name2);
 
-        // Don't allow links to existing objects
-        if (err == ENOERR)
-                return EEXIST;
+	err = jffs2_find(&ds2);
 
-        // Allow through links to non-existing terminal objects
-        if (ds2.last && err == ENOENT)
-                ds2.node = NULL, err = ENOERR;
+	// Don't allow links to existing objects
+	if (err == ENOERR) {
+		jffs2_iput(ds1.dir);
+		jffs2_iput(ds1.node);
+		jffs2_iput(ds2.dir);
+		jffs2_iput(ds2.node);
+		return EEXIST;
+	}
 
-        if (err != ENOERR)
-                return err;
+	// Allow through links to non-existing terminal objects
+	if (ds2.last && err == ENOENT) {
+		jffs2_iput(ds2.node);
+		ds2.node = NULL;
+		err = ENOERR;
+	}
 
-        // Now we know that there is no existing node at the destination,
-        // make a new direntry at the destination.
+	if (err != ENOERR) {
+		jffs2_iput(ds1.dir);
+		jffs2_iput(ds1.node);
+		jffs2_iput(ds2.dir);
+		return err;
+	}
 
-        hashname = ds2.name;
-        this.name = hashname;
-        c = *(const unsigned char *) hashname;
+	// Now we know that there is no existing node at the destination,
+	// make a new direntry at the destination.
 
-        hash = init_name_hash();
-        do {
-                hashname++;
-                hash = partial_name_hash(c, hash);
-                c = *(const unsigned char *) hashname;
-        } while (c && (c != '/'));
-        this.len = hashname - (const char *) this.name;
-        this.hash = end_name_hash(hash);
+	err = jffs2_link(ds1.node, ds2.dir, ds2.name);
 
-        err = jffs2_link(ds1.node, ds2.dir, &this);
+	if (err == 0)
+		ds1.node->i_ctime =
+		    ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp();
 
-        if (err == 0)
-                ds1.node->i_ctime =
-                    ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp();
+	jffs2_iput(ds1.dir);
+	jffs2_iput(ds1.node);
+	jffs2_iput(ds2.dir);
 
-        return err;
+	return -err;
 }
-
+#endif /* CYGOPT_FS_JFFS2_WRITE */
 // -------------------------------------------------------------------------
 // jffs2_opendir()
 // Open a directory for reading.
 
 static int jffs2_opendir(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
-                         cyg_file * file)
+			 cyg_file * file)
 {
-        jffs2_dirsearch ds;
-        int err;
-
-        D2(printf("jffs2_opendir\n"));
+	jffs2_dirsearch ds;
+	int err;
 
-        icache_evict((struct inode *) mte->root, (struct inode *) dir);
+	D2(printf("jffs2_opendir\n"));
 
-        init_dirsearch(&ds, (struct inode *) dir, name);
+	init_dirsearch(&ds, (struct _inode *) dir, name);
 
-        err = jffs2_find(&ds);
+	err = jffs2_find(&ds);
 
-        if (err != ENOERR)
-                return err;
+	jffs2_iput(ds.dir);
 
-        // check it is really a directory.
-        if (!S_ISDIR(ds.node->i_mode))
-                return ENOTDIR;
+	if (err != ENOERR)
+		return err;
 
-        ds.node->i_count++;     // Count successful open
+	// check it is really a directory.
+	if (!S_ISDIR(ds.node->i_mode)) {
+		jffs2_iput(ds.node);
+		return ENOTDIR;
+	}
 
-        // Initialize the file object, setting the f_ops field to a
-        // special set of file ops.
+	// Initialize the file object, setting the f_ops field to a
+	// special set of file ops.
 
-        file->f_type = CYG_FILE_TYPE_FILE;
-        file->f_ops = &jffs2_dirops;
-        file->f_offset = 0;
-        file->f_data = (CYG_ADDRWORD) ds.node;
-        file->f_xops = 0;
+	file->f_type = CYG_FILE_TYPE_FILE;
+	file->f_ops = &jffs2_dirops;
+	file->f_offset = 0;
+	file->f_data = (CYG_ADDRWORD) ds.node;
+	file->f_xops = 0;
 
-        return ENOERR;
+	return ENOERR;
 
 }
 
 // -------------------------------------------------------------------------
 // jffs2_chdir()
 // Change directory support.
 
 static int jffs2_chdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
-                       cyg_dir * dir_out)
+		       cyg_dir * dir_out)
 {
-        D2(printf("jffs2_chdir\n"));
-
-        if (dir_out != NULL) {
-                // This is a request to get a new directory pointer in
-                // *dir_out.
+	D2(printf("jffs2_chdir\n"));
 
-                jffs2_dirsearch ds;
-                int err;
+	if (dir_out != NULL) {
+		// This is a request to get a new directory pointer in
+		// *dir_out.
 
-                icache_evict((struct inode *) mte->root, (struct inode *) dir);
+		jffs2_dirsearch ds;
+		int err;
 
-                init_dirsearch(&ds, (struct inode *) dir, name);
+		init_dirsearch(&ds, (struct _inode *) dir, name);
 
-                err = jffs2_find(&ds);
+		err = jffs2_find(&ds);
+		jffs2_iput(ds.dir);
 
-                if (err != ENOERR)
-                        return err;
+		if (err != ENOERR)
+			return err;
 
-                // check it is a directory
-                if (!S_ISDIR(ds.node->i_mode))
-                        return ENOTDIR;
+		// check it is a directory
+		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 {
+		// If no output dir is required, this means that the mte and
+		// dir arguments are the current cdir setting and we should
+		// forget this fact.
 
-                // Pass it out
-                *dir_out = (cyg_dir) ds.node;
-        } else {
-                // If no output dir is required, this means that the mte and
-                // dir arguments are the current cdir setting and we should
-                // forget this fact.
+		struct _inode *node = (struct _inode *) dir;
 
-                struct inode *node = (struct inode *) dir;
+		// Just decrement directory reference count.
+		jffs2_iput(node);
+	}
 
-                // Just decrement directory reference count.
-                dec_refcnt(node);
-        }
-
-        return ENOERR;
+	return ENOERR;
 }
 
 // -------------------------------------------------------------------------
 // jffs2_stat()
 // Get struct stat info for named object.
 
 static int jffs2_stat(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
-                      struct stat *buf)
+		      struct stat *buf)
 {
-        jffs2_dirsearch ds;
-        int err;
-
-        D2(printf("jffs2_stat\n"));
+	jffs2_dirsearch ds;
+	int err;
 
-        icache_evict((struct inode *) mte->root, (struct inode *) dir);
+	D2(printf("jffs2_stat\n"));
 
-        init_dirsearch(&ds, (struct inode *) dir, name);
+	init_dirsearch(&ds, (struct _inode *) dir, name);
 
-        err = jffs2_find(&ds);
+	err = jffs2_find(&ds);
+	jffs2_iput(ds.dir);
 
-        if (err != ENOERR)
-                return err;
+	if (err != ENOERR)
+		return err;
 
-        // Fill in the status
-        buf->st_mode = ds.node->i_mode;
-        buf->st_ino = ds.node->i_ino;
-        buf->st_dev = 0;
-        buf->st_nlink = ds.node->i_nlink;
-        buf->st_uid = 0;
-        buf->st_gid = 0;
-        buf->st_size = ds.node->i_size;
-        buf->st_atime = ds.node->i_atime;
-        buf->st_mtime = ds.node->i_mtime;
-        buf->st_ctime = ds.node->i_ctime;
+	// Fill in the status
+	buf->st_mode = ds.node->i_mode;
+	buf->st_ino = ds.node->i_ino;
+	buf->st_dev = 0;
+	buf->st_nlink = ds.node->i_nlink;
+	buf->st_uid = ds.node->i_uid;
+	buf->st_gid = ds.node->i_gid;
+	buf->st_size = ds.node->i_size;
+	buf->st_atime = ds.node->i_atime;
+	buf->st_mtime = ds.node->i_mtime;
+	buf->st_ctime = ds.node->i_ctime;
 
-        return err;
+	jffs2_iput(ds.node);
 
-        return ENOERR;
+	return ENOERR;
 }
 
 // -------------------------------------------------------------------------
 // jffs2_getinfo()
 // Getinfo. Currently only support pathconf().
 
 static int jffs2_getinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
-                         int key, void *buf, int len)
+			 int key, void *buf, int len)
 {
-        jffs2_dirsearch ds;
-        int err;
+	jffs2_dirsearch ds;
+	int err;
 
-        D2(printf("jffs2_getinfo\n"));
+	D2(printf("jffs2_getinfo\n"));
 
-        icache_evict((struct inode *) mte->root, (struct inode *) dir);
+	init_dirsearch(&ds, (struct _inode *) dir, name);
 
-        init_dirsearch(&ds, (struct inode *) dir, name);
+	err = jffs2_find(&ds);
+	jffs2_iput(ds.dir);
 
-        err = jffs2_find(&ds);
+	if (err != ENOERR)
+		return err;
 
-        if (err != ENOERR)
-                return err;
+	switch (key) {
+	case FS_INFO_CONF:
+		err = jffs2_pathconf(ds.node, (struct cyg_pathconf_info *) buf);
+		break;
 
-        switch (key) {
-        case FS_INFO_CONF:
-                err = jffs2_pathconf(ds.node, (struct cyg_pathconf_info *) buf);
-                break;
-
-        default:
-                err = EINVAL;
-        }
-        return err;
+	default:
+		err = EINVAL;
+	}
 
-        return ENOERR;
+	jffs2_iput(ds.node);
+	return err;
 }
 
 // -------------------------------------------------------------------------
 // jffs2_setinfo()
 // Setinfo. Nothing to support here at present.
 
 static int jffs2_setinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
-                         int key, void *buf, int len)
+			 int key, void *buf, int len)
 {
-        // No setinfo keys supported at present
+	// No setinfo keys supported at present
 
-        D2(printf("jffs2_setinfo\n"));
+	D2(printf("jffs2_setinfo\n"));
 
-        return EINVAL;
+	return EINVAL;
 }
 
 //==========================================================================
 // File operations
 
@@ -1223,305 +1194,342 @@ static int jffs2_setinfo(cyg_mtab_entry 
 // jffs2_fo_read()
 // Read data from the file.
 
 static int jffs2_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
 {
-        struct inode *inode = (struct inode *) fp->f_data;
-        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
-        struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-        int i;
-        ssize_t resid = uio->uio_resid;
-        off_t pos = fp->f_offset;
-
-        down(&f->sem);
-
-        // Loop over the io vectors until there are none left
-        for (i = 0; i < uio->uio_iovcnt && pos < inode->i_size; i++) {
-                int ret;
-                cyg_iovec *iov = &uio->uio_iov[i];
-                off_t len = min(iov->iov_len, inode->i_size - pos);
-
-                D2(printf("jffs2_fo_read inode size %d\n", inode->i_size));
-
-                ret =
-                    jffs2_read_inode_range(c, f,
-                                           (unsigned char *) iov->iov_base, pos,
-                                           len);
-                if (ret) {
-                        D1(printf
-                           ("jffs2_fo_read(): read_inode_range failed %d\n",
-                            ret));
-                        uio->uio_resid = resid;
-                        up(&f->sem);
-                        return -ret;
-                }
-                resid -= len;
-                pos += len;
-        }
-
-        // We successfully read some data, update the node's access time
-        // and update the file offset and transfer residue.
-
-        inode->i_atime = cyg_timestamp();
+	struct _inode *inode = (struct _inode *) fp->f_data;
+	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+	int i;
+	ssize_t resid = uio->uio_resid;
+	off_t pos = fp->f_offset;
+
+	down(&f->sem);
+
+	// Loop over the io vectors until there are none left
+	for (i = 0; i < uio->uio_iovcnt && pos < inode->i_size; i++) {
+		int ret;
+		cyg_iovec *iov = &uio->uio_iov[i];
+		off_t len = min(iov->iov_len, inode->i_size - pos);
+
+		D2(printf("jffs2_fo_read inode size %d\n", inode->i_size));
+
+		ret =
+		    jffs2_read_inode_range(c, f,
+					   (unsigned char *) iov->iov_base, pos,
+					   len);
+		if (ret) {
+			D1(printf
+			   ("jffs2_fo_read(): read_inode_range failed %d\n",
+			    ret));
+			uio->uio_resid = resid;
+			up(&f->sem);
+			return -ret;
+		}
+		resid -= len;
+		pos += len;
+	}
+
+	// We successfully read some data, update the node's access time
+	// and update the file offset and transfer residue.
+
+	inode->i_atime = cyg_timestamp();
+
+	uio->uio_resid = resid;
+	fp->f_offset = pos;
 
-        uio->uio_resid = resid;
-        fp->f_offset = pos;
+	up(&f->sem);
 
-        up(&f->sem);
-
-        return ENOERR;
+	return ENOERR;
 }
 
+
+#ifdef CYGOPT_FS_JFFS2_WRITE
 // -------------------------------------------------------------------------
 // jffs2_fo_write()
 // Write data to file.
+static int jffs2_extend_file (struct _inode *inode, struct jffs2_raw_inode *ri,
+		       unsigned long offset)
+{
+	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+	struct jffs2_full_dnode *fn;
+	uint32_t phys_ofs, alloc_len;
+	int ret = 0;
+
+	/* Make new hole frag from old EOF to new page */
+	D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n",
+		  (unsigned int)inode->i_size, offset));
+
+	ret = jffs2_reserve_space(c, sizeof(ri), &phys_ofs, &alloc_len, ALLOC_NORMAL);
+	if (ret)
+		return ret;
+
+	down(&f->sem);
+
+	ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+	ri->totlen = cpu_to_je32(sizeof(ri));
+	ri->hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4));
+
+	ri->version = cpu_to_je32(++f->highest_version);
+	ri->isize = cpu_to_je32(max((uint32_t)inode->i_size, offset));
+
+	ri->offset = cpu_to_je32(inode->i_size);
+	ri->dsize = cpu_to_je32(offset - inode->i_size);
+	ri->csize = cpu_to_je32(0);
+	ri->compr = JFFS2_COMPR_ZERO;
+	ri->node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
+	ri->data_crc = cpu_to_je32(0);
+		
+	fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL);
+	jffs2_complete_reservation(c);
+	if (IS_ERR(fn)) {
+		ret = PTR_ERR(fn);
+		up(&f->sem);
+		return ret;
+	}
+	ret = jffs2_add_full_dnode_to_inode(c, f, fn);
+	if (f->metadata) {
+		jffs2_mark_node_obsolete(c, f->metadata->raw);
+		jffs2_free_full_dnode(f->metadata);
+		f->metadata = NULL;
+	}
+	if (ret) {
+		D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in prepare_write, returned %d\n", ret));
+		jffs2_mark_node_obsolete(c, fn->raw);
+		jffs2_free_full_dnode(fn);
+		up(&f->sem);
+		return ret;
+	}
+	inode->i_size = offset;
+	up(&f->sem);
+	return 0;
+}
 
 static int jffs2_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
 {
-        struct page write_page;
-        off_t page_start_pos;
-        struct inode *node = (struct inode *) fp->f_data;
-        off_t pos = fp->f_offset;
-        ssize_t resid = uio->uio_resid;
-        int i;
-
-        memset(&read_write_buffer, 0, PAGE_CACHE_SIZE);
-        write_page.virtual = &read_write_buffer;
-
-        // If the APPEND mode bit was supplied, force all writes to
-        // the end of the file.
-        if (fp->f_flag & CYG_FAPPEND)
-                pos = fp->f_offset = node->i_size;
-
-        // Check that pos is within current file size, or at the very end.
-        if (pos < 0 || pos > node->i_size)
-                return EINVAL;
-
-        // Now loop over the iovecs until they are all done, or
-        // we get an error.
-        for (i = 0; i < uio->uio_iovcnt; i++) {
-                cyg_iovec *iov = &uio->uio_iov[i];
-                char *buf = (char *) iov->iov_base;
-                off_t len = iov->iov_len;
-
-                // loop over the vector writing it to the file until it has
-                // all been done.
-                while (len > 0) {
-                        //cyg_uint8 *fbuf;
-                        //size_t bsize;
-                        size_t writtenlen;
-                        off_t l = len;
-                        int err;
-
-                        write_page.index = 0;
-
-                        page_start_pos = pos;
-                        while (page_start_pos >= (PAGE_CACHE_SIZE)) {
-                                write_page.index++;
-                                page_start_pos -= PAGE_CACHE_SIZE;
-                        }
-
-                        if (l > PAGE_CACHE_SIZE - page_start_pos)
-                                l = PAGE_CACHE_SIZE - page_start_pos;
-
-                        D2(printf
-                           ("jffs2_fo_write write_page.index %d\n",
-                            write_page.index));
-                        D2(printf
-                           ("jffs2_fo_write page_start_pos %d\n",
-                            page_start_pos));
-                        D2(printf("jffs2_fo_write transfer size %d\n", l));
-
-                        err =
-                            jffs2_prepare_write(node, &write_page,
-                                                page_start_pos,
-                                                page_start_pos + l);
-
-                        if (err != 0)
-                                return err;
-
-                        // copy data in
-                        memcpy(&read_write_buffer[page_start_pos], buf, l);
-
-                        writtenlen =
-                            jffs2_commit_write(node, &write_page,
-                                               page_start_pos,
-                                               page_start_pos + l);
-
-                        if (writtenlen != l)
-                                return ENOSPC;
-
-                        // Update working vars
-                        len -= l;
-                        buf += l;
-                        pos += l;
-                        resid -= l;
-                }
-        }
-
-        // We wrote some data successfully, update the modified and access
-        // times of the node, increase its size appropriately, and update
-        // the file offset and transfer residue.
-        node->i_mtime = node->i_ctime = cyg_timestamp();
-        if (pos > node->i_size)
-                node->i_size = pos;
+	struct _inode *inode = (struct _inode *) fp->f_data;
+	off_t pos = fp->f_offset;
+	ssize_t resid = uio->uio_resid;
+	struct jffs2_raw_inode ri;
+	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+	int i;
+
+	// If the APPEND mode bit was supplied, force all writes to
+	// the end of the file.
+	if (fp->f_flag & CYG_FAPPEND)
+		pos = fp->f_offset = inode->i_size;
+
+	if (pos < 0)
+		return EINVAL;
+
+	memset(&ri, 0, sizeof(ri));
+
+	ri.ino = cpu_to_je32(f->inocache->ino);
+	ri.mode = cpu_to_jemode(inode->i_mode);
+	ri.uid = cpu_to_je16(inode->i_uid);
+	ri.gid = cpu_to_je16(inode->i_gid);
+	ri.atime = ri.ctime = ri.mtime = cpu_to_je32(cyg_timestamp());
+
+	if (pos > inode->i_size) {
+		int err;
+		ri.version = cpu_to_je32(++f->highest_version);
+		err = jffs2_extend_file(inode, &ri, pos);
+		if (err)
+			return -err;
+	}
+
+	// Now loop over the iovecs until they are all done, or
+	// we get an error.
+	for (i = 0; i < uio->uio_iovcnt; i++) {
+		cyg_iovec *iov = &uio->uio_iov[i];
+		char *buf = (char *) iov->iov_base;
+		off_t len = iov->iov_len;
+
+		uint32_t writtenlen;
+		int err;
+
+		D2(printf("jffs2_fo_write page_start_pos %d\n", pos));
+		D2(printf("jffs2_fo_write transfer size %d\n", l));
+
+		err = jffs2_write_inode_range(c, f, &ri, buf,
+					      pos, len, &writtenlen);
+		if (err)
+			return -err;
+		
+		if (writtenlen != len)
+			return ENOSPC;
+
+		pos += len;
+		resid -= len;
+	}
+
+	// We wrote some data successfully, update the modified and access
+	// times of the inode, increase its size appropriately, and update
+	// the file offset and transfer residue.
+	inode->i_mtime = inode->i_ctime = je32_to_cpu(ri.mtime);
+	if (pos > inode->i_size)
+		inode->i_size = pos;
 
-        uio->uio_resid = resid;
-        fp->f_offset = pos;
+	uio->uio_resid = resid;
+	fp->f_offset = pos;
 
-        return ENOERR;
+	return ENOERR;
 }
+#endif /* CYGOPT_FS_JFFS2_WRITE */
 
 // -------------------------------------------------------------------------
 // jffs2_fo_lseek()
 // Seek to a new file position.
 
 static int jffs2_fo_lseek(struct CYG_FILE_TAG *fp, off_t * apos, int whence)
 {
-        struct inode *node = (struct inode *) fp->f_data;
-        off_t pos = *apos;
-
-        D2(printf("jffs2_fo_lseek\n"));
+	struct _inode *node = (struct _inode *) fp->f_data;
+	off_t pos = *apos;
 
-        switch (whence) {
-        case SEEK_SET:
-                // Pos is already where we want to be.
-                break;
-
-        case SEEK_CUR:
-                // Add pos to current offset.
-                pos += fp->f_offset;
-                break;
-
-        case SEEK_END:
-                // Add pos to file size.
-                pos += node->i_size;
-                break;
+	D2(printf("jffs2_fo_lseek\n"));
 
-        default:
-                return EINVAL;
-        }
-
-        // Check that pos is still within current file size, or at the
-        // very end.
-        if (pos < 0 || pos > node->i_size)
-                return EINVAL;
+	switch (whence) {
+	case SEEK_SET:
+		// Pos is already where we want to be.
+		break;
+
+	case SEEK_CUR:
+		// Add pos to current offset.
+		pos += fp->f_offset;
+		break;
+
+	case SEEK_END:
+		// Add pos to file size.
+		pos += node->i_size;
+		break;
+
+	default:
+		return EINVAL;
+	}
+
+	// Check that pos is still within current file size, or at the
+	// very end.
+	if (pos < 0 || pos > node->i_size)
+		return EINVAL;
 
-        // All OK, set fp offset and return new position.
-        *apos = fp->f_offset = pos;
+	// All OK, set fp offset and return new position.
+	*apos = fp->f_offset = pos;
 
-        return ENOERR;
+	return ENOERR;
 }
 
 // -------------------------------------------------------------------------
 // jffs2_fo_ioctl()
 // Handle ioctls. Currently none are defined.
 
 static int jffs2_fo_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
-                          CYG_ADDRWORD data)
+			  CYG_ADDRWORD data)
 {
-        // No Ioctls currenly defined.
+	// No Ioctls currenly defined.
 
-        D2(printf("jffs2_fo_ioctl\n"));
+	D2(printf("jffs2_fo_ioctl\n"));
 
-        return EINVAL;
+	return EINVAL;
 }
 
 // -------------------------------------------------------------------------
 // jffs2_fo_fsync().
 // Force the file out to data storage.
 
 static int jffs2_fo_fsync(struct CYG_FILE_TAG *fp, int mode)
 {
-        // Data is always permanently where it belongs, nothing to do
-        // here.
+	// Data is always permanently where it belongs, nothing to do
+	// here.
 
-        D2(printf("jffs2_fo_fsync\n"));
+	D2(printf("jffs2_fo_fsync\n"));
 
-        return ENOERR;
+	return ENOERR;
 }
 
 // -------------------------------------------------------------------------
 // jffs2_fo_close()
 // Close a file. We just decrement the refcnt and let it go away if
 // that is all that is keeping it here.
 
 static int jffs2_fo_close(struct CYG_FILE_TAG *fp)
 {
-        struct inode *node = (struct inode *) fp->f_data;
+	struct _inode *node = (struct _inode *) fp->f_data;
 
-        D2(printf("jffs2_fo_close\n"));
+	D2(printf("jffs2_fo_close\n"));
 
-        dec_refcnt(node);
+	jffs2_iput(node);
 
-        fp->f_data = 0;         // zero data pointer
+	fp->f_data = 0;		// zero data pointer
 
-        return ENOERR;
+	return ENOERR;
 }
 
 // -------------------------------------------------------------------------
 //jffs2_fo_fstat()
 // Get file status.
 
 static int jffs2_fo_fstat(struct CYG_FILE_TAG *fp, struct stat *buf)
 {
-        struct inode *node = (struct inode *) fp->f_data;
+	struct _inode *node = (struct _inode *) fp->f_data;
 
-        D2(printf("jffs2_fo_fstat\n"));
+	D2(printf("jffs2_fo_fstat\n"));
 
-        // Fill in the status
-        buf->st_mode = node->i_mode;
-        buf->st_ino = node->i_ino;
-        buf->st_dev = 0;
-        buf->st_nlink = node->i_nlink;
-        buf->st_uid = 0;
-        buf->st_gid = 0;
-        buf->st_size = node->i_size;
-        buf->st_atime = node->i_atime;
-        buf->st_mtime = node->i_mtime;
-        buf->st_ctime = node->i_ctime;
+	// Fill in the status
+	buf->st_mode = node->i_mode;
+	buf->st_ino = node->i_ino;
+	buf->st_dev = 0;
+	buf->st_nlink = node->i_nlink;
+	buf->st_uid = node->i_uid;
+	buf->st_gid = node->i_gid;
+	buf->st_size = node->i_size;
+	buf->st_atime = node->i_atime;
+	buf->st_mtime = node->i_mtime;
+	buf->st_ctime = node->i_ctime;
 
-        return ENOERR;
+	return ENOERR;
 }
 
 // -------------------------------------------------------------------------
 // jffs2_fo_getinfo()
 // Get info. Currently only supports fpathconf().
 
 static int jffs2_fo_getinfo(struct CYG_FILE_TAG *fp, int key, void *buf,
-                            int len)
+			    int len)
 {
-        struct inode *node = (struct inode *) fp->f_data;
-        int err;
+	struct _inode *node = (struct _inode *) fp->f_data;
+	int err;
 
-        D2(printf("jffs2_fo_getinfo\n"));
+	D2(printf("jffs2_fo_getinfo\n"));
 
-        switch (key) {
-        case FS_INFO_CONF:
-                err = jffs2_pathconf(node, (struct cyg_pathconf_info *) buf);
-                break;
+	switch (key) {
+	case FS_INFO_CONF:
+		err = jffs2_pathconf(node, (struct cyg_pathconf_info *) buf);
+		break;
 
-        default:
-                err = EINVAL;
-        }
-        return err;
+	default:
+		err = EINVAL;
+	}
+	return err;
 
-        return ENOERR;
+	return ENOERR;
 }
 
 // -------------------------------------------------------------------------
 // jffs2_fo_setinfo()
 // Set info. Nothing supported here.
 
 static int jffs2_fo_setinfo(struct CYG_FILE_TAG *fp, int key, void *buf,
-                            int len)
+			    int len)
 {
-        // No setinfo key supported at present
+	// No setinfo key supported at present
 
-        D2(printf("jffs2_fo_setinfo\n"));
+	D2(printf("jffs2_fo_setinfo\n"));
 
-        return ENOERR;
+	return ENOERR;
 }
 
 //==========================================================================
 // Directory operations
 
@@ -1529,456 +1537,288 @@ static int jffs2_fo_setinfo(struct CYG_F
 // jffs2_fo_dirread()
 // Read a single directory entry from a file.
 
 static __inline void filldir(char *nbuf, int nlen, const char *name, int namlen)
 {
-        int len = nlen < namlen ? nlen : namlen;
-        memcpy(nbuf, name, len);
-        nbuf[len] = '\0';
+	int len = nlen < namlen ? nlen : namlen;
+	memcpy(nbuf, name, len);
+	nbuf[len] = '\0';
 }
 
 static int jffs2_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
 {
-        struct inode *d_inode = (struct inode *) fp->f_data;
-        struct dirent *ent = (struct dirent *) uio->uio_iov[0].iov_base;
-        char *nbuf = ent->d_name;
-        int nlen = sizeof (ent->d_name) - 1;
-        off_t len = uio->uio_iov[0].iov_len;
-        struct jffs2_inode_info *f;
-        struct jffs2_sb_info *c;
-        struct inode *inode = d_inode;
-        struct jffs2_full_dirent *fd;
-        unsigned long offset, curofs;
-        int found = 1;
-
-        if (len < sizeof (struct dirent))
-                return EINVAL;
-
-        D1(printk
-           (KERN_DEBUG "jffs2_readdir() for dir_i #%lu\n", d_inode->i_ino));
-
-        f = JFFS2_INODE_INFO(inode);
-        c = JFFS2_SB_INFO(inode->i_sb);
-
-        offset = fp->f_offset;
-
-        if (offset == 0) {
-                D1(printk
-                   (KERN_DEBUG "Dirent 0: \".\", ino #%lu\n", inode->i_ino));
-                filldir(nbuf, nlen, ".", 1);
-                goto out;
-        }
-        if (offset == 1) {
-                filldir(nbuf, nlen, "..", 2);
-                goto out;
-        }
-
-        curofs = 1;
-        down(&f->sem);
-        for (fd = f->dents; fd; fd = fd->next) {
-
-                curofs++;
-                /* First loop: curofs = 2; offset = 2 */
-                if (curofs < offset) {
-                        D2(printk
-                           (KERN_DEBUG
-                            "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n",
-                            fd->name, fd->ino, fd->type, curofs, offset));
-                        continue;
-                }
-                if (!fd->ino) {
-                        D2(printk
-                           (KERN_DEBUG "Skipping deletion dirent \"%s\"\n",
-                            fd->name));
-                        offset++;
-                        continue;
-                }
-                D2(printk
-                   (KERN_DEBUG "Dirent %ld: \"%s\", ino #%u, type %d\n", offset,
-                    fd->name, fd->ino, fd->type));
-                filldir(nbuf, nlen, fd->name, strlen(fd->name));
-                goto out_sem;
-        }
-        /* Reached the end of the directory */
-        found = 0;
+	struct _inode *d_inode = (struct _inode *) fp->f_data;
+	struct dirent *ent = (struct dirent *) uio->uio_iov[0].iov_base;
+	char *nbuf = ent->d_name;
+	int nlen = sizeof (ent->d_name) - 1;
+	off_t len = uio->uio_iov[0].iov_len;
+	struct jffs2_inode_info *f;
+	struct jffs2_sb_info *c;
+	struct _inode *inode = d_inode;
+	struct jffs2_full_dirent *fd;
+	unsigned long offset, curofs;
+	int found = 1;
+
+	if (len < sizeof (struct dirent))
+		return EINVAL;
+
+	D1(printk
+	   (KERN_DEBUG "jffs2_readdir() for dir_i #%lu\n", d_inode->i_ino));
+
+	f = JFFS2_INODE_INFO(inode);
+	c = JFFS2_SB_INFO(inode->i_sb);
+
+	offset = fp->f_offset;
+
+	if (offset == 0) {
+		D1(printk
+		   (KERN_DEBUG "Dirent 0: \".\", ino #%lu\n", inode->i_ino));
+		filldir(nbuf, nlen, ".", 1);
+		goto out;
+	}
+	if (offset == 1) {
+		filldir(nbuf, nlen, "..", 2);
+		goto out;
+	}
+
+	curofs = 1;
+	down(&f->sem);
+	for (fd = f->dents; fd; fd = fd->next) {
+
+		curofs++;
+		/* First loop: curofs = 2; offset = 2 */
+		if (curofs < offset) {
+			D2(printk
+			   (KERN_DEBUG
+			    "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n",
+			    fd->name, fd->ino, fd->type, curofs, offset));
+			continue;
+		}
+		if (!fd->ino) {
+			D2(printk
+			   (KERN_DEBUG "Skipping deletion dirent \"%s\"\n",
+			    fd->name));
+			offset++;
+			continue;
+		}
+		D2(printk
+		   (KERN_DEBUG "Dirent %ld: \"%s\", ino #%u, type %d\n", offset,
+		    fd->name, fd->ino, fd->type));
+		filldir(nbuf, nlen, fd->name, strlen(fd->name));
+		goto out_sem;
+	}
+	/* Reached the end of the directory */
+	found = 0;
       out_sem:
-        up(&f->sem);
+	up(&f->sem);
       out:
-        fp->f_offset = ++offset;
-        if (found) {
-                uio->uio_resid -= sizeof (struct dirent);
-        }
-        return ENOERR;
+	fp->f_offset = ++offset;
+	if (found) {
+		uio->uio_resid -= sizeof (struct dirent);
+	}
+	return ENOERR;
 }
 
 // -------------------------------------------------------------------------
 // jffs2_fo_dirlseek()
 // Seek directory to start.
 
 static int jffs2_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t * pos, int whence)
 {
-        // Only allow SEEK_SET to zero
+	// Only allow SEEK_SET to zero
 
-        D2(printf("jffs2_fo_dirlseek\n"));
+	D2(printf("jffs2_fo_dirlseek\n"));
 
-        if (whence != SEEK_SET || *pos != 0)
-                return EINVAL;
+	if (whence != SEEK_SET || *pos != 0)
+		return EINVAL;
 
-        *pos = fp->f_offset = 0;
+	*pos = fp->f_offset = 0;
 
-        return ENOERR;
+	return ENOERR;
 }
 
 //==========================================================================
 // 
 // Called by JFFS2
 // ===============
 // 
 //
 //==========================================================================
 
-struct page *read_cache_page(unsigned long index,
-                             int (*filler) (void *, struct page *), void *data)
+unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, 
+				   struct jffs2_inode_info *f, 
+				   unsigned long offset,
+				   unsigned long *priv)
 {
-        // Only called in gc.c jffs2_garbage_collect_dnode
-        // but gets a real page for the specified inode
-
-        int err;
-        struct page *gc_page = malloc(sizeof (struct page));
+	/* FIXME: This works only with one file system mounted at a time */
+	int ret;
 
-        printf("read_cache_page\n");
-        memset(&gc_buffer, 0, PAGE_CACHE_SIZE);
-
-        if (gc_page != NULL) {
-                gc_page->virtual = &gc_buffer;
-                gc_page->index = index;
-
-                err = filler(data, gc_page);
-                if (err < 0) {
-                        free(gc_page);
-                        gc_page = NULL;
-                }
-        }
+	ret = jffs2_read_inode_range(c, f, gc_buffer, offset, PAGE_CACHE_SIZE);
+	if (ret)
+		return ERR_PTR(ret);
 
-        return gc_page;
+	return gc_buffer;
 }
 
-void page_cache_release(struct page *pg)
+void jffs2_gc_release_page(struct jffs2_sb_info *c,
+			   unsigned char *ptr,
+			   unsigned long *priv)
 {
-
-        // Only called in gc.c jffs2_garbage_collect_dnode
-        // but should free the page malloc'd by read_cache_page
-
-        printf("page_cache_release\n");
-        free(pg);
+	/* Do nothing */
 }
 
-struct inode *new_inode(struct super_block *sb)
+static struct _inode *new_inode(struct super_block *sb)
 {
 
-        // Only called in write.c jffs2_new_inode
-        // Always adds itself to inode cache
-
-        struct inode *inode;
-        struct inode *cached_inode;
+	// Only called in write.c jffs2_new_inode
+	// Always adds itself to inode cache
 
-        inode = malloc(sizeof (struct inode));
-        if (inode == NULL)
-                return 0;
+	struct _inode *inode;
+	struct _inode *cached_inode;
 
-        D2(printf
-           ("malloc new_inode %x ####################################\n",
-            inode));
+	inode = malloc(sizeof (struct _inode));
+	if (inode == NULL)
+		return 0;
 
-        memset(inode, 0, sizeof (struct inode));
-        inode->i_sb = sb;
-        inode->i_ino = 1;
-        inode->i_count = 0;     //1; // Let ecos manage the open count
+	D2(printf
+	   ("malloc new_inode %x ####################################\n",
+	    inode));
 
-        inode->i_nlink = 1;     // Let JFFS2 manage the link count
-        inode->i_size = 0;
+	memset(inode, 0, sizeof (struct _inode));
+	inode->i_sb = sb;
+	inode->i_ino = 1;
+	inode->i_count = 1;
+	inode->i_nlink = 1;	// Let JFFS2 manage the link count
+	inode->i_size = 0;
 
-        inode->i_cache_next = NULL;     // Newest inode, about to be cached
+	inode->i_cache_next = NULL;	// Newest inode, about to be cached
 
-        // Add to the icache
-        for (cached_inode = sb->s_root; cached_inode != NULL;
-             cached_inode = cached_inode->i_cache_next) {
-                if (cached_inode->i_cache_next == NULL) {
-                        cached_inode->i_cache_next = inode;     // Current last in cache points to newcomer
-                        inode->i_cache_prev = cached_inode;     // Newcomer points back to last
-                        break;
-                }
-        }
+	// Add to the icache
+	for (cached_inode = sb->s_root; cached_inode != NULL;
+	     cached_inode = cached_inode->i_cache_next) {
+		if (cached_inode->i_cache_next == NULL) {
+			cached_inode->i_cache_next = inode;	// Current last in cache points to newcomer
+			inode->i_cache_prev = cached_inode;	// Newcomer points back to last
+			break;
+		}
+	}
 
-        return inode;
+	return inode;
 }
-struct inode *ilookup(struct super_block *sb, cyg_uint32 ino)
+
+static struct _inode *ilookup(struct super_block *sb, cyg_uint32 ino)
 {
-        struct inode *inode = NULL;
+	struct _inode *inode = NULL;
 
-        D2(printf("ilookup\n"));
-        // Check for this inode in the cache
-        for (inode = sb->s_root; inode != NULL; inode = inode->i_cache_next) {
-                if (inode->i_ino == ino) {
-                        inode->i_count++;
-                        break;
-                }
-        }
+	D2(printf("ilookup\n"));
+	// Check for this inode in the cache
+	for (inode = sb->s_root; inode != NULL; inode = inode->i_cache_next) {
+		if (inode->i_ino == ino) {
+			inode->i_count++;
+			break;
+		}
+	}
 
-        return inode;
+	return inode;
 }
 
-struct inode *iget(struct super_block *sb, cyg_uint32 ino)
+struct _inode *jffs2_iget(struct super_block *sb, cyg_uint32 ino)
 {
+	// Called in super.c jffs2_read_super, dir.c jffs2_lookup,
+	// and gc.c jffs2_garbage_collect_pass
 
-        // Substitute for iget drops straight through to reading the 
-        // inode from disk if it is not in the inode cache
+	// Must first check for cached inode 
+	// If this fails let new_inode create one
 
-        // Called in super.c jffs2_read_super, dir.c jffs2_lookup,
-        // and gc.c jffs2_garbage_collect_pass
+	struct _inode *inode;
+	int err;
 
-        // Must first check for cached inode 
-        // If this fails let new_inode create one
+	D2(printf("jffs2_iget\n"));
 
-        struct inode *inode;
+	inode = ilookup(sb, ino);
+	if (inode)
+		return inode;
 
-        D2(printf("iget\n"));
+	// Not cached, so malloc it
+	inode = new_inode(sb);
+	if (inode == NULL)
+		return 0;
 
-        inode = ilookup(sb, ino);
-        if (inode)
-                return inode;
+	inode->i_ino = ino;
 
-        // Not cached, so malloc it
-        inode = new_inode(sb);
-        if (inode == NULL)
-                return 0;
-
-        inode->i_ino = ino;
-        jffs2_read_inode(inode);
-        inode->i_count = 1;
-        return inode;
+	err = jffs2_read_inode(inode);
+	if (err) {
+		printf("jffs2_read_inode() failed\n");
+		jffs2_iput(inode);
+		inode = NULL;
+		return ERR_PTR(err);
+	}
+	return inode;
 }
 
-void iput(struct inode *i)
-{
-
-        // Called in dec_refcnt, 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 != NULL) {
-                // Remove from the icache
-                for (cached_inode = i->i_sb->s_root; cached_inode != NULL;
-                     cached_inode = cached_inode->i_cache_next) {
-                        if (cached_inode == i) {
-                                if(cached_inode->i_cache_prev != NULL) {
-                                        cached_inode->i_cache_prev->i_cache_next = cached_inode->i_cache_next;  // Previous entry points ahead of us
-                                        if (cached_inode->i_cache_next != NULL)
-                                                cached_inode->i_cache_next->i_cache_prev = cached_inode->i_cache_prev;  // Next entry points behind us
-                                }
-                                break;
-                        }
-                }
-                // inode has been seperated from the cache
-                jffs2_clear_inode(i);
-                free(i);
-        }
-}
+// -------------------------------------------------------------------------
+// Decrement the reference count on an inode. If this makes the ref count
+// zero, then this inode can be freed.
 
-static int return_EIO(void)
+void jffs2_iput(struct _inode *i)
 {
-        return -EIO;
+	// Called in jffs2_find 
+	// (and jffs2_open and jffs2_ops_mkdir?)
+	// super.c jffs2_read_super,
+	// and gc.c jffs2_garbage_collect_pass
+ recurse:
+	if (!i) {
+		printf("jffs2_iput() called with NULL inode\n");
+		// and let it fault... 
+	}
+
+	i->i_count--;
+
+	if (i->i_count < 0)
+		BUG();
+
+	if (i->i_count)
+		return;
+
+	if (!i->i_nlink) {
+		struct _inode *parent;
+
+		// Remove from the icache linked list and free immediately
+		if (i->i_cache_prev)
+			i->i_cache_prev->i_cache_next = i->i_cache_next;
+		if (i->i_cache_next)
+			i->i_cache_next->i_cache_prev = i->i_cache_prev;
+
+		parent = i->i_parent;
+		jffs2_clear_inode(i);
+		memset(i, 0x5a, sizeof(*i));
+		free(i);
+
+		if (parent && parent != i) {
+			i = parent;
+			goto recurse;
+		}
+
+	} else {
+		// Evict some _other_ inode with i_count zero, leaving
+		// this latest one in the cache for a while 
+		icache_evict(i->i_sb->s_root, i);
+	}
 }
 
-#define EIO_ERROR ((void *) (return_EIO))
 
-void make_bad_inode(struct inode *inode)
-{
-
-        // In readinode.c JFFS2 checks whether the inode has appropriate
-        // content for its marked type
-
-        D2(printf("make_bad_inode\n"));
-
-        inode->i_mode = S_IFREG;
-        inode->i_atime = inode->i_mtime = inode->i_ctime = cyg_timestamp();
-        inode->i_op = EIO_ERROR;
-        inode->i_fop = EIO_ERROR;
-}
-
-int is_bad_inode(struct inode *inode)
-{
-
-        // Called in super.c jffs2_read_super,
-        // and gc.c jffs2_garbage_collect_pass
-
-        D2(printf("is_bad_inode\n"));
-
-        return (inode->i_op == EIO_ERROR);
-        /*if(i == NULL)
-           return 1;
-           return 0; */
-}
-
-cyg_bool jffs2_flash_read(struct jffs2_sb_info * c,
-                          cyg_uint32 read_buffer_offset, const size_t size,
-                          size_t * return_size, char *write_buffer)
-{
-        Cyg_ErrNo err;
-        cyg_uint32 len = size;
-        struct super_block *sb = OFNI_BS_2SFFJ(c);
-
-        //D2(printf("FLASH READ\n"));
-        //D2(printf("read address = %x\n", CYGNUM_FS_JFFS2_BASE_ADDRESS + read_buffer_offset));
-        //D2(printf("write address = %x\n", write_buffer));
-        //D2(printf("size = %x\n", size));
-        err = cyg_io_bread(sb->s_dev, write_buffer, &len, read_buffer_offset);
-
-        *return_size = (size_t) len;
-        return ((err == ENOERR) ? ENOERR : -EIO);
-}
-
-cyg_bool jffs2_flash_write(struct jffs2_sb_info * c,
-                           cyg_uint32 write_buffer_offset, const size_t size,
-                           size_t * return_size, char *read_buffer)
-{
-
-        Cyg_ErrNo err;
-        cyg_uint32 len = size;
-        struct super_block *sb = OFNI_BS_2SFFJ(c);
-
-        //    D2(printf("FLASH WRITE ENABLED!!!\n"));
-        //    D2(printf("write address = %x\n", CYGNUM_FS_JFFS2_BASE_ADDRESS + write_buffer_offset));
-        //    D2(printf("read address = %x\n", read_buffer));
-        //    D2(printf("size = %x\n", size));
-
-        err = cyg_io_bwrite(sb->s_dev, read_buffer, &len, write_buffer_offset);
-        *return_size = (size_t) len;
-
-        return ((err == ENOERR) ? ENOERR : -EIO);
-}
-
-int
-jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct iovec *vecs,
-                   unsigned long count, loff_t to, size_t * retlen)
-{
-        unsigned long i;
-        size_t totlen = 0, thislen;
-        int ret = 0;
-
-        for (i = 0; i < count; i++) {
-                // writes need to be aligned but the data we're passed may not be
-                // Observation suggests most unaligned writes are small, so we
-                // optimize for that case.
-
-                if (((vecs[i].iov_len & (sizeof (int) - 1))) ||
-                    (((unsigned long) vecs[i].
-                      iov_base & (sizeof (unsigned long) - 1)))) {
-                        // are there iov's after this one? Or is it so much we'd need
-                        // to do multiple writes anyway?
-                        if ((i + 1) < count || vecs[i].iov_len > 256) {
-                                // cop out and malloc
-                                unsigned long j;
-                                ssize_t sizetomalloc = 0, totvecsize = 0;
-                                char *cbuf, *cbufptr;
-
-                                for (j = i; j < count; j++)
-                                        totvecsize += vecs[j].iov_len;
-
-                                // pad up in case unaligned
-                                sizetomalloc = totvecsize + sizeof (int) - 1;
-                                sizetomalloc &= ~(sizeof (int) - 1);
-                                cbuf = (char *) malloc(sizetomalloc);
-                                // malloc returns aligned memory
-                                if (!cbuf) {
-                                        ret = -ENOMEM;
-                                        goto writev_out;
-                                }
-                                cbufptr = cbuf;
-                                for (j = i; j < count; j++) {
-                                        memcpy(cbufptr, vecs[j].iov_base,
-                                               vecs[j].iov_len);
-                                        cbufptr += vecs[j].iov_len;
-                                }
-                                ret =
-                                    jffs2_flash_write(c, to, sizetomalloc,
-                                                      &thislen, cbuf);
-                                if (thislen > totvecsize)       // in case it was aligned up
-                                        thislen = totvecsize;
-                                totlen += thislen;
-                                free(cbuf);
-                                goto writev_out;
-                        } else {
-                                // otherwise optimize for the common case
-                                int buf[256 / sizeof (int)];    // int, so int aligned
-                                size_t lentowrite;
-
-                                lentowrite = vecs[i].iov_len;
-                                // pad up in case its unaligned
-                                lentowrite += sizeof (int) - 1;
-                                lentowrite &= ~(sizeof (int) - 1);
-                                memcpy(buf, vecs[i].iov_base, lentowrite);
-
-                                ret =
-                                    jffs2_flash_write(c, to, lentowrite,
-                                                      &thislen, (char *) &buf);
-                                if (thislen > vecs[i].iov_len)
-                                        thislen = vecs[i].iov_len;
-                        }       // else
-                } else
-                        ret =
-                            jffs2_flash_write(c, to, vecs[i].iov_len, &thislen,
-                                              vecs[i].iov_base);
-                totlen += thislen;
-                if (ret || thislen != vecs[i].iov_len)
-                        break;
-                to += vecs[i].iov_len;
-        }
-      writev_out:
-        if (retlen)
-                *retlen = totlen;
+// -------------------------------------------------------------------------
+// EOF jffs2.c
 
-        return ret;
-}
 
-cyg_bool jffs2_flash_erase(struct jffs2_sb_info * c,
-                           struct jffs2_eraseblock * jeb)
+static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
 {
-        cyg_io_flash_getconfig_erase_t e;
-        void *err_addr;
-        Cyg_ErrNo err;
-        cyg_uint32 len = sizeof (e);
-        struct super_block *sb = OFNI_BS_2SFFJ(c);
-
-        e.offset = jeb->offset;
-        e.len = c->sector_size;
-        e.err_address = &err_addr;
-
-        //        D2(printf("FLASH ERASE ENABLED!!!\n"));
-        //        D2(printf("erase address = %x\n", CYGNUM_FS_JFFS2_BASE_ADDRESS + jeb->offset));
-        //        D2(printf("size = %x\n", c->sector_size));
-
-        err = cyg_io_get_config(sb->s_dev, CYG_IO_GET_CONFIG_FLASH_ERASE,
-                                &e, &len);
-
-        return (err != ENOERR || e.flasherr != 0);
+	memset(f, 0, sizeof(*f));
+	init_MUTEX_LOCKED(&f->sem);
 }
 
-// -------------------------------------------------------------------------
-// EOF jffs2.c
-void jffs2_clear_inode (struct inode *inode)
+static void jffs2_clear_inode (struct _inode *inode)
 {
         /* We can forget about this inode for now - drop all
          *  the nodelists associated with it, etc.
          */
         struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
@@ -1990,85 +1830,229 @@ void jffs2_clear_inode (struct inode *in
 }
 
 
 /* jffs2_new_inode: allocate a new inode and inocache, add it to the hash,
    fill in the raw_inode while you're at it. */
-struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri)
+struct _inode *jffs2_new_inode (struct _inode *dir_i, int mode, struct jffs2_raw_inode *ri)
 {
-        struct inode *inode;
-        struct super_block *sb = dir_i->i_sb;
-        struct jffs2_sb_info *c;
-        struct jffs2_inode_info *f;
-        int ret;
-
-        D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode));
-
-        c = JFFS2_SB_INFO(sb);
-        
-        inode = new_inode(sb);
-        
-        if (!inode)
-                return ERR_PTR(-ENOMEM);
-
-        f = JFFS2_INODE_INFO(inode);
-        jffs2_init_inode_info(f);
-
-        memset(ri, 0, sizeof(*ri));
-        /* Set OS-specific defaults for new inodes */
-        ri->uid = ri->gid = cpu_to_je16(0);
-        ri->mode =  cpu_to_jemode(mode);
-        ret = jffs2_do_new_inode (c, f, mode, ri);
-        if (ret) {
-                make_bad_inode(inode);
-                iput(inode);
-                return ERR_PTR(ret);
-        }
-        inode->i_nlink = 1;
-        inode->i_ino = je32_to_cpu(ri->ino);
-