www.pudn.com > drivers.rar > core.h
/******************************************************************************
* 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 $
*
******************************************************************************/
#ifndef _CORE_H_
#define _CORE_H_
#ifndef TARGET
#include "ffs.cfg"
#endif
#if (TARGET == 1)
#include "rv/rv_defined_swe.h"
#else
#include "ffs/board/tffs.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 10
#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 (0x0300)
#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.
#if (LOCOSTO_LITE)
#define FFS_BLOCKS_MAX 32
#else
#define FFS_BLOCKS_MAX 128
#endif // LOCOSTO_LITE
// 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'
// Number of free inodes and journal entries to keep for "emergencies"
#define FFS_INODES_MARGIN 10
#define FFS_JOURNAL_MARGIN 10
#define FFS_REPLACEMENT_INODES_MAX 5
/******************************************************************************
* 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)
// 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))
/******************************************************************************
* 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 {
// Shared
BF_WRITING = 0x0003, //
BF_FREE = 0x000C, // free (preformatted and with block magic)
BF_LOST = 0x3000, // block is lost and will soon be erased
// Data
BF_DATA = 0x0030, // data
BF_CLEANING = 0x0C00, // block is being cleaned
// Inode
BF_INODES = 0x0300, // block contains inodes
BF_COPYING = 0x0C00 // block is a coming inodes block
};
enum BLOCK_STATES {
BF_IS_EMPTY = ~(0),
BF_IS_WRITING = ~(BF_WRITING),
BF_IS_FREE = ~(BF_FREE | BF_WRITING),
BF_IS_DATA = ~(BF_FREE | BF_WRITING | BF_DATA),
BF_IS_CLEANING = ~(BF_FREE | BF_WRITING | BF_DATA | BF_CLEANING),
BF_IS_DATA_LOST = ~(BF_FREE | BF_WRITING | BF_DATA | BF_CLEANING | BF_LOST),
BF_IS_COPYING = ~(BF_FREE | BF_WRITING | BF_COPYING),
BF_IS_INODES = ~(BF_FREE | BF_WRITING | BF_COPYING | BF_INODES),
BF_IS_INODES_LOST = ~(BF_FREE | BF_WRITING | 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)
// Block status. This struct holds the status of one ffs block This relation
// is always valid: = + + . The block size
// is obtained from the corresponding block_info structure. and
// variables always holds a value which is a multiple of
// FFS_GRANULARITY. For inodes, is number of inodes in active use,
// is number of deleted/lost inodes, 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 {
OTE_FILE = 0x0E,
OTE_SEGMENT = 0x0C,
OTE_DIR = 0x0A,
OTE_LINK = 0x06,
// remaining filetypes are in ffs.h
OT_ERASED = 0x3F,
OT_ERASED_MSb = 0x80, // Not a real flag
OT_VALID = 0xCF,
OT_VALID_MSb = 0x20, // Not a real flag
OT_REP = 0x03,
OT_MASK = 0x0E,
OT_MAX = 4
};
// This enum MUST be in sync with the one in ffs.h.
enum OBJECT_FLAGS_E {
OFE_READONLY = 0x1,
// remaining object flags are in ffs.h
OF_ALL = OFE_READONLY, // all flags allowed to be changed by user
OF_MASK = 0xF1
};
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
#if (FFS_SEEK_OPT == 1)
/* optimization on ffs_seek & ffs_read */
iref_t rch; // Inode of read chunk
int roffset; // offset in read chunk
#endif
#if (FFS_READ_CACHE_ENBALE == 1)
/* Includes a simpler read buffering */
iref_t cache_i;
char *cache_read_buf;
int cache_read_buf_size;
#endif
};
/******************************************************************************
* Journal types and global fs structure
******************************************************************************/
enum JOURNAL_FLAGS {
JOURNAL_WRITING = 0x03, // journal is being written to journal file
JOURNAL_READY = 0x0C, // journal has been written to journal file
JOURNAL_DONE = 0x30 // 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.
uint8 align; // Dummy
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)
};
// RAM journal struct. Not saved in the flash journal file.
struct journal_ram_s {
objflags_t flags; // type of object
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
iref_t repi_table[FFS_REPLACEMENT_INODES_MAX]; // Table of replacement inodes
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 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;
struct journal_ram_s journal_ram;
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
struct journal_ram_s ojournal_ram; // "Old" journal
int link_child; // Link child in journal or not
iref_t i_backup; // Used by ffs_file_write()
uint8 is_reclaim_running; // Flag used to avoid reclaim loop
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 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 valid (directory, file or symlink)
#define is_object_valid(ip) (((ip->flags & OT_ERASED_MSb) != 0) && ((ip->flags & OT_VALID_MSb) == 0))
#define is_object_erased(ip) ((ip->flags & OT_ERASED_MSb)== 0)
// test if object is of a specific type (and valid)
#define is_object(ip, type) (is_object_valid(ip) && ((ip->flags & OT_MASK) == ((type) & OT_MASK)))
// 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))
#define get_child(ip) (ip->child != 0 ? ip->child : lookup_child(ip))
#define get_sibling(ip) (ip->sibling != 0 ? ip->sibling : lookup_sibling(ip))
/******************************************************************************
* Types used for power-fail framework
******************************************************************************/
enum POWERFAIL_MODE {
PFM_NOINIT = 0x001, // Skip initialization after powerfail
PFM_RANDOM = 0x002, // Any write can trigger a powerfail
PFM_NEXTINODE = 0x004, // Domain, use inode addr as base addr
PFM_BLOCKHEADER = 0x008, // Domain, use block header addr as base addr
PFM_JOURNAL = 0x010,
PFM_DIRI = 0x020,
PFM_OLDI = 0x040,
PFM_CHUNK = 0x080,
PFM_ERASE = 0x100,
PFM_NEXTERASE = 0x200
};
// All inode releated powerfail modes
#define PFM_INODES (PFM_NEXTINODE | PFM_DIRI | PFM_OLDI)
#define PFM_JOURNALING (PFM_JOURNAL | PFM_INODES)
#if (TARGET == 0)
void powerfail_write(volatile uint16 *addr, uint16 value);
void powerfail_erase(uint8 block);
void powerfail_domain_begin(int domain);
void powerfail_domain_end(void);
void powerfail_set_addr(int addr);
#define POWERFAIL_DOMAIN_BEGIN(domain) powerfail_domain_begin(domain)
#define POWERFAIL_DOMAIN_END() powerfail_domain_end()
#define POWERFAIL_SET_ADDR(addr) powerfail_set_addr(addr)
#define POWERFAIL_BOUNDARY(where) powerfail.boundary = where
#define POWERFAIL_WRITE(addr, value) powerfail_write(addr, value)
#define POWERFAIL_ERASE(block) powerfail_erase(block)
#define POWERFAIL_ENABLED (powerfail.enable > 0)
#else
#define POWERFAIL_DOMAIN_BEGIN(domain)
#define POWERFAIL_DOMAIN_END()
#define POWERFAIL_SET_ADDR(addr)
#define POWERFAIL_BOUNDARY(where)
#define POWERFAIL_WRITE(addr, value)
#define POWERFAIL_ERASE(block)
#define POWERFAIL_ENABLED (0)
#endif
/******************************************************************************
* 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, uint16 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);
iref_t get_repi(iref_t i);
iref_t lookup_child(struct inode_s *ip);
iref_t lookup_sibling(struct inode_s *ip);
// 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);
// Replacementinode
void validate_replacementinode(struct journal_s *addr);
void create_replacementinode(struct journal_s *old_addr);
// 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(void);
int data_reclaim_try(void);
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);
void ffs_panic(int error);
// 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);
#if (FFS_READ_CACHE_ENBALE == 1)
int segment_read_cache(fd_t fdi,iref_t i, char *buf, int size, int offset);
#endif
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);
#endif // _CORE_H_