引言:ROMFS是在嵌入式设备上常用的一种文件系统,具备体积小,可靠性好,读取速度快等优点。同时支持目录,符号链接,硬链接,设备文件。但也有其局限性。ROMFS是一种只读文件系统,同时由于ROMFS本身设计上的原因,使得ROMFS支持的最大文件不超过256M。本文讨论了 ROMFS的原理,并针对其代码做了详细的分析,指出了ROMFS的优缺点并做了相应的改进。Linux, uclinux都支持ROMFS文件系统。除ROMFS外,其它常用的嵌入式设备的文件系统还有CRAMFS,JFFS2等,它们各有特色。
1.ROMFS文件系统的特点
ROMFS是一种只读的文件系统,它使用顺序存储方式,所有数据,包括目录,链接等都按目录树的顺序存放。相对于EXT2等较大型的文件系统而言,ROMFS非常节省空间。通常ROMFS用在嵌入式设备中作为根文件系统,或者用于保存boot loader以便引导系统启动。
2.ROMFS文件系统的数据存储方式
设计一个文件系统首先要确定它的数据存储方式。不同的数据存储方式对文件系统占用空间,读写效率,查找速度等主要性能有极大影响。ROMFS是一种只读的文件系统,它使用顺序存储方式,所有数据都是顺序存放的。因此ROMFS中的数据一旦确定就无法修改,这是ROMFS只能是一种只读文件系统的原因,它的数据存储方式决定了无法对ROMFS进行写操作。由于采用了顺序存放策略,ROMFS中每个文件的数据都能连续存放,读取过程中只需要一次寻址操作,进而就可以读入整块数据,因此ROMFS中读取数据效率很高。
整个ROMFS文件系统的布局如下:
ROMFS的首部
前八个字节是文件系统的名字,在这里是”-rom1fs-“, 8-11字节存放该文件系统大小,12-15字节为前512字节的校验和,从16字节开始是文件系统的卷名,卷名的长度必须的16字节的整数倍,不足的部分可以用‘0’填充。
ROMFS的首部是ROMFS的超级块信息,操作系统通过超级块来识别文件系统的类型。首部之后就是实际的数据,包括目录,普通文件,设备文件,硬链接等。ROMFS支持所有这些类型的文件。
ROMFS文件系统中文件存储方式:
[page]
3. ROMFS的主要数据结构
ROMFS的数据结构比较简单,主要有文件系统结构和文件结构两种数据结构。
ROMFS的文件系统结构如下:
struct romfs_super_block {
__u32 word0;
__u32 word1;
__u32 size;
__u32 checksum;
char name[0]; /* volume name */
};
该结构用于识别整个ROMFS文件系统,大小为512字节,word0初始值为'-','r','o','m',word1初始值为 '-','1','f','s',通过这两个字操作系统确定这是一个ROMFS文件系统。size字段用于记录整个文件系统的大小,理论上ROMFS大小最多可以达到4G。checksum是前512字节的校验和,用于确认整个文件系统结构数据的正确性。前面4个字段占用了16字节,剩下的都可以用作文件系统的卷名,如果整个首部不足512字节便用0填充,以保证首部符合16字节对齐的规则。
ROMFS的文件结构如下:
struct romfs_inode {
__u32 next; /* low 4 bits see ROMFH_ */
__u32 spec;
__u32 size;
__u32 checksum;
char name[0];
};
next 字段是下一个文件的偏移地址,该地址的后4位是保留的,用于记录文件模式信息,其中前两位为文件类型,后两位则标识该文件是否为可执行文件。因此 ROMFS用于文件寻址的字段实际上只有28bit,所以ROMFS中文件大小不能超过256M。spec字段用于标识该文件类型。目前ROMFS支持的文件类型包括普通文件,目录文件,符号链接,块设备和字符设备文件。size是文件大小,checksum是校验和,校验内容包括文件名,填充字段。 name是文件名首地址,文件名长度必须保证16字节对齐,不足的部分用可以0填充。
4.ROMFS的实现
在Linux系统中定义一个文件系统首先要定义相应的file_system_type以及读取超级块的函数。具体到ROMFS本身,这两个对象分别是romfs_fs_type和romfs_read_super,通过宏DECLARE_FSTYPE_DEV来实现对romfs_fs_type的定义以及初始化工作。此外还需要实现对目录,文件的读写操作。
在Linux对ROMFS的实现中,比较重要的数据结构如下:
//超级块操作表
static struct super_operations romfs_ops = {
read_inode: romfs_read_inode,
statfs: romfs_statfs,};
//页操作表
static struct address_space_operations romfs_aops = {
readpage: romfs_readpage};
//常规文件操作表
static struct file_operations romfs_dir_operations = {
read: generic_read_dir,
readdir: romfs_readdir,};
//索引节点操作表
static struct inode_operations romfs_dir_inode_operations = {
lookup: romfs_lookup,};[page]
romfs_read_super()用来读取ROMFS文件系统的首部,并利用该首部初始化一个超级块对象作为相应ROMFS的超级块,具体流程如下
1 初始化超级块。
A 设置一次读取的块大小并初始化超级块对象某些域。
B 从指定ROMFS中读取第0块到一个缓冲区。bh=sb_bread(s, 0),其中s是文件系统的超级块对象。ROMFS的文件系统结构被保存到缓冲区bh中。
C 取出ROMFS的文件系统结构,rsb = (struct romfs_super_block *)bh->b_data,rsb是一个romfs_super_block结构,用以保存该ROMFS的文件系统结构的数据。然后对该数据进行检验,确定其文件系统类型,检验和,文件系统大小。
D 继续初始化超级块对象某些域,比较重要的是s_magic = ROMFS_MAGIC和s_flags |= MS_RDONLY,分别表明了该超级块的magic签名和s_flags参数,此处它们分别表示该文件系统类型为romfs,并且是只读文件系统。
2 给超级块对象的操作表赋值(s->s_op = &romfs_ops)
3 为根目录分配目录项 s->s_root = d_alloc_root(iget(s,sz), sz为文件系统开始偏移。
超级块操作表中romfs文件系统实现了两个函数
static struct super_operations romfs_ops = {
read_inode: romfs_read_inode,
statfs: romfs_statfs,};
函数romfs_read_inode是从ROMFS中读取一个inode索引节点对象并进行一些初始化工作,具体流程如下:
1 根据inode参数寻找对应的索引节点。
2 初始化索引节点某些域
3 根据该inode对应的文件的访问权限和类别来设置索引节点的相应操作表
A 如果是目录文件则将索引节点操作表设为i_>i_op=&romfs_dir_inode_operations;文件操作表设置为i->i_fop=&romfs_dir_operations。
B 如果是常规文件,则将文件操作表设置为i->i_fop=&generic_ro_fops;将页高诉缓存表设置为i-> i_data.a_ops=&romfs_aops;由于romfs是只读文件系统,它在对常规文件操作时不需要索引节点操作,如 mknod,link等,因此不用设置索引节点操作表。
对常规文件的操作也只需要使用内核提供的通用函数表generic_ro_fops ,它包含基本的三种常规文件操作:
llseek: generic_file_llseek,
read: generic_file_read,
mmap: generic_file_mmap,
这几种函数是块设备读取的通用函数,它们可以实现对ROMFS中常规文件的读取,寻址等操作。
C 如果是符号链接文件,则将索引节点操作表设置为
i->i_op = &page_symlink_inode_operation;
page_symlink_inode_operations是通用的符号链接操作表。同时还需要实现页高速缓
存操作,因此将页高诉缓存表设置为i->i_data.a_ops=&romfs_aops。
D 如果是套接字或管道则进行特殊文件初始化操作init_special_inode(I,ino,nextfh);
函数romfs_statfs用于提取一些ROMFS的基本信息,包括文件系统大小,卷名等。相对而言非常简单。
5. 对ROMFS的改进
5.1 改进思路
ROMFS有紧凑,小巧等优点,但是也存在一些明显的不足。作为一个只读的文件系统,ROMFS的中文件最大只能达到256M。因此难以在 ROMFS中保存较大的文件。在实际工作中我们常常会碰到超过256M的大文件,因此本人对ROMFS做了一些改进,使它能够容纳超过256M的文件。
ROMFS中限制文件大小的原因在于ROMFS的文件结构。ROMFS采用连续存放数据的策略,每个文件都必须放在连续空间内,故文件寻址只能是一级寻址,不能通过增减数据块来改变文件大小。虽然ROMFS使用32位地址进行文件的寻址操作,但该32位地址的后4位留做它用,因此ROMFS实际用于文件寻址的地址只有28位,这就造成ROMFS的任意两个文件头之间地址相差不能超过256M,这就是ROMFS中文件大小不能超过256M的原因。[page]
针对这点我们可以做一些适当的改进工作,ROMFS的基本结构十分紧凑,能够改动的范围比较有限。为了尽可能保留原有代码的结构,我们没有在 ROMFS的文件结构中添加新字段,只是利用了文件名的填充字段作为对文件寻址的补充。在构造文件系统时在实际文件名后加上1个字节作为文件名的附加段,实际文件名加上附加段后写入文件系统作为该文件的文件名。附加段的前4位用来作为文件首地址的低4位。这样如果文件名不是16个字节整数倍则可以利用对文件名的填充字节,不会额外占用空间;如果文件名长度刚好为16字节的整数倍,那么加上一个字节的附加段后必须再填充15个字节以符合文件名保持16字节对齐的要求。这会浪费15个字节的空间,但文件名本身恰好满足16字节对齐的机会并不大,从概率角度讲只有1/16,因此是可以接受的。修改后ROMFS的文件结构如下:
在对文件寻址时,将next filehdr 字段的前28位和additional 字段的前4位合并起来作为下一个文件头起始地址,这样文件的寻址可以达到32位,ROMFS能够容纳的最大文件可以达到4G。
5.2 试验分析:
使用ROMFS生成一个文件系统。我们使用普通的Linux操作系统,内核版本为2.4.20-8,编译时选择支持ROMFS文件系统。至于romfs工具和源代码,可以从http://romfs.sourceforge.net得到。我们使用修改后的代码,同时对Linux中ROMFS的代码也要进行适当的修改,并重新编译内核。试验可以建立一个简单的目录FSROOT,目录结构如下:
FSROOT |
FILE1 |
FILE2 |
SUBDIR1 |
FILE3 |
FILE1 和FILE2 大小为100M,FILE3大小为512M
生成romfs的命令如下(在当前目录下):genromfs -f romfs.bin –d FSROOT/
程序会根据目录FSROOT内容生成一个名为 romfs.bin的映像文件。选择一个挂载点,如/home目录,将生成的romfs.bin挂载到该目录下,命令为 mount –t romfs romfs.bin /home,将指定的映像文件挂载到/home目录下。可以用ls命令查看该目录。
[root@linuxserver home]# ls
[root@linuxserver home]# DIR1 FILE1 FILE2
[root@linuxserver home]# cd DIR1
[root@linuxserver DIR1]# ls
[root@linuxserver DIR1]# FILE3
可以看到新修改的ROMFS文件系统工作的很好,能够容纳超过256M的文件,达到了我们预期的目的。
6. 结束语
ROMFS是众多应用于嵌入式的文件系统之一,目前Linux和ucLinux都支持ROMFS。本文从数据的组织方式,基本数据结构,重要的操作的实现等方面详细分析了ROMFS的原理。同时指出了ROMFS一些局限性并做了一些改进工作。但是ROMFS本身的设计使其难以被修改为可擦写的文件系统,如果要在文件系统中提供可擦写功能,可以使用其它支持读写的嵌入式文件系统(比如JFFS2)以适应需要对闪存进行读写的应用。
本文的创新点在于对ROMFS 文件系统中文件寻址方法的改进,使得ROMFS可以支持更大的文件,满足了嵌入式设备中对存储系统更高的需求。
参考文献:
[1] 杨途军,郑明.嵌入式文件系统在触摸屏中的应用[J].微计算机信息.2005,5:100-101
[2] 孙建恒.嵌入式系统应用研究及实例[J].微计算机信息,2004,6:65-66
[3] 美 Moshe Bar《Linux文件系统》清华大学出版社
[4] Jonathan Corbet,Alessandro Rubini Greg Kroah-Hartman《Linux设备驱动程序》 O’REILLY 中国电力出版社
[5] Linux Kernel 2.4.20-8 Source Code[CP/OL].http://lxr.1inux. no/source/fs
[6] Janos Farkas ,Jakub Jelinek Genromfs 源代码. http://romfs.sourceforge.net
[7] 毛德操、胡希明,《linux内核源代码情景分析》浙江大学出版社
上一篇:基于Framebuffer的嵌入式GUI系统实现
下一篇:嵌入式Linux实时技术改进与实现
推荐阅读最新更新时间:2024-05-02 21:58