ROMFS文件系统分析

| 2014年4月6日

作者:许振文

ROMFS是一种简单的只读文件系统,主要是用来当做初始文件系统来使用的,在嵌入式linux或是uclinux中通常使用这中文件系统来作为引导系统的文件系统,甚至uclinux有时就直接把ROMFS作为其根文件系统,而不是将其作为系统启动中的过渡文件系统。在前面我也分析过,linux操作系统启动中一个是要加载内核,另一个就是要加载一个用于系统简单初始化的文件系统。这个文件系统的格式也是经过了很多发展的。现在一般使用的是一中cpio的格式。在嵌入式系统中一般使用romfs+其它的可读文件系统。romfs由于它的小巧性(其内核编译只有4000字节),所以非常适合作为系统启动初始化的文件系统。本文就是对ROMFS文件系统进行结构上的分析。前面我也曾对其源代码结构进行了简单的分析。关于ROMFS最为权威的资料是内核源代码树下的“Documentation/filesystems/romfs.txt”。本文多数资料就是来自于该文件。

ROMFS文件系统的制作

一般我们可以使用一些工具来制作ROMFS的文件系统。制作好之后其实也就是一个二进制的文件。制作工具一般使用”genromfs“,这个工具在网上就可下载到,其源代码并不是很多,只有不到900行。

以下是genromfs工具所支持的参数:

xux@zhwen:~/fs-sys$ genromfs -h
genromfs 0.5.2
Usage: genromfs [OPTIONS] -f IMAGE
Create a romfs filesystem image from a directory

  -f IMAGE               Output the image into this file
  -d DIRECTORY           Use this directory as source
  -v                     (Too) verbose operation
  -V VOLUME              Use the specified volume name
  -a ALIGN               Align regular file data to ALIGN bytes
  -A ALIGN,PATTERN       Align all objects matching pattern to at least ALIGN bytes
  -x PATTERN             Exclude all objects matching pattern
  -h                     Show this help

Report bugs to chexum@shadow.banki.hu
xux@zhwen:~/fs-sys$ 

参数解释:

-f IMAGE     指定输出romfs映像的名字

-d DIRECTORY 指定源目录(将该目录制作成romfs文件系统)

-v           显示详细的创建过程

-V VOLUME    指定卷标

-a ALIGN     指定普通文件的对齐边界(默认为16字节)

-A ALIGN,PATTERN 匹配参数PATTERN的对象对齐在ALIGN边界上

-x PATTERN 不包括匹配PATTERN的对象。

-h 显示帮助文档。

以下是如何制作生成一个romfs的文件系统:

xux@zhwen:~/fs-sys$ ls
test  
xux@zhwen:~/fs-sys$ ls test/
test  xux  zhwen
xux@zhwen:~/fs-sys$ genromfs -V "xromfs" -f romfs.img -d test
xux@zhwen:~/fs-sys$ ls
romfs.img  test 
xux@zhwen:~/fs-sys$ file romfs.img 
romfs.img: romfs filesystem, version 1 592 bytes, named xromfs.
xux@zhwen:~/fs-sys$ sudo mount romfs.img /mnt -o loop
xux@zhwen:~/fs-sys$ ls /mnt/
test  xux  zhwen
xux@zhwen:~/fs-sys$ 

ROMFS文件系统结构分析

ROMFS系统中最大文件的大小理论上可以达到4G,文件名的大小一般小于16字节,而且整个文件系统都是以16字节来对齐。

其结构如下:

offset      content
        +---+---+---+---+
  0     |  -  |  r  |  o  | m  |  \
        +---+---+---+---+    The ASCII representation of those bytes
  4     |  1  |  f  |  s  |  -  |  /    (i.e. "-rom1fs-")
        +---+---+---+---+
  8     |     full size       |    The number of accessible bytes in this fs.
        +---+---+---+---+
 12     |    checksum   |       The checksum of the FIRST 512 BYTES.
        +---+---+---+---+
 16     |  volume name     |    The zero terminated name of the volume,
        :               :       padded to 16 byte boundary.
        +---+---+---+---+
 xx     |     file      |
        :    headers    :

File headers之前的字节由如下的数据结构来控制:include/linux/romfs_fs.h

```c /* On-disk "super block" */ struct romfs_super_block { __be32 word0; __be32 word1; __be32 size; __be32 checksum; char name[0]; /* volume name */ }; ``` (1)这个数据结构中的word0和word1的是固定的值:“-rom1fs-”,由如下的宏定义说明:

include/linux/romfs_fs.h

#define ROMSB_WORD0 __mk4('-','r','o','m')
#define ROMSB_WORD1 __mk4('1','f','s','-')

(2)而size是对整个文件系统的大小的说明。

(3)checksum是对前512个字节的校验和(如果小于512,就以实际大小计算)。

(4)name是当前这个文件系统的名称。

下面在来看文件的堆放格式

```c offset content +---+---+---+---+ | file header | +---+---+---+---+ | file date | +---+---+---+---+ | file header | +---+---+---+---+ | file date | | file header | +---+---+---+---+ | file date | +---+---+---+---+ | ……. | +---+---+---+---+ ```

File header的格式如下

```c offset content +---+---+---+---+ 0 | next filehdr | X | The offset of the next file header +---+---+---+---+ (zero if no more files) 4 | spec.info | Info for directories/hard links/devices +---+---+---+---+ 8 | size | The size of this file in bytes +---+---+---+---+ 12 | checksum | Covering the meta data, including the file +---+---+---+---+ name, and padding 16 | file name | The zero terminated name of the file, : : padded to 16 byte boundary ``` 在内核源代码中如下:include/linux/romfs_fs.h ```c /* On disk inode */ struct romfs_inode { __be32 next; /* low 4 bits see ROMFH_ */ __be32 spec; __be32 size; __be32 checksum; char name[0]; }; ``` (1)其中next的前面28位是指向下一个文件的地址,应为整个文件系统以16字节对齐,所以任何一个文件的起始地址的最后4位始终为“0”。

而这最后的4位并没就此浪费,而是进行了新的利用--指定文件的类型和是否可执行。在linux下文件的类型分为:目录,一般文件,链接文件,管道文件,设备文件等。 所以这4位中的最高一位使用来表示该文件是否可执行,而其余三位使用来表示该文件的类型。

include/linux/romfs_fs.h

#define ROMFH_TYPE 7
#define ROMFH_HRD 0
#define ROMFH_DIR 1
#define ROMFH_REG 2
#define ROMFH_SYM 3
#define ROMFH_BLK 4
#define ROMFH_CHR 5
#define ROMFH_SCK 6
#define ROMFH_FIF 7
#define ROMFH_EXEC 8

(2)spec这个字段存放的是目录/硬链接/设备文件的相关信息:

这个域是文件类型相关的,也就是说对于不同的文件类型,这个域表示的含义是不一样的。下面是具体的说明;来自“Documentation/filesystems/romfs.txt”。

          mapping               spec.info means
 0      hard link       link destination [file header]
 1      directory       first file's header
 2      regular file    unused, must be zero [MBZ]
 3      symbolic link   unused, MBZ (file data is the link content)
 4      block device    16/16 bits major/minor number
 5      char device                 - " -
 6      socket          unused, MBZ
 7      fifo            unused, MBZ

(3)size是这个文件的大小。

(4)checksum这个域只是文件头和文件名的校验和。

(5)name是文件的名称。

看完本文有收获?请分享给更多人

关注「黑光技术」,关注大数据+微服务