打印

eCos扫盲之eCos内存文件系统

[复制链接]
4240|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
涛行九天|  楼主 | 2008-5-8 02:13 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
这个是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进行相应的读/写操作;


相关帖子

沙发
armecos| | 2008-5-8 06:40 | 只看该作者

不错,ecos的RAM文件系统是非常好的入门教材,

    如果你对文件系统感兴趣,建议不要一开始就看FAT等资料,而是先从ROMFS的源码看起,那个特别简单,而且完全符合UNIX IO标准,程序还特别短,学起来很快。
    
    然后看看RAMFS文件系统,它的特点是能读写,支持动态地增加文件节点,里面用到的数据结构非常巧妙,这种把文件和目录看成节点的方法,特别能启发我们的设计思路。
    
    我是2007年才看的这两个FS实现源码,当时立即就顿悟了文件系统的实现原理,然后很快就看懂了FAT文件,ecos这方面的一致性很好,所有FS都是一个模子。JFFS2也差不多是这样。
    
    如果你想一开始就学习正规标准的FS,那么最好选择《ecos增值包》产品。看到很多人从FAT开始学习文件系统,我感到有些担忧,那一定很痛苦,而且现在的FAT源码质量参差不齐,初学者如果参考一个很不标准正规的代码,那么会对以后使用造成障碍,养成坏习惯再改就太困难了,所以最好一开始就学习ecos高质量的标准FS代码。建议不要学习DOS下的那种文件系统,而是一开始就学习UNIX下的那种。

使用特权

评论回复
板凳
Swd21ic| | 2008-5-9 23:37 | 只看该作者

Re

我觉得armecos真是天才..
随时随地都能进行推销...

哈哈.

使用特权

评论回复
地板
rainmans| | 2008-5-13 18:07 | 只看该作者

LS说的对,杨工是个商业奇才。技术好自不必说

使用特权

评论回复
5
coke| | 2008-5-14 10:30 | 只看该作者

re

不知道eCos和VxWorks哪个在产品应用更广泛. 

使用特权

评论回复
6
brandnew| | 2008-5-14 12:03 | 只看该作者

。。。

口水+小狗

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

4249

主题

8684

帖子

239

粉丝