根文件系统是构建一个Linux 嵌入式系统的重要组成部分,目前嵌入式系统可以选 择的根文件系统有:Romfs、Cramfs、Ramfs、Jffs2、Ext2 等,而目前广泛使用的Cramfs 根文件系统是只读型文件系统,在实际应用中,应用程序往往需要对根文件系统进行读、写 操作的,因此,如果针对Cramfs 系统直接进行写操作就会造成系统错误。文中提出了配置 Cramfs 根文件系统的新方法,实验证明,该方法能够使Cramfs 满足应用程序的读、写要 求,并能够保障系统的正常稳定运行,同时也减小了根文件系统所占用的存储空间。
1 引言
随着电子产业的不断发展,基于 ARM 技术的系统设计和开发平台越来越多地在控制 类、消费类、通信类等电子产品中广泛应用。从软件角度上看,构建基于ARM 技术的linux 系统要涉及到引导加载程序、Linux 内核、文件系统、用户应用程序几部分的设计。 文件系统是操作系统中用来管理用户文件的内核软件层。文件可能存在于磁盘、网络或 者是一些虚拟的文件。文件系统包括根文件系统和建立于内存设备之上文件系统。根文件系 统是linux 系统的核心部分,包含系统使用的软件和库,以及所有用来为用户提供支持架构 和用户使用的应用软件,并作为存储数据读写结果的区域。由于嵌入式设备中Flash 资源很 紧张,如何有效地使用有限的存储空间是嵌入式开发者必须考虑的,合适的文件系统格式是 解决这一问题的关键所在。本文讨论了只读型压缩Cramfs 根文件系统的特点,并详细的说 明了NAND FLASH 上建立一个可读可写型嵌嵌入式Linux 的Cramfs 根文件系统的新方法。
2 Linux 根文件系统概述
2.1 Linux根文件系统
根文件系统不同于普通文件系统,它是在内核启动时挂载(mount)的第一个文件系统, 内核代码映像文件保存在根文件系统中,而系统引导启动程序会在根文件系统挂载之后把一 些基本的初始化脚本和服务程序等加载到内存中。
Linux 根文件系统是树型结构组织[1,3],它包含了内核和系统管理所需要的各种文档和程序等。一般来说,根目录“/”下顶层目录都有一些比较固定命名和用途,下面列出一
个Linux 根文件系统中的比较常见的目录结构。
/bin:存放二进制可执行命令的目录。
/dev:存放设备文件和目录。
/etc:存放系统管理和配置文件和目录。
/home:用户主目录,比如用户user 的主目录就是/home/user,可以用~user 来表示。
/lib:存放动态链接共享库的目录。
/sbin:存放系统管理员使用的管理程序的目录。
/tmp:公用的临时文件存储点。
/root:系统管理员的主目录。
/mnt:用以临时挂载其他的文件系统。
/proc:虚拟文件系统,可直接访问这个目录来获取系统信息。
/var:某些大文件溢出区。
/usr:存放应用程序和文件。
对于嵌入式 Linux 系统的根文件系统来说,由于受系统资源的限制,一般没有上述 那么复杂,仅保留一些常用的目录即可。如/bin、/dev、/etc、/lib、/proc、/var、/tmp、/usr、 /mnt 等[2]。 由于嵌入式系统的设计冗余度小、系统紧凑,通常存储容量有限,因此,必须选择 一个合适的根文件系统以使系统运行最佳。目前,嵌入式Linux 根文件系统主要的根文件系 统类型有:Romfs, JFFS2, RAMDISK, YAFFS/YAFFS2, Cramfs, Squashfs 等[1]。本文主要对 Cramfs 根文件系统进行讨论。
2.2 Cramfs根文件系统及其在实际应用中存在的问题
Cramfs 是Linux 的创始人 Linus Torvalds 参与开发的一种只读的压缩文件系统,它基于 MTD(Memory Technology Device,存储技术设备)驱动程序。在cramfs 文件系统中,每一页 (4KB)被单独压缩,可以随机页访问,其压缩比高达2:1,为嵌入式系统节省大量的Flash 存储 空间,使系统可通过更低容量的FLASH 存储相同的文件,从而降低系统成本。
Cramfs 并不 需要一次性地将文件系统中的所有内容都解压到内存中,而只是在系统需要访问某个位置的 数据时,立即计算出该数据在Cramfs 中的位置,将其实时地解压缩到内存中,然后通过对 内存的访问来获取文件系统中需要读取的数据。Cramfs 中的解压缩以及解压缩之后内存中 的数据存放位置都是由Cramfs 文件系统本身进行维护的,用户并不需要了解具体实现过程, 因此这种方式增强了透明度,对开发人员来说,既方便又节省了存储空间。
由于 Cramfs 是只读型文件系统,而大多嵌入式应用程序需要在临时目录/tmp 进行创建 临时文件等写操作,如不对Cramfs 进行配置,则应用程序将不能正常运行,导致系统崩溃。 目前,解决些问题的方法是复合文件系统法,即使用YAFFS/YAFFS2 等可写型文件系统与 Cramfs 复合而成的文件系统作为嵌入式系统的根文件系统,使Cramfs 根文件系统启动时挂 载YAFFS/YAFFS2 文件系统,同时将应用程序存放在YAFFS/YAFFS2 文件系统中。这种方 法解决了应用程序对根文件系统的写操作问题,但由于在通常的根文件系统之外还增加了一 个额外的可写型文件系统,必然会增大整个根文件系统所占的存储空间,造成嵌入式系统存 储资源紧张。本文在实践的基础上,通过对Linux Cramfs 根文件系统的研究,发现了一种通 过修改根文件系统启动脚本和配置文件来实现根文件系统的可读、可写性的新方法,它不需 要新增额外的文件系统来支持应用程序的读、写要求,而是利用根文件系统本身的特性来构 造一个局部可写的根文件系统。
3 嵌入式Linux 根文件系统的配置
3.1 Cramfs根文件系统配置文件的分析
Cramfs 根文件系统中的配置文件存放在/etc 目录下,有22 个文件及文件夹,可分为以 下几类:
引导和登录/注销类,包括/etc/issue、/etc/issue.net、/etc/rc.d/rc、/etc/rc.d/rc.local、 /etc/rc.d/rc.sysinit、/etc/rc.d/rc/rcX.d 等文件,它们主要记录系统的启动信息及运行级别等。
文件系统类,包括/etc/mtab、/etc/fstab、/etc/mtools.conf 文件等,它们记录着系统文 件系统的安装、卸载信息,系统启动时可以被安装的文件系统以及在这些文件系统上所定 义的操作。
系统管理类,包括/etc/group、/etc/nologin、/etc/passwd、/etc/rpmrc、/etc/securetty、 /etc/usertty、/etc/shadow、/etc/shells、/etc/motd 等文件,它们记录着系统用户和用户组的登 录信息、加密后的用户帐号密码信息、用户组的权限信息等。
网络类,包括/etc/gated.conf、/etc/networks、/etc/protocols、/etc/gateway、/etc/services、 /etc/inetd.conf、/etc/sysconfig/netword、/etc/recolv.conf、/etc/rpc、/etc/exports 等文件,它们 记录着系统对网络接口的配置信息、网络服务程序、网络协议、网络文件系统配置等信息。
系统命令类,包括/etc/lilo.conf、/etc/logrotate.conf、/et/identd.conf、/etc/ld.so.conf、 /etc/inittab、/etc/termcp 等文件,这些文件记录着要独占地控制系统的系统命令及动态链接 程序配置等信息等。
系统初始化脚本类,包括/etc/init.d 和/etc/rc/init.d 等文件,它们包含一些系统服务类 程序及系统启动脚本。
根文件系统对挂载文件系统的配置主要由两个文件决定,即fstab、init.d/rcS[3],fstab 描述了当前系统中已被定义好的可以被系统挂载的文件系统,init.d/rcS 文件描述了系统启 动时将启动的命令、服务程序及将要挂载的的文件系统。
由此可见,要使 Cramfs 根文件系统能满足应用程序的读写要求,必须在系统启动 时为应用程序挂载一个可写型的文件系统,即配置/etc/fstab 及/etc/init.d/rcS 文件来挂载可写 型的文件系统。
3.2 为Crmafs文件系统添加应用程序
要发布应用程序到嵌入式系统中,须将应用程序及应用程序所需要的共享库文件一起 添加到根文件系统中。根文件系统可以根据需要定制,但这样需要花费大量时间且工作量 大;也可以修改已有的根文件系统,这样可以节省大量的时间和精力,且不易出错[4]。
以下 是以蓝海微芯LJD-2410DVK-I 嵌入式开发板所提供的root.cramfs 根文件系统为基础进行修 改和配置的,root.cramfs 是只读型的文件系统,为了能向里边加入用户应用程序,需要将其 重新挂载、压缩及解压缩成新的目录,步骤如下:
在root.cramfs 的相同目录下新建立一个目录,如myroot。
在终端中执行命令:mount -o loop root.cramfs myroot, tar –cvf myroot.tar myroot。这两条 命令的功能分别是将已有的root.cramfs 以块设备的方式挂载到myroot 并将myroot 压缩为 myroot.tar。
为不出现目录重名,将 myroot.tar 拷贝到另一目录进行解压:tar –xvf myroot.tar,解压 出来的文件夹myroot 即是即将作为根文件系统的目录,它是可读可写的。
将已经交叉编译并调试过的用户目标程序拷贝到myroot 目录下的/usr/bin 目录下,此目 录为根文件系统中为用户程序准备的目录。同时将用户程序所需要用到的关联库文件拷贝到 myroot 目录下的/usr/lib 目录下,用户程序的关联库文件可通过ldd 命令查看,ldd 命令格式 如下:
Ldd [选项] 文件
选项有-v:打印ldd 的版本号;-d:执行符号重部署,并报告缺少的目标对象(只对ELF 格式适用);-r:对目标对象和函数执行重新部署,并报告缺少的目标对象和函数(只对ELF 格式适用);-h:帮助信息。
执行如下命令来查看应用程序所关联的库:
Ldd –v 程序名
将交叉编译工具目录下的/3.4.1/arm-linux/lib 下的libgcc-s.so.*,libstdc++.so.6 复制到 myroot 目录下的/root/lib 目录下。
3.3 配置Cramfs根文件系统
为使Cramfs 能支持应用程序的写操作,需要修改文件系统的配置文件,即/etc 目录下的 文件。
(1) 修改/etc/init.d/rcS 文件
/etc/init.d/rcS 是Linux 的系统初始化脚本,修改步骤如下:
用 vi 或其它文本工具打开myroot 目录下的/etc/init.d/rcS 文件;
在文件中增加:
/bin/mount –n –t ramfs ramfs /mnt/yaffs(yaffs 是文件系统的一个目录);
/bin/mkdir /mnt/yaffs/Qtopia;
/bin/mkdir /mnt/yaffs/Qtopia/tmp。
保存并退出 vi 或文本工具。
根文件系统的配置如图 1 所示。
图1 根文件系统的配置
当系统启动并执行到系统初始化脚本/etc/init.d/rcS 时,mount 命令将/mnt/yaffs 目录挂载 为ramfs 类型的随机存储文件系统,并在此文件系统上建立Qtopia 和Qtopia/tmp 目录[5], /Qtopia/tmp 目录即为应用程序可能对文件系统进行写操作的临时文件目录,故应用程序便可 对/mnt/yaffs 目录进行读写操作,保障有读写操作要求的应用程序的正常执行。
(2) 修改/etc/profile 文件
用 vi 或其它文本工具打开myroot 目录下的/etc/profile 文件;
将 PATH 改为:PATH=/bin: /sbin: /usr/sbin: /用户程序目录名
在文件中新增以下语句:
LD_LIBRARY_PATH=/lib: /usr/lib: /用户库目录名
export PATH LD_LIBRARY_PATH
保存并退出 vi 或文本工具。
其中,修改环境变量 PATH 的目的是使系统命令/程序目录扩展到用户程序目录,这样, 当执行用户应用程序时,系统才能找到相应的共享文件等;修改LD_LIBRARY_PATH 的目的是将系统的共享库路径扩展为包含系统程序和用户程序库文件路径的库文件路径,以便在 运行用户程序时能使系统找到应用程序所使用的库文件。
4 制做Cramfs 根文件系统
制做Cramfs 根文件系统,即是把上述配置好的myroot 目录文件夹压缩成为能够让Linux 内核支持的Cramfs 格式的映像文件[6]。
制做 Cramfs 根文件系统需要用到mkcramfs 工具,mkcramfs 工具用来创建Cramfs 文件系统,它能把配置好的根文件系统压缩成Cramfs 格式的根文件系统,压缩比可达到2:
1,下面是mkcramfs 命令的格式:
mkcramfs [-h] [-e edition] [-i file] [-n name] dirnAME outfile
其中参数含义分别是-h:显示帮助信息;-e edition:设置生成的文件系统中的版本 号;-i file:将一个文件映象插入到文件系统中(只能在Linux2.4.0 以后的内核版本中使用); -n name:设定Cramfs 文件系统的名称;dirname:指明需要被压缩的整个目录树;outfile: 最终输出的文件。
将mkcramfs 工具拷贝到myroot 相同目录下,在终端中执行:
mkcramfs myroot myroot.cramfs
此命令所生成的myroot.cramfs 即为可下载到开发板上的根文件系统。
5 结束语
通过对嵌入式Linux 根文件系统结构特点的分析,提出了基于Cramfs 根文件系统配置 的新方法,使嵌入式根文件系统具有了可读、可写的功能,同时也减小了根文件系统所占的 存储空间。