=?yes?q?=5BPATCH=204/5=5D=20JFFS2=3A=20Add=20RTEMS=20support?=

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


---
 cpukit/Makefile.am                                 |    3 +
 cpukit/libcsupport/include/rtems/libio.h           |    1 +
 cpukit/libfs/Makefile.am                           |   29 +
 .../libfs/src/jffs2/include/cyg/infra/cyg_type.h   |  484 +----
 cpukit/libfs/src/jffs2/include/rtems/jffs2.h       |  455 ++++
 cpukit/libfs/src/jffs2/src/compr.c                 |  360 +---
 cpukit/libfs/src/jffs2/src/compr.h                 |    2 +-
 cpukit/libfs/src/jffs2/src/compr_rtime.c           |   57 +-
 cpukit/libfs/src/jffs2/src/compr_zlib.c            |  179 +-
 cpukit/libfs/src/jffs2/src/debug.h                 |   18 +
 cpukit/libfs/src/jffs2/src/dir-rtems.c             |  225 ++-
 cpukit/libfs/src/jffs2/src/erase.c                 |    2 +-
 cpukit/libfs/src/jffs2/src/flashio.c               |   60 +-
 cpukit/libfs/src/jffs2/src/fs-rtems.c              | 2378 ++++++++------------
 cpukit/libfs/src/jffs2/src/gc.c                    |    6 +
 cpukit/libfs/src/jffs2/src/jffs2_fs_i.h            |    2 +
 cpukit/libfs/src/jffs2/src/malloc-rtems.c          |  106 +-
 cpukit/libfs/src/jffs2/src/nodelist.h              |    6 +-
 cpukit/libfs/src/jffs2/src/os-rtems.h              |  133 +-
 cpukit/libfs/src/jffs2/src/readinode.c             |    7 +
 cpukit/libfs/src/jffs2/src/scan.c                  |    3 +-
 cpukit/preinstall.am                               |    4 +
 cpukit/sapi/include/confdefs.h                     |   19 +-
 cpukit/wrapup/Makefile.am                          |    1 +
 24 files changed, 1830 insertions(+), 2710 deletions(-)
 create mode 100644 cpukit/libfs/src/jffs2/include/rtems/jffs2.h

diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am
index 1330c7d..7bc6296 100644
--- a/cpukit/Makefile.am
+++ b/cpukit/Makefile.am
@@ -120,6 +120,9 @@ include_rtems_rfs_HEADERS += libfs/src/rfs/rtems-rfs-link.h
 include_rtems_rfs_HEADERS += libfs/src/rfs/rtems-rfs-mutex.h
 include_rtems_rfs_HEADERS += libfs/src/rfs/rtems-rfs-trace.h
 
+# JFFS2
+include_rtems_HEADERS += libfs/src/jffs2/include/rtems/jffs2.h
+
 ## libblock
 include_rtems_HEADERS += libblock/include/rtems/bdbuf.h
 include_rtems_HEADERS += libblock/include/rtems/blkdev.h
diff --git a/cpukit/libcsupport/include/rtems/libio.h b/cpukit/libcsupport/include/rtems/libio.h
index 23853f9..f3a9181 100644
--- a/cpukit/libcsupport/include/rtems/libio.h
+++ b/cpukit/libcsupport/include/rtems/libio.h
@@ -1437,6 +1437,7 @@ extern int rtems_mkdir(const char *path, mode_t mode);
 #define RTEMS_FILESYSTEM_TYPE_NFS "nfs"
 #define RTEMS_FILESYSTEM_TYPE_DOSFS "dosfs"
 #define RTEMS_FILESYSTEM_TYPE_RFS "rfs"
+#define RTEMS_FILESYSTEM_TYPE_JFFS2 "jffs2"
 
 /** @} */
 
diff --git a/cpukit/libfs/Makefile.am b/cpukit/libfs/Makefile.am
index 58733f7..c9f14b5 100644
--- a/cpukit/libfs/Makefile.am
+++ b/cpukit/libfs/Makefile.am
@@ -102,6 +102,35 @@ librfs_a_SOURCES = \
     src/rfs/rtems-rfs-rtems-dir.c src/rfs/rtems-rfs-rtems-file.c \
     src/rfs/rtems-rfs-trace.c
 
+# JFFS2
+noinst_LIBRARIES += libjffs2.a
+libjffs2_a_SOURCES =
+libjffs2_a_SOURCES += src/jffs2/src/build.c
+libjffs2_a_SOURCES += src/jffs2/src/compat-crc32.c
+libjffs2_a_SOURCES += src/jffs2/src/compat-rbtree.c
+libjffs2_a_SOURCES += src/jffs2/src/compr.c
+libjffs2_a_SOURCES += src/jffs2/src/compr_rtime.c
+libjffs2_a_SOURCES += src/jffs2/src/compr_zlib.c
+libjffs2_a_SOURCES += src/jffs2/src/debug.c
+libjffs2_a_SOURCES += src/jffs2/src/dir-rtems.c
+libjffs2_a_SOURCES += src/jffs2/src/erase.c
+libjffs2_a_SOURCES += src/jffs2/src/flashio.c
+libjffs2_a_SOURCES += src/jffs2/src/fs-rtems.c
+libjffs2_a_SOURCES += src/jffs2/src/gc.c
+libjffs2_a_SOURCES += src/jffs2/src/malloc-rtems.c
+libjffs2_a_SOURCES += src/jffs2/src/nodelist.c
+libjffs2_a_SOURCES += src/jffs2/src/nodemgmt.c
+libjffs2_a_SOURCES += src/jffs2/src/read.c
+libjffs2_a_SOURCES += src/jffs2/src/readinode.c
+libjffs2_a_SOURCES += src/jffs2/src/scan.c
+libjffs2_a_SOURCES += src/jffs2/src/write.c
+libjffs2_a_CFLAGS =
+libjffs2_a_CFLAGS += -Wno-pointer-sign
+libjffs2_a_CPPFLAGS =
+libjffs2_a_CPPFLAGS += $(AM_CPPFLAGS) -I$(srcdir)/src/jffs2/include
+libjffs2_a_CPPFLAGS += -D__ECOS
+libjffs2_a_CPPFLAGS += '-DKBUILD_MODNAME="JFFS2"'
+
 # ---
 include $(srcdir)/preinstall.am
 include $(top_srcdir)/automake/subdirs.am
diff --git a/cpukit/libfs/src/jffs2/include/cyg/infra/cyg_type.h b/cpukit/libfs/src/jffs2/include/cyg/infra/cyg_type.h
index 5047493..e046872 100644
--- a/cpukit/libfs/src/jffs2/include/cyg/infra/cyg_type.h
+++ b/cpukit/libfs/src/jffs2/include/cyg/infra/cyg_type.h
@@ -55,130 +55,11 @@
 //
 
 #include <stddef.h>           // Definition of NULL from the compiler
+#include <stdint.h>
 
-// -------------------------------------------------------------------------
-// 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.
+typedef uint16_t cyg_uint16;
 
-#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
+typedef uint32_t cyg_uint32;
 
 // -------------------------------------------------------------------------
 // Allow creation of procedure-like macros that are a single statement,
@@ -195,365 +76,6 @@ typedef cyg_halbool bool;
   __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/rtems/jffs2.h b/cpukit/libfs/src/jffs2/include/rtems/jffs2.h
new file mode 100644
index 0000000..fda7c35
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/rtems/jffs2.h
@@ -0,0 +1,455 @@
+/*
+ * Copyright (c) 2013 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef RTEMS_JFFS2_H
+#define RTEMS_JFFS2_H
+
+#include <rtems/fs.h>
+#include <sys/param.h>
+#include <zlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct rtems_jffs2_flash_control rtems_jffs2_flash_control;
+
+/**
+ * @defgroup JFFS2 Journalling Flash File System Version 2 (JFFS2) Support
+ *
+ * @ingroup FileSystemTypesAndMount
+ *
+ * @brief Mount options for the Journalling Flash File System, Version 2
+ * (JFFS2).
+ *
+ * The application must provide flash device geometry information and flash
+ * device operations in the flash control structure
+ * @ref rtems_jffs2_flash_control.
+ *
+ * The application can optionally provide a compressor control structure to
+ * enable data compression using the selected compression algorithm.
+ *
+ * The application must enable JFFS2 support with rtems_filesystem_register()
+ * or CONFIGURE_FILESYSTEM_JFFS2 via <rtems/confdefs.h>.
+ *
+ * An example mount with a simple memory based flash device simulation follows.
+ * The zlib is used for as the compressor.
+ *
+ * @code
+ * #include <string.h>
+ *
+ * #include <rtems/jffs2.h>
+ * #include <rtems/libio.h>
+ *
+ * #define BLOCK_SIZE (32UL * 1024UL)
+ *
+ * #define FLASH_SIZE (32UL * BLOCK_SIZE)
+ *
+ * typedef struct {
+ *   rtems_jffs2_flash_control super;
+ *   unsigned char area[FLASH_SIZE];
+ * } flash_control;
+ *
+ * static flash_control *get_flash_control(rtems_jffs2_flash_control *super)
+ * {
+ *   return (flash_control *) super;
+ * }
+ *
+ * static int flash_read(
+ *   rtems_jffs2_flash_control *super,
+ *   uint32_t offset,
+ *   unsigned char *buffer,
+ *   size_t size_of_buffer
+ * )
+ * {
+ *   flash_control *self = get_flash_control(super);
+ *   unsigned char *chunk = &self->area[offset];
+ *
+ *   memcpy(buffer, chunk, size_of_buffer);
+ *
+ *   return 0;
+ * }
+ *
+ * static int flash_write(
+ *   rtems_jffs2_flash_control *super,
+ *   uint32_t offset,
+ *   const unsigned char *buffer,
+ *   size_t size_of_buffer
+ * )
+ * {
+ *   flash_control *self = get_flash_control(super);
+ *   unsigned char *chunk = &self->area[offset];
+ *   size_t i;
+ *
+ *   for (i = 0; i < size_of_buffer; ++i) {
+ *     chunk[i] &= buffer[i];
+ *   }
+ *
+ *   return 0;
+ * }
+ *
+ * static int flash_erase(
+ *   rtems_jffs2_flash_control *super,
+ *   uint32_t offset
+ * )
+ * {
+ *   flash_control *self = get_flash_control(super);
+ *   unsigned char *chunk = &self->area[offset];
+ *
+ *   memset(chunk, 0xff, BLOCK_SIZE);
+ *
+ *   return 0;
+ * }
+ *
+ * static flash_control flash_instance = {
+ *   .super = {
+ *     .block_size = BLOCK_SIZE,
+ *     .flash_size = FLASH_SIZE,
+ *     .read = flash_read,
+ *     .write = flash_write,
+ *     .erase = flash_erase
+ *   }
+ * };
+ *
+ * static rtems_jffs2_compressor_zlib_control compressor_instance = {
+ *   .super = {
+ *     .compress = rtems_jffs2_compressor_zlib_compress,
+ *     .decompress = rtems_jffs2_compressor_zlib_decompress
+ *   }
+ * };
+ *
+ * static const rtems_jffs2_mount_data mount_data = {
+ *   .flash_control = &flash_instance.super,
+ *   .compressor_control = &compressor_instance.super
+ * };
+ *
+ * static void erase_all(void)
+ * {
+ *   memset(&flash_instance.area[0], 0xff, FLASH_SIZE);
+ * }
+ *
+ * void example_jffs2_mount(const char *mount_dir)
+ * {
+ *   int rv;
+ *
+ *   erase_all();
+ *
+ *   rv = mount_and_make_target_path(
+ *     NULL,
+ *     mount_dir,
+ *     RTEMS_FILESYSTEM_TYPE_JFFS2,
+ *     RTEMS_FILESYSTEM_READ_WRITE,
+ *     &mount_data
+ *   );
+ *   assert(rv == 0);
+ * }
+ * @endcode
+ *
+ * @{
+ */
+
+/**
+ * @brief Read from flash operation.
+ *
+ * @param[in, out] self The flash control.
+ * @param[in] offset The offset to read from the flash begin in bytes.
+ * @param[out] buffer The buffer receiving the data.
+ * @param[in] size_of_buffer The size of the buffer in bytes.
+ *
+ * @retval 0 Successful operation.
+ * @retval -EIO An error occurred.  Please note that the value is negative.
+ * @retval other All other values are reserved and must not be used.
+ */
+typedef int (*rtems_jffs2_flash_read)(
+  rtems_jffs2_flash_control *self,
+  uint32_t offset,
+  unsigned char *buffer,
+  size_t size_of_buffer
+);
+
+/**
+ * @brief Write to flash operation.
+ *
+ * @param[in, out] self The flash control.
+ * @param[in] offset The offset to write from the flash begin in bytes.
+ * @param[in] buffer The buffer containing the data to write.
+ * @param[in] size_of_buffer The size of the buffer in bytes.
+ *
+ * @retval 0 Successful operation.
+ * @retval -EIO An error occurred.  Please note that the value is negative.
+ * @retval other All other values are reserved and must not be used.
+ */
+typedef int (*rtems_jffs2_flash_write)(
+  rtems_jffs2_flash_control *self,
+  uint32_t offset,
+  const unsigned char *buffer,
+  size_t size_of_buffer
+);
+
+/**
+ * @brief Flash erase operation.
+ *
+ * This operation must erase one block specified by the offset.
+ *
+ * @param[in, out] self The flash control.
+ * @param[in] offset The offset to erase from the flash begin in bytes.
+ *
+ * @retval 0 Successful operation.
+ * @retval -EIO An error occurred.  Please note that the value is negative.
+ * @retval other All other values are reserved and must not be used.
+ */
+typedef int (*rtems_jffs2_flash_erase)(
+  rtems_jffs2_flash_control *self,
+  uint32_t offset
+);
+
+/**
+ * @brief Flash destroy operation.
+ *
+ * The flash destroy operation is called during unmount of the file system
+ * instance.  It can be used to free the resources associated with the now
+ * unused flash control
+ *
+ * @param[in, out] self The flash control.
+ */
+typedef void (*rtems_jffs2_flash_destroy)(
+  rtems_jffs2_flash_control *self
+);
+
+/**
+ * @brief JFFS2 flash device control.
+ */
+struct rtems_jffs2_flash_control {
+  /**
+   * @brief The size in bytes of the erasable unit of the flash device.
+   */
+  uint32_t block_size;
+
+  /**
+   * @brief The size in bytes of the flash device.
+   *
+   * It must be an integral multiple of the block size.  The flash device must
+   * have at least five blocks.
+   */
+  uint32_t flash_size;
+
+  /**
+   * @brief Read from flash operation.
+   */
+  rtems_jffs2_flash_read read;
+
+  /**
+   * @brief Write to flash operation.
+   */
+  rtems_jffs2_flash_write write;
+
+  /**
+   * @brief Flash erase operation.
+   */
+  rtems_jffs2_flash_erase erase;
+
+  /**
+   * @brief Flash destroy operation.
+   *
+   * This operation is optional and the pointer may be @c NULL.
+   */
+  rtems_jffs2_flash_destroy destroy;
+};
+
+typedef struct rtems_jffs2_compressor_control rtems_jffs2_compressor_control;
+
+/**
+ * @brief Compress operation.
+ *
+ * @param[in, out] self The compressor control.
+ * @param[in] data_in The uncompressed data.
+ * @param[out] cdata_out Pointer to buffer with the compressed data.
+ * @param[in, out] datalen On entry, the size in bytes of the uncompressed
+ * data.  On exit, the size in bytes of uncompressed data which was actually
+ * compressed.
+ * @param[in, out] cdatalen On entry, the size in bytes available for
+ * compressed data.  On exit, the size in bytes of the actually compressed
+ * data.
+ *
+ * @return The compressor type.
+ */
+typedef uint16_t (*rtems_jffs2_compressor_compress)(
+  rtems_jffs2_compressor_control *self,
+  unsigned char *data_in,
+  unsigned char *cdata_out,
+  uint32_t *datalen,
+  uint32_t *cdatalen
+);
+
+/**
+ * @brief Decompress operation.
+ *
+ * @param[in, out] self The compressor control.
+ * @param[in] comprtype The compressor type.
+ * @param[in] cdata_in The compressed data.
+ * @param[out] data_out The uncompressed data.
+ * @param[in] cdatalen The size in bytes of the compressed data.
+ * @param[in] datalen The size in bytes of the uncompressed data.
+ *
+ * @retval 0 Successful operation.
+ * @retval -EIO An error occurred.  Please note that the value is negative.
+ * @retval other All other values are reserved and must not be used.
+ */
+typedef int (*rtems_jffs2_compressor_decompress)(
+  rtems_jffs2_compressor_control *self,
+  uint16_t comprtype,
+  unsigned char *cdata_in,
+  unsigned char *data_out,
+  uint32_t cdatalen,
+  uint32_t datalen
+);
+
+/**
+ * @brief Compressor destroy operation.
+ *
+ * The compressor destroy operation is called during unmount of the file system
+ * instance.  It can be used to free the resources associated with the now
+ * unused compressor operations.
+ *
+ * @param[in, out] self The compressor control.
+ */
+typedef void (*rtems_jffs2_compressor_destroy)(
+  rtems_jffs2_compressor_control *self
+);
+
+/**
+ * @brief JFFS2 compressor control.
+ */
+struct rtems_jffs2_compressor_control {
+  /**
+   * @brief Compress operation.
+   */
+  rtems_jffs2_compressor_compress compress;
+
+  /**
+   * @brief Decompress operation.
+   */
+  rtems_jffs2_compressor_decompress decompress;
+
+  /**
+   * @brief Compressor destroy operation.
+   *
+   * This operation is optional and the pointer may be @c NULL.
+   */
+  rtems_jffs2_compressor_destroy destroy;
+
+  /**
+   * @brief Compression buffer.
+   */
+  unsigned char buffer[PAGE_SIZE];
+};
+
+/**
+ * @brief RTIME compressor compress operation.
+ */
+uint16_t rtems_jffs2_compressor_rtime_compress(
+  rtems_jffs2_compressor_control *self,
+  unsigned char *data_in,
+  unsigned char *cdata_out,
+  uint32_t *datalen,
+  uint32_t *cdatalen
+);
+
+/**
+ * @brief RTIME compressor decompress operation.
+ */
+int rtems_jffs2_compressor_rtime_decompress(
+  rtems_jffs2_compressor_control *self,
+  uint16_t comprtype,
+  unsigned char *cdata_in,
+  unsigned char *data_out,
+  uint32_t cdatalen,
+  uint32_t datalen
+);
+
+/**
+ * @brief ZLIB compressor control structure.
+ */
+typedef struct {
+  rtems_jffs2_compressor_control super;
+  z_stream stream;
+} rtems_jffs2_compressor_zlib_control;
+
+/**
+ * @brief ZLIB compressor compress operation.
+ */
+uint16_t rtems_jffs2_compressor_zlib_compress(
+  rtems_jffs2_compressor_control *self,
+  unsigned char *data_in,
+  unsigned char *cdata_out,
+  uint32_t *datalen,
+  uint32_t *cdatalen
+);
+
+/**
+ * @brief ZLIB compressor decompress operation.
+ */
+int rtems_jffs2_compressor_zlib_decompress(
+  rtems_jffs2_compressor_control *self,
+  uint16_t comprtype,
+  unsigned char *cdata_in,
+  unsigned char *data_out,
+  uint32_t cdatalen,
+  uint32_t datalen
+);
+
+/**
+ * @brief JFFS2 mount options.
+ *
+ * For JFFS2 the mount options are mandatory.
+ */
+typedef struct {
+  /**
+   * @brief Flash control.
+   */
+  rtems_jffs2_flash_control *flash_control;
+
+  /**
+   * @brief Compressor control.
+   *
+   * The compressor is optional and this pointer may be @c NULL.
+   */
+  rtems_jffs2_compressor_control *compressor_control;
+} rtems_jffs2_mount_data;
+
+/**
+ * @brief Initialization handler of the JFFS2 file system.
+ *
+ * @param[in, out] mt_entry The mount table entry.
+ * @param[in] data The mount options are mandatory for JFFS2 and data must
+ * point to a valid @ref rtems_jffs2_mount_data structure used for this file
+ * system instance.
+ *
+ * @retval 0 Successful operation.
+ * @retval -1 An error occurred.  The @c errno indicates the error.
+ *
+ * @see mount().
+ */
+int rtems_jffs2_initialize(
+  rtems_filesystem_mount_table_entry_t *mt_entry,
+  const void *data
+);
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* RTEMS_JFFS2_H */
diff --git a/cpukit/libfs/src/jffs2/src/compr.c b/cpukit/libfs/src/jffs2/src/compr.c
index 4849a4c..9859649 100644
--- a/cpukit/libfs/src/jffs2/src/compr.c
+++ b/cpukit/libfs/src/jffs2/src/compr.c
@@ -5,6 +5,7 @@
  * Copyright © 2004-2010 David Woodhouse <dwmw2 at infradead.org>
  * Copyright © 2004 Ferenc Havasi <havasi at inf.u-szeged.hu>,
  *		    University of Szeged, Hungary
+ * Copyright © 2013 embedded brains GmbH <rtems at embedded-brains.de>
  *
  * Created by Arjan van de Ven <arjan at infradead.org>
  *
@@ -16,117 +17,6 @@
 
 #include "compr.h"
 
-static DEFINE_SPINLOCK(jffs2_compressor_list_lock);
-
-/* Available compressors are on this list */
-static LIST_HEAD(jffs2_compressor_list);
-
-/* Actual compression mode */
-static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
-
-/* Statistics for blocks stored without compression */
-static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0;
-
-
-/*
- * Return 1 to use this compression
- */
-static int jffs2_is_best_compression(struct jffs2_compressor *this,
-		struct jffs2_compressor *best, uint32_t size, uint32_t bestsize)
-{
-	switch (jffs2_compression_mode) {
-	case JFFS2_COMPR_MODE_SIZE:
-		if (bestsize > size)
-			return 1;
-		return 0;
-	case JFFS2_COMPR_MODE_FAVOURLZO:
-		if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > size))
-			return 1;
-		if ((best->compr != JFFS2_COMPR_LZO) && (bestsize > size))
-			return 1;
-		if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > (size * FAVOUR_LZO_PERCENT / 100)))
-			return 1;
-		if ((bestsize * FAVOUR_LZO_PERCENT / 100) > size)
-			return 1;
-
-		return 0;
-	}
-	/* Shouldn't happen */
-	return 0;
-}
-
-/*
- * jffs2_selected_compress:
- * @compr: Explicit compression type to use (ie, JFFS2_COMPR_ZLIB).
- *	If 0, just take the first available compression mode.
- * @data_in: Pointer to uncompressed data
- * @cpage_out: Pointer to returned pointer to buffer for compressed data
- * @datalen: On entry, holds the amount of data available for compression.
- *	On exit, expected to hold the amount of data actually compressed.
- * @cdatalen: On entry, holds the amount of space available for compressed
- *	data. On exit, expected to hold the actual size of the compressed
- *	data.
- *
- * Returns: the compression type used.  Zero is used to show that the data
- * could not be compressed; probably because we couldn't find the requested
- * compression mode.
- */
-static int jffs2_selected_compress(u8 compr, unsigned char *data_in,
-		unsigned char **cpage_out, u32 *datalen, u32 *cdatalen)
-{
-	struct jffs2_compressor *this;
-	int err, ret = JFFS2_COMPR_NONE;
-	uint32_t orig_slen, orig_dlen;
-	char *output_buf;
-
-	output_buf = kmalloc(*cdatalen, GFP_KERNEL);
-	if (!output_buf) {
-		pr_warn("No memory for compressor allocation. Compression failed.\n");
-		return ret;
-	}
-	orig_slen = *datalen;
-	orig_dlen = *cdatalen;
-	spin_lock(&jffs2_compressor_list_lock);
-	list_for_each_entry(this, &jffs2_compressor_list, list) {
-		/* Skip decompress-only and disabled modules */
-		if (!this->compress || this->disabled)
-			continue;
-
-		/* Skip if not the desired compression type */
-		if (compr && (compr != this->compr))
-			continue;
-
-		/*
-		 * Either compression type was unspecified, or we found our
-		 * compressor; either way, we're good to go.
-		 */
-		this->usecount++;
-		spin_unlock(&jffs2_compressor_list_lock);
-
-		*datalen  = orig_slen;
-		*cdatalen = orig_dlen;
-		err = this->compress(data_in, output_buf, datalen, cdatalen);
-
-		spin_lock(&jffs2_compressor_list_lock);
-		this->usecount--;
-		if (!err) {
-			/* Success */
-			ret = this->compr;
-			this->stat_compr_blocks++;
-			this->stat_compr_orig_size += *datalen;
-			this->stat_compr_new_size += *cdatalen;
-			break;
-		}
-	}
-	spin_unlock(&jffs2_compressor_list_lock);
-	if (ret == JFFS2_COMPR_NONE)
-		kfree(output_buf);
-	else
-		*cpage_out = output_buf;
-
-	return ret;
-}
-
 /* jffs2_compress:
  * @data_in: Pointer to uncompressed data
  * @cpage_out: Pointer to returned pointer to buffer for compressed data
@@ -149,103 +39,20 @@ uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
 			unsigned char *data_in, unsigned char **cpage_out,
 			uint32_t *datalen, uint32_t *cdatalen)
 {
-	int ret = JFFS2_COMPR_NONE;
-	int mode, compr_ret;
-	struct jffs2_compressor *this, *best=NULL;
-	unsigned char *output_buf = NULL, *tmp_buf;
-	uint32_t orig_slen, orig_dlen;
-	uint32_t best_slen=0, best_dlen=0;
-
-	if (c->mount_opts.override_compr)
-		mode = c->mount_opts.compr;
-	else
-		mode = jffs2_compression_mode;
+	struct super_block *sb = OFNI_BS_2SFFJ(c);
+	rtems_jffs2_compressor_control *cc = sb->s_compressor_control;
+	int ret;
 
-	switch (mode) {
-	case JFFS2_COMPR_MODE_NONE:
-		break;
-	case JFFS2_COMPR_MODE_PRIORITY:
-		ret = jffs2_selected_compress(0, data_in, cpage_out, datalen,
-				cdatalen);
-		break;
-	case JFFS2_COMPR_MODE_SIZE:
-	case JFFS2_COMPR_MODE_FAVOURLZO:
-		orig_slen = *datalen;
-		orig_dlen = *cdatalen;
-		spin_lock(&jffs2_compressor_list_lock);
-		list_for_each_entry(this, &jffs2_compressor_list, list) {
-			/* Skip decompress-only backwards-compatibility and disabled modules */
-			if ((!this->compress)||(this->disabled))
-				continue;
-			/* Allocating memory for output buffer if necessary */
-			if ((this->compr_buf_size < orig_slen) && (this->compr_buf)) {
-				spin_unlock(&jffs2_compressor_list_lock);
-				kfree(this->compr_buf);
-				spin_lock(&jffs2_compressor_list_lock);
-				this->compr_buf_size=0;
-				this->compr_buf=NULL;
-			}
-			if (!this->compr_buf) {
-				spin_unlock(&jffs2_compressor_list_lock);
-				tmp_buf = kmalloc(orig_slen, GFP_KERNEL);
-				spin_lock(&jffs2_compressor_list_lock);
-				if (!tmp_buf) {
-					pr_warn("No memory for compressor allocation. (%d bytes)\n",
-						orig_slen);
-					continue;
-				}
-				else {
-					this->compr_buf = tmp_buf;
-					this->compr_buf_size = orig_slen;
-				}
-			}
-			this->usecount++;
-			spin_unlock(&jffs2_compressor_list_lock);
-			*datalen  = orig_slen;
-			*cdatalen = orig_dlen;
-			compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen);
-			spin_lock(&jffs2_compressor_list_lock);
-			this->usecount--;
-			if (!compr_ret) {
-				if (((!best_dlen) || jffs2_is_best_compression(this, best, *cdatalen, best_dlen))
-						&& (*cdatalen < *datalen)) {
-					best_dlen = *cdatalen;
-					best_slen = *datalen;
-					best = this;
-				}
-			}
-		}
-		if (best_dlen) {
-			*cdatalen = best_dlen;
-			*datalen  = best_slen;
-			output_buf = best->compr_buf;
-			best->compr_buf = NULL;
-			best->compr_buf_size = 0;
-			best->stat_compr_blocks++;
-			best->stat_compr_orig_size += best_slen;
-			best->stat_compr_new_size  += best_dlen;
-			ret = best->compr;
-			*cpage_out = output_buf;
-		}
-		spin_unlock(&jffs2_compressor_list_lock);
-		break;
-	case JFFS2_COMPR_MODE_FORCELZO:
-		ret = jffs2_selected_compress(JFFS2_COMPR_LZO, data_in,
-				cpage_out, datalen, cdatalen);
-		break;
-	case JFFS2_COMPR_MODE_FORCEZLIB:
-		ret = jffs2_selected_compress(JFFS2_COMPR_ZLIB, data_in,
-				cpage_out, datalen, cdatalen);
-		break;
-	default:
-		pr_err("unknown compression mode\n");
+	if (cc != NULL) {
+		*cpage_out = &cc->buffer[0];
+		ret = (*cc->compress)(cc, data_in, *cpage_out, datalen, cdatalen);
+	} else {
+		ret = JFFS2_COMPR_NONE;
 	}
 
 	if (ret == JFFS2_COMPR_NONE) {
 		*cpage_out = data_in;
 		*datalen = *cdatalen;
-		none_stat_compr_blocks++;
-		none_stat_compr_size += *datalen;
 	}
 	return ret;
 }
@@ -254,8 +61,8 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
 		     uint16_t comprtype, unsigned char *cdata_in,
 		     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen)
 {
-	struct jffs2_compressor *this;
-	int ret;
+	struct super_block *sb = OFNI_BS_2SFFJ(c);
+	rtems_jffs2_compressor_control *cc = sb->s_compressor_control;
 
 	/* Older code had a bug where it would write non-zero 'usercompr'
 	   fields. Deal with it. */
@@ -266,153 +73,16 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
 	case JFFS2_COMPR_NONE:
 		/* This should be special-cased elsewhere, but we might as well deal with it */
 		memcpy(data_out, cdata_in, datalen);
-		none_stat_decompr_blocks++;
 		break;
 	case JFFS2_COMPR_ZERO:
 		memset(data_out, 0, datalen);
 		break;
 	default:
-		spin_lock(&jffs2_compressor_list_lock);
-		list_for_each_entry(this, &jffs2_compressor_list, list) {
-			if (comprtype == this->compr) {
-				this->usecount++;
-				spin_unlock(&jffs2_compressor_list_lock);
-				ret = this->decompress(cdata_in, data_out, cdatalen, datalen);
-				spin_lock(&jffs2_compressor_list_lock);
-				if (ret) {
-					pr_warn("Decompressor \"%s\" returned %d\n",
-						this->name, ret);
-				}
-				else {
-					this->stat_decompr_blocks++;
-				}
-				this->usecount--;
-				spin_unlock(&jffs2_compressor_list_lock);
-				return ret;
-			}
-		}
-		pr_warn("compression type 0x%02x not available\n", comprtype);
-		spin_unlock(&jffs2_compressor_list_lock);
-		return -EIO;
-	}
-	return 0;
-}
-
-int jffs2_register_compressor(struct jffs2_compressor *comp)
-{
-	struct jffs2_compressor *this;
-
-	if (!comp->name) {
-		pr_warn("NULL compressor name at registering JFFS2 compressor. Failed.\n");
-		return -1;
-	}
-	comp->compr_buf_size=0;
-	comp->compr_buf=NULL;
-	comp->usecount=0;
-	comp->stat_compr_orig_size=0;
-	comp->stat_compr_new_size=0;
-	comp->stat_compr_blocks=0;
-	comp->stat_decompr_blocks=0;
-	jffs2_dbg(1, "Registering JFFS2 compressor \"%s\"\n", comp->name);
-
-	spin_lock(&jffs2_compressor_list_lock);
-
-	list_for_each_entry(this, &jffs2_compressor_list, list) {
-		if (this->priority < comp->priority) {
-			list_add(&comp->list, this->list.prev);
-			goto out;
+		if (cc != NULL) {
+			return (*cc->decompress)(cc, comprtype, cdata_in, data_out, cdatalen, datalen);
+		} else {
+			return -EIO;
 		}
 	}
-	list_add_tail(&comp->list, &jffs2_compressor_list);
-out:
-	D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
-		printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
-	})
-
-	spin_unlock(&jffs2_compressor_list_lock);
-
-	return 0;
-}
-
-int jffs2_unregister_compressor(struct jffs2_compressor *comp)
-{
-	D2(struct jffs2_compressor *this);
-
-	jffs2_dbg(1, "Unregistering JFFS2 compressor \"%s\"\n", comp->name);
-
-	spin_lock(&jffs2_compressor_list_lock);
-
-	if (comp->usecount) {
-		spin_unlock(&jffs2_compressor_list_lock);
-		pr_warn("Compressor module is in use. Unregister failed.\n");
-		return -1;
-	}
-	list_del(&comp->list);
-
-	D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
-		printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
-	})
-	spin_unlock(&jffs2_compressor_list_lock);
-	return 0;
-}
-
-void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
-{
-	if (orig != comprbuf)
-		kfree(comprbuf);
-}
-
-int __init jffs2_compressors_init(void)
-{
-/* Registering compressors */
-#ifdef CONFIG_JFFS2_ZLIB
-	jffs2_zlib_init();
-#endif
-#ifdef CONFIG_JFFS2_RTIME
-	jffs2_rtime_init();
-#endif
-#ifdef CONFIG_JFFS2_RUBIN
-	jffs2_rubinmips_init();
-	jffs2_dynrubin_init();
-#endif
-#ifdef CONFIG_JFFS2_LZO
-	jffs2_lzo_init();
-#endif
-/* Setting default compression mode */
-#ifdef CONFIG_JFFS2_CMODE_NONE
-	jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
-	jffs2_dbg(1, "default compression mode: none\n");
-#else
-#ifdef CONFIG_JFFS2_CMODE_SIZE
-	jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
-	jffs2_dbg(1, "default compression mode: size\n");
-#else
-#ifdef CONFIG_JFFS2_CMODE_FAVOURLZO
-	jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO;
-	jffs2_dbg(1, "default compression mode: favourlzo\n");
-#else
-	jffs2_dbg(1, "default compression mode: priority\n");
-#endif
-#endif
-#endif
-	return 0;
-}
-
-int jffs2_compressors_exit(void)
-{
-/* Unregistering compressors */
-#ifdef CONFIG_JFFS2_LZO
-	jffs2_lzo_exit();
-#endif
-#ifdef CONFIG_JFFS2_RUBIN
-	jffs2_dynrubin_exit();
-	jffs2_rubinmips_exit();
-#endif
-#ifdef CONFIG_JFFS2_RTIME
-	jffs2_rtime_exit();
-#endif
-#ifdef CONFIG_JFFS2_ZLIB
-	jffs2_zlib_exit();
-#endif
 	return 0;
 }
diff --git a/cpukit/libfs/src/jffs2/src/compr.h b/cpukit/libfs/src/jffs2/src/compr.h
index 5e91d57..e6226e7 100644
--- a/cpukit/libfs/src/jffs2/src/compr.h
+++ b/cpukit/libfs/src/jffs2/src/compr.h
@@ -78,7 +78,7 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
 		     uint16_t comprtype, unsigned char *cdata_in,
 		     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen);
 
-void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig);
+#define jffs2_free_comprbuf(x, y) do { } while (0)
 
 /* Compressor modules */
 /* These functions will be called by jffs2_compressors_init/exit */
diff --git a/cpukit/libfs/src/jffs2/src/compr_rtime.c b/cpukit/libfs/src/jffs2/src/compr_rtime.c
index 16a5047..3386d1e 100644
--- a/cpukit/libfs/src/jffs2/src/compr_rtime.c
+++ b/cpukit/libfs/src/jffs2/src/compr_rtime.c
@@ -28,15 +28,20 @@
 #include <linux/jffs2.h>
 #include "compr.h"
 
-/* _compress returns the compressed size, -1 if bigger */
-static int jffs2_rtime_compress(unsigned char *data_in,
-				unsigned char *cpage_out,
-				uint32_t *sourcelen, uint32_t *dstlen)
+uint16_t rtems_jffs2_compressor_rtime_compress(
+	rtems_jffs2_compressor_control *self,
+	unsigned char *data_in,
+	unsigned char *cpage_out,
+	uint32_t *sourcelen,
+	uint32_t *dstlen
+)
 {
 	short positions[256];
 	int outpos = 0;
 	int pos=0;
 
+	(void) self;
+
 	memset(positions,0,sizeof(positions));
 
 	while (pos < (*sourcelen) && outpos <= (*dstlen)-2) {
@@ -60,24 +65,35 @@ static int jffs2_rtime_compress(unsigned char *data_in,
 
 	if (outpos >= pos) {
 		/* We failed */
-		return -1;
+		return JFFS2_COMPR_NONE;
 	}
 
 	/* Tell the caller how much we managed to compress, and how much space it took */
 	*sourcelen = pos;
 	*dstlen = outpos;
-	return 0;
+	return JFFS2_COMPR_RTIME;
 }
 
 
-static int jffs2_rtime_decompress(unsigned char *data_in,
-				  unsigned char *cpage_out,
-				  uint32_t srclen, uint32_t destlen)
+int rtems_jffs2_compressor_rtime_decompress(
+	rtems_jffs2_compressor_control *self,
+	uint16_t comprtype,
+	unsigned char *data_in,
+	unsigned char *cpage_out,
+	uint32_t srclen,
+	uint32_t destlen
+)
 {
 	short positions[256];
 	int outpos = 0;
 	int pos=0;
 
+	(void) self;
+
+	if (comprtype != JFFS2_COMPR_RTIME) {
+		return -EIO;
+	}
+
 	memset(positions,0,sizeof(positions));
 
 	while (outpos<destlen) {
@@ -105,26 +121,3 @@ static int jffs2_rtime_decompress(unsigned char *data_in,
 	}
 	return 0;
 }
-
-static struct jffs2_compressor jffs2_rtime_comp = {
-    .priority = JFFS2_RTIME_PRIORITY,
-    .name = "rtime",
-    .compr = JFFS2_COMPR_RTIME,
-    .compress = &jffs2_rtime_compress,
-    .decompress = &jffs2_rtime_decompress,
-#ifdef JFFS2_RTIME_DISABLED
-    .disabled = 1,
-#else
-    .disabled = 0,
-#endif
-};
-
-int jffs2_rtime_init(void)
-{
-    return jffs2_register_compressor(&jffs2_rtime_comp);
-}
-
-void jffs2_rtime_exit(void)
-{
-    jffs2_unregister_compressor(&jffs2_rtime_comp);
-}
diff --git a/cpukit/libfs/src/jffs2/src/compr_zlib.c b/cpukit/libfs/src/jffs2/src/compr_zlib.c
index 0b9a1e4..8bfbacf 100644
--- a/cpukit/libfs/src/jffs2/src/compr_zlib.c
+++ b/cpukit/libfs/src/jffs2/src/compr_zlib.c
@@ -33,126 +33,115 @@
 
 static DEFINE_MUTEX(deflate_mutex);
 static DEFINE_MUTEX(inflate_mutex);
-static z_stream inf_strm, def_strm;
 
-#ifdef __KERNEL__ /* Linux-only */
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/mutex.h>
-
-static int __init alloc_workspaces(void)
-{
-	def_strm.workspace = vmalloc(zlib_deflate_workspacesize(MAX_WBITS,
-							MAX_MEM_LEVEL));
-	if (!def_strm.workspace)
-		return -ENOMEM;
-
-	jffs2_dbg(1, "Allocated %d bytes for deflate workspace\n",
-		  zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL));
-	inf_strm.workspace = vmalloc(zlib_inflate_workspacesize());
-	if (!inf_strm.workspace) {
-		vfree(def_strm.workspace);
-		return -ENOMEM;
-	}
-	jffs2_dbg(1, "Allocated %d bytes for inflate workspace\n",
-		  zlib_inflate_workspacesize());
-	return 0;
-}
-
-static void free_workspaces(void)
+static rtems_jffs2_compressor_zlib_control *get_zlib_control(
+	rtems_jffs2_compressor_control *super
+)
 {
-	vfree(def_strm.workspace);
-	vfree(inf_strm.workspace);
+	return (rtems_jffs2_compressor_zlib_control *) super;
 }
-#else
-#define alloc_workspaces() (0)
-#define free_workspaces() do { } while(0)
-#endif /* __KERNEL__ */
 
-static int jffs2_zlib_compress(unsigned char *data_in,
-			       unsigned char *cpage_out,
-			       uint32_t *sourcelen, uint32_t *dstlen)
+uint16_t rtems_jffs2_compressor_zlib_compress(
+	rtems_jffs2_compressor_control *super,
+	unsigned char *data_in,
+	unsigned char *cpage_out,
+	uint32_t *sourcelen,
+	uint32_t *dstlen
+)
 {
+	rtems_jffs2_compressor_zlib_control *self = get_zlib_control(super);
+	z_stream *def_strm = &self->stream;
 	int ret;
 
 	if (*dstlen <= STREAM_END_SPACE)
-		return -1;
+		return JFFS2_COMPR_NONE;
 
 	mutex_lock(&deflate_mutex);
 
-	if (Z_OK != zlib_deflateInit(&def_strm, 3)) {
+	if (Z_OK != zlib_deflateInit(def_strm, 3)) {
 		pr_warn("deflateInit failed\n");
 		mutex_unlock(&deflate_mutex);
-		return -1;
+		return JFFS2_COMPR_NONE;
 	}
 
-	def_strm.next_in = data_in;
-	def_strm.total_in = 0;
+	def_strm->next_in = data_in;
+	def_strm->total_in = 0;
 
-	def_strm.next_out = cpage_out;
-	def_strm.total_out = 0;
+	def_strm->next_out = cpage_out;
+	def_strm->total_out = 0;
 
-	while (def_strm.total_out < *dstlen - STREAM_END_SPACE && def_strm.total_in < *sourcelen) {
-		def_strm.avail_out = *dstlen - (def_strm.total_out + STREAM_END_SPACE);
-		def_strm.avail_in = min((unsigned)(*sourcelen-def_strm.total_in), def_strm.avail_out);
+	while (def_strm->total_out < *dstlen - STREAM_END_SPACE && def_strm->total_in < *sourcelen) {
+		def_strm->avail_out = *dstlen - (def_strm->total_out + STREAM_END_SPACE);
+		def_strm->avail_in = min((unsigned)(*sourcelen-def_strm->total_in), def_strm->avail_out);
 		jffs2_dbg(1, "calling deflate with avail_in %d, avail_out %d\n",
-			  def_strm.avail_in, def_strm.avail_out);
-		ret = zlib_deflate(&def_strm, Z_PARTIAL_FLUSH);
+			  def_strm->avail_in, def_strm->avail_out);
+		ret = zlib_deflate(def_strm, Z_PARTIAL_FLUSH);
 		jffs2_dbg(1, "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n",
-			  def_strm.avail_in, def_strm.avail_out,
-			  def_strm.total_in, def_strm.total_out);
+			  def_strm->avail_in, def_strm->avail_out,
+			  def_strm->total_in, def_strm->total_out);
 		if (ret != Z_OK) {
 			jffs2_dbg(1, "deflate in loop returned %d\n", ret);
-			zlib_deflateEnd(&def_strm);
+			zlib_deflateEnd(def_strm);
 			mutex_unlock(&deflate_mutex);
-			return -1;
+			return JFFS2_COMPR_NONE;
 		}
 	}
-	def_strm.avail_out += STREAM_END_SPACE;
-	def_strm.avail_in = 0;
-	ret = zlib_deflate(&def_strm, Z_FINISH);
-	zlib_deflateEnd(&def_strm);
+	def_strm->avail_out += STREAM_END_SPACE;
+	def_strm->avail_in = 0;
+	ret = zlib_deflate(def_strm, Z_FINISH);
+	zlib_deflateEnd(def_strm);
 
 	if (ret != Z_STREAM_END) {
 		jffs2_dbg(1, "final deflate returned %d\n", ret);
-		ret = -1;
+		ret = JFFS2_COMPR_NONE;
 		goto out;
 	}
 
-	if (def_strm.total_out >= def_strm.total_in) {
+	if (def_strm->total_out >= def_strm->total_in) {
 		jffs2_dbg(1, "zlib compressed %ld bytes into %ld; failing\n",
-			  def_strm.total_in, def_strm.total_out);
-		ret = -1;
+			  def_strm->total_in, def_strm->total_out);
+		ret = JFFS2_COMPR_NONE;
 		goto out;
 	}
 
 	jffs2_dbg(1, "zlib compressed %ld bytes into %ld\n",
-		  def_strm.total_in, def_strm.total_out);
+		  def_strm->total_in, def_strm->total_out);
 
-	*dstlen = def_strm.total_out;
-	*sourcelen = def_strm.total_in;
-	ret = 0;
+	*dstlen = def_strm->total_out;
+	*sourcelen = def_strm->total_in;
+	ret = JFFS2_COMPR_ZLIB;
  out:
 	mutex_unlock(&deflate_mutex);
 	return ret;
 }
 
-static int jffs2_zlib_decompress(unsigned char *data_in,
-				 unsigned char *cpage_out,
-				 uint32_t srclen, uint32_t destlen)
+int rtems_jffs2_compressor_zlib_decompress(
+	rtems_jffs2_compressor_control *super,
+	uint16_t comprtype,
+	unsigned char *data_in,
+	unsigned char *cpage_out,
+	uint32_t srclen,
+	uint32_t destlen
+)
 {
+	rtems_jffs2_compressor_zlib_control *self = get_zlib_control(super);
+	z_stream *inf_strm = &self->stream;
 	int ret;
 	int wbits = MAX_WBITS;
 
+	if (comprtype != JFFS2_COMPR_ZLIB) {
+		return -EIO;
+	}
+
 	mutex_lock(&inflate_mutex);
 
-	inf_strm.next_in = data_in;
-	inf_strm.avail_in = srclen;
-	inf_strm.total_in = 0;
+	inf_strm->next_in = data_in;
+	inf_strm->avail_in = srclen;
+	inf_strm->total_in = 0;
 
-	inf_strm.next_out = cpage_out;
-	inf_strm.avail_out = destlen;
-	inf_strm.total_out = 0;
+	inf_strm->next_out = cpage_out;
+	inf_strm->avail_out = destlen;
+	inf_strm->total_out = 0;
 
 	/* If it's deflate, and it's got no preset dictionary, then
 	   we can tell zlib to skip the adler32 check. */
@@ -162,60 +151,26 @@ static int jffs2_zlib_decompress(unsigned char *data_in,
 
 		jffs2_dbg(2, "inflate skipping adler32\n");
 		wbits = -((data_in[0] >> 4) + 8);
-		inf_strm.next_in += 2;
-		inf_strm.avail_in -= 2;
+		inf_strm->next_in += 2;
+		inf_strm->avail_in -= 2;
 	} else {
 		/* Let this remain D1 for now -- it should never happen */
 		jffs2_dbg(1, "inflate not skipping adler32\n");
 	}
 
 
-	if (Z_OK != zlib_inflateInit2(&inf_strm, wbits)) {
+	if (Z_OK != zlib_inflateInit2(inf_strm, wbits)) {
 		pr_warn("inflateInit failed\n");
 		mutex_unlock(&inflate_mutex);
-		return 1;
+		return -EIO;
 	}
 
-	while((ret = zlib_inflate(&inf_strm, Z_FINISH)) == Z_OK)
+	while((ret = zlib_inflate(inf_strm, Z_FINISH)) == Z_OK)
 		;
 	if (ret != Z_STREAM_END) {
 		pr_notice("inflate returned %d\n", ret);
 	}
-	zlib_inflateEnd(&inf_strm);
+	zlib_inflateEnd(inf_strm);
 	mutex_unlock(&inflate_mutex);
 	return 0;
 }
-
-static struct jffs2_compressor jffs2_zlib_comp = {
-    .priority = JFFS2_ZLIB_PRIORITY,
-    .name = "zlib",
-    .compr = JFFS2_COMPR_ZLIB,
-    .compress = &jffs2_zlib_compress,
-    .decompress = &jffs2_zlib_decompress,
-#ifdef JFFS2_ZLIB_DISABLED
-    .disabled = 1,
-#else
-    .disabled = 0,
-#endif
-};
-
-int __init jffs2_zlib_init(void)
-{
-    int ret;
-
-    ret = alloc_workspaces();
-    if (ret)
-	    return ret;
-
-    ret = jffs2_register_compressor(&jffs2_zlib_comp);
-    if (ret)
-	    free_workspaces();
-
-    return ret;
-}
-
-void jffs2_zlib_exit(void)
-{
-    jffs2_unregister_compressor(&jffs2_zlib_comp);
-    free_workspaces();
-}
diff --git a/cpukit/libfs/src/jffs2/src/debug.h b/cpukit/libfs/src/jffs2/src/debug.h
index 4fd9be4..6c905b3 100644
--- a/cpukit/libfs/src/jffs2/src/debug.h
+++ b/cpukit/libfs/src/jffs2/src/debug.h
@@ -75,6 +75,7 @@ do {						\
 #define JFFS2_DBG_MSG_PREFIX	JFFS2_DBG JFFS2_DBG_PREFIX
 
 /* JFFS2 message macros */
+#ifndef __rtems__
 #define JFFS2_ERROR(fmt, ...)					\
 	pr_err("error: (%d) %s: " fmt,				\
 	       task_pid_nr(current), __func__, ##__VA_ARGS__)
@@ -90,6 +91,23 @@ do {						\
 #define JFFS2_DEBUG(fmt, ...)						\
 	printk(KERN_DEBUG "[JFFS2 DBG] (%d) %s: " fmt,			\
 	       task_pid_nr(current), __func__, ##__VA_ARGS__)
+#else /* __rtems__ */
+#define JFFS2_ERROR(fmt, ...)					\
+	pr_err("error: %s: " fmt,				\
+	       __func__, ##__VA_ARGS__)
+
+#define JFFS2_WARNING(fmt, ...)						\
+	pr_warn("warning: %s: " fmt,				\
+		__func__, ##__VA_ARGS__)
+
+#define JFFS2_NOTICE(fmt, ...)						\
+	pr_notice("notice: %s: " fmt,				\
+		  __func__, ##__VA_ARGS__)
+
+#define JFFS2_DEBUG(fmt, ...)						\
+	printk(KERN_DEBUG "[JFFS2 DBG] %s: " fmt,			\
+	       __func__, ##__VA_ARGS__)
+#endif /* __rtems__ */
 
 /*
  * We split our debugging messages on several parts, depending on the JFFS2
diff --git a/cpukit/libfs/src/jffs2/src/dir-rtems.c b/cpukit/libfs/src/jffs2/src/dir-rtems.c
index 16b62cc..d1d67d7 100644
--- a/cpukit/libfs/src/jffs2/src/dir-rtems.c
+++ b/cpukit/libfs/src/jffs2/src/dir-rtems.c
@@ -1,10 +1,15 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Free Software Foundation, Inc.
+ * Copyright © 2001-2003 Free Software Foundation, Inc.
+ * Copyright © 2001-2007 Red Hat, Inc.
+ * Copyright © 2004-2010 David Woodhouse <dwmw2 at infradead.org>
+ * Copyright © 2013 embedded brains GmbH <rtems at embedded-brains.de>
  *
  * Created by David Woodhouse <dwmw2 at cambridge.redhat.com>
  *
+ * Port to the RTEMS by embedded brains GmbH.
+ *
  * 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 $
@@ -21,7 +26,6 @@
 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);
@@ -30,9 +34,8 @@ struct _inode *jffs2_lookup(struct _inode *dir_i, const unsigned char *d_name, i
 	D1(printk("jffs2_lookup()\n"));
 
 	dir_f = JFFS2_INODE_INFO(dir_i);
-	c = JFFS2_SB_INFO(dir_i->i_sb);
 
-	down(&dir_f->sem);
+	mutex_lock(&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) {
@@ -45,12 +48,14 @@ struct _inode *jffs2_lookup(struct _inode *dir_i, const unsigned char *d_name, i
 	}
 	if (fd)
 		ino = fd->ino;
-	up(&dir_f->sem);
+	mutex_unlock(&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;
+		} else {
+			inode->i_fd = fd;
 		}
 	}
 
@@ -61,14 +66,17 @@ struct _inode *jffs2_lookup(struct _inode *dir_i, const unsigned char *d_name, i
 
 
 
-int jffs2_create(struct _inode *dir_i, const unsigned char *d_name, int mode,
-                 struct _inode **new_i)
+int jffs2_create(struct _inode *dir_i, const char *d_name, int namelen, int mode)
 {
 	struct jffs2_raw_inode *ri;
 	struct jffs2_inode_info *f, *dir_f;
 	struct jffs2_sb_info *c;
 	struct _inode *inode;
 	int ret;
+	struct qstr qstr;
+
+	qstr.name = d_name;
+	qstr.len = namelen;
 
 	ri = jffs2_alloc_raw_inode();
 	if (!ri)
@@ -89,9 +97,7 @@ int jffs2_create(struct _inode *dir_i, const unsigned char *d_name, int mode,
 	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));
+	ret = jffs2_do_create(c, dir_f, f, ri, &qstr);
 
 	if (ret) {
 		inode->i_nlink = 0;
@@ -100,34 +106,36 @@ int jffs2_create(struct _inode *dir_i, const unsigned char *d_name, int mode,
 		return ret;
 	}
 
+	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime));
+
 	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;
+		  inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->pino_nlink));
+	jffs2_iput(inode);
 	return 0;
 }
 
 /***********************************************************************/
 
 
-int jffs2_unlink(struct _inode *dir_i, struct _inode *d_inode, const unsigned char *d_name)
+int jffs2_unlink(struct _inode *dir_i, struct _inode *d_inode, const unsigned char *d_name, size_t d_namelen)
 {
 	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);
+	ret = jffs2_do_unlink(c, dir_f, (const char *)d_name,
+			       d_namelen, dead_f, get_seconds());
 	if (dead_f->inocache)
-		d_inode->i_nlink = dead_f->inocache->nlink;
+		d_inode->i_nlink = dead_f->inocache->pino_nlink;
 	return ret;
 }
 /***********************************************************************/
 
 
-int jffs2_link (struct _inode *old_d_inode, struct _inode *dir_i, const unsigned char *d_name)
+int jffs2_link (struct _inode *old_d_inode, struct _inode *dir_i, const unsigned char *d_name, size_t d_namelen)
 {
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(old_d_inode->i_sb);
 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_d_inode);
@@ -140,17 +148,26 @@ int jffs2_link (struct _inode *old_d_inode, struct _inode *dir_i, const unsigned
 
 	ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, 
                             (const char * )d_name, 
-                            strlen((char *)d_name));
+                            d_namelen, get_seconds());
 
 	if (!ret) {
-		down(&f->sem);
-		old_d_inode->i_nlink = ++f->inocache->nlink;
-		up(&f->sem);
+		mutex_lock(&f->sem);
+		old_d_inode->i_nlink = ++f->inocache->pino_nlink;
+		mutex_unlock(&f->sem);
 	}
 	return ret;
 }
 
-int jffs2_mkdir (struct _inode *dir_i, const unsigned char *d_name, int mode)
+/***********************************************************************/
+
+int jffs2_mknod(
+	struct _inode *dir_i,
+	const unsigned char *d_name,
+	size_t d_namelen,
+	int mode,
+	const unsigned char *data,
+	size_t datalen
+)
 {
 	struct jffs2_inode_info *f, *dir_f;
 	struct jffs2_sb_info *c;
@@ -159,23 +176,26 @@ int jffs2_mkdir (struct _inode *dir_i, const unsigned char *d_name, int mode)
 	struct jffs2_raw_dirent *rd;
 	struct jffs2_full_dnode *fn;
 	struct jffs2_full_dirent *fd;
-	int namelen;
-	uint32_t alloclen, phys_ofs;
+	uint32_t alloclen;
 	int ret;
 
-	mode |= S_IFDIR;
+	/* FIXME: If you care. We'd need to use frags for the data
+	   if it grows much more than this */
+	if (datalen > 254)
+		return -ENAMETOOLONG;
 
 	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 
+	/* 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);
+	ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &alloclen,
+				  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
 
 	if (ret) {
 		jffs2_free_raw_inode(ri);
@@ -192,104 +212,132 @@ int jffs2_mkdir (struct _inode *dir_i, const unsigned char *d_name, int mode)
 
 	f = JFFS2_INODE_INFO(inode);
 
-	ri->data_crc = cpu_to_je32(0);
+	inode->i_size = datalen;
+	ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size);
+	ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size);
+	ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
+
+	ri->compr = JFFS2_COMPR_NONE;
+	ri->data_crc = cpu_to_je32(crc32(0, data, datalen));
 	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);
+
+	fn = jffs2_write_dnode(c, f, ri, data, datalen, ALLOC_NORMAL);
 
 	jffs2_free_raw_inode(ri);
 
 	if (IS_ERR(fn)) {
 		/* Eeek. Wave bye bye */
-		up(&f->sem);
+		mutex_unlock(&f->sem);
 		jffs2_complete_reservation(c);
-		inode->i_nlink = 0;
-		jffs2_iput(inode);
-		return PTR_ERR(fn);
+		ret = PTR_ERR(fn);
+		goto fail;
+	}
+
+	if (S_ISLNK(mode)) {
+		/* We use f->target field to store the target path. */
+		f->target = kmemdup(data, datalen + 1, GFP_KERNEL);
+		if (!f->target) {
+			pr_warn("Can't allocate %d bytes of memory\n", datalen + 1);
+			mutex_unlock(&f->sem);
+			jffs2_complete_reservation(c);
+			ret = -ENOMEM;
+			goto fail;
+		}
+
+		jffs2_dbg(1, "%s(): symlink's target '%s' cached\n",
+			  __func__, (char *)f->target);
 	}
-	/* No data here. Only a metadata node, which will be 
+
+	/* No data here. Only a metadata node, which will be
 	   obsoleted by the first data write
 	*/
 	f->metadata = fn;
-	up(&f->sem);
+	mutex_unlock(&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;
-	}
-	
+
+	ret = jffs2_reserve_space(c, sizeof(*rd)+d_namelen, &alloclen,
+				  ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(d_namelen));
+	if (ret)
+		goto fail;
+
 	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;
+		ret = -ENOMEM;
+		goto fail;
 	}
 
 	dir_f = JFFS2_INODE_INFO(dir_i);
-	down(&dir_f->sem);
+	mutex_lock(&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->totlen = cpu_to_je32(sizeof(*rd) + d_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->mctime = cpu_to_je32(get_seconds());
+	rd->nsize = d_namelen;
+
+	/* XXX: This is ugly. */
+	rd->type = (mode & S_IFMT) >> 12;
+
 	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
-	rd->name_crc = cpu_to_je32(crc32(0, d_name, namelen));
+	rd->name_crc = cpu_to_je32(crc32(0, d_name, d_namelen));
+
+	fd = jffs2_write_dirent(c, dir_f, rd, d_name, d_namelen, ALLOC_NORMAL);
 
-	fd = jffs2_write_dirent(c, dir_f, rd, d_name, namelen, phys_ofs, ALLOC_NORMAL);
-	
-	jffs2_complete_reservation(c);
-	jffs2_free_raw_dirent(rd);
-	
 	if (IS_ERR(fd)) {
-		/* dirent failed to write. Delete the inode normally 
+		/* 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);
+		jffs2_complete_reservation(c);
+		jffs2_free_raw_dirent(rd);
+		mutex_unlock(&dir_f->sem);
+		ret = PTR_ERR(fd);
+		goto fail;
 	}
 
+	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
+
+	jffs2_free_raw_dirent(rd);
+
 	/* 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);
 
+	mutex_unlock(&dir_f->sem);
+	jffs2_complete_reservation(c);
+
+ fail:
 	jffs2_iput(inode);
-	return 0;
+
+	return ret;
 }
 
-int jffs2_rmdir (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, size_t d_namelen)
 {
 	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 -ENOTEMPTY;
 	}
-	return jffs2_unlink(dir_i, d_inode, d_name);
+	return jffs2_unlink(dir_i, d_inode, d_name, d_namelen);
 }
 
-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 jffs2_rename (struct _inode *old_dir_i, struct _inode *d_inode, const unsigned char *old_d_name, size_t old_d_namelen,
+		  struct _inode *new_dir_i, const unsigned char *new_d_name, size_t new_d_namelen)
 {
 	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;
+	uint32_t now;
 
 #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 */
@@ -309,14 +357,14 @@ int jffs2_rename (struct _inode *old_dir_i, struct _inode *d_inode, const unsign
 				/* Cannot rename non-directory over directory */
 				return -EINVAL;
 			}
-			down(&victim_f->sem);
+			mutex_lock(&victim_f->sem);
 			for (fd = victim_f->dents; fd; fd = fd->next) {
 				if (fd->ino) {
-					up(&victim_f->sem);
+					mutex_unlock(&victim_f->sem);
 					return -ENOTEMPTY;
 				}
 			}
-			up(&victim_f->sem);
+			mutex_unlock(&victim_f->sem);
 		}
 	}
 #endif
@@ -332,10 +380,11 @@ int jffs2_rename (struct _inode *old_dir_i, struct _inode *d_inode, const unsign
 	type = (d_inode->i_mode & S_IFMT) >> 12;
 	if (!type) type = DT_REG;
 
-	ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), 
+	now = get_seconds();
+	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));
+			    (const char *)new_d_name,
+                            new_d_namelen, now);
 
 	if (ret)
 		return ret;
@@ -345,24 +394,24 @@ int jffs2_rename (struct _inode *old_dir_i, struct _inode *d_inode, const unsign
 		/* 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);
+			mutex_lock(&victim_f->sem);
+			victim_f->inocache->pino_nlink--;
+			mutex_unlock(&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);
+	ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
+                              (const char *)old_d_name,
+                              old_d_namelen, NULL, now);
 
 	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);
+		mutex_lock(&f->sem);
 		if (f->inocache)
-			d_inode->i_nlink = f->inocache->nlink++;
-		up(&f->sem);
+			d_inode->i_nlink = f->inocache->pino_nlink++;
+		mutex_unlock(&f->sem);
 
 		printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret);
 	}
diff --git a/cpukit/libfs/src/jffs2/src/erase.c b/cpukit/libfs/src/jffs2/src/erase.c
index 4a6cf28..d0d8a69 100644
--- a/cpukit/libfs/src/jffs2/src/erase.c
+++ b/cpukit/libfs/src/jffs2/src/erase.c
@@ -391,7 +391,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
 
 		*bad_offset = ofs;
 
-		ret = mtd_read(c->mtd, ofs, readlen, &retlen, ebuf);
+		ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf);
 		if (ret) {
 			pr_warn("Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n",
 				ofs, ret);
diff --git a/cpukit/libfs/src/jffs2/src/flashio.c b/cpukit/libfs/src/jffs2/src/flashio.c
index 13a12e3..af93168 100644
--- a/cpukit/libfs/src/jffs2/src/flashio.c
+++ b/cpukit/libfs/src/jffs2/src/flashio.c
@@ -15,46 +15,28 @@
 #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,
+int 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);
+	const struct super_block *sb = OFNI_BS_2SFFJ(c);
+	rtems_jffs2_flash_control *fc = sb->s_flash_control;
 
-	//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;
 
-	*return_size = (size_t) len;
-	return ((err == ENOERR) ? ENOERR : -EIO);
+	return (*fc->read)(fc, read_buffer_offset, write_buffer, size);
 }
 
-cyg_bool jffs2_flash_write(struct jffs2_sb_info * c,
+int 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)
 {
+	const struct super_block *sb = OFNI_BS_2SFFJ(c);
+	rtems_jffs2_flash_control *fc = sb->s_flash_control;
 
-	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_size = size;
 
-	return ((err == ENOERR) ? ENOERR : -EIO);
+	return (*fc->write)(fc, write_buffer_offset, read_buffer, size);
 }
 
 int
@@ -140,26 +122,12 @@ jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct iovec *vecs,
 	return ret;
 }
 
-cyg_bool jffs2_flash_erase(struct jffs2_sb_info * c,
+int 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);
+	const struct super_block *sb = OFNI_BS_2SFFJ(c);
+	rtems_jffs2_flash_control *fc = sb->s_flash_control;
 
-	return (err != ENOERR || e.flasherr != 0);
+	return (*fc->erase)(fc, jeb->offset);
 }
 
diff --git a/cpukit/libfs/src/jffs2/src/fs-rtems.c b/cpukit/libfs/src/jffs2/src/fs-rtems.c
index c38b719..f274ead 100644
--- a/cpukit/libfs/src/jffs2/src/fs-rtems.c
+++ b/cpukit/libfs/src/jffs2/src/fs-rtems.c
@@ -1,11 +1,16 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Free Software Foundation, Inc.
+ * Copyright © 2001-2003 Free Software Foundation, Inc.
+ * Copyright © 2001-2007 Red Hat, Inc.
+ * Copyright © 2004-2010 David Woodhouse <dwmw2 at infradead.org>
+ * Copyright © 2013 embedded brains GmbH <rtems at embedded-brains.de>
  *
  * Created by Dominic Ostrowski <dominic.ostrowski at 3glab.com>
  * Contributors: David Woodhouse, Nick Garnett, Richard Panton.
  *
+ * Port to the RTEMS by embedded brains GmbH.
+ *
  * 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 $
@@ -19,164 +24,11 @@
 #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);
-
+#include <assert.h>
+#include <rtems/libio_.h>
 
 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
@@ -214,1550 +66,1157 @@ static void icache_evict(struct _inode *root_i, struct _inode *i)
 	}
 }
 
-//==========================================================================
-// 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)
+// jffs2_fo_write()
+// Write data to file.
+static int jffs2_extend_file (struct _inode *inode, struct jffs2_raw_inode *ri,
+		       unsigned long offset)
 {
-	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;
+	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 alloc_len;
+	int ret = 0;
 
-	// update name in dirsearch object
-	ds->name = name;
-	ds->namelen = namelen;
+	/* 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));
 
-	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;
-		}
+	ret = jffs2_reserve_space(c, sizeof(*ri), &alloc_len, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
+	if (ret)
+		return ret;
 
-	// Here we have the name and its length set up.
-	// Search the directory for a matching entry
+	mutex_lock(&f->sem);
 
-	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));
+	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));
 
-	if (d == NULL)
-		return ENOENT;
-	if (IS_ERR(d))
-		return -PTR_ERR(d);
+	ri->version = cpu_to_je32(++f->highest_version);
+	ri->isize = cpu_to_je32(max((uint32_t)inode->i_size, offset));
 
-	// 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++;
+	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, ALLOC_NORMAL);
+	jffs2_complete_reservation(c);
+	if (IS_ERR(fn)) {
+		ret = PTR_ERR(fn);
+		mutex_unlock(&f->sem);
+		return ret;
 	}
-
-	// 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;
+	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;
 	}
-
-	// 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
+	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);
+		mutex_unlock(&f->sem);
+		return ret;
 	}
+	inode->i_size = offset;
+	mutex_unlock(&f->sem);
+	return 0;
 }
 
-//==========================================================================
-// Pathconf support
-// This function provides support for pathconf() and fpathconf().
-
-static int jffs2_pathconf(struct _inode *node, struct cyg_pathconf_info *info)
+static int jffs2_do_setattr (struct _inode *inode, struct iattr *iattr)
 {
-	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;
+	struct jffs2_full_dnode *old_metadata, *new_metadata;
+	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+	struct jffs2_raw_inode *ri;
+	unsigned char *mdata = NULL;
+	int mdatalen = 0;
+	unsigned int ivalid;
+	uint32_t alloclen;
+	int ret;
+	int alloc_type = ALLOC_NORMAL;
 
-	case _PC_MAX_INPUT:
-		info->value = -1;	// not supported
-		err = EINVAL;
-		break;
+	jffs2_dbg(1, "%s(): ino #%lu\n", __func__, inode->i_ino);
 
-	case _PC_NAME_MAX:
-		info->value = NAME_MAX;
-		break;
+	/* Special cases - we don't want more than one data node
+	   for these types on the medium at any time. So setattr
+	   must read the original data associated with the node
+	   (i.e. the device numbers or the target name) and write
+	   it out again with the appropriate data attached */
+	if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
+		return -EIO;
+	} else if (S_ISLNK(inode->i_mode)) {
+		mutex_lock(&f->sem);
+		mdatalen = f->metadata->size;
+		mdata = kmalloc(f->metadata->size, GFP_USER);
+		if (!mdata) {
+			mutex_unlock(&f->sem);
+			return -ENOMEM;
+		}
+		ret = jffs2_read_dnode(c, f, f->metadata, mdata, 0, mdatalen);
+		if (ret) {
+			mutex_unlock(&f->sem);
+			kfree(mdata);
+			return ret;
+		}
+		mutex_unlock(&f->sem);
+		jffs2_dbg(1, "%s(): Writing %d bytes of symlink target\n",
+			  __func__, mdatalen);
+	}
 
-	case _PC_PATH_MAX:
-		info->value = PATH_MAX;
-		break;
+	ri = jffs2_alloc_raw_inode();
+	if (!ri) {
+		if (S_ISLNK(inode->i_mode))
+			kfree(mdata);
+		return -ENOMEM;
+	}
 
-	case _PC_PIPE_BUF:
-		info->value = -1;	// not supported
-		err = EINVAL;
-		break;
+	ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &alloclen,
+				  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
+	if (ret) {
+		jffs2_free_raw_inode(ri);
+		if (S_ISLNK(inode->i_mode))
+			 kfree(mdata);
+		return ret;
+	}
+	mutex_lock(&f->sem);
+	ivalid = iattr->ia_valid;
 
-	case _PC_ASYNC_IO:
-		info->value = -1;	// not supported
-		err = EINVAL;
-		break;
+	ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+	ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen);
+	ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
 
-	case _PC_CHOWN_RESTRICTED:
-		info->value = -1;	// not supported
-		err = EINVAL;
-		break;
+	ri->ino = cpu_to_je32(inode->i_ino);
+	ri->version = cpu_to_je32(++f->highest_version);
 
-	case _PC_NO_TRUNC:
-		info->value = 0;
-		break;
+	ri->uid = cpu_to_je16((ivalid & ATTR_UID)?
+		from_kuid(&init_user_ns, iattr->ia_uid):i_uid_read(inode));
+	ri->gid = cpu_to_je16((ivalid & ATTR_GID)?
+		from_kgid(&init_user_ns, iattr->ia_gid):i_gid_read(inode));
 
-	case _PC_PRIO_IO:
-		info->value = 0;
-		break;
+	if (ivalid & ATTR_MODE)
+		ri->mode = cpu_to_jemode(iattr->ia_mode);
+	else
+		ri->mode = cpu_to_jemode(inode->i_mode);
 
-	case _PC_SYNC_IO:
-		info->value = 0;
-		break;
 
-	case _PC_VDISABLE:
-		info->value = -1;	// not supported
-		err = EINVAL;
-		break;
+	ri->isize = cpu_to_je32((ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size);
+	ri->atime = cpu_to_je32(I_SEC((ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime));
+	ri->mtime = cpu_to_je32(I_SEC((ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime));
+	ri->ctime = cpu_to_je32(I_SEC((ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime));
 
-	default:
-		err = EINVAL;
-		break;
+	ri->offset = cpu_to_je32(0);
+	ri->csize = ri->dsize = cpu_to_je32(mdatalen);
+	ri->compr = JFFS2_COMPR_NONE;
+	if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
+		/* It's an extension. Make it a hole node */
+		ri->compr = JFFS2_COMPR_ZERO;
+		ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size);
+		ri->offset = cpu_to_je32(inode->i_size);
+	} else if (ivalid & ATTR_SIZE && !iattr->ia_size) {
+		/* For truncate-to-zero, treat it as deletion because
+		   it'll always be obsoleting all previous nodes */
+		alloc_type = ALLOC_DELETION;
 	}
+	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
+	if (mdatalen)
+		ri->data_crc = cpu_to_je32(crc32(0, mdata, mdatalen));
+	else
+		ri->data_crc = cpu_to_je32(0);
 
-	return err;
-}
+	new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, alloc_type);
+	if (S_ISLNK(inode->i_mode))
+		kfree(mdata);
 
-//==========================================================================
-// Filesystem operations
+	if (IS_ERR(new_metadata)) {
+		jffs2_complete_reservation(c);
+		jffs2_free_raw_inode(ri);
+		mutex_unlock(&f->sem);
+		return PTR_ERR(new_metadata);
+	}
+	/* It worked. Update the inode */
+	inode->i_atime = ITIME(je32_to_cpu(ri->atime));
+	inode->i_ctime = ITIME(je32_to_cpu(ri->ctime));
+	inode->i_mtime = ITIME(je32_to_cpu(ri->mtime));
+	inode->i_mode = jemode_to_cpu(ri->mode);
+	i_uid_write(inode, je16_to_cpu(ri->uid));
+	i_gid_write(inode, je16_to_cpu(ri->gid));
 
-// -------------------------------------------------------------------------
-// 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"));
+	old_metadata = f->metadata;
 
-	c = JFFS2_SB_INFO(sb);
+	if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size)
+		jffs2_truncate_fragtree (c, &f->fragtree, iattr->ia_size);
 
-	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;
+	if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
+		jffs2_add_full_dnode_to_inode(c, f, new_metadata);
+		inode->i_size = iattr->ia_size;
+		f->metadata = NULL;
+	} else {
+		f->metadata = new_metadata;
 	}
-	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;
+	if (old_metadata) {
+		jffs2_mark_node_obsolete(c, old_metadata->raw);
+		jffs2_free_full_dnode(old_metadata);
 	}
+	jffs2_free_raw_inode(ri);
 
-	c->sector_size = bs.block_size;
-	c->flash_size = ds.dev_size;
-	c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
+	mutex_unlock(&f->sem);
+	jffs2_complete_reservation(c);
 
-	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;
-	}
+	/* We have to do the truncate_setsize() without f->sem held, since
+	   some pages may be locked and waiting for it in readpage().
+	   We are protected from a simultaneous write() extending i_size
+	   back past iattr->ia_size, because do_truncate() holds the
+	   generic inode semaphore. */
+	if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) {
+		truncate_setsize(inode, iattr->ia_size);
+	}	
 
 	return 0;
+}
 
-      out_nodes:
-	jffs2_free_ino_caches(c);
-	jffs2_free_raw_node_refs(c);
-	free(c->blocks);
+typedef struct {
+	struct super_block sb;
+	struct jffs2_inode_cache *inode_cache[];
+} rtems_jffs2_fs_info;
 
-	return err;
+static void rtems_jffs2_do_lock(const struct super_block *sb)
+{
+	rtems_status_code sc = rtems_semaphore_obtain(sb->s_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+	assert(sc == RTEMS_SUCCESSFUL);
 }
 
-static int jffs2_mount(cyg_fstab_entry * fste, cyg_mtab_entry * mte)
+static void rtems_jffs2_do_unlock(const struct super_block *sb)
 {
-	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;
+	rtems_status_code sc = rtems_semaphore_release(sb->s_mutex);
+	assert(sc == RTEMS_SUCCESSFUL);
+}
 
-	D2(printf("jffs2_mount\n"));
+static void rtems_jffs2_free_directory_entries(struct _inode *inode)
+{
+        struct jffs2_full_dirent *current = inode->jffs2_i.dents;
 
-	err = cyg_io_lookup(mte->devname, &t);
-	if (err != ENOERR)
-		return -err;
+	while (current != NULL) {
+		struct jffs2_full_dirent *victim = current;
 
-	// 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;
-		}
+		current = victim->next;
+		jffs2_free_full_dirent(victim);
 	}
+}
 
-	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
+static void rtems_jffs2_flash_control_destroy(rtems_jffs2_flash_control *fc)
+{
+	if (fc->destroy != NULL) {
+		(*fc->destroy)(fc);
 	}
-	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)
+static void rtems_jffs2_compressor_control_destroy(rtems_jffs2_compressor_control *cc)
 {
-	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 (cc != NULL && cc->destroy != NULL) {
+		(*cc->destroy)(cc);
+	}
+}
 
-		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;
+static void rtems_jffs2_free_fs_info(rtems_jffs2_fs_info *fs_info, bool do_mount_fs_was_successful)
+{
+	struct super_block *sb = &fs_info->sb;
+	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
 
-		// Clean up the super block and root inode
+	if (do_mount_fs_was_successful) {
 		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.
+	if (sb->s_mutex != 0) {
+		rtems_status_code sc = rtems_semaphore_delete(sb->s_mutex);
+		assert(sc == RTEMS_SUCCESSFUL);
+	}
 
-static int jffs2_open(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
-		      int mode, cyg_file * file)
-{
+	rtems_jffs2_flash_control_destroy(fs_info->sb.s_flash_control);
+	rtems_jffs2_compressor_control_destroy(fs_info->sb.s_compressor_control);
 
-	jffs2_dirsearch ds;
-	struct _inode *node = NULL;
-	int err;
+	free(fs_info);
+}
 
-	D2(printf("jffs2_open\n"));
+static int rtems_jffs2_eno_to_rv_and_errno(int eno)
+{
+	if (eno == 0) {
+		return 0;
+	} else {
+		errno = eno;
 
-	/* 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;
+		return -1;
+	}
+}
 
-#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);
+static struct _inode *rtems_jffs2_get_inode_by_location(
+	const rtems_filesystem_location_info_t *loc
+)
+{
+	return loc->node_access;
+}
 
-	err = jffs2_find(&ds);
+static struct _inode *rtems_jffs2_get_inode_by_iop(
+	const rtems_libio_t *iop
+)
+{
+	return iop->pathinfo.node_access;
+}
 
-	if (err == ENOENT) {
-#ifdef CYGOPT_FS_JFFS2_WRITE
-		if (ds.last && (mode & O_CREAT)) {
+static int rtems_jffs2_fstat(
+	const rtems_filesystem_location_info_t *loc,
+	struct stat *buf
+)
+{
+	struct _inode *inode = rtems_jffs2_get_inode_by_location(loc);
 
-			// 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.
+	rtems_jffs2_do_lock(inode->i_sb);
 
-			err = jffs2_create(ds.dir, ds.name, S_IRUGO|S_IXUGO|S_IWUSR|S_IFREG, &node);
+	buf->st_blksize = PAGE_SIZE;
+	buf->st_mode = inode->i_mode;
+	buf->st_ino = inode->i_ino;
+	buf->st_nlink = inode->i_nlink;
+	buf->st_uid = inode->i_uid;
+	buf->st_gid = inode->i_gid;
+	buf->st_size = inode->i_size;
+	buf->st_atime = inode->i_atime;
+	buf->st_mtime = inode->i_mtime;
+	buf->st_ctime = inode->i_ctime;
 
-			if (err != 0) {
-                                //Possible orphaned inode on the flash - but will be gc'd
-                          	jffs2_iput(ds.dir);
-                                return -err;
-			}
+	rtems_jffs2_do_unlock(inode->i_sb);
 
-			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.
+	return 0;
+}
 
-		if ((mode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) {
-			jffs2_iput(ds.node);
-			err = EEXIST;
-		} else
-			node = ds.node;
-	}
+static int rtems_jffs2_fill_dirent(struct dirent *de, off_t off, uint32_t ino, const char *name)
+{
+	int eno = 0;
+	size_t len;
 
-	// Finished with the directory now 
-	jffs2_iput(ds.dir);
+	memset(de, 0, sizeof(*de));
 
-	if (err != ENOERR)
-		return err;
+	de->d_off = off * sizeof(*de);
+	de->d_reclen = sizeof(*de);
+	de->d_ino = ino;
 
-	// Check that we actually have a file here
-	if (S_ISDIR(node->i_mode)) {
-		jffs2_iput(node);
-		return EISDIR;
-	}
+	len = strlen(name);
+	de->d_namlen = len;
 
-             // 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;
+	if (len < sizeof(de->d_name) - 1) {
+		memcpy(&de->d_name[0], name, len);
+	} else {
+		eno = EOVERFLOW;
+	}
 
-	return ENOERR;
+	return eno;
 }
 
-#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)
+static ssize_t rtems_jffs2_dir_read(rtems_libio_t *iop, void *buf, size_t len)
 {
-	jffs2_dirsearch ds;
-	int err;
-
-	D2(printf("jffs2_ops_unlink\n"));
+	struct _inode *inode = rtems_jffs2_get_inode_by_iop(iop);
+	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+	struct dirent *de = buf;
+	off_t fd_off = 2;
+	int eno = 0;
+	struct jffs2_full_dirent *fd;
+	off_t begin;
+	off_t end;
+	off_t off;
 
-	init_dirsearch(&ds, (struct _inode *) dir, 
-                       (const unsigned char *)name);
+	rtems_jffs2_do_lock(inode->i_sb);
 
-	err = jffs2_find(&ds);
+	fd = f->dents;
+	begin = iop->offset;
+	end = begin + len / sizeof(*de);
+	off = begin;
 
-	if (err != ENOERR) {
-		jffs2_iput(ds.dir);
-		return err;
+	if (off == 0 && off < end) {
+		eno = rtems_jffs2_fill_dirent(de, off, inode->i_ino, ".");
+		assert(eno == 0);
+		++off;
+		++de;
 	}
 
-	// Cannot unlink directories, use rmdir() instead
-	if (S_ISDIR(ds.node->i_mode)) {
-		jffs2_iput(ds.dir);
-		jffs2_iput(ds.node);
-		return EPERM;
+	if (off == 1 && off < end) {
+		eno = rtems_jffs2_fill_dirent(de, off, inode->i_parent->i_ino, "..");
+		assert(eno == 0);
+		++off;
+		++de;
 	}
 
-	// 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;
+	while (eno == 0 && off < end && fd != NULL) {
+		if (fd->ino != 0) {
+			if (off == fd_off) {
+				eno = rtems_jffs2_fill_dirent(de, off, fd->ino, fd->name);
+				++off;
+				++de;
+			}
 
-	D2(printf("jffs2_ops_mkdir\n"));
+			++fd_off;
+		}
 
-	init_dirsearch(&ds, (struct _inode *) dir, 
-                       (const unsigned char *)name);
+		fd = fd->next;
+	}
 
-	err = jffs2_find(&ds);
+	rtems_jffs2_do_unlock(inode->i_sb);
 
-	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.
+	if (eno == 0) {
+		iop->offset = off;
 
-			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.
+		return (off - begin) * sizeof(*de);
 	} 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;
-               }
+		return rtems_jffs2_eno_to_rv_and_errno(eno);
 	}
-	jffs2_iput(ds.dir);
-	return err;
 }
 
-// -------------------------------------------------------------------------
-// jffs2_ops_rmdir()
-// Remove a directory.
+static const rtems_filesystem_file_handlers_r rtems_jffs2_directory_handlers = {
+	.open_h = rtems_filesystem_default_open,
+	.close_h = rtems_filesystem_default_close,
+	.read_h = rtems_jffs2_dir_read,
+	.write_h = rtems_filesystem_default_write,
+	.ioctl_h = rtems_filesystem_default_ioctl,
+	.lseek_h = rtems_filesystem_default_lseek_directory,
+	.fstat_h = rtems_jffs2_fstat,
+	.ftruncate_h = rtems_filesystem_default_ftruncate_directory,
+	.fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
+	.fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
+	.fcntl_h = rtems_filesystem_default_fcntl
+};
 
-static int jffs2_ops_rmdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name)
+static ssize_t rtems_jffs2_file_read(rtems_libio_t *iop, void *buf, size_t len)
 {
-	jffs2_dirsearch ds;
-	int err;
+	struct _inode *inode = rtems_jffs2_get_inode_by_iop(iop);
+	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+	int err = 0;
+	off_t pos;
+
+	rtems_jffs2_do_lock(inode->i_sb);
 
-	D2(printf("jffs2_ops_rmdir\n"));
+	pos = iop->offset;
 
-	init_dirsearch(&ds, (struct _inode *) dir, 
-                       (const unsigned char *)name);
+	if (pos >= inode->i_size) {
+		len = 0;
+	} else {
+		uint32_t pos_32 = (uint32_t) pos;
+		uint32_t max_available = inode->i_size - pos_32;
 
-	err = jffs2_find(&ds);
+		if (len > max_available) {
+			len = max_available;
+		}
 
-	if (err != ENOERR) {
-		jffs2_iput(ds.dir);
-		return err;
+		err = jffs2_read_inode_range(c, f, buf, pos_32, len);
 	}
 
-	// Check that this is actually a directory.
-	if (!S_ISDIR(ds.node->i_mode)) {
-		jffs2_iput(ds.dir);
-		jffs2_iput(ds.node);
-		return EPERM;
+	if (err == 0) {
+		iop->offset += len;
 	}
 
-	err = jffs2_rmdir(ds.dir, ds.node, ds.name);
+	rtems_jffs2_do_unlock(inode->i_sb);
 
-	jffs2_iput(ds.dir);
-	jffs2_iput(ds.node);
-	return -err;
-}
+	if (err == 0) {
+		return (ssize_t) len;
+	} else {
+		errno = -err;
 
-// -------------------------------------------------------------------------
-// jffs2_ops_rename()
-// Rename a file/dir.
+		return -1;
+	}
+}
 
-static int jffs2_ops_rename(cyg_mtab_entry * mte, cyg_dir dir1,
-			    const char *name1, cyg_dir dir2, const char *name2)
+static ssize_t rtems_jffs2_file_write(rtems_libio_t *iop, const void *buf, size_t len)
 {
-	jffs2_dirsearch ds1, ds2;
-	int err;
+	struct _inode *inode = rtems_jffs2_get_inode_by_iop(iop);
+	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+	struct jffs2_raw_inode ri;
+	uint32_t writtenlen;
+	off_t pos;
+	int eno = 0;
 
-	D2(printf("jffs2_ops_rename\n"));
+	memset(&ri, 0, sizeof(ri));
 
-	init_dirsearch(&ds1, (struct _inode *) dir1, 
-                       (const unsigned char *)name1);
+	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(get_seconds());
 
-	err = jffs2_find(&ds1);
+	rtems_jffs2_do_lock(inode->i_sb);
 
-	if (err != ENOERR) {
-		jffs2_iput(ds1.dir);
-		return err;
+	if ((iop->flags & LIBIO_FLAGS_APPEND) == 0) {
+		pos = iop->offset;
+	} else {
+		pos = inode->i_size;
 	}
 
-	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 (pos > inode->i_size) {
+		ri.version = cpu_to_je32(++f->highest_version);
+		eno = -jffs2_extend_file(inode, &ri, pos);
 	}
 
-	if (err != ENOERR) {
-		jffs2_iput(ds1.dir);
-		jffs2_iput(ds1.node);
-		jffs2_iput(ds2.dir);
-		return err;
-	}
+	if (eno == 0) {
+		ri.isize = cpu_to_je32(inode->i_size);
 
-	// Null rename, just return
-	if (ds1.node == ds2.node) {
-		err = ENOERR;
-		goto out;
+		eno = -jffs2_write_inode_range(c, f, &ri, (void *) buf, pos, len, &writtenlen);
 	}
 
-	// First deal with any entry that is at the destination
-	if (ds2.node) {
-		// Check that we are renaming like-for-like
+	if (eno == 0) {
+		pos += writtenlen;
 
-		if (!S_ISDIR(ds1.node->i_mode) && S_ISDIR(ds2.node->i_mode)) {
-			err = EISDIR;
-			goto out;
-		}
+		inode->i_mtime = inode->i_ctime = je32_to_cpu(ri.mtime);
 
-		if (S_ISDIR(ds1.node->i_mode) && !S_ISDIR(ds2.node->i_mode)) {
-			err = ENOTDIR;
-			goto out;
+		if (pos > inode->i_size) {
+			inode->i_size = pos;
 		}
 
-		// 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;
+		iop->offset = pos;
 
+		if (writtenlen != len) {
+			eno = ENOSPC;
+		}
 	}
-	// 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);
+	rtems_jffs2_do_unlock(inode->i_sb);
 
-	// 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... */
+	if (eno == 0) {
+		return writtenlen;
 	} else {
-		jffs2_iput(ds2.dir); /* ... doing this */
+		errno = eno;
+
+		return -1;
 	}
-	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)
+static int rtems_jffs2_file_ftruncate(rtems_libio_t *iop, off_t length)
 {
-	jffs2_dirsearch ds1, ds2;
-	int err;
+	struct _inode *inode = rtems_jffs2_get_inode_by_iop(iop);
+	struct iattr iattr;
+	int eno;
 
-	D2(printf("jffs2_ops_link\n"));
+	iattr.ia_valid = ATTR_SIZE | ATTR_MTIME | ATTR_CTIME;
+	iattr.ia_size = length;
+	iattr.ia_mtime = get_seconds();
+	iattr.ia_ctime = iattr.ia_mtime;
 
-	// Only do hard links for now in this filesystem
-	if (type != CYG_FSLINK_HARD)
-		return EINVAL;
+	rtems_jffs2_do_lock(inode->i_sb);
 
-	init_dirsearch(&ds1, (struct _inode *) dir1, 
-                       (const unsigned char *) name1);
+	eno = -jffs2_do_setattr(inode, &iattr);
 
-	err = jffs2_find(&ds1);
+	rtems_jffs2_do_unlock(inode->i_sb);
 
-	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.
+	return rtems_jffs2_eno_to_rv_and_errno(eno);
+}
 
-	err = jffs2_link(ds1.node, ds2.dir, ds2.name);
+static const rtems_filesystem_file_handlers_r rtems_jffs2_file_handlers = {
+	.open_h = rtems_filesystem_default_open,
+	.close_h = rtems_filesystem_default_close,
+	.read_h = rtems_jffs2_file_read,
+	.write_h = rtems_jffs2_file_write,
+	.ioctl_h = rtems_filesystem_default_ioctl,
+	.lseek_h = rtems_filesystem_default_lseek_file,
+	.fstat_h = rtems_jffs2_fstat,
+	.ftruncate_h = rtems_jffs2_file_ftruncate,
+	.fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
+	.fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
+	.fcntl_h = rtems_filesystem_default_fcntl
+};
 
-	if (err == 0)
-		ds1.node->i_ctime =
-		    ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp();
+static const rtems_filesystem_file_handlers_r rtems_jffs2_link_handlers = {
+	.open_h = rtems_filesystem_default_open,
+	.close_h = rtems_filesystem_default_close,
+	.read_h = rtems_filesystem_default_read,
+	.write_h = rtems_filesystem_default_write,
+	.ioctl_h = rtems_filesystem_default_ioctl,
+	.lseek_h = rtems_filesystem_default_lseek,
+	.fstat_h = rtems_jffs2_fstat,
+	.ftruncate_h = rtems_filesystem_default_ftruncate,
+	.fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
+	.fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
+	.fcntl_h = rtems_filesystem_default_fcntl
+};
 
-	jffs2_iput(ds1.dir);
-	jffs2_iput(ds1.node);
-	jffs2_iput(ds2.dir);
+static void rtems_jffs2_set_location(rtems_filesystem_location_info_t *loc, struct _inode *inode)
+{
+	loc->node_access = inode;
 
-	return -err;
+	switch (inode->i_mode & S_IFMT) {
+		case S_IFREG:
+			loc->handlers = &rtems_jffs2_file_handlers;
+			break;
+		case S_IFDIR:
+			loc->handlers = &rtems_jffs2_directory_handlers;
+			break;
+		case S_IFLNK:
+			loc->handlers = &rtems_jffs2_link_handlers;
+			break;
+		default:
+			loc->handlers = &rtems_filesystem_null_handlers;
+			break;
+	};
 }
-#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)
+static bool rtems_jffs2_eval_is_directory(
+	rtems_filesystem_eval_path_context_t *ctx,
+	void *arg
+)
 {
-	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;
+	rtems_filesystem_location_info_t *currentloc =
+		rtems_filesystem_eval_path_get_currentloc(ctx);
+	struct _inode *inode = rtems_jffs2_get_inode_by_location(currentloc);
 
+	return S_ISDIR(inode->i_mode);
 }
 
-// -------------------------------------------------------------------------
-// jffs2_chdir()
-// Change directory support.
-
-static int jffs2_chdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
-		       cyg_dir * dir_out)
+static rtems_filesystem_eval_path_generic_status rtems_jffs2_eval_token(
+	rtems_filesystem_eval_path_context_t *ctx,
+	void *arg,
+	const char *token,
+	size_t tokenlen
+)
 {
-	D2(printf("jffs2_chdir\n"));
+	rtems_filesystem_eval_path_generic_status status =
+		RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE;
+	rtems_filesystem_location_info_t *currentloc =
+		rtems_filesystem_eval_path_get_currentloc(ctx);
+	struct _inode *dir_i = rtems_jffs2_get_inode_by_location(currentloc);
+	bool access_ok = rtems_filesystem_eval_path_check_access(
+		ctx,
+		RTEMS_FS_PERMS_EXEC,
+		dir_i->i_mode,
+		dir_i->i_uid,
+		dir_i->i_gid
+	);
 
-	if (dir_out != NULL) {
-		// This is a request to get a new directory pointer in
-		// *dir_out.
+	if (access_ok) {
+		struct _inode *entry_i;
 
-		jffs2_dirsearch ds;
-		int err;
+		if (rtems_filesystem_is_current_directory(token, tokenlen)) {
+			entry_i = dir_i;
+			++entry_i->i_count;
+		} else if (rtems_filesystem_is_parent_directory(token, tokenlen)) {
+			entry_i = dir_i->i_parent;
+			++entry_i->i_count;
+		} else {
+			entry_i = jffs2_lookup(dir_i, token, (int) tokenlen);
+		}
 
-		init_dirsearch(&ds, (struct _inode *) dir, 
-                               (const unsigned char *) name);
+		if (IS_ERR(entry_i)) {
+			rtems_filesystem_eval_path_error(ctx, PTR_ERR(entry_i));
+		} else if (entry_i != NULL) {
+			bool terminal = !rtems_filesystem_eval_path_has_path(ctx);
+			int eval_flags = rtems_filesystem_eval_path_get_flags(ctx);
+			bool follow_sym_link = (eval_flags & RTEMS_FS_FOLLOW_SYM_LINK) != 0;
 
-		err = jffs2_find(&ds);
-		jffs2_iput(ds.dir);
+			rtems_filesystem_eval_path_clear_token(ctx);
 
-		if (err != ENOERR)
-			return err;
+			if (S_ISLNK(entry_i->i_mode) && (follow_sym_link || !terminal)) {
+				struct jffs2_inode_info *f = JFFS2_INODE_INFO(entry_i);
+				const char *target = f->target;
 
-		// 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.
+				rtems_filesystem_eval_path_recursive(ctx, target, strlen(target));
 
-		struct _inode *node = (struct _inode *) dir;
+				jffs2_iput(entry_i);
+			} else {
+				if (S_ISDIR(entry_i->i_mode) && entry_i->i_parent == NULL) {
+					entry_i->i_parent = dir_i;
+					++dir_i->i_count;
+				}
+
+				jffs2_iput(dir_i);
+				rtems_jffs2_set_location(currentloc, entry_i);
 
-		// Just decrement directory reference count.
-		jffs2_iput(node);
+				if (rtems_filesystem_eval_path_has_path(ctx)) {
+					status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE;
+				}
+			}
+		} else {
+			status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_NO_ENTRY;
+		}
 	}
 
-	return ENOERR;
+	return status;
 }
 
-// -------------------------------------------------------------------------
-// jffs2_stat()
-// Get struct stat info for named object.
+static const rtems_filesystem_eval_path_generic_config rtems_jffs2_eval_config = {
+	.is_directory = rtems_jffs2_eval_is_directory,
+	.eval_token = rtems_jffs2_eval_token
+};
 
-static int jffs2_stat(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
-		      struct stat *buf)
+static void rtems_jffs2_lock(const rtems_filesystem_mount_table_entry_t *mt_entry)
 {
-	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;
+	const rtems_jffs2_fs_info *fs_info = mt_entry->fs_info;
+	const struct super_block *sb = &fs_info->sb;
 
-	// 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;
+	rtems_jffs2_do_lock(sb);
+}
 
-	jffs2_iput(ds.node);
+static void rtems_jffs2_unlock(const rtems_filesystem_mount_table_entry_t *mt_entry)
+{
+	const rtems_jffs2_fs_info *fs_info = mt_entry->fs_info;
+	const struct super_block *sb = &fs_info->sb;
 
-	return ENOERR;
+	rtems_jffs2_do_unlock(sb);
 }
 
-// -------------------------------------------------------------------------
-// jffs2_getinfo()
-// Getinfo. Currently only support pathconf().
+static void rtems_jffs2_eval_path(rtems_filesystem_eval_path_context_t *ctx)
+{
+	rtems_filesystem_eval_path_generic(ctx, NULL, &rtems_jffs2_eval_config);
+}
 
-static int jffs2_getinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
-			 int key, void *buf, int len)
+static int rtems_jffs2_link(
+	const rtems_filesystem_location_info_t *parentloc,
+	const rtems_filesystem_location_info_t *targetloc,
+	const char *name,
+	size_t namelen
+)
 {
-	jffs2_dirsearch ds;
-	int err;
+	struct _inode *old_d_inode = rtems_jffs2_get_inode_by_location(targetloc);
+	struct _inode *dir_i = rtems_jffs2_get_inode_by_location(parentloc);
+	int eno;
 
-	D2(printf("jffs2_getinfo\n"));
+	eno = -jffs2_link(old_d_inode, dir_i, name, namelen);
 
-	init_dirsearch(&ds, (struct _inode *) dir, 
-                       (const unsigned char *) name);
+	return rtems_jffs2_eno_to_rv_and_errno(eno);
+}
 
-	err = jffs2_find(&ds);
-	jffs2_iput(ds.dir);
+static bool rtems_jffs2_are_nodes_equal(
+	const rtems_filesystem_location_info_t *a,
+	const rtems_filesystem_location_info_t *b
+)
+{
+	struct _inode *inode_a = rtems_jffs2_get_inode_by_location(a);
+	struct _inode *inode_b = rtems_jffs2_get_inode_by_location(b);
 
-	if (err != ENOERR)
-		return err;
+	return inode_a->i_ino == inode_b->i_ino;
+}
 
-	switch (key) {
-	case FS_INFO_CONF:
-		err = jffs2_pathconf(ds.node, (struct cyg_pathconf_info *) buf);
-		break;
+static rtems_filesystem_node_types_t rtems_jffs2_node_type(
+	const rtems_filesystem_location_info_t *loc
+)
+{
+	struct _inode *inode = rtems_jffs2_get_inode_by_location(loc);
+	rtems_filesystem_node_types_t type;
 
-	default:
-		err = EINVAL;
+	switch (inode->i_mode & S_IFMT) {
+		case S_IFDIR:
+			type = RTEMS_FILESYSTEM_DIRECTORY;
+			break;
+		case S_IFREG:
+			type = RTEMS_FILESYSTEM_MEMORY_FILE;
+			break;
+		case S_IFLNK:
+			type = RTEMS_FILESYSTEM_SYM_LINK;
+			break;
+		default:
+			type = RTEMS_FILESYSTEM_INVALID_NODE_TYPE;
+			break;
 	}
 
-	jffs2_iput(ds.node);
-	return err;
+	return type;
 }
 
-// -------------------------------------------------------------------------
-// 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)
+static int rtems_jffs2_mknod(
+	const rtems_filesystem_location_info_t *parentloc,
+	const char *name,
+	size_t namelen,
+	mode_t mode,
+	dev_t dev
+)
 {
-	// No setinfo keys supported at present
+	struct _inode *dir_i = rtems_jffs2_get_inode_by_location(parentloc);
+	int eno;
 
-	D2(printf("jffs2_setinfo\n"));
+	switch (mode & S_IFMT) {
+		case S_IFDIR:
+			eno = -jffs2_mknod(dir_i, name, namelen, mode, NULL, 0);
+			break;
+		case S_IFREG:
+			eno = -jffs2_create(dir_i, name, namelen, mode);
+			break;
+		default:
+			eno = EINVAL;
+			break;
+	}
 
-	return EINVAL;
+	return rtems_jffs2_eno_to_rv_and_errno(eno);
 }
 
-//==========================================================================
-// 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)
+static int rtems_jffs2_cache_fd_name(struct _inode *inode, char **name, size_t *namelen)
 {
-	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;
+	struct super_block *sb = inode->i_sb;
+	char *fd_name = inode->i_fd->name;
+	size_t fd_namelen = strlen(fd_name);
+	int eno = 0;
 
-	down(&f->sem);
+	if (fd_namelen <= sizeof(sb->s_name_buf)) {
+		*namelen = fd_namelen;
+		*name = memcpy(&sb->s_name_buf[0], fd_name, fd_namelen);
+	} else {
+		eno = ENOMEM;
+	}
 
-	// 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);
+	return eno;
+}
 
-		D2(printf("jffs2_fo_read inode size %d\n", inode->i_size));
+static int rtems_jffs2_rmnod(
+	const rtems_filesystem_location_info_t *parentloc,
+	const rtems_filesystem_location_info_t *loc
+)
+{
+	struct _inode *dir_i = rtems_jffs2_get_inode_by_location(parentloc);
+	struct _inode *entry_i = rtems_jffs2_get_inode_by_location(loc);
+	char *name;
+	size_t namelen;
+	int eno = rtems_jffs2_cache_fd_name(entry_i, &name, &namelen);
 
-		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;
+	if (eno == 0) {
+		switch (dir_i->i_mode & S_IFMT) {
+			case S_IFDIR:
+				eno = -jffs2_rmdir(dir_i, entry_i, name, namelen);
+				break;
+			case S_IFREG:
+				eno = -jffs2_unlink(dir_i, entry_i, name, namelen);
+				break;
+			default:
+				eno = EINVAL;
+				break;
 		}
-		resid -= len;
-		pos += len;
 	}
 
-	// We successfully read some data, update the node's access time
-	// and update the file offset and transfer residue.
+	return rtems_jffs2_eno_to_rv_and_errno(eno);
+}
 
-	inode->i_atime = cyg_timestamp();
+static int rtems_jffs2_fchmod(
+	const rtems_filesystem_location_info_t *loc,
+	mode_t mode
+)
+{
+	struct _inode *inode = rtems_jffs2_get_inode_by_location(loc);
+	struct iattr iattr;
+	int eno;
 
-	uio->uio_resid = resid;
-	fp->f_offset = pos;
+	iattr.ia_valid = ATTR_MODE | ATTR_CTIME;
+	iattr.ia_mode = mode;
+	iattr.ia_ctime = get_seconds();
 
-	up(&f->sem);
+	eno = -jffs2_do_setattr(inode, &iattr);
 
-	return ENOERR;
+	return rtems_jffs2_eno_to_rv_and_errno(eno);
 }
 
-
-#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)
+static int rtems_jffs2_chown(
+	const rtems_filesystem_location_info_t *loc,
+	uid_t owner,
+	gid_t group
+)
 {
-	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;
+	struct _inode *inode = rtems_jffs2_get_inode_by_location(loc);
+	struct iattr iattr;
+	int eno;
 
-	/* 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));
+	iattr.ia_valid = ATTR_UID | ATTR_GID | ATTR_CTIME;
+	iattr.ia_uid = owner;
+	iattr.ia_gid = group;
+	iattr.ia_ctime = get_seconds();
 
-	ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloc_len, ALLOC_NORMAL);
-	if (ret)
-		return ret;
+	eno = -jffs2_do_setattr(inode, &iattr);
 
-	down(&f->sem);
+	return rtems_jffs2_eno_to_rv_and_errno(eno);
+}
 
-	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));
+static int rtems_jffs2_clonenode(rtems_filesystem_location_info_t *loc)
+{
+	struct _inode *inode = rtems_jffs2_get_inode_by_location(loc);
 
-	ri->version = cpu_to_je32(++f->highest_version);
-	ri->isize = cpu_to_je32(max((uint32_t)inode->i_size, offset));
+	++inode->i_count;
 
-	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)
+static void rtems_jffs2_freenode(const rtems_filesystem_location_info_t *loc)
 {
-     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;
+	struct _inode *inode = rtems_jffs2_get_inode_by_location(loc);
+
+	jffs2_iput(inode);
 }
 
-static int jffs2_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
+static void rtems_jffs2_fsunmount(rtems_filesystem_mount_table_entry_t *mt_entry)
 {
-	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);
+	rtems_jffs2_fs_info *fs_info = mt_entry->fs_info;
+	struct _inode *root_i = mt_entry->mt_fs_root->location.node_access;
 
-	// 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;
+	icache_evict(root_i, NULL);
+	assert(root_i->i_cache_next == NULL);
+	assert(root_i->i_count == 1);
+	jffs2_iput(root_i);
 
-		uint32_t writtenlen;
-		int err;
+	rtems_jffs2_free_directory_entries(root_i);
+	free(root_i);
 
-		D2(printf("jffs2_fo_write page_start_pos %d\n", pos));
-		D2(printf("jffs2_fo_write transfer size %d\n", len));
+	rtems_jffs2_free_fs_info(fs_info, true);
+}
 
-		err = jffs2_write_inode_range(c, f, &ri, buf,
-					      pos, len, &writtenlen);
-		if (err)
-			return -err;
-		
-		if (writtenlen != len)
-			return ENOSPC;
+static int rtems_jffs2_rename(
+	const rtems_filesystem_location_info_t *oldparentloc,
+	const rtems_filesystem_location_info_t *oldloc,
+	const rtems_filesystem_location_info_t *newparentloc,
+	const char *name,
+	size_t namelen
+)
+{
+	struct _inode *old_dir_i = rtems_jffs2_get_inode_by_location(oldparentloc);
+	struct _inode *new_dir_i = rtems_jffs2_get_inode_by_location(newparentloc);
+	struct _inode *d_inode = rtems_jffs2_get_inode_by_location(oldloc);
+	char *oldname;
+	size_t oldnamelen;
+	int eno = rtems_jffs2_cache_fd_name(d_inode, &oldname, &oldnamelen);
 
-		pos += len;
-		resid -= len;
+	if (eno == 0) {
+		eno = -jffs2_rename(old_dir_i, d_inode, oldname, oldnamelen, new_dir_i, name, namelen);
 	}
 
-	// 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;
+	return rtems_jffs2_eno_to_rv_and_errno(eno);
 }
-#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)
+static int rtems_jffs2_statvfs(
+	const rtems_filesystem_location_info_t *loc,
+	struct statvfs *buf
+)
 {
-	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;
+	struct _inode *inode = rtems_jffs2_get_inode_by_location(loc);
+	struct super_block *sb = inode->i_sb;
+	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
+	unsigned long avail;
 
-	case SEEK_END:
-		// Add pos to file size.
-		pos += node->i_size;
-		break;
-
-	default:
-		return EINVAL;
+	spin_lock(&c->erase_completion_lock);
+	avail = c->dirty_size + c->free_size;
+	if (avail > c->sector_size * c->resv_blocks_write) {
+		avail -= c->sector_size * c->resv_blocks_write;
+	} else {
+		avail = 0;
 	}
+	spin_unlock(&c->erase_completion_lock);
 
-        if (pos < 0 )
-                return EINVAL;
+	buf->f_bavail = avail >> PAGE_SHIFT;
+	buf->f_blocks = c->flash_size >> PAGE_SHIFT;
+	buf->f_bsize = 1UL << PAGE_SHIFT;
+	buf->f_fsid = JFFS2_SUPER_MAGIC;
+	buf->f_namemax = JFFS2_MAX_NAME_LEN;
 
-	// All OK, set fp offset and return new position.
-	*apos = fp->f_offset = pos;
+	buf->f_bfree = buf->f_bavail;
+	buf->f_frsize = buf->f_bsize;
 
-	return ENOERR;
+	return 0;
 }
 
-// -------------------------------------------------------------------------
-// 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)
+static int rtems_jffs2_utime(
+	const rtems_filesystem_location_info_t *loc,
+	time_t actime,
+	time_t modtime
+)
 {
-	// No Ioctls currenly defined.
+	struct _inode *inode = rtems_jffs2_get_inode_by_location(loc);
+	struct iattr iattr;
+	int eno;
 
-	D2(printf("jffs2_fo_ioctl\n"));
+	iattr.ia_valid = ATTR_ATIME | ATTR_MTIME | ATTR_CTIME;
+	iattr.ia_atime = actime;
+	iattr.ia_mtime = modtime;
+	iattr.ia_ctime = get_seconds();
 
-	return EINVAL;
-}
+	eno = -jffs2_do_setattr(inode, &iattr);
 
-// -------------------------------------------------------------------------
-// jffs2_fo_fsync().
-// Force the file out to data storage.
+	return rtems_jffs2_eno_to_rv_and_errno(eno);
+}
 
-static int jffs2_fo_fsync(struct CYG_FILE_TAG *fp, int mode)
+static int rtems_jffs2_symlink(
+	const rtems_filesystem_location_info_t *parentloc,
+	const char *name,
+	size_t namelen,
+	const char *target
+)
 {
-	// Data is always permanently where it belongs, nothing to do
-	// here.
+	struct _inode *dir_i = rtems_jffs2_get_inode_by_location(parentloc);
+	int eno;
 
-	D2(printf("jffs2_fo_fsync\n"));
+	eno = -jffs2_mknod(dir_i, name, namelen, S_IFLNK | S_IRWXUGO, target, strlen(target));
 
-	return ENOERR;
+	return rtems_jffs2_eno_to_rv_and_errno(eno);
 }
 
-// -------------------------------------------------------------------------
-// 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)
+static ssize_t rtems_jffs2_readlink(
+	const rtems_filesystem_location_info_t *loc,
+	char *buf,
+	size_t bufsize
+)
 {
-	struct _inode *node = (struct _inode *) fp->f_data;
-
-	D2(printf("jffs2_fo_close\n"));
-
-	jffs2_iput(node);
+	struct _inode *inode = rtems_jffs2_get_inode_by_location(loc);
+	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+	const char *target = f->target;
+	ssize_t i;
 
-	fp->f_data = 0;		// zero data pointer
+	for (i = 0; i < (ssize_t) bufsize && target[i] != '\0'; ++i) {
+		buf[i] = target[i];
+	}
 
-	return ENOERR;
+	return i;
 }
 
-// -------------------------------------------------------------------------
-//jffs2_fo_fstat()
-// Get file status.
+static const rtems_filesystem_operations_table rtems_jffs2_ops = {
+	.lock_h = rtems_jffs2_lock,
+	.unlock_h = rtems_jffs2_unlock,
+	.eval_path_h = rtems_jffs2_eval_path,
+	.link_h = rtems_jffs2_link,
+	.are_nodes_equal_h = rtems_jffs2_are_nodes_equal,
+	.node_type_h = rtems_jffs2_node_type,
+	.mknod_h = rtems_jffs2_mknod,
+	.rmnod_h = rtems_jffs2_rmnod,
+	.fchmod_h = rtems_jffs2_fchmod,
+	.chown_h = rtems_jffs2_chown,
+	.clonenod_h = rtems_jffs2_clonenode,
+	.freenod_h = rtems_jffs2_freenode,
+	.mount_h = rtems_filesystem_default_mount,
+	.fsmount_me_h = rtems_jffs2_initialize,
+	.unmount_h = rtems_filesystem_default_unmount,
+	.fsunmount_me_h = rtems_jffs2_fsunmount,
+	.utime_h = rtems_jffs2_utime,
+	.symlink_h = rtems_jffs2_symlink,
+	.readlink_h = rtems_jffs2_readlink,
+	.rename_h = rtems_jffs2_rename,
+	.statvfs_h = rtems_jffs2_statvfs
+};
 
-static int jffs2_fo_fstat(struct CYG_FILE_TAG *fp, struct stat *buf)
+static int calculate_inocache_hashsize(uint32_t flash_size)
 {
-	struct _inode *node = (struct _inode *) fp->f_data;
+	/*
+	 * Pick a inocache hash size based on the size of the medium.
+	 * Count how many megabytes we're dealing with, apply a hashsize twice
+	 * that size, but rounding down to the usual big powers of 2. And keep
+	 * to sensible bounds.
+	 */
 
-	D2(printf("jffs2_fo_fstat\n"));
+	int size_mb = flash_size / 1024 / 1024;
+	int hashsize = (size_mb * 2) & ~0x3f;
 
-	// 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;
+	if (hashsize < INOCACHE_HASHSIZE_MIN)
+		return INOCACHE_HASHSIZE_MIN;
+	if (hashsize > INOCACHE_HASHSIZE_MAX)
+		return INOCACHE_HASHSIZE_MAX;
 
-	return ENOERR;
+	return hashsize;
 }
 
-// -------------------------------------------------------------------------
-// jffs2_fo_getinfo()
-// Get info. Currently only supports fpathconf().
-
-static int jffs2_fo_getinfo(struct CYG_FILE_TAG *fp, int key, void *buf,
-			    int len)
+int rtems_jffs2_initialize(
+	rtems_filesystem_mount_table_entry_t *mt_entry,
+	const void *data
+)
 {
-	struct _inode *node = (struct _inode *) fp->f_data;
+	const rtems_jffs2_mount_data *jffs2_mount_data = data;
+	rtems_jffs2_flash_control *fc = jffs2_mount_data->flash_control;
+	int inocache_hashsize = calculate_inocache_hashsize(fc->flash_size);
+	rtems_jffs2_fs_info *fs_info = calloc(
+		1,
+		sizeof(*fs_info) + (size_t) inocache_hashsize * sizeof(fs_info->inode_cache[0])
+	);
+	bool do_mount_fs_was_successful = false;
+	struct super_block *sb;
+	struct jffs2_sb_info *c;
 	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;
+	if (fs_info != NULL) {
+		err = 0;
+	} else {
+		err = -ENOMEM;
 	}
-	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
+	sb = &fs_info->sb;
+	c = JFFS2_SB_INFO(sb);
 
-// -------------------------------------------------------------------------
-// jffs2_fo_dirread()
-// Read a single directory entry from a file.
+	if (err == 0) {
+		uint32_t blocks = fc->flash_size / fc->block_size;
 
-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';
-}
+		if ((fc->block_size * blocks) != fc->flash_size) {
+			fc->flash_size = fc->block_size * blocks;
+			pr_info("Flash size not aligned to erasesize, reducing to %dKiB\n",
+				fc->flash_size / 1024);
+		}
 
-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 (fc->flash_size < 5*fc->block_size) {
+			pr_err("Too few erase blocks (%d)\n",
+			       fc->flash_size / fc->block_size);
+			err = -EINVAL;
+		}
+	}
 
-	if (len < sizeof (struct dirent))
-		return EINVAL;
+	if (err == 0) {
+		rtems_status_code sc = rtems_semaphore_create(
+			rtems_build_name('J', 'F', 'F', 'S'),
+			1,
+			RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY | RTEMS_BINARY_SEMAPHORE,
+			0,
+			&sb->s_mutex
+		);
 
-	D1(printk
-	   (KERN_DEBUG "jffs2_readdir() for dir_i #%lu\n", d_inode->i_ino));
+		err = sc == RTEMS_SUCCESSFUL ? 0 : -ENOMEM;
+	}
 
-	f = JFFS2_INODE_INFO(inode);
-	c = JFFS2_SB_INFO(inode->i_sb);
+	if (err == 0) {
+		sb->s_is_readonly = !mt_entry->writeable;
+		sb->s_flash_control = fc;
+		sb->s_compressor_control = jffs2_mount_data->compressor_control;
 
-	offset = fp->f_offset;
+		c->inocache_hashsize = inocache_hashsize;
+		c->inocache_list = &fs_info->inode_cache[0];
+		c->sector_size = fc->block_size;
+		c->flash_size = fc->flash_size;
+		c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
 
-	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;
+		err = jffs2_do_mount_fs(c);
 	}
 
-	curofs = 1;
-	down(&f->sem);
-	for (fd = f->dents; fd; fd = fd->next) {
+	if (err == 0) {
+		do_mount_fs_was_successful = true;
 
-		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;
+		sb->s_root = jffs2_iget(sb, 1);
+		if (IS_ERR(sb->s_root)) {
+			err = PTR_ERR(sb->s_root);
 		}
-		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.
+	if (err == 0) {
+		sb->s_root->i_parent = sb->s_root;
 
-static int jffs2_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t * pos, int whence)
-{
-	// Only allow SEEK_SET to zero
+		if (!jffs2_is_readonly(c)) {
+			jffs2_erase_pending_blocks(c, 0);
+		}
 
-	D2(printf("jffs2_fo_dirlseek\n"));
+		mt_entry->fs_info = fs_info;
+		mt_entry->ops = &rtems_jffs2_ops;
+		mt_entry->mt_fs_root->location.node_access = sb->s_root;
+		mt_entry->mt_fs_root->location.handlers = &rtems_jffs2_directory_handlers;
 
-	if (whence != SEEK_SET || *pos != 0)
-		return EINVAL;
+		return 0;
+	} else {
+		if (fs_info != NULL) {
+			rtems_jffs2_free_fs_info(fs_info, do_mount_fs_was_successful);
+		} else {
+			rtems_jffs2_flash_control_destroy(fc);
+			rtems_jffs2_compressor_control_destroy(jffs2_mount_data->compressor_control);
+		}
 
-	*pos = fp->f_offset = 0;
+		errno = -err;
 
-	return ENOERR;
+		return -1;
+	}
 }
 
 //==========================================================================
@@ -1773,8 +1232,9 @@ unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
 				   unsigned long offset,
 				   unsigned long *priv)
 {
-	/* FIXME: This works only with one file system mounted at a time */
 	int ret;
+	struct super_block *sb = OFNI_BS_2SFFJ(c);
+	unsigned char *gc_buffer = &sb->s_gc_buffer[0];
 
 	ret = jffs2_read_inode_range(c, f, gc_buffer, 
 				     offset & ~(PAGE_CACHE_SIZE-1), PAGE_CACHE_SIZE);
@@ -1870,7 +1330,7 @@ struct _inode *jffs2_iget(struct super_block *sb, cyg_uint32 ino)
 
 	err = jffs2_read_inode(inode);
 	if (err) {
-		printf("jffs2_read_inode() failed\n");
+		printk("jffs2_read_inode() failed\n");
                 inode->i_nlink = 0; // free _this_ bad inode right now
 		jffs2_iput(inode);
 		inode = NULL;
@@ -1890,10 +1350,7 @@ void jffs2_iput(struct _inode *i)
 	// 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... 
-	}
+	assert(i != NULL);
 
 	i->i_count--;
 
@@ -1934,10 +1391,10 @@ void jffs2_iput(struct _inode *i)
 // EOF jffs2.c
 
 
-static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
+static inline int jffs2_init_inode_info(struct jffs2_inode_info *f)
 {
 	memset(f, 0, sizeof(*f));
-	init_MUTEX_LOCKED(&f->sem);
+	return 0;
 }
 
 static void jffs2_clear_inode (struct _inode *inode)
@@ -1974,11 +1431,15 @@ struct _inode *jffs2_new_inode (struct _inode *dir_i, int mode, struct jffs2_raw
 		return ERR_PTR(-ENOMEM);
 
 	f = JFFS2_INODE_INFO(inode);
-	jffs2_init_inode_info(f);
+	ret = jffs2_init_inode_info(f);
+	if (ret) {
+		return ERR_PTR(ret);
+	}
 
 	memset(ri, 0, sizeof(*ri));
 	/* Set OS-specific defaults for new inodes */
-	ri->uid = ri->gid = cpu_to_je16(0);
+	ri->uid = cpu_to_je16(geteuid());
+	ri->gid = cpu_to_je16(getegid());
 	ri->mode =  cpu_to_jemode(mode);
 	ret = jffs2_do_new_inode (c, f, mode, ri);
 	if (ret) {
@@ -1988,7 +1449,7 @@ struct _inode *jffs2_new_inode (struct _inode *dir_i, int mode, struct jffs2_raw
                        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));
+                mutex_unlock(&(f->sem));
                 jffs2_clear_inode(inode);
                 memset(inode, 0x6a, sizeof(*inode));
                 free(inode);
@@ -1999,7 +1460,7 @@ struct _inode *jffs2_new_inode (struct _inode *dir_i, int mode, struct jffs2_raw
 	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();
+	inode->i_atime = inode->i_ctime = inode->i_mtime = get_seconds();
 	ri->atime = ri->mtime = ri->ctime = cpu_to_je32(inode->i_mtime);
 
 	inode->i_size = 0;
@@ -2020,12 +1481,15 @@ static int jffs2_read_inode (struct _inode *inode)
 	f = JFFS2_INODE_INFO(inode);
 	c = JFFS2_SB_INFO(inode->i_sb);
 
-	jffs2_init_inode_info(f);
+	ret = jffs2_init_inode_info(f);
+	if (ret) {
+		return ret;
+	}
 	
 	ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node);
 
 	if (ret) {
-		up(&f->sem);
+		mutex_unlock(&f->sem);
 		return ret;
 	}
 	inode->i_mode = jemode_to_cpu(latest_node.mode);
@@ -2036,8 +1500,8 @@ static int jffs2_read_inode (struct _inode *inode)
 	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);
+	inode->i_nlink = f->inocache->pino_nlink;
+	mutex_unlock(&f->sem);
 
 	D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n"));
 	return 0;
@@ -2051,41 +1515,43 @@ void jffs2_gc_release_inode(struct jffs2_sb_info *c,
 }
 
 struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
-						     int inum, int nlink)
+					      int inum, int unlinked)
 {
 	struct _inode *inode;
 	struct jffs2_inode_cache *ic;
-	if (!nlink) {
+
+	if (unlinked) {
 		/* 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.
+		   obsolete. This has to be because we're still waiting for
+		   the final (close() and) iput() to happen.
 
-		   There's a possibility that the final jffs2_iput() could have 
+		   There's a possibility that the final iput() could have
 		   happened while we were contemplating. In order to ensure
 		   that we don't cause a new read_inode() (which would fail)
 		   for the inode in question, we use ilookup() in this case
-		   instead of jffs2_iget().
+		   instead of iget().
 
-		   The nlink can't _become_ zero at this point because we're 
+		   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));
+			jffs2_dbg(1, "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));
+				jffs2_dbg(1, "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));
+				jffs2_dbg(1, "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);
@@ -2096,11 +1562,11 @@ struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
 	} 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.
+		   Just 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 ERR_CAST(inode);
 	}
 
 	return JFFS2_INODE_INFO(inode);
@@ -2144,7 +1610,7 @@ uint32_t jffs2_from_os_mode(uint32_t osmode)
 		return jmode | 0001000;
 #endif
 	}
-	printf("os_to_jffs2_mode() cannot convert 0x%x\n", osmode);
+	printk("os_to_jffs2_mode() cannot convert 0x%x\n", osmode);
 	BUG();
 	return 0;
 }
@@ -2185,7 +1651,7 @@ uint32_t jffs2_to_os_mode (uint32_t jmode)
 		return osmode | S_ISVTX;
 #endif
 	}
-	printf("jffs2_to_os_mode() cannot convert 0x%x\n", osmode);
+	printk("jffs2_to_os_mode() cannot convert 0x%x\n", osmode);
 	BUG();
 	return 0;
 }
diff --git a/cpukit/libfs/src/jffs2/src/gc.c b/cpukit/libfs/src/jffs2/src/gc.c
index 5a2dec2..2f42ee2 100644
--- a/cpukit/libfs/src/jffs2/src/gc.c
+++ b/cpukit/libfs/src/jffs2/src/gc.c
@@ -741,7 +741,9 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
 	struct jffs2_full_dnode *new_fn;
 	struct jffs2_raw_inode ri;
 	struct jffs2_node_frag *last_frag;
+#ifndef __rtems__
 	union jffs2_device_node dev;
+#endif /* __rtems__ */
 	char *mdata = NULL;
 	int mdatalen = 0;
 	uint32_t alloclen, ilen;
@@ -749,11 +751,15 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
 
 	if (S_ISBLK(JFFS2_F_I_MODE(f)) ||
 	    S_ISCHR(JFFS2_F_I_MODE(f)) ) {
+#ifndef __rtems__
 		/* For these, we don't actually need to read the old node */
 		mdatalen = jffs2_encode_dev(&dev, JFFS2_F_I_RDEV(f));
 		mdata = (char *)&dev;
 		jffs2_dbg(1, "%s(): Writing %d bytes of kdev_t\n",
 			  __func__, mdatalen);
+#else /* __rtems__ */
+		return -EIO;
+#endif /* __rtems__ */
 	} else if (S_ISLNK(JFFS2_F_I_MODE(f))) {
 		mdatalen = fn->size;
 		mdata = kmalloc(fn->size, GFP_KERNEL);
diff --git a/cpukit/libfs/src/jffs2/src/jffs2_fs_i.h b/cpukit/libfs/src/jffs2/src/jffs2_fs_i.h
index 2e4a867..6b6050e 100644
--- a/cpukit/libfs/src/jffs2/src/jffs2_fs_i.h
+++ b/cpukit/libfs/src/jffs2/src/jffs2_fs_i.h
@@ -50,7 +50,9 @@ struct jffs2_inode_info {
 
 	uint16_t flags;
 	uint8_t usercompr;
+#if !defined (__ECOS)
 	struct inode vfs_inode;
+#endif
 };
 
 #endif /* _JFFS2_FS_I */
diff --git a/cpukit/libfs/src/jffs2/src/malloc-rtems.c b/cpukit/libfs/src/jffs2/src/malloc-rtems.c
index a06cf5f..100b619 100644
--- a/cpukit/libfs/src/jffs2/src/malloc-rtems.c
+++ b/cpukit/libfs/src/jffs2/src/malloc-rtems.c
@@ -12,13 +12,8 @@
  */
 
 #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);
@@ -69,85 +64,70 @@ 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)
+static struct jffs2_raw_node_ref *jffs2_alloc_refblock(void)
 {
-	return 0;
-}
+	struct jffs2_raw_node_ref *ret;
 
-void jffs2_destroy_slab_caches(void)
-{
+	ret = malloc((REFS_PER_BLOCK + 1) * sizeof(*ret));
+	if (ret) {
+		int i = 0;
+		for (i=0; i < REFS_PER_BLOCK; i++) {
+			ret[i].flash_offset = REF_EMPTY_NODE;
+			ret[i].next_in_ino = NULL;
+		}
+		ret[i].flash_offset = REF_LINK_NODE;
+		ret[i].next_in_ino = NULL;
+	}
+	return ret;
 }
 
-struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void)
+int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c,
+				 struct jffs2_eraseblock *jeb, int nr)
 {
-	return malloc(sizeof(struct jffs2_raw_node_ref));
-}
+	struct jffs2_raw_node_ref **p, *ref;
+	int i = nr;
 
-void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x)
-{
-	free(x);
-}
+	p = &jeb->last_node;
+	ref = *p;
 
-#else // CYGNUM_FS_JFFS2_RAW_NODE_REF_CACHE_POOL_SIZE == 0
+	/* If jeb->last_node is really a valid node then skip over it */
+	if (ref && ref->flash_offset != REF_EMPTY_NODE)
+		ref++;
 
-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;
+	while (i) {
+		if (!ref) {
+			ref = *p = jffs2_alloc_refblock();
+			if (!ref)
+				return -ENOMEM;
+		}
+		if (ref->flash_offset == REF_LINK_NODE) {
+			p = &ref->next_in_ino;
+			ref = *p;
+			continue;
+		}
+		i--;
+		ref++;
+	}
+	jeb->allocated_refs = nr;
 
-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)
+void jffs2_free_refblock(struct jffs2_raw_node_ref *x)
 {
+	free(x);
 }
 
-struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void)
+struct jffs2_node_frag *jffs2_alloc_node_frag(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;
+	return malloc(sizeof(struct jffs2_node_frag));
 }
 
-void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x)
+void jffs2_free_node_frag(struct jffs2_node_frag *x)
 {
-	cyg_drv_mutex_lock(&mutex);
-	x->next_phys = first;
-	first = x;
-	cyg_drv_mutex_unlock(&mutex);
+	free(x);
 }
 
-#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));
diff --git a/cpukit/libfs/src/jffs2/src/nodelist.h b/cpukit/libfs/src/jffs2/src/nodelist.h
index e4619b0..1e09f4b 100644
--- a/cpukit/libfs/src/jffs2/src/nodelist.h
+++ b/cpukit/libfs/src/jffs2/src/nodelist.h
@@ -21,8 +21,8 @@
 #include "acl.h"
 #include "summary.h"
 
-#ifdef __ECOS
-#include "os-ecos.h"
+#ifdef __rtems__
+#include "os-rtems.h"
 #else
 #include "os-linux.h"
 #endif
@@ -309,6 +309,7 @@ static inline int jffs2_blocks_use_vmalloc(struct jffs2_sb_info *c)
 
 #define PAD(x) (((x)+3)&~3)
 
+#ifndef __rtems__
 static inline int jffs2_encode_dev(union jffs2_device_node *jdev, dev_t rdev)
 {
 	if (old_valid_dev(rdev)) {
@@ -319,6 +320,7 @@ static inline int jffs2_encode_dev(union jffs2_device_node *jdev, dev_t rdev)
 		return sizeof(jdev->new_id);
 	}
 }
+#endif /* __rtems__ */
 
 static inline struct jffs2_node_frag *frag_first(struct rb_root *root)
 {
diff --git a/cpukit/libfs/src/jffs2/src/os-rtems.h b/cpukit/libfs/src/jffs2/src/os-rtems.h
index bb4abe7..a47dcf9 100644
--- a/cpukit/libfs/src/jffs2/src/os-rtems.h
+++ b/cpukit/libfs/src/jffs2/src/os-rtems.h
@@ -1,55 +1,40 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2002-2003 Free Software Foundation, Inc.
+ * Copyright © 2002-2003 Free Software Foundation, Inc.
+ * Copyright © 2013 embedded brains GmbH <rtems at embedded-brains.de>
  *
  * Created by David Woodhouse <dwmw2 at cambridge.redhat.com>
  *
+ * Port to the RTEMS by embedded brains GmbH.
+ *
  * 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__
+#ifndef __JFFS2_OS_RTEMS_H__
+#define __JFFS2_OS_RTEMS_H__
 
-#include <pkgconf/fs_jffs2.h>
-#include <cyg/io/io.h>
-#include <sys/types.h>
 #include <asm/atomic.h>
-#include <linux/stat.h>
+#include <asm/bug.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 <linux/list.h>
+#include <linux/pagemap.h>
+#include <linux/stat.h>
+#include <linux/types.h>
 #include <dirent.h>
-
-#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <string.h>
+#include <time.h>
 
-#include <cyg/fileio/fileio.h>
-
-#include <cyg/hal/drv_api.h>
-#include <cyg/infra/diag.h>
+#include <rtems/jffs2.h>
 
-#include <cyg/io/flash.h>
-
-#include <linux/types.h>
-#include <linux/list.h>
-#include <asm/bug.h>
+#define CONFIG_JFFS2_RTIME
 
-#define printf diag_printf
+#define CONFIG_JFFS2_ZLIB
 
 struct _inode;
 struct super_block;
@@ -69,17 +54,14 @@ static inline unsigned int full_name_hash(const unsigned char * name, unsigned i
 	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 */
+/* NAND flash not currently supported on RTEMS */
 #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 ITIME(sec) (sec)
+#define I_SEC(tv) (tv)
  
 #define JFFS2_F_I_SIZE(f) (OFNI_EDONI_2SFFJ(f)->i_size)
 #define JFFS2_F_I_MODE(f) (OFNI_EDONI_2SFFJ(f)->i_mode)
@@ -89,11 +71,7 @@ static inline unsigned int full_name_hash(const unsigned char * name, unsigned i
 #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
+#define get_seconds() time(NULL)
 
 struct _inode {
 	cyg_uint32		i_ino;
@@ -112,6 +90,7 @@ struct _inode {
 		off_t		i_size; // For files only
 //	};
 	struct super_block *	i_sb;
+	struct jffs2_full_dirent * i_fd;
 
 	struct jffs2_inode_info	jffs2_i;
 
@@ -125,39 +104,30 @@ struct _inode {
 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
+	rtems_jffs2_flash_control	*s_flash_control;
+	rtems_jffs2_compressor_control	*s_compressor_control;
+	bool			s_is_readonly;
+	unsigned char		s_gc_buffer[PAGE_CACHE_SIZE]; // Avoids malloc when user may be under memory pressure
+	rtems_id		s_mutex;
+	char			s_name_buf[JFFS2_MAX_NAME_LEN];
 };
 
 #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 bool jffs2_is_readonly(struct jffs2_sb_info *c)
+{
+	struct super_block *sb = OFNI_BS_2SFFJ(c);
+
+	return sb->s_is_readonly;
+}
+
 static inline void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c)
 {
-	/* We don't have a GC thread in eCos (yet) */
+       /* We don't have a GC thread in RTEMS (yet) */
 }
-#endif
 
-/* fs-ecos.c */
+/* fs-rtems.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);
@@ -167,30 +137,30 @@ unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, struct jffs2_inode_i
 				   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_ */
+/* Avoid polluting RTEMS 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,
+int 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,
+int 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);
+int jffs2_flash_erase(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 
-// dir-ecos.c
+// dir-rtems.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);
+int jffs2_create(struct _inode *dir_i, const char *d_name, int namelen, int mode);
+int jffs2_mknod(struct _inode *dir_i, const unsigned char *d_name, size_t d_namelen, int mode, const unsigned char *data, size_t datalen);
+int jffs2_link (struct _inode *old_d_inode, struct _inode *dir_i, const unsigned char *d_name, size_t d_namelen);
+int jffs2_unlink(struct _inode *dir_i, struct _inode *d_inode, const unsigned char *d_name, size_t d_namelen);
+int jffs2_rmdir (struct _inode *dir_i, struct _inode *d_inode, const unsigned char *d_name, size_t d_namelen);
+int jffs2_rename (struct _inode *old_dir_i, struct _inode *d_inode, const unsigned char *old_d_name, size_t old_d_namelen,
+		  struct _inode *new_dir_i, const unsigned char *new_d_name, size_t new_d_namelen);
 
 /* erase.c */
 static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
@@ -199,6 +169,7 @@ 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_is_writebuffered(c) (0)
 #define jffs2_cleanmarker_oob(c) (0)
 #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
 
@@ -223,4 +194,4 @@ static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
 
 #define __init
 
-#endif /* __JFFS2_OS_ECOS_H__ */
+#endif /* __JFFS2_OS_RTEMS_H__ */
diff --git a/cpukit/libfs/src/jffs2/src/readinode.c b/cpukit/libfs/src/jffs2/src/readinode.c
index ae81b01..7c0f1bf 100644
--- a/cpukit/libfs/src/jffs2/src/readinode.c
+++ b/cpukit/libfs/src/jffs2/src/readinode.c
@@ -416,7 +416,14 @@ static void eat_last(struct rb_root *root, struct rb_node *node)
 
 	*link = node->rb_left;
 	if (node->rb_left)
+#ifndef __rtems__
 		node->rb_left->__rb_parent_color = node->__rb_parent_color;
+#else /* __rtems__ */
+	{
+		node->rb_left->rb_parent = node->rb_parent;
+		node->rb_left->rb_color = node->rb_color;
+	}
+#endif /* __rtems__ */
 }
 
 /* We put the version tree in reverse order, so we can use the same eat_last()
diff --git a/cpukit/libfs/src/jffs2/src/scan.c b/cpukit/libfs/src/jffs2/src/scan.c
index 7654e87..4d45ca2 100644
--- a/cpukit/libfs/src/jffs2/src/scan.c
+++ b/cpukit/libfs/src/jffs2/src/scan.c
@@ -95,8 +95,9 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
 	unsigned char *flashbuf = NULL;
 	uint32_t buf_size = 0;
 	struct jffs2_summary *s = NULL; /* summary info collected by the scan process */
+	size_t try_size;
 #ifndef __ECOS
-	size_t pointlen, try_size;
+	size_t pointlen;
 
 	ret = mtd_point(c->mtd, 0, c->mtd->size, &pointlen,
 			(void **)&flashbuf, NULL);
diff --git a/cpukit/preinstall.am b/cpukit/preinstall.am
index d22d3a1..cef2a44 100644
--- a/cpukit/preinstall.am
+++ b/cpukit/preinstall.am
@@ -257,6 +257,10 @@ $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-trace.h: libfs/src/rfs/rtems-rfs-trace.h
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-trace.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-trace.h
 
+$(PROJECT_INCLUDE)/rtems/jffs2.h: libfs/src/jffs2/include/rtems/jffs2.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/jffs2.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/jffs2.h
+
 $(PROJECT_INCLUDE)/rtems/bdbuf.h: libblock/include/rtems/bdbuf.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/bdbuf.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/bdbuf.h
diff --git a/cpukit/sapi/include/confdefs.h b/cpukit/sapi/include/confdefs.h
index 24c768f..f016b07 100644
--- a/cpukit/sapi/include/confdefs.h
+++ b/cpukit/sapi/include/confdefs.h
@@ -237,6 +237,7 @@ const rtems_libio_helper rtems_fs_init_helper =
  *     CONFIGURE_FILESYSTEM_NFS      - Network File System, networking enabled
  *     CONFIGURE_FILESYSTEM_DOSFS    - DOS File System, uses libblock
  *     CONFIGURE_FILESYSTEM_RFS      - RTEMS File System (RFS), uses libblock
+ *     CONFIGURE_FILESYSTEM_JFFS2    - Journalling Flash File System, Version 2
  *
  *   Combinations:
  *
@@ -264,6 +265,7 @@ const rtems_libio_helper rtems_fs_init_helper =
     #define CONFIGURE_FILESYSTEM_NFS
     #define CONFIGURE_FILESYSTEM_DOSFS
     #define CONFIGURE_FILESYSTEM_RFS
+    #define CONFIGURE_FILESYSTEM_JFFS2
   #endif
 
   /*
@@ -283,7 +285,8 @@ const rtems_libio_helper rtems_fs_init_helper =
         defined(CONFIGURE_FILESYSTEM_FTPFS) || \
         defined(CONFIGURE_FILESYSTEM_NFS) || \
         defined(CONFIGURE_FILESYSTEM_DOSFS) || \
-        defined(CONFIGURE_FILESYSTEM_RFS)
+        defined(CONFIGURE_FILESYSTEM_RFS) || \
+        defined(CONFIGURE_FILESYSTEM_JFFS2)
         #error "Configured filesystems but root filesystem was not IMFS!"
         #error "Filesystems could be disabled, DEVFS is root, or"
         #error "  miniIMFS is root!"
@@ -440,6 +443,16 @@ const rtems_libio_helper rtems_fs_init_helper =
     { RTEMS_FILESYSTEM_TYPE_RFS, rtems_rfs_rtems_initialise }
 #endif
 
+/**
+ * JFFS2
+ */
+#if !defined(CONFIGURE_FILESYSTEM_ENTRY_JFFS2) && \
+    defined(CONFIGURE_FILESYSTEM_JFFS2)
+  #include <rtems/jffs2.h>
+  #define CONFIGURE_FILESYSTEM_ENTRY_JFFS2 \
+    { RTEMS_FILESYSTEM_TYPE_JFFS2, rtems_jffs2_initialize }
+#endif
+
 #ifdef CONFIGURE_INIT
 
   /**
@@ -513,6 +526,10 @@ const rtems_libio_helper rtems_fs_init_helper =
           defined(CONFIGURE_FILESYSTEM_ENTRY_RFS)
         CONFIGURE_FILESYSTEM_ENTRY_RFS,
       #endif
+      #if defined(CONFIGURE_FILESYSTEM_JFFS2) && \
+          defined(CONFIGURE_FILESYSTEM_ENTRY_JFFS2)
+        CONFIGURE_FILESYSTEM_ENTRY_JFFS2,
+      #endif
       CONFIGURE_FILESYSTEM_NULL
     };
   #endif
diff --git a/cpukit/wrapup/Makefile.am b/cpukit/wrapup/Makefile.am
index 26a5bd0..e89426f 100644
--- a/cpukit/wrapup/Makefile.am
+++ b/cpukit/wrapup/Makefile.am
@@ -27,6 +27,7 @@ TMP_LIBS += ../libfs/libdefaultfs.a
 TMP_LIBS += ../libfs/libdevfs.a
 TMP_LIBS += ../libfs/libimfs.a
 TMP_LIBS += ../libfs/librfs.a
+TMP_LIBS += ../libfs/libjffs2.a
 
 TMP_LIBS += ../libmisc/libmonitor.a
 TMP_LIBS += ../libmisc/libuntar.a
-- 
1.7.7




More information about the devel mailing list