[PATCH 2/5] JFFS2: Import from eCos

Sebastian Huber sebastian.huber at embedded-brains.de
Fri Sep 13 15:09:42 UTC 2013


Import of Linux compatibility layer and JFFS2 file system support from
eCos.
---
 cpukit/libfs/src/jffs2/include/asm/atomic.h        |   10 +
 cpukit/libfs/src/jffs2/include/asm/bug.h           |    6 +
 cpukit/libfs/src/jffs2/include/asm/page.h          |   11 +
 cpukit/libfs/src/jffs2/include/cyg/crc/crc.h       |  105 +
 .../libfs/src/jffs2/include/cyg/infra/cyg_type.h   |  559 +++++
 cpukit/libfs/src/jffs2/include/linux/compiler.h    |    7 +
 cpukit/libfs/src/jffs2/include/linux/completion.h  |    7 +
 cpukit/libfs/src/jffs2/include/linux/config.h      |    5 +
 cpukit/libfs/src/jffs2/include/linux/crc32.h       |    8 +
 cpukit/libfs/src/jffs2/include/linux/errno.h       |    1 +
 cpukit/libfs/src/jffs2/include/linux/fs.h          |   13 +
 cpukit/libfs/src/jffs2/include/linux/kernel.h      |   31 +
 cpukit/libfs/src/jffs2/include/linux/list.h        |  139 ++
 .../libfs/src/jffs2/include/linux/mtd/compatmac.h  |    5 +
 cpukit/libfs/src/jffs2/include/linux/mtd/mtd.h     |    5 +
 cpukit/libfs/src/jffs2/include/linux/pagemap.h     |   19 +
 cpukit/libfs/src/jffs2/include/linux/rbtree.h      |   46 +
 cpukit/libfs/src/jffs2/include/linux/rwsem.h       |   20 +
 cpukit/libfs/src/jffs2/include/linux/sched.h       |    7 +
 cpukit/libfs/src/jffs2/include/linux/slab.h        |   14 +
 cpukit/libfs/src/jffs2/include/linux/spinlock.h    |   34 +
 cpukit/libfs/src/jffs2/include/linux/stat.h        |   12 +
 cpukit/libfs/src/jffs2/include/linux/string.h      |    6 +
 cpukit/libfs/src/jffs2/include/linux/timer.h       |   10 +
 cpukit/libfs/src/jffs2/include/linux/types.h       |   19 +
 cpukit/libfs/src/jffs2/include/linux/version.h     |    5 +
 cpukit/libfs/src/jffs2/include/linux/vmalloc.h     |    3 +
 cpukit/libfs/src/jffs2/include/linux/wait.h        |   15 +
 cpukit/libfs/src/jffs2/include/linux/workqueue.h   |   11 +
 cpukit/libfs/src/jffs2/include/linux/zlib.h        |   14 +
 cpukit/libfs/src/jffs2/include/linux/zutil.h       |    6 +
 cpukit/libfs/src/jffs2/src/compat-crc32.c          |  166 ++
 cpukit/libfs/src/jffs2/src/compat-rbtree.c         |  408 ++++
 cpukit/libfs/src/jffs2/src/dir-rtems.c             |  371 ++++
 cpukit/libfs/src/jffs2/src/flashio.c               |  165 ++
 cpukit/libfs/src/jffs2/src/fs-rtems.c              | 2191 ++++++++++++++++++++
 cpukit/libfs/src/jffs2/src/malloc-rtems.c          |  163 ++
 cpukit/libfs/src/jffs2/src/os-rtems.h              |  226 ++
 38 files changed, 4843 insertions(+), 0 deletions(-)
 create mode 100644 cpukit/libfs/src/jffs2/include/asm/atomic.h
 create mode 100644 cpukit/libfs/src/jffs2/include/asm/bug.h
 create mode 100644 cpukit/libfs/src/jffs2/include/asm/page.h
 create mode 100644 cpukit/libfs/src/jffs2/include/cyg/crc/crc.h
 create mode 100644 cpukit/libfs/src/jffs2/include/cyg/infra/cyg_type.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/compiler.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/completion.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/config.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/crc32.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/errno.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/fs.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/kernel.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/list.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/mtd/compatmac.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/mtd/mtd.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/pagemap.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/rbtree.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/rwsem.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/sched.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/slab.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/spinlock.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/stat.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/string.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/timer.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/types.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/version.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/vmalloc.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/wait.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/workqueue.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/zlib.h
 create mode 100644 cpukit/libfs/src/jffs2/include/linux/zutil.h
 create mode 100644 cpukit/libfs/src/jffs2/src/compat-crc32.c
 create mode 100644 cpukit/libfs/src/jffs2/src/compat-rbtree.c
 create mode 100644 cpukit/libfs/src/jffs2/src/dir-rtems.c
 create mode 100644 cpukit/libfs/src/jffs2/src/flashio.c
 create mode 100644 cpukit/libfs/src/jffs2/src/fs-rtems.c
 create mode 100644 cpukit/libfs/src/jffs2/src/malloc-rtems.c
 create mode 100644 cpukit/libfs/src/jffs2/src/os-rtems.h

diff --git a/cpukit/libfs/src/jffs2/include/asm/atomic.h b/cpukit/libfs/src/jffs2/include/asm/atomic.h
new file mode 100644
index 0000000..5cb72ff
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/asm/atomic.h
@@ -0,0 +1,10 @@
+#ifndef __ASM_ATOMIC_H__
+#define __ASM_ATOMIC_H__
+
+#define atomic_t int
+#define atomic_inc(atom) (*atom)++
+#define atomic_dec(atom) (*atom)--
+#define atomic_read(atom) (*atom)
+
+
+#endif /* __ASM_ATOMIC_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/asm/bug.h b/cpukit/libfs/src/jffs2/include/asm/bug.h
new file mode 100644
index 0000000..060eb27
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/asm/bug.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_BUG_H__
+#define __ASM_BUG_H__
+
+#define BUG() do { diag_printf("BUG() at %s %d\n", __FILE__, __LINE__); *(int *)0=0; } while (0)
+
+#endif /* __ASM_BUG_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/asm/page.h b/cpukit/libfs/src/jffs2/include/asm/page.h
new file mode 100644
index 0000000..d77a39a
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/asm/page.h
@@ -0,0 +1,11 @@
+#ifndef __ASM_PAGE_H__
+#define __ASM_PAGE_H__
+
+#include <pkgconf/linux_compat.h>
+
+/* These aren't used by much yet. If that changes, you might want
+   to make them actually correct :) */
+#define PAGE_SIZE  (0x1 << PAGE_SHIFT)
+
+
+#endif /* __ASM_PAGE_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/cyg/crc/crc.h b/cpukit/libfs/src/jffs2/include/cyg/crc/crc.h
new file mode 100644
index 0000000..7b7db10
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/cyg/crc/crc.h
@@ -0,0 +1,105 @@
+//==========================================================================
+//
+//      crc.h
+//
+//      Interface for the CRC algorithms.
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 2002, 2009 Free Software Foundation, Inc.                        
+//
+// eCos is free software; you can redistribute it and/or modify it under    
+// the terms of the GNU General Public License as published by the Free     
+// Software Foundation; either version 2 or (at your option) any later      
+// version.                                                                 
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT      
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+// for more details.                                                        
+//
+// You should have received a copy of the GNU General Public License        
+// along with eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    Andrew Lunn
+// Contributors: Andrew Lunn
+// Date:         2002-08-06
+// Purpose:      
+// Description:  
+//              
+// This code is part of eCos (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#ifndef _SERVICES_CRC_CRC_H_
+#define _SERVICES_CRC_CRC_H_
+
+#include <cyg/infra/cyg_type.h>
+
+#ifndef __externC
+# ifdef __cplusplus
+#  define __externC extern "C"
+# else
+#  define __externC extern
+# endif
+#endif
+
+// Compute a CRC, using the POSIX 1003 definition
+
+__externC cyg_uint32 
+cyg_posix_crc32(unsigned char *s, int len);
+
+// Gary S. Brown's 32 bit CRC
+
+__externC cyg_uint32 
+cyg_crc32(unsigned char *s, int len);
+
+// Gary S. Brown's 32 bit CRC, but accumulate the result from a
+// previous CRC calculation
+
+__externC cyg_uint32 
+cyg_crc32_accumulate(cyg_uint32 crc, unsigned char *s, int len);
+
+// Ethernet FCS Algorithm
+
+__externC cyg_uint32 
+cyg_ether_crc32(unsigned char *s, int len);
+
+// Ethernet FCS algorithm, but accumulate the result from a previous
+// CRC calculation.
+
+__externC cyg_uint32 
+cyg_ether_crc32_accumulate(cyg_uint32 crc, unsigned char *s, int len);
+
+// 16 bit CRC with polynomial x^16+x^12+x^5+1
+
+__externC cyg_uint16
+cyg_crc16(unsigned char *s, int len);
+
+__externC cyg_uint16
+cyg_crc16_accumulate(cyg_uint16 crc, unsigned char *s, int len);
+
+#endif // _SERVICES_CRC_CRC_H_
+
+
+
diff --git a/cpukit/libfs/src/jffs2/include/cyg/infra/cyg_type.h b/cpukit/libfs/src/jffs2/include/cyg/infra/cyg_type.h
new file mode 100644
index 0000000..5047493
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/cyg/infra/cyg_type.h
@@ -0,0 +1,559 @@
+#ifndef CYGONCE_INFRA_CYG_TYPE_H
+#define CYGONCE_INFRA_CYG_TYPE_H
+
+//==========================================================================
+//
+//      cyg_type.h
+//
+//      Standard types, and some useful coding macros.
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2009 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under    
+// the terms of the GNU General Public License as published by the Free     
+// Software Foundation; either version 2 or (at your option) any later      
+// version.                                                                 
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT      
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+// for more details.                                                        
+//
+// You should have received a copy of the GNU General Public License        
+// along with eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):   nickg from an original by hmt
+// Contributors:  nickg
+// Date:        1997-09-08
+// Purpose:     share unambiguously sized types.
+// Description: we typedef [cyg_][u]int8,16,32 &c for general use.
+// Usage:       #include "cyg/infra/cyg_type.h"
+//              ...
+//              cyg_int32 my_32bit_integer;
+//              
+//####DESCRIPTIONEND####
+//
+
+#include <stddef.h>           // Definition of NULL from the compiler
+
+// -------------------------------------------------------------------------
+// Some useful macros. These are defined here by default.
+
+// __externC is used in mixed C/C++ headers to force C linkage on an external
+// definition. It avoids having to put all sorts of ifdefs in.
+
+#ifdef __cplusplus
+# define __externC extern "C"
+#else
+# define __externC extern
+#endif
+// Also define externC for now - but it is deprecated
+#define externC __externC
+
+// Compiler version.
+#ifdef __GNUC__
+# if defined(__GNU_PATCHLEVEL__)
+#  define __GNUC_VERSION__ (__GNUC__ * 10000 \
+                             + __GNUC_MINOR__ * 100 \
+                             + __GNUC_PATCHLEVEL__)
+# else
+#  define __GNUC_VERSION__ (__GNUC__ * 10000 \
+                             + __GNUC_MINOR__ * 100)
+# endif
+#endif
+
+// -------------------------------------------------------------------------
+// The header <basetype.h> defines the base types used here. It is
+// supplied either by the target architecture HAL, or by the host
+// porting kit. They are all defined as macros, and only those that
+// make choices other than the defaults given below need be defined.
+
+#define CYG_LSBFIRST 1234
+#define CYG_MSBFIRST 4321
+
+#include <cyg/hal/basetype.h>
+
+#if (CYG_BYTEORDER != CYG_LSBFIRST) && (CYG_BYTEORDER != CYG_MSBFIRST)
+# error You must define CYG_BYTEORDER to equal CYG_LSBFIRST or CYG_MSBFIRST
+#endif
+
+#ifndef CYG_DOUBLE_BYTEORDER
+#define CYG_DOUBLE_BYTEORDER CYG_BYTEORDER
+#endif
+
+#ifndef cyg_halint8
+# define cyg_halint8 char
+#endif
+#ifndef cyg_halint16
+# define cyg_halint16 short
+#endif
+#ifndef cyg_halint32
+# define cyg_halint32 int
+#endif
+#ifndef cyg_halint64
+# define cyg_halint64 long long
+#endif
+
+#ifndef cyg_halcount8
+# define cyg_halcount8 int
+#endif
+#ifndef cyg_halcount16
+# define cyg_halcount16 int
+#endif
+#ifndef cyg_halcount32
+# define cyg_halcount32 int
+#endif
+#ifndef cyg_halcount64
+# define cyg_halcount64 long long
+#endif
+
+#ifndef cyg_haladdress
+# define cyg_haladdress cyg_uint32
+#endif
+#ifndef cyg_haladdrword
+# define cyg_haladdrword cyg_uint32
+#endif
+
+#ifndef cyg_halbool
+# define cyg_halbool int
+#endif
+
+#ifndef cyg_halatomic
+# define cyg_halatomic cyg_halint8
+#endif
+
+// -------------------------------------------------------------------------
+// Provide a default architecture alignment
+// This may be overridden in basetype.h if necessary.
+// These should be straightforward numbers to allow use in assembly.
+
+#ifndef CYGARC_ALIGNMENT
+# define CYGARC_ALIGNMENT 8
+#endif
+// And corresponding power of two alignment
+#ifndef CYGARC_P2ALIGNMENT
+# define CYGARC_P2ALIGNMENT 3
+#endif
+#if (CYGARC_ALIGNMENT) != (1 << CYGARC_P2ALIGNMENT)
+# error "Inconsistent CYGARC_ALIGNMENT and CYGARC_P2ALIGNMENT values"
+#endif
+
+// -------------------------------------------------------------------------
+// The obvious few that compilers may define for you.
+// But in case they don't:
+
+#ifndef NULL
+# define NULL 0
+#endif
+
+#ifndef __cplusplus
+
+typedef cyg_halbool bool;
+
+# ifndef false
+#  define false 0
+# endif
+
+# ifndef true
+#  define true (!false)
+# endif
+
+#endif
+
+// -------------------------------------------------------------------------
+// Allow creation of procedure-like macros that are a single statement,
+// and must be followed by a semi-colon
+
+#define CYG_MACRO_START do {
+#define CYG_MACRO_END   } while (0)
+
+#define CYG_EMPTY_STATEMENT CYG_MACRO_START CYG_MACRO_END
+
+#define CYG_UNUSED_PARAM( _type_, _name_ ) CYG_MACRO_START      \
+  _type_ __tmp1 = (_name_);                                     \
+  _type_ __tmp2 = __tmp1;                                       \
+  __tmp1 = __tmp2;                                              \
+CYG_MACRO_END
+
+
+//----------------------------------------------------------------------------
+// The unused attribute stops the compiler warning about the variable
+// not being used.
+// The used attribute prevents the compiler from optimizing it away.
+
+#define CYG_REFERENCE_OBJECT(__object__)                            \
+    CYG_MACRO_START                                                 \
+    static const void*  __cygvar_discard_me__                       \
+    __attribute__ ((unused, used)) = (const void*)&(__object__);    \
+    CYG_MACRO_END
+
+// -------------------------------------------------------------------------
+// Define basic types for using integers in memory and structures;
+// depends on compiler defaults and CPU type.
+
+typedef unsigned cyg_halint8    cyg_uint8  ;
+typedef   signed cyg_halint8    cyg_int8   ;
+
+typedef unsigned cyg_halint16   cyg_uint16 ;
+typedef   signed cyg_halint16   cyg_int16  ;
+
+typedef unsigned cyg_halint32   cyg_uint32 ;
+typedef   signed cyg_halint32   cyg_int32  ;
+
+typedef unsigned cyg_halint64   cyg_uint64 ;
+typedef   signed cyg_halint64   cyg_int64  ;
+
+typedef  cyg_halbool            cyg_bool   ;
+
+// -------------------------------------------------------------------------
+// Define types for using integers in registers for looping and the like;
+// depends on CPU type, choose what it is most comfortable with, with at
+// least the range required.
+
+typedef unsigned cyg_halcount8  cyg_ucount8  ;
+typedef   signed cyg_halcount8  cyg_count8   ;
+
+typedef unsigned cyg_halcount16 cyg_ucount16 ;
+typedef   signed cyg_halcount16 cyg_count16  ;
+
+typedef unsigned cyg_halcount32 cyg_ucount32 ;
+typedef   signed cyg_halcount32 cyg_count32  ;
+
+typedef unsigned cyg_halcount64 cyg_ucount64 ;
+typedef   signed cyg_halcount64 cyg_count64  ;
+
+// -------------------------------------------------------------------------
+// Define a type to be used for atomic accesses. This type is guaranteed
+// to be read or written in a single uninterruptible operation. This type
+// is at least a single byte.
+
+typedef volatile unsigned cyg_halatomic  cyg_atomic;
+typedef volatile unsigned cyg_halatomic  CYG_ATOMIC;
+
+// -------------------------------------------------------------------------
+// Define types for access plain, on-the-metal memory or devices.
+
+typedef cyg_uint32  CYG_WORD;
+typedef cyg_uint8   CYG_BYTE;
+typedef cyg_uint16  CYG_WORD16;
+typedef cyg_uint32  CYG_WORD32;
+typedef cyg_uint64  CYG_WORD64;
+
+typedef cyg_haladdress  CYG_ADDRESS;
+typedef cyg_haladdrword CYG_ADDRWORD;
+
+// -------------------------------------------------------------------------
+// Number of elements in a (statically allocated) array.
+
+#define CYG_NELEM(a) (sizeof(a) / sizeof((a)[0]))
+
+// -------------------------------------------------------------------------
+// Constructor ordering macros.  These are added as annotations to all
+// static objects to order the constuctors appropriately.
+
+#if defined(__cplusplus) && defined(__GNUC__) && \
+    !defined(CYGBLD_ATTRIB_INIT_PRI)
+# define CYGBLD_ATTRIB_INIT_PRI( _pri_ ) __attribute__((init_priority(_pri_)))
+#elif !defined(CYGBLD_ATTRIB_INIT_PRI)
+// FIXME: should maybe just bomb out if this is attempted anywhere else?
+// Not sure
+# define CYGBLD_ATTRIB_INIT_PRI( _pri_ )
+#endif
+    
+// The following will be removed eventually as it doesn't allow the use of
+// e.g. pri+5 format
+#define CYG_INIT_PRIORITY( _pri_ ) CYGBLD_ATTRIB_INIT_PRI( CYG_INIT_##_pri_ )
+
+#define CYGBLD_ATTRIB_INIT_BEFORE( _pri_ ) CYGBLD_ATTRIB_INIT_PRI(_pri_-100)
+#define CYGBLD_ATTRIB_INIT_AFTER( _pri_ )  CYGBLD_ATTRIB_INIT_PRI(_pri_+100)
+
+#if defined(__GNUC__) && !defined(__cplusplus) && (__GNUC_VERSION__ >= 40300)
+// Equivalents of the above for C functions, available from gcc 4.3 onwards.
+# define CYGBLD_ATTRIB_C_INIT_PRI( _pri_)       __attribute__((constructor (_pri_)))
+# define CYGBLD_ATTRIB_C_INIT_BEFORE( _pri_ )   __attribute__((constructor (_pri_-100)))
+# define CYGBLD_ATTRIB_C_INIT_AFTER( _pri_ )    __attribute__((constructor (_pri_+100)))
+#endif
+
+// Start with initializing everything inside the cpu and the main memory.
+#define CYG_INIT_HAL                    10000
+#define CYG_INIT_SCHEDULER              11000
+#define CYG_INIT_IDLE_THREAD            11100
+#define CYG_INIT_INTERRUPTS             12000
+#define CYG_INIT_CLOCK                  14000
+#define CYG_INIT_THREADS                16000
+#define CYG_INIT_KERNEL                 19000
+#define CYG_INIT_MEMALLOC               20000
+// Now move on to I/O subsystems and device drivers. These can make use of
+// kernel and HAL functionality, and can dynamically allocate memory if
+// absolutely needed. For now they can also assume that diag_printf()
+// functionality is available, but that may change in future.
+//
+// Primary buses are ones very closely tied to the processor, e.g. PCI.
+#define CYG_INIT_BUS_PRIMARY            30000
+// Not yet: on some targets cyg_pci_init() has to be called very early
+// on for HAL diagnostics to work.
+// #define CYG_INIT_BUS_PCI                CYG_INIT_BUS_PRIMARY
+//
+// Secondary buses may hang off primary buses, e.g. USB host.
+#define CYG_INIT_BUS_SECONDARY          31000
+// Tertiary buses are everything else.
+#define CYG_INIT_BUS_TERTIARY           32000
+#define CYG_INIT_BUS_I2C                CYG_INIT_BUS_TERTIARY
+#define CYG_INIT_BUS_SPI                CYG_INIT_BUS_TERTIARY
+//
+// In future HAL diag initialization may happen at this point.
+//
+// Watchdogs and wallclocks often hang off a tertiary bus but
+// have no dependencies
+#define CYG_INIT_DEV_WATCHDOG           35000
+#define CYG_INIT_DEV_WALLCLOCK          36000
+// A primary block configuration can be initialized with no need
+// for per-unit configuration information.
+#define CYG_INIT_DEV_BLOCK_PRIMARY      37000
+#define CYG_INIT_DEV_FLASH              CYG_INIT_DEV_BLOCK_PRIMARY
+// Per-unit configuration data extracted from primary storage.
+// NOTE: for future use, not implemented yet.
+#define CYG_INIT_CONFIG                 38000
+// Secondary block devices may use per-unit configuration data
+// for e.g. interpreting partition layout. Few devices are expected
+// to fall into this category. Note that these devices, as well as
+// some char devices, may not actually be usable until interrupts
+// are enabled.
+#define CYG_INIT_DEV_BLOCK_SECONDARY    40000
+// Char devices are everything else: serial, ethernet, CAN, ...
+#define CYG_INIT_DEV_CHAR               41000
+// For backwards compatibility. Subject to change in future so
+// a CYG_INIT_DEV_ priority should be used instead.
+#define CYG_INIT_DRIVERS                48000
+// CYG_INIT_IO and CYG_INIT_IO_FS are poorly defined at present,
+// and may get reorganized in future.
+#define CYG_INIT_IO                     49000
+#define CYG_INIT_IO_FS                  50000
+// The I/O subsystems and device drivers have been initialized.
+#define CYG_INIT_LIBC                   56000
+#define CYG_INIT_COMPAT                 58000
+#define CYG_INIT_APPLICATION            60000
+#define CYG_INIT_PREDEFAULT             65534
+#define CYG_INIT_DEFAULT                65535
+
+// -------------------------------------------------------------------------
+// Label name macros. Some toolsets generate labels with initial
+// underscores and others don't. CYG_LABEL_NAME should be used on
+// labels in C/C++ code that are defined in assembly code or linker
+// scripts. CYG_LABEL_DEFN is for use in assembly code and linker
+// scripts where we need to manufacture labels that can be used from
+// C/C++.
+// These are default implementations that should work for most targets.
+// They may be overridden in basetype.h if necessary.
+
+#ifndef CYG_LABEL_NAME
+
+#define CYG_LABEL_NAME(_name_) _name_
+
+#endif
+
+#ifndef CYG_LABEL_DEFN
+
+#define CYG_LABEL_DEFN(_label) _label
+
+#endif
+
+// -------------------------------------------------------------------------
+// COMPILER-SPECIFIC STUFF
+
+#ifdef __GNUC__
+// Force a 'C' routine to be called like a 'C++' contructor
+# if !defined(CYGBLD_ATTRIB_CONSTRUCTOR)
+#  define CYGBLD_ATTRIB_CONSTRUCTOR __attribute__((constructor))
+# endif
+
+// Define a compiler-specific rune for saying a function doesn't return
+# if !defined(CYGBLD_ATTRIB_NORET)
+#  define CYGBLD_ATTRIB_NORET __attribute__((noreturn))
+# endif
+
+// How to define weak symbols - this is only relevant for ELF and a.out,
+// but that won't be a problem for eCos
+# if !defined(CYGBLD_ATTRIB_WEAK)
+#  define CYGBLD_ATTRIB_WEAK __attribute__ ((weak))
+# endif
+
+// How to define alias to symbols. Just pass in the symbol itself, not
+// the string name of the symbol
+# if !defined(CYGBLD_ATTRIB_ALIAS)
+#  define CYGBLD_ATTRIB_ALIAS(__symbol__) \
+        __attribute__ ((alias (#__symbol__)))
+# endif
+
+// This effectively does the reverse of the previous macro. It defines
+// a name that the attributed variable or function will actually have
+// in assembler.
+# if !defined(CYGBLD_ATTRIB_ASM_ALIAS)
+#  define __Str(x) #x
+#  define __Xstr(x) __Str(x)
+#  define CYGBLD_ATTRIB_ASM_ALIAS(__symbol__) \
+             __asm__ ( __Xstr( CYG_LABEL_DEFN( __symbol__ ) ) )
+# endif
+
+// Shows that a function returns the same value when given the same args, but
+// note this can't be used if there are pointer args
+# if !defined(CYGBLD_ATTRIB_CONST)
+#  define CYGBLD_ATTRIB_CONST __attribute__((const))
+#endif
+
+// Assign a defined variable to a specific section
+# if !defined(CYGBLD_ATTRIB_SECTION)
+#  define CYGBLD_ATTRIB_SECTION(__sect__) __attribute__((section (__sect__)))
+# endif
+
+// Give a type or object explicit minimum alignment
+# if !defined(CYGBLD_ATTRIB_ALIGN)
+#  define CYGBLD_ATTRIB_ALIGN(__align__) __attribute__((aligned(__align__)))
+# endif
+
+# if !defined(CYGBLD_ATTRIB_ALIGN_MAX)
+#  define CYGBLD_ATTRIB_ALIGN_MAX __attribute__((aligned))
+# endif
+
+# if !defined(CYGBLD_ATTRIB_ALIGNOFTYPE)
+#  define CYGBLD_ATTRIB_ALIGNOFTYPE( _type_ ) \
+     __attribute__((aligned(__alignof__( _type_ ))))
+# endif
+
+// Teach compiler how to check format of printf-like functions
+# define CYGBLD_ATTRIB_PRINTF_FORMAT(__format__, __args__) \
+        __attribute__((format (printf, __format__, __args__)))
+
+// Teach compiler how to check format of scanf-like functions
+# define CYGBLD_ATTRIB_SCANF_FORMAT(__format__, __args__) \
+        __attribute__((format (scanf, __format__, __args__)))
+
+// Teach compiler how to check format of strftime-like functions
+# define CYGBLD_ATTRIB_STRFTIME_FORMAT(__format__, __args__) \
+        __attribute__((format (strftime, __format__, __args__)))
+
+// Tell compiler not to warn us about an unused variable -- generally
+// because it will be used when sources are build under certain
+// circumstances (e.g. with debugging or asserts enabled.
+# define CYGBLD_ATTRIB_UNUSED  __attribute__((unused))
+
+// Tell the compiler not to throw away a variable or function. Only known
+// available on 3.3.2 or above. Old version's didn't throw them away,
+// but using the unused attribute should stop warnings.
+# if !defined(CYGBLD_ATTRIB_USED)
+#  if __GNUC_VERSION__ >= 30302
+#   define CYGBLD_ATTRIB_USED __attribute__((used))
+#  else
+#   define CYGBLD_ATTRIB_USED __attribute__((unused))
+#  endif
+# endif 
+
+// Enforce inlining of a C function. GCC does not inline any C
+// function when not optimizing, unless you specify "always_inline" attribute.
+// Other attributes suppress generation of standalone function.
+# if !defined(CYGBLD_FORCE_INLINE)
+#  define CYGBLD_FORCE_INLINE __externC inline __attribute((gnu_inline)) __attribute((always_inline))
+# endif
+
+// Suppress function inlining
+#define CYGBLD_ATTRIB_NO_INLINE __attribute__((noinline))
+
+#else // non-GNU
+
+# define CYGBLD_ATTRIB_UNUSED  /* nothing */
+
+# define CYGBLD_ATTRIB_CONSTRUCTOR
+
+# define CYGBLD_ATTRIB_NORET
+    // This intentionally gives an error only if we actually try to
+    // use it.  #error would give an error if we simply can't.
+// FIXME: Had to disarm the bomb - the CYGBLD_ATTRIB_WEAK macro is now
+//        (indirectly) used in host tools.
+# define CYGBLD_ATTRIB_WEAK /* !!!-- Attribute weak not defined --!!! */
+
+# define CYGBLD_ATTRIB_ALIAS(__x__) !!!-- Attribute alias not defined --!!!
+
+# define CYGBLD_ATTRIB_ASM_ALIAS(__symbol__) !!!-- Asm alias not defined --!!!
+
+# define CYGBLD_ATTRIB_CONST
+
+# define CYGBLD_ATTRIB_ALIGN(__align__) !!!-- Alignment alias not defined --!!!
+
+# define CYGBLD_ATTRIB_ALIGN_MAX !!!-- Alignment alias not defined --!!!
+
+# define CYGBLD_ATTRIB_ALIGNOFTYPE( _type_ ) !!!-- Alignment alias not defined --!!!
+
+# define CYGBLD_ATTRIB_PRINTF_FORMAT(__format__, __args__)
+
+# define CYGBLD_ATTRIB_SCANF_FORMAT(__format__, __args__)
+
+# define CYGBLD_ATTRIB_STRFTIME_FORMAT(__format__, __args__)
+
+#define CYGBLD_FORCE_INLINE
+
+#define CYGBLD_ATTRIB_NO_INLINE
+
+#endif
+
+// How to define weak aliases. Currently this is simply a mixture of the
+// above
+
+# define CYGBLD_ATTRIB_WEAK_ALIAS(__symbol__) \
+        CYGBLD_ATTRIB_WEAK CYGBLD_ATTRIB_ALIAS(__symbol__)
+
+#ifdef __cplusplus
+# define __THROW throw()
+#else
+# define __THROW
+#endif
+
+// -------------------------------------------------------------------------
+// Variable annotations
+// These annotations may be added to various static variables in the
+// HAL and kernel to indicate which component they belong to. These
+// are used by some targets to optimize memory placement of these
+// variables.
+
+#ifndef CYGBLD_ANNOTATE_VARIABLE_HAL
+#define CYGBLD_ANNOTATE_VARIABLE_HAL
+#endif
+#ifndef CYGBLD_ANNOTATE_VARIABLE_SCHED
+#define CYGBLD_ANNOTATE_VARIABLE_SCHED
+#endif
+#ifndef CYGBLD_ANNOTATE_VARIABLE_CLOCK
+#define CYGBLD_ANNOTATE_VARIABLE_CLOCK
+#endif
+#ifndef CYGBLD_ANNOTATE_VARIABLE_INTR
+#define CYGBLD_ANNOTATE_VARIABLE_INTR
+#endif
+
+// -------------------------------------------------------------------------
+// Various "flavours" of memory regions that can be described by the 
+// Memory Layout Tool (MLT).
+
+#define CYGMEM_REGION_ATTR_R  0x01  // Region can be read
+#define CYGMEM_REGION_ATTR_W  0x02  // Region can be written
+
+// -------------------------------------------------------------------------
+#endif // CYGONCE_INFRA_CYG_TYPE_H multiple inclusion protection
+// EOF cyg_type.h
diff --git a/cpukit/libfs/src/jffs2/include/linux/compiler.h b/cpukit/libfs/src/jffs2/include/linux/compiler.h
new file mode 100644
index 0000000..fb25365
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/compiler.h
@@ -0,0 +1,7 @@
+#ifndef __LINUX_COMPILER_H__
+#define __LINUX_COMPILER_H__
+
+#define likely(x) (x)
+#define unlikely(x) (x)
+
+#endif /* __LINUX_COMPILER_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/completion.h b/cpukit/libfs/src/jffs2/include/linux/completion.h
new file mode 100644
index 0000000..f131af8
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/completion.h
@@ -0,0 +1,7 @@
+#ifndef __LINUX_COMPLETION_H__
+#define __LINUX_COMPLETION_H__
+
+struct completion { } ;
+
+#endif /* __LINUX_COMPLETION_H__ */
+
diff --git a/cpukit/libfs/src/jffs2/include/linux/config.h b/cpukit/libfs/src/jffs2/include/linux/config.h
new file mode 100644
index 0000000..986e10b
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/config.h
@@ -0,0 +1,5 @@
+#ifndef __LINUX_CONFIG_H__
+#define __LINUX_CONFIG_H__
+
+
+#endif /* __LINUX_CONFIG_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/crc32.h b/cpukit/libfs/src/jffs2/include/linux/crc32.h
new file mode 100644
index 0000000..8d19a1e
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/crc32.h
@@ -0,0 +1,8 @@
+#ifndef CRC32_H
+#define CRC32_H
+
+#include <cyg/crc/crc.h>
+
+#define crc32(val, s, len) cyg_crc32_accumulate(val, (unsigned char *)s, len)
+
+#endif
diff --git a/cpukit/libfs/src/jffs2/include/linux/errno.h b/cpukit/libfs/src/jffs2/include/linux/errno.h
new file mode 100644
index 0000000..339f4fc
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/errno.h
@@ -0,0 +1 @@
+#include <errno.h>
diff --git a/cpukit/libfs/src/jffs2/include/linux/fs.h b/cpukit/libfs/src/jffs2/include/linux/fs.h
new file mode 100644
index 0000000..c2f173a
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/fs.h
@@ -0,0 +1,13 @@
+#ifndef __LINUX_FS_H__
+#define __LINUX_FS_H__
+
+#include <linux/stat.h>
+/*
+ * File types
+ */
+#define DT_UNKNOWN	0
+#define DT_DIR		4
+#define DT_REG		8
+
+
+#endif /* __LINUX_FS_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/kernel.h b/cpukit/libfs/src/jffs2/include/linux/kernel.h
new file mode 100644
index 0000000..e5d8d90
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/kernel.h
@@ -0,0 +1,31 @@
+#ifndef __LINUX_KERNEL_H__
+#define __LINUX_KERNEL_H__
+
+#define jiffies ((unsigned long)cyg_current_time())
+
+#define ERR_PTR(err) ((void*)(err))
+#define PTR_ERR(err) ((unsigned long)(err))
+#define IS_ERR(err) ((unsigned long)err > (unsigned long)-1000L)
+
+#define CURRENT_TIME cyg_timestamp()
+
+#define	KERN_EMERG              "<0>" // system is unusable
+#define	KERN_ALERT              "<1>" // action must be taken immediately
+#define	KERN_CRIT               "<2>" // critical conditions
+#define	KERN_ERR                "<3>" // error conditions
+#define	KERN_WARNING            "<4>" // warning conditions
+#define	KERN_NOTICE             "<5>" // normal but significant condition
+#define	KERN_INFO               "<6>" // informational
+#define	KERN_DEBUG              "<7>" // debug-level messages
+#define printk diag_printf
+
+#define min(x,y) (x<y?x:y)
+#define max(x,y) (x<y?y:x)
+#define min_t(t, x,y) ((t)x<(t)y?(t)x:(t)y)
+
+
+#endif /* __LINUX_KERNEL_H__ */
+
+
+
+
diff --git a/cpukit/libfs/src/jffs2/include/linux/list.h b/cpukit/libfs/src/jffs2/include/linux/list.h
new file mode 100644
index 0000000..e9ebab1
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/list.h
@@ -0,0 +1,139 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ *
+ * Created by Jonathan Larmour <jlarmour at redhat.com>
+ * 
+ *===========================================================================
+ * ####ECOSGPLCOPYRIGHTBEGIN####                                            
+ * -------------------------------------------                              
+ * This file is part of eCos, the Embedded Configurable Operating System.   
+ * Copyright (C) 2002, 2003 Free Software Foundation, Inc.                  
+ *
+ * eCos is free software; you can redistribute it and/or modify it under    
+ * the terms of the GNU General Public License as published by the Free     
+ * Software Foundation; either version 2 or (at your option) any later      
+ * version.                                                                 
+ *
+ * eCos is distributed in the hope that it will be useful, but WITHOUT      
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+ * for more details.                                                        
+ *
+ * You should have received a copy of the GNU General Public License        
+ * along with eCos; if not, write to the Free Software Foundation, Inc.,    
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+ *
+ * As a special exception, if other files instantiate templates or use      
+ * macros or inline functions from this file, or you compile this file      
+ * and link it with other works to produce a work based on this file,       
+ * this file does not by itself cause the resulting work to be covered by   
+ * the GNU General Public License. However the source code for this file    
+ * must still be made available in accordance with section (3) of the GNU   
+ * General Public License v2.                                               
+ *
+ * This exception does not invalidate any other reasons why a work based    
+ * on this file might be covered by the GNU General Public License.         
+ * -------------------------------------------                              
+ * ####ECOSGPLCOPYRIGHTEND####                                              
+ *===========================================================================
+ *
+ */
+
+#ifndef CYGONCE_FS_JFFS2_LIST_H
+#define CYGONCE_FS_JFFS2_LIST_H
+
+
+/* -----------------------------------------------------------------------*/
+
+/* Doubly linked list implementation to replace the GPL'd one used in
+   the Linux kernel. */
+
+#include <stddef.h>
+#include <cyg/infra/cyg_type.h>
+
+/* TYPES */
+
+struct list_head {
+    struct list_head *next;
+    struct list_head *prev;
+};
+
+/* MACROS */
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+        struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD( _list_ )              \
+CYG_MACRO_START                               \
+(_list_)->next = (_list_)->prev = (_list_);   \
+CYG_MACRO_END
+
+/* FUNCTIONS */
+
+/* Insert an entry _after_ the specified entry */
+static __inline__ void
+list_add( struct list_head *newent, struct list_head *afterthisent )
+{
+    struct list_head *next = afterthisent->next;
+    newent->next = next;
+    newent->prev = afterthisent;
+    afterthisent->next = newent;
+    next->prev = newent;
+} /* list_add() */
+
+/* Insert an entry _before_ the specified entry */
+static __inline__ void
+list_add_tail( struct list_head *newent, struct list_head *beforethisent )
+{
+    struct list_head *prev = beforethisent->prev;
+    newent->prev = prev;
+    newent->next = beforethisent;
+    beforethisent->prev = newent;
+    prev->next = newent;
+} /* list_add_tail() */
+
+/* Delete the specified entry */
+static __inline__ void
+list_del( struct list_head *ent )
+{
+    ent->prev->next = ent->next;
+    ent->next->prev = ent->prev;
+} /* list_del() */
+
+/* Is this list empty? */
+static __inline__ int
+list_empty( struct list_head *list )
+{
+    return ( list->next == list );
+} /* list_empty() */
+
+/* list_entry - Assuming you have a struct of type _type_ that contains a
+   list which has the name _member_ in that struct type, then given the
+   address of that list in the struct, _list_, this returns the address
+   of the container structure */
+
+#define list_entry( _list_, _type_, _member_ ) \
+    ((_type_ *)((char *)(_list_)-(char *)(offsetof(_type_,_member_))))
+
+/* list_for_each - using _ent_, iterate through list _list_ */
+
+#define list_for_each( _ent_, _list_ )   \
+    for ( (_ent_) = (_list_)->next;      \
+    (_ent_) != (_list_);                 \
+    (_ent_) = (_ent_)->next )
+
+/*
+ * list_for_each_entry - this function can be use to iterate over all
+ * items in a list* _list_ with it's head at _head_ and link _item_
+ */
+#define list_for_each_entry(_list_, _head_, _item_)                     \
+for ((_list_) = list_entry((_head_)->next, typeof(*_list_), _item_); \
+     &((_list_)->_item_) != (_head_);                                 \
+     (_list_) = list_entry((_list_)->_item_.next, typeof(*_list_), _item_))
+
+/* -----------------------------------------------------------------------*/
+#endif /* #ifndef CYGONCE_FS_JFFS2_LIST_H */
+/* EOF list.h */
diff --git a/cpukit/libfs/src/jffs2/include/linux/mtd/compatmac.h b/cpukit/libfs/src/jffs2/include/linux/mtd/compatmac.h
new file mode 100644
index 0000000..cee3749
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/mtd/compatmac.h
@@ -0,0 +1,5 @@
+#ifndef __LINUX_MTD_COMPATMAC_H__
+#define __LINUX_MTD_COMPATMAC_H__
+
+
+#endif /* __LINUX_MTD_COMPATMAC_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/mtd/mtd.h b/cpukit/libfs/src/jffs2/include/linux/mtd/mtd.h
new file mode 100644
index 0000000..817d31c
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/mtd/mtd.h
@@ -0,0 +1,5 @@
+#ifndef __LINUX_MTD_MTD_H__
+#define __LINUX_MTD_MTD_H__
+
+
+#endif /* __LINUX_MTD_MTD_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/pagemap.h b/cpukit/libfs/src/jffs2/include/linux/pagemap.h
new file mode 100644
index 0000000..fccf9c4
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/pagemap.h
@@ -0,0 +1,19 @@
+#ifndef __LINUX_PAGEMAP_H__
+#define __LINUX_PAGEMAP_H__
+
+#include <asm/bug.h>
+#include <asm/page.h>
+
+#define PAGE_CACHE_SHIFT        PAGE_SHIFT
+#define PAGE_CACHE_SIZE         PAGE_SIZE
+
+#define PageLocked(pg) 1
+#define Page_Uptodate(pg) 0
+#define UnlockPage(pg) 
+#define PAGE_BUG(pg) BUG()
+#define ClearPageUptodate(pg)
+#define SetPageError(pg)
+#define ClearPageError(pg)
+#define SetPageUptodate(pg)
+
+#endif /* __LINUX_PAGEMAP_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/rbtree.h b/cpukit/libfs/src/jffs2/include/linux/rbtree.h
new file mode 100644
index 0000000..fef5f71
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/rbtree.h
@@ -0,0 +1,46 @@
+#ifndef	_LINUX_RBTREE_H
+#define	_LINUX_RBTREE_H
+
+
+struct rb_node {
+	struct rb_node *rb_left;	/* left element */
+	struct rb_node *rb_right;	/* right element */
+	struct rb_node *rb_parent;	/* parent element */
+	int rb_color;			/* node color */
+};
+
+struct rb_root {
+	struct rb_node *rb_node; /* root of the tree */
+};
+#define NULL ((void *)0)
+#define RB_ROOT ((struct rb_root){NULL})
+#define rb_entry(p, container, field)		\
+	((container *) ((char *)p - ((char *)&(((container *)0)->field))))
+
+#define RB_BLACK	0
+#define RB_RED		1
+
+
+extern void rb_insert_color(struct rb_node *, struct rb_root *);
+extern void rb_erase(struct rb_node *, struct rb_root *);
+
+/* Find logical next and previous nodes in a tree */
+extern struct rb_node *rb_next(struct rb_node *);
+extern struct rb_node *rb_prev(struct rb_node *);
+extern struct rb_node *rb_first(struct rb_root *);
+
+/* Fast replacement of a single node without remove/rebalance/add/rebalance */
+extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, 
+			    struct rb_root *root);
+
+static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
+				struct rb_node ** rb_link)
+{
+	node->rb_parent = parent;
+	node->rb_color = RB_RED;
+	node->rb_left = node->rb_right = NULL;
+
+	*rb_link = node;
+}
+
+#endif	/* _LINUX_RBTREE_H */
diff --git a/cpukit/libfs/src/jffs2/include/linux/rwsem.h b/cpukit/libfs/src/jffs2/include/linux/rwsem.h
new file mode 100644
index 0000000..d648a15
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/rwsem.h
@@ -0,0 +1,20 @@
+#ifndef __LINUX_RWSEM_H__
+#define __LINUX_RWSEM_H__
+
+// eCos does not have the concept of a read/write semaphore. So just
+// map them onto normal semaphores and hope we don't deadlock
+// somewhere.
+
+#include <asm/semaphore.h>
+
+struct rw_semaphore;
+
+#define down_read(sem) cyg_drv_mutex_lock((cyg_drv_mutex_t *)sem)
+#define down_read_trylock(sem) cyg_drv_mutex_trylock((cyg_drv_mutex_t *)sem)
+#define down_write(sem) cyg_drv_mutex_lock((cyg_drv_mutex_t *)sem)
+#define down_write_trylock(sem) cyg_drv_mutex_trylock((cyg_drv_mutex_t *)sem)
+#define up_read(sem) cyg_drv_mutex_unlock((cyg_drv_mutex_t *)sem)
+#define up_write(sem) cyg_drv_mutex_unlock((cyg_drv_mutex_t *)sem)
+#define downgrade_write(sem) 
+
+#endif // __LINUX_RWSEM_H__ 
diff --git a/cpukit/libfs/src/jffs2/include/linux/sched.h b/cpukit/libfs/src/jffs2/include/linux/sched.h
new file mode 100644
index 0000000..14a7359
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/sched.h
@@ -0,0 +1,7 @@
+#ifndef __LINUX_SCHED_H__
+#define __LINUX_SCHED_H__
+
+#define cond_resched() do { } while(0)
+#define signal_pending(x) (0)
+
+#endif /* __LINUX_SCHED_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/slab.h b/cpukit/libfs/src/jffs2/include/linux/slab.h
new file mode 100644
index 0000000..fff3949
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/slab.h
@@ -0,0 +1,14 @@
+#ifndef __LINUX_SLAB_H__
+#define __LINUX_SLAB_H__
+
+#include <stdlib.h>
+
+#include <asm/page.h> /* Don't ask. Linux headers are a mess. */
+
+#define kmalloc(x, y) malloc(x)
+#define kfree(x) free(x)
+#define vmalloc(x) malloc(x)
+#define vfree(x) free(x)
+
+#endif /* __LINUX_SLAB_H__ */
+
diff --git a/cpukit/libfs/src/jffs2/include/linux/spinlock.h b/cpukit/libfs/src/jffs2/include/linux/spinlock.h
new file mode 100644
index 0000000..22eba0b
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/spinlock.h
@@ -0,0 +1,34 @@
+#ifndef __LINUX_SPINLOCK_H__
+#define __LINUX_SPINLOCK_H__
+
+
+typedef struct { } spinlock_t;
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { }
+#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED
+
+#define spin_lock_init(lock)             \
+CYG_MACRO_START;                         \
+CYG_UNUSED_PARAM(spinlock_t *, lock);    \
+CYG_MACRO_END
+
+#define spin_lock(lock)                  \
+CYG_MACRO_START;                         \
+CYG_UNUSED_PARAM(spinlock_t *, lock);    \
+CYG_MACRO_END
+
+#define spin_unlock(lock)                \
+CYG_MACRO_START;                         \
+CYG_UNUSED_PARAM(spinlock_t *, lock);    \
+CYG_MACRO_END
+
+#define spin_lock_bh(lock)               \
+CYG_MACRO_START;                         \
+CYG_UNUSED_PARAM(spinlock_t *, lock);    \
+CYG_MACRO_END
+
+#define spin_unlock_bh(lock)             \
+CYG_MACRO_START;                         \
+CYG_UNUSED_PARAM(spinlock_t *, lock);    \
+CYG_MACRO_END
+
+#endif /* __LINUX_SPINLOCK_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/stat.h b/cpukit/libfs/src/jffs2/include/linux/stat.h
new file mode 100644
index 0000000..a3efd61
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/stat.h
@@ -0,0 +1,12 @@
+#ifndef __LINUX_STAT_H__
+#define __LINUX_STAT_H__
+
+
+#include <sys/stat.h>
+
+#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH)
+#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH)
+#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH)
+#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO)
+
+#endif /* __LINUX_STAT_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/string.h b/cpukit/libfs/src/jffs2/include/linux/string.h
new file mode 100644
index 0000000..fc14ba6
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/string.h
@@ -0,0 +1,6 @@
+#ifndef __LINUX_STRING_H__
+#define __LINUX_STRING_H__
+
+#include <string.h>
+
+#endif /* __LINUX_STRING_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/timer.h b/cpukit/libfs/src/jffs2/include/linux/timer.h
new file mode 100644
index 0000000..80e9ef5
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/timer.h
@@ -0,0 +1,10 @@
+#ifndef __LINUX_TIMER_H__
+#define __LINUX_TIMER_H__
+
+/* Not yet */
+
+struct timer_list { } ;
+
+
+#endif /* __LINUX_TIMER_H__ */
+
diff --git a/cpukit/libfs/src/jffs2/include/linux/types.h b/cpukit/libfs/src/jffs2/include/linux/types.h
new file mode 100644
index 0000000..56665b7
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/types.h
@@ -0,0 +1,19 @@
+#ifndef __LINUX_TYPES_H__
+#define __LINUX_TYPES_H__
+
+#include "cyg/infra/cyg_type.h"
+
+#define uint8_t cyg_uint8
+#define uint16_t cyg_uint16
+#define uint32_t cyg_uint32
+
+#define int8_t cyg_int8
+#define int16_t cyg_int16
+#define int32_t cyg_int32
+
+#define loff_t off_t
+
+
+#define kvec iovec
+#endif /* __LINUX_TYPES_H__ */
+
diff --git a/cpukit/libfs/src/jffs2/include/linux/version.h b/cpukit/libfs/src/jffs2/include/linux/version.h
new file mode 100644
index 0000000..cca2d73
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/version.h
@@ -0,0 +1,5 @@
+#ifndef __LINUX_VERSION_H__
+#define __LINUX_VERSION_H__
+
+
+#endif /* __LINUX_VERSION_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/vmalloc.h b/cpukit/libfs/src/jffs2/include/linux/vmalloc.h
new file mode 100644
index 0000000..6f18ab2
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/vmalloc.h
@@ -0,0 +1,3 @@
+#ifndef __LINUX_VMALLOC_H__
+#define __LINUX_VMALLOC_H__
+#endif
diff --git a/cpukit/libfs/src/jffs2/include/linux/wait.h b/cpukit/libfs/src/jffs2/include/linux/wait.h
new file mode 100644
index 0000000..2b422e3
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/wait.h
@@ -0,0 +1,15 @@
+#ifndef __LINUX_WAIT_H__
+#define __LINUX_WAIT_H__
+
+
+typedef struct { } wait_queue_head_t;
+
+#define init_waitqueue_head(wait) do{} while (0)
+#define add_wait_queue(wait,new_wait) do{} while (0)
+#define remove_wait_queue(wait,old_wait) do{} while (0)
+#define DECLARE_WAITQUEUE(wait,current) do{} while (0)
+
+static inline void wake_up(wait_queue_head_t *erase_wait)
+{ /* Only used for waking up threads blocks on erases. Not used in eCos */ }
+
+#endif /* __LINUX_WAIT_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/workqueue.h b/cpukit/libfs/src/jffs2/include/linux/workqueue.h
new file mode 100644
index 0000000..8c900a4
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/workqueue.h
@@ -0,0 +1,11 @@
+#ifndef __LINUX_WORKQUEUE_H__
+#define __LINUX_WORKQUEUE_H__
+
+/* We don't do this yet */
+struct work_struct { } ;
+
+#define INIT_WORK(x,y,z) /* */
+#define schedule_work(x) do { } while(0)
+#define flush_scheduled_work() do { } while(0)
+
+#endif /* __LINUX_WORKQUEUE_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/zlib.h b/cpukit/libfs/src/jffs2/include/linux/zlib.h
new file mode 100644
index 0000000..9de691e
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/zlib.h
@@ -0,0 +1,14 @@
+#ifndef __LINUX_ZLIB_H__
+#define __LINUX_ZLIB_H__
+
+#include <cyg/compress/zlib.h>
+
+#define zlib_deflateInit(x,y) deflateInit(x,y)
+#define zlib_deflate(x,y) deflate(x,y)
+#define zlib_deflateEnd(x) deflateEnd(x)
+#define zlib_inflateInit(x) inflateInit(x)
+#define zlib_inflateInit2(x,y) inflateInit2(x,y)
+#define zlib_inflate(x,y) inflate(x,y)
+#define zlib_inflateEnd(x) inflateEnd(x)
+
+#endif /* __LINUX_ZLIB_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/zutil.h b/cpukit/libfs/src/jffs2/include/linux/zutil.h
new file mode 100644
index 0000000..c3774ba
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/zutil.h
@@ -0,0 +1,6 @@
+#ifndef __LINUX_ZUTIL_H__
+#define __LINUX_ZUTIL_H__
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+#endif /* __LINUX_ZUTIL_H__ */
diff --git a/cpukit/libfs/src/jffs2/src/compat-crc32.c b/cpukit/libfs/src/jffs2/src/compat-crc32.c
new file mode 100644
index 0000000..7e4ea26
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/src/compat-crc32.c
@@ -0,0 +1,166 @@
+//==========================================================================
+//
+//      crc32.c
+//
+//      Gary S. Brown's 32 bit CRC
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under    
+// the terms of the GNU General Public License as published by the Free     
+// Software Foundation; either version 2 or (at your option) any later      
+// version.                                                                 
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT      
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+// for more details.                                                        
+//
+// You should have received a copy of the GNU General Public License        
+// along with eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    gthomas
+// Contributors: gthomas,asl
+// Date:         2001-01-31
+// Purpose:      
+// Description:  
+//              
+// This code is part of eCos (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/crc/crc.h>
+
+  /* ====================================================================== */
+  /*  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or       */
+  /*  code or tables extracted from it, as desired without restriction.     */
+  /*                                                                        */
+  /*  First, the polynomial itself and its table of feedback terms.  The    */
+  /*  polynomial is                                                         */
+  /*  X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0   */
+  /*                                                                        */
+  /* ====================================================================== */
+
+static const cyg_uint32 crc32_tab[] = {
+      0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+      0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+      0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+      0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+      0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+      0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+      0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+      0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+      0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+      0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+      0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+      0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+      0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+      0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+      0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+      0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+      0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+      0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+      0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+      0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+      0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+      0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+      0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+      0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+      0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+      0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+      0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+      0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+      0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+      0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+      0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+      0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+      0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+      0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+      0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+      0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+      0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+      0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+      0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+      0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+      0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+      0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+      0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+      0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+      0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+      0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+      0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+      0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+      0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+      0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+      0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+      0x2d02ef8dL
+   };
+
+/* This is the standard Gary S. Brown's 32 bit CRC algorithm, but
+   accumulate the CRC into the result of a previous CRC. */
+cyg_uint32 
+cyg_crc32_accumulate(cyg_uint32 crc32val, unsigned char *s, int len)
+{
+  int i;
+
+  for (i = 0;  i < len;  i++) {
+    crc32val = crc32_tab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8);
+  }
+  return crc32val;
+}
+
+/* This is the standard Gary S. Brown's 32 bit CRC algorithm */
+cyg_uint32
+cyg_crc32(unsigned char *s, int len)
+{
+  return (cyg_crc32_accumulate(0,s,len));
+}
+
+/* Return a 32-bit CRC of the contents of the buffer accumulating the
+   result from a previous CRC calculation. This uses the Ethernet FCS
+   algorithm.*/
+cyg_uint32
+cyg_ether_crc32_accumulate(cyg_uint32 crc32val, unsigned char *s, int len)
+{
+  int i;
+
+  if (s == 0) return 0L;
+  
+  crc32val = crc32val ^ 0xffffffff;
+  for (i = 0;  i < len;  i++) {
+      crc32val = crc32_tab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8);
+  }
+  return crc32val ^ 0xffffffff;
+}
+
+/* Return a 32-bit CRC of the contents of the buffer, using the
+   Ethernet FCS algorithm. */
+cyg_uint32
+cyg_ether_crc32(unsigned char *s, int len)
+{
+  return cyg_ether_crc32_accumulate(0,s,len);
+}
+
+
diff --git a/cpukit/libfs/src/jffs2/src/compat-rbtree.c b/cpukit/libfs/src/jffs2/src/compat-rbtree.c
new file mode 100644
index 0000000..5bc1cc5
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/src/compat-rbtree.c
@@ -0,0 +1,408 @@
+/*========================================================================
+//
+//      rbtree.c
+//
+//      Red Black tree implementation
+//
+//========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under    
+// the terms of the GNU General Public License as published by the Free     
+// Software Foundation; either version 2 or (at your option) any later      
+// version.                                                                 
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT      
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+// for more details.                                                        
+//
+// You should have received a copy of the GNU General Public License        
+// along with eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     Niels Provos/OpenBSD
+// Contributors:  dwmw2
+// Date:          2003-01-21
+// Purpose:       This file provides an implementation of red-black trees.
+// Description:   Derived from OpenBSD src/sys/sys/tree.h
+// Usage:         
+//
+//####DESCRIPTIONEND####
+//
+//======================================================================
+*/
+
+/*	$OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $	*/
+/*
+ * Copyright 2002 Niels Provos <provos at citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Fields renamed to match Linux ones. */
+#include <linux/rbtree.h>
+
+
+#define RB_HEAD(head)		(head)->rb_node
+#define RB_LEFT(elm)		(elm)->rb_left
+#define RB_RIGHT(elm)		(elm)->rb_right
+#define RB_PARENT(elm)		(elm)->rb_parent
+#define RB_COLOR(elm)		(elm)->rb_color
+
+
+#define RB_SET(elm, parent) do {				\
+	RB_PARENT(elm) = parent;				\
+	RB_LEFT(elm) = RB_RIGHT(elm) = NULL;	\
+	RB_COLOR(elm) = RB_RED;				\
+} while (0)
+
+#define RB_SET_BLACKRED(black, red) do {			\
+	RB_COLOR(black) = RB_BLACK;				\
+	RB_COLOR(red) = RB_RED;					\
+} while (0)
+
+#ifndef RB_AUGMENT
+#define RB_AUGMENT(x)
+#endif
+
+#define RB_ROTATE_LEFT(head, elm, tmp) do {			\
+	(tmp) = RB_RIGHT(elm);					\
+	if ((RB_RIGHT(elm) = RB_LEFT(tmp))) {			\
+		RB_PARENT(RB_LEFT(tmp)) = (elm);		\
+	}							\
+	RB_AUGMENT(elm);					\
+	if ((RB_PARENT(tmp) = RB_PARENT(elm))) {		\
+		if ((elm) == RB_LEFT(RB_PARENT(elm)))		\
+			RB_LEFT(RB_PARENT(elm)) = (tmp);	\
+		else						\
+			RB_RIGHT(RB_PARENT(elm)) = (tmp);	\
+	} else							\
+		(head)->rb_node = (tmp);			\
+	RB_LEFT(tmp) = (elm);					\
+	RB_PARENT(elm) = (tmp);					\
+	RB_AUGMENT(tmp);					\
+	if ((RB_PARENT(tmp)))					\
+		RB_AUGMENT(RB_PARENT(tmp));			\
+} while (0)
+
+#define RB_ROTATE_RIGHT(head, elm, tmp) do {			\
+	(tmp) = RB_LEFT(elm);					\
+	if ((RB_LEFT(elm) = RB_RIGHT(tmp))) {			\
+		RB_PARENT(RB_RIGHT(tmp)) = (elm);		\
+	}							\
+	RB_AUGMENT(elm);					\
+	if ((RB_PARENT(tmp) = RB_PARENT(elm))) {		\
+		if ((elm) == RB_LEFT(RB_PARENT(elm)))		\
+			RB_LEFT(RB_PARENT(elm)) = (tmp);	\
+		else						\
+			RB_RIGHT(RB_PARENT(elm)) = (tmp);	\
+	} else							\
+		(head)->rb_node = (tmp);			\
+	RB_RIGHT(tmp) = (elm);					\
+	RB_PARENT(elm) = (tmp);					\
+	RB_AUGMENT(tmp);					\
+	if ((RB_PARENT(tmp)))					\
+		RB_AUGMENT(RB_PARENT(tmp));			\
+} while(0)
+
+/* Note args swapped to match Linux */
+void rb_insert_color(struct rb_node *elm, struct rb_root *head)
+{
+	struct rb_node *parent, *gparent, *tmp;
+	while ((parent = RB_PARENT(elm)) &&
+	    RB_COLOR(parent) == RB_RED) {
+		gparent = RB_PARENT(parent);
+		if (parent == RB_LEFT(gparent)) {
+			tmp = RB_RIGHT(gparent);
+			if (tmp && RB_COLOR(tmp) == RB_RED) {
+				RB_COLOR(tmp) = RB_BLACK;
+				RB_SET_BLACKRED(parent, gparent);
+				elm = gparent;
+				continue;
+			}
+			if (RB_RIGHT(parent) == elm) {
+				RB_ROTATE_LEFT(head, parent, tmp);
+				tmp = parent;
+				parent = elm;
+				elm = tmp;
+			}
+			RB_SET_BLACKRED(parent, gparent);
+			RB_ROTATE_RIGHT(head, gparent, tmp);
+		} else {
+			tmp = RB_LEFT(gparent);
+			if (tmp && RB_COLOR(tmp) == RB_RED) {
+				RB_COLOR(tmp) = RB_BLACK;
+				RB_SET_BLACKRED(parent, gparent);
+				elm = gparent;
+				continue;
+			}
+			if (RB_LEFT(parent) == elm) {
+				RB_ROTATE_RIGHT(head, parent, tmp);
+				tmp = parent;
+				parent = elm;
+				elm = tmp;
+			}
+			RB_SET_BLACKRED(parent, gparent);
+			RB_ROTATE_LEFT(head, gparent, tmp);
+		}
+	}
+	RB_COLOR(head->rb_node) = RB_BLACK;
+}
+
+
+static void rb_remove_color(struct rb_root *head, struct rb_node *parent,
+			    struct rb_node *elm)
+{
+	struct rb_node *tmp;
+	while ((elm == NULL || RB_COLOR(elm) == RB_BLACK) &&
+	    elm != RB_HEAD(head)) {
+		if (RB_LEFT(parent) == elm) {
+			tmp = RB_RIGHT(parent);
+			if (RB_COLOR(tmp) == RB_RED) {
+				RB_SET_BLACKRED(tmp, parent);
+				RB_ROTATE_LEFT(head, parent, tmp);
+				tmp = RB_RIGHT(parent);
+			}
+			if ((RB_LEFT(tmp) == NULL ||
+			    RB_COLOR(RB_LEFT(tmp)) == RB_BLACK) &&
+			    (RB_RIGHT(tmp) == NULL ||
+			    RB_COLOR(RB_RIGHT(tmp)) == RB_BLACK)) {
+				RB_COLOR(tmp) = RB_RED;
+				elm = parent;
+				parent = RB_PARENT(elm);
+			} else {
+				if (RB_RIGHT(tmp) == NULL ||
+				    RB_COLOR(RB_RIGHT(tmp)) == RB_BLACK) {
+					struct rb_node *oleft;
+					if ((oleft = RB_LEFT(tmp)))
+						RB_COLOR(oleft) = RB_BLACK;
+					RB_COLOR(tmp) = RB_RED;
+					RB_ROTATE_RIGHT(head, tmp, oleft);
+					tmp = RB_RIGHT(parent);
+				}
+				RB_COLOR(tmp) = RB_COLOR(parent);
+				RB_COLOR(parent) = RB_BLACK;
+				if (RB_RIGHT(tmp))
+					RB_COLOR(RB_RIGHT(tmp)) = RB_BLACK;
+				RB_ROTATE_LEFT(head, parent, tmp);
+				elm = RB_HEAD(head);
+				break;
+			}
+		} else {
+			tmp = RB_LEFT(parent);
+			if (RB_COLOR(tmp) == RB_RED) {
+				RB_SET_BLACKRED(tmp, parent);
+				RB_ROTATE_RIGHT(head, parent, tmp);
+				tmp = RB_LEFT(parent);
+			}
+			if ((RB_LEFT(tmp) == NULL ||
+			    RB_COLOR(RB_LEFT(tmp)) == RB_BLACK) &&
+			    (RB_RIGHT(tmp) == NULL ||
+			    RB_COLOR(RB_RIGHT(tmp)) == RB_BLACK)) {
+				RB_COLOR(tmp) = RB_RED;
+				elm = parent;
+				parent = RB_PARENT(elm);
+			} else {
+				if (RB_LEFT(tmp) == NULL ||
+				    RB_COLOR(RB_LEFT(tmp)) == RB_BLACK) {
+					struct rb_node *oright;
+					if ((oright = RB_RIGHT(tmp)))
+						RB_COLOR(oright) = RB_BLACK;
+					RB_COLOR(tmp) = RB_RED;
+					RB_ROTATE_LEFT(head, tmp, oright);
+					tmp = RB_LEFT(parent);
+				}
+				RB_COLOR(tmp) = RB_COLOR(parent);
+				RB_COLOR(parent) = RB_BLACK;
+				if (RB_LEFT(tmp))
+					RB_COLOR(RB_LEFT(tmp)) = RB_BLACK;
+				RB_ROTATE_RIGHT(head, parent, tmp);
+				elm = RB_HEAD(head);
+				break;
+			}
+		}
+	}
+	if (elm)
+		RB_COLOR(elm) = RB_BLACK;
+}
+
+/* Note name changed. Guess why :) */
+void rb_erase(struct rb_node *elm, struct rb_root *head)
+{
+	struct rb_node *child, *parent, *old = elm;
+	int color;
+	if (RB_LEFT(elm) == NULL)
+		child = RB_RIGHT(elm);
+	else if (RB_RIGHT(elm) == NULL)
+		child = RB_LEFT(elm);
+	else {
+		struct rb_node *left;
+		elm = RB_RIGHT(elm);
+		while ((left = RB_LEFT(elm)))
+			elm = left;
+		child = RB_RIGHT(elm);
+		parent = RB_PARENT(elm);
+		color = RB_COLOR(elm);
+		if (child)
+			RB_PARENT(child) = parent;
+		if (parent) {
+			if (RB_LEFT(parent) == elm)
+				RB_LEFT(parent) = child;
+			else
+				RB_RIGHT(parent) = child;
+			RB_AUGMENT(parent);
+		} else
+			RB_HEAD(head) = child;
+		if (RB_PARENT(elm) == old)
+			parent = elm;
+		*(elm) = *(old);
+		if (RB_PARENT(old)) {
+			if (RB_LEFT(RB_PARENT(old)) == old)
+				RB_LEFT(RB_PARENT(old)) = elm;
+			else
+				RB_RIGHT(RB_PARENT(old)) = elm;
+			RB_AUGMENT(RB_PARENT(old));
+		} else
+			RB_HEAD(head) = elm;
+		RB_PARENT(RB_LEFT(old)) = elm;
+		if (RB_RIGHT(old))
+			RB_PARENT(RB_RIGHT(old)) = elm;
+		if (parent) {
+			left = parent;
+			do {
+				RB_AUGMENT(left);
+			} while ((left = RB_PARENT(left)));
+		}
+		goto color;
+	}
+	parent = RB_PARENT(elm);
+	color = RB_COLOR(elm);
+	if (child)
+		RB_PARENT(child) = parent;
+	if (parent) {
+		if (RB_LEFT(parent) == elm)
+			RB_LEFT(parent) = child;
+		else
+			RB_RIGHT(parent) = child;
+		RB_AUGMENT(parent);
+	} else
+		RB_HEAD(head) = child;
+color:
+	if (color == RB_BLACK)
+		rb_remove_color(head, parent, child);
+}
+
+struct rb_node *rb_next(struct rb_node *elm)
+{
+	if (RB_RIGHT(elm)) {
+		elm = RB_RIGHT(elm);
+		while (RB_LEFT(elm))
+			elm = RB_LEFT(elm);
+	} else {
+		if (RB_PARENT(elm) &&
+		    (elm == RB_LEFT(RB_PARENT(elm))))
+			elm = RB_PARENT(elm);
+		else {
+			while (RB_PARENT(elm) &&
+			    (elm == RB_RIGHT(RB_PARENT(elm))))
+				elm = RB_PARENT(elm);
+			elm = RB_PARENT(elm);
+		}
+	}
+	return (elm);
+}
+
+struct rb_node *rb_prev(struct rb_node *elm)
+{
+	if (RB_LEFT(elm)) {
+		elm = RB_LEFT(elm);
+		while (RB_RIGHT(elm))
+			elm = RB_RIGHT(elm);
+	} else {
+		if (RB_PARENT(elm) &&
+		    (elm == RB_RIGHT(RB_PARENT(elm))))
+			elm = RB_PARENT(elm);
+		else {
+			while (RB_PARENT(elm) &&
+			    (elm == RB_LEFT(RB_PARENT(elm))))
+				elm = RB_PARENT(elm);
+			elm = RB_PARENT(elm);
+		}
+	}
+	return (elm);
+}
+
+/* These ones are lifted from Linux -- but that's OK because I
+   wrote them. dwmw2. */
+struct rb_node *rb_first(struct rb_root *root)
+{
+        struct rb_node  *n;
+
+        n = root->rb_node;
+        if (!n)
+                return 0;
+        while (n->rb_left)
+                n = n->rb_left;
+        return n;
+}
+
+void rb_replace_node(struct rb_node *victim, struct rb_node *new,
+                     struct rb_root *root)
+{
+        struct rb_node *parent = victim->rb_parent;
+
+        /* Set the surrounding nodes to point to the replacement */
+        if (parent) {
+                if (victim == parent->rb_left)
+                        parent->rb_left = new;
+                else
+                        parent->rb_right = new;
+        } else {
+                root->rb_node = new;
+        }
+        if (victim->rb_left)
+                victim->rb_left->rb_parent = new;
+        if (victim->rb_right)
+                victim->rb_right->rb_parent = new;
+
+        /* Copy the pointers/colour from the victim to the replacement */
+        *new = *victim;
+}
diff --git a/cpukit/libfs/src/jffs2/src/dir-rtems.c b/cpukit/libfs/src/jffs2/src/dir-rtems.c
new file mode 100644
index 0000000..16b62cc
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/src/dir-rtems.c
@@ -0,0 +1,371 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Free Software Foundation, Inc.
+ *
+ * Created by David Woodhouse <dwmw2 at cambridge.redhat.com>
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ * $Id: dir-ecos.c,v 1.11 2005/02/08 19:36:27 lunn Exp $
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/crc32.h>
+#include "nodelist.h"
+
+/***********************************************************************/
+
+/* 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;
+	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 <= hash; fd_list = fd_list->next) {
+		if (fd_list->nhash == hash && 
+		    (!fd || fd_list->version > fd->version) &&
+		    strlen((char *)fd_list->name) == namelen &&
+		    !strncmp((char *)fd_list->name, (char *)d_name, namelen)) {
+			fd = fd_list;
+		}
+	}
+	if (fd)
+		ino = fd->ino;
+	up(&dir_f->sem);
+	if (ino) {
+		inode = jffs2_iget(dir_i->i_sb, ino);
+		if (IS_ERR(inode)) {
+			printk("jffs2_iget() failed for ino #%u\n", ino);
+			return inode;
+		}
+	}
+
+	return inode;
+}
+
+/***********************************************************************/
+
+
+
+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;
+	int ret;
+
+	ri = jffs2_alloc_raw_inode();
+	if (!ri)
+		return -ENOMEM;
+	
+	c = JFFS2_SB_INFO(dir_i->i_sb);
+
+	D1(printk(KERN_DEBUG "jffs2_create()\n"));
+
+	inode = jffs2_new_inode(dir_i, mode, ri);
+
+	if (IS_ERR(inode)) {
+		D1(printk(KERN_DEBUG "jffs2_new_inode() failed\n"));
+		jffs2_free_raw_inode(ri);
+		return PTR_ERR(inode);
+	}
+
+	f = JFFS2_INODE_INFO(inode);
+	dir_f = JFFS2_INODE_INFO(dir_i);
+
+	ret = jffs2_do_create(c, dir_f, f, ri, 
+			      (const char *)d_name, 
+                              strlen((char *)d_name));
+
+	if (ret) {
+		inode->i_nlink = 0;
+		jffs2_iput(inode);
+		jffs2_free_raw_inode(ri);
+		return ret;
+	}
+
+	jffs2_free_raw_inode(ri);
+
+	D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d)\n",
+		  inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink));
+        *new_i = inode;
+	return 0;
+}
+
+/***********************************************************************/
+
+
+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, (const char *)d_name, 
+			       strlen((char *)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, 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, 
+                            (const char * )d_name, 
+                            strlen((char *)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, const unsigned char *d_name, int mode)
+{
+	struct jffs2_inode_info *f, *dir_f;
+	struct jffs2_sb_info *c;
+	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;
+	uint32_t alloclen, phys_ofs;
+	int ret;
+
+	mode |= S_IFDIR;
+
+	ri = jffs2_alloc_raw_inode();
+	if (!ri)
+		return -ENOMEM;
+	
+	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 = strlen((char *)d_name);
+	ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL);
+
+	if (ret) {
+		jffs2_free_raw_inode(ri);
+		return ret;
+	}
+
+	inode = jffs2_new_inode(dir_i, mode, ri);
+
+	if (IS_ERR(inode)) {
+		jffs2_free_raw_inode(ri);
+		jffs2_complete_reservation(c);
+		return PTR_ERR(inode);
+	}
+
+	f = JFFS2_INODE_INFO(inode);
+
+	ri->data_crc = cpu_to_je32(0);
+	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
+	
+	fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL);
+
+	jffs2_free_raw_inode(ri);
+
+	if (IS_ERR(fn)) {
+		/* Eeek. Wave bye bye */
+		up(&f->sem);
+		jffs2_complete_reservation(c);
+		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
+	*/
+	f->metadata = fn;
+	up(&f->sem);
+
+	jffs2_complete_reservation(c);
+	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+	if (ret) {
+		/* Eep. */
+		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);
+		inode->i_nlink = 0;
+		jffs2_iput(inode);
+		return -ENOMEM;
+	}
+
+	dir_f = JFFS2_INODE_INFO(dir_i);
+	down(&dir_f->sem);
+
+	rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
+	rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
+	rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
+
+	rd->pino = cpu_to_je32(dir_i->i_ino);
+	rd->version = cpu_to_je32(++dir_f->highest_version);
+	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, namelen));
+
+	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);
+		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);
+
+	jffs2_iput(inode);
+	return 0;
+}
+
+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) {
+		if (fd->ino)
+			return EPERM; //-ENOTEMPTY;
+	}
+	return jffs2_unlink(dir_i, d_inode, 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;
+
+#if 0 /* FIXME -- this really doesn't belong in individual file systems. 
+	 The fileio code ought to do this for us, or at least part of it */
+	if (new_dentry->d_inode) {
+		if (S_ISDIR(d_inode->i_mode) && 
+		    !S_ISDIR(new_dentry->d_inode->i_mode)) {
+			/* Cannot rename directory over non-directory */
+			return -EINVAL;
+		}
+
+		victim_f = JFFS2_INODE_INFO(new_dentry->d_inode);
+
+		if (S_ISDIR(new_dentry->d_inode->i_mode)) {
+			struct jffs2_full_dirent *fd;
+
+			if (!S_ISDIR(d_inode->i_mode)) {
+				/* Cannot rename non-directory over directory */
+				return -EINVAL;
+			}
+			down(&victim_f->sem);
+			for (fd = victim_f->dents; fd; fd = fd->next) {
+				if (fd->ino) {
+					up(&victim_f->sem);
+					return -ENOTEMPTY;
+				}
+			}
+			up(&victim_f->sem);
+		}
+	}
+#endif
+
+	/* XXX: We probably ought to alloc enough space for
+	   both nodes at the same time. Writing the new link, 
+	   then getting -ENOSPC, is quite bad :)
+	*/
+
+	/* Make a hard link */
+	
+	/* XXX: This is ugly */
+	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,
+			    (const char *)new_d_name, 
+                            strlen((char *)new_d_name));
+
+	if (ret)
+		return ret;
+
+	if (victim_f) {
+		/* There was a victim. Kill it off nicely */
+		/* Don't oops if the victim was a dirent pointing to an
+		   inode which didn't exist. */
+		if (victim_f->inocache) {
+			down(&victim_f->sem);
+			victim_f->inocache->nlink--;
+			up(&victim_f->sem);
+		}
+	}
+
+	/* Unlink the original */
+	ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), 
+                              (const char *)old_d_name, 
+                              strlen((char *)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);
+		if (f->inocache)
+			d_inode->i_nlink = f->inocache->nlink++;
+		up(&f->sem);
+
+		printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret);
+	}
+	return ret;
+}
+
diff --git a/cpukit/libfs/src/jffs2/src/flashio.c b/cpukit/libfs/src/jffs2/src/flashio.c
new file mode 100644
index 0000000..13a12e3
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/src/flashio.c
@@ -0,0 +1,165 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Red Hat, Inc.
+ *
+ * Created by Dominic Ostrowski <dominic.ostrowski at 3glab.com>
+ * Contributors: David Woodhouse, Nick Garnett, Richard Panton.
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ * $Id: flashio.c,v 1.1 2003/11/26 14:09:29 dwmw2 Exp $
+ *
+ */
+
+#include <linux/kernel.h>
+#include "nodelist.h"
+
+#include <cyg/io/io.h>
+#include <cyg/io/config_keys.h>
+#include <cyg/io/flash.h>
+
+cyg_bool jffs2_flash_read(struct jffs2_sb_info * c,
+			  cyg_uint32 read_buffer_offset, const size_t size,
+			  size_t * return_size, unsigned 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, unsigned 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;
+
+	return ret;
+}
+
+cyg_bool jffs2_flash_erase(struct jffs2_sb_info * c,
+			   struct jffs2_eraseblock * jeb)
+{
+	cyg_io_flash_getconfig_erase_t e;
+	cyg_flashaddr_t 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);
+}
+
diff --git a/cpukit/libfs/src/jffs2/src/fs-rtems.c b/cpukit/libfs/src/jffs2/src/fs-rtems.c
new file mode 100644
index 0000000..c38b719
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/src/fs-rtems.c
@@ -0,0 +1,2191 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Free Software Foundation, Inc.
+ *
+ * Created by Dominic Ostrowski <dominic.ostrowski at 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.44 2005/07/24 15:29:57 dedekind Exp $
+ *
+ */
+
+#include <linux/kernel.h>
+#include "nodelist.h"
+#include <linux/pagemap.h>
+#include <linux/crc32.h>
+#include "compr.h"
+#include <errno.h>
+#include <string.h>
+#include <cyg/io/config_keys.h>
+
+#if (__GNUC__ == 3) && (__GNUC_MINOR__ == 2) && \
+    (defined (__arm__) || defined (_mips))
+#error This compiler is known to be broken. Please see:
+#error "http://ecos.sourceware.org/ml/ecos-patches/2003-08/msg00006.html"
+#endif
+
+//==========================================================================
+// Forward definitions
+
+// 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);
+#ifdef CYGOPT_FS_JFFS2_WRITE
+static int jffs2_ops_unlink(cyg_mtab_entry * mte, cyg_dir dir,
+			    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);
+static int jffs2_ops_link(cyg_mtab_entry * mte, cyg_dir dir1, const char *name1,
+			  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);
+static int jffs2_chdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
+		       cyg_dir * dir_out);
+static int jffs2_stat(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
+		      struct stat *buf);
+static int jffs2_getinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
+			 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);
+
+// 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);
+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);
+static int jffs2_fo_setinfo(struct CYG_FILE_TAG *fp, int key, void *buf,
+			    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);
+static int jffs2_truncate_file (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_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);
+#else
+FSTAB_ENTRY(jffs2_fste, "jffs2", 0,
+	    CYG_SYNCMODE_FILE_FILESYSTEM | CYG_SYNCMODE_IO_FILESYSTEM,
+	    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,
+#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
+};
+
+//==========================================================================
+// STATIC VARIABLES !!!
+
+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 unsigned char *path;  // path to follow
+	struct _inode *node;	    // Node found
+	const unsigned 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
+
+
+// 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)
+{
+	struct _inode *this = root_i, *next;
+
+ 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 unsigned char *name)
+{
+	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)
+{
+	struct _inode *dir = ds->dir;
+	const unsigned char *name = ds->path;
+	const unsigned 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++;
+
+	// Check if this is the last path element.
+	while( *n == '/') n++;
+	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 (IS_ERR(d))
+		return -PTR_ERR(d);
+
+	// 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;
+
+	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;
+		while (*(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)
+{
+	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;
+	}
+
+	return err;
+}
+
+//==========================================================================
+// Filesystem operations
+
+// -------------------------------------------------------------------------
+// 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;
+	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;
+	}
+
+	return 0;
+
+      out_nodes:
+	jffs2_free_ino_caches(c);
+	jffs2_free_raw_node_refs(c);
+	free(c->blocks);
+
+	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);
+                if (n_fs_mounted++ == 0) {
+                        jffs2_create_slab_caches(); // No error check, cannot fail
+			jffs2_compressors_init(); 
+		}
+
+		err = jffs2_read_super(jffs2_sb);
+
+		if (err) {
+                        if (--n_fs_mounted == 0) {
+                                jffs2_destroy_slab_caches();
+				jffs2_compressors_exit();
+			}
+                        
+			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));
+
+	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);
+        struct jffs2_full_dirent *fd, *next;
+
+	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 directory entries
+		for (fd = root->jffs2_i.dents; fd; fd = next) {
+		  next=fd->next;
+		  jffs2_free_full_dirent(fd);
+		}
+
+		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--;
+        }
+        if (--n_fs_mounted == 0) {
+                jffs2_destroy_slab_caches();        
+		jffs2_compressors_exit();
+	}
+	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)
+{
+
+	jffs2_dirsearch ds;
+	struct _inode *node = NULL;
+	int err;
+
+	D2(printf("jffs2_open\n"));
+
+	/* 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;
+
+#ifndef CYGOPT_FS_JFFS2_WRITE
+	if (mode & (O_CREAT|O_TRUNC|O_WRONLY))
+		return EROFS;
+#endif
+	init_dirsearch(&ds, (struct _inode *) dir, 
+                       (const unsigned char *) name);
+
+	err = jffs2_find(&ds);
+
+	if (err == ENOENT) {
+#ifdef CYGOPT_FS_JFFS2_WRITE
+		if (ds.last && (mode & O_CREAT)) {
+
+			// 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.
+
+			err = jffs2_create(ds.dir, ds.name, S_IRUGO|S_IXUGO|S_IWUSR|S_IFREG, &node);
+
+			if (err != 0) {
+                                //Possible orphaned inode on the flash - but will be gc'd
+                          	jffs2_iput(ds.dir);
+                                return -err;
+			}
+
+			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;
+	}
+
+             // If the O_TRUNC bit is set we must clean out the file data.
+	if (mode & O_TRUNC) {
+#ifdef CYGOPT_FS_JFFS2_WRITE
+             err = jffs2_truncate_file(node);
+             if (err) {
+                  jffs2_iput(node);
+                  return err;
+             }
+#else
+             jffs2_iput(node);
+             return EROFS;
+#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;
+}
+
+#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)
+{
+	jffs2_dirsearch ds;
+	int err;
+
+	D2(printf("jffs2_ops_unlink\n"));
+
+	init_dirsearch(&ds, (struct _inode *) dir, 
+                       (const unsigned char *)name);
+
+	err = jffs2_find(&ds);
+
+	if (err != ENOERR) {
+		jffs2_iput(ds.dir);
+		return err;
+	}
+
+	// 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
+
+	err = jffs2_unlink(ds.dir, ds.node, ds.name);
+	jffs2_iput(ds.dir);
+	jffs2_iput(ds.node);
+
+	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;
+	int err;
+
+	D2(printf("jffs2_ops_mkdir\n"));
+
+	init_dirsearch(&ds, (struct _inode *) dir, 
+                       (const unsigned char *)name);
+
+	err = jffs2_find(&ds);
+
+	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.
+               if (err == ENOERR) {
+            		jffs2_iput(ds.node);
+                        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)
+{
+	jffs2_dirsearch ds;
+	int err;
+
+	D2(printf("jffs2_ops_rmdir\n"));
+
+	init_dirsearch(&ds, (struct _inode *) dir, 
+                       (const unsigned char *)name);
+
+	err = jffs2_find(&ds);
+
+	if (err != ENOERR) {
+		jffs2_iput(ds.dir);
+		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;
+	}
+
+	err = jffs2_rmdir(ds.dir, ds.node, ds.name);
+
+	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)
+{
+	jffs2_dirsearch ds1, ds2;
+	int err;
+
+	D2(printf("jffs2_ops_rename\n"));
+
+	init_dirsearch(&ds1, (struct _inode *) dir1, 
+                       (const unsigned char *)name1);
+
+	err = jffs2_find(&ds1);
+
+	if (err != ENOERR) {
+		jffs2_iput(ds1.dir);
+		return err;
+	}
+
+	init_dirsearch(&ds2, (struct _inode *) dir2, 
+                       (const unsigned char *)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);
+	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 */
+	}
+	jffs2_iput(ds1.node);
+	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)
+{
+	jffs2_dirsearch ds1, ds2;
+	int err;
+
+	D2(printf("jffs2_ops_link\n"));
+
+	// Only do hard links for now in this filesystem
+	if (type != CYG_FSLINK_HARD)
+		return EINVAL;
+
+	init_dirsearch(&ds1, (struct _inode *) dir1, 
+                       (const unsigned char *) name1);
+
+	err = jffs2_find(&ds1);
+
+	if (err != ENOERR) {
+		jffs2_iput(ds1.dir);
+		return err;
+	}
+
+	init_dirsearch(&ds2, (struct _inode *) dir2, 
+                       (const unsigned char *) name2);
+
+	err = jffs2_find(&ds2);
+
+	// 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;
+	}
+
+	// Allow through links to non-existing terminal 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;
+	}
+
+	// Now we know that there is no existing node at the destination,
+	// make a new direntry at the destination.
+
+	err = jffs2_link(ds1.node, ds2.dir, ds2.name);
+
+	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;
+}
+#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)
+{
+	jffs2_dirsearch ds;
+	int err;
+
+	D2(printf("jffs2_opendir\n"));
+
+	init_dirsearch(&ds, (struct _inode *) dir, 
+                       (const unsigned char *) name);
+
+	err = jffs2_find(&ds);
+
+	jffs2_iput(ds.dir);
+
+	if (err != ENOERR)
+		return err;
+
+	// 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.
+
+	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;
+
+}
+
+// -------------------------------------------------------------------------
+// jffs2_chdir()
+// Change directory support.
+
+static int jffs2_chdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
+		       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.
+
+		jffs2_dirsearch ds;
+		int err;
+
+		init_dirsearch(&ds, (struct _inode *) dir, 
+                               (const unsigned char *) name);
+
+		err = jffs2_find(&ds);
+		jffs2_iput(ds.dir);
+
+		if (err != ENOERR)
+			return err;
+
+		// check it is a directory
+		if (!S_ISDIR(ds.node->i_mode)) {
+                        jffs2_iput(ds.node);
+			return ENOTDIR;
+                }
+                
+		// 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;
+
+		// Just decrement directory reference count.
+		jffs2_iput(node);
+	}
+
+	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)
+{
+	jffs2_dirsearch ds;
+	int err;
+
+	D2(printf("jffs2_stat\n"));
+
+	init_dirsearch(&ds, (struct _inode *) dir, 
+                       (const unsigned char *) name);
+
+	err = jffs2_find(&ds);
+	jffs2_iput(ds.dir);
+
+	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 = 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;
+
+	jffs2_iput(ds.node);
+
+	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)
+{
+	jffs2_dirsearch ds;
+	int err;
+
+	D2(printf("jffs2_getinfo\n"));
+
+	init_dirsearch(&ds, (struct _inode *) dir, 
+                       (const unsigned char *) name);
+
+	err = jffs2_find(&ds);
+	jffs2_iput(ds.dir);
+
+	if (err != ENOERR)
+		return err;
+
+	switch (key) {
+	case FS_INFO_CONF:
+		err = jffs2_pathconf(ds.node, (struct cyg_pathconf_info *) buf);
+		break;
+
+	default:
+		err = EINVAL;
+	}
+
+	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)
+{
+	// No setinfo keys supported at present
+
+	D2(printf("jffs2_setinfo\n"));
+
+	return EINVAL;
+}
+
+//==========================================================================
+// File operations
+
+// -------------------------------------------------------------------------
+// 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();
+
+	uio->uio_resid = resid;
+	fp->f_offset = pos;
+
+	up(&f->sem);
+
+	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;
+}
+
+// jffs2_fo_open()
+// Truncate a file
+static int jffs2_truncate_file (struct _inode *inode)
+{
+     struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+     struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+     struct jffs2_full_dnode *new_metadata, * old_metadata;
+     struct jffs2_raw_inode *ri;
+     uint32_t phys_ofs, alloclen;
+     int err;
+     
+     ri = jffs2_alloc_raw_inode();
+     if (!ri) {
+          return ENOMEM;
+     }
+     err = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL);
+     
+     if (err) {
+          jffs2_free_raw_inode(ri);
+          return err;
+     }
+     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->ino = cpu_to_je32(inode->i_ino);
+     ri->version = cpu_to_je32(++f->highest_version);
+     
+     ri->uid = cpu_to_je16(inode->i_uid);
+     ri->gid = cpu_to_je16(inode->i_gid);
+     ri->mode = cpu_to_jemode(inode->i_mode);
+     ri->isize = cpu_to_je32(0);
+     ri->atime = cpu_to_je32(inode->i_atime);
+     ri->mtime = cpu_to_je32(cyg_timestamp());
+     ri->offset = cpu_to_je32(0);
+     ri->csize = ri->dsize = cpu_to_je32(0);
+     ri->compr = JFFS2_COMPR_NONE;
+     ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
+     ri->data_crc = cpu_to_je32(0);
+     new_metadata = jffs2_write_dnode(c, f, ri, NULL, 0, 
+                                      phys_ofs, ALLOC_NORMAL);
+     if (IS_ERR(new_metadata)) {
+          jffs2_complete_reservation(c);
+          jffs2_free_raw_inode(ri);
+          up(&f->sem);
+          return PTR_ERR(new_metadata);
+     }
+     
+     /* It worked. Update the inode */
+     inode->i_mtime = cyg_timestamp();
+     inode->i_size = 0;
+     old_metadata = f->metadata;
+     jffs2_truncate_fragtree (c, &f->fragtree, 0);
+     f->metadata = new_metadata;
+     if (old_metadata) {
+          jffs2_mark_node_obsolete(c, old_metadata->raw);
+          jffs2_free_full_dnode(old_metadata);
+     }
+     jffs2_free_raw_inode(ri);
+     
+     up(&f->sem);
+     jffs2_complete_reservation(c);
+     
+     return 0;
+}
+
+static int jffs2_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
+{
+	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;
+	}
+	ri.isize = cpu_to_je32(inode->i_size);
+
+	// 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];
+		unsigned char *buf = 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", len));
+
+		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;
+
+	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"));
+
+	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;
+	}
+
+        if (pos < 0 )
+                return EINVAL;
+
+	// All OK, set fp offset and return new position.
+	*apos = fp->f_offset = pos;
+
+	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)
+{
+	// No Ioctls currenly defined.
+
+	D2(printf("jffs2_fo_ioctl\n"));
+
+	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.
+
+	D2(printf("jffs2_fo_fsync\n"));
+
+	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;
+
+	D2(printf("jffs2_fo_close\n"));
+
+	jffs2_iput(node);
+
+	fp->f_data = 0;		// zero data pointer
+
+	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;
+
+	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 = 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;
+}
+
+// -------------------------------------------------------------------------
+// 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)
+{
+	struct _inode *node = (struct _inode *) fp->f_data;
+	int err;
+
+	D2(printf("jffs2_fo_getinfo\n"));
+
+	switch (key) {
+	case FS_INFO_CONF:
+		err = jffs2_pathconf(node, (struct cyg_pathconf_info *) buf);
+		break;
+
+	default:
+		err = EINVAL;
+	}
+	return err;
+
+	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)
+{
+	// No setinfo key supported at present
+
+	D2(printf("jffs2_fo_setinfo\n"));
+
+	return ENOERR;
+}
+
+//==========================================================================
+// Directory operations
+
+// -------------------------------------------------------------------------
+// jffs2_fo_dirread()
+// Read a single directory entry from a file.
+
+static __inline void filldir(char *nbuf, int nlen, const unsigned char *name, int namlen)
+{
+	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;
+#ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE
+	struct _inode *c_ino;
+#endif
+	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, (const unsigned char *) ".", 1);
+#ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE
+ 		// Flags here are the same as jffs2_mkdir. Make sure
+                // d_type is the same as st_mode of calling stat.
+                ent->d_type = 
+                  jemode_to_cpu(cpu_to_jemode(S_IRUGO|S_IXUGO|S_IWUSR|S_IFDIR));
+#endif
+                goto out;
+	}
+	if (offset == 1) {
+		filldir(nbuf, nlen, (const unsigned char *) "..", 2);
+#ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE
+                // Flags here are the same as jffs2_mkdir. Make sure
+                // d_type is the same as st_mode of calling stat.
+                ent->d_type = 
+                  jemode_to_cpu(cpu_to_jemode(S_IRUGO|S_IXUGO|S_IWUSR|S_IFDIR));
+#endif
+                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((char *)fd->name));
+#ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE
+		c_ino = jffs2_iget(inode->i_sb, fd->ino);
+		if(IS_ERR(c_ino)) {
+			D1(printk(KERN_WARNING "get entry inode failed\n"));
+			// fileio already set it to zero, so not needed here
+			// ent->d_type = 0;
+		}
+		else {
+			ent->d_type = c_ino->i_mode;
+			jffs2_iput(c_ino);
+		}
+#endif
+		goto out_sem;
+	}
+	/* Reached the end of the directory */
+	found = 0;
+      out_sem:
+	up(&f->sem);
+      out:
+	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
+
+	D2(printf("jffs2_fo_dirlseek\n"));
+
+	if (whence != SEEK_SET || *pos != 0)
+		return EINVAL;
+
+	*pos = fp->f_offset = 0;
+
+	return ENOERR;
+}
+
+//==========================================================================
+// 
+// Called by JFFS2
+// ===============
+// 
+//
+//==========================================================================
+
+unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, 
+				   struct jffs2_inode_info *f, 
+				   unsigned long offset,
+				   unsigned long *priv)
+{
+	/* FIXME: This works only with one file system mounted at a time */
+	int ret;
+
+	ret = jffs2_read_inode_range(c, f, gc_buffer, 
+				     offset & ~(PAGE_CACHE_SIZE-1), PAGE_CACHE_SIZE);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return gc_buffer;
+}
+
+void jffs2_gc_release_page(struct jffs2_sb_info *c,
+			   unsigned char *ptr,
+			   unsigned long *priv)
+{
+	/* Do nothing */
+}
+
+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;
+
+	inode = malloc(sizeof (struct _inode));
+	if (inode == NULL)
+		return 0;
+
+	D2(printf
+	   ("malloc new_inode %x ####################################\n",
+	    inode));
+
+	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
+
+	// 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;
+}
+
+static struct _inode *ilookup(struct super_block *sb, cyg_uint32 ino)
+{
+	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;
+		}
+	}
+	return inode;
+}
+
+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
+
+	// Must first check for cached inode 
+	// If this fails let new_inode create one
+
+	struct _inode *inode;
+	int err;
+
+	D2(printf("jffs2_iget\n"));
+
+	inode = ilookup(sb, ino);
+	if (inode)
+		return inode;
+
+	// Not cached, so malloc it
+	inode = new_inode(sb);
+	if (inode == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	inode->i_ino = ino;
+
+	err = jffs2_read_inode(inode);
+	if (err) {
+		printf("jffs2_read_inode() failed\n");
+                inode->i_nlink = 0; // free _this_ bad inode right now
+		jffs2_iput(inode);
+		inode = NULL;
+		return ERR_PTR(err);
+	}
+	return inode;
+}
+
+// -------------------------------------------------------------------------
+// Decrement the reference count on an inode. If this makes the ref count
+// zero, then this inode can be freed.
+
+void jffs2_iput(struct _inode *i)
+{
+	// 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);
+	}
+}
+
+
+// -------------------------------------------------------------------------
+// EOF jffs2.c
+
+
+static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
+{
+	memset(f, 0, sizeof(*f));
+	init_MUTEX_LOCKED(&f->sem);
+}
+
+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);
+        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+
+        D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
+
+        jffs2_do_clear_inode(c, f);
+}
+
+
+/* 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 *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) {
+                // forceful evict: f->sem is locked already, and the
+                // inode is bad.
+                if (inode->i_cache_prev)
+                       inode->i_cache_prev->i_cache_next = inode->i_cache_next;
+                if (inode->i_cache_next)
+                       inode->i_cache_next->i_cache_prev = inode->i_cache_prev; 
+                up(&(f->sem));
+                jffs2_clear_inode(inode);
+                memset(inode, 0x6a, sizeof(*inode));
+                free(inode);
+                return ERR_PTR(ret);
+	}
+	inode->i_nlink = 1;
+	inode->i_ino = je32_to_cpu(ri->ino);
+	inode->i_mode = jemode_to_cpu(ri->mode);
+	inode->i_gid = je16_to_cpu(ri->gid);
+	inode->i_uid = je16_to_cpu(ri->uid);
+	inode->i_atime = inode->i_ctime = inode->i_mtime = cyg_timestamp();
+	ri->atime = ri->mtime = ri->ctime = cpu_to_je32(inode->i_mtime);
+
+	inode->i_size = 0;
+
+	return inode;
+}
+
+
+static int jffs2_read_inode (struct _inode *inode)
+{
+	struct jffs2_inode_info *f;
+	struct jffs2_sb_info *c;
+	struct jffs2_raw_inode latest_node;
+	int ret;
+
+	D1(printk(KERN_DEBUG "jffs2_read_inode(): inode->i_ino == %lu\n", inode->i_ino));
+
+	f = JFFS2_INODE_INFO(inode);
+	c = JFFS2_SB_INFO(inode->i_sb);
+
+	jffs2_init_inode_info(f);
+	
+	ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node);
+
+	if (ret) {
+		up(&f->sem);
+		return ret;
+	}
+	inode->i_mode = jemode_to_cpu(latest_node.mode);
+	inode->i_uid = je16_to_cpu(latest_node.uid);
+	inode->i_gid = je16_to_cpu(latest_node.gid);
+	inode->i_size = je32_to_cpu(latest_node.isize);
+	inode->i_atime = je32_to_cpu(latest_node.atime);
+	inode->i_mtime = je32_to_cpu(latest_node.mtime);
+	inode->i_ctime = je32_to_cpu(latest_node.ctime);
+
+	inode->i_nlink = f->inocache->nlink;
+	up(&f->sem);
+
+	D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n"));
+	return 0;
+}
+
+
+void jffs2_gc_release_inode(struct jffs2_sb_info *c,
+				   struct jffs2_inode_info *f)
+{
+	jffs2_iput(OFNI_EDONI_2SFFJ(f));
+}
+
+struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
+						     int inum, int nlink)
+{
+	struct _inode *inode;
+	struct jffs2_inode_cache *ic;
+	if (!nlink) {
+		/* The inode has zero nlink but its nodes weren't yet marked
+		   obsolete. This has to be because we're still waiting for 
+		   the final (close() and) jffs2_iput() to happen.
+
+		   There's a possibility that the final jffs2_iput() could have 
+		   happened while we were contemplating. In order to ensure
+		   that we don't cause a new read_inode() (which would fail)
+		   for the inode in question, we use ilookup() in this case
+		   instead of jffs2_iget().
+
+		   The nlink can't _become_ zero at this point because we're 
+		   holding the alloc_sem, and jffs2_do_unlink() would also
+		   need that while decrementing nlink on any inode.
+		*/
+		inode = ilookup(OFNI_BS_2SFFJ(c), inum);
+		if (!inode) {
+			D1(printk(KERN_DEBUG "ilookup() failed for ino #%u; inode is probably deleted.\n",
+				  inum));
+
+			spin_lock(&c->inocache_lock);
+			ic = jffs2_get_ino_cache(c, inum);
+			if (!ic) {
+				D1(printk(KERN_DEBUG "Inode cache for ino #%u is gone.\n", inum));
+				spin_unlock(&c->inocache_lock);
+				return NULL;
+			}
+			if (ic->state != INO_STATE_CHECKEDABSENT) {
+				/* Wait for progress. Don't just loop */
+				D1(printk(KERN_DEBUG "Waiting for ino #%u in state %d\n",
+					  ic->ino, ic->state));
+				sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
+			} else {
+				spin_unlock(&c->inocache_lock);
+			}
+
+			return NULL;
+		}
+	} else {
+		/* Inode has links to it still; they're not going away because
+		   jffs2_do_unlink() would need the alloc_sem and we have it.
+		   Just jffs2_iget() it, and if read_inode() is necessary that's OK.
+		*/
+		inode = jffs2_iget(OFNI_BS_2SFFJ(c), inum);
+		if (IS_ERR(inode))
+			return (void *)inode;
+	}
+
+	return JFFS2_INODE_INFO(inode);
+}
+
+
+
+uint32_t jffs2_from_os_mode(uint32_t osmode)
+{
+	uint32_t jmode = ((osmode & S_IRUSR)?00400:0) |
+		((osmode & S_IWUSR)?00200:0) |
+		((osmode & S_IXUSR)?00100:0) |
+		((osmode & S_IRGRP)?00040:0) |
+		((osmode & S_IWGRP)?00020:0) |
+		((osmode & S_IXGRP)?00010:0) |
+		((osmode & S_IROTH)?00004:0) |
+		((osmode & S_IWOTH)?00002:0) |
+		((osmode & S_IXOTH)?00001:0);
+
+	switch (osmode & S_IFMT) {
+	case S_IFSOCK:
+		return jmode | 0140000;
+	case S_IFLNK:
+		return jmode | 0120000;
+	case S_IFREG:
+		return jmode | 0100000;
+	case S_IFBLK:
+		return jmode | 0060000;
+	case S_IFDIR:
+		return jmode | 0040000;
+	case S_IFCHR:
+		return jmode | 0020000;
+	case S_IFIFO:
+		return jmode | 0010000;
+	case S_ISUID:
+		return jmode | 0004000;
+	case S_ISGID:
+		return jmode | 0002000;
+#ifdef S_ISVTX
+	case S_ISVTX:
+		return jmode | 0001000;
+#endif
+	}
+	printf("os_to_jffs2_mode() cannot convert 0x%x\n", osmode);
+	BUG();
+	return 0;
+}
+
+uint32_t jffs2_to_os_mode (uint32_t jmode)
+{
+	uint32_t osmode = ((jmode & 00400)?S_IRUSR:0) |
+		((jmode & 00200)?S_IWUSR:0) |
+		((jmode & 00100)?S_IXUSR:0) |
+		((jmode & 00040)?S_IRGRP:0) |
+		((jmode & 00020)?S_IWGRP:0) |
+		((jmode & 00010)?S_IXGRP:0) |
+		((jmode & 00004)?S_IROTH:0) |
+		((jmode & 00002)?S_IWOTH:0) |
+		((jmode & 00001)?S_IXOTH:0);
+
+	switch(jmode & 00170000) {
+	case 0140000:
+		return osmode | S_IFSOCK;
+	case 0120000:
+		return osmode | S_IFLNK;
+	case 0100000:
+		return osmode | S_IFREG;
+	case 0060000:
+		return osmode | S_IFBLK;
+	case 0040000:
+		return osmode | S_IFDIR;
+	case 0020000:
+		return osmode | S_IFCHR;
+	case 0010000:
+		return osmode | S_IFIFO;
+	case 0004000:
+		return osmode | S_ISUID;
+	case 0002000:
+		return osmode | S_ISGID;
+#ifdef S_ISVTX
+	case 0001000:
+		return osmode | S_ISVTX;
+#endif
+	}
+	printf("jffs2_to_os_mode() cannot convert 0x%x\n", osmode);
+	BUG();
+	return 0;
+}
diff --git a/cpukit/libfs/src/jffs2/src/malloc-rtems.c b/cpukit/libfs/src/jffs2/src/malloc-rtems.c
new file mode 100644
index 0000000..a06cf5f
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/src/malloc-rtems.c
@@ -0,0 +1,163 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Free Software Foundation, Inc.
+ *
+ * Created by David Woodhouse <dwmw2 at cambridge.redhat.com>
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ * $Id: malloc-ecos.c,v 1.4 2003/11/26 15:55:35 dwmw2 Exp $
+ *
+ */
+
+#include <linux/kernel.h>
+#include <cyg/hal/drv_api.h>
+#include "nodelist.h"
+
+#if !defined(CYGNUM_FS_JFFS2_RAW_NODE_REF_CACHE_POOL_SIZE)
+# define CYGNUM_FS_JFFS2_RAW_NODE_REF_CACHE_POOL_SIZE 0
+#endif
+
+struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize)
+{
+	return malloc(sizeof(struct jffs2_full_dirent) + namesize);
+}
+
+void jffs2_free_full_dirent(struct jffs2_full_dirent *x)
+{
+	free(x);
+}
+
+struct jffs2_full_dnode *jffs2_alloc_full_dnode(void)
+{
+	return malloc(sizeof(struct jffs2_full_dnode));
+}
+
+void jffs2_free_full_dnode(struct jffs2_full_dnode *x)
+{
+	free(x);
+}
+
+struct jffs2_raw_dirent *jffs2_alloc_raw_dirent(void)
+{
+	return malloc(sizeof(struct jffs2_raw_dirent));
+}
+
+void jffs2_free_raw_dirent(struct jffs2_raw_dirent *x)
+{
+	free(x);
+}
+
+struct jffs2_raw_inode *jffs2_alloc_raw_inode(void)
+{
+	return malloc(sizeof(struct jffs2_raw_inode));
+}
+
+void jffs2_free_raw_inode(struct jffs2_raw_inode *x)
+{
+	free(x);
+}
+
+struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void)
+{
+	return malloc(sizeof(struct jffs2_tmp_dnode_info));
+}
+
+void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x)
+{
+	free(x);
+}
+
+struct jffs2_node_frag *jffs2_alloc_node_frag(void)
+{
+	return malloc(sizeof(struct jffs2_node_frag));
+}
+
+void jffs2_free_node_frag(struct jffs2_node_frag *x)
+{
+	free(x);
+}
+
+#if CYGNUM_FS_JFFS2_RAW_NODE_REF_CACHE_POOL_SIZE == 0
+
+int jffs2_create_slab_caches(void)
+{
+	return 0;
+}
+
+void jffs2_destroy_slab_caches(void)
+{
+}
+
+struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void)
+{
+	return malloc(sizeof(struct jffs2_raw_node_ref));
+}
+
+void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x)
+{
+	free(x);
+}
+
+#else // CYGNUM_FS_JFFS2_RAW_NODE_REF_CACHE_POOL_SIZE == 0
+
+static struct jffs2_raw_node_ref
+	rnr_pool[CYGNUM_FS_JFFS2_RAW_NODE_REF_CACHE_POOL_SIZE] __attribute__ ((aligned (4))),
+	* first = NULL;
+static cyg_drv_mutex_t mutex;
+
+int jffs2_create_slab_caches(void)
+{
+	struct jffs2_raw_node_ref * p;
+	cyg_drv_mutex_init(&mutex);
+	for (
+		p = rnr_pool;
+		p < rnr_pool + CYGNUM_FS_JFFS2_RAW_NODE_REF_CACHE_POOL_SIZE - 1;
+		p++
+	)
+		p->next_phys = p + 1;
+	rnr_pool[CYGNUM_FS_JFFS2_RAW_NODE_REF_CACHE_POOL_SIZE - 1].next_phys = NULL;
+	first = &rnr_pool[0];
+	return 0;
+}
+
+void jffs2_destroy_slab_caches(void)
+{
+}
+
+struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void)
+{
+	struct jffs2_raw_node_ref * p;
+	
+	cyg_drv_mutex_lock(&mutex);
+	p = first;
+	if (p != NULL)
+		first = p->next_phys;
+	cyg_drv_mutex_unlock(&mutex);
+	return p;
+}
+
+void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x)
+{
+	cyg_drv_mutex_lock(&mutex);
+	x->next_phys = first;
+	first = x;
+	cyg_drv_mutex_unlock(&mutex);
+}
+
+#endif // CYGNUM_FS_JFFS2_RAW_NODE_REF_CACHE_POOL_SIZE == 0
+
+struct jffs2_inode_cache *jffs2_alloc_inode_cache(void)
+{
+	struct jffs2_inode_cache *ret = malloc(sizeof(struct jffs2_inode_cache));
+	D1(printk(KERN_DEBUG "Allocated inocache at %p\n", ret));
+	return ret;
+}
+
+void jffs2_free_inode_cache(struct jffs2_inode_cache *x)
+{
+	D1(printk(KERN_DEBUG "Freeing inocache at %p\n", x));
+	free(x);
+}
+
diff --git a/cpukit/libfs/src/jffs2/src/os-rtems.h b/cpukit/libfs/src/jffs2/src/os-rtems.h
new file mode 100644
index 0000000..bb4abe7
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/src/os-rtems.h
@@ -0,0 +1,226 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2002-2003 Free Software Foundation, Inc.
+ *
+ * Created by David Woodhouse <dwmw2 at cambridge.redhat.com>
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ * $Id: os-ecos.h,v 1.24 2005/02/09 09:23:55 pavlov Exp $
+ *
+ */
+
+#ifndef __JFFS2_OS_ECOS_H__
+#define __JFFS2_OS_ECOS_H__
+
+#include <pkgconf/fs_jffs2.h>
+#include <cyg/io/io.h>
+#include <sys/types.h>
+#include <asm/atomic.h>
+#include <linux/stat.h>
+#include <linux/compiler.h>
+
+#include <pkgconf/system.h>
+#include <pkgconf/hal.h>
+#include <pkgconf/io_fileio.h>
+
+#include <cyg/infra/cyg_trac.h>        // tracing macros
+#include <cyg/infra/cyg_ass.h>         // assertion macros
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <dirent.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <cyg/fileio/fileio.h>
+
+#include <cyg/hal/drv_api.h>
+#include <cyg/infra/diag.h>
+
+#include <cyg/io/flash.h>
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <asm/bug.h>
+
+#define printf diag_printf
+
+struct _inode;
+struct super_block;
+
+struct iovec {
+        void *iov_base;
+        ssize_t iov_len; 
+};
+
+static inline unsigned int full_name_hash(const unsigned char * name, unsigned int len) {
+
+	unsigned hash = 0;
+ 	while (len--) {
+		hash = (hash << 4) | (hash >> 28);
+		hash ^= *(name++);
+	}
+	return hash;
+}
+
+#ifdef CYGOPT_FS_JFFS2_WRITE
+#define jffs2_is_readonly(c) (0)
+#else
+#define jffs2_is_readonly(c) (1)
+#endif
+
+/* NAND flash not currently supported on eCos */
+#define jffs2_can_mark_obsolete(c) (1)
+
+#define JFFS2_INODE_INFO(i) (&(i)->jffs2_i)
+#define OFNI_EDONI_2SFFJ(f)  ((struct _inode *) ( ((char *)f) - ((char *)(&((struct _inode *)NULL)->jffs2_i)) ) )
+ 
+#define JFFS2_F_I_SIZE(f) (OFNI_EDONI_2SFFJ(f)->i_size)
+#define JFFS2_F_I_MODE(f) (OFNI_EDONI_2SFFJ(f)->i_mode)
+#define JFFS2_F_I_UID(f) (OFNI_EDONI_2SFFJ(f)->i_uid)
+#define JFFS2_F_I_GID(f) (OFNI_EDONI_2SFFJ(f)->i_gid)
+#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime)
+#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime)
+#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime)
+
+/* FIXME: eCos doesn't hav a concept of device major/minor numbers */
+#define JFFS2_F_I_RDEV_MIN(f) ((OFNI_EDONI_2SFFJ(f)->i_rdev)&0xff)
+#define JFFS2_F_I_RDEV_MAJ(f) ((OFNI_EDONI_2SFFJ(f)->i_rdev)>>8)
+
+#define get_seconds cyg_timestamp
+
+struct _inode {
+	cyg_uint32		i_ino;
+
+	int			i_count;
+	mode_t			i_mode;
+	nlink_t			i_nlink; // Could we dispense with this?
+	uid_t			i_uid;
+	gid_t			i_gid;
+	time_t			i_atime;
+	time_t			i_mtime;
+	time_t			i_ctime;
+//	union {
+		unsigned short	i_rdev; // For devices only
+		struct _inode *	i_parent; // For directories only
+		off_t		i_size; // For files only
+//	};
+	struct super_block *	i_sb;
+
+	struct jffs2_inode_info	jffs2_i;
+
+        struct _inode *		i_cache_prev; // We need doubly-linked?
+        struct _inode *		i_cache_next;
+};
+
+#define JFFS2_SB_INFO(sb) (&(sb)->jffs2_sb)
+#define OFNI_BS_2SFFJ(c)  ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->jffs2_sb)) ) )
+
+struct super_block {
+	struct jffs2_sb_info	jffs2_sb;
+	struct _inode *		s_root;
+        unsigned long		s_mount_count;
+	cyg_io_handle_t		s_dev;
+
+#ifdef CYGOPT_FS_JFFS2_GCTHREAD
+	cyg_mutex_t s_lock;             // Lock the inode cache
+	cyg_flag_t  s_gc_thread_flags;  // Communication with the gcthread
+	cyg_handle_t s_gc_thread_handle; 
+	cyg_thread s_gc_thread;
+#if (CYGNUM_JFFS2_GC_THREAD_STACK_SIZE >= CYGNUM_HAL_STACK_SIZE_MINIMUM)
+        char s_gc_thread_stack[CYGNUM_JFFS2_GC_THREAD_STACK_SIZE];
+#else
+        char s_gc_thread_stack[CYGNUM_HAL_STACK_SIZE_MINIMUM];
+#endif
+       cyg_mtab_entry *mte;
+#endif
+};
+
+#define sleep_on_spinunlock(wq, sl) spin_unlock(sl)
+#define EBADFD 32767
+
+/* background.c */
+#ifdef CYGOPT_FS_JFFS2_GCTHREAD
+void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c);
+void jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c);
+void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c);
+#else
+static inline void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c)
+{
+	/* We don't have a GC thread in eCos (yet) */
+}
+#endif
+
+/* fs-ecos.c */
+struct _inode *jffs2_new_inode (struct _inode *dir_i, int mode, struct jffs2_raw_inode *ri);
+struct _inode *jffs2_iget(struct super_block *sb, cyg_uint32 ino);
+void jffs2_iput(struct _inode * i);
+void jffs2_gc_release_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f);
+struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, int inum, int nlink);
+unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, struct jffs2_inode_info *f, 
+				   unsigned long offset, unsigned long *priv);
+void jffs2_gc_release_page(struct jffs2_sb_info *c, unsigned char *pg, unsigned long *priv);
+
+/* Avoid polluting eCos namespace with names not starting in jffs2_ */
+#define os_to_jffs2_mode(x) jffs2_from_os_mode(x)
+uint32_t jffs2_from_os_mode(uint32_t osmode);
+uint32_t jffs2_to_os_mode (uint32_t jmode);
+
+
+/* flashio.c */
+cyg_bool jffs2_flash_read(struct jffs2_sb_info *c, cyg_uint32 read_buffer_offset,
+			  const size_t size, size_t * return_size, unsigned char * write_buffer);
+cyg_bool jffs2_flash_write(struct jffs2_sb_info *c, cyg_uint32 write_buffer_offset,
+			   const size_t size, size_t * return_size, unsigned char * read_buffer);
+int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct iovec *vecs,
+			      unsigned long count, loff_t to, size_t *retlen);
+cyg_bool jffs2_flash_erase(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
+
+// dir-ecos.c
+struct _inode *jffs2_lookup(struct _inode *dir_i, const unsigned char *name, int namelen);
+int jffs2_create(struct _inode *dir_i, const unsigned char *d_name, int mode, struct _inode **new_i);
+int jffs2_mkdir (struct _inode *dir_i, const unsigned char *d_name, int mode);
+int jffs2_link (struct _inode *old_d_inode, struct _inode *dir_i, const unsigned char *d_name);
+int jffs2_unlink(struct _inode *dir_i, struct _inode *d_inode, const unsigned char *d_name);
+int jffs2_rmdir (struct _inode *dir_i, struct _inode *d_inode, const unsigned char *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);
+
+/* erase.c */
+static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
+{ }
+
+#ifndef CONFIG_JFFS2_FS_WRITEBUFFER
+#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) )
+#define jffs2_can_mark_obsolete(c) (1)
+#define jffs2_cleanmarker_oob(c) (0)
+#define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
+
+#define jffs2_flush_wbuf_pad(c) (c=c)
+#define jffs2_flush_wbuf_gc(c, i) ({ (void)(c), (void) i, 0; })
+#define jffs2_nand_read_failcnt(c,jeb) do { ; } while(0)
+#define jffs2_write_nand_badblock(c,jeb,p) (0)
+#define jffs2_flash_setup(c) (0)
+#define jffs2_nand_flash_cleanup(c) do {} while(0)
+#define jffs2_wbuf_dirty(c) (0)
+#define jffs2_flash_writev(a,b,c,d,e,f) jffs2_flash_direct_writev(a,b,c,d,e)
+#define jffs2_wbuf_timeout NULL
+#define jffs2_wbuf_process NULL
+#define jffs2_nor_ecc(c) (0)
+#else
+#error no nand yet
+#endif
+
+#ifndef BUG_ON
+#define BUG_ON(x) do { if (unlikely(x)) BUG(); } while(0)
+#endif
+
+#define __init
+
+#endif /* __JFFS2_OS_ECOS_H__ */
-- 
1.7.7




More information about the devel mailing list