From 3c96bee3f9a3fef7f20ecaa856cc83745bf6aaea Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 12 Sep 2013 15:32:07 +0200 Subject: JFFS2: Add RTEMS support --- 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 | 231 +- cpukit/libfs/src/jffs2/src/erase.c | 2 +- cpukit/libfs/src/jffs2/src/flashio.c | 64 +- cpukit/libfs/src/jffs2/src/fs-rtems.c | 2518 ++++++++------------ 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 | 150 +- 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, 1885 insertions(+), 2822 deletions(-) create mode 100644 cpukit/libfs/src/jffs2/include/rtems/jffs2.h diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am index 1330c7d79a..7bc62960e2 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 23853f916e..f3a918169a 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 58733f739e..c9f14b5f2f 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 5047493527..e046872712 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 // Definition of NULL from the compiler +#include -// ------------------------------------------------------------------------- -// 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 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 - -#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 0000000000..fda7c35a68 --- /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 + * + * + * 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 +#include +#include + +#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 . + * + * An example mount with a simple memory based flash device simulation follows. + * The zlib is used for as the compressor. + * + * @code + * #include + * + * #include + * #include + * + * #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 4849a4c9a0..985964997e 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 * Copyright © 2004 Ferenc Havasi , * University of Szeged, Hungary + * Copyright © 2013 embedded brains GmbH * * Created by Arjan van de Ven * @@ -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 5e91d578f4..e6226e7258 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 16a5047903..3386d1e1da 100644 --- a/cpukit/libfs/src/jffs2/src/compr_rtime.c +++ b/cpukit/libfs/src/jffs2/src/compr_rtime.c @@ -28,15 +28,20 @@ #include #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 -#include -#include - -static int __init alloc_workspaces(void) +static rtems_jffs2_compressor_zlib_control *get_zlib_control( + rtems_jffs2_compressor_control *super +) { - 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; + return (rtems_jffs2_compressor_zlib_control *) super; } -static void free_workspaces(void) -{ - vfree(def_strm.workspace); - vfree(inf_strm.workspace); -} -#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 4fd9be4cbc..6c905b3854 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 16b62cc15f..1950bbda7c 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 + * Copyright © 2013 embedded brains GmbH * * Created by David Woodhouse * + * 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 $ @@ -18,39 +23,39 @@ /***********************************************************************/ /* Takes length argument because it can be either NUL-terminated or '/'-terminated */ -struct _inode *jffs2_lookup(struct _inode *dir_i, const unsigned char *d_name, int namelen) +struct _inode *jffs2_lookup(struct _inode *dir_i, const unsigned char *name, size_t 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); + uint32_t hash = full_name_hash(name, namelen); struct _inode *inode = NULL; D1(printk("jffs2_lookup()\n")); dir_f = JFFS2_INODE_INFO(dir_i); - c = JFFS2_SB_INFO(dir_i->i_sb); - down(&dir_f->sem); + 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) { if (fd_list->nhash == hash && (!fd || fd_list->version > fd->version) && strlen((char *)fd_list->name) == namelen && - !strncmp((char *)fd_list->name, (char *)d_name, namelen)) { + !strncmp((char *)fd_list->name, (char *)name, namelen)) { fd = fd_list; } } 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, size_t d_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 = d_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 4a6cf289be..d0d8a6972f 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 13a12e35b3..af93168cea 100644 --- a/cpukit/libfs/src/jffs2/src/flashio.c +++ b/cpukit/libfs/src/jffs2/src/flashio.c @@ -15,46 +15,28 @@ #include #include "nodelist.h" -#include -#include -#include - -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); - - //D2(printf("FLASH READ\n")); - //D2(printf("read address = %x\n", CYGNUM_FS_JFFS2_BASE_ADDRESS + read_buffer_offset)); - //D2(printf("write address = %x\n", write_buffer)); - //D2(printf("size = %x\n", size)); - err = cyg_io_bread(sb->s_dev, write_buffer, &len, read_buffer_offset); - - *return_size = (size_t) len; - return ((err == ENOERR) ? ENOERR : -EIO); + const struct super_block *sb = OFNI_BS_2SFFJ(c); + rtems_jffs2_flash_control *fc = sb->s_flash_control; + + *return_size = size; + + 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)); + *return_size = size; - err = cyg_io_bwrite(sb->s_dev, read_buffer, &len, write_buffer_offset); - *return_size = (size_t) len; - - 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 c38b71906c..376c77f45f 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 + * Copyright © 2013 embedded brains GmbH * * Created by Dominic Ostrowski * 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,38 @@ #include "compr.h" #include #include -#include - -#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 +#include + +/* Ensure that the JFFS2 values are identical to the POSIX defines */ + +RTEMS_STATIC_ASSERT(DT_DIR == (S_IFDIR >> 12), DT_DIR); +RTEMS_STATIC_ASSERT(DT_LNK == (S_IFLNK >> 12), DT_LNK); +RTEMS_STATIC_ASSERT(DT_REG == (S_IFREG >> 12), DT_REG); + +RTEMS_STATIC_ASSERT(00400 == S_IRUSR, S_IRUSR); +RTEMS_STATIC_ASSERT(00200 == S_IWUSR, S_IWUSR); +RTEMS_STATIC_ASSERT(00100 == S_IXUSR, S_IXUSR); +RTEMS_STATIC_ASSERT(00040 == S_IRGRP, S_IRGRP); +RTEMS_STATIC_ASSERT(00020 == S_IWGRP, S_IWGRP); +RTEMS_STATIC_ASSERT(00010 == S_IXGRP, S_IXGRP); +RTEMS_STATIC_ASSERT(00004 == S_IROTH, S_IROTH); +RTEMS_STATIC_ASSERT(00002 == S_IWOTH, S_IWOTH); +RTEMS_STATIC_ASSERT(00001 == S_IXOTH, S_IXOTH); + +RTEMS_STATIC_ASSERT(0140000 == S_IFSOCK, S_IFSOCK); +RTEMS_STATIC_ASSERT(0120000 == S_IFLNK, S_IFLNK); +RTEMS_STATIC_ASSERT(0100000 == S_IFREG, S_IFREG); +RTEMS_STATIC_ASSERT(0060000 == S_IFBLK, S_IFBLK); +RTEMS_STATIC_ASSERT(0040000 == S_IFDIR, S_IFDIR); +RTEMS_STATIC_ASSERT(0020000 == S_IFCHR, S_IFCHR); +RTEMS_STATIC_ASSERT(0010000 == S_IFIFO, S_IFIFO); +RTEMS_STATIC_ASSERT(0004000 == S_ISUID, S_ISUID); +RTEMS_STATIC_ASSERT(0002000 == S_ISGID, S_ISGID); +RTEMS_STATIC_ASSERT(0001000 == S_ISVTX, S_ISVTX); 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 +93,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) +// jffs2_fo_write() +// Write data to file. +static int jffs2_extend_file (struct _inode *inode, struct jffs2_raw_inode *ri, + unsigned long offset) { - 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. + 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; -static int find_entry(jffs2_dirsearch * ds) -{ - struct _inode *dir = ds->dir; - const unsigned char *name = ds->path; - const unsigned char *n = name; - char namelen = 0; - struct _inode *d; + /* 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)); - D2(printf("find_entry\n")); + ret = jffs2_reserve_space(c, sizeof(*ri), &alloc_len, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); + if (ret) + return ret; - // check that we really have a directory - if (!S_ISDIR(dir->i_mode)) - return ENOTDIR; + mutex_lock(&f->sem); - // Isolate the next element of the path name. - while (*n != '\0' && *n != '/') - n++, namelen++; + 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)); - // Check if this is the last path element. - while( *n == '/') n++; - if (*n == '\0') - ds->last = true; + ri->version = cpu_to_je32(++f->highest_version); + ri->isize = cpu_to_je32(max((uint32_t)inode->i_size, offset)); - // update name in dirsearch object - ds->name = name; - ds->namelen = namelen; + 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; + } + 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); + mutex_unlock(&f->sem); + return ret; + } + inode->i_size = offset; + mutex_unlock(&f->sem); + return 0; +} - 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; +static int jffs2_do_setattr (struct _inode *inode, struct iattr *iattr) +{ + 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; + + jffs2_dbg(1, "%s(): ino #%lu\n", __func__, inode->i_ino); + + /* 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); + } - // Here we have the name and its length set up. - // Search the directory for a matching entry - - D2(printf("find_entry for name = %s\n", ds->path)); - d = jffs2_lookup(dir, name, namelen); - D2(printf("find_entry got dir = %x\n", d)); - - if (d == NULL) - return ENOENT; - if (IS_ERR(d)) - return -PTR_ERR(d); - - // If it's a new directory inode, increase refcount on its parent - if (S_ISDIR(d->i_mode) && !d->i_parent) { - d->i_parent = dir; - dir->i_count++; + ri = jffs2_alloc_raw_inode(); + if (!ri) { + if (S_ISLNK(inode->i_mode)) + kfree(mdata); + return -ENOMEM; } - // pass back the node we have found - ds->node = d; - return ENOERR; + 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; -} + 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)); -// ------------------------------------------------------------------------- -// jffs2_find() -// Main interface to directory search code. This is used in all file -// level operations to locate the object named by the pathname. + ri->ino = cpu_to_je32(inode->i_ino); + ri->version = cpu_to_je32(++f->highest_version); -// 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; + 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)); + + if (ivalid & ATTR_MODE) + ri->mode = cpu_to_jemode(iattr->ia_mode); + else + ri->mode = cpu_to_jemode(inode->i_mode); + + + 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)); + + 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); + + new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, alloc_type); + if (S_ISLNK(inode->i_mode)) + kfree(mdata); + + 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)); - D2(printf("jffs2_find for path =%s\n", d->path)); - // Short circuit empty paths - if (*(d->path) == '\0') { - d->node->i_count++; - return ENOERR; - } + old_metadata = f->metadata; - // iterate down directory tree until we find the object - // we want. - for (;;) { - err = find_entry(d); + if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) + jffs2_truncate_fragtree (c, &f->fragtree, iattr->ia_size); - if (err != ENOERR) - 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; + } + if (old_metadata) { + jffs2_mark_node_obsolete(c, old_metadata->raw); + jffs2_free_full_dnode(old_metadata); + } + jffs2_free_raw_inode(ri); - if (d->last) - return ENOERR; + mutex_unlock(&f->sem); + jffs2_complete_reservation(c); - /* 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); + /* 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); + } - // Update dirsearch object to search next directory. - d->dir = d->node; - d->path += d->namelen; - while (*(d->path) == '/') - d->path++; // skip dirname separators - } + return 0; } -//========================================================================== -// Pathconf support -// This function provides support for pathconf() and fpathconf(). +typedef struct { + struct super_block sb; + struct jffs2_inode_cache *inode_cache[]; +} rtems_jffs2_fs_info; -static int jffs2_pathconf(struct _inode *node, struct cyg_pathconf_info *info) +static void rtems_jffs2_do_lock(const struct super_block *sb) { - int err = ENOERR; - D2(printf("jffs2_pathconf\n")); - - switch (info->name) { - case _PC_LINK_MAX: - info->value = LINK_MAX; - break; - - case _PC_MAX_CANON: - info->value = -1; // not supported - err = EINVAL; - break; - - case _PC_MAX_INPUT: - info->value = -1; // not supported - err = EINVAL; - break; - - case _PC_NAME_MAX: - info->value = NAME_MAX; - break; - - case _PC_PATH_MAX: - info->value = PATH_MAX; - break; - - case _PC_PIPE_BUF: - info->value = -1; // not supported - err = EINVAL; - break; - - case _PC_ASYNC_IO: - info->value = -1; // not supported - err = EINVAL; - break; - - case _PC_CHOWN_RESTRICTED: - info->value = -1; // not supported - err = EINVAL; - break; - - case _PC_NO_TRUNC: - info->value = 0; - break; - - case _PC_PRIO_IO: - info->value = 0; - break; - - case _PC_SYNC_IO: - info->value = 0; - break; - - case _PC_VDISABLE: - info->value = -1; // not supported - err = EINVAL; - break; - - default: - err = EINVAL; - break; - } - - return err; + rtems_status_code sc = rtems_semaphore_obtain(sb->s_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + assert(sc == RTEMS_SUCCESSFUL); } -//========================================================================== -// Filesystem operations - -// ------------------------------------------------------------------------- -// jffs2_mount() -// Process a mount request. This mainly creates a root for the -// filesystem. -static int jffs2_read_super(struct super_block *sb) +static void rtems_jffs2_do_unlock(const 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; + rtems_status_code sc = rtems_semaphore_release(sb->s_mutex); + assert(sc == RTEMS_SUCCESSFUL); +} - D1(printk(KERN_DEBUG "jffs2: read_super\n")); +static void rtems_jffs2_free_directory_entries(struct _inode *inode) +{ + struct jffs2_full_dirent *current = inode->jffs2_i.dents; - c = JFFS2_SB_INFO(sb); + while (current != NULL) { + struct jffs2_full_dirent *victim = current; - len = sizeof (ds); - err = cyg_io_get_config(sb->s_dev, - CYG_IO_GET_CONFIG_FLASH_DEVSIZE, &ds, &len); - if (err != ENOERR) { - D1(printf - ("jffs2: cyg_io_get_config failed to get dev size: %d\n", - err)); - return err; - } - len = sizeof (bs); - bs.offset = 0; - err = cyg_io_get_config(sb->s_dev, - CYG_IO_GET_CONFIG_FLASH_BLOCKSIZE, &bs, &len); - if (err != ENOERR) { - D1(printf - ("jffs2: cyg_io_get_config failed to get block size: %d\n", - err)); - return err; + current = victim->next; + jffs2_free_full_dirent(victim); } +} - c->sector_size = bs.block_size; - c->flash_size = ds.dev_size; - c->cleanmarker_size = sizeof(struct jffs2_unknown_node); - - err = jffs2_do_mount_fs(c); - if (err) - return -err; - - D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n")); - sb->s_root = jffs2_iget(sb, 1); - if (IS_ERR(sb->s_root)) { - D1(printk(KERN_WARNING "get root inode failed\n")); - err = PTR_ERR(sb->s_root); - sb->s_root = NULL; - goto out_nodes; +static void rtems_jffs2_flash_control_destroy(rtems_jffs2_flash_control *fc) +{ + if (fc->destroy != NULL) { + (*fc->destroy)(fc); } - - return 0; - - out_nodes: - jffs2_free_ino_caches(c); - jffs2_free_raw_node_refs(c); - free(c->blocks); - - return err; } - -static int jffs2_mount(cyg_fstab_entry * fste, cyg_mtab_entry * mte) +static void rtems_jffs2_compressor_control_destroy(rtems_jffs2_compressor_control *cc) { - extern cyg_mtab_entry cyg_mtab[], cyg_mtab_end; - struct super_block *jffs2_sb = NULL; - struct jffs2_sb_info *c; - cyg_mtab_entry *m; - cyg_io_handle_t t; - Cyg_ErrNo err; - - D2(printf("jffs2_mount\n")); - - err = cyg_io_lookup(mte->devname, &t); - if (err != ENOERR) - return -err; - - // Iterate through the mount table to see if we're mounted - // FIXME: this should be done better - perhaps if the superblock - // can be stored as an inode in the icache. - for (m = &cyg_mtab[0]; m != &cyg_mtab_end; m++) { - // stop if there are more than the configured maximum - if (m - &cyg_mtab[0] >= CYGNUM_FILEIO_MTAB_MAX) { - m = &cyg_mtab_end; - break; - } - if (m->valid && strcmp(m->fsname, "jffs2") == 0 && - strcmp(m->devname, mte->devname) == 0) { - jffs2_sb = (struct super_block *) m->data; - } + if (cc != NULL && cc->destroy != NULL) { + (*cc->destroy)(cc); } +} - 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); +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); - if (err) { - if (--n_fs_mounted == 0) { - jffs2_destroy_slab_caches(); - jffs2_compressors_exit(); - } - - free(jffs2_sb); - free(c->inocache_list); - return err; - } + if (do_mount_fs_was_successful) { + jffs2_free_ino_caches(c); + jffs2_free_raw_node_refs(c); + free(c->blocks); + } - 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 + if (sb->s_mutex != 0) { + rtems_status_code sc = rtems_semaphore_delete(sb->s_mutex); + assert(sc == RTEMS_SUCCESSFUL); } - 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)); + rtems_jffs2_flash_control_destroy(fs_info->sb.s_flash_control); + rtems_jffs2_compressor_control_destroy(fs_info->sb.s_compressor_control); - return ENOERR; + free(fs_info); } -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 int rtems_jffs2_eno_to_rv_and_errno(int eno) { - struct _inode *root = (struct _inode *) mte->root; - struct super_block *jffs2_sb = root->i_sb; - struct jffs2_sb_info *c = JFFS2_SB_INFO(jffs2_sb); - struct jffs2_full_dirent *fd, *next; - - D2(printf("jffs2_umount\n")); - - // Only really umount if this is the only mount - if (jffs2_sb->s_mount_count == 1) { - icache_evict(root, NULL); - if (root->i_cache_next != NULL) { - struct _inode *inode = root; - printf("Refuse to unmount.\n"); - while (inode) { - printf("Ino #%u has use count %d\n", - inode->i_ino, inode->i_count); - inode = inode->i_cache_next; - } - // root icount was set to 1 on mount - return EBUSY; - } - if (root->i_count == 2 && - cyg_cdir_mtab_entry == mte && - cyg_cdir_dir == (cyg_dir)root && - !strcmp(mte->name, "/")) { - /* If we were mounted on root, there's no - way for the cwd to change out and free - the file system for unmounting. So we hack - it -- if cwd is '/' we unset it. Perhaps - we should allow chdir(NULL) to unset - cyg_cdir_dir? */ - cyg_cdir_dir = CYG_DIR_NULL; - jffs2_iput(root); - } - /* Argh. The fileio code sets this; never clears it */ - if (cyg_cdir_mtab_entry == mte) - cyg_cdir_mtab_entry = NULL; - - if (root->i_count != 1) { - printf("Ino #1 has use count %d\n", - root->i_count); - return EBUSY; - } -#ifdef CYGOPT_FS_JFFS2_GCTHREAD - jffs2_stop_garbage_collect_thread(c); -#endif - jffs2_iput(root); // Time to free the root inode - - // free directory entries - for (fd = root->jffs2_i.dents; fd; fd = next) { - next=fd->next; - jffs2_free_full_dirent(fd); - } - - free(root); - //Clear root inode - //root_i = NULL; - - // Clean up the super block and root inode - jffs2_free_ino_caches(c); - jffs2_free_raw_node_refs(c); - free(c->blocks); - free(c->inocache_list); - free(jffs2_sb); - // Clear superblock & root pointer - mte->root = CYG_DIR_NULL; - mte->data = 0; - mte->fs->data = 0; // fstab entry, visible to all mounts. No current mount - // That's all folks. - D2(printf("jffs2_umount No current mounts\n")); + if (eno == 0) { + return 0; } else { - jffs2_sb->s_mount_count--; - } - if (--n_fs_mounted == 0) { - jffs2_destroy_slab_caches(); - jffs2_compressors_exit(); + errno = eno; + + return -1; } - return ENOERR; } -// ------------------------------------------------------------------------- -// jffs2_open() -// Open a file for reading or writing. - -static int jffs2_open(cyg_mtab_entry * mte, cyg_dir dir, const char *name, - int mode, cyg_file * file) +static struct _inode *rtems_jffs2_get_inode_by_location( + const rtems_filesystem_location_info_t *loc +) { + return loc->node_access; +} - jffs2_dirsearch ds; - struct _inode *node = NULL; - int err; - - D2(printf("jffs2_open\n")); - - /* If no chdir has been called and we were the first file system - mounted, we get called with dir == NULL. Deal with it */ - if (!dir) - dir = mte->root; +static struct _inode *rtems_jffs2_get_inode_by_iop( + const rtems_libio_t *iop +) +{ + return iop->pathinfo.node_access; +} -#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 int rtems_jffs2_fstat( + const rtems_filesystem_location_info_t *loc, + struct stat *buf +) +{ + struct _inode *inode = rtems_jffs2_get_inode_by_location(loc); - err = jffs2_find(&ds); + rtems_jffs2_do_lock(inode->i_sb); - if (err == ENOENT) { -#ifdef CYGOPT_FS_JFFS2_WRITE - if (ds.last && (mode & O_CREAT)) { + 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; - // 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_unlock(inode->i_sb); - err = jffs2_create(ds.dir, ds.name, S_IRUGO|S_IXUGO|S_IWUSR|S_IFREG, &node); + return 0; +} - if (err != 0) { - //Possible orphaned inode on the flash - but will be gc'd - jffs2_iput(ds.dir); - return -err; - } +static int rtems_jffs2_fill_dirent(struct dirent *de, off_t off, uint32_t ino, const char *name) +{ + int eno = 0; + size_t len; - err = ENOERR; - } -#endif - } else if (err == ENOERR) { - // The node exists. If the O_CREAT and O_EXCL bits are set, we - // must fail the open. - - if ((mode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) { - jffs2_iput(ds.node); - err = EEXIST; - } else - node = ds.node; - } + memset(de, 0, sizeof(*de)); - // Finished with the directory now - jffs2_iput(ds.dir); + de->d_off = off * sizeof(*de); + de->d_reclen = sizeof(*de); + de->d_ino = ino; - if (err != ENOERR) - return err; + len = strlen(name); + de->d_namlen = len; - // Check that we actually have a file here - if (S_ISDIR(node->i_mode)) { - jffs2_iput(node); - return EISDIR; + if (len < sizeof(de->d_name) - 1) { + memcpy(&de->d_name[0], name, len); + } else { + eno = EOVERFLOW; } - // If the O_TRUNC bit is set we must clean out the file data. - if (mode & O_TRUNC) { -#ifdef CYGOPT_FS_JFFS2_WRITE - err = jffs2_truncate_file(node); - if (err) { - jffs2_iput(node); - return err; - } -#else - jffs2_iput(node); - return EROFS; -#endif - } - - // Initialise the file object - file->f_flag |= mode & CYG_FILE_MODE_MASK; - file->f_type = CYG_FILE_TYPE_FILE; - file->f_ops = &jffs2_fileops; - file->f_offset = (mode & O_APPEND) ? node->i_size : 0; - file->f_data = (CYG_ADDRWORD) node; - file->f_xops = 0; - - return ENOERR; + 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")); - - init_dirsearch(&ds, (struct _inode *) dir, - (const unsigned char *)name); - - err = jffs2_find(&ds); - - if (err != ENOERR) { - jffs2_iput(ds.dir); - return err; + 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; + + rtems_jffs2_do_lock(inode->i_sb); + + fd = f->dents; + begin = iop->offset; + end = begin + len / sizeof(*de); + off = begin; + + 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; - D2(printf("jffs2_ops_rmdir\n")); + rtems_jffs2_do_lock(inode->i_sb); - init_dirsearch(&ds, (struct _inode *) dir, - (const unsigned char *)name); + pos = iop->offset; - err = jffs2_find(&ds); + if (pos >= inode->i_size) { + len = 0; + } else { + uint32_t pos_32 = (uint32_t) pos; + uint32_t max_available = inode->i_size - pos_32; - if (err != ENOERR) { - jffs2_iput(ds.dir); - return err; + if (len > max_available) { + len = max_available; + } + + 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); - - // Update directory times - if (!err) - ds1.dir->i_ctime = - ds1.dir->i_mtime = - ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp(); - out: - jffs2_iput(ds1.dir); - if (S_ISDIR(ds1.node->i_mode)) { - /* Renamed a directory to elsewhere... so fix up its - i_parent pointer and the i_counts of its old and - new parents. */ - jffs2_iput(ds1.node->i_parent); - ds1.node->i_parent = ds2.dir; - /* We effectively increase its use count by not... */ - } else { - jffs2_iput(ds2.dir); /* ... doing this */ - } - jffs2_iput(ds1.node); - if (ds2.node) - jffs2_iput(ds2.node); - - return err; -} -// ------------------------------------------------------------------------- -// jffs2_ops_link() -// Make a new directory entry for a file. - -static int jffs2_ops_link(cyg_mtab_entry * mte, cyg_dir dir1, const char *name1, - cyg_dir dir2, const char *name2, int type) -{ - jffs2_dirsearch ds1, ds2; - int err; + rtems_jffs2_do_unlock(inode->i_sb); - D2(printf("jffs2_ops_link\n")); - - // Only do hard links for now in this filesystem - if (type != CYG_FSLINK_HARD) - return EINVAL; - - init_dirsearch(&ds1, (struct _inode *) dir1, - (const unsigned char *) name1); - - err = jffs2_find(&ds1); + if (eno == 0) { + return writtenlen; + } else { + errno = eno; - if (err != ENOERR) { - jffs2_iput(ds1.dir); - return err; + return -1; } +} - init_dirsearch(&ds2, (struct _inode *) dir2, - (const unsigned char *) name2); +static int rtems_jffs2_file_ftruncate(rtems_libio_t *iop, off_t length) +{ + struct _inode *inode = rtems_jffs2_get_inode_by_iop(iop); + struct iattr iattr; + int eno; - err = jffs2_find(&ds2); + iattr.ia_valid = ATTR_SIZE | ATTR_MTIME | ATTR_CTIME; + iattr.ia_size = length; + iattr.ia_mtime = get_seconds(); + iattr.ia_ctime = iattr.ia_mtime; - // 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; - } + rtems_jffs2_do_lock(inode->i_sb); - // Allow through links to non-existing terminal objects - if (ds2.last && err == ENOENT) { - ds2.node = NULL; - err = ENOERR; - } + eno = -jffs2_do_setattr(inode, &iattr); - if (err != ENOERR) { - jffs2_iput(ds1.dir); - jffs2_iput(ds1.node); - jffs2_iput(ds2.dir); - return err; - } + rtems_jffs2_do_unlock(inode->i_sb); - // 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")); - - if (dir_out != NULL) { - // This is a request to get a new directory pointer in - // *dir_out. + 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 (access_ok) { + struct _inode *entry_i; + + 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); + } - jffs2_dirsearch ds; - int err; + 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; - init_dirsearch(&ds, (struct _inode *) dir, - (const unsigned char *) name); + rtems_filesystem_eval_path_clear_token(ctx); - err = jffs2_find(&ds); - jffs2_iput(ds.dir); + 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; - if (err != ENOERR) - return err; + rtems_filesystem_eval_path_recursive(ctx, target, strlen(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. + 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; + } - struct _inode *node = (struct _inode *) dir; + 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; - - down(&f->sem); - - // Loop over the io vectors until there are none left - for (i = 0; i < uio->uio_iovcnt && pos < inode->i_size; i++) { - int ret; - cyg_iovec *iov = &uio->uio_iov[i]; - off_t len = min(iov->iov_len, inode->i_size - pos); + struct super_block *sb = inode->i_sb; + char *fd_name = inode->i_fd->name; + size_t fd_namelen = strlen(fd_name); + int eno = 0; + + 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; + } - D2(printf("jffs2_fo_read inode size %d\n", inode->i_size)); + return eno; +} - 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; +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); + + 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; + rtems_jffs2_fs_info *fs_info = mt_entry->fs_info; + struct _inode *root_i = mt_entry->mt_fs_root->location.node_access; - // 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; + icache_evict(root_i, NULL); + assert(root_i->i_cache_next == NULL); + assert(root_i->i_count == 1); + jffs2_iput(root_i); - 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_free_directory_entries(root_i); + free(root_i); - // Now loop over the iovecs until they are all done, or - // we get an error. - for (i = 0; i < uio->uio_iovcnt; i++) { - cyg_iovec *iov = &uio->uio_iov[i]; - unsigned char *buf = iov->iov_base; - off_t len = iov->iov_len; - - uint32_t writtenlen; - int err; - - D2(printf("jffs2_fo_write page_start_pos %d\n", pos)); - D2(printf("jffs2_fo_write transfer size %d\n", len)); - - err = jffs2_write_inode_range(c, f, &ri, buf, - pos, len, &writtenlen); - if (err) - return -err; - - if (writtenlen != len) - return ENOSPC; + rtems_jffs2_free_fs_info(fs_info, true); +} - pos += len; - resid -= len; +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); + + 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; - - case SEEK_END: - // Add pos to file size. - pos += node->i_size; - break; - - default: - return EINVAL; + 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; + + 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; - - D2(printf("jffs2_fo_fstat\n")); - - // Fill in the status - buf->st_mode = node->i_mode; - buf->st_ino = node->i_ino; - buf->st_dev = 0; - buf->st_nlink = node->i_nlink; - buf->st_uid = node->i_uid; - buf->st_gid = node->i_gid; - buf->st_size = node->i_size; - buf->st_atime = node->i_atime; - buf->st_mtime = node->i_mtime; - buf->st_ctime = node->i_ctime; - - return ENOERR; + /* + * 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. + */ + + int size_mb = flash_size / 1024 / 1024; + int hashsize = (size_mb * 2) & ~0x3f; + + if (hashsize < INOCACHE_HASHSIZE_MIN) + return INOCACHE_HASHSIZE_MIN; + if (hashsize > INOCACHE_HASHSIZE_MAX) + return INOCACHE_HASHSIZE_MAX; + + 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; -} + sb = &fs_info->sb; + c = JFFS2_SB_INFO(sb); -//========================================================================== -// Directory operations + if (err == 0) { + uint32_t blocks = fc->flash_size / fc->block_size; -// ------------------------------------------------------------------------- -// jffs2_fo_dirread() -// Read a single directory entry from a file. + 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 __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->flash_size < 5*fc->block_size) { + pr_err("Too few erase blocks (%d)\n", + fc->flash_size / fc->block_size); + err = -EINVAL; + } + } -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 (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 + ); - if (len < sizeof (struct dirent)) - return EINVAL; + err = sc == RTEMS_SUCCESSFUL ? 0 : -ENOMEM; + } - D1(printk - (KERN_DEBUG "jffs2_readdir() for dir_i #%lu\n", d_inode->i_ino)); + if (err == 0) { + sb->s_is_readonly = !mt_entry->writeable; + sb->s_flash_control = fc; + sb->s_compressor_control = jffs2_mount_data->compressor_control; - f = JFFS2_INODE_INFO(inode); - c = JFFS2_SB_INFO(inode->i_sb); + 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); - offset = fp->f_offset; - - if (offset == 0) { - D1(printk - (KERN_DEBUG "Dirent 0: \".\", ino #%lu\n", inode->i_ino)); - filldir(nbuf, nlen, (const unsigned char *) ".", 1); -#ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE - // Flags here are the same as jffs2_mkdir. Make sure - // d_type is the same as st_mode of calling stat. - ent->d_type = - jemode_to_cpu(cpu_to_jemode(S_IRUGO|S_IXUGO|S_IWUSR|S_IFDIR)); -#endif - goto out; - } - if (offset == 1) { - filldir(nbuf, nlen, (const unsigned char *) "..", 2); -#ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE - // Flags here are the same as jffs2_mkdir. Make sure - // d_type is the same as st_mode of calling stat. - ent->d_type = - jemode_to_cpu(cpu_to_jemode(S_IRUGO|S_IXUGO|S_IWUSR|S_IFDIR)); -#endif - goto out; + err = jffs2_do_mount_fs(c); } - curofs = 1; - down(&f->sem); - for (fd = f->dents; fd; fd = fd->next) { - - curofs++; - /* First loop: curofs = 2; offset = 2 */ - if (curofs < offset) { - D2(printk - (KERN_DEBUG - "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n", - fd->name, fd->ino, fd->type, curofs, offset)); - continue; - } - if (!fd->ino) { - D2(printk - (KERN_DEBUG "Skipping deletion dirent \"%s\"\n", - fd->name)); - offset++; - continue; - } - D2(printk - (KERN_DEBUG "Dirent %ld: \"%s\", ino #%u, type %d\n", offset, - fd->name, fd->ino, fd->type)); - filldir(nbuf, nlen, fd->name, strlen((char *)fd->name)); -#ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE - c_ino = jffs2_iget(inode->i_sb, fd->ino); - if(IS_ERR(c_ino)) { - D1(printk(KERN_WARNING "get entry inode failed\n")); - // fileio already set it to zero, so not needed here - // ent->d_type = 0; - } - else { - ent->d_type = c_ino->i_mode; - jffs2_iput(c_ino); + if (err == 0) { + do_mount_fs_was_successful = true; + + sb->s_root = jffs2_iget(sb, 1); + if (IS_ERR(sb->s_root)) { + err = PTR_ERR(sb->s_root); } -#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 +1259,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 +1357,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 +1377,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--; @@ -1937,7 +1421,6 @@ void jffs2_iput(struct _inode *i) static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) { memset(f, 0, sizeof(*f)); - init_MUTEX_LOCKED(&f->sem); } static void jffs2_clear_inode (struct _inode *inode) @@ -1978,7 +1461,8 @@ struct _inode *jffs2_new_inode (struct _inode *dir_i, int mode, struct jffs2_raw 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 +1472,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 +1483,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; @@ -2025,7 +1509,7 @@ static int jffs2_read_inode (struct _inode *inode) 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 +1520,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 +1535,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,96 +1582,12 @@ 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); } - - - -uint32_t jffs2_from_os_mode(uint32_t osmode) -{ - uint32_t jmode = ((osmode & S_IRUSR)?00400:0) | - ((osmode & S_IWUSR)?00200:0) | - ((osmode & S_IXUSR)?00100:0) | - ((osmode & S_IRGRP)?00040:0) | - ((osmode & S_IWGRP)?00020:0) | - ((osmode & S_IXGRP)?00010:0) | - ((osmode & S_IROTH)?00004:0) | - ((osmode & S_IWOTH)?00002:0) | - ((osmode & S_IXOTH)?00001:0); - - switch (osmode & S_IFMT) { - case S_IFSOCK: - return jmode | 0140000; - case S_IFLNK: - return jmode | 0120000; - case S_IFREG: - return jmode | 0100000; - case S_IFBLK: - return jmode | 0060000; - case S_IFDIR: - return jmode | 0040000; - case S_IFCHR: - return jmode | 0020000; - case S_IFIFO: - return jmode | 0010000; - case S_ISUID: - return jmode | 0004000; - case S_ISGID: - return jmode | 0002000; -#ifdef S_ISVTX - case S_ISVTX: - return jmode | 0001000; -#endif - } - printf("os_to_jffs2_mode() cannot convert 0x%x\n", osmode); - BUG(); - return 0; -} - -uint32_t jffs2_to_os_mode (uint32_t jmode) -{ - uint32_t osmode = ((jmode & 00400)?S_IRUSR:0) | - ((jmode & 00200)?S_IWUSR:0) | - ((jmode & 00100)?S_IXUSR:0) | - ((jmode & 00040)?S_IRGRP:0) | - ((jmode & 00020)?S_IWGRP:0) | - ((jmode & 00010)?S_IXGRP:0) | - ((jmode & 00004)?S_IROTH:0) | - ((jmode & 00002)?S_IWOTH:0) | - ((jmode & 00001)?S_IXOTH:0); - - switch(jmode & 00170000) { - case 0140000: - return osmode | S_IFSOCK; - case 0120000: - return osmode | S_IFLNK; - case 0100000: - return osmode | S_IFREG; - case 0060000: - return osmode | S_IFBLK; - case 0040000: - return osmode | S_IFDIR; - case 0020000: - return osmode | S_IFCHR; - case 0010000: - return osmode | S_IFIFO; - case 0004000: - return osmode | S_ISUID; - case 0002000: - return osmode | S_ISGID; -#ifdef S_ISVTX - case 0001000: - return osmode | S_ISVTX; -#endif - } - printf("jffs2_to_os_mode() cannot convert 0x%x\n", osmode); - BUG(); - return 0; -} diff --git a/cpukit/libfs/src/jffs2/src/gc.c b/cpukit/libfs/src/jffs2/src/gc.c index 5a2dec2b06..2f42ee2d70 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 2e4a86763c..6b6050e9eb 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 a06cf5f16d..100b619e07 100644 --- a/cpukit/libfs/src/jffs2/src/malloc-rtems.c +++ b/cpukit/libfs/src/jffs2/src/malloc-rtems.c @@ -12,13 +12,8 @@ */ #include -#include #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 e4619b00f7..1e09f4bdce 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 bb4abe70ac..9fdb6a5bd3 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 * * Created by David Woodhouse * + * 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 -#include -#include #include -#include +#include #include - -#include -#include -#include - -#include // tracing macros -#include // assertion macros - -#include -#include -#include -#include -#include +#include +#include +#include +#include #include - -#include +#include +#include #include +#include -#include - -#include -#include +#include -#include - -#include -#include -#include +#define CONFIG_JFFS2_RTIME -#define printf diag_printf +#define CONFIG_JFFS2_ZLIB struct _inode; struct super_block; @@ -59,7 +44,7 @@ struct iovec { ssize_t iov_len; }; -static inline unsigned int full_name_hash(const unsigned char * name, unsigned int len) { +static inline unsigned int full_name_hash(const unsigned char * name, size_t len) { unsigned hash = 0; while (len--) { @@ -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,37 @@ 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); +static inline uint32_t jffs2_from_os_mode(uint32_t osmode) +{ + return osmode & (S_IFMT | S_IRWXU | S_IRWXG | S_IRWXO); +} + +static inline uint32_t jffs2_to_os_mode (uint32_t jmode) +{ + return jmode & (S_IFMT | S_IRWXU | S_IRWXG | S_IRWXO); +} /* 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); - -// dir-ecos.c -struct _inode *jffs2_lookup(struct _inode *dir_i, const unsigned char *name, int namelen); -int jffs2_create(struct _inode *dir_i, const unsigned char *d_name, int mode, struct _inode **new_i); -int jffs2_mkdir (struct _inode *dir_i, const unsigned char *d_name, int mode); -int jffs2_link (struct _inode *old_d_inode, struct _inode *dir_i, const unsigned char *d_name); -int jffs2_unlink(struct _inode *dir_i, struct _inode *d_inode, const unsigned char *d_name); -int jffs2_rmdir (struct _inode *dir_i, struct _inode *d_inode, const unsigned char *d_name); -int jffs2_rename (struct _inode *old_dir_i, struct _inode *d_inode, const unsigned char *old_d_name, - struct _inode *new_dir_i, const unsigned char *new_d_name); +int jffs2_flash_erase(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); + +// dir-rtems.c +struct _inode *jffs2_lookup(struct _inode *dir_i, const unsigned char *name, size_t namelen); +int jffs2_create(struct _inode *dir_i, const char *d_name, size_t d_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 +176,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 +201,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 ae81b01e6f..7c0f1bf631 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 7654e87b04..4d45ca2ea4 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 d22d3a1cd1..cef2a44add 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 24c768f700..f016b07254 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 + #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 26a5bd00f0..e89426fee8 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 -- cgit v1.2.3