Yaffs文件系统结构

1         Yaffs 文件系统结构

 

1.1        简介

1.1.1           应用场合

Yaffs Yet Another Flash File System )文件系统是专门针对 NAND 闪存设计的嵌入式文件系统 目前有 YAFFS YAFFS2 两个版本 两个版本的主要区别之一在于 YAFFS2 能够更好的支持大容量的 NAND FLASH 芯片。

Yaffs 文件系统有些类似于 JFFS/JFFS2 文件系统,与之不同的是 JFFS1/2 文件系统最初是针对 NOR FLASH 的应用场合设计的,而 NOR FLASH NAND FLASH 本质上有较大的区别,所以尽管 JFFS1/2 文件系统也能应用于 NAND FLASH ,但由于它在内存占用和启动时间方面针对 NOR 的特性做了一些取舍,所以对 NAND 来说通常并不是最优的方案。

1.1.2           NOR NAND 的比较

基本上 NOR 比较适合存储程序代码,其容量一般较小(比如小于 32MB ),价格较高,而 NAND 容量可达 1GB 以上,价格也相对便宜,适合存储数据。一般来说, 128MB 以下容量 NAND FLASH 芯片的一页大小为 528 字节,用来存放数据,另外每一页还有 16 字节的备用空间( SpareData,OOB ),用来存储 ECC 校验 / 坏块标志等信息,再由若干页组成一个块,通常一块为 32 16K 。以前的 nand flash

Pagesize 页大小,多为 512B+16B oob block 大小为 64* 512B+16B =32KB+1KB

现在目前市场上见到的,绝大多数,都是新的 nand falsh ,其 Pagesize 页大小多为 2KB+64B oob block 大小多为 64pages =64* 2K+64B =128KB+4KB ,一个 nand flash 中的芯片,一般含有 4096 个块,比如 samsung K9F4G08U0M ,所以这个 nand flash 大小就是

4096 Blocks = 4096 * 64 * 2K+64B =512MB

即:

1 Page = (2K + 64)Bytes

1 Block = (2K + 64)B x 64 Pages

= (128K + 4K) Bytes

1 Device = (2K+64)B x 64Pages x 4,096 Blocks

= 4,224 Mbits =512MB

NOR 相比, NAND 不是完全可靠的,每块芯片出厂时都有一定比例的坏块存在,对数据的存取不是使用地址映射而是通过寄存器的操作,串行存取数据。

1.2        Yaffs 文件系统数据在 NAND 上的存储方式

Yaffs 对文件系统上的所有内容(比如正常文件,目录,链接,设备文件等等)都统一当作文件来处理,每个文件都有一个页面专门存放文件头,文件头保存了文件的模式、所有者 id 、组 id 、长度、文件名、 Parent Object ID 等信息。因为需要在一页内放下这些内容,所以对文件名的长度,符号链接对象的路径名等长度都有限制。

前面说到对于 NAND FLASH 上的每一页数据,都有额外的空间用来存储附加信息,通常 NAND 驱动只使用了这些空间的一部分, Yaffs 正是利用了这部分空间中剩余的部分来存储文件系统相关的内容。以 512+16B 为一个 PAGE NAND FLASH 芯片为例 ,Yaffs 文件系统数据的存储布局如下所示:

 

0..511

数据区域

512..515

YAFFS TAG

516

Data status byte

517

Block status byte 坏块标志位

518..519

YAFFS TAG

520..522

256 字节数据的 ECC 校验结果

523..524

YAFFS TAG

525..527

256 字节数据的 ECC 校验结果

 

可以看到在这里 YAFFS 一共使用了 8 BYTE 用来存放文件系统相关的信息( yaffs_Tags )。这 8 Byte 的具体使用情况按顺序如下:

Bits

Content

20

ChunkID ,该 page 在一个文件内的索引号,所以文件大小被限制在 2^20 PAGE 512Mb

2

2 bits serial number

10

ByteCount page 内的有效字节数

18

ObjectID 对象 ID 号,用来唯一标示一个文件

12

Ecc, Yaffs_Tags 本身的 ECC 校验和

2

Unused

 

512 byte pagesize

OffsetContentComment
0x00ECC byte 0Error correction code byte 0 of the lower 256 Byte data in this page
0x01ECC byte 1Error correction code byte 1 of the lower 256 Bytes of data in this page
0x02ECC byte 2Error correction code byte 2 of the lower 256 Bytes of data in this page
0x03ECC byte 3Error correction code byte 0 of the upper 256 Bytes of data in this page
0x04reservedreserved
0x05Bad block markerIf any bit in this byte is zero, then this block is bad. This applies only to the first page in a block. In the remaining pages this byte is reserved
0x06ECC byte 4Error correction code byte 1 of the upper 256 Bytes of data in this page
0x07ECC byte 5Error correction code byte 2 of the upper 256 Bytes of data in this page
0x08 - 0x0FAutoplace 0 - 7 

2048 byte pagesize

OffsetContentComment
0x00Bad block markerIf any bit in this byte is zero, then this block is bad. This applies only to the first page in a block. In the remaining pages this byte is reserved
0x01ReservedReserved
0x02-0x27Autoplace 0 - 37 
0x28ECC byte 0Error correction code byte 0 of the first 256 Byte data in this page
0x29ECC byte 1Error correction code byte 1 of the first 256 Bytes of data in this page
0x2AECC byte 2Error correction code byte 2 of the first 256 Bytes data in this page
0x2BECC byte 3Error correction code byte 0 of the second 256 Bytes of data in this page
0x2CECC byte 4Error correction code byte 1 of the second 256 Bytes of data in this page
0x2DECC byte 5Error correction code byte 2 of the second 256 Bytes of data in this page
0x2EECC byte 6Error correction code byte 0 of the third 256 Bytes of data in this page
0x2FECC byte 7Error correction code byte 1 of the third 256 Bytes of data in this page
0x30ECC byte 8Error correction code byte 2 of the third 256 Bytes of data in this page
0x31ECC byte 9Error correction code byte 0 of the fourth 256 Bytes of data in this page
0x32ECC byte 10Error correction code byte 1 of the fourth 256 Bytes of data in this page
0x33ECC byte 11Error correction code byte 2 of the fourth 256 Bytes of data in this page
0x34ECC byte 12Error correction code byte 0 of the fifth 256 Bytes of data in this page
0x35ECC byte 13Error correction code byte 1 of the fifth 256 Bytes of data in this page
0x36ECC byte 14Error correction code byte 2 of the fifth 256 Bytes of data in this page
0x37ECC byte 15Error correction code byte 0 of the sixt 256 Bytes of data in this page
0x38ECC byte 16Error correction code byte 1 of the sixt 256 Bytes of data in this page
0x39ECC byte 17Error correction code byte 2 of the sixt 256 Bytes of data in this page
0x3AECC byte 18Error correction code byte 0 of the seventh 256 Bytes of data in this page
0x3BECC byte 19Error correction code byte 1 of the seventh 256 Bytes of data in this page
0x3CECC byte 20Error correction code byte 2 of the seventh 256 Bytes of data in this page
0x3DECC byte 21Error correction code byte 0 of the eigth 256 Bytes of data in this page
0x3EECC byte 22Error correction code byte 1 of the eigth 256 Bytes of data in this page
0x3FECC byte 23Error correction code byte 2 of the eigth 256 Bytes of data in this page

其中 Serial Number 在文件系统创建时都为 0 ,以后每次写具有同一 ObjectID ChunkID page 的时候都加一,因为 Yaffs 在更新一个 PAGE 的时候总是在一个新的物理 Page 上写入数据,再将原先的物理 Page 删除,所以该 serial number 可以在断电等特殊情况下,当新的 page 已经写入但老的 page 还没有被删除的时候用来识别正确的 Page ,保证数据的正确性。

ObjectID 号为 18bit ,所以文件的总数限制在 256K 26 万个左右。

最后以上这些是针对 Yaffs1 而言,对于 Yaffs2 因为针对 chunk size 大于 1k NAND FLASH ,在 Tags 各分量及总体尺寸上都做了修改,以便更快更好的处理大容量的 NAND FLASH 芯片。由于 Tag 尺寸的增大,在 512+16B 类型的 NAND FLASH 上就一个 Trunk 对应一个 page 的情况,目前就无法使用 Yaffs2 文件系统了。

由于文件系统的基本组织信息保存在页面的备份空间中,因此,在文件系统加载时只需要扫描各个页面的备份空间,即可建立起整个文件系统的结构,而不需要像 JFFS1/2 那样扫描整个介质,从而大大加快了文件系统的加载速度。

1.3        yaffs 文件系统在内存中的组织方式

1.3.1           SupperBlock

操作文件系统的第一步自然是取得 SuperBlock 了, Yaffs 文件系统本身在 NAND Flash 上并不存在所谓的 SuperBlock 块,完全是在文件系统 mount 的过程中由 read_super 函数填充的,不过有意思的一点是,由于物理上没有存储 superblock 块,所以 NAND Flash 上的 yaffs 文件系统本身没有存储 filesystem 的魔数( MagicNum ),在内存中 superblock 里的 s_magic 参数也是直接赋值的,所以存储在 NAND FLASH 上的任何文件系统都能被当作 yaffs 文件系统 mount 上来,只是数据都会被当作错误数据放在 lost+found 目录中,不知道这算不算 yaffs 文件系统的一个 bug

通常一个具体的文件系统在 VFS Super_block 结构中除了通用的数据外,还有自己专用的数据, Yaffs 文件系统的专用数据是一个 yaffs_DeviceStruct 结构,主要用来存储一些相关软硬件配置信息,相关函数指针和统计信息等。

1.3.2           文件在内存中的组织方式

mount 过程执行 read_super 的过程中, Yaffs 文件系统还需要将文件系统的目录结构在内存中建立起来。由于没有 super 块,所以需要扫描 Yaffs 分区,根据从 OOB 中读取出的 yaffs_tags 信息判断出是文件头 page 还是数据 page 。再根据文件头 page 中的内容以及数据 page 中的 ObjectID/ChunkID/serial Number 等信息在内存中为每个文件( Object )建立一个对应的 yaffs_object 对象。

yaffs_object 结构中,主要包含了:

Ø       如修改时间,用户 ID ,组 ID 等文件属性;

Ø       用作 yaffs 文件系统维护用的各种标记位如脏( dirty )标记,删除标记等等;

Ø       用作组织结构的,如指向父目录的 Parent 指针,指向同级目录中其他对象链表的 siblings 双向链表头结构

此外根据 Object 类型的不同(目录,文件,链接),对应于某一具体类型的 Object ,在 Yaffs_object 中还有其各自专有的数据内容

Ø       普通文件:文件尺寸,用于快速查找文件数据块的 yaffs_Tnode 树的指针等

Ø       目录:目录项内容双向链表头( children

Ø       链接: softlink alias hardlink 对应的 ObjectID

 

除了对应于存储在 NAND FLASH 上的 object 而建立起来的 yaffs_object 以外,在 read_super 执行过程中还会建立一些虚拟对象( Fake Object ),这些 Fake Object NAND FLASH 上没有对应的物理实体,比如在建立文件目录结构的最初, yaffs 会建立四个虚拟目录( Fake Directory ): rootDir, unlinkedDir, deleteDir, lostNfoundDir 分别用作根目录, unlinked 对象挂接的目录, delete 对象挂接的目录,无效或零时数据块挂接的目录。

通过创建这些 yaffs_object yaffs 文件系统就能够将存储在 NAND FLASH 上数据系统的组织起来,在内存中维护一个完整的文件系统结构。

2         Yaffs 文件系统集成及应用相关

2.1        系统移植

这里所谓移植,就是在特定的软硬件环境里编译出 yaffs 文件系统模块了。目前最新的 yaffs 版本的代码里主要是按照 2.6 内核的方式写的 Kconfig Makefile ,对于 2.4 内核来说,改起来也很简单,基本上,只需要:

 

Ø       在内核中建立 YAFFS 目录 fs/yaffs ,并把下载的 YAFFS 代码复制到该目录下面。

Ø       参考 yaffs 代码中的 Kconfig 文件 ,按照 2.4 内核的风格 修改你自己的 Config.in 文件 使得可以配置 YAFFS

Ø       修改 fs/makefile 加入 yaffs 目录

Ø       按照 2.4 内核的风格修改 YAFFS 目录中的 Makefile 文件。

 

只是在配置 YAFFS 的时候需要注意一点,即使你的 NAND FLASH 512+16B 的,不需要使用 YAFFS2 ,也需要将对 2k page NAND FLASH 的支持这一项选上,否则编译无法通过(因为部分代码没有用 CONFIG 宏包起来),不知道这是不是我下载的这个版本的个别现象,还是对 Makefile 还需要进一步的修改。

此外就是最好把 Lets Yaffs do its own ECC 选上,理由后面会说,其他选项就无所谓了,主要是对性能的调整,看着选吧,按推荐配置好了,比如 Turn off debug chunk erase check ,这一项,我试验的结果选上后平均可以提高 20-30% 左右的擦写速度。

2.2        Yaffs 文件系统的制作和使用

2.2.1           通过 Yaffs Image 文件制作 yaffs 文件系统

Yaffs 源代码包的 utils 目录下包含了 mkyaffsimage/mkyaffs2image 的代码,简单的修改一下 Makefile 里的内核路径就能编译出 mkyaffsimage/mkyaffs2image 工具。

运行 mkyaffsimage dir imagename 可以制作出 yaffs1 文件系统的镜像。

但是,需要注意的是,制作出来的 yaffs image 文件与通常的文件系统的 image 文件不同,因为在 image 文件里除了以 512 字节为单位的一个 page data 数据外,同时紧跟在后还包括了 16 字节为单位的 NAND 备份数据区( OOB )的数据。所以实际上是以 528 个字节为单位的。就是因为包含了这额外的 16 字节 /page 的数据,所以基本上常规办法如 dd ,或者通常的下载其它类型 image 的工具就无法正常下载 yaffs image 了,需要修改你所使用的下载工具的代码,使得它能将 yaffs image 中的这些额外数据也写入 NAND FLASH OOB 中。

这里还有一点需要注意的是,通过 mkyaffsimage 制做出来的 image OOB 中也包含它自己计算的 ECC 校验数据,其校验算法有可能和 MTD NAND 驱动的校验算法不同,如果在内核中由 MTD 来处理 ECC ,会造成 MTD 认为所有的 page 都校验错误。所以,这也是我前面说最好把 Lets Yaffs do its own ECC 选上的原因,同时,要把 MTD NAND 驱动中的 ECC 校验关闭。

2.2.2           其它方式制作 yaffs 文件系统

如果不考虑产线批量下载的话,也可以通过 mount 拷贝的方式准备 yaffs 文件系统。用 flash_eraseall NAND FLASH 分区擦除,然后做为 yaffs 分区直接 mount 上来,将文件系统的内容拷贝上去就可以了。这可能是在真正的 NAND FLASH 上试验 yaffs 文件系统最简单的方式了。

2.2.3           没有相应的 NAND 设备时如何测试 yaffs 文件系统

没有相应的 NAND FLASH 设备包含两种情况:

Ø       硬件上没有 NAND FLASH ,开发板上没有或者想在主机环境中测试 yaffs 文件系统

Ø       没有合适的 page size NAND FLASH 芯片,比如板上 NAND FLASH 芯片为 512+16 的格式,但是想要试验 Yaffs2 文件系统。

Yaffs 提供了两种用来在这种情况下测试 yaffs 文件系统的途径。

2.2.3.1        Nandemul

Yaffs source 包里包含了 mtdemul 目录, Yaffs2 中该目录下的文件主要是 Nandemul2k.c 用来模拟 2K page size NAND FLASH 。在 Yaffs 中则是 Nandemul.c 用来模拟 512 字节 page size NAND FLASH

稍微修改一下 Makeflie 将编译出来的模块插入内核,将在 /dev/mtd /dev/mtdblock 目录下创建一个新的 MTD 设备。然后就可以将该设备当作一个物理的 MTD NAND 设备分区进行相关的操作,可以在上面创建 yaffs 文件系统, mount umount 等等。这种方法不仅适用于 yaffs 文件系统,同样也适用于其它可用于 NAND 设备的文件系统。

2.2.3.2        Yaffsram

根据 yaffs 官方文档的描述,通过 mount –t yaffsram none /mountpoint 可以在内存中建立一个 yaffs 分区,这有些类似于 ramfs 。不过,在试验最新版本的 Yaffs2 文件系统时,该功能并不可用,只有 Yaffs1 文件系统的代码包里包含了相关的代码。

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值