这个是2001年学习的时候弄的,现在都忘到爪哇国了,大家了解一下eCos,还是一个很不错的os,这方面armecos是专家。
eCos内存文件系统
eCos提供两种存储方式,由宏CYGPKG_FS_RAM_SIMPLE是否定义来决定采用那种存储方式。 1. 简单存储 优点:操作方法和存储结构简单。 缺点:如果一些文件需要按比例分配,产生的碎片可能会导致一些文件无法得到扩展空间,尽管还有足够的空间;需要malloc()函数。 2. 块存储 可以通过malloc()分配或根据需要从保留的内存块数组中得到。 优点:方便管理;用malloc()分配时,可以分配任何空闲内存以得到正确的大小;不需要malloc()函数。 缺点:用malloc()分配时,每块的内存占用描述符要占用内存空间;使用内存块数组,则它将被永久保留。
所有的文件和目录都用结点对象来描述;每个ramfs_node结构如下: struct ramfs_node { mode_t mode; // node type cyg_ucount32 refcnt; // open file/current dir references nlink_t nlink; // number of links to this node size_t size; // size of file in bytes time_t atime; // last access time time_t mtime; // last modified time time_t ctime; // last changed status time #ifdef CYGPKG_FS_RAM_SIMPLE
// The data storage in this case consists of a single // malloced memory block, together with its size. size_t datasize; // size of data block cyg_uint8 *data; // malloced data buffer
#else
// The data storage in this case consists of arrays of pointers // to data blocks. #if CYGNUM_RAMFS_BLOCKS_DIRECT > 0 // Directly accessible blocks from the inode. ramfs_block *direct[CYGNUM_RAMFS_BLOCKS_DIRECT]; #endif #if CYGNUM_RAMFS_BLOCKS_INDIRECT1 > 0 // Single level indirection ramfs_block **indirect1[CYGNUM_RAMFS_BLOCKS_INDIRECT1]; #endif #if CYGNUM_RAMFS_BLOCKS_INDIRECT2 > 0 // Two level indirection ramfs_block ***indirect2[CYGNUM_RAMFS_BLOCKS_INDIRECT2]; #endif
#endif };
.mode 结点类型,文件或目录 .refcnt引用计数;对文件来讲,每一个open是一次引用;对目录来讲,当成为当前目 录或打开进行读操作是一次引用 .nlink链接计数,每个目录对该结点的引用 .size 该结点的数据大小(按字节) .atime结点最后被访问时间 .mtime结点数据最后被修改时间 .ctime结点状态最后被改变的时间 .数据区:整体或块存储
目录入口 ramfs_dirent结构包含以下字段: struct ramfs_dirent { ramfs_node *node; // pointer to node unsigned int inuse:1, // entry in use? first:1, // first directory entry fragment? last:1, // last directory entry fragment? namelen:8, // bytes in whole name fraglen:8; // bytes in name fragment off_t next; // offset of next dirent
// Name fragment, fills rest of entry. char name[CYGNUM_RAMFS_DIRENT_SIZE- sizeof(ramfs_node *)- sizeof( cyg_uint32)- sizeof(off_t)]; };
.node被该入口引用的结点(出现在每一个目录入口片段) .inuse 1:在使用,0:空闲 .first 1:这是目录入口的第一个片段 .last 1:这是目录入口的第一个片段 .namelen 文件名的总长度 .fraglen 在该片段存贮的文件名的长度(按字节) .next 该目录入口的下一个片段 .name 存贮在该入口的文件名的片段
结点对象与目录入口的关系(以块存储为例): 1. 如果一个结点描述的是目录,则其数据区存放的是一系列目录入口,包含“。”、“。。”和其下的子目录的目录入口(指向对应的子目录结点对象)和文件的目录入口(指向对应的文件结点对象)。 2. 如果一个结点描述的是文件,则其数据区存放的是其文件内容。其所在目录的目 录入口中该文件的目录入口指向该结点。
假如存在这样一个文件:/mylongdirtest/test1.c;每个目录入口保存8个字符长的名字; 则其对应的内存文件系统的结构如图(见下页),每个ramfs_node结点的数据按块存贮; 以下显示了一个文件最大时的数据块的分布:(一块256字节,缺省配置)
Node ~ ~ | | | | +------------+ | *------+--------> data block 0 +-------------+ | *------+--------> data block 1 +-------------+ | *------+--------> data block 2 +-------------+ | *------+--------> data block 3 +-------------+ | *------+--------> data block 4 +-------------+ | *------+--------> data block 5 +------------+ | *------+--------> data block 6 +-------------+ | *------+--------> data block 7 +-------------+ | *------+-----------> +------------+ +-------------+ | *------+--------> data block 8 | *------+----+ +------------+ +-------------+ | | | | ~ ~ | | | | +-----------+ | | *------+--------> data block 71 | +-----------+ | +----->+------------+ +------------+ | *------+---------->| *------+---->data block 72 +------------+ +------------+ | | | | ~ ~ ~ ~ | | | | +------------+ +-------------+ | *------+----+ | *------+----> data block 135 +------------+ | +-------------+ | | +------------+ +-------->| *------+----> data block 4104 +------------+ | | ~ ~ | | +------------+ | *------+----> data block 4167 +------------+ struct cyg_mtab_entry struct ramfs_node root ramfs_fste
ramblock
longdir ramfs_dirent
“.”
ramfs_dirent “.” test1 “..”
“..”
“mylongdi”
struct cyg_file
“test1.c”
&ramfs_fileops “rtest” 函数说明: 1. block_init:如果定义了文件内存块数组,则将这些内存块组织成一个链表,表头是 block_free_list. 2. block_alloc: 如果定义了文件内存块数组,则从block_free_list中分配一块,否则用malloc动态分配;并将该块的数据全部置为零. 3. block_free: 如果定义了文件内存块数组,则将其释放到以block_free_list为表头的空闲内存链中;否则用free释放到内存池. 4. findbuffer_node( ramfs_node *node, off_t pos, cyg_uint8 **buffer, size_t *size, cyg_bool alloc) //直接调用findbuffer_direct(块存储) 在结点node的数据区中找到偏移量为pos的内存区域,如果相应的块不存在且alloc=true, 则分配一块(当然要受到块的数量的限制)。 5. freebuffer_node: 释放一个文件结点的数据区。 6.findbuffer_direct( off_t pos, ramfs_block **blocks, int nblocks, cyg_uint8 **buffer, size_t *size, cyg_bool alloc) 根据pos计算出块号和块内偏移量,如果相应的块不存在且alloc是true,则分配一块; blocks[nblocks+1]保存了当前所有的块,如果blocks[块号]=NULL,说明对应的块未分配, 块号不能大于nblocks;正确返回时*buffer指向对应块偏移量的地址,*size=块的尺寸-块内 偏移量(如alloc=true,即该块剩余空间)。 7.alloc_node:为文件结点分配一段内存,并初始化struct ramfs_node. 8.free-node: 释放一个文件结点。 9.dec_refcnt: 文件结点的引用计数减1,如为0则可能会导致该结点被删除。 10. add_direntry( ramfs_node *dir, /*欲添加目录的结点(该结点是一目录)*/ const char *name, /*添加的目录名*/ int namelen, /*添加的目录名的长度*/ ramfs_node *node /*引用的结点*/ ) 在目录dir下添加目录入口(长文件名会添加几个目录入口),引用结点node. 比如:add_direntry(root,”.”,1,root) :在root结点添加一个目录”.”,引用的结点是其自己; add_direntry(root,”bar”,3,node): 在root结点添加一个目录”bar”,引用结点node. 11. find_direntry( ramfs_node *dir, const char *name, int namelen ) 在目录dir的数据区查找名字为name的目录,找到后,返回其第一个目录入口; 比如:find_direntry(root,”mylongdirtest”,13):返回root结点下名字是”mylongdi”的目录入口. 12. del_direntry( ramfs_node *dir, const char *name, int namelen ) 删除目录dir下名字为name的所有目录入口片断。 13. init_dirsearch ( ramfs_dirsearch *ds,ramfs_node *dir, const char *name) { ds->dir = dir; ds->path = name; ds->node = dir; ds->name = name; ds->namelen = 0; ds->last = false; } 初始化目录查找对象ds; struct ramfs_dirsearch { ramfs_node *dir; // 进行查找的目录 const char *path; // 查找路径 ramfs_node *node; // 找到的结点 const char *name; // 最后用到的名字片段 int namelen; // 名字片段的长度 cyg_bool last; // 路径的最后一个名字片段? }; 14. find_entry( ramfs_dirsearch *ds ) 查找ds.path中下一个目录,并修改 ds->node. 比如init_dirsearch(ds,root,”mylongdirtest/test1.c”); 此时: ds->dir =root; ds->path = ”mylongdirtest/test1.c”; ds->node = root; ds->name = ”mylongdirtest/test1.c”; ds->namelen = 0; ds->last = false; find_entry( ds); ds->dir =root; ds->path = ”mylongdirtest/test1.c”; ds->node =longdir; //见P7图示 ds->name = ”mylongdirtest/test1.c”; ds->namelen = 13; ds->last = false; 其实,ds->dir、ds->path也要作相应的修改(ds->dir=longdir,ds->path=”test1.c”), 只是不在这作,在ramfs_find中修改. 10. ramfs_find( ramfs_dirsearch *d ) 查找某个目录或文件 比如:init_dirsearch(ds,root,”mylongdirtest/test1.c”); ramfs_find(ds); 此时ds的内容为: ds->dir =longdir; //指向要查找的文件结点的父目录 ds->path = ”test1.c”; ds->node =test1; //见P7图示,指向要查找的文件结点 ds->name = ”mylongdirtest/test1.c”; ds->namelen =7; ds->last = true; 11. ramfs_mount ( cyg_fstab_entry *fste, cyg_mtab_entry *mte ) 安装内存文件系统 12.ramfs_open ( cyg_mtab_entry *mte, cyg_dir dir, const char *name, int mode, cyg_file *file ) 为了读或写,打开一个文件;如果文件不存在,则根据mode进行相应处理,比如若mode&O_CREATE,则建一个新的文件;文件的偏移量为零或结尾(若mode&O_APPEND). 会使该文件结点的引用计数refcnt+1,且指针offset指向文件头。 比如ramfs_open(mte,root,”mylongdirtest/test1.c”,READ,file),结果见图示; 13. ramfs_mkdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name ) 创建一个目录,同时会在自己目录下添加“。”“。。”两个目录入口,分别引用结点自己和父目录结点。 比如ramfs_mkdir(mte,root,”mydir1/mydir2”):在目录mydir1处创建子目录mydir2, 若目录mydir1不存在,则出错。 14.ramfs_fo_read (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) ramfs_fo_write (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) 读和写都是对结构CYG_UIO_TAG进行操作;
struct CYG_UIO_TAG { struct CYG_IOVEC_TAG *uio_iov; /* pointer to array of iovecs */ int uio_iovcnt; /* number of iovecs in array */ off_t uio_offset; /* offset into file this uio corresponds to */ ssize_t uio_resid; /* residual i/o count */ enum cyg_uio_seg uio_seg**; /* see above */ enum cyg_uio_rw uio_rw; /* see above */ };
struct CYG_IOVEC_TAG { void *iov_base; /* Base address. */ ssize_t iov_len; /* Length. */ }; 比如当应用程序调用函数read/write对某个内存文件进行读/写操作时,函数read/write填充上述两个结构,然后调用ramfs_fo_read/ramfs_fo_write进行相应的读/写操作;
|