📄 fs-ecos.c
字号:
/* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright (C) 2001, 2002 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. * * $Id: fs-ecos.c,v 1.8 2003/01/21 18:13:01 dwmw2 Exp $ * */#include <linux/types.h>#include <linux/stat.h>#include <linux/kernel.h>#include "jffs2port.h"#include <linux/jffs2.h>#include <linux/jffs2_fs_sb.h>#include <linux/jffs2_fs_i.h>#include <linux/pagemap.h>#include "nodelist.h"#include <errno.h>#include <string.h>#include <cyg/io/io.h>#include <cyg/io/config_keys.h>#include <cyg/io/flash.h>//==========================================================================// Forward definitions// Filesystem operationsstatic 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);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);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 operationsstatic int jffs2_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);static int jffs2_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);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 operationsstatic 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);//==========================================================================// 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.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);// -------------------------------------------------------------------------// File operations.// This set of file operations are used for normal open files.static cyg_fileops jffs2_fileops = { jffs2_fo_read, jffs2_fo_write, 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 char read_write_buffer[PAGE_CACHE_SIZE]; //avoids malloc when user may be under memory pressurestatic char gc_buffer[PAGE_CACHE_SIZE]; //avoids malloc when user may be under memory pressure//==========================================================================// Directory operationsstruct jffs2_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 jffs2_dirsearch jffs2_dirsearch;//==========================================================================// Ref count and nlink management// -------------------------------------------------------------------------// dec_refcnt()// Decrment the reference count on an inode. If this makes the ref count// zero, then this inode can be freed.static int dec_refcnt(struct inode *node){ int err = ENOERR; node->i_count--; // In JFFS2 inode's are temporary in ram structures that are free'd when the usage i_count drops to 0 // The i_nlink however is managed by JFFS2 and is unrelated to usage if (node->i_count == 0) { // This inode is not in use, so delete it. iput(node); } return err;}// 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 *cached_inode; struct inode *next_inode; 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) if (i == root_i) { for (cached_inode = root_i; cached_inode != NULL; cached_inode = next_inode) { next_inode = cached_inode->i_cache_next; if (cached_inode->i_count == 0) { cached_inode->i_cache_prev->i_cache_next = cached_inode->i_cache_next; // Prveious entry points ahead of us if (cached_inode->i_cache_next != NULL) cached_inode->i_cache_next->i_cache_prev = cached_inode->i_cache_prev; // Next entry points behind us jffs2_clear_inode(cached_inode); D2(printf ("free icache_evict inode %x $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n", cached_inode)); free(cached_inode); } } }}//==========================================================================// Directory search// -------------------------------------------------------------------------// init_dirsearch()// Initialize a dirsearch object to start a searchstatic void init_dirsearch(jffs2_dirsearch * ds, struct inode *dir, const char *name){ D2(printf("init_dirsearch name = %s\n", name)); D2(printf("init_dirsearch dir = %x\n", dir)); 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){ unsigned long hash; struct qstr this; unsigned int c; const char *hashname; 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++; // If we terminated on a NUL, set last flag. 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->node = ds->dir->i_parent; if (ds->dir->i_count == 0) { iput(ds->dir); // This inode may be evicted ds->dir = NULL; } return ENOERR; case 1: // Dot is consumed D2(printf("find_entry found .\n")); ds->node = ds->dir; return ENOERR; } // Here we have the name and its length set up. // Search the directory for a matching entry hashname = name; this.name = hashname; c = *(const unsigned char *) hashname; hash = init_name_hash(); do { hashname++; hash = partial_name_hash(c, hash); c = *(const unsigned char *) hashname; } while (c && (c != '/')); this.len = hashname - (const char *) this.name; this.hash = end_name_hash(hash); D2(printf("find_entry for name = %s\n", ds->path)); d = jffs2_lookup(dir, &this); D2(printf("find_entry got dir = %x\n", d)); if (d == NULL) return ENOENT; // The back path for dotdot to follow d->i_parent = dir; // 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.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') 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; // every inode traversed in the find is temporary and should be free'd //iput(d->dir); // Update dirsearch object to search next directory. d->dir = d->node; d->path += d->namelen; if (*(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; struct inode *root_i; 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")); root_i = iget(sb, 1); if (is_bad_inode(root_i)) { D1(printk(KERN_WARNING "get root inode failed\n")); err = EIO; goto out_nodes; } D1(printk(KERN_DEBUG "jffs2_read_super(): d_alloc_root()\n")); sb->s_root = d_alloc_root(root_i); if (!sb->s_root) { err = ENOMEM; goto out_root_i; } sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = JFFS2_SUPER_MAGIC; return 0; out_root_i: iput(root_i); 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 mtab[], 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"));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -