📄 fs-ecos.c
字号:
/* * JFFS3 -- Journalling Flash File System, Version 3. * * Copyright (C) 2001-2003 Red Hat, Inc. * * Created by Dominic Ostrowski <dominic.ostrowski@3glab.com> * Contributors: David Woodhouse, Nick Garnett, Richard Panton. * * For licensing information, see the file 'LICENCE' in this directory. * * JFFS2 Id: fs-ecos.c,v 1.39 2004/11/11 12:46:17 dwmw2 Exp * $Id: fs-ecos.c,v 3.4 2005/01/05 16:19:01 dedekind Exp $ * */#include <linux/types.h>#include <linux/stat.h>#include <linux/kernel.h>#include <linux/pagemap.h>#include <linux/crc32.h>#include "jffs3.h"#include "nodelist.h"#include "compr.h"#include <errno.h>#include <string.h>#include <cyg/io/io.h>#include <cyg/io/config_keys.h>#if (__GNUC__ == 3) && (__GNUC_MINOR__ == 2) && defined (__ARM_ARCH_4__)#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 operationsstatic int jffs3_mount(cyg_fstab_entry * fste, cyg_mtab_entry * mte);static int jffs3_umount(cyg_mtab_entry * mte);static int jffs3_open(cyg_mtab_entry * mte, cyg_dir dir, const char *name, int mode, cyg_file * fte);#ifdef CYGOPT_FS_JFFS3_WRITEstatic int jffs3_ops_unlink(cyg_mtab_entry * mte, cyg_dir dir, const char *name);static int jffs3_ops_mkdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name);static int jffs3_ops_rmdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name);static int jffs3_ops_rename(cyg_mtab_entry * mte, cyg_dir dir1, const char *name1, cyg_dir dir2, const char *name2);static int jffs3_ops_link(cyg_mtab_entry * mte, cyg_dir dir1, const char *name1, cyg_dir dir2, const char *name2, int type);#endifstatic int jffs3_opendir(cyg_mtab_entry * mte, cyg_dir dir, const char *name, cyg_file * fte);static int jffs3_chdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name, cyg_dir * dir_out);static int jffs3_stat(cyg_mtab_entry * mte, cyg_dir dir, const char *name, struct stat *buf);static int jffs3_getinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name, int key, void *buf, int len);static int jffs3_setinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name, int key, void *buf, int len);// File operationsstatic int jffs3_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);#ifdef CYGOPT_FS_JFFS3_WRITEstatic int jffs3_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);#endifstatic int jffs3_fo_lseek(struct CYG_FILE_TAG *fp, off_t * pos, int whence);static int jffs3_fo_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD com, CYG_ADDRWORD data);static int jffs3_fo_fsync(struct CYG_FILE_TAG *fp, int mode);static int jffs3_fo_close(struct CYG_FILE_TAG *fp);static int jffs3_fo_fstat(struct CYG_FILE_TAG *fp, struct stat *buf);static int jffs3_fo_getinfo(struct CYG_FILE_TAG *fp, int key, void *buf, int len);static int jffs3_fo_setinfo(struct CYG_FILE_TAG *fp, int key, void *buf, int len);// Directory operationsstatic int jffs3_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);static int jffs3_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t * pos, int whence);static int jffs3_read_inode (struct _inode *inode);static void jffs3_clear_inode (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_JFFS3_WRITEFSTAB_ENTRY(jffs3_fste, "jffs3", 0, CYG_SYNCMODE_FILE_FILESYSTEM | CYG_SYNCMODE_IO_FILE, jffs3_mount, jffs3_umount, jffs3_open, jffs3_ops_unlink, jffs3_ops_mkdir, jffs3_ops_rmdir, jffs3_ops_rename, jffs3_ops_link, jffs3_opendir, jffs3_chdir, jffs3_stat, jffs3_getinfo, jffs3_setinfo);#elseFSTAB_ENTRY(jffs3_fste, "jffs3", 0, CYG_SYNCMODE_FILE_FILESYSTEM | CYG_SYNCMODE_IO_FILE, jffs3_mount, jffs3_umount, jffs3_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, jffs3_opendir, jffs3_chdir, jffs3_stat, jffs3_getinfo, jffs3_setinfo);#endif// -------------------------------------------------------------------------// File operations.// This set of file operations are used for normal open files.static cyg_fileops jffs3_fileops = { jffs3_fo_read,#ifdef CYGOPT_FS_JFFS3_WRITE jffs3_fo_write,#else (cyg_fileop_write *) cyg_fileio_erofs,#endif jffs3_fo_lseek, jffs3_fo_ioctl, cyg_fileio_seltrue, jffs3_fo_fsync, jffs3_fo_close, jffs3_fo_fstat, jffs3_fo_getinfo, jffs3_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 jffs3_dirops = { jffs3_fo_dirread, (cyg_fileop_write *) cyg_fileio_enosys, jffs3_fo_dirlseek, (cyg_fileop_ioctl *) cyg_fileio_enosys, cyg_fileio_seltrue, (cyg_fileop_fsync *) cyg_fileio_enosys, jffs3_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 pressurestatic unsigned char n_fs_mounted = 0; // a counter to track the number of jffs3 instances mounted//==========================================================================// Directory operationsstruct jffs3_dirsearch { struct _inode *dir; // directory to search const char *path; // path to follow struct _inode *node; // Node found const char *name; // last name fragment used int namelen; // name fragment length cyg_bool last; // last name in path?};typedef struct jffs3_dirsearch jffs3_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; jffs3_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 searchstatic void init_dirsearch(jffs3_dirsearch * ds, struct _inode *dir, const 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(jffs3_dirsearch * ds){ struct _inode *dir = ds->dir; const char *name = ds->path; const 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 = jffs3_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;}// -------------------------------------------------------------------------// jffs3_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 instatic int jffs3_find(jffs3_dirsearch * d){ int err; D2(printf("jffs3_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 */ jffs3_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 jffs3_pathconf(struct _inode *node, struct cyg_pathconf_info *info){ int err = ENOERR; D2(printf("jffs3_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// -------------------------------------------------------------------------// jffs3_mount()// Process a mount request. This mainly creates a root for the// filesystem.static int jffs3_read_super(struct super_block *sb){ struct jffs3_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 "jffs3: read_super\n")); c = JFFS3_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 ("jffs3: 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 ("jffs3: 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 jffs3_unknown_node); err = jffs3_do_mount_fs(c); if (err) return -err; D1(printk(KERN_DEBUG "jffs3_read_super(): Getting root inode\n")); sb->s_root = jffs3_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: jffs3_free_ino_caches(c); jffs3_free_raw_node_refs(c); free(c->blocks); return err;}static int jffs3_mount(cyg_fstab_entry * fste, cyg_mtab_entry * mte){ extern cyg_mtab_entry cyg_mtab[], cyg_mtab_end; struct super_block *jffs3_sb = NULL; struct jffs3_sb_info *c; cyg_mtab_entry *m; cyg_io_handle_t t; Cyg_ErrNo err; D2(printf("jffs3_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++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -