From 672038b174456ff89d46a5f16ecac90f43e364f3 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 12 Sep 2013 16:46:51 +0200 Subject: JFFS2: Import from eCos Import of Linux compatibility layer and JFFS2 file system support from eCos. The files are imported from eCos CVS on 2013-09-16. cvs -d :pserver:anoncvs@ecos.sourceware.org:/cvs/ecos login cvs -z3 -d :pserver:anoncvs@ecos.sourceware.org:/cvs/ecos co -P ecos The files "ecos/packages/compat/linux/current/asm/atomic.h", "ecos/packages/compat/linux/current/asm/bug.h", "ecos/packages/compat/linux/current/asm/page.h", "ecos/packages/compat/linux/current/cyg/crc/crc.h", "ecos/packages/compat/linux/current/cyg/infra/cyg_type.h", "ecos/packages/compat/linux/current/linux/compiler.h", "ecos/packages/compat/linux/current/linux/completion.h", "ecos/packages/compat/linux/current/linux/config.h", "ecos/packages/compat/linux/current/linux/crc32.h", "ecos/packages/compat/linux/current/linux/errno.h", "ecos/packages/compat/linux/current/linux/fs.h", "ecos/packages/compat/linux/current/linux/kernel.h", "ecos/packages/compat/linux/current/linux/list.h", "ecos/packages/compat/linux/current/linux/mtd/compatmac.h", "ecos/packages/compat/linux/current/linux/mtd/mtd.h", "ecos/packages/compat/linux/current/linux/pagemap.h", "ecos/packages/compat/linux/current/linux/rbtree.h", "ecos/packages/compat/linux/current/linux/rwsem.h", "ecos/packages/compat/linux/current/linux/sched.h", "ecos/packages/compat/linux/current/linux/slab.h", "ecos/packages/compat/linux/current/linux/spinlock.h", "ecos/packages/compat/linux/current/linux/stat.h", "ecos/packages/compat/linux/current/linux/string.h", "ecos/packages/compat/linux/current/linux/timer.h", "ecos/packages/compat/linux/current/linux/types.h", "ecos/packages/compat/linux/current/linux/version.h", "ecos/packages/compat/linux/current/linux/vmalloc.h", "ecos/packages/compat/linux/current/linux/wait.h", "ecos/packages/compat/linux/current/linux/workqueue.h", and "ecos/packages/compat/linux/current/linux/zlib.h" "ecos/packages/compat/linux/current/linux/zutil.h" are copied to "cpukit/libfs/src/jffs2/include". The file "ecos/packages/services/crc/current/src/crc32.c" is copied to "cpukit/libfs/src/jffs2/src/compat-crc32.c". The file "ecos/packages/compat/linux/current/src/rbtree.c" is copied to "cpukit/libfs/src/jffs2/src/compat-rbtree.c". The file "ecos/packages/fs/jffs2/current/src/dir-ecos.c" is copied to "cpukit/libfs/src/jffs2/src/dir-rtems.c". The file "ecos/packages/fs/jffs2/current/src/flashio.c" is copied to "cpukit/libfs/src/jffs2/src/flashio.c". The file "ecos/packages/fs/jffs2/current/src/fs-ecos.c" is copied to "cpukit/libfs/src/jffs2/src/fs-rtems.c". The file "ecos/packages/fs/jffs2/current/src/malloc-ecos.c" is copied to "cpukit/libfs/src/jffs2/src/malloc-rtems.c". The file "ecos/packages/fs/jffs2/current/src/os-ecos.h" is copied to "cpukit/libfs/src/jffs2/src/os-rtems.h". The LICENSE file referenced in some files of this patch set is part of a previous patch set imported from Linux. --- cpukit/libfs/src/jffs2/include/asm/atomic.h | 10 + cpukit/libfs/src/jffs2/include/asm/bug.h | 6 + cpukit/libfs/src/jffs2/include/asm/page.h | 11 + cpukit/libfs/src/jffs2/include/cyg/crc/crc.h | 105 + .../libfs/src/jffs2/include/cyg/infra/cyg_type.h | 559 +++++ cpukit/libfs/src/jffs2/include/linux/compiler.h | 7 + cpukit/libfs/src/jffs2/include/linux/completion.h | 7 + cpukit/libfs/src/jffs2/include/linux/config.h | 5 + cpukit/libfs/src/jffs2/include/linux/crc32.h | 8 + cpukit/libfs/src/jffs2/include/linux/errno.h | 1 + cpukit/libfs/src/jffs2/include/linux/fs.h | 13 + cpukit/libfs/src/jffs2/include/linux/kernel.h | 31 + cpukit/libfs/src/jffs2/include/linux/list.h | 139 ++ .../libfs/src/jffs2/include/linux/mtd/compatmac.h | 5 + cpukit/libfs/src/jffs2/include/linux/mtd/mtd.h | 5 + cpukit/libfs/src/jffs2/include/linux/pagemap.h | 19 + cpukit/libfs/src/jffs2/include/linux/rbtree.h | 46 + cpukit/libfs/src/jffs2/include/linux/rwsem.h | 20 + cpukit/libfs/src/jffs2/include/linux/sched.h | 7 + cpukit/libfs/src/jffs2/include/linux/slab.h | 14 + cpukit/libfs/src/jffs2/include/linux/spinlock.h | 34 + cpukit/libfs/src/jffs2/include/linux/stat.h | 12 + cpukit/libfs/src/jffs2/include/linux/string.h | 6 + cpukit/libfs/src/jffs2/include/linux/timer.h | 10 + cpukit/libfs/src/jffs2/include/linux/types.h | 19 + cpukit/libfs/src/jffs2/include/linux/version.h | 5 + cpukit/libfs/src/jffs2/include/linux/vmalloc.h | 3 + cpukit/libfs/src/jffs2/include/linux/wait.h | 15 + cpukit/libfs/src/jffs2/include/linux/workqueue.h | 11 + cpukit/libfs/src/jffs2/include/linux/zlib.h | 14 + cpukit/libfs/src/jffs2/include/linux/zutil.h | 6 + cpukit/libfs/src/jffs2/src/compat-crc32.c | 166 ++ cpukit/libfs/src/jffs2/src/compat-rbtree.c | 408 ++++ cpukit/libfs/src/jffs2/src/dir-rtems.c | 371 ++++ cpukit/libfs/src/jffs2/src/flashio.c | 165 ++ cpukit/libfs/src/jffs2/src/fs-rtems.c | 2191 ++++++++++++++++++++ cpukit/libfs/src/jffs2/src/malloc-rtems.c | 163 ++ cpukit/libfs/src/jffs2/src/os-rtems.h | 226 ++ 38 files changed, 4843 insertions(+) create mode 100644 cpukit/libfs/src/jffs2/include/asm/atomic.h create mode 100644 cpukit/libfs/src/jffs2/include/asm/bug.h create mode 100644 cpukit/libfs/src/jffs2/include/asm/page.h create mode 100644 cpukit/libfs/src/jffs2/include/cyg/crc/crc.h create mode 100644 cpukit/libfs/src/jffs2/include/cyg/infra/cyg_type.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/compiler.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/completion.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/config.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/crc32.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/errno.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/fs.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/kernel.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/list.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/mtd/compatmac.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/mtd/mtd.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/pagemap.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/rbtree.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/rwsem.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/sched.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/slab.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/spinlock.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/stat.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/string.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/timer.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/types.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/version.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/vmalloc.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/wait.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/workqueue.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/zlib.h create mode 100644 cpukit/libfs/src/jffs2/include/linux/zutil.h create mode 100644 cpukit/libfs/src/jffs2/src/compat-crc32.c create mode 100644 cpukit/libfs/src/jffs2/src/compat-rbtree.c create mode 100644 cpukit/libfs/src/jffs2/src/dir-rtems.c create mode 100644 cpukit/libfs/src/jffs2/src/flashio.c create mode 100644 cpukit/libfs/src/jffs2/src/fs-rtems.c create mode 100644 cpukit/libfs/src/jffs2/src/malloc-rtems.c create mode 100644 cpukit/libfs/src/jffs2/src/os-rtems.h diff --git a/cpukit/libfs/src/jffs2/include/asm/atomic.h b/cpukit/libfs/src/jffs2/include/asm/atomic.h new file mode 100644 index 0000000000..5cb72ff8ce --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/asm/atomic.h @@ -0,0 +1,10 @@ +#ifndef __ASM_ATOMIC_H__ +#define __ASM_ATOMIC_H__ + +#define atomic_t int +#define atomic_inc(atom) (*atom)++ +#define atomic_dec(atom) (*atom)-- +#define atomic_read(atom) (*atom) + + +#endif /* __ASM_ATOMIC_H__ */ diff --git a/cpukit/libfs/src/jffs2/include/asm/bug.h b/cpukit/libfs/src/jffs2/include/asm/bug.h new file mode 100644 index 0000000000..060eb27830 --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/asm/bug.h @@ -0,0 +1,6 @@ +#ifndef __ASM_BUG_H__ +#define __ASM_BUG_H__ + +#define BUG() do { diag_printf("BUG() at %s %d\n", __FILE__, __LINE__); *(int *)0=0; } while (0) + +#endif /* __ASM_BUG_H__ */ diff --git a/cpukit/libfs/src/jffs2/include/asm/page.h b/cpukit/libfs/src/jffs2/include/asm/page.h new file mode 100644 index 0000000000..d77a39ac43 --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/asm/page.h @@ -0,0 +1,11 @@ +#ifndef __ASM_PAGE_H__ +#define __ASM_PAGE_H__ + +#include + +/* These aren't used by much yet. If that changes, you might want + to make them actually correct :) */ +#define PAGE_SIZE (0x1 << PAGE_SHIFT) + + +#endif /* __ASM_PAGE_H__ */ diff --git a/cpukit/libfs/src/jffs2/include/cyg/crc/crc.h b/cpukit/libfs/src/jffs2/include/cyg/crc/crc.h new file mode 100644 index 0000000000..7b7db10e9e --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/cyg/crc/crc.h @@ -0,0 +1,105 @@ +//========================================================================== +// +// crc.h +// +// Interface for the CRC algorithms. +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2002, 2009 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Andrew Lunn +// Contributors: Andrew Lunn +// Date: 2002-08-06 +// Purpose: +// Description: +// +// This code is part of eCos (tm). +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#ifndef _SERVICES_CRC_CRC_H_ +#define _SERVICES_CRC_CRC_H_ + +#include + +#ifndef __externC +# ifdef __cplusplus +# define __externC extern "C" +# else +# define __externC extern +# endif +#endif + +// Compute a CRC, using the POSIX 1003 definition + +__externC cyg_uint32 +cyg_posix_crc32(unsigned char *s, int len); + +// Gary S. Brown's 32 bit CRC + +__externC cyg_uint32 +cyg_crc32(unsigned char *s, int len); + +// Gary S. Brown's 32 bit CRC, but accumulate the result from a +// previous CRC calculation + +__externC cyg_uint32 +cyg_crc32_accumulate(cyg_uint32 crc, unsigned char *s, int len); + +// Ethernet FCS Algorithm + +__externC cyg_uint32 +cyg_ether_crc32(unsigned char *s, int len); + +// Ethernet FCS algorithm, but accumulate the result from a previous +// CRC calculation. + +__externC cyg_uint32 +cyg_ether_crc32_accumulate(cyg_uint32 crc, unsigned char *s, int len); + +// 16 bit CRC with polynomial x^16+x^12+x^5+1 + +__externC cyg_uint16 +cyg_crc16(unsigned char *s, int len); + +__externC cyg_uint16 +cyg_crc16_accumulate(cyg_uint16 crc, unsigned char *s, int len); + +#endif // _SERVICES_CRC_CRC_H_ + + + diff --git a/cpukit/libfs/src/jffs2/include/cyg/infra/cyg_type.h b/cpukit/libfs/src/jffs2/include/cyg/infra/cyg_type.h new file mode 100644 index 0000000000..5047493527 --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/cyg/infra/cyg_type.h @@ -0,0 +1,559 @@ +#ifndef CYGONCE_INFRA_CYG_TYPE_H +#define CYGONCE_INFRA_CYG_TYPE_H + +//========================================================================== +// +// cyg_type.h +// +// Standard types, and some useful coding macros. +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2009 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): nickg from an original by hmt +// Contributors: nickg +// Date: 1997-09-08 +// Purpose: share unambiguously sized types. +// Description: we typedef [cyg_][u]int8,16,32 &c for general use. +// Usage: #include "cyg/infra/cyg_type.h" +// ... +// cyg_int32 my_32bit_integer; +// +//####DESCRIPTIONEND#### +// + +#include // Definition of NULL from the compiler + +// ------------------------------------------------------------------------- +// Some useful macros. These are defined here by default. + +// __externC is used in mixed C/C++ headers to force C linkage on an external +// definition. It avoids having to put all sorts of ifdefs in. + +#ifdef __cplusplus +# define __externC extern "C" +#else +# define __externC extern +#endif +// Also define externC for now - but it is deprecated +#define externC __externC + +// Compiler version. +#ifdef __GNUC__ +# if defined(__GNU_PATCHLEVEL__) +# define __GNUC_VERSION__ (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) +# else +# define __GNUC_VERSION__ (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100) +# endif +#endif + +// ------------------------------------------------------------------------- +// The header 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 + +// ------------------------------------------------------------------------- +// Allow creation of procedure-like macros that are a single statement, +// and must be followed by a semi-colon + +#define CYG_MACRO_START do { +#define CYG_MACRO_END } while (0) + +#define CYG_EMPTY_STATEMENT CYG_MACRO_START CYG_MACRO_END + +#define CYG_UNUSED_PARAM( _type_, _name_ ) CYG_MACRO_START \ + _type_ __tmp1 = (_name_); \ + _type_ __tmp2 = __tmp1; \ + __tmp1 = __tmp2; \ +CYG_MACRO_END + + +//---------------------------------------------------------------------------- +// The unused attribute stops the compiler warning about the variable +// not being used. +// The used attribute prevents the compiler from optimizing it away. + +#define CYG_REFERENCE_OBJECT(__object__) \ + CYG_MACRO_START \ + static const void* __cygvar_discard_me__ \ + __attribute__ ((unused, used)) = (const void*)&(__object__); \ + CYG_MACRO_END + +// ------------------------------------------------------------------------- +// Define basic types for using integers in memory and structures; +// depends on compiler defaults and CPU type. + +typedef unsigned cyg_halint8 cyg_uint8 ; +typedef signed cyg_halint8 cyg_int8 ; + +typedef unsigned cyg_halint16 cyg_uint16 ; +typedef signed cyg_halint16 cyg_int16 ; + +typedef unsigned cyg_halint32 cyg_uint32 ; +typedef signed cyg_halint32 cyg_int32 ; + +typedef unsigned cyg_halint64 cyg_uint64 ; +typedef signed cyg_halint64 cyg_int64 ; + +typedef cyg_halbool cyg_bool ; + +// ------------------------------------------------------------------------- +// Define types for using integers in registers for looping and the like; +// depends on CPU type, choose what it is most comfortable with, with at +// least the range required. + +typedef unsigned cyg_halcount8 cyg_ucount8 ; +typedef signed cyg_halcount8 cyg_count8 ; + +typedef unsigned cyg_halcount16 cyg_ucount16 ; +typedef signed cyg_halcount16 cyg_count16 ; + +typedef unsigned cyg_halcount32 cyg_ucount32 ; +typedef signed cyg_halcount32 cyg_count32 ; + +typedef unsigned cyg_halcount64 cyg_ucount64 ; +typedef signed cyg_halcount64 cyg_count64 ; + +// ------------------------------------------------------------------------- +// Define a type to be used for atomic accesses. This type is guaranteed +// to be read or written in a single uninterruptible operation. This type +// is at least a single byte. + +typedef volatile unsigned cyg_halatomic cyg_atomic; +typedef volatile unsigned cyg_halatomic CYG_ATOMIC; + +// ------------------------------------------------------------------------- +// Define types for access plain, on-the-metal memory or devices. + +typedef cyg_uint32 CYG_WORD; +typedef cyg_uint8 CYG_BYTE; +typedef cyg_uint16 CYG_WORD16; +typedef cyg_uint32 CYG_WORD32; +typedef cyg_uint64 CYG_WORD64; + +typedef cyg_haladdress CYG_ADDRESS; +typedef cyg_haladdrword CYG_ADDRWORD; + +// ------------------------------------------------------------------------- +// Number of elements in a (statically allocated) array. + +#define CYG_NELEM(a) (sizeof(a) / sizeof((a)[0])) + +// ------------------------------------------------------------------------- +// Constructor ordering macros. These are added as annotations to all +// static objects to order the constuctors appropriately. + +#if defined(__cplusplus) && defined(__GNUC__) && \ + !defined(CYGBLD_ATTRIB_INIT_PRI) +# define CYGBLD_ATTRIB_INIT_PRI( _pri_ ) __attribute__((init_priority(_pri_))) +#elif !defined(CYGBLD_ATTRIB_INIT_PRI) +// FIXME: should maybe just bomb out if this is attempted anywhere else? +// Not sure +# define CYGBLD_ATTRIB_INIT_PRI( _pri_ ) +#endif + +// The following will be removed eventually as it doesn't allow the use of +// e.g. pri+5 format +#define CYG_INIT_PRIORITY( _pri_ ) CYGBLD_ATTRIB_INIT_PRI( CYG_INIT_##_pri_ ) + +#define CYGBLD_ATTRIB_INIT_BEFORE( _pri_ ) CYGBLD_ATTRIB_INIT_PRI(_pri_-100) +#define CYGBLD_ATTRIB_INIT_AFTER( _pri_ ) CYGBLD_ATTRIB_INIT_PRI(_pri_+100) + +#if defined(__GNUC__) && !defined(__cplusplus) && (__GNUC_VERSION__ >= 40300) +// Equivalents of the above for C functions, available from gcc 4.3 onwards. +# define CYGBLD_ATTRIB_C_INIT_PRI( _pri_) __attribute__((constructor (_pri_))) +# define CYGBLD_ATTRIB_C_INIT_BEFORE( _pri_ ) __attribute__((constructor (_pri_-100))) +# define CYGBLD_ATTRIB_C_INIT_AFTER( _pri_ ) __attribute__((constructor (_pri_+100))) +#endif + +// Start with initializing everything inside the cpu and the main memory. +#define CYG_INIT_HAL 10000 +#define CYG_INIT_SCHEDULER 11000 +#define CYG_INIT_IDLE_THREAD 11100 +#define CYG_INIT_INTERRUPTS 12000 +#define CYG_INIT_CLOCK 14000 +#define CYG_INIT_THREADS 16000 +#define CYG_INIT_KERNEL 19000 +#define CYG_INIT_MEMALLOC 20000 +// Now move on to I/O subsystems and device drivers. These can make use of +// kernel and HAL functionality, and can dynamically allocate memory if +// absolutely needed. For now they can also assume that diag_printf() +// functionality is available, but that may change in future. +// +// Primary buses are ones very closely tied to the processor, e.g. PCI. +#define CYG_INIT_BUS_PRIMARY 30000 +// Not yet: on some targets cyg_pci_init() has to be called very early +// on for HAL diagnostics to work. +// #define CYG_INIT_BUS_PCI CYG_INIT_BUS_PRIMARY +// +// Secondary buses may hang off primary buses, e.g. USB host. +#define CYG_INIT_BUS_SECONDARY 31000 +// Tertiary buses are everything else. +#define CYG_INIT_BUS_TERTIARY 32000 +#define CYG_INIT_BUS_I2C CYG_INIT_BUS_TERTIARY +#define CYG_INIT_BUS_SPI CYG_INIT_BUS_TERTIARY +// +// In future HAL diag initialization may happen at this point. +// +// Watchdogs and wallclocks often hang off a tertiary bus but +// have no dependencies +#define CYG_INIT_DEV_WATCHDOG 35000 +#define CYG_INIT_DEV_WALLCLOCK 36000 +// A primary block configuration can be initialized with no need +// for per-unit configuration information. +#define CYG_INIT_DEV_BLOCK_PRIMARY 37000 +#define CYG_INIT_DEV_FLASH CYG_INIT_DEV_BLOCK_PRIMARY +// Per-unit configuration data extracted from primary storage. +// NOTE: for future use, not implemented yet. +#define CYG_INIT_CONFIG 38000 +// Secondary block devices may use per-unit configuration data +// for e.g. interpreting partition layout. Few devices are expected +// to fall into this category. Note that these devices, as well as +// some char devices, may not actually be usable until interrupts +// are enabled. +#define CYG_INIT_DEV_BLOCK_SECONDARY 40000 +// Char devices are everything else: serial, ethernet, CAN, ... +#define CYG_INIT_DEV_CHAR 41000 +// For backwards compatibility. Subject to change in future so +// a CYG_INIT_DEV_ priority should be used instead. +#define CYG_INIT_DRIVERS 48000 +// CYG_INIT_IO and CYG_INIT_IO_FS are poorly defined at present, +// and may get reorganized in future. +#define CYG_INIT_IO 49000 +#define CYG_INIT_IO_FS 50000 +// The I/O subsystems and device drivers have been initialized. +#define CYG_INIT_LIBC 56000 +#define CYG_INIT_COMPAT 58000 +#define CYG_INIT_APPLICATION 60000 +#define CYG_INIT_PREDEFAULT 65534 +#define CYG_INIT_DEFAULT 65535 + +// ------------------------------------------------------------------------- +// Label name macros. Some toolsets generate labels with initial +// underscores and others don't. CYG_LABEL_NAME should be used on +// labels in C/C++ code that are defined in assembly code or linker +// scripts. CYG_LABEL_DEFN is for use in assembly code and linker +// scripts where we need to manufacture labels that can be used from +// C/C++. +// These are default implementations that should work for most targets. +// They may be overridden in basetype.h if necessary. + +#ifndef CYG_LABEL_NAME + +#define CYG_LABEL_NAME(_name_) _name_ + +#endif + +#ifndef CYG_LABEL_DEFN + +#define CYG_LABEL_DEFN(_label) _label + +#endif + +// ------------------------------------------------------------------------- +// COMPILER-SPECIFIC STUFF + +#ifdef __GNUC__ +// Force a 'C' routine to be called like a 'C++' contructor +# if !defined(CYGBLD_ATTRIB_CONSTRUCTOR) +# define CYGBLD_ATTRIB_CONSTRUCTOR __attribute__((constructor)) +# endif + +// Define a compiler-specific rune for saying a function doesn't return +# if !defined(CYGBLD_ATTRIB_NORET) +# define CYGBLD_ATTRIB_NORET __attribute__((noreturn)) +# endif + +// How to define weak symbols - this is only relevant for ELF and a.out, +// but that won't be a problem for eCos +# if !defined(CYGBLD_ATTRIB_WEAK) +# define CYGBLD_ATTRIB_WEAK __attribute__ ((weak)) +# endif + +// How to define alias to symbols. Just pass in the symbol itself, not +// the string name of the symbol +# if !defined(CYGBLD_ATTRIB_ALIAS) +# define CYGBLD_ATTRIB_ALIAS(__symbol__) \ + __attribute__ ((alias (#__symbol__))) +# endif + +// This effectively does the reverse of the previous macro. It defines +// a name that the attributed variable or function will actually have +// in assembler. +# if !defined(CYGBLD_ATTRIB_ASM_ALIAS) +# define __Str(x) #x +# define __Xstr(x) __Str(x) +# define CYGBLD_ATTRIB_ASM_ALIAS(__symbol__) \ + __asm__ ( __Xstr( CYG_LABEL_DEFN( __symbol__ ) ) ) +# endif + +// Shows that a function returns the same value when given the same args, but +// note this can't be used if there are pointer args +# if !defined(CYGBLD_ATTRIB_CONST) +# define CYGBLD_ATTRIB_CONST __attribute__((const)) +#endif + +// Assign a defined variable to a specific section +# if !defined(CYGBLD_ATTRIB_SECTION) +# define CYGBLD_ATTRIB_SECTION(__sect__) __attribute__((section (__sect__))) +# endif + +// Give a type or object explicit minimum alignment +# if !defined(CYGBLD_ATTRIB_ALIGN) +# define CYGBLD_ATTRIB_ALIGN(__align__) __attribute__((aligned(__align__))) +# endif + +# if !defined(CYGBLD_ATTRIB_ALIGN_MAX) +# define CYGBLD_ATTRIB_ALIGN_MAX __attribute__((aligned)) +# endif + +# if !defined(CYGBLD_ATTRIB_ALIGNOFTYPE) +# define CYGBLD_ATTRIB_ALIGNOFTYPE( _type_ ) \ + __attribute__((aligned(__alignof__( _type_ )))) +# endif + +// Teach compiler how to check format of printf-like functions +# define CYGBLD_ATTRIB_PRINTF_FORMAT(__format__, __args__) \ + __attribute__((format (printf, __format__, __args__))) + +// Teach compiler how to check format of scanf-like functions +# define CYGBLD_ATTRIB_SCANF_FORMAT(__format__, __args__) \ + __attribute__((format (scanf, __format__, __args__))) + +// Teach compiler how to check format of strftime-like functions +# define CYGBLD_ATTRIB_STRFTIME_FORMAT(__format__, __args__) \ + __attribute__((format (strftime, __format__, __args__))) + +// Tell compiler not to warn us about an unused variable -- generally +// because it will be used when sources are build under certain +// circumstances (e.g. with debugging or asserts enabled. +# define CYGBLD_ATTRIB_UNUSED __attribute__((unused)) + +// Tell the compiler not to throw away a variable or function. Only known +// available on 3.3.2 or above. Old version's didn't throw them away, +// but using the unused attribute should stop warnings. +# if !defined(CYGBLD_ATTRIB_USED) +# if __GNUC_VERSION__ >= 30302 +# define CYGBLD_ATTRIB_USED __attribute__((used)) +# else +# define CYGBLD_ATTRIB_USED __attribute__((unused)) +# endif +# endif + +// Enforce inlining of a C function. GCC does not inline any C +// function when not optimizing, unless you specify "always_inline" attribute. +// Other attributes suppress generation of standalone function. +# if !defined(CYGBLD_FORCE_INLINE) +# define CYGBLD_FORCE_INLINE __externC inline __attribute((gnu_inline)) __attribute((always_inline)) +# endif + +// Suppress function inlining +#define CYGBLD_ATTRIB_NO_INLINE __attribute__((noinline)) + +#else // non-GNU + +# define CYGBLD_ATTRIB_UNUSED /* nothing */ + +# define CYGBLD_ATTRIB_CONSTRUCTOR + +# define CYGBLD_ATTRIB_NORET + // This intentionally gives an error only if we actually try to + // use it. #error would give an error if we simply can't. +// FIXME: Had to disarm the bomb - the CYGBLD_ATTRIB_WEAK macro is now +// (indirectly) used in host tools. +# define CYGBLD_ATTRIB_WEAK /* !!!-- Attribute weak not defined --!!! */ + +# define CYGBLD_ATTRIB_ALIAS(__x__) !!!-- Attribute alias not defined --!!! + +# define CYGBLD_ATTRIB_ASM_ALIAS(__symbol__) !!!-- Asm alias not defined --!!! + +# define CYGBLD_ATTRIB_CONST + +# define CYGBLD_ATTRIB_ALIGN(__align__) !!!-- Alignment alias not defined --!!! + +# define CYGBLD_ATTRIB_ALIGN_MAX !!!-- Alignment alias not defined --!!! + +# define CYGBLD_ATTRIB_ALIGNOFTYPE( _type_ ) !!!-- Alignment alias not defined --!!! + +# define CYGBLD_ATTRIB_PRINTF_FORMAT(__format__, __args__) + +# define CYGBLD_ATTRIB_SCANF_FORMAT(__format__, __args__) + +# define CYGBLD_ATTRIB_STRFTIME_FORMAT(__format__, __args__) + +#define CYGBLD_FORCE_INLINE + +#define CYGBLD_ATTRIB_NO_INLINE + +#endif + +// How to define weak aliases. Currently this is simply a mixture of the +// above + +# define CYGBLD_ATTRIB_WEAK_ALIAS(__symbol__) \ + CYGBLD_ATTRIB_WEAK CYGBLD_ATTRIB_ALIAS(__symbol__) + +#ifdef __cplusplus +# define __THROW throw() +#else +# define __THROW +#endif + +// ------------------------------------------------------------------------- +// Variable annotations +// These annotations may be added to various static variables in the +// HAL and kernel to indicate which component they belong to. These +// are used by some targets to optimize memory placement of these +// variables. + +#ifndef CYGBLD_ANNOTATE_VARIABLE_HAL +#define CYGBLD_ANNOTATE_VARIABLE_HAL +#endif +#ifndef CYGBLD_ANNOTATE_VARIABLE_SCHED +#define CYGBLD_ANNOTATE_VARIABLE_SCHED +#endif +#ifndef CYGBLD_ANNOTATE_VARIABLE_CLOCK +#define CYGBLD_ANNOTATE_VARIABLE_CLOCK +#endif +#ifndef CYGBLD_ANNOTATE_VARIABLE_INTR +#define CYGBLD_ANNOTATE_VARIABLE_INTR +#endif + +// ------------------------------------------------------------------------- +// Various "flavours" of memory regions that can be described by the +// Memory Layout Tool (MLT). + +#define CYGMEM_REGION_ATTR_R 0x01 // Region can be read +#define CYGMEM_REGION_ATTR_W 0x02 // Region can be written + +// ------------------------------------------------------------------------- +#endif // CYGONCE_INFRA_CYG_TYPE_H multiple inclusion protection +// EOF cyg_type.h diff --git a/cpukit/libfs/src/jffs2/include/linux/compiler.h b/cpukit/libfs/src/jffs2/include/linux/compiler.h new file mode 100644 index 0000000000..fb253651a3 --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/compiler.h @@ -0,0 +1,7 @@ +#ifndef __LINUX_COMPILER_H__ +#define __LINUX_COMPILER_H__ + +#define likely(x) (x) +#define unlikely(x) (x) + +#endif /* __LINUX_COMPILER_H__ */ diff --git a/cpukit/libfs/src/jffs2/include/linux/completion.h b/cpukit/libfs/src/jffs2/include/linux/completion.h new file mode 100644 index 0000000000..f131af83f8 --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/completion.h @@ -0,0 +1,7 @@ +#ifndef __LINUX_COMPLETION_H__ +#define __LINUX_COMPLETION_H__ + +struct completion { } ; + +#endif /* __LINUX_COMPLETION_H__ */ + diff --git a/cpukit/libfs/src/jffs2/include/linux/config.h b/cpukit/libfs/src/jffs2/include/linux/config.h new file mode 100644 index 0000000000..986e10b49b --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/config.h @@ -0,0 +1,5 @@ +#ifndef __LINUX_CONFIG_H__ +#define __LINUX_CONFIG_H__ + + +#endif /* __LINUX_CONFIG_H__ */ diff --git a/cpukit/libfs/src/jffs2/include/linux/crc32.h b/cpukit/libfs/src/jffs2/include/linux/crc32.h new file mode 100644 index 0000000000..8d19a1eb62 --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/crc32.h @@ -0,0 +1,8 @@ +#ifndef CRC32_H +#define CRC32_H + +#include + +#define crc32(val, s, len) cyg_crc32_accumulate(val, (unsigned char *)s, len) + +#endif diff --git a/cpukit/libfs/src/jffs2/include/linux/errno.h b/cpukit/libfs/src/jffs2/include/linux/errno.h new file mode 100644 index 0000000000..339f4fc10c --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/errno.h @@ -0,0 +1 @@ +#include diff --git a/cpukit/libfs/src/jffs2/include/linux/fs.h b/cpukit/libfs/src/jffs2/include/linux/fs.h new file mode 100644 index 0000000000..c2f173ac81 --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/fs.h @@ -0,0 +1,13 @@ +#ifndef __LINUX_FS_H__ +#define __LINUX_FS_H__ + +#include +/* + * File types + */ +#define DT_UNKNOWN 0 +#define DT_DIR 4 +#define DT_REG 8 + + +#endif /* __LINUX_FS_H__ */ diff --git a/cpukit/libfs/src/jffs2/include/linux/kernel.h b/cpukit/libfs/src/jffs2/include/linux/kernel.h new file mode 100644 index 0000000000..e5d8d90437 --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/kernel.h @@ -0,0 +1,31 @@ +#ifndef __LINUX_KERNEL_H__ +#define __LINUX_KERNEL_H__ + +#define jiffies ((unsigned long)cyg_current_time()) + +#define ERR_PTR(err) ((void*)(err)) +#define PTR_ERR(err) ((unsigned long)(err)) +#define IS_ERR(err) ((unsigned long)err > (unsigned long)-1000L) + +#define CURRENT_TIME cyg_timestamp() + +#define KERN_EMERG "<0>" // system is unusable +#define KERN_ALERT "<1>" // action must be taken immediately +#define KERN_CRIT "<2>" // critical conditions +#define KERN_ERR "<3>" // error conditions +#define KERN_WARNING "<4>" // warning conditions +#define KERN_NOTICE "<5>" // normal but significant condition +#define KERN_INFO "<6>" // informational +#define KERN_DEBUG "<7>" // debug-level messages +#define printk diag_printf + +#define min(x,y) (x + * + *=========================================================================== + * ####ECOSGPLCOPYRIGHTBEGIN#### + * ------------------------------------------- + * This file is part of eCos, the Embedded Configurable Operating System. + * Copyright (C) 2002, 2003 Free Software Foundation, Inc. + * + * eCos is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 or (at your option) any later + * version. + * + * eCos is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with eCos; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * As a special exception, if other files instantiate templates or use + * macros or inline functions from this file, or you compile this file + * and link it with other works to produce a work based on this file, + * this file does not by itself cause the resulting work to be covered by + * the GNU General Public License. However the source code for this file + * must still be made available in accordance with section (3) of the GNU + * General Public License v2. + * + * This exception does not invalidate any other reasons why a work based + * on this file might be covered by the GNU General Public License. + * ------------------------------------------- + * ####ECOSGPLCOPYRIGHTEND#### + *=========================================================================== + * + */ + +#ifndef CYGONCE_FS_JFFS2_LIST_H +#define CYGONCE_FS_JFFS2_LIST_H + + +/* -----------------------------------------------------------------------*/ + +/* Doubly linked list implementation to replace the GPL'd one used in + the Linux kernel. */ + +#include +#include + +/* TYPES */ + +struct list_head { + struct list_head *next; + struct list_head *prev; +}; + +/* MACROS */ + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD( _list_ ) \ +CYG_MACRO_START \ +(_list_)->next = (_list_)->prev = (_list_); \ +CYG_MACRO_END + +/* FUNCTIONS */ + +/* Insert an entry _after_ the specified entry */ +static __inline__ void +list_add( struct list_head *newent, struct list_head *afterthisent ) +{ + struct list_head *next = afterthisent->next; + newent->next = next; + newent->prev = afterthisent; + afterthisent->next = newent; + next->prev = newent; +} /* list_add() */ + +/* Insert an entry _before_ the specified entry */ +static __inline__ void +list_add_tail( struct list_head *newent, struct list_head *beforethisent ) +{ + struct list_head *prev = beforethisent->prev; + newent->prev = prev; + newent->next = beforethisent; + beforethisent->prev = newent; + prev->next = newent; +} /* list_add_tail() */ + +/* Delete the specified entry */ +static __inline__ void +list_del( struct list_head *ent ) +{ + ent->prev->next = ent->next; + ent->next->prev = ent->prev; +} /* list_del() */ + +/* Is this list empty? */ +static __inline__ int +list_empty( struct list_head *list ) +{ + return ( list->next == list ); +} /* list_empty() */ + +/* list_entry - Assuming you have a struct of type _type_ that contains a + list which has the name _member_ in that struct type, then given the + address of that list in the struct, _list_, this returns the address + of the container structure */ + +#define list_entry( _list_, _type_, _member_ ) \ + ((_type_ *)((char *)(_list_)-(char *)(offsetof(_type_,_member_)))) + +/* list_for_each - using _ent_, iterate through list _list_ */ + +#define list_for_each( _ent_, _list_ ) \ + for ( (_ent_) = (_list_)->next; \ + (_ent_) != (_list_); \ + (_ent_) = (_ent_)->next ) + +/* + * list_for_each_entry - this function can be use to iterate over all + * items in a list* _list_ with it's head at _head_ and link _item_ + */ +#define list_for_each_entry(_list_, _head_, _item_) \ +for ((_list_) = list_entry((_head_)->next, typeof(*_list_), _item_); \ + &((_list_)->_item_) != (_head_); \ + (_list_) = list_entry((_list_)->_item_.next, typeof(*_list_), _item_)) + +/* -----------------------------------------------------------------------*/ +#endif /* #ifndef CYGONCE_FS_JFFS2_LIST_H */ +/* EOF list.h */ diff --git a/cpukit/libfs/src/jffs2/include/linux/mtd/compatmac.h b/cpukit/libfs/src/jffs2/include/linux/mtd/compatmac.h new file mode 100644 index 0000000000..cee3749250 --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/mtd/compatmac.h @@ -0,0 +1,5 @@ +#ifndef __LINUX_MTD_COMPATMAC_H__ +#define __LINUX_MTD_COMPATMAC_H__ + + +#endif /* __LINUX_MTD_COMPATMAC_H__ */ diff --git a/cpukit/libfs/src/jffs2/include/linux/mtd/mtd.h b/cpukit/libfs/src/jffs2/include/linux/mtd/mtd.h new file mode 100644 index 0000000000..817d31cf6f --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/mtd/mtd.h @@ -0,0 +1,5 @@ +#ifndef __LINUX_MTD_MTD_H__ +#define __LINUX_MTD_MTD_H__ + + +#endif /* __LINUX_MTD_MTD_H__ */ diff --git a/cpukit/libfs/src/jffs2/include/linux/pagemap.h b/cpukit/libfs/src/jffs2/include/linux/pagemap.h new file mode 100644 index 0000000000..fccf9c4061 --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/pagemap.h @@ -0,0 +1,19 @@ +#ifndef __LINUX_PAGEMAP_H__ +#define __LINUX_PAGEMAP_H__ + +#include +#include + +#define PAGE_CACHE_SHIFT PAGE_SHIFT +#define PAGE_CACHE_SIZE PAGE_SIZE + +#define PageLocked(pg) 1 +#define Page_Uptodate(pg) 0 +#define UnlockPage(pg) +#define PAGE_BUG(pg) BUG() +#define ClearPageUptodate(pg) +#define SetPageError(pg) +#define ClearPageError(pg) +#define SetPageUptodate(pg) + +#endif /* __LINUX_PAGEMAP_H__ */ diff --git a/cpukit/libfs/src/jffs2/include/linux/rbtree.h b/cpukit/libfs/src/jffs2/include/linux/rbtree.h new file mode 100644 index 0000000000..fef5f718d6 --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/rbtree.h @@ -0,0 +1,46 @@ +#ifndef _LINUX_RBTREE_H +#define _LINUX_RBTREE_H + + +struct rb_node { + struct rb_node *rb_left; /* left element */ + struct rb_node *rb_right; /* right element */ + struct rb_node *rb_parent; /* parent element */ + int rb_color; /* node color */ +}; + +struct rb_root { + struct rb_node *rb_node; /* root of the tree */ +}; +#define NULL ((void *)0) +#define RB_ROOT ((struct rb_root){NULL}) +#define rb_entry(p, container, field) \ + ((container *) ((char *)p - ((char *)&(((container *)0)->field)))) + +#define RB_BLACK 0 +#define RB_RED 1 + + +extern void rb_insert_color(struct rb_node *, struct rb_root *); +extern void rb_erase(struct rb_node *, struct rb_root *); + +/* Find logical next and previous nodes in a tree */ +extern struct rb_node *rb_next(struct rb_node *); +extern struct rb_node *rb_prev(struct rb_node *); +extern struct rb_node *rb_first(struct rb_root *); + +/* Fast replacement of a single node without remove/rebalance/add/rebalance */ +extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, + struct rb_root *root); + +static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, + struct rb_node ** rb_link) +{ + node->rb_parent = parent; + node->rb_color = RB_RED; + node->rb_left = node->rb_right = NULL; + + *rb_link = node; +} + +#endif /* _LINUX_RBTREE_H */ diff --git a/cpukit/libfs/src/jffs2/include/linux/rwsem.h b/cpukit/libfs/src/jffs2/include/linux/rwsem.h new file mode 100644 index 0000000000..d648a150ca --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/rwsem.h @@ -0,0 +1,20 @@ +#ifndef __LINUX_RWSEM_H__ +#define __LINUX_RWSEM_H__ + +// eCos does not have the concept of a read/write semaphore. So just +// map them onto normal semaphores and hope we don't deadlock +// somewhere. + +#include + +struct rw_semaphore; + +#define down_read(sem) cyg_drv_mutex_lock((cyg_drv_mutex_t *)sem) +#define down_read_trylock(sem) cyg_drv_mutex_trylock((cyg_drv_mutex_t *)sem) +#define down_write(sem) cyg_drv_mutex_lock((cyg_drv_mutex_t *)sem) +#define down_write_trylock(sem) cyg_drv_mutex_trylock((cyg_drv_mutex_t *)sem) +#define up_read(sem) cyg_drv_mutex_unlock((cyg_drv_mutex_t *)sem) +#define up_write(sem) cyg_drv_mutex_unlock((cyg_drv_mutex_t *)sem) +#define downgrade_write(sem) + +#endif // __LINUX_RWSEM_H__ diff --git a/cpukit/libfs/src/jffs2/include/linux/sched.h b/cpukit/libfs/src/jffs2/include/linux/sched.h new file mode 100644 index 0000000000..14a7359754 --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/sched.h @@ -0,0 +1,7 @@ +#ifndef __LINUX_SCHED_H__ +#define __LINUX_SCHED_H__ + +#define cond_resched() do { } while(0) +#define signal_pending(x) (0) + +#endif /* __LINUX_SCHED_H__ */ diff --git a/cpukit/libfs/src/jffs2/include/linux/slab.h b/cpukit/libfs/src/jffs2/include/linux/slab.h new file mode 100644 index 0000000000..fff3949687 --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/slab.h @@ -0,0 +1,14 @@ +#ifndef __LINUX_SLAB_H__ +#define __LINUX_SLAB_H__ + +#include + +#include /* Don't ask. Linux headers are a mess. */ + +#define kmalloc(x, y) malloc(x) +#define kfree(x) free(x) +#define vmalloc(x) malloc(x) +#define vfree(x) free(x) + +#endif /* __LINUX_SLAB_H__ */ + diff --git a/cpukit/libfs/src/jffs2/include/linux/spinlock.h b/cpukit/libfs/src/jffs2/include/linux/spinlock.h new file mode 100644 index 0000000000..22eba0ba55 --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/spinlock.h @@ -0,0 +1,34 @@ +#ifndef __LINUX_SPINLOCK_H__ +#define __LINUX_SPINLOCK_H__ + + +typedef struct { } spinlock_t; +#define SPIN_LOCK_UNLOCKED (spinlock_t) { } +#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED + +#define spin_lock_init(lock) \ +CYG_MACRO_START; \ +CYG_UNUSED_PARAM(spinlock_t *, lock); \ +CYG_MACRO_END + +#define spin_lock(lock) \ +CYG_MACRO_START; \ +CYG_UNUSED_PARAM(spinlock_t *, lock); \ +CYG_MACRO_END + +#define spin_unlock(lock) \ +CYG_MACRO_START; \ +CYG_UNUSED_PARAM(spinlock_t *, lock); \ +CYG_MACRO_END + +#define spin_lock_bh(lock) \ +CYG_MACRO_START; \ +CYG_UNUSED_PARAM(spinlock_t *, lock); \ +CYG_MACRO_END + +#define spin_unlock_bh(lock) \ +CYG_MACRO_START; \ +CYG_UNUSED_PARAM(spinlock_t *, lock); \ +CYG_MACRO_END + +#endif /* __LINUX_SPINLOCK_H__ */ diff --git a/cpukit/libfs/src/jffs2/include/linux/stat.h b/cpukit/libfs/src/jffs2/include/linux/stat.h new file mode 100644 index 0000000000..a3efd61876 --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/stat.h @@ -0,0 +1,12 @@ +#ifndef __LINUX_STAT_H__ +#define __LINUX_STAT_H__ + + +#include + +#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH) +#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH) +#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH) +#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO) + +#endif /* __LINUX_STAT_H__ */ diff --git a/cpukit/libfs/src/jffs2/include/linux/string.h b/cpukit/libfs/src/jffs2/include/linux/string.h new file mode 100644 index 0000000000..fc14ba607f --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/string.h @@ -0,0 +1,6 @@ +#ifndef __LINUX_STRING_H__ +#define __LINUX_STRING_H__ + +#include + +#endif /* __LINUX_STRING_H__ */ diff --git a/cpukit/libfs/src/jffs2/include/linux/timer.h b/cpukit/libfs/src/jffs2/include/linux/timer.h new file mode 100644 index 0000000000..80e9ef509c --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/timer.h @@ -0,0 +1,10 @@ +#ifndef __LINUX_TIMER_H__ +#define __LINUX_TIMER_H__ + +/* Not yet */ + +struct timer_list { } ; + + +#endif /* __LINUX_TIMER_H__ */ + diff --git a/cpukit/libfs/src/jffs2/include/linux/types.h b/cpukit/libfs/src/jffs2/include/linux/types.h new file mode 100644 index 0000000000..56665b774e --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/types.h @@ -0,0 +1,19 @@ +#ifndef __LINUX_TYPES_H__ +#define __LINUX_TYPES_H__ + +#include "cyg/infra/cyg_type.h" + +#define uint8_t cyg_uint8 +#define uint16_t cyg_uint16 +#define uint32_t cyg_uint32 + +#define int8_t cyg_int8 +#define int16_t cyg_int16 +#define int32_t cyg_int32 + +#define loff_t off_t + + +#define kvec iovec +#endif /* __LINUX_TYPES_H__ */ + diff --git a/cpukit/libfs/src/jffs2/include/linux/version.h b/cpukit/libfs/src/jffs2/include/linux/version.h new file mode 100644 index 0000000000..cca2d731f1 --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/version.h @@ -0,0 +1,5 @@ +#ifndef __LINUX_VERSION_H__ +#define __LINUX_VERSION_H__ + + +#endif /* __LINUX_VERSION_H__ */ diff --git a/cpukit/libfs/src/jffs2/include/linux/vmalloc.h b/cpukit/libfs/src/jffs2/include/linux/vmalloc.h new file mode 100644 index 0000000000..6f18ab2255 --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/vmalloc.h @@ -0,0 +1,3 @@ +#ifndef __LINUX_VMALLOC_H__ +#define __LINUX_VMALLOC_H__ +#endif diff --git a/cpukit/libfs/src/jffs2/include/linux/wait.h b/cpukit/libfs/src/jffs2/include/linux/wait.h new file mode 100644 index 0000000000..2b422e34cb --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/wait.h @@ -0,0 +1,15 @@ +#ifndef __LINUX_WAIT_H__ +#define __LINUX_WAIT_H__ + + +typedef struct { } wait_queue_head_t; + +#define init_waitqueue_head(wait) do{} while (0) +#define add_wait_queue(wait,new_wait) do{} while (0) +#define remove_wait_queue(wait,old_wait) do{} while (0) +#define DECLARE_WAITQUEUE(wait,current) do{} while (0) + +static inline void wake_up(wait_queue_head_t *erase_wait) +{ /* Only used for waking up threads blocks on erases. Not used in eCos */ } + +#endif /* __LINUX_WAIT_H__ */ diff --git a/cpukit/libfs/src/jffs2/include/linux/workqueue.h b/cpukit/libfs/src/jffs2/include/linux/workqueue.h new file mode 100644 index 0000000000..8c900a48bb --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/workqueue.h @@ -0,0 +1,11 @@ +#ifndef __LINUX_WORKQUEUE_H__ +#define __LINUX_WORKQUEUE_H__ + +/* We don't do this yet */ +struct work_struct { } ; + +#define INIT_WORK(x,y,z) /* */ +#define schedule_work(x) do { } while(0) +#define flush_scheduled_work() do { } while(0) + +#endif /* __LINUX_WORKQUEUE_H__ */ diff --git a/cpukit/libfs/src/jffs2/include/linux/zlib.h b/cpukit/libfs/src/jffs2/include/linux/zlib.h new file mode 100644 index 0000000000..9de691e8b3 --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/zlib.h @@ -0,0 +1,14 @@ +#ifndef __LINUX_ZLIB_H__ +#define __LINUX_ZLIB_H__ + +#include + +#define zlib_deflateInit(x,y) deflateInit(x,y) +#define zlib_deflate(x,y) deflate(x,y) +#define zlib_deflateEnd(x) deflateEnd(x) +#define zlib_inflateInit(x) inflateInit(x) +#define zlib_inflateInit2(x,y) inflateInit2(x,y) +#define zlib_inflate(x,y) inflate(x,y) +#define zlib_inflateEnd(x) inflateEnd(x) + +#endif /* __LINUX_ZLIB_H__ */ diff --git a/cpukit/libfs/src/jffs2/include/linux/zutil.h b/cpukit/libfs/src/jffs2/include/linux/zutil.h new file mode 100644 index 0000000000..c3774baf9e --- /dev/null +++ b/cpukit/libfs/src/jffs2/include/linux/zutil.h @@ -0,0 +1,6 @@ +#ifndef __LINUX_ZUTIL_H__ +#define __LINUX_ZUTIL_H__ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + +#endif /* __LINUX_ZUTIL_H__ */ diff --git a/cpukit/libfs/src/jffs2/src/compat-crc32.c b/cpukit/libfs/src/jffs2/src/compat-crc32.c new file mode 100644 index 0000000000..7e4ea269f2 --- /dev/null +++ b/cpukit/libfs/src/jffs2/src/compat-crc32.c @@ -0,0 +1,166 @@ +//========================================================================== +// +// crc32.c +// +// Gary S. Brown's 32 bit CRC +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): gthomas +// Contributors: gthomas,asl +// Date: 2001-01-31 +// Purpose: +// Description: +// +// This code is part of eCos (tm). +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include + + /* ====================================================================== */ + /* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */ + /* code or tables extracted from it, as desired without restriction. */ + /* */ + /* First, the polynomial itself and its table of feedback terms. The */ + /* polynomial is */ + /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ + /* */ + /* ====================================================================== */ + +static const cyg_uint32 crc32_tab[] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL + }; + +/* This is the standard Gary S. Brown's 32 bit CRC algorithm, but + accumulate the CRC into the result of a previous CRC. */ +cyg_uint32 +cyg_crc32_accumulate(cyg_uint32 crc32val, unsigned char *s, int len) +{ + int i; + + for (i = 0; i < len; i++) { + crc32val = crc32_tab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8); + } + return crc32val; +} + +/* This is the standard Gary S. Brown's 32 bit CRC algorithm */ +cyg_uint32 +cyg_crc32(unsigned char *s, int len) +{ + return (cyg_crc32_accumulate(0,s,len)); +} + +/* Return a 32-bit CRC of the contents of the buffer accumulating the + result from a previous CRC calculation. This uses the Ethernet FCS + algorithm.*/ +cyg_uint32 +cyg_ether_crc32_accumulate(cyg_uint32 crc32val, unsigned char *s, int len) +{ + int i; + + if (s == 0) return 0L; + + crc32val = crc32val ^ 0xffffffff; + for (i = 0; i < len; i++) { + crc32val = crc32_tab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8); + } + return crc32val ^ 0xffffffff; +} + +/* Return a 32-bit CRC of the contents of the buffer, using the + Ethernet FCS algorithm. */ +cyg_uint32 +cyg_ether_crc32(unsigned char *s, int len) +{ + return cyg_ether_crc32_accumulate(0,s,len); +} + + diff --git a/cpukit/libfs/src/jffs2/src/compat-rbtree.c b/cpukit/libfs/src/jffs2/src/compat-rbtree.c new file mode 100644 index 0000000000..5bc1cc53e2 --- /dev/null +++ b/cpukit/libfs/src/jffs2/src/compat-rbtree.c @@ -0,0 +1,408 @@ +/*======================================================================== +// +// rbtree.c +// +// Red Black tree implementation +// +//======================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//======================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Niels Provos/OpenBSD +// Contributors: dwmw2 +// Date: 2003-01-21 +// Purpose: This file provides an implementation of red-black trees. +// Description: Derived from OpenBSD src/sys/sys/tree.h +// Usage: +// +//####DESCRIPTIONEND#### +// +//====================================================================== +*/ + +/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */ +/* + * Copyright 2002 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Fields renamed to match Linux ones. */ +#include + + +#define RB_HEAD(head) (head)->rb_node +#define RB_LEFT(elm) (elm)->rb_left +#define RB_RIGHT(elm) (elm)->rb_right +#define RB_PARENT(elm) (elm)->rb_parent +#define RB_COLOR(elm) (elm)->rb_color + + +#define RB_SET(elm, parent) do { \ + RB_PARENT(elm) = parent; \ + RB_LEFT(elm) = RB_RIGHT(elm) = NULL; \ + RB_COLOR(elm) = RB_RED; \ +} while (0) + +#define RB_SET_BLACKRED(black, red) do { \ + RB_COLOR(black) = RB_BLACK; \ + RB_COLOR(red) = RB_RED; \ +} while (0) + +#ifndef RB_AUGMENT +#define RB_AUGMENT(x) +#endif + +#define RB_ROTATE_LEFT(head, elm, tmp) do { \ + (tmp) = RB_RIGHT(elm); \ + if ((RB_RIGHT(elm) = RB_LEFT(tmp))) { \ + RB_PARENT(RB_LEFT(tmp)) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp) = RB_PARENT(elm))) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm))) \ + RB_LEFT(RB_PARENT(elm)) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm)) = (tmp); \ + } else \ + (head)->rb_node = (tmp); \ + RB_LEFT(tmp) = (elm); \ + RB_PARENT(elm) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp))) \ + RB_AUGMENT(RB_PARENT(tmp)); \ +} while (0) + +#define RB_ROTATE_RIGHT(head, elm, tmp) do { \ + (tmp) = RB_LEFT(elm); \ + if ((RB_LEFT(elm) = RB_RIGHT(tmp))) { \ + RB_PARENT(RB_RIGHT(tmp)) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp) = RB_PARENT(elm))) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm))) \ + RB_LEFT(RB_PARENT(elm)) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm)) = (tmp); \ + } else \ + (head)->rb_node = (tmp); \ + RB_RIGHT(tmp) = (elm); \ + RB_PARENT(elm) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp))) \ + RB_AUGMENT(RB_PARENT(tmp)); \ +} while(0) + +/* Note args swapped to match Linux */ +void rb_insert_color(struct rb_node *elm, struct rb_root *head) +{ + struct rb_node *parent, *gparent, *tmp; + while ((parent = RB_PARENT(elm)) && + RB_COLOR(parent) == RB_RED) { + gparent = RB_PARENT(parent); + if (parent == RB_LEFT(gparent)) { + tmp = RB_RIGHT(gparent); + if (tmp && RB_COLOR(tmp) == RB_RED) { + RB_COLOR(tmp) = RB_BLACK; + RB_SET_BLACKRED(parent, gparent); + elm = gparent; + continue; + } + if (RB_RIGHT(parent) == elm) { + RB_ROTATE_LEFT(head, parent, tmp); + tmp = parent; + parent = elm; + elm = tmp; + } + RB_SET_BLACKRED(parent, gparent); + RB_ROTATE_RIGHT(head, gparent, tmp); + } else { + tmp = RB_LEFT(gparent); + if (tmp && RB_COLOR(tmp) == RB_RED) { + RB_COLOR(tmp) = RB_BLACK; + RB_SET_BLACKRED(parent, gparent); + elm = gparent; + continue; + } + if (RB_LEFT(parent) == elm) { + RB_ROTATE_RIGHT(head, parent, tmp); + tmp = parent; + parent = elm; + elm = tmp; + } + RB_SET_BLACKRED(parent, gparent); + RB_ROTATE_LEFT(head, gparent, tmp); + } + } + RB_COLOR(head->rb_node) = RB_BLACK; +} + + +static void rb_remove_color(struct rb_root *head, struct rb_node *parent, + struct rb_node *elm) +{ + struct rb_node *tmp; + while ((elm == NULL || RB_COLOR(elm) == RB_BLACK) && + elm != RB_HEAD(head)) { + if (RB_LEFT(parent) == elm) { + tmp = RB_RIGHT(parent); + if (RB_COLOR(tmp) == RB_RED) { + RB_SET_BLACKRED(tmp, parent); + RB_ROTATE_LEFT(head, parent, tmp); + tmp = RB_RIGHT(parent); + } + if ((RB_LEFT(tmp) == NULL || + RB_COLOR(RB_LEFT(tmp)) == RB_BLACK) && + (RB_RIGHT(tmp) == NULL || + RB_COLOR(RB_RIGHT(tmp)) == RB_BLACK)) { + RB_COLOR(tmp) = RB_RED; + elm = parent; + parent = RB_PARENT(elm); + } else { + if (RB_RIGHT(tmp) == NULL || + RB_COLOR(RB_RIGHT(tmp)) == RB_BLACK) { + struct rb_node *oleft; + if ((oleft = RB_LEFT(tmp))) + RB_COLOR(oleft) = RB_BLACK; + RB_COLOR(tmp) = RB_RED; + RB_ROTATE_RIGHT(head, tmp, oleft); + tmp = RB_RIGHT(parent); + } + RB_COLOR(tmp) = RB_COLOR(parent); + RB_COLOR(parent) = RB_BLACK; + if (RB_RIGHT(tmp)) + RB_COLOR(RB_RIGHT(tmp)) = RB_BLACK; + RB_ROTATE_LEFT(head, parent, tmp); + elm = RB_HEAD(head); + break; + } + } else { + tmp = RB_LEFT(parent); + if (RB_COLOR(tmp) == RB_RED) { + RB_SET_BLACKRED(tmp, parent); + RB_ROTATE_RIGHT(head, parent, tmp); + tmp = RB_LEFT(parent); + } + if ((RB_LEFT(tmp) == NULL || + RB_COLOR(RB_LEFT(tmp)) == RB_BLACK) && + (RB_RIGHT(tmp) == NULL || + RB_COLOR(RB_RIGHT(tmp)) == RB_BLACK)) { + RB_COLOR(tmp) = RB_RED; + elm = parent; + parent = RB_PARENT(elm); + } else { + if (RB_LEFT(tmp) == NULL || + RB_COLOR(RB_LEFT(tmp)) == RB_BLACK) { + struct rb_node *oright; + if ((oright = RB_RIGHT(tmp))) + RB_COLOR(oright) = RB_BLACK; + RB_COLOR(tmp) = RB_RED; + RB_ROTATE_LEFT(head, tmp, oright); + tmp = RB_LEFT(parent); + } + RB_COLOR(tmp) = RB_COLOR(parent); + RB_COLOR(parent) = RB_BLACK; + if (RB_LEFT(tmp)) + RB_COLOR(RB_LEFT(tmp)) = RB_BLACK; + RB_ROTATE_RIGHT(head, parent, tmp); + elm = RB_HEAD(head); + break; + } + } + } + if (elm) + RB_COLOR(elm) = RB_BLACK; +} + +/* Note name changed. Guess why :) */ +void rb_erase(struct rb_node *elm, struct rb_root *head) +{ + struct rb_node *child, *parent, *old = elm; + int color; + if (RB_LEFT(elm) == NULL) + child = RB_RIGHT(elm); + else if (RB_RIGHT(elm) == NULL) + child = RB_LEFT(elm); + else { + struct rb_node *left; + elm = RB_RIGHT(elm); + while ((left = RB_LEFT(elm))) + elm = left; + child = RB_RIGHT(elm); + parent = RB_PARENT(elm); + color = RB_COLOR(elm); + if (child) + RB_PARENT(child) = parent; + if (parent) { + if (RB_LEFT(parent) == elm) + RB_LEFT(parent) = child; + else + RB_RIGHT(parent) = child; + RB_AUGMENT(parent); + } else + RB_HEAD(head) = child; + if (RB_PARENT(elm) == old) + parent = elm; + *(elm) = *(old); + if (RB_PARENT(old)) { + if (RB_LEFT(RB_PARENT(old)) == old) + RB_LEFT(RB_PARENT(old)) = elm; + else + RB_RIGHT(RB_PARENT(old)) = elm; + RB_AUGMENT(RB_PARENT(old)); + } else + RB_HEAD(head) = elm; + RB_PARENT(RB_LEFT(old)) = elm; + if (RB_RIGHT(old)) + RB_PARENT(RB_RIGHT(old)) = elm; + if (parent) { + left = parent; + do { + RB_AUGMENT(left); + } while ((left = RB_PARENT(left))); + } + goto color; + } + parent = RB_PARENT(elm); + color = RB_COLOR(elm); + if (child) + RB_PARENT(child) = parent; + if (parent) { + if (RB_LEFT(parent) == elm) + RB_LEFT(parent) = child; + else + RB_RIGHT(parent) = child; + RB_AUGMENT(parent); + } else + RB_HEAD(head) = child; +color: + if (color == RB_BLACK) + rb_remove_color(head, parent, child); +} + +struct rb_node *rb_next(struct rb_node *elm) +{ + if (RB_RIGHT(elm)) { + elm = RB_RIGHT(elm); + while (RB_LEFT(elm)) + elm = RB_LEFT(elm); + } else { + if (RB_PARENT(elm) && + (elm == RB_LEFT(RB_PARENT(elm)))) + elm = RB_PARENT(elm); + else { + while (RB_PARENT(elm) && + (elm == RB_RIGHT(RB_PARENT(elm)))) + elm = RB_PARENT(elm); + elm = RB_PARENT(elm); + } + } + return (elm); +} + +struct rb_node *rb_prev(struct rb_node *elm) +{ + if (RB_LEFT(elm)) { + elm = RB_LEFT(elm); + while (RB_RIGHT(elm)) + elm = RB_RIGHT(elm); + } else { + if (RB_PARENT(elm) && + (elm == RB_RIGHT(RB_PARENT(elm)))) + elm = RB_PARENT(elm); + else { + while (RB_PARENT(elm) && + (elm == RB_LEFT(RB_PARENT(elm)))) + elm = RB_PARENT(elm); + elm = RB_PARENT(elm); + } + } + return (elm); +} + +/* These ones are lifted from Linux -- but that's OK because I + wrote them. dwmw2. */ +struct rb_node *rb_first(struct rb_root *root) +{ + struct rb_node *n; + + n = root->rb_node; + if (!n) + return 0; + while (n->rb_left) + n = n->rb_left; + return n; +} + +void rb_replace_node(struct rb_node *victim, struct rb_node *new, + struct rb_root *root) +{ + struct rb_node *parent = victim->rb_parent; + + /* Set the surrounding nodes to point to the replacement */ + if (parent) { + if (victim == parent->rb_left) + parent->rb_left = new; + else + parent->rb_right = new; + } else { + root->rb_node = new; + } + if (victim->rb_left) + victim->rb_left->rb_parent = new; + if (victim->rb_right) + victim->rb_right->rb_parent = new; + + /* Copy the pointers/colour from the victim to the replacement */ + *new = *victim; +} diff --git a/cpukit/libfs/src/jffs2/src/dir-rtems.c b/cpukit/libfs/src/jffs2/src/dir-rtems.c new file mode 100644 index 0000000000..16b62cc15f --- /dev/null +++ b/cpukit/libfs/src/jffs2/src/dir-rtems.c @@ -0,0 +1,371 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2001-2003 Free Software Foundation, Inc. + * + * Created by David Woodhouse + * + * For licensing information, see the file 'LICENCE' in this directory. + * + * $Id: dir-ecos.c,v 1.11 2005/02/08 19:36:27 lunn Exp $ + * + */ + +#include +#include +#include "nodelist.h" + +/***********************************************************************/ + +/* Takes length argument because it can be either NUL-terminated or '/'-terminated */ +struct _inode *jffs2_lookup(struct _inode *dir_i, const unsigned char *d_name, int namelen) +{ + struct jffs2_inode_info *dir_f; + struct jffs2_sb_info *c; + struct jffs2_full_dirent *fd = NULL, *fd_list; + uint32_t ino = 0; + uint32_t hash = full_name_hash(d_name, namelen); + struct _inode *inode = NULL; + + D1(printk("jffs2_lookup()\n")); + + dir_f = JFFS2_INODE_INFO(dir_i); + c = JFFS2_SB_INFO(dir_i->i_sb); + + down(&dir_f->sem); + + /* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */ + for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= hash; fd_list = fd_list->next) { + if (fd_list->nhash == hash && + (!fd || fd_list->version > fd->version) && + strlen((char *)fd_list->name) == namelen && + !strncmp((char *)fd_list->name, (char *)d_name, namelen)) { + fd = fd_list; + } + } + if (fd) + ino = fd->ino; + up(&dir_f->sem); + if (ino) { + inode = jffs2_iget(dir_i->i_sb, ino); + if (IS_ERR(inode)) { + printk("jffs2_iget() failed for ino #%u\n", ino); + return inode; + } + } + + return inode; +} + +/***********************************************************************/ + + + +int jffs2_create(struct _inode *dir_i, const unsigned char *d_name, int mode, + struct _inode **new_i) +{ + struct jffs2_raw_inode *ri; + struct jffs2_inode_info *f, *dir_f; + struct jffs2_sb_info *c; + struct _inode *inode; + int ret; + + ri = jffs2_alloc_raw_inode(); + if (!ri) + return -ENOMEM; + + c = JFFS2_SB_INFO(dir_i->i_sb); + + D1(printk(KERN_DEBUG "jffs2_create()\n")); + + inode = jffs2_new_inode(dir_i, mode, ri); + + if (IS_ERR(inode)) { + D1(printk(KERN_DEBUG "jffs2_new_inode() failed\n")); + jffs2_free_raw_inode(ri); + return PTR_ERR(inode); + } + + f = JFFS2_INODE_INFO(inode); + dir_f = JFFS2_INODE_INFO(dir_i); + + ret = jffs2_do_create(c, dir_f, f, ri, + (const char *)d_name, + strlen((char *)d_name)); + + if (ret) { + inode->i_nlink = 0; + jffs2_iput(inode); + jffs2_free_raw_inode(ri); + return ret; + } + + jffs2_free_raw_inode(ri); + + D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d)\n", + inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink)); + *new_i = inode; + return 0; +} + +/***********************************************************************/ + + +int jffs2_unlink(struct _inode *dir_i, struct _inode *d_inode, const unsigned char *d_name) +{ + struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb); + struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); + struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(d_inode); + int ret; + + ret = jffs2_do_unlink(c, dir_f, (const char *)d_name, + strlen((char *)d_name), dead_f); + if (dead_f->inocache) + d_inode->i_nlink = dead_f->inocache->nlink; + return ret; +} +/***********************************************************************/ + + +int jffs2_link (struct _inode *old_d_inode, struct _inode *dir_i, const unsigned char *d_name) +{ + struct jffs2_sb_info *c = JFFS2_SB_INFO(old_d_inode->i_sb); + struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_d_inode); + struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); + int ret; + + /* XXX: This is ugly */ + uint8_t type = (old_d_inode->i_mode & S_IFMT) >> 12; + if (!type) type = DT_REG; + + ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, + (const char * )d_name, + strlen((char *)d_name)); + + if (!ret) { + down(&f->sem); + old_d_inode->i_nlink = ++f->inocache->nlink; + up(&f->sem); + } + return ret; +} + +int jffs2_mkdir (struct _inode *dir_i, const unsigned char *d_name, int mode) +{ + struct jffs2_inode_info *f, *dir_f; + struct jffs2_sb_info *c; + struct _inode *inode; + struct jffs2_raw_inode *ri; + struct jffs2_raw_dirent *rd; + struct jffs2_full_dnode *fn; + struct jffs2_full_dirent *fd; + int namelen; + uint32_t alloclen, phys_ofs; + int ret; + + mode |= S_IFDIR; + + ri = jffs2_alloc_raw_inode(); + if (!ri) + return -ENOMEM; + + c = JFFS2_SB_INFO(dir_i->i_sb); + + /* Try to reserve enough space for both node and dirent. + * Just the node will do for now, though + */ + namelen = strlen((char *)d_name); + ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL); + + if (ret) { + jffs2_free_raw_inode(ri); + return ret; + } + + inode = jffs2_new_inode(dir_i, mode, ri); + + if (IS_ERR(inode)) { + jffs2_free_raw_inode(ri); + jffs2_complete_reservation(c); + return PTR_ERR(inode); + } + + f = JFFS2_INODE_INFO(inode); + + ri->data_crc = cpu_to_je32(0); + ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); + + fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL); + + jffs2_free_raw_inode(ri); + + if (IS_ERR(fn)) { + /* Eeek. Wave bye bye */ + up(&f->sem); + jffs2_complete_reservation(c); + inode->i_nlink = 0; + jffs2_iput(inode); + return PTR_ERR(fn); + } + /* No data here. Only a metadata node, which will be + obsoleted by the first data write + */ + f->metadata = fn; + up(&f->sem); + + jffs2_complete_reservation(c); + ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); + if (ret) { + /* Eep. */ + inode->i_nlink = 0; + jffs2_iput(inode); + return ret; + } + + rd = jffs2_alloc_raw_dirent(); + if (!rd) { + /* Argh. Now we treat it like a normal delete */ + jffs2_complete_reservation(c); + inode->i_nlink = 0; + jffs2_iput(inode); + return -ENOMEM; + } + + dir_f = JFFS2_INODE_INFO(dir_i); + down(&dir_f->sem); + + rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); + rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); + rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); + + rd->pino = cpu_to_je32(dir_i->i_ino); + rd->version = cpu_to_je32(++dir_f->highest_version); + rd->ino = cpu_to_je32(inode->i_ino); + rd->mctime = cpu_to_je32(cyg_timestamp()); + rd->nsize = namelen; + rd->type = DT_DIR; + rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); + rd->name_crc = cpu_to_je32(crc32(0, d_name, namelen)); + + fd = jffs2_write_dirent(c, dir_f, rd, d_name, namelen, phys_ofs, ALLOC_NORMAL); + + jffs2_complete_reservation(c); + jffs2_free_raw_dirent(rd); + + if (IS_ERR(fd)) { + /* dirent failed to write. Delete the inode normally + as if it were the final unlink() */ + up(&dir_f->sem); + inode->i_nlink = 0; + jffs2_iput(inode); + return PTR_ERR(fd); + } + + /* Link the fd into the inode's list, obsoleting an old + one if necessary. */ + jffs2_add_fd_to_list(c, fd, &dir_f->dents); + up(&dir_f->sem); + + jffs2_iput(inode); + return 0; +} + +int jffs2_rmdir (struct _inode *dir_i, struct _inode *d_inode, const unsigned char *d_name) +{ + struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode); + struct jffs2_full_dirent *fd; + + for (fd = f->dents ; fd; fd = fd->next) { + if (fd->ino) + return EPERM; //-ENOTEMPTY; + } + return jffs2_unlink(dir_i, d_inode, d_name); +} + +int jffs2_rename (struct _inode *old_dir_i, struct _inode *d_inode, const unsigned char *old_d_name, + struct _inode *new_dir_i, const unsigned char *new_d_name) +{ + int ret; + struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); + struct jffs2_inode_info *victim_f = NULL; + uint8_t type; + +#if 0 /* FIXME -- this really doesn't belong in individual file systems. + The fileio code ought to do this for us, or at least part of it */ + if (new_dentry->d_inode) { + if (S_ISDIR(d_inode->i_mode) && + !S_ISDIR(new_dentry->d_inode->i_mode)) { + /* Cannot rename directory over non-directory */ + return -EINVAL; + } + + victim_f = JFFS2_INODE_INFO(new_dentry->d_inode); + + if (S_ISDIR(new_dentry->d_inode->i_mode)) { + struct jffs2_full_dirent *fd; + + if (!S_ISDIR(d_inode->i_mode)) { + /* Cannot rename non-directory over directory */ + return -EINVAL; + } + down(&victim_f->sem); + for (fd = victim_f->dents; fd; fd = fd->next) { + if (fd->ino) { + up(&victim_f->sem); + return -ENOTEMPTY; + } + } + up(&victim_f->sem); + } + } +#endif + + /* XXX: We probably ought to alloc enough space for + both nodes at the same time. Writing the new link, + then getting -ENOSPC, is quite bad :) + */ + + /* Make a hard link */ + + /* XXX: This is ugly */ + type = (d_inode->i_mode & S_IFMT) >> 12; + if (!type) type = DT_REG; + + ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), + d_inode->i_ino, type, + (const char *)new_d_name, + strlen((char *)new_d_name)); + + if (ret) + return ret; + + if (victim_f) { + /* There was a victim. Kill it off nicely */ + /* Don't oops if the victim was a dirent pointing to an + inode which didn't exist. */ + if (victim_f->inocache) { + down(&victim_f->sem); + victim_f->inocache->nlink--; + up(&victim_f->sem); + } + } + + /* Unlink the original */ + ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), + (const char *)old_d_name, + strlen((char *)old_d_name), NULL); + + if (ret) { + /* Oh shit. We really ought to make a single node which can do both atomically */ + struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode); + down(&f->sem); + if (f->inocache) + d_inode->i_nlink = f->inocache->nlink++; + up(&f->sem); + + printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret); + } + return ret; +} + diff --git a/cpukit/libfs/src/jffs2/src/flashio.c b/cpukit/libfs/src/jffs2/src/flashio.c new file mode 100644 index 0000000000..13a12e35b3 --- /dev/null +++ b/cpukit/libfs/src/jffs2/src/flashio.c @@ -0,0 +1,165 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2001-2003 Red Hat, Inc. + * + * Created by Dominic Ostrowski + * Contributors: David Woodhouse, Nick Garnett, Richard Panton. + * + * For licensing information, see the file 'LICENCE' in this directory. + * + * $Id: flashio.c,v 1.1 2003/11/26 14:09:29 dwmw2 Exp $ + * + */ + +#include +#include "nodelist.h" + +#include +#include +#include + +cyg_bool jffs2_flash_read(struct jffs2_sb_info * c, + cyg_uint32 read_buffer_offset, const size_t size, + size_t * return_size, unsigned char *write_buffer) +{ + Cyg_ErrNo err; + cyg_uint32 len = size; + struct super_block *sb = OFNI_BS_2SFFJ(c); + + //D2(printf("FLASH READ\n")); + //D2(printf("read address = %x\n", CYGNUM_FS_JFFS2_BASE_ADDRESS + read_buffer_offset)); + //D2(printf("write address = %x\n", write_buffer)); + //D2(printf("size = %x\n", size)); + err = cyg_io_bread(sb->s_dev, write_buffer, &len, read_buffer_offset); + + *return_size = (size_t) len; + return ((err == ENOERR) ? ENOERR : -EIO); +} + +cyg_bool jffs2_flash_write(struct jffs2_sb_info * c, + cyg_uint32 write_buffer_offset, const size_t size, + size_t * return_size, unsigned char *read_buffer) +{ + + Cyg_ErrNo err; + cyg_uint32 len = size; + struct super_block *sb = OFNI_BS_2SFFJ(c); + + // D2(printf("FLASH WRITE ENABLED!!!\n")); + // D2(printf("write address = %x\n", CYGNUM_FS_JFFS2_BASE_ADDRESS + write_buffer_offset)); + // D2(printf("read address = %x\n", read_buffer)); + // D2(printf("size = %x\n", size)); + + err = cyg_io_bwrite(sb->s_dev, read_buffer, &len, write_buffer_offset); + *return_size = (size_t) len; + + return ((err == ENOERR) ? ENOERR : -EIO); +} + +int +jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct iovec *vecs, + unsigned long count, loff_t to, size_t * retlen) +{ + unsigned long i; + size_t totlen = 0, thislen; + int ret = 0; + + for (i = 0; i < count; i++) { + // writes need to be aligned but the data we're passed may not be + // Observation suggests most unaligned writes are small, so we + // optimize for that case. + + if (((vecs[i].iov_len & (sizeof (int) - 1))) || + (((unsigned long) vecs[i]. + iov_base & (sizeof (unsigned long) - 1)))) { + // are there iov's after this one? Or is it so much we'd need + // to do multiple writes anyway? + if ((i + 1) < count || vecs[i].iov_len > 256) { + // cop out and malloc + unsigned long j; + ssize_t sizetomalloc = 0, totvecsize = 0; + char *cbuf, *cbufptr; + + for (j = i; j < count; j++) + totvecsize += vecs[j].iov_len; + + // pad up in case unaligned + sizetomalloc = totvecsize + sizeof (int) - 1; + sizetomalloc &= ~(sizeof (int) - 1); + cbuf = (char *) malloc(sizetomalloc); + // malloc returns aligned memory + if (!cbuf) { + ret = -ENOMEM; + goto writev_out; + } + cbufptr = cbuf; + for (j = i; j < count; j++) { + memcpy(cbufptr, vecs[j].iov_base, + vecs[j].iov_len); + cbufptr += vecs[j].iov_len; + } + ret = + jffs2_flash_write(c, to, sizetomalloc, + &thislen, cbuf); + if (thislen > totvecsize) // in case it was aligned up + thislen = totvecsize; + totlen += thislen; + free(cbuf); + goto writev_out; + } else { + // otherwise optimize for the common case + int buf[256 / sizeof (int)]; // int, so int aligned + size_t lentowrite; + + lentowrite = vecs[i].iov_len; + // pad up in case its unaligned + lentowrite += sizeof (int) - 1; + lentowrite &= ~(sizeof (int) - 1); + memcpy(buf, vecs[i].iov_base, lentowrite); + + ret = + jffs2_flash_write(c, to, lentowrite, + &thislen, (char *) &buf); + if (thislen > vecs[i].iov_len) + thislen = vecs[i].iov_len; + } // else + } else + ret = + jffs2_flash_write(c, to, vecs[i].iov_len, &thislen, + vecs[i].iov_base); + totlen += thislen; + if (ret || thislen != vecs[i].iov_len) + break; + to += vecs[i].iov_len; + } + writev_out: + if (retlen) + *retlen = totlen; + + return ret; +} + +cyg_bool jffs2_flash_erase(struct jffs2_sb_info * c, + struct jffs2_eraseblock * jeb) +{ + cyg_io_flash_getconfig_erase_t e; + cyg_flashaddr_t err_addr; + Cyg_ErrNo err; + cyg_uint32 len = sizeof (e); + struct super_block *sb = OFNI_BS_2SFFJ(c); + + e.offset = jeb->offset; + e.len = c->sector_size; + e.err_address = &err_addr; + + // D2(printf("FLASH ERASE ENABLED!!!\n")); + // D2(printf("erase address = %x\n", CYGNUM_FS_JFFS2_BASE_ADDRESS + jeb->offset)); + // D2(printf("size = %x\n", c->sector_size)); + + err = cyg_io_get_config(sb->s_dev, CYG_IO_GET_CONFIG_FLASH_ERASE, + &e, &len); + + return (err != ENOERR || e.flasherr != 0); +} + diff --git a/cpukit/libfs/src/jffs2/src/fs-rtems.c b/cpukit/libfs/src/jffs2/src/fs-rtems.c new file mode 100644 index 0000000000..c38b71906c --- /dev/null +++ b/cpukit/libfs/src/jffs2/src/fs-rtems.c @@ -0,0 +1,2191 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2001-2003 Free Software Foundation, Inc. + * + * Created by Dominic Ostrowski + * Contributors: David Woodhouse, Nick Garnett, Richard Panton. + * + * For licensing information, see the file 'LICENCE' in this directory. + * + * $Id: fs-ecos.c,v 1.44 2005/07/24 15:29:57 dedekind Exp $ + * + */ + +#include +#include "nodelist.h" +#include +#include +#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); + + +static int jffs2_read_inode (struct _inode *inode); +static void jffs2_clear_inode (struct _inode *inode); +static int jffs2_truncate_file (struct _inode *inode); + +//========================================================================== +// Filesystem table entries + +// ------------------------------------------------------------------------- +// Fstab entry. +// This defines the entry in the filesystem table. +// For simplicity we use _FILESYSTEM synchronization for all accesses since +// we should never block in any filesystem operations. + +#ifdef CYGOPT_FS_JFFS2_WRITE +FSTAB_ENTRY(jffs2_fste, "jffs2", 0, + CYG_SYNCMODE_FILE_FILESYSTEM | CYG_SYNCMODE_IO_FILESYSTEM, + jffs2_mount, + jffs2_umount, + jffs2_open, + jffs2_ops_unlink, + jffs2_ops_mkdir, + jffs2_ops_rmdir, + jffs2_ops_rename, + jffs2_ops_link, + jffs2_opendir, + jffs2_chdir, jffs2_stat, jffs2_getinfo, jffs2_setinfo); +#else +FSTAB_ENTRY(jffs2_fste, "jffs2", 0, + CYG_SYNCMODE_FILE_FILESYSTEM | CYG_SYNCMODE_IO_FILESYSTEM, + jffs2_mount, + jffs2_umount, + jffs2_open, + (cyg_fsop_unlink *)cyg_fileio_erofs, + (cyg_fsop_mkdir *)cyg_fileio_erofs, + (cyg_fsop_rmdir *)cyg_fileio_erofs, + (cyg_fsop_rename *)cyg_fileio_erofs, + (cyg_fsop_link *)cyg_fileio_erofs, + jffs2_opendir, + jffs2_chdir, jffs2_stat, jffs2_getinfo, jffs2_setinfo); +#endif + +// ------------------------------------------------------------------------- +// File operations. +// This set of file operations are used for normal open files. + +static cyg_fileops jffs2_fileops = { + jffs2_fo_read, +#ifdef CYGOPT_FS_JFFS2_WRITE + jffs2_fo_write, +#else + (cyg_fileop_write *) cyg_fileio_erofs, +#endif + jffs2_fo_lseek, + jffs2_fo_ioctl, + cyg_fileio_seltrue, + jffs2_fo_fsync, + jffs2_fo_close, + jffs2_fo_fstat, + jffs2_fo_getinfo, + jffs2_fo_setinfo +}; + +// ------------------------------------------------------------------------- +// Directory file operations. +// This set of operations are used for open directories. Most entries +// point to error-returning stub functions. Only the read, lseek and +// close entries are functional. + +static cyg_fileops jffs2_dirops = { + jffs2_fo_dirread, + (cyg_fileop_write *) cyg_fileio_enosys, + jffs2_fo_dirlseek, + (cyg_fileop_ioctl *) cyg_fileio_enosys, + cyg_fileio_seltrue, + (cyg_fileop_fsync *) cyg_fileio_enosys, + jffs2_fo_close, + (cyg_fileop_fstat *) cyg_fileio_enosys, + (cyg_fileop_getinfo *) cyg_fileio_enosys, + (cyg_fileop_setinfo *) cyg_fileio_enosys +}; + +//========================================================================== +// STATIC VARIABLES !!! + +static unsigned char gc_buffer[PAGE_CACHE_SIZE]; //avoids malloc when user may be under memory pressure +static unsigned char n_fs_mounted = 0; // a counter to track the number of jffs2 instances mounted + +//========================================================================== +// Directory operations + +struct jffs2_dirsearch { + struct _inode *dir; // directory to search + const unsigned char *path; // path to follow + struct _inode *node; // Node found + const unsigned char *name; // last name fragment used + int namelen; // name fragment length + cyg_bool last; // last name in path? +}; + +typedef struct jffs2_dirsearch jffs2_dirsearch; + +//========================================================================== +// Ref count and nlink management + + +// FIXME: This seems like real cruft. Wouldn't it be better just to do the +// right thing? +static void icache_evict(struct _inode *root_i, struct _inode *i) +{ + struct _inode *this = root_i, *next; + + restart: + D2(printf("icache_evict\n")); + // If this is an absolute search path from the root, + // remove all cached inodes with i_count of zero (these are only + // held where needed for dotdot filepaths) + while (this) { + next = this->i_cache_next; + if (this != i && this->i_count == 0) { + struct _inode *parent = this->i_parent; + if (this->i_cache_next) + this->i_cache_next->i_cache_prev = this->i_cache_prev; + if (this->i_cache_prev) + this->i_cache_prev->i_cache_next = this->i_cache_next; + jffs2_clear_inode(this); + memset(this, 0x5a, sizeof(*this)); + free(this); + if (parent && parent != this) { + parent->i_count--; + this = root_i; + goto restart; + } + } + this = next; + } +} + +//========================================================================== +// Directory search + +// ------------------------------------------------------------------------- +// init_dirsearch() +// Initialize a dirsearch object to start a search + +static void init_dirsearch(jffs2_dirsearch * ds, + struct _inode *dir, const unsigned char *name) +{ + D2(printf("init_dirsearch name = %s\n", name)); + D2(printf("init_dirsearch dir = %x\n", dir)); + + dir->i_count++; + ds->dir = dir; + ds->path = name; + ds->node = dir; + ds->name = name; + ds->namelen = 0; + ds->last = false; +} + +// ------------------------------------------------------------------------- +// find_entry() +// Search a single directory for the next name in a path and update the +// dirsearch object appropriately. + +static int find_entry(jffs2_dirsearch * ds) +{ + struct _inode *dir = ds->dir; + const unsigned char *name = ds->path; + const unsigned char *n = name; + char namelen = 0; + struct _inode *d; + + D2(printf("find_entry\n")); + + // check that we really have a directory + if (!S_ISDIR(dir->i_mode)) + return ENOTDIR; + + // Isolate the next element of the path name. + while (*n != '\0' && *n != '/') + n++, namelen++; + + // Check if this is the last path element. + while( *n == '/') n++; + if (*n == '\0') + ds->last = true; + + // update name in dirsearch object + ds->name = name; + ds->namelen = namelen; + + if (name[0] == '.') + switch (namelen) { + default: + break; + case 2: + // Dot followed by not Dot, treat as any other name + if (name[1] != '.') + break; + // Dot Dot + // Move back up the search path + D2(printf("find_entry found ..\n")); + ds->dir = ds->node; + ds->node = ds->dir->i_parent; + ds->node->i_count++; + return ENOERR; + case 1: + // Dot is consumed + D2(printf("find_entry found .\n")); + ds->node = ds->dir; + ds->dir->i_count++; + return ENOERR; + } + + // Here we have the name and its length set up. + // Search the directory for a matching entry + + D2(printf("find_entry for name = %s\n", ds->path)); + d = jffs2_lookup(dir, name, namelen); + D2(printf("find_entry got dir = %x\n", d)); + + if (d == NULL) + return ENOENT; + if (IS_ERR(d)) + return -PTR_ERR(d); + + // If it's a new directory inode, increase refcount on its parent + if (S_ISDIR(d->i_mode) && !d->i_parent) { + d->i_parent = dir; + dir->i_count++; + } + + // pass back the node we have found + ds->node = d; + return ENOERR; + +} + +// ------------------------------------------------------------------------- +// jffs2_find() +// Main interface to directory search code. This is used in all file +// level operations to locate the object named by the pathname. + +// Returns with use count incremented on both the sought object and +// the directory it was found in +static int jffs2_find(jffs2_dirsearch * d) +{ + int err; + + D2(printf("jffs2_find for path =%s\n", d->path)); + + // Short circuit empty paths + if (*(d->path) == '\0') { + d->node->i_count++; + return ENOERR; + } + + // iterate down directory tree until we find the object + // we want. + for (;;) { + err = find_entry(d); + + if (err != ENOERR) + return err; + + if (d->last) + return ENOERR; + + /* We're done with it, although it we found a subdir that + will have caused the refcount to have been increased */ + jffs2_iput(d->dir); + + // Update dirsearch object to search next directory. + d->dir = d->node; + d->path += d->namelen; + while (*(d->path) == '/') + d->path++; // skip dirname separators + } +} + +//========================================================================== +// Pathconf support +// This function provides support for pathconf() and fpathconf(). + +static int jffs2_pathconf(struct _inode *node, struct cyg_pathconf_info *info) +{ + int err = ENOERR; + D2(printf("jffs2_pathconf\n")); + + switch (info->name) { + case _PC_LINK_MAX: + info->value = LINK_MAX; + break; + + case _PC_MAX_CANON: + info->value = -1; // not supported + err = EINVAL; + break; + + case _PC_MAX_INPUT: + info->value = -1; // not supported + err = EINVAL; + break; + + case _PC_NAME_MAX: + info->value = NAME_MAX; + break; + + case _PC_PATH_MAX: + info->value = PATH_MAX; + break; + + case _PC_PIPE_BUF: + info->value = -1; // not supported + err = EINVAL; + break; + + case _PC_ASYNC_IO: + info->value = -1; // not supported + err = EINVAL; + break; + + case _PC_CHOWN_RESTRICTED: + info->value = -1; // not supported + err = EINVAL; + break; + + case _PC_NO_TRUNC: + info->value = 0; + break; + + case _PC_PRIO_IO: + info->value = 0; + break; + + case _PC_SYNC_IO: + info->value = 0; + break; + + case _PC_VDISABLE: + info->value = -1; // not supported + err = EINVAL; + break; + + default: + err = EINVAL; + break; + } + + return err; +} + +//========================================================================== +// Filesystem operations + +// ------------------------------------------------------------------------- +// jffs2_mount() +// Process a mount request. This mainly creates a root for the +// filesystem. +static int jffs2_read_super(struct super_block *sb) +{ + struct jffs2_sb_info *c; + Cyg_ErrNo err; + cyg_uint32 len; + cyg_io_flash_getconfig_devsize_t ds; + cyg_io_flash_getconfig_blocksize_t bs; + + D1(printk(KERN_DEBUG "jffs2: read_super\n")); + + c = JFFS2_SB_INFO(sb); + + len = sizeof (ds); + err = cyg_io_get_config(sb->s_dev, + CYG_IO_GET_CONFIG_FLASH_DEVSIZE, &ds, &len); + if (err != ENOERR) { + D1(printf + ("jffs2: cyg_io_get_config failed to get dev size: %d\n", + err)); + return err; + } + len = sizeof (bs); + bs.offset = 0; + err = cyg_io_get_config(sb->s_dev, + CYG_IO_GET_CONFIG_FLASH_BLOCKSIZE, &bs, &len); + if (err != ENOERR) { + D1(printf + ("jffs2: cyg_io_get_config failed to get block size: %d\n", + err)); + return err; + } + + c->sector_size = bs.block_size; + c->flash_size = ds.dev_size; + c->cleanmarker_size = sizeof(struct jffs2_unknown_node); + + err = jffs2_do_mount_fs(c); + if (err) + return -err; + + D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n")); + sb->s_root = jffs2_iget(sb, 1); + if (IS_ERR(sb->s_root)) { + D1(printk(KERN_WARNING "get root inode failed\n")); + err = PTR_ERR(sb->s_root); + sb->s_root = NULL; + goto out_nodes; + } + + return 0; + + out_nodes: + jffs2_free_ino_caches(c); + jffs2_free_raw_node_refs(c); + free(c->blocks); + + return err; +} + +static int jffs2_mount(cyg_fstab_entry * fste, cyg_mtab_entry * mte) +{ + extern cyg_mtab_entry cyg_mtab[], cyg_mtab_end; + struct super_block *jffs2_sb = NULL; + struct jffs2_sb_info *c; + cyg_mtab_entry *m; + cyg_io_handle_t t; + Cyg_ErrNo err; + + D2(printf("jffs2_mount\n")); + + err = cyg_io_lookup(mte->devname, &t); + if (err != ENOERR) + return -err; + + // Iterate through the mount table to see if we're mounted + // FIXME: this should be done better - perhaps if the superblock + // can be stored as an inode in the icache. + for (m = &cyg_mtab[0]; m != &cyg_mtab_end; m++) { + // stop if there are more than the configured maximum + if (m - &cyg_mtab[0] >= CYGNUM_FILEIO_MTAB_MAX) { + m = &cyg_mtab_end; + break; + } + if (m->valid && strcmp(m->fsname, "jffs2") == 0 && + strcmp(m->devname, mte->devname) == 0) { + jffs2_sb = (struct super_block *) m->data; + } + } + + if (jffs2_sb == NULL) { + jffs2_sb = malloc(sizeof (struct super_block)); + + if (jffs2_sb == NULL) + return ENOMEM; + + c = JFFS2_SB_INFO(jffs2_sb); + memset(jffs2_sb, 0, sizeof (struct super_block)); + jffs2_sb->s_dev = t; + + c->inocache_list = malloc(sizeof(struct jffs2_inode_cache *) * INOCACHE_HASHSIZE); + if (!c->inocache_list) { + free(jffs2_sb); + return ENOMEM; + } + memset(c->inocache_list, 0, sizeof(struct jffs2_inode_cache *) * INOCACHE_HASHSIZE); + if (n_fs_mounted++ == 0) { + jffs2_create_slab_caches(); // No error check, cannot fail + jffs2_compressors_init(); + } + + err = jffs2_read_super(jffs2_sb); + + if (err) { + if (--n_fs_mounted == 0) { + jffs2_destroy_slab_caches(); + jffs2_compressors_exit(); + } + + free(jffs2_sb); + free(c->inocache_list); + return err; + } + + jffs2_sb->s_root->i_parent = jffs2_sb->s_root; // points to itself, no dotdot paths above mountpoint + jffs2_sb->s_root->i_cache_prev = NULL; // root inode, so always null + jffs2_sb->s_root->i_cache_next = NULL; + jffs2_sb->s_root->i_count = 1; // Ensures the root inode is always in ram until umount + + D2(printf("jffs2_mount erasing pending blocks\n")); +#ifdef CYGOPT_FS_JFFS2_WRITE + if (!jffs2_is_readonly(c)) + jffs2_erase_pending_blocks(c,0); +#endif +#ifdef CYGOPT_FS_JFFS2_GCTHREAD + jffs2_start_garbage_collect_thread(c); +#endif + } + mte->data = (CYG_ADDRWORD) jffs2_sb; + + jffs2_sb->s_mount_count++; + mte->root = (cyg_dir) jffs2_sb->s_root; + D2(printf("jffs2_mounted superblock at %x\n", mte->root)); + + return ENOERR; +} + +extern cyg_dir cyg_cdir_dir; +extern cyg_mtab_entry *cyg_cdir_mtab_entry; + +// ------------------------------------------------------------------------- +// jffs2_umount() +// Unmount the filesystem. + +static int jffs2_umount(cyg_mtab_entry * mte) +{ + struct _inode *root = (struct _inode *) mte->root; + struct super_block *jffs2_sb = root->i_sb; + struct jffs2_sb_info *c = JFFS2_SB_INFO(jffs2_sb); + struct jffs2_full_dirent *fd, *next; + + D2(printf("jffs2_umount\n")); + + // Only really umount if this is the only mount + if (jffs2_sb->s_mount_count == 1) { + icache_evict(root, NULL); + if (root->i_cache_next != NULL) { + struct _inode *inode = root; + printf("Refuse to unmount.\n"); + while (inode) { + printf("Ino #%u has use count %d\n", + inode->i_ino, inode->i_count); + inode = inode->i_cache_next; + } + // root icount was set to 1 on mount + return EBUSY; + } + if (root->i_count == 2 && + cyg_cdir_mtab_entry == mte && + cyg_cdir_dir == (cyg_dir)root && + !strcmp(mte->name, "/")) { + /* If we were mounted on root, there's no + way for the cwd to change out and free + the file system for unmounting. So we hack + it -- if cwd is '/' we unset it. Perhaps + we should allow chdir(NULL) to unset + cyg_cdir_dir? */ + cyg_cdir_dir = CYG_DIR_NULL; + jffs2_iput(root); + } + /* Argh. The fileio code sets this; never clears it */ + if (cyg_cdir_mtab_entry == mte) + cyg_cdir_mtab_entry = NULL; + + if (root->i_count != 1) { + printf("Ino #1 has use count %d\n", + root->i_count); + return EBUSY; + } +#ifdef CYGOPT_FS_JFFS2_GCTHREAD + jffs2_stop_garbage_collect_thread(c); +#endif + jffs2_iput(root); // Time to free the root inode + + // free directory entries + for (fd = root->jffs2_i.dents; fd; fd = next) { + next=fd->next; + jffs2_free_full_dirent(fd); + } + + free(root); + //Clear root inode + //root_i = NULL; + + // Clean up the super block and root inode + jffs2_free_ino_caches(c); + jffs2_free_raw_node_refs(c); + free(c->blocks); + free(c->inocache_list); + free(jffs2_sb); + // Clear superblock & root pointer + mte->root = CYG_DIR_NULL; + mte->data = 0; + mte->fs->data = 0; // fstab entry, visible to all mounts. No current mount + // That's all folks. + D2(printf("jffs2_umount No current mounts\n")); + } else { + jffs2_sb->s_mount_count--; + } + if (--n_fs_mounted == 0) { + jffs2_destroy_slab_caches(); + jffs2_compressors_exit(); + } + return ENOERR; +} + +// ------------------------------------------------------------------------- +// jffs2_open() +// Open a file for reading or writing. + +static int jffs2_open(cyg_mtab_entry * mte, cyg_dir dir, const char *name, + int mode, cyg_file * file) +{ + + jffs2_dirsearch ds; + struct _inode *node = NULL; + int err; + + D2(printf("jffs2_open\n")); + + /* If no chdir has been called and we were the first file system + mounted, we get called with dir == NULL. Deal with it */ + if (!dir) + dir = mte->root; + +#ifndef CYGOPT_FS_JFFS2_WRITE + if (mode & (O_CREAT|O_TRUNC|O_WRONLY)) + return EROFS; +#endif + init_dirsearch(&ds, (struct _inode *) dir, + (const unsigned char *) name); + + err = jffs2_find(&ds); + + if (err == ENOENT) { +#ifdef CYGOPT_FS_JFFS2_WRITE + if (ds.last && (mode & O_CREAT)) { + + // No node there, if the O_CREAT bit is set then we must + // create a new one. The dir and name fields of the dirsearch + // object will have been updated so we know where to put it. + + err = jffs2_create(ds.dir, ds.name, S_IRUGO|S_IXUGO|S_IWUSR|S_IFREG, &node); + + if (err != 0) { + //Possible orphaned inode on the flash - but will be gc'd + jffs2_iput(ds.dir); + return -err; + } + + err = ENOERR; + } +#endif + } else if (err == ENOERR) { + // The node exists. If the O_CREAT and O_EXCL bits are set, we + // must fail the open. + + if ((mode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) { + jffs2_iput(ds.node); + err = EEXIST; + } else + node = ds.node; + } + + // Finished with the directory now + jffs2_iput(ds.dir); + + if (err != ENOERR) + return err; + + // Check that we actually have a file here + if (S_ISDIR(node->i_mode)) { + jffs2_iput(node); + return EISDIR; + } + + // If the O_TRUNC bit is set we must clean out the file data. + if (mode & O_TRUNC) { +#ifdef CYGOPT_FS_JFFS2_WRITE + err = jffs2_truncate_file(node); + if (err) { + jffs2_iput(node); + return err; + } +#else + jffs2_iput(node); + return EROFS; +#endif + } + + // Initialise the file object + file->f_flag |= mode & CYG_FILE_MODE_MASK; + file->f_type = CYG_FILE_TYPE_FILE; + file->f_ops = &jffs2_fileops; + file->f_offset = (mode & O_APPEND) ? node->i_size : 0; + file->f_data = (CYG_ADDRWORD) node; + file->f_xops = 0; + + return ENOERR; +} + +#ifdef CYGOPT_FS_JFFS2_WRITE +// ------------------------------------------------------------------------- +// jffs2_ops_unlink() +// Remove a file link from its directory. + +static int jffs2_ops_unlink(cyg_mtab_entry * mte, cyg_dir dir, const char *name) +{ + jffs2_dirsearch ds; + int err; + + D2(printf("jffs2_ops_unlink\n")); + + init_dirsearch(&ds, (struct _inode *) dir, + (const unsigned char *)name); + + err = jffs2_find(&ds); + + if (err != ENOERR) { + jffs2_iput(ds.dir); + return err; + } + + // Cannot unlink directories, use rmdir() instead + if (S_ISDIR(ds.node->i_mode)) { + jffs2_iput(ds.dir); + jffs2_iput(ds.node); + return EPERM; + } + + // Delete it from its directory + + err = jffs2_unlink(ds.dir, ds.node, ds.name); + jffs2_iput(ds.dir); + jffs2_iput(ds.node); + + return -err; +} + +// ------------------------------------------------------------------------- +// jffs2_ops_mkdir() +// Create a new directory. + +static int jffs2_ops_mkdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name) +{ + jffs2_dirsearch ds; + int err; + + D2(printf("jffs2_ops_mkdir\n")); + + init_dirsearch(&ds, (struct _inode *) dir, + (const unsigned char *)name); + + err = jffs2_find(&ds); + + if (err == ENOENT) { + if (ds.last) { + // The entry does not exist, and it is the last element in + // the pathname, so we can create it here. + + err = -jffs2_mkdir(ds.dir, ds.name, S_IRUGO|S_IXUGO|S_IWUSR); + } + // If this was not the last element, then an intermediate + // directory does not exist. + } else { + // If there we no error, something already exists with that + // name, so we cannot create another one. + if (err == ENOERR) { + jffs2_iput(ds.node); + err = EEXIST; + } + } + jffs2_iput(ds.dir); + return err; +} + +// ------------------------------------------------------------------------- +// jffs2_ops_rmdir() +// Remove a directory. + +static int jffs2_ops_rmdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name) +{ + jffs2_dirsearch ds; + int err; + + D2(printf("jffs2_ops_rmdir\n")); + + init_dirsearch(&ds, (struct _inode *) dir, + (const unsigned char *)name); + + err = jffs2_find(&ds); + + if (err != ENOERR) { + jffs2_iput(ds.dir); + return err; + } + + // Check that this is actually a directory. + if (!S_ISDIR(ds.node->i_mode)) { + jffs2_iput(ds.dir); + jffs2_iput(ds.node); + return EPERM; + } + + err = jffs2_rmdir(ds.dir, ds.node, ds.name); + + jffs2_iput(ds.dir); + jffs2_iput(ds.node); + return -err; +} + +// ------------------------------------------------------------------------- +// jffs2_ops_rename() +// Rename a file/dir. + +static int jffs2_ops_rename(cyg_mtab_entry * mte, cyg_dir dir1, + const char *name1, cyg_dir dir2, const char *name2) +{ + jffs2_dirsearch ds1, ds2; + int err; + + D2(printf("jffs2_ops_rename\n")); + + init_dirsearch(&ds1, (struct _inode *) dir1, + (const unsigned char *)name1); + + err = jffs2_find(&ds1); + + if (err != ENOERR) { + jffs2_iput(ds1.dir); + return err; + } + + init_dirsearch(&ds2, (struct _inode *) dir2, + (const unsigned char *)name2); + + err = jffs2_find(&ds2); + + // Allow through renames to non-existent objects. + if (ds2.last && err == ENOENT) { + ds2.node = NULL; + err = ENOERR; + } + + if (err != ENOERR) { + jffs2_iput(ds1.dir); + jffs2_iput(ds1.node); + jffs2_iput(ds2.dir); + return err; + } + + // Null rename, just return + if (ds1.node == ds2.node) { + err = ENOERR; + goto out; + } + + // First deal with any entry that is at the destination + if (ds2.node) { + // Check that we are renaming like-for-like + + if (!S_ISDIR(ds1.node->i_mode) && S_ISDIR(ds2.node->i_mode)) { + err = EISDIR; + goto out; + } + + if (S_ISDIR(ds1.node->i_mode) && !S_ISDIR(ds2.node->i_mode)) { + err = ENOTDIR; + goto out; + } + + // Now delete the destination directory entry + /* Er, what happened to atomicity of rename()? */ + err = -jffs2_unlink(ds2.dir, ds2.node, ds2.name); + + if (err != 0) + goto out; + + } + // Now we know that there is no clashing node at the destination, + // make a new direntry at the destination and delete the old entry + // at the source. + + err = -jffs2_rename(ds1.dir, ds1.node, ds1.name, ds2.dir, ds2.name); + + // Update directory times + if (!err) + ds1.dir->i_ctime = + ds1.dir->i_mtime = + ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp(); + out: + jffs2_iput(ds1.dir); + if (S_ISDIR(ds1.node->i_mode)) { + /* Renamed a directory to elsewhere... so fix up its + i_parent pointer and the i_counts of its old and + new parents. */ + jffs2_iput(ds1.node->i_parent); + ds1.node->i_parent = ds2.dir; + /* We effectively increase its use count by not... */ + } else { + jffs2_iput(ds2.dir); /* ... doing this */ + } + jffs2_iput(ds1.node); + if (ds2.node) + jffs2_iput(ds2.node); + + return err; +} + +// ------------------------------------------------------------------------- +// jffs2_ops_link() +// Make a new directory entry for a file. + +static int jffs2_ops_link(cyg_mtab_entry * mte, cyg_dir dir1, const char *name1, + cyg_dir dir2, const char *name2, int type) +{ + jffs2_dirsearch ds1, ds2; + int err; + + D2(printf("jffs2_ops_link\n")); + + // Only do hard links for now in this filesystem + if (type != CYG_FSLINK_HARD) + return EINVAL; + + init_dirsearch(&ds1, (struct _inode *) dir1, + (const unsigned char *) name1); + + err = jffs2_find(&ds1); + + if (err != ENOERR) { + jffs2_iput(ds1.dir); + return err; + } + + init_dirsearch(&ds2, (struct _inode *) dir2, + (const unsigned char *) name2); + + err = jffs2_find(&ds2); + + // Don't allow links to existing objects + if (err == ENOERR) { + jffs2_iput(ds1.dir); + jffs2_iput(ds1.node); + jffs2_iput(ds2.dir); + jffs2_iput(ds2.node); + return EEXIST; + } + + // Allow through links to non-existing terminal objects + if (ds2.last && err == ENOENT) { + ds2.node = NULL; + err = ENOERR; + } + + if (err != ENOERR) { + jffs2_iput(ds1.dir); + jffs2_iput(ds1.node); + jffs2_iput(ds2.dir); + return err; + } + + // Now we know that there is no existing node at the destination, + // make a new direntry at the destination. + + err = jffs2_link(ds1.node, ds2.dir, ds2.name); + + if (err == 0) + ds1.node->i_ctime = + ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp(); + + jffs2_iput(ds1.dir); + jffs2_iput(ds1.node); + jffs2_iput(ds2.dir); + + return -err; +} +#endif /* CYGOPT_FS_JFFS2_WRITE */ +// ------------------------------------------------------------------------- +// jffs2_opendir() +// Open a directory for reading. + +static int jffs2_opendir(cyg_mtab_entry * mte, cyg_dir dir, const char *name, + cyg_file * file) +{ + jffs2_dirsearch ds; + int err; + + D2(printf("jffs2_opendir\n")); + + init_dirsearch(&ds, (struct _inode *) dir, + (const unsigned char *) name); + + err = jffs2_find(&ds); + + jffs2_iput(ds.dir); + + if (err != ENOERR) + return err; + + // check it is really a directory. + if (!S_ISDIR(ds.node->i_mode)) { + jffs2_iput(ds.node); + return ENOTDIR; + } + + // Initialize the file object, setting the f_ops field to a + // special set of file ops. + + file->f_type = CYG_FILE_TYPE_FILE; + file->f_ops = &jffs2_dirops; + file->f_offset = 0; + file->f_data = (CYG_ADDRWORD) ds.node; + file->f_xops = 0; + + return ENOERR; + +} + +// ------------------------------------------------------------------------- +// jffs2_chdir() +// Change directory support. + +static int jffs2_chdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name, + cyg_dir * dir_out) +{ + D2(printf("jffs2_chdir\n")); + + if (dir_out != NULL) { + // This is a request to get a new directory pointer in + // *dir_out. + + jffs2_dirsearch ds; + int err; + + init_dirsearch(&ds, (struct _inode *) dir, + (const unsigned char *) name); + + err = jffs2_find(&ds); + jffs2_iput(ds.dir); + + if (err != ENOERR) + return err; + + // check it is a directory + if (!S_ISDIR(ds.node->i_mode)) { + jffs2_iput(ds.node); + return ENOTDIR; + } + + // Pass it out + *dir_out = (cyg_dir) ds.node; + } else { + // If no output dir is required, this means that the mte and + // dir arguments are the current cdir setting and we should + // forget this fact. + + struct _inode *node = (struct _inode *) dir; + + // Just decrement directory reference count. + jffs2_iput(node); + } + + return ENOERR; +} + +// ------------------------------------------------------------------------- +// jffs2_stat() +// Get struct stat info for named object. + +static int jffs2_stat(cyg_mtab_entry * mte, cyg_dir dir, const char *name, + struct stat *buf) +{ + jffs2_dirsearch ds; + int err; + + D2(printf("jffs2_stat\n")); + + init_dirsearch(&ds, (struct _inode *) dir, + (const unsigned char *) name); + + err = jffs2_find(&ds); + jffs2_iput(ds.dir); + + if (err != ENOERR) + return err; + + // Fill in the status + buf->st_mode = ds.node->i_mode; + buf->st_ino = ds.node->i_ino; + buf->st_dev = 0; + buf->st_nlink = ds.node->i_nlink; + buf->st_uid = ds.node->i_uid; + buf->st_gid = ds.node->i_gid; + buf->st_size = ds.node->i_size; + buf->st_atime = ds.node->i_atime; + buf->st_mtime = ds.node->i_mtime; + buf->st_ctime = ds.node->i_ctime; + + jffs2_iput(ds.node); + + return ENOERR; +} + +// ------------------------------------------------------------------------- +// jffs2_getinfo() +// Getinfo. Currently only support pathconf(). + +static int jffs2_getinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name, + int key, void *buf, int len) +{ + jffs2_dirsearch ds; + int err; + + D2(printf("jffs2_getinfo\n")); + + init_dirsearch(&ds, (struct _inode *) dir, + (const unsigned char *) name); + + err = jffs2_find(&ds); + jffs2_iput(ds.dir); + + if (err != ENOERR) + return err; + + switch (key) { + case FS_INFO_CONF: + err = jffs2_pathconf(ds.node, (struct cyg_pathconf_info *) buf); + break; + + default: + err = EINVAL; + } + + jffs2_iput(ds.node); + return err; +} + +// ------------------------------------------------------------------------- +// jffs2_setinfo() +// Setinfo. Nothing to support here at present. + +static int jffs2_setinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name, + int key, void *buf, int len) +{ + // No setinfo keys supported at present + + D2(printf("jffs2_setinfo\n")); + + return EINVAL; +} + +//========================================================================== +// File operations + +// ------------------------------------------------------------------------- +// jffs2_fo_read() +// Read data from the file. + +static int jffs2_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) +{ + struct _inode *inode = (struct _inode *) fp->f_data; + struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); + int i; + ssize_t resid = uio->uio_resid; + off_t pos = fp->f_offset; + + down(&f->sem); + + // Loop over the io vectors until there are none left + for (i = 0; i < uio->uio_iovcnt && pos < inode->i_size; i++) { + int ret; + cyg_iovec *iov = &uio->uio_iov[i]; + off_t len = min(iov->iov_len, inode->i_size - pos); + + D2(printf("jffs2_fo_read inode size %d\n", inode->i_size)); + + ret = + jffs2_read_inode_range(c, f, + (unsigned char *) iov->iov_base, pos, + len); + if (ret) { + D1(printf + ("jffs2_fo_read(): read_inode_range failed %d\n", + ret)); + uio->uio_resid = resid; + up(&f->sem); + return -ret; + } + resid -= len; + pos += len; + } + + // We successfully read some data, update the node's access time + // and update the file offset and transfer residue. + + inode->i_atime = cyg_timestamp(); + + uio->uio_resid = resid; + fp->f_offset = pos; + + up(&f->sem); + + return ENOERR; +} + + +#ifdef CYGOPT_FS_JFFS2_WRITE +// ------------------------------------------------------------------------- +// jffs2_fo_write() +// Write data to file. +static int jffs2_extend_file (struct _inode *inode, struct jffs2_raw_inode *ri, + unsigned long offset) +{ + struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); + struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + struct jffs2_full_dnode *fn; + uint32_t phys_ofs, alloc_len; + int ret = 0; + + /* Make new hole frag from old EOF to new page */ + D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", + (unsigned int)inode->i_size, offset)); + + ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloc_len, ALLOC_NORMAL); + if (ret) + return ret; + + down(&f->sem); + + ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); + ri->totlen = cpu_to_je32(sizeof(*ri)); + ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); + + ri->version = cpu_to_je32(++f->highest_version); + ri->isize = cpu_to_je32(max((uint32_t)inode->i_size, offset)); + + ri->offset = cpu_to_je32(inode->i_size); + ri->dsize = cpu_to_je32(offset - inode->i_size); + ri->csize = cpu_to_je32(0); + ri->compr = JFFS2_COMPR_ZERO; + ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); + ri->data_crc = cpu_to_je32(0); + + fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL); + jffs2_complete_reservation(c); + if (IS_ERR(fn)) { + ret = PTR_ERR(fn); + up(&f->sem); + return ret; + } + ret = jffs2_add_full_dnode_to_inode(c, f, fn); + if (f->metadata) { + jffs2_mark_node_obsolete(c, f->metadata->raw); + jffs2_free_full_dnode(f->metadata); + f->metadata = NULL; + } + if (ret) { + D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in prepare_write, returned %d\n", ret)); + jffs2_mark_node_obsolete(c, fn->raw); + jffs2_free_full_dnode(fn); + up(&f->sem); + return ret; + } + inode->i_size = offset; + up(&f->sem); + return 0; +} + +// jffs2_fo_open() +// Truncate a file +static int jffs2_truncate_file (struct _inode *inode) +{ + struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); + struct jffs2_full_dnode *new_metadata, * old_metadata; + struct jffs2_raw_inode *ri; + uint32_t phys_ofs, alloclen; + int err; + + ri = jffs2_alloc_raw_inode(); + if (!ri) { + return ENOMEM; + } + err = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL); + + if (err) { + jffs2_free_raw_inode(ri); + return err; + } + down(&f->sem); + ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); + ri->totlen = cpu_to_je32(sizeof(*ri)); + ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); + + ri->ino = cpu_to_je32(inode->i_ino); + ri->version = cpu_to_je32(++f->highest_version); + + ri->uid = cpu_to_je16(inode->i_uid); + ri->gid = cpu_to_je16(inode->i_gid); + ri->mode = cpu_to_jemode(inode->i_mode); + ri->isize = cpu_to_je32(0); + ri->atime = cpu_to_je32(inode->i_atime); + ri->mtime = cpu_to_je32(cyg_timestamp()); + ri->offset = cpu_to_je32(0); + ri->csize = ri->dsize = cpu_to_je32(0); + ri->compr = JFFS2_COMPR_NONE; + ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); + ri->data_crc = cpu_to_je32(0); + new_metadata = jffs2_write_dnode(c, f, ri, NULL, 0, + phys_ofs, ALLOC_NORMAL); + if (IS_ERR(new_metadata)) { + jffs2_complete_reservation(c); + jffs2_free_raw_inode(ri); + up(&f->sem); + return PTR_ERR(new_metadata); + } + + /* It worked. Update the inode */ + inode->i_mtime = cyg_timestamp(); + inode->i_size = 0; + old_metadata = f->metadata; + jffs2_truncate_fragtree (c, &f->fragtree, 0); + f->metadata = new_metadata; + if (old_metadata) { + jffs2_mark_node_obsolete(c, old_metadata->raw); + jffs2_free_full_dnode(old_metadata); + } + jffs2_free_raw_inode(ri); + + up(&f->sem); + jffs2_complete_reservation(c); + + return 0; +} + +static int jffs2_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) +{ + struct _inode *inode = (struct _inode *) fp->f_data; + off_t pos = fp->f_offset; + ssize_t resid = uio->uio_resid; + struct jffs2_raw_inode ri; + struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); + int i; + + // If the APPEND mode bit was supplied, force all writes to + // the end of the file. + if (fp->f_flag & CYG_FAPPEND) + pos = fp->f_offset = inode->i_size; + + if (pos < 0) + return EINVAL; + + memset(&ri, 0, sizeof(ri)); + + ri.ino = cpu_to_je32(f->inocache->ino); + ri.mode = cpu_to_jemode(inode->i_mode); + ri.uid = cpu_to_je16(inode->i_uid); + ri.gid = cpu_to_je16(inode->i_gid); + ri.atime = ri.ctime = ri.mtime = cpu_to_je32(cyg_timestamp()); + + if (pos > inode->i_size) { + int err; + ri.version = cpu_to_je32(++f->highest_version); + err = jffs2_extend_file(inode, &ri, pos); + if (err) + return -err; + } + ri.isize = cpu_to_je32(inode->i_size); + + // Now loop over the iovecs until they are all done, or + // we get an error. + for (i = 0; i < uio->uio_iovcnt; i++) { + cyg_iovec *iov = &uio->uio_iov[i]; + unsigned char *buf = iov->iov_base; + off_t len = iov->iov_len; + + uint32_t writtenlen; + int err; + + D2(printf("jffs2_fo_write page_start_pos %d\n", pos)); + D2(printf("jffs2_fo_write transfer size %d\n", len)); + + err = jffs2_write_inode_range(c, f, &ri, buf, + pos, len, &writtenlen); + if (err) + return -err; + + if (writtenlen != len) + return ENOSPC; + + pos += len; + resid -= len; + } + + // We wrote some data successfully, update the modified and access + // times of the inode, increase its size appropriately, and update + // the file offset and transfer residue. + inode->i_mtime = inode->i_ctime = je32_to_cpu(ri.mtime); + if (pos > inode->i_size) + inode->i_size = pos; + + uio->uio_resid = resid; + fp->f_offset = pos; + + return ENOERR; +} +#endif /* CYGOPT_FS_JFFS2_WRITE */ + +// ------------------------------------------------------------------------- +// jffs2_fo_lseek() +// Seek to a new file position. + +static int jffs2_fo_lseek(struct CYG_FILE_TAG *fp, off_t * apos, int whence) +{ + struct _inode *node = (struct _inode *) fp->f_data; + off_t pos = *apos; + + D2(printf("jffs2_fo_lseek\n")); + + switch (whence) { + case SEEK_SET: + // Pos is already where we want to be. + break; + + case SEEK_CUR: + // Add pos to current offset. + pos += fp->f_offset; + break; + + case SEEK_END: + // Add pos to file size. + pos += node->i_size; + break; + + default: + return EINVAL; + } + + if (pos < 0 ) + return EINVAL; + + // All OK, set fp offset and return new position. + *apos = fp->f_offset = pos; + + return ENOERR; +} + +// ------------------------------------------------------------------------- +// jffs2_fo_ioctl() +// Handle ioctls. Currently none are defined. + +static int jffs2_fo_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD com, + CYG_ADDRWORD data) +{ + // No Ioctls currenly defined. + + D2(printf("jffs2_fo_ioctl\n")); + + return EINVAL; +} + +// ------------------------------------------------------------------------- +// jffs2_fo_fsync(). +// Force the file out to data storage. + +static int jffs2_fo_fsync(struct CYG_FILE_TAG *fp, int mode) +{ + // Data is always permanently where it belongs, nothing to do + // here. + + D2(printf("jffs2_fo_fsync\n")); + + return ENOERR; +} + +// ------------------------------------------------------------------------- +// jffs2_fo_close() +// Close a file. We just decrement the refcnt and let it go away if +// that is all that is keeping it here. + +static int jffs2_fo_close(struct CYG_FILE_TAG *fp) +{ + struct _inode *node = (struct _inode *) fp->f_data; + + D2(printf("jffs2_fo_close\n")); + + jffs2_iput(node); + + fp->f_data = 0; // zero data pointer + + return ENOERR; +} + +// ------------------------------------------------------------------------- +//jffs2_fo_fstat() +// Get file status. + +static int jffs2_fo_fstat(struct CYG_FILE_TAG *fp, struct stat *buf) +{ + struct _inode *node = (struct _inode *) fp->f_data; + + D2(printf("jffs2_fo_fstat\n")); + + // Fill in the status + buf->st_mode = node->i_mode; + buf->st_ino = node->i_ino; + buf->st_dev = 0; + buf->st_nlink = node->i_nlink; + buf->st_uid = node->i_uid; + buf->st_gid = node->i_gid; + buf->st_size = node->i_size; + buf->st_atime = node->i_atime; + buf->st_mtime = node->i_mtime; + buf->st_ctime = node->i_ctime; + + return ENOERR; +} + +// ------------------------------------------------------------------------- +// jffs2_fo_getinfo() +// Get info. Currently only supports fpathconf(). + +static int jffs2_fo_getinfo(struct CYG_FILE_TAG *fp, int key, void *buf, + int len) +{ + struct _inode *node = (struct _inode *) fp->f_data; + int err; + + D2(printf("jffs2_fo_getinfo\n")); + + switch (key) { + case FS_INFO_CONF: + err = jffs2_pathconf(node, (struct cyg_pathconf_info *) buf); + break; + + default: + err = EINVAL; + } + return err; + + return ENOERR; +} + +// ------------------------------------------------------------------------- +// jffs2_fo_setinfo() +// Set info. Nothing supported here. + +static int jffs2_fo_setinfo(struct CYG_FILE_TAG *fp, int key, void *buf, + int len) +{ + // No setinfo key supported at present + + D2(printf("jffs2_fo_setinfo\n")); + + return ENOERR; +} + +//========================================================================== +// Directory operations + +// ------------------------------------------------------------------------- +// jffs2_fo_dirread() +// Read a single directory entry from a file. + +static __inline void filldir(char *nbuf, int nlen, const unsigned char *name, int namlen) +{ + int len = nlen < namlen ? nlen : namlen; + memcpy(nbuf, name, len); + nbuf[len] = '\0'; +} + +static int jffs2_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) +{ + struct _inode *d_inode = (struct _inode *) fp->f_data; + struct dirent *ent = (struct dirent *) uio->uio_iov[0].iov_base; + char *nbuf = ent->d_name; +#ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE + struct _inode *c_ino; +#endif + int nlen = sizeof (ent->d_name) - 1; + off_t len = uio->uio_iov[0].iov_len; + struct jffs2_inode_info *f; + struct jffs2_sb_info *c; + struct _inode *inode = d_inode; + struct jffs2_full_dirent *fd; + unsigned long offset, curofs; + int found = 1; + + if (len < sizeof (struct dirent)) + return EINVAL; + + D1(printk + (KERN_DEBUG "jffs2_readdir() for dir_i #%lu\n", d_inode->i_ino)); + + f = JFFS2_INODE_INFO(inode); + c = JFFS2_SB_INFO(inode->i_sb); + + offset = fp->f_offset; + + if (offset == 0) { + D1(printk + (KERN_DEBUG "Dirent 0: \".\", ino #%lu\n", inode->i_ino)); + filldir(nbuf, nlen, (const unsigned char *) ".", 1); +#ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE + // Flags here are the same as jffs2_mkdir. Make sure + // d_type is the same as st_mode of calling stat. + ent->d_type = + jemode_to_cpu(cpu_to_jemode(S_IRUGO|S_IXUGO|S_IWUSR|S_IFDIR)); +#endif + goto out; + } + if (offset == 1) { + filldir(nbuf, nlen, (const unsigned char *) "..", 2); +#ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE + // Flags here are the same as jffs2_mkdir. Make sure + // d_type is the same as st_mode of calling stat. + ent->d_type = + jemode_to_cpu(cpu_to_jemode(S_IRUGO|S_IXUGO|S_IWUSR|S_IFDIR)); +#endif + goto out; + } + + curofs = 1; + down(&f->sem); + for (fd = f->dents; fd; fd = fd->next) { + + curofs++; + /* First loop: curofs = 2; offset = 2 */ + if (curofs < offset) { + D2(printk + (KERN_DEBUG + "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n", + fd->name, fd->ino, fd->type, curofs, offset)); + continue; + } + if (!fd->ino) { + D2(printk + (KERN_DEBUG "Skipping deletion dirent \"%s\"\n", + fd->name)); + offset++; + continue; + } + D2(printk + (KERN_DEBUG "Dirent %ld: \"%s\", ino #%u, type %d\n", offset, + fd->name, fd->ino, fd->type)); + filldir(nbuf, nlen, fd->name, strlen((char *)fd->name)); +#ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE + c_ino = jffs2_iget(inode->i_sb, fd->ino); + if(IS_ERR(c_ino)) { + D1(printk(KERN_WARNING "get entry inode failed\n")); + // fileio already set it to zero, so not needed here + // ent->d_type = 0; + } + else { + ent->d_type = c_ino->i_mode; + jffs2_iput(c_ino); + } +#endif + goto out_sem; + } + /* Reached the end of the directory */ + found = 0; + out_sem: + up(&f->sem); + out: + fp->f_offset = ++offset; + if (found) { + uio->uio_resid -= sizeof (struct dirent); + } + return ENOERR; +} + +// ------------------------------------------------------------------------- +// jffs2_fo_dirlseek() +// Seek directory to start. + +static int jffs2_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t * pos, int whence) +{ + // Only allow SEEK_SET to zero + + D2(printf("jffs2_fo_dirlseek\n")); + + if (whence != SEEK_SET || *pos != 0) + return EINVAL; + + *pos = fp->f_offset = 0; + + return ENOERR; +} + +//========================================================================== +// +// Called by JFFS2 +// =============== +// +// +//========================================================================== + +unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, + struct jffs2_inode_info *f, + unsigned long offset, + unsigned long *priv) +{ + /* FIXME: This works only with one file system mounted at a time */ + int ret; + + ret = jffs2_read_inode_range(c, f, gc_buffer, + offset & ~(PAGE_CACHE_SIZE-1), PAGE_CACHE_SIZE); + if (ret) + return ERR_PTR(ret); + + return gc_buffer; +} + +void jffs2_gc_release_page(struct jffs2_sb_info *c, + unsigned char *ptr, + unsigned long *priv) +{ + /* Do nothing */ +} + +static struct _inode *new_inode(struct super_block *sb) +{ + + // Only called in write.c jffs2_new_inode + // Always adds itself to inode cache + + struct _inode *inode; + struct _inode *cached_inode; + + inode = malloc(sizeof (struct _inode)); + if (inode == NULL) + return 0; + + D2(printf + ("malloc new_inode %x ####################################\n", + inode)); + + memset(inode, 0, sizeof (struct _inode)); + inode->i_sb = sb; + inode->i_ino = 1; + inode->i_count = 1; + inode->i_nlink = 1; // Let JFFS2 manage the link count + inode->i_size = 0; + + inode->i_cache_next = NULL; // Newest inode, about to be cached + + // Add to the icache + for (cached_inode = sb->s_root; cached_inode != NULL; + cached_inode = cached_inode->i_cache_next) { + if (cached_inode->i_cache_next == NULL) { + cached_inode->i_cache_next = inode; // Current last in cache points to newcomer + inode->i_cache_prev = cached_inode; // Newcomer points back to last + break; + } + } + return inode; +} + +static struct _inode *ilookup(struct super_block *sb, cyg_uint32 ino) +{ + struct _inode *inode = NULL; + + D2(printf("ilookup\n")); + // Check for this inode in the cache + for (inode = sb->s_root; inode != NULL; inode = inode->i_cache_next) { + if (inode->i_ino == ino) { + inode->i_count++; + break; + } + } + return inode; +} + +struct _inode *jffs2_iget(struct super_block *sb, cyg_uint32 ino) +{ + // Called in super.c jffs2_read_super, dir.c jffs2_lookup, + // and gc.c jffs2_garbage_collect_pass + + // Must first check for cached inode + // If this fails let new_inode create one + + struct _inode *inode; + int err; + + D2(printf("jffs2_iget\n")); + + inode = ilookup(sb, ino); + if (inode) + return inode; + + // Not cached, so malloc it + inode = new_inode(sb); + if (inode == NULL) + return ERR_PTR(-ENOMEM); + + inode->i_ino = ino; + + err = jffs2_read_inode(inode); + if (err) { + printf("jffs2_read_inode() failed\n"); + inode->i_nlink = 0; // free _this_ bad inode right now + jffs2_iput(inode); + inode = NULL; + return ERR_PTR(err); + } + return inode; +} + +// ------------------------------------------------------------------------- +// Decrement the reference count on an inode. If this makes the ref count +// zero, then this inode can be freed. + +void jffs2_iput(struct _inode *i) +{ + // Called in jffs2_find + // (and jffs2_open and jffs2_ops_mkdir?) + // super.c jffs2_read_super, + // and gc.c jffs2_garbage_collect_pass + recurse: + if (!i) { + printf("jffs2_iput() called with NULL inode\n"); + // and let it fault... + } + + i->i_count--; + + if (i->i_count < 0) + BUG(); + + if (i->i_count) + return; + + if (!i->i_nlink) { + struct _inode *parent; + + // Remove from the icache linked list and free immediately + if (i->i_cache_prev) + i->i_cache_prev->i_cache_next = i->i_cache_next; + if (i->i_cache_next) + i->i_cache_next->i_cache_prev = i->i_cache_prev; + + parent = i->i_parent; + jffs2_clear_inode(i); + memset(i, 0x5a, sizeof(*i)); + free(i); + + if (parent && parent != i) { + i = parent; + goto recurse; + } + + } else { + // Evict some _other_ inode with i_count zero, leaving + // this latest one in the cache for a while + icache_evict(i->i_sb->s_root, i); + } +} + + +// ------------------------------------------------------------------------- +// EOF jffs2.c + + +static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) +{ + memset(f, 0, sizeof(*f)); + init_MUTEX_LOCKED(&f->sem); +} + +static void jffs2_clear_inode (struct _inode *inode) +{ + /* We can forget about this inode for now - drop all + * the nodelists associated with it, etc. + */ + struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); + struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + + D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode)); + + jffs2_do_clear_inode(c, f); +} + + +/* jffs2_new_inode: allocate a new inode and inocache, add it to the hash, + fill in the raw_inode while you're at it. */ +struct _inode *jffs2_new_inode (struct _inode *dir_i, int mode, struct jffs2_raw_inode *ri) +{ + struct _inode *inode; + struct super_block *sb = dir_i->i_sb; + struct jffs2_sb_info *c; + struct jffs2_inode_info *f; + int ret; + + D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode)); + + c = JFFS2_SB_INFO(sb); + + inode = new_inode(sb); + + if (!inode) + return ERR_PTR(-ENOMEM); + + f = JFFS2_INODE_INFO(inode); + jffs2_init_inode_info(f); + + memset(ri, 0, sizeof(*ri)); + /* Set OS-specific defaults for new inodes */ + ri->uid = ri->gid = cpu_to_je16(0); + ri->mode = cpu_to_jemode(mode); + ret = jffs2_do_new_inode (c, f, mode, ri); + if (ret) { + // forceful evict: f->sem is locked already, and the + // inode is bad. + if (inode->i_cache_prev) + inode->i_cache_prev->i_cache_next = inode->i_cache_next; + if (inode->i_cache_next) + inode->i_cache_next->i_cache_prev = inode->i_cache_prev; + up(&(f->sem)); + jffs2_clear_inode(inode); + memset(inode, 0x6a, sizeof(*inode)); + free(inode); + return ERR_PTR(ret); + } + inode->i_nlink = 1; + inode->i_ino = je32_to_cpu(ri->ino); + inode->i_mode = jemode_to_cpu(ri->mode); + inode->i_gid = je16_to_cpu(ri->gid); + inode->i_uid = je16_to_cpu(ri->uid); + inode->i_atime = inode->i_ctime = inode->i_mtime = cyg_timestamp(); + ri->atime = ri->mtime = ri->ctime = cpu_to_je32(inode->i_mtime); + + inode->i_size = 0; + + return inode; +} + + +static int jffs2_read_inode (struct _inode *inode) +{ + struct jffs2_inode_info *f; + struct jffs2_sb_info *c; + struct jffs2_raw_inode latest_node; + int ret; + + D1(printk(KERN_DEBUG "jffs2_read_inode(): inode->i_ino == %lu\n", inode->i_ino)); + + f = JFFS2_INODE_INFO(inode); + c = JFFS2_SB_INFO(inode->i_sb); + + jffs2_init_inode_info(f); + + ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node); + + if (ret) { + up(&f->sem); + return ret; + } + inode->i_mode = jemode_to_cpu(latest_node.mode); + inode->i_uid = je16_to_cpu(latest_node.uid); + inode->i_gid = je16_to_cpu(latest_node.gid); + inode->i_size = je32_to_cpu(latest_node.isize); + inode->i_atime = je32_to_cpu(latest_node.atime); + inode->i_mtime = je32_to_cpu(latest_node.mtime); + inode->i_ctime = je32_to_cpu(latest_node.ctime); + + inode->i_nlink = f->inocache->nlink; + up(&f->sem); + + D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n")); + return 0; +} + + +void jffs2_gc_release_inode(struct jffs2_sb_info *c, + struct jffs2_inode_info *f) +{ + jffs2_iput(OFNI_EDONI_2SFFJ(f)); +} + +struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, + int inum, int nlink) +{ + struct _inode *inode; + struct jffs2_inode_cache *ic; + if (!nlink) { + /* The inode has zero nlink but its nodes weren't yet marked + obsolete. This has to be because we're still waiting for + the final (close() and) jffs2_iput() to happen. + + There's a possibility that the final jffs2_iput() could have + happened while we were contemplating. In order to ensure + that we don't cause a new read_inode() (which would fail) + for the inode in question, we use ilookup() in this case + instead of jffs2_iget(). + + The nlink can't _become_ zero at this point because we're + holding the alloc_sem, and jffs2_do_unlink() would also + need that while decrementing nlink on any inode. + */ + inode = ilookup(OFNI_BS_2SFFJ(c), inum); + if (!inode) { + D1(printk(KERN_DEBUG "ilookup() failed for ino #%u; inode is probably deleted.\n", + inum)); + + spin_lock(&c->inocache_lock); + ic = jffs2_get_ino_cache(c, inum); + if (!ic) { + D1(printk(KERN_DEBUG "Inode cache for ino #%u is gone.\n", inum)); + spin_unlock(&c->inocache_lock); + return NULL; + } + if (ic->state != INO_STATE_CHECKEDABSENT) { + /* Wait for progress. Don't just loop */ + D1(printk(KERN_DEBUG "Waiting for ino #%u in state %d\n", + ic->ino, ic->state)); + sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); + } else { + spin_unlock(&c->inocache_lock); + } + + return NULL; + } + } else { + /* Inode has links to it still; they're not going away because + jffs2_do_unlink() would need the alloc_sem and we have it. + Just jffs2_iget() it, and if read_inode() is necessary that's OK. + */ + inode = jffs2_iget(OFNI_BS_2SFFJ(c), inum); + if (IS_ERR(inode)) + return (void *)inode; + } + + return JFFS2_INODE_INFO(inode); +} + + + +uint32_t jffs2_from_os_mode(uint32_t osmode) +{ + uint32_t jmode = ((osmode & S_IRUSR)?00400:0) | + ((osmode & S_IWUSR)?00200:0) | + ((osmode & S_IXUSR)?00100:0) | + ((osmode & S_IRGRP)?00040:0) | + ((osmode & S_IWGRP)?00020:0) | + ((osmode & S_IXGRP)?00010:0) | + ((osmode & S_IROTH)?00004:0) | + ((osmode & S_IWOTH)?00002:0) | + ((osmode & S_IXOTH)?00001:0); + + switch (osmode & S_IFMT) { + case S_IFSOCK: + return jmode | 0140000; + case S_IFLNK: + return jmode | 0120000; + case S_IFREG: + return jmode | 0100000; + case S_IFBLK: + return jmode | 0060000; + case S_IFDIR: + return jmode | 0040000; + case S_IFCHR: + return jmode | 0020000; + case S_IFIFO: + return jmode | 0010000; + case S_ISUID: + return jmode | 0004000; + case S_ISGID: + return jmode | 0002000; +#ifdef S_ISVTX + case S_ISVTX: + return jmode | 0001000; +#endif + } + printf("os_to_jffs2_mode() cannot convert 0x%x\n", osmode); + BUG(); + return 0; +} + +uint32_t jffs2_to_os_mode (uint32_t jmode) +{ + uint32_t osmode = ((jmode & 00400)?S_IRUSR:0) | + ((jmode & 00200)?S_IWUSR:0) | + ((jmode & 00100)?S_IXUSR:0) | + ((jmode & 00040)?S_IRGRP:0) | + ((jmode & 00020)?S_IWGRP:0) | + ((jmode & 00010)?S_IXGRP:0) | + ((jmode & 00004)?S_IROTH:0) | + ((jmode & 00002)?S_IWOTH:0) | + ((jmode & 00001)?S_IXOTH:0); + + switch(jmode & 00170000) { + case 0140000: + return osmode | S_IFSOCK; + case 0120000: + return osmode | S_IFLNK; + case 0100000: + return osmode | S_IFREG; + case 0060000: + return osmode | S_IFBLK; + case 0040000: + return osmode | S_IFDIR; + case 0020000: + return osmode | S_IFCHR; + case 0010000: + return osmode | S_IFIFO; + case 0004000: + return osmode | S_ISUID; + case 0002000: + return osmode | S_ISGID; +#ifdef S_ISVTX + case 0001000: + return osmode | S_ISVTX; +#endif + } + printf("jffs2_to_os_mode() cannot convert 0x%x\n", osmode); + BUG(); + return 0; +} diff --git a/cpukit/libfs/src/jffs2/src/malloc-rtems.c b/cpukit/libfs/src/jffs2/src/malloc-rtems.c new file mode 100644 index 0000000000..a06cf5f16d --- /dev/null +++ b/cpukit/libfs/src/jffs2/src/malloc-rtems.c @@ -0,0 +1,163 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2001-2003 Free Software Foundation, Inc. + * + * Created by David Woodhouse + * + * For licensing information, see the file 'LICENCE' in this directory. + * + * $Id: malloc-ecos.c,v 1.4 2003/11/26 15:55:35 dwmw2 Exp $ + * + */ + +#include +#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); +} + +void jffs2_free_full_dirent(struct jffs2_full_dirent *x) +{ + free(x); +} + +struct jffs2_full_dnode *jffs2_alloc_full_dnode(void) +{ + return malloc(sizeof(struct jffs2_full_dnode)); +} + +void jffs2_free_full_dnode(struct jffs2_full_dnode *x) +{ + free(x); +} + +struct jffs2_raw_dirent *jffs2_alloc_raw_dirent(void) +{ + return malloc(sizeof(struct jffs2_raw_dirent)); +} + +void jffs2_free_raw_dirent(struct jffs2_raw_dirent *x) +{ + free(x); +} + +struct jffs2_raw_inode *jffs2_alloc_raw_inode(void) +{ + return malloc(sizeof(struct jffs2_raw_inode)); +} + +void jffs2_free_raw_inode(struct jffs2_raw_inode *x) +{ + free(x); +} + +struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void) +{ + return malloc(sizeof(struct jffs2_tmp_dnode_info)); +} + +void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x) +{ + free(x); +} + +struct jffs2_node_frag *jffs2_alloc_node_frag(void) +{ + return malloc(sizeof(struct jffs2_node_frag)); +} + +void jffs2_free_node_frag(struct jffs2_node_frag *x) +{ + free(x); +} + +#if CYGNUM_FS_JFFS2_RAW_NODE_REF_CACHE_POOL_SIZE == 0 + +int jffs2_create_slab_caches(void) +{ + return 0; +} + +void jffs2_destroy_slab_caches(void) +{ +} + +struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void) +{ + return malloc(sizeof(struct jffs2_raw_node_ref)); +} + +void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x) +{ + free(x); +} + +#else // CYGNUM_FS_JFFS2_RAW_NODE_REF_CACHE_POOL_SIZE == 0 + +static struct jffs2_raw_node_ref + rnr_pool[CYGNUM_FS_JFFS2_RAW_NODE_REF_CACHE_POOL_SIZE] __attribute__ ((aligned (4))), + * first = NULL; +static cyg_drv_mutex_t mutex; + +int jffs2_create_slab_caches(void) +{ + struct jffs2_raw_node_ref * p; + cyg_drv_mutex_init(&mutex); + for ( + p = rnr_pool; + p < rnr_pool + CYGNUM_FS_JFFS2_RAW_NODE_REF_CACHE_POOL_SIZE - 1; + p++ + ) + p->next_phys = p + 1; + rnr_pool[CYGNUM_FS_JFFS2_RAW_NODE_REF_CACHE_POOL_SIZE - 1].next_phys = NULL; + first = &rnr_pool[0]; + return 0; +} + +void jffs2_destroy_slab_caches(void) +{ +} + +struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void) +{ + struct jffs2_raw_node_ref * p; + + cyg_drv_mutex_lock(&mutex); + p = first; + if (p != NULL) + first = p->next_phys; + cyg_drv_mutex_unlock(&mutex); + return p; +} + +void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x) +{ + cyg_drv_mutex_lock(&mutex); + x->next_phys = first; + first = x; + cyg_drv_mutex_unlock(&mutex); +} + +#endif // CYGNUM_FS_JFFS2_RAW_NODE_REF_CACHE_POOL_SIZE == 0 + +struct jffs2_inode_cache *jffs2_alloc_inode_cache(void) +{ + struct jffs2_inode_cache *ret = malloc(sizeof(struct jffs2_inode_cache)); + D1(printk(KERN_DEBUG "Allocated inocache at %p\n", ret)); + return ret; +} + +void jffs2_free_inode_cache(struct jffs2_inode_cache *x) +{ + D1(printk(KERN_DEBUG "Freeing inocache at %p\n", x)); + free(x); +} + diff --git a/cpukit/libfs/src/jffs2/src/os-rtems.h b/cpukit/libfs/src/jffs2/src/os-rtems.h new file mode 100644 index 0000000000..bb4abe70ac --- /dev/null +++ b/cpukit/libfs/src/jffs2/src/os-rtems.h @@ -0,0 +1,226 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2002-2003 Free Software Foundation, Inc. + * + * Created by David Woodhouse + * + * For licensing information, see the file 'LICENCE' in this directory. + * + * $Id: os-ecos.h,v 1.24 2005/02/09 09:23:55 pavlov Exp $ + * + */ + +#ifndef __JFFS2_OS_ECOS_H__ +#define __JFFS2_OS_ECOS_H__ + +#include +#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 + +#define printf diag_printf + +struct _inode; +struct super_block; + +struct iovec { + void *iov_base; + ssize_t iov_len; +}; + +static inline unsigned int full_name_hash(const unsigned char * name, unsigned int len) { + + unsigned hash = 0; + while (len--) { + hash = (hash << 4) | (hash >> 28); + hash ^= *(name++); + } + return hash; +} + +#ifdef CYGOPT_FS_JFFS2_WRITE +#define jffs2_is_readonly(c) (0) +#else +#define jffs2_is_readonly(c) (1) +#endif + +/* NAND flash not currently supported on eCos */ +#define jffs2_can_mark_obsolete(c) (1) + +#define JFFS2_INODE_INFO(i) (&(i)->jffs2_i) +#define OFNI_EDONI_2SFFJ(f) ((struct _inode *) ( ((char *)f) - ((char *)(&((struct _inode *)NULL)->jffs2_i)) ) ) + +#define JFFS2_F_I_SIZE(f) (OFNI_EDONI_2SFFJ(f)->i_size) +#define JFFS2_F_I_MODE(f) (OFNI_EDONI_2SFFJ(f)->i_mode) +#define JFFS2_F_I_UID(f) (OFNI_EDONI_2SFFJ(f)->i_uid) +#define JFFS2_F_I_GID(f) (OFNI_EDONI_2SFFJ(f)->i_gid) +#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime) +#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime) +#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime) + +/* FIXME: eCos doesn't hav a concept of device major/minor numbers */ +#define JFFS2_F_I_RDEV_MIN(f) ((OFNI_EDONI_2SFFJ(f)->i_rdev)&0xff) +#define JFFS2_F_I_RDEV_MAJ(f) ((OFNI_EDONI_2SFFJ(f)->i_rdev)>>8) + +#define get_seconds cyg_timestamp + +struct _inode { + cyg_uint32 i_ino; + + int i_count; + mode_t i_mode; + nlink_t i_nlink; // Could we dispense with this? + uid_t i_uid; + gid_t i_gid; + time_t i_atime; + time_t i_mtime; + time_t i_ctime; +// union { + unsigned short i_rdev; // For devices only + struct _inode * i_parent; // For directories only + off_t i_size; // For files only +// }; + struct super_block * i_sb; + + struct jffs2_inode_info jffs2_i; + + struct _inode * i_cache_prev; // We need doubly-linked? + struct _inode * i_cache_next; +}; + +#define JFFS2_SB_INFO(sb) (&(sb)->jffs2_sb) +#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->jffs2_sb)) ) ) + +struct super_block { + struct jffs2_sb_info jffs2_sb; + struct _inode * s_root; + unsigned long s_mount_count; + cyg_io_handle_t s_dev; + +#ifdef CYGOPT_FS_JFFS2_GCTHREAD + cyg_mutex_t s_lock; // Lock the inode cache + cyg_flag_t s_gc_thread_flags; // Communication with the gcthread + cyg_handle_t s_gc_thread_handle; + cyg_thread s_gc_thread; +#if (CYGNUM_JFFS2_GC_THREAD_STACK_SIZE >= CYGNUM_HAL_STACK_SIZE_MINIMUM) + char s_gc_thread_stack[CYGNUM_JFFS2_GC_THREAD_STACK_SIZE]; +#else + char s_gc_thread_stack[CYGNUM_HAL_STACK_SIZE_MINIMUM]; +#endif + cyg_mtab_entry *mte; +#endif +}; + +#define sleep_on_spinunlock(wq, sl) spin_unlock(sl) +#define EBADFD 32767 + +/* background.c */ +#ifdef CYGOPT_FS_JFFS2_GCTHREAD +void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c); +void jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c); +void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c); +#else +static inline void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c) +{ + /* We don't have a GC thread in eCos (yet) */ +} +#endif + +/* fs-ecos.c */ +struct _inode *jffs2_new_inode (struct _inode *dir_i, int mode, struct jffs2_raw_inode *ri); +struct _inode *jffs2_iget(struct super_block *sb, cyg_uint32 ino); +void jffs2_iput(struct _inode * i); +void jffs2_gc_release_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f); +struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, int inum, int nlink); +unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, struct jffs2_inode_info *f, + unsigned long offset, unsigned long *priv); +void jffs2_gc_release_page(struct jffs2_sb_info *c, unsigned char *pg, unsigned long *priv); + +/* Avoid polluting eCos namespace with names not starting in jffs2_ */ +#define os_to_jffs2_mode(x) jffs2_from_os_mode(x) +uint32_t jffs2_from_os_mode(uint32_t osmode); +uint32_t jffs2_to_os_mode (uint32_t jmode); + + +/* flashio.c */ +cyg_bool jffs2_flash_read(struct jffs2_sb_info *c, cyg_uint32 read_buffer_offset, + const size_t size, size_t * return_size, unsigned char * write_buffer); +cyg_bool jffs2_flash_write(struct jffs2_sb_info *c, cyg_uint32 write_buffer_offset, + const size_t size, size_t * return_size, unsigned char * read_buffer); +int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct iovec *vecs, + unsigned long count, loff_t to, size_t *retlen); +cyg_bool jffs2_flash_erase(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); + +// dir-ecos.c +struct _inode *jffs2_lookup(struct _inode *dir_i, const unsigned char *name, int namelen); +int jffs2_create(struct _inode *dir_i, const unsigned char *d_name, int mode, struct _inode **new_i); +int jffs2_mkdir (struct _inode *dir_i, const unsigned char *d_name, int mode); +int jffs2_link (struct _inode *old_d_inode, struct _inode *dir_i, const unsigned char *d_name); +int jffs2_unlink(struct _inode *dir_i, struct _inode *d_inode, const unsigned char *d_name); +int jffs2_rmdir (struct _inode *dir_i, struct _inode *d_inode, const unsigned char *d_name); +int jffs2_rename (struct _inode *old_dir_i, struct _inode *d_inode, const unsigned char *old_d_name, + struct _inode *new_dir_i, const unsigned char *new_d_name); + +/* erase.c */ +static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c) +{ } + +#ifndef CONFIG_JFFS2_FS_WRITEBUFFER +#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) ) +#define jffs2_can_mark_obsolete(c) (1) +#define jffs2_cleanmarker_oob(c) (0) +#define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) + +#define jffs2_flush_wbuf_pad(c) (c=c) +#define jffs2_flush_wbuf_gc(c, i) ({ (void)(c), (void) i, 0; }) +#define jffs2_nand_read_failcnt(c,jeb) do { ; } while(0) +#define jffs2_write_nand_badblock(c,jeb,p) (0) +#define jffs2_flash_setup(c) (0) +#define jffs2_nand_flash_cleanup(c) do {} while(0) +#define jffs2_wbuf_dirty(c) (0) +#define jffs2_flash_writev(a,b,c,d,e,f) jffs2_flash_direct_writev(a,b,c,d,e) +#define jffs2_wbuf_timeout NULL +#define jffs2_wbuf_process NULL +#define jffs2_nor_ecc(c) (0) +#else +#error no nand yet +#endif + +#ifndef BUG_ON +#define BUG_ON(x) do { if (unlikely(x)) BUG(); } while(0) +#endif + +#define __init + +#endif /* __JFFS2_OS_ECOS_H__ */ -- cgit v1.2.3