diff gsm-fw/services/ffs/core.h @ 209:6f4a12b4582f

gsm-fw FFS: starting to integrate C code
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Thu, 26 Dec 2013 03:59:59 +0000
parents
children 847e2585a0f2
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gsm-fw/services/ffs/core.h	Thu Dec 26 03:59:59 2013 +0000
@@ -0,0 +1,579 @@
+/******************************************************************************
+ * Flash File System (ffs)
+ * Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com
+ *
+ * ffs core functions
+ *
+ * $Id: core.h 1.80.1.15.1.36 Thu, 08 Jan 2004 15:05:23 +0100 tsj $
+ *
+ ******************************************************************************/
+
+#if (TARGET == 1)
+#include "../../riviera/rv/rv_defined_swe.h"
+#endif
+
+/******************************************************************************
+ * Compile option switches
+ ******************************************************************************/
+
+// FFS compiled with extra test functionality
+#define FFS_TEST 1
+
+// Default max number of simultaneous open files
+#ifdef RVM_MSFE_SWE
+#define FFS_FD_MAX 20
+#else
+#define FFS_FD_MAX 4
+#endif
+
+#define FFS_RECLAIM_NEW 1
+
+/******************************************************************************
+ * Compile constants
+ ******************************************************************************/
+
+// FFS API version (in four-digit BCD format)
+#define FFS_API_VERSION ((uint16) 0x0642)
+
+// FFS_DRV_VERSION is in drv.h
+
+// TMFFS protocol version is in tmffs.h
+
+// Magic for determining (formatted) file system version. First two digits
+// represent major version, bottom two digits represent minor version. An
+// ffs code compiled for one major version X is compatible with any other
+// format version with major = X. Minor version is incremented when adding
+// new features that does not break compatibility.
+#define FFS_FORMAT_VERSION (0x0210)
+#define BLOCK_MAGIC_LOW    ('f'<<8|'F') // "Ffs#"
+#define BLOCK_MAGIC_HIGH   ('#'<<8|'s')
+#define BLOCK_MAGIC        ((BLOCK_MAGIC_HIGH << 8)|(BLOCK_MAGIC_LOW))
+
+// Absolute maximum number of inodes allowed
+#define FFS_INODES_MAX 2048
+
+// Default maximum number of inodes allowed
+#define FFS_INODES_MAX_DEFAULT 1024
+
+// Default number of path components (limit due to recursiveness of
+// inodes_reclaim())
+#define FFS_PATH_DEPTH_MAX 6
+
+// Maximum number of blocks (flash sectors) in a ffs system. FFS_BLOCKS_MAX
+// must be >= the number of blocks in the largest flash device memory
+// map. It is used to allocate the number of entries in the static bstat
+// array.
+#define FFS_BLOCKS_MAX 128
+// Default size of journal file (represented as 256'ths of the blocksize)
+#define FFS_JOURNAL_SIZE_IN256THS 16  // one 16'ths of the block size. 
+
+// Without the min size will the maximum of files (fs.blocks_files_max) in
+// one block be 32 files if the blocksize is 8kB!
+#define FFS_JOURNAL_SIZE_MIN 1024
+
+#define FFS_JOURNAL_NAME ".journal"
+
+// Default max size of file name (excluding null terminator)
+#define FFS_FILENAME_MAX 20
+
+// Maximum distance in age between youngest and oldest blocks
+#define FFS_DAGE_MAX 256
+#define FFS_DAGE_GAIN_MIN (FFS_DAGE_MAX / 4)
+#define FFS_DAGE_EARLY_WIDTH 64
+
+// Offset on file descriptors 
+#define FFS_FD_OFFSET '1'
+
+// Macros to set flags and test bits in flash memory words (negative logic)
+#define BIT_SET(value, bits) ((value) & (~bits))
+#define IS_BIT_SET(value, bits) (~(value) & (bits))
+
+// Number of free inodes and journal entries to keep for "emergencies"
+#define FFS_INODES_MARGIN  4
+#define FFS_JOURNAL_MARGIN 4
+
+
+/******************************************************************************
+ * Macros used in both drv.c and core.c
+ ******************************************************************************/
+
+// Convert a offset_t value to a block index
+#define offset2block(offset) (((uint32) offset) >> dev.binfo[0].size_ld)
+ 
+// Convert between offset and address
+#define offset2addr(offset) (dev.base + (offset))
+
+// Size of a block
+#define blocksize(block) (1 << dev.binfo[block].size_ld)
+
+// Test if flag is set
+#define is_open_option(options, flags) ((options & flags) == flags)
+
+// Amount of reserved space. 
+#define	RESERVED_LOW  2 * fs.journal_size 
+#define RESERVED_NONE 0
+
+// We have to saturate because a recently reclaimed inodes block could
+// theoretically possess a high age
+#define saturate_dage(dage) (dage > (2*FFS_DAGE_MAX) ? (2*FFS_DAGE_MAX) : dage) 
+
+/******************************************************************************
+ * External declarations
+ ******************************************************************************/
+
+extern struct fs_s fs;
+extern struct block_stat_s bstat[FFS_BLOCKS_MAX];
+
+extern struct ffs_stats_s stats;
+
+extern const struct block_info_s *binfo;
+
+
+/******************************************************************************
+ * Block Types
+ ******************************************************************************/
+
+// Block age, ie. number of times block has been erased
+typedef uint16 age_t;
+
+// Maximum age a block can have
+#define BLOCK_AGE_MAX 0xFFFF
+
+// ffs block status flags. These are stored in the first 2 bytes of
+// the ffs block in the flash sector.
+enum BLOCK_FLAGS {
+    BF_LOST        =  0x80,  // block is lost and will soon be erased
+    BF_FREE        =  0x40,  // free (preformatted and with block magic)
+    BF_DATA        =  0x02,  // data
+    BF_CLEANING    =  0x01,  // block is being cleaned
+    BF_INODES      =  0x10,  // block contains inodes
+    BF_COPYING     =  0x04   // block is a coming inodes block
+};
+enum BLOCK_STATES {
+    BF_IS_EMPTY       = ~(0),
+    BF_IS_FREE        = ~(BF_FREE),
+    BF_IS_DATA        = ~(BF_FREE | BF_DATA),
+    BF_IS_CLEANING    = ~(BF_FREE | BF_DATA | BF_CLEANING),
+    BF_IS_COPYING     = ~(BF_FREE | BF_COPYING),
+    BF_IS_INODES      = ~(BF_FREE | BF_COPYING | BF_INODES),
+    BF_IS_INODES_LOST = ~(BF_FREE | BF_COPYING | BF_INODES | BF_LOST)
+};
+
+// Header of each FFS block
+struct block_header_s {
+    uint16 magic_low;  // 32-bit magic number
+    uint16 magic_high;
+    uint16 version;    // FFS_FORMAT_VERSION used for formatting
+    age_t  age;        // number of times this block has been erased
+    uint16 flags;      // status flags of this block (BLOCK_FLAGS)
+    uint16 reserved0;
+    uint16 reserved1;
+    uint16 reserved2;
+};
+
+// Important the below define MUST fit to the size of the header that is written
+#define BHEADER_SIZE sizeof(struct block_header_s)
+
+#define OLD_BLOCK_MAGIC_LOW    ('S'<<8|'F') // "FS"
+#define OLD_FFS_FORMAT_VERSION (0x0100)     // 1.00 (in four-digit BCD format)
+
+// Old header of each FFS block. From old/previous FFS format version
+struct block_header_old_s {
+    uint8  flags;
+    uint8  copied;
+    uint8  magicflags;
+    uint8  reserved0;
+    uint16 magic_low;
+    uint16 magic_high;
+    uint16 reserved1;
+    uint16 reserved2;
+};
+
+// Block status. This struct holds the status of one ffs block This relation
+// is always valid: <block size> = <used> + <lost> + <free>. The block size
+// is obtained from the corresponding block_info structure. <used> and
+// <lost> variables always holds a value which is a multiple of
+// FFS_GRANULARITY.  For inodes, <used> is number of inodes in active use,
+// <lost> is number of deleted/lost inodes, <numfiles> is the index of the
+// first free inode.
+struct block_stat_s {
+    blocksize_t used;    // number of used bytes
+    blocksize_t lost;    // number of lost bytes
+    uint16      flags;   // flash block flags (first 16 bits of each block)
+    uint16      objects; // number of valid objects
+};
+
+
+/******************************************************************************
+ * Object Types
+ ******************************************************************************/
+
+// This enum MUST be in sync with the one in ffs.h.
+enum OBJECT_TYPE_E {
+    // remaining filetypes are in ffs.h
+    OT_ERASED  = 0,
+    OT_NULL    = 7,
+    OT_MASK    = 7,
+    OT_MAX     = 4
+};
+
+// This enum MUST be in sync with the one in ffs.h.
+enum OBJECT_FLAGS_E {
+    // remaining object flags are in ffs.h
+    OF_UNDEF0   = 1<<5,
+    OF_UNDEF1   = 1<<6,
+    OF_EXACT    = 1<<7, // used by control()/update_commit() interaction. This
+                        // is *not* an object flag!
+    OF_ALL      = OF_READONLY, // all flags allowed to be changed by user
+    OF_MASK     = 0xF0
+};
+
+struct inode_s {
+    uint16      size;
+    uint8       reserved;  // size extension?
+    objflags_t  flags;
+    iref_t      child;     // link to first inode in dir (this inode is a dir)
+    iref_t      sibling;   // link to next inode in same directory
+    location_t  location;  // location of object
+    uint16      sequence;  // 
+    uint16      updates;   // times this object has been updated
+};
+
+struct file_descriptor_s {      
+    char    *buf;          // Write buffer 
+    iref_t  seghead;       // First chunk. Contain file name and optional data 
+    iref_t  wch;           // Inode of work chunk (if chunk is read to buf)
+    int     fp;            // File pointer
+    int     wfp;           // Work file pointer always points to start of wch
+    int     size;          // Size of object (all chunks and data from buf)
+    int8    options;       // Open options
+    int     dirty;         // Indicate if buf contain valid data or not
+};
+
+
+/******************************************************************************
+ * Journal types and global fs structure
+ ******************************************************************************/
+
+enum JOURNAL_FLAGS {
+    JOURNAL_WRITING = 0x02,  // journal is being written to journal file
+    JOURNAL_READY   = 0x04,  // journal has been written to journal file
+    JOURNAL_DONE    = 0x08   // journal has been written to ffs
+};
+
+enum JOURNAL_STATES {
+    JOURNAL_IS_EMPTY   = ~(0),
+    JOURNAL_IS_WRITING = ~(JOURNAL_WRITING),
+    JOURNAL_IS_READY   = ~(JOURNAL_WRITING | JOURNAL_READY),
+    JOURNAL_IS_DONE    = ~(JOURNAL_WRITING | JOURNAL_READY | JOURNAL_DONE)
+};
+
+// Journal entry structure. Note that the state byte *MUST* be the first
+// byte of the structure!
+struct journal_s {
+    uint8      state;    // state of journal entry.
+    objflags_t flags;    // type of object
+    iref_t     i;        // iref of object
+    iref_t     diri;     // iref of object that is this object's parent/sibling
+    iref_t     oldi;     // iref of object being replaced (only for updates)
+    location_t location; // object's location
+    uint16     size;     // object's size
+    iref_t     repli;    // inode which is replaced
+};
+
+// Main ffs info struct (initialised by ffs_initialize())
+struct fs_s {
+    struct inode_s *inodes_addr; // base address of inodes
+    iref_t    root;            // iref of root directory
+    bref_t    inodes;          // index into bstat containing inode block
+    bref_t    newinodes;       // index into bstat containing new inode block
+    bref_t    blocks_free_min; // Number of spare blocks (0 or 1)
+    int       filesize_max;    // Max size of object data
+    int       reserved_space;  // Byte size of space reserved for journal relocation
+    iref_t    inodes_max;      // Max number of inodes possible
+    iref_t    inodes_high;     // number of inodes triggering an inodes_reclaim()
+    iref_t    objects_max;     // Max number of objects (valid inodes) allowed
+    age_t     age_max;         // Max block age found by blocks_fsck()
+    iref_t    block_files_max; // max number of files in a block
+    iref_t    block_files_reserved;    // Reserved for journals
+    uint16    format;          // FFS version as formatted in flash blocks
+    uint16    sequence;        // Object sequence number (for debug only)
+    effs_t    initerror;       // ffs_initialize() return code
+    uint8     lost_threshold;  // Threshold percentage for data block reclaim
+    uint8     flags;           // Global FFS options/flags
+    uint8     filename_max;    // Max length of a filename
+    uint8     path_depth_max;  // Max path componenents allowed
+    uint8     numfds;          // Mumber of available file descriptors
+    uint8     testflags;
+    int8      journal_depth;   // Current journal nesting depth (0 or 1)
+    iref_t    ijournal;        // iref of journal file
+    uint32    journal_size;    // Byte size of journal file
+    uint32    journal_pos;     // Byte offset to first free entry in journal file
+    struct journal_s journal;
+    uint8     fd_max;          // number of max available file descriptors
+    int       fd_buf_size;     // size of stream buffer
+    struct file_descriptor_s fd[FFS_FD_MAX];
+    struct journal_s ojournal; // "Old" journal
+    int       link_child;      // Link child in journal or not
+    iref_t    i_backup;        // Used by ffs_file_write()
+    int       chunk_size_max;  // Max size of one chunk
+    int       chunk_size_min;  // Min size of one chunk 
+    uint32    debug[4];
+};
+
+// This is the layout of the FFS performance statistics file. The file is
+// created with the name ".statistics" in the root directory at format. It
+// is updated after each data and inodes reclaim (after writing the file
+// that provoked the reclaim). The file is only updated if it exists, so if
+// the user does not want the file, she can erase it after the initial
+// format. FIXME: The use of the .statistics file is not yet implemented
+struct ffs_stats_s {
+    uint32 data_allocated;   // implemented
+
+    struct {                 // Not yet implemented
+        uint32 created;
+        uint32 updated;
+        uint32 read;
+    } files;
+    struct {                 // Not yet implemented
+        uint32 written[2];
+        uint32 read[2];
+    } bytes;
+    struct {
+        uint32 most_lost;    // Block candidate
+        uint32 most_unused;  // Block candidate
+        uint32 youngest;     // Block candidate
+        uint32 valid[2];     // Amount of valid reclaimed data 
+        uint32 lost[2];      // Amount of lost reclaimed data 
+    } drec;
+    struct { 
+        uint32 num;          // Number of inode reclaims
+        uint32 valid;        // Number of valid reclaimed inodes
+        uint32 lost;         // Number of lost reclaimed inodes
+    } irec;
+};
+extern struct ffs_stats_s stats;
+
+
+/******************************************************************************
+ * Miscellaneous types
+ ******************************************************************************/
+
+// only used with (FFS_TEST == 1)
+enum TEST_RECOVERY {
+    JOURNAL_TEST_BASE       = 0x10,
+    JOURNAL_TEST_EMPTY,
+    JOURNAL_TEST_WRITING,
+    JOURNAL_TEST_READY,
+    JOURNAL_TEST_COMMITTING,
+    JOURNAL_TEST_COMMITTED,
+    JOURNAL_TEST_DONE,
+    BLOCK_COMMIT_BASE       = 0x20,
+    BLOCK_COMMIT_BEFORE,
+    BLOCK_COMMIT_NO_VALID,
+    BLOCK_COMMIT_OLD_FREE,
+    BLOCK_COMMIT_AFTER,
+    BLOCK_RECLAIM_BASE      = 0x40,
+    BLOCK_RECLAIM_ALLOC,
+    BLOCK_RECLAIM_CLEANING,
+    BLOCK_RECLAIM_NO_CLEAN,
+    BLOCK_RECOVER_OBJECTS
+};
+
+enum FLASH_DATA {
+    FLASH_NULL8  = 0xFF,
+    FLASH_NULL16 = 0xFFFF,
+    FLASH_NULL32 = 0xFFFFFFFFL,
+    IREF_NULL    = FLASH_NULL16
+};
+
+
+// This enum MUST be in sync with the one in ffs.h.
+enum OBJECT_CONTROL {
+    // remaining object control codes are in ffs.h
+    OC_FS_FLAGS       =  80,
+    OC_TRACE_INIT     =  82,
+    OC_DEV_MANUFACT   =  88,
+    OC_DEV_DEVICE     =  89,
+
+    OC_DEBUG_FIRST    = 120,
+    OC_DEBUG_0        = 120,
+    OC_DEBUG_1        = 121,
+    OC_DEBUG_2        = 122,
+    OC_DEBUG_3        = 123,
+    OC_DEBUG_LAST     = 123,
+
+    OC_FS_TESTFLAGS   = 127
+};
+
+enum FS_FLAGS {
+    FS_DIR_DATA   = 0x01   // allow directory objects to contain data.
+};
+
+enum RECLAIM_CANDIDATE {
+    MOST_LOST,
+    MOST_UNUSED,
+    YOUNGEST
+};
+
+/******************************************************************************
+ * Macros
+ ******************************************************************************/
+
+// Convert between location and offset
+#define location2offset(location) ((location) << dev.atomlog2)
+#define offset2location(offset) (((uint32) offset) >> dev.atomlog2)
+
+// test if object is of a specific type
+#define is_object(objp, type) (((objp)->flags & OT_MASK) == (type))
+
+// test if object is valid (directory, file or symlink)
+#define is_object_valid(ip) ((ip->flags & OT_MASK) <= OT_MAX && (ip->flags & OT_MASK) != OT_ERASED)
+
+// test if block is in a specific state
+#define is_block(block, state) (bstat[block].flags == (uint16) (state))
+
+// test if block has certain flags set
+#define is_block_flag(block, bits) (IS_BIT_SET(bstat[block].flags, (bits)))
+
+// convert an object's data address to the address of the object's name
+#define addr2name(addr) (addr)
+
+// Convert a size to an aligned size
+#define atomalign(size) (((size) + dev.atomsize-1) & ~dev.atomnotmask)
+#define wordalign(size) (((size) + 3) & ~3)
+#define halfwordalign(size) (((size) + 1) & ~1)
+
+#define inode_addr(i)   (fs.inodes_addr + i)
+
+#define JOURNAL_POS_INITIAL (wordalign(2 + sizeof(FFS_JOURNAL_NAME) + 1))
+
+
+/******************************************************************************
+ * Function prototypes
+ ******************************************************************************/
+
+// Helper functions
+
+effs_t is_filename(const char *s);
+int ffs_strlen(const char *s);
+int ffs_strcmp(const char *s, const char *p);
+char *addr2data(const char *addr, const struct inode_s *ip);
+
+int object_datasize(iref_t i);
+iref_t is_readonly(iref_t i, const char *name);
+iref_t dir_traverse(iref_t i, iref_t *entries);
+
+bref_t block_alloc(bref_t n, uint16 flags);
+bref_t block_alloc_try(bref_t *n);
+void block_flags_write(uint8 block, uint8 flags);
+
+offset_t data_alloc(int size);
+offset_t data_alloc_try(int size);
+offset_t data_reserved_alloc(int size);
+
+iref_t inode_alloc(void);
+
+effs_t is_fd_valid(fd_t fdi);
+effs_t is_offset_in_buf(int offset, fd_t fdi);
+
+iref_t chunk_alloc(int realsize, int is_journal, offset_t *offset);  
+
+iref_t inode_alloc_try(void);
+fd_t get_fdi(iref_t i);
+
+offset_t data_prealloc(int realsize);
+
+// Functions used by API
+
+effs_t object_update(iref_t oldi);
+iref_t object_create(const char *name, const char *buf, int size,
+                         iref_t dir);
+int file_read(const char *name, void *addr, int size);
+int stream_read(fd_t fdi, void *src, int size);
+int object_read(const char *name, char *buf, int size, int linkflag);
+
+iref_t object_stat(const char *name, struct xstat_s *stat,
+                       int linkflag, int fdi, int extended);
+effs_t object_remove(iref_t i);
+iref_t object_rename(iref_t oldi, const char *newname, iref_t newdir);
+effs_t object_control(iref_t i, int8 action, int value);
+int object_truncate(const char *pathname, fd_t fdi, offset_t length);
+iref_t object_lookup(const char *path, char **leaf, iref_t *dir);
+iref_t object_lookup_once(const char *path, char **leaf, iref_t *dir);
+iref_t dir_open(const char *name);
+iref_t dir_next (iref_t dir, iref_t i, char *name, int8 size);
+
+
+// Journalling
+
+void journal_begin(iref_t oldi);
+void journal_end(uint8 type);
+void journal_commit(uint8 type);
+int journal_push(void);
+int journal_pop(void);
+iref_t journal_create(iref_t oldi);
+effs_t journal_init(iref_t i);
+
+
+// Format, Init and Reclaim
+
+void block_preformat(bref_t b, age_t age);
+effs_t fs_preformat(void);
+effs_t is_formattable(int8 flag);
+effs_t fs_format(const char *fsname_and_options);
+
+effs_t ffs_initialize(void);
+void fs_params_init(const char *p);
+blocksize_t block_used(bref_t b);
+
+effs_t ffs_begin(void);
+int ffs_end(int error);
+
+int block_reclaim(bref_t b);
+int blocks_reclaim(void);
+void block_commit(void);
+
+iref_t data_reclaim(int space);
+int data_reclaim_try(int space);
+iref_t data_block_reclaim(bref_t b, int reclaim_candidate);
+iref_t object_relocate(iref_t oldi);
+iref_t block_clean(bref_t b);
+
+void block_free(bref_t block);
+
+void inodes_set(iref_t i);
+effs_t inodes_reclaim(void);
+
+int reclaim(void);
+
+// Internally used functions
+
+effs_t file_read_int(const char *path, void *src, int size);
+effs_t file_update(const char *path, void *src, int size);
+
+int statistics_file_create(void);
+int statistics_write(void);
+void statistics_init(void);
+void statistics_update_drec(int valid, int lost, int candidate);
+void statistics_update_irec(int valid, int lost);
+
+// Chunk Operations
+iref_t segment_create(const char *buf, int size, iref_t dir);
+int segment_datasize(const struct inode_s *ip);
+int segment_read(iref_t i, char *buf, int size, int offset);
+iref_t segment_next(iref_t i);
+iref_t segment_traverse(iref_t i, iref_t *entries);
+int segfile_seek(iref_t in_i, int in_pos, 
+                     iref_t *out_i, int *out_pos_i);
+iref_t chunk_traverse(iref_t i);
+effs_t datasync(fd_t fdi);
+// debug/test functions
+
+void tr_bstat(void);
+void tr_fd(fd_t fdi);
+
+// These prototypes really belong in ffs.h but as they have not been
+// implemented, we will not show these prototypes to application
+// programmers.
+effs_t fcntl(fd_t fd, int8 action, uint32 *param);