FreeCalypso > hg > freecalypso-sw
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);