嵌入式系统文件系统比较 jffs2, yaffs, cramfs, romfs, ramdisk, ramfs/tmpfs
Linux 支持多种文件系统,包括ext2、ext3、vfat、ntfs、iso9660、jffs、romfs和nfs等,为了对各类文件系统进行统一管理,Linux引入了虚拟文件系统VFS(Virtual File System),为各类文件系统提供一个统一的操作界面和应用编程接口。Linux启动时,第一个必须挂载的是根文件系统;若系统不能从指定设备上挂载根文件系统,则系统
Linux 支持多种文件系统,包括ext2、ext3、vfat、ntfs、iso9660、jffs、romfs和nfs等,为了对各类文件系统进行统一管理,Linux引入了虚拟文件系统VFS(Virtual File System),为各类文件系统提供一个统一的操作界面和应用编程接口。
Linux启动时,第一个必须挂载的是根文件系统;若系统不能从指定设备上挂载根文件系统,则系统会出错而退出启动。之后可以自动或手动挂载其他的文件系统。因此,一个系统中可以同时存在不同的文件系统。
不同的文件系统类型有不同的特点,因而根据存储设备的硬件特性、系统需求等有不同的应用场合。在嵌入式Linux应用中,主要的存储设备为 RAM(DRAM, SDRAM)和ROM(常采用FLASH存储器),常用的基于存储设备的文件系统类型包括:jffs2, yaffs, cramfs, romfs, ramdisk, ramfs/tmpfs等。
1. 基于FLASH的文件系统
Flash(闪存)作为嵌入式系统的主要存储媒介,有其自身的特性。Flash的写入操作只能把对应位置的1修改为0,而不能把0修改为1(擦除Flash就是把对应存储块的内容恢复为1),因此,一般情况下,向Flash写入内容时,需要先擦除对应的存储区间,这种擦除是以块(block)为单位进行的。
闪存主要有NOR和NAND两种技术(简单比较见附录)。Flash存储器的擦写次数是有限的,NAND闪存还有特殊的硬件接口和读写时序。因此,必须针对Flash的硬件特性设计符合应用要求的文件系统;传统的文件系统如ext2等,用作Flash的文件系统会有诸多弊端。
在嵌入式Linux下,MTD(Memory Technology Device,存储技术设备)为底层硬件(闪存)和上层(文件系统)之间提供一个统一的抽象接口,即Flash的文件系统都是基于MTD驱动层的(参见上面的Linux下的文件系统结构图)。使用MTD驱动程序的主要优点在于,它是专门针对各种非易失性存储器(以闪存为主)而设计的,因而它对Flash有更好的支持、管理和基于扇区的擦除、读/写操作接口。
顺便一提,一块Flash芯片可以被划分为多个分区,各分区可以采用不同的文件系统;两块Flash芯片也可以合并为一个分区使用,采用一个文件系统。即文件系统是针对于存储器分区而言的,而非存储芯片。
(1) jffs2
JFFS文件系统最早是由瑞典 Axis Communications公司基于Linux2.0的内核为嵌入式系统开发的文件系统。JFFS2是RedHat公司基于JFFS开发的闪存文件系统,最初是针对RedHat公司的嵌入式产品eCos开发的嵌入式文件系统,所以JFFS2也可以用在Linux, uCLinux中。
Jffs2: 日志闪存文件系统版本2 (Journalling Flash FileSystem v2)
主要用于NOR型闪存,基于MTD驱动层,特点是:可读写的、支持数据压缩的、基于哈希表的日志型文件系统,并提供了崩溃/掉电安全保护,提供“写平衡”支持等。缺点主要是当文件系统已满或接近满时,因为垃圾收集的关系而使jffs2的运行速度大大放慢。
目前jffs3正在开发中。关于jffs系列文件系统的使用详细文档,可参考MTD补丁包中mtd-jffs-HOWTO.txt。
jffsx不适合用于NAND闪存主要是因为NAND闪存的容量一般较大,这样导致jffs为维护日志节点所占用的内存空间迅速增大,另外,jffsx文件系统在挂载时需要扫描整个FLASH的内容,以找出所有的日志节点,建立文件结构,对于大容量的NAND闪存会耗费大量时间。
(2) yaffs:Yet Another Flash File System
yaffs/yaffs2是专为嵌入式系统使用NAND型闪存而设计的一种日志型文件系统。与jffs2相比,它减少了一些功能(例如不支持数据压缩),所以速度更快,挂载时间很短,对内存的占用较小。另外,它还是跨平台的文件系统,除了Linux和eCos,还支持WinCE, pSOS和ThreadX等。
yaffs/yaffs2自带NAND芯片的驱动,并且为嵌入式系统提供了直接访问文件系统的API,用户可以不使用Linux中的MTD与VFS,直接对文件系统操作。当然,yaffs也可与MTD驱动程序配合使用。
yaffs与yaffs2的主要区别在于,前者仅支持小页(512 Bytes) NAND闪存,后者则可支持大页(2KB) NAND闪存。同时,yaffs2在内存空间占用、垃圾回收速度、读/写速度等方面均有大幅提升。
(3) Cramfs:Compressed ROM File System
Cramfs是Linux的创始人Linus Torvalds参与开发的一种只读的压缩文件系统。它也基于MTD驱动程序。
在cramfs文件系统中,每一页(4KB)被单独压缩,可以随机页访问,其压缩比高达2:1,为嵌入式系统节省大量的Flash存储空间,使系统可通过更低容量的FLASH存储相同的文件,从而降低系统成本。
Cramfs文件系统以压缩方式存储,在运行时解压缩,所以不支持应用程序以XIP(eXecute In Place,芯片内执行)方式运行,所有的应用程序要求被拷到RAM里去运行,但这并不代表比Ramfs需求的RAM空间要大一点,因为Cramfs是采用分页压缩的方式存放档案,在读取档案时,不会一下子就耗用过多的内存空间,只针对目前实际读取的部分分配内存,尚没有读取的部分不分配内存空间,当我们读取的档案不在内存时,Cramfs文件系统自动计算压缩后的资料所存的位置,再即时解压缩到RAM中。
另外,它的速度快,效率高,其只读的特点有利于保护文件系统免受破坏,提高了系统的可靠性。
由于以上特性,Cramfs在嵌入式系统中应用广泛。
但是它的只读属性同时又是它的一大缺陷,使得用户无法对其内容对进扩充。
Cramfs映像通常是放在Flash中,但是也能放在别的文件系统里,使用loopback设备可以把它安装别的文件系统里。
(4) Romfs
传统型的Romfs文件系统是一种简单的、紧凑的、只读的文件系统,不支持动态擦写保存,按顺序存放数据,因而支持应用程序以 XIP(eXecute In Place,片内运行)方式运行,在系统运行时,节省RAM空间。uClinux系统通常采用Romfs文件系统。
其他文件系 统:fat/fat32也可用于实际嵌入式系统的扩展存储器(例如PDA, Smartphone, 数码相机等的SD卡),这主要是为了更好的与最流行的Windows桌面操作系统相兼容。ext2也可以作为嵌入式Linux的文件系统,不过将它用于 FLASH闪存会有诸多弊端。
2. 基于RAM的文件系统
(1) Ramdisk
Ramdisk是将一部分固定大小的内存当作分区来使用。它并非一个实际的文件系统,而是一种将实际的文件系统装入内存的机制,并且可以作为根文件系统。将一些经常被访问而又不会更改的文件(如只读的根文件系统)通过Ramdisk放在内存中,可以明显地提高系统的性能。
在Linux的启动阶段,initrd提供了一套机制,可以将内核映像和根文件系统一起载入内存。
(2)ramfs/tmpfs
Ramfs是Linus Torvalds开发的一种基于内存的文件系统,工作于虚拟文件系统(VFS)层,不能格式化,可以创建多个,在创建时可以指定其最大能使用的内存大小。(实际上,VFS本质上可看成一种内存文件系统,它统一了文件在内核中的表示方式,并对磁盘文件系统进行缓冲。)
Ramfs/tmpfs文件系统把所有的文件都放在RAM中,所以读/写操作发生在RAM中,可以用ramfs/tmpfs来存储一些临时性或经常要修改的数据,例如/tmp和/var目录,这样既避免了对Flash存储器的读写损耗,也提高了数据读写速度。
Ramfs/tmpfs相对于传统的Ramdisk的不同之处主要在于:不能格式化,文件系统大小可随所含文件内容大小变化。
Tmpfs的一个缺点是当系统重新引导时会丢失所有数据。
3. 网络文件系统NFS (Network File System)
NFS是由Sun开发并发展起来的一项在不同机器、不同操作系统之间通过网络共享文件的技术。在嵌入式Linux系统的开发调试阶段,可以利用该技术在主机上建立基于NFS的根文件系统,挂载到嵌入式设备,可以很方便地修改根文件系统的内容。
以上讨论的都是基于存储设备的文件系统(memory-based file system),它们都可用作Linux的根文件系统。实际上,Linux还支持逻辑的或伪文件系统(logical or pseudo file system),例如procfs(proc文件系统),用于获取系统信息,以及devfs(设备文件系统)和sysfs,用于维护设备文件。
附录:NOR闪存与NAND闪存比较
NOR FLASH NAND FLASH
接口时序同SRAM,易使用地址/数据线复用,数据位较窄
读取速度较快读取速度较慢
擦除速度慢,以64-128KB的块为单位擦除速度快,以8-32KB的块为单位
写入速度慢(因为一般要先擦除)写入速度快
随机存取速度较快,支持XIP(eXecute In Place,芯片内执行),适用于代码存储。在嵌入式系统中,常用于存放引导程序、根文件系统等。顺序读取速度较快,随机存取速度慢,适用于数据存储(如大容量的多媒体应用)。在嵌入式系统中,常用于存放用户文件系统等。
单片容量较小,1-32MB单片容量较大,8-128MB,提高了单元密度
最大擦写次数10万次最大擦写次数100万次
RamFS/TmpFS文件系统
RamFS/TmpFS(以下简称RamFS)是Linus Torvalds开发的一种基于内存的文件系统,工作于虚拟文件系统层(VFS),不能格式化啊,可以创建多个,在创建时可以指定最大能使用的内存大小,并且读写。
当Linux运行于嵌入式设备上市,许多守护进程会在后台运行并生成许多日志消息。另外,内核日志记录机制,像syslogd、dmesg和 klogd,会在 /var和/tmp 目录下生成许多消息。由于这些进程长生了大量数据,而且只是为了记录系统当前的执行状态,在重新引导之后就丢弃了这些信息,所有如果解决这个问题的比较好的方案是使用RamFS。
RamFS 文件系统把所有的文件都放在 RAM中,所以读/写操作发生在RAM中,可以用RamFS来存储一些临时性或经常要修改的数据,例如 /tmp和/var 目录,这样既避免了对Flash存储器的读写损耗,也提高了数据读写速度。
RamFS 相对于传统的Ramdisk的不同之处主要在于:不能格式化,文件系统大小可以随所含文件内容大小变化。RamFS相对于传统的 Ramdisk 的优点包括:
> 动态文件系统大小。文件系统大小可以根据被复制、创建或删除的文件及目录的数据来缩放,使得能够以最理想的方式使用内存;
> 速度。因为RamFS驻留在RAM,所以读和写几乎都是瞬时的。即使以交换的形式存储文件,I/O操作的速度仍非常快。
同样,RamFS在系统重新引导时会丢失所有数据。因此,需要长期保存的数据不能存储在RamFS上。
如果Linux内核已经支持了RamFS,那么就可以随时可以使用RamFS了。创建一个目录,加载RamFS 到该目录即可。
与EXT2和 JFFS2 等大多数其他文件系统都驻留在块设备之上不同,RamFS直接位于VFS 上。因而,挂载 RamFS文件系统的命令略有不同。如下所示:
$ mkdir /mnt/Ramfs
$ mount -t ramfs none /mnt/Ramfs
注意RamFS没有对应的dev 目录下的设备文件。
默认情况下,RamFS被限制最多可使用的内存大小的一半。可以通过 maxsize(以KB 为单位)选项来改变。如:
$ mount -t ramfs none /mnt/Ramfs -o maxsize=2000
这个命令创建了一个限定最大使用内存为2M的Ramdisk。
在 /etc/rc.d文件中,常常能看到这样的内容:
$mount -t tmpfs /var -o size=512K
$mkdir -p /var/tmp
$mkdir -p /var/log
$ln -s /var/tmp /tmp
这段命令将在 /var上创建的 RamFS 并将RamFS 的最大大小限制为512K。同时,tmp/和 log/ 目录成为 RmpFS 的一部分以便在RAM中存储日志消息。可见 RamFS还是相当实用的一种Ramdisk。
如果想将 RamFS的一项添加在 /etc/fstab,那么它可能看起来像这样:
tmpfs /var tmpfs size=32m 0 0
这将在 /var上挂载一个新的 RamFS 文件系统。
UBI文件系统简介 收藏
在linux-2.6.27以前,谈到Flash文件系统,大家很多时候多会想到cramfs、jffs2、yaffs2等文件系统。它们也都是基于文件系统+mtd+flash设备的架构。linux-2.6.27后,内核加入了一种新型的flash文件系统UBI(Unsorted Block Images)。这里简单介绍下UBI文件系统加入的原因,及使用方法。我也是刚接触到这个文件系统,可能有理解不对的地方,也请指正。
一、产生的背景
FLASH具有的“先擦除再写入”、坏块、“有限的读写次数”等特性,目前管理FLASH的方法主要有:
1、采用MTD+FTL/NFTL(flash 转换层/nand flash转换层)+ 传统文件系统,如:FAT、ext2等。FTL/NFTL的使用就是针对FLASH的特有属性,通过软件的方式来实现日志管理、坏块管理、损益均衡等技术。但实践证明,由于知识产权、效率等各方面因素导致本方案有一定的局限性。
2、采用硬件翻译层+传统文件系统的方案。这种方法被很多存储卡产品采用,如:SD卡、U盘等。这种方案对于一些产品来说,成本较高。
3、采用MTD+ FLASH专用文件系统,如JFFS1/2,YAFFS1/2等。它们大大提高了FLASH的管理能力,并被广泛应用。
JFFS2、YAFFS2等专用文件系统也存在着一些技术瓶颈,如:内存消耗大,对FLASH容量、文件系统大小、内容、访问模式等的线性依赖,损益均衡能力差或过渡损益等。在此背景下内核加入了UBI文件系统的支持。
二、用法
环境:omap3530处理器、 (128MByte 16 位NAND Flash) 、linnux-2.6.28内核
1、配置内核支持UBIFS
Device Drivers --->Memory Technology Device (MTD) support --->UBI - Unsorted block images --->Enable UBI
配置mtd支持UBI接口
File systems --->Miscellaneous filesystems --->UBIFS file system support
配置内核支持UBIFS文件系统
2、将一个MTD分区4挂载为UBIFS格式
● flash_eraseall /dev/mtd4 //擦除mtd4
● ubiattach /dev/ubi_ctrl -m 4 //和mtd4关联
● ubimkvol /dev/ubi0 -N rootfs -s 100MiB //设定volume 大小(不是固定值,可以用工具改变)及名称
● mount -t ubifs ubi0_0 /mnt/ubi或mount -t ubifs ubi0:rootfs /mnt/ubi
3、制作UBIFS文件系统
在制作UBI镜像时,需要首先确定以下几个参数:
MTD partition size; //对应的FLASH分区大小
flash physical eraseblock size; // FLASH物理擦除块大小
minimum flash input/output unit size; //最小的FLASH输入输出单元大小
for NAND flashes - sub-page size; //对于nand flash来说,子页大小
logical eraseblock size.//逻辑擦除块大小
参数可以由几种方式得到
1)如果使用的是2.6.30以后的内核,这些信息可以通过工具从内核获得,如:mtdinfo –u。
2)之前的内核可以通过以下方法:
● MTD partition size:从内核的分区表或cat /proc/mtd获得
● flash physical eraseblock size:从flash芯片手册中可以得到FLASH物理擦除块大小,或cat /proc/mtd
● minimum flash input/output unit size:
1)nor flash:通常是1个字节
2)nand falsh:一个页面
● sub-page size:通过flash手册获得
● logical eraseblock size:对于有子页的NAND FLASH来说,等于“物理擦除块大小-1页的大小”
3)也可以通过ubi和mtd连接时的产生的信息获取,如:
#modprobe ubi mtd=4 //ubi作为模块加载
或
#ubiattach /dev/ubi_ctrl -m 4 //通过ubiattach关联MTD
UBI: attaching mtd4 to ubi0
UBI: physical eraseblock size: 131072 bytes (128 KiB)
UBI: logical eraseblock size: 129024 bytes
UBI: smallest flash I/O unit: 2048
UBI: sub-page size: 512
UBI: VID header offset: 512 (aligned 512)
UBI: data offset: 2048
UBI: attached mtd4 to ubi0
更详细的解释参见http://www.linux-mtd.infradead.org/doc/ubi.html#L_overhead
#mkfs.ubifs -r rootfs -m 2048 -e 129024 -c 812 -o ubifs.img
#ubinize -o ubi.img -m 2048 -p 128KiB -s 512 /home/lht/omap3530/tools/ubinize.cfg
-r:制定文件内容的位置
-m:页面大小
-e:逻辑擦除块大小
-p:物理擦除块大小
-c:最大的逻辑擦除块数量
对我们这种情况,文件系统最多可以访问卷上的129024*812=100M空间
-s:最小的硬件输入输出页面大小,如:k9f1208为256(上下半页访问)
其中,ubinize.cfg的内容为:
[ubifs]
mode=ubi
image=ubifs.img
vol_id=0
vol_size=100MiB
vol_type=dynamic
vol_name=rootfs
vol_flags=autoresize
4、利用uboot烧写、启动UBIFS镜像
1)烧写UBIFS镜像
OMAP3 DevKit8000 # mmcinit
OMAP3 DevKit8000 # fatload mmc 0:1 81000000 ubi.img
reading ubi.img
12845056 bytes read
OMAP3 DevKit8000 # nand unlock
device 0 whole chip
nand_unlock: start: 00000000, length: 268435456!
NAND flash successfully unlocked
OMAP3 DevKit8000 # nand ecc sw
OMAP3 DevKit8000 # nand erase 680000 7980000
NAND erase: device 0 offset 0x680000, size 0x7980000
Erasing at 0x7fe0000 -- 100% complete.
OK
OMAP3 DevKit8000 # nand write.i 81000000 680000 $(filesize)
NAND write: device 0 offset 0x680000, size 0xc40000
Writing data at 0x12bf800 -- 100% complete.
12845056 bytes written: OK
烧写过程和烧写内核镜像的过程一致,所以UBI文件系统应该不像yaffs文件系统那样用到了nand的OOB区域。
2)设置UBIFS文件系统作为根文件系统启动的参数
OMAP3 DevKit8000 # setenv bootargs console=ttyS2,115200n8 ubi.mtd=4 root=ubi0:rootfs
rootfstype=ubifs video=omapfb:mode:4.3inch_LCD
OMAP3 DevKit8000 # setenv bootcmd nand read.i 80300000 280000 200000/;bootm 80300000
根文件系统的位置在MTD4上
系统启动时会打印出如下和UBI相关的信息:
Creating 5 MTD partitions on "omap2-nand":
0x00000000-0x00080000 : "X-Loader"
0x00080000-0x00260000 : "U-Boot"
0x00260000-0x00280000 : "U-Boot Env"
0x00280000-0x00680000 : "Kernel"
0x00680000-0x08000000 : "File System"
UBI: attaching mtd4 to ubi0
UBI: physical eraseblock size: 131072 bytes (128 KiB)
UBI: logical eraseblock size: 129024 bytes
UBI: smallest flash I/O unit: 2048
UBI: sub-page size: 512
UBI: VID header offset: 512 (aligned 512)
UBI: data offset: 2048
UBI: attached mtd4 to ubi0
UBI: MTD device name: "File System"
UBI: MTD device size: 121 MiB
UBI: number of good PEBs: 970
UBI: number of bad PEBs: 2
UBI: max. allowed volumes: 128
UBI: wear-leveling threshold: 4096
UBI: number of internal volumes: 1
UBI: number of user volumes: 1
UBI: available PEBs: 0
UBI: total number of reserved PEBs: 970
UBI: number of PEBs reserved for bad PEB handling: 9
UBI: max/mean erase counter: 2/0
以上是从网络下载下来的关于ubifs的操作方法,有一定的参考价值。
以下是从marvell获得操作文档。
Building the mtd-utils
======================
For Debian distribution, you need the following packages installed for
building the head snapshot of mtd-utils,
uuid-dev
liblzo2-dev
libz-dev
Extract the latest snapshot of mtd-utils and go into the sub directory of
'mkfs.ubifs' and then type 'make' to build the mkfs.ubifs utility. Once it
is done, go up one directory and then go into the sub directory 'ubi-tuils'.
Inside that directory, type 'make' again to make the rest of ubi utilities
(ubinfo, ubinize, ubiformat, etc.).
How to find out min. I/O unit size, sub-page size, etc
======================================================
The easiest way to find this out is to attach your MTD device to UBI and
glance to the syslog/dmesg output (erase the MTD device before doing this).
The newest UBI prints something like this:
UBI: attaching mtd0 to ubi0
UBI: physical eraseblock size: 262144 bytes (256 KiB)
UBI: logical eraseblock size: 258048 bytes
UBI: smallest flash I/O unit: 2048
UBI: VID header offset: 2048 (aligned 2048)
UBI: data offset: 4096
UBI: empty MTD device detected
UBI: create volume table (copy #1)
UBI: create volume table (copy #2)
UBI: attached mtd0 to ubi0
UBI: MTD device name: "rootfs"
UBI: MTD device size: 2048 MiB
UBI: number of good PEBs: 8183
UBI: number of bad PEBs: 9
UBI: max. allowed volumes: 128
UBI: wear-leveling threshold: 4096
UBI: number of internal volumes: 1
UBI: number of user volumes: 0
UBI: available PEBs: 8098
UBI: total number of reserved PEBs: 85
UBI: number of PEBs reserved for bad PEB handling: 81
UBI: max/mean erase counter: 0/0
UBI: background thread "ubi_bgt0d" started, PID 254
How to attach an MTD device
===========================
If UBI is compiled into the kernel, the mtd device to attach may be specified
in the ubi.mtd=kernel boot parameter, e.g.,
ubi.mtd=0
(For attaching the first MTD device)
How to Mount a UBI device
=========================
First, you need to create a user volume on the UBI device.
ubimkvol /dev/ubi0 -n 0 -N rootfs -s 4096MiB
The above commands will only work after the correct kernel boot parameter is
specified. Once the user volume is created, you may use the following command
to mount it,
mount -t ubifs ubi0:rootfs /mnt
If there is no need to keep the user volume, you may use the following command
to delete it,
ubirmvol /dev/ubi0 -n 0
How to create UBI images
========================
First, you need to use the mkfs.ubifs utility to create a volume for your root
file system,
mkfs.ubifs -m 2KiB -e 258048 -x lzo -c 8000 -d foxes-rootfs-20081128/ -o system_ubifs.img
(The above command must have root previledge)
Then use the ubinize utility to combine all the volumes you need into a UBI
image,
ubinize -o system_ubi.img -m 2KiB -p 256KiB -s 2KiB ubinize.cfg
In the ubinize.cfg, the following items are specified,
# Section header
[rootfs]
# Volume mode (other option is static)
mode=ubi
# Source image
image=system_ubifs.img
# Volume ID in UBI image
vol_id=0
# Volume size
vol_size=1900MiB
# Allow for dynamic resize
vol_type=dynamic
# Volume name
vol_name=rootfs
# Autoresize volume at first mount
vol_flags=autoresize
How to flash UBI images (and preserve erase counters)
=====================================================
First, you need to detach the ubi device by using the follwing command if the
ubi device is attached,
ubidetach /dev/ubi_ctrl -d 0
The, use the ubiformat utility.
ubiformat /dev/mtd0 -f system_ubi.img
How to use UBIFS as the root file system
========================================
You must specify the following text in the kernel boot parameter,
ubi.mtd=0 root=ubi0:rootfs rootfstype=ubifs rw mtdparts=cafe_nand:2G(rootfs)
More Infromation
================
You may obtain more information at the following web sites,
(1) UBI FAQ and HOWTO (Memory Technology Device (MTD) Subsystem for Linux)
http://www.linux-mtd.infradead.org/faq/ubi.html
(2) UBIFS initial experiments (OLPC)
http://wiki.laptop.org/go/UBIFS_initial_experiments
两者虽有重复的地方,却有互有补充的地方。
以上的指导,可以应付大部分的应用层操作了。
更多推荐
所有评论(0)