收藏 分享(赏)

UBIFS文件系统说明文档.doc

上传人:tangtianxu2 文档编号:2904408 上传时间:2018-09-29 格式:DOC 页数:13 大小:43.07KB
下载 相关 举报
UBIFS文件系统说明文档.doc_第1页
第1页 / 共13页
UBIFS文件系统说明文档.doc_第2页
第2页 / 共13页
UBIFS文件系统说明文档.doc_第3页
第3页 / 共13页
UBIFS文件系统说明文档.doc_第4页
第4页 / 共13页
UBIFS文件系统说明文档.doc_第5页
第5页 / 共13页
点击查看更多>>
资源描述

1、UBIFS 文件系统说明文档注意:在了解 UBIFS 之前一定要注意到 UBIFS 和任何传统的文件系统是不一样的:UBIFS不是运行在 block device 之上的(如 hard disk,MMC/SD 卡,USB flash 等)。UBIFS 是运行于 raw flash 之上,请在开始认识 UBIFS 前确保理解 raw flash 这个概念。UBIFS 是建立在 MTD device 基础上的,而不是 block device 上的。简介:UBIFS 是由 NOKIA 工程师在赛格德大学帮助下开发的新的 Flash 文件系统,UBIFS 是JFFS2 文件系统的下一代产品。JFFS

2、2 运行在 MTD 设备之上,而 UBIFS 则只能工作于 UBI volume 之上。UBIFS 涉及三个子系统:1.MTD 子系统,提供对 Flash 芯片的访问接口,MTD 子系统提供了 MTD 设备的概念,比如/dev/mtdx,MTD 可以认为是 raw flash。2.UBI 子系统,为 Flash 设备提供了耗损均衡(wear leveling)和卷管理(volume management)功能; UBI 工作在 MTD 设备之上,提供了 UBI volume;UBI 是 MTD 设备的高层次表示,对上层屏蔽了一些直接使用 MTD 设备需要处理的问题,比如损耗均衡以及坏块管理。3

3、.UBIFS 文件系统,工作于 UBI 之上的文件系统。UBIFS 的主要特点:1.可扩展性:UBIFS 对 Flash 尺寸有着很好的扩展性,也就是说 mount 时间,内存消耗以及I/O 速度都不依赖于 Flash 的尺寸,UBIFS 可以很好的运行在 GB 级的 Flashe 设备上,当然 UBI 本身还是有扩展性的问题,但是无论如何 UBI/UBIFS 都比 JFFS2 的可扩展性好。如果 UBI 成为瓶颈,可以改进 UBI 而不需改变 UBIFS 本身。2.快速 mount:不像 JFFS2 文件系统,UBIFS 在 mount 阶段不需要扫描整个文件系统,UBIFS mount 的

4、时间只是毫秒级,时间不依赖与 Flash 的尺寸;然而 UBI 的初始化时间是依赖Flash 的尺寸的,因此必须把这个时间考虑在内。3.write back 支持:回写或者延迟写,与 JFFS2 文件系统的立即写入内存(write through)相比可以显著的提高文件系统的吞吐量。4.异常 unmount 适应度:UBIFS 是日志文件系统,可以容忍突然掉电以及 unclean 重启; UBIFS 通过 replay 日志来恢复 unclean unmount。在这种情况下 replay 会消耗一些时间,因此 mount 时间会稍微增加,但是 replay 过程并不会扫描整个 Flash 介

5、质,所以 UBIFS 的异常 mount 时间大概在几分之一秒。5.快速 I/O 操作:即使我们不使能 write back(在 unmount 时使用-o sync mount 选项),UBIFS 的性能仍然接近 JFFS2;JFFS2 的同步 I/O 是非常惊人的,因为 JFFS2 不需要在flash 上维护 indexing data 结构,所以就没有因此而带来的负担,而 UBIFS 恰恰是有index 数据的,UBIFS 之所以够快是因为 UBIFS 提交日志的方式:不是把数据从一个地方移动到另外一个位置,而只是把数据的地址加到文件系统的 index,然后选择不同的eraseblock

6、 作为新的日志块,此外还有 multi headed 日志方式等技巧。6.On the flight compression:存储在 Flash 介质上的数据是压缩的,同时也可以灵活的针对单个文件来打开关闭压缩。例如,可能需要针对某个特定的文件打开压缩;或者可能缺省方式下支持压缩,但是对多媒体文件则关闭压缩。7.可恢复性:UBIFS 可以从 index 破坏后恢复; UBIFS 中的每一片信息都用一个 header 来描述,因此可以通过扫描整个 Flash 介质来重构文件系统,这点和 JFFS2 非常类似。想像如果你擦除 FAT 文件系统的 FAT 表,对于 FAT 文件系统来说是致命的错误,

7、但是如果擦除UBIFS 的 index,你仍然可以重构文件系统,当然这需要使用一个用户空间程序来做恢复8.完整性:UBIFS 通过把 checksum 写到 flash 介质上来保证数据的完整性,UBIFS 不会无视损坏的文件数据或 meta data;缺省的情况,UBIFS 仅仅检查 meta data 的 CRC,但是你可以通过 mount 选项,强制进行 data CRC 的检查。UBIFS 的可扩展性UBIFS 文件系统的所有数据结构都是使用 tree,UBIFS 对 flash 尺寸大小在算法上是可扩展的。然而 UBI 复杂度随着 Flash size 线性增长,因此 UBI 加 U

8、BIFS 整体上是线性增大的。但是 UBIFS 的作者认为可以创建一个新的 UBI2,克服当前 UBI 的线性增长,当前的 UBI 实现适和 216GiB 大小的 raw flashes,具体大小依赖于 I/O 速度和系统需求。注意:尽管 UBI 是线性增长的,但是它的可扩展性依然好过 JFFS2,因为 JFFS2 最初是为32MiB Nor flashes 设计的。JFFS2 的扩展性问题是文件系统级的,而 UBI/UBIFS 的扩展性问题则是 raw flash 级的。UBIFS 对回写操作的支持UBIFS 支持 write back, 意味着文件的改变并不是立刻提交到 flash med

9、ia 上,而是cache 这些修改,直到达到写入的条件,这减少了 I/O 的数目因此改善 I/O 性能和系统性能。回写本身也是文件系统的标准技术,由于数据没有立刻写入 flash, 回写带来了数据丢失的风险。相反 JFFS2 不支持 write back, JFFS2 文件系统的所有变化都是立刻同步到flash 介质上。事实上,JFFS2 有一个很小的 buffer 大小是 NAND page size(如果是 NAND flash),这个 buffer 保存这最后要写的数据,一旦 buffer 写满立刻就会执行flush。 因此 JFFS2 非常类似于同步文件系统。Write back 支持

10、,需要应用程序注意及时同步重要的文件。否则掉电会导致这些文件的损坏和消失,掉电对于嵌入式系统而言是很常见的。然而一些应用空间程序并没有考虑 write back 这种情况,当这些应用运行在JFFS2 上工作良好尽管这些应用是 buggy 的,一旦运行在 UBIFS 上,bugs 就很容易重现了。所以在把 JFFS2 换作 UBIFS 后,确保检查你的应用是否正确处理掉电功能。下列是检查列表以及一些建议,这些方法对于任何文件系统都是可行的,包括 JFFS2 文件系统:1.如果你想切换到同步模式,在 mount 文件系统是使用 -o 同步选项。然而,要注意文件系统将会下降。此外,要记住 UBIFS

11、 mount 为同步模式仍然不如 JFFS2 提供更多的保证。2.一定要时刻记住运行 fsync 在你修改重要数据后;当然,没有必要 sync 临时的文件;要先考虑文件数据的重要性,不要执行没必要的 fsync,因为 fsync 操作会降低性能。3.如果你想更精确些,那么就使用 fdatasync,仅仅修改的数据被 flushed,而 inode meta data 变化不会被 flush(比如 mtime 或者 permissions)。4.你也可以在 open()调用时使用 O_SYNC 标志;这使得这个文件所修改的 data(不包括meta data)都会在 write()操作返回前写入

12、 media。通常最好使用 fsync(),而且 fsync 允许多个累积的写。5.还可以使一定数目 inodes 为同步模式,通过设置 inode 的 sync 标志;在 shell 脚本中执行 chattr +S;在 C 程序中,则可以使用 FS_IOC_SETFLAGS ioctl 命令;注意,mkfs.ubifs 工具会检查原始的 FS 树,如果文件在原始文件树是同步的,那么在 UBIFS image 也会是同步的。fsync()可能包括目录,它同步目录 inode 的 meta-data。“sync“ flag 也可以用在目录上,使得目录 inode 变成同步的。但是“sync“ f

13、lag 是可继承的,意味这这个目录下的所有新节点都有这个标志,这个目录的新文件和新子目录也就变成同步的,子目录的 child 也是如此。这个功能对于创建一个整个目录树都同步的目录是很有用的。fdatasync()调用对 UBIFS 的目录是不起作用的,因为 UBIFS 对目录项的操作都是同步的,当然不是所有文件系统都如此。“dirsync“ inode 标志对 UBIFS 也没有作用。以上提到的功能都是作用于文件描述符,而不是文件 stream(FILE *)。同步一个stream,你应该通过 libc 的 fileno()取得文件描述符,首先使用 fflush()来 flush stream

14、 ,然后调用 fsync 或者 fdatasync。你也可以使用其他的同步方法,但是记得在同步文件之前要先 flush stream,fflush() 和 sync(),fsync,fdatasync 与前者的区别,在于前者仅仅同步 libc-level 的 buffer,而后者则是同步 kernel level buffers。回写操作在 LINUX 中的控制Linux 有几个内核参数可以用来调整 write back,可查看/proc/sys/vm。这些参数是global, 所以会影响所有的文件系统。1.dirty_writeback_centisecs:linux 周期性 write b

15、ack 线程写出 dirty 数据的周期,这个机制可以确保所有的脏数据在某个时间点都可以写入介质。2.dirty_expire_centisecs:dirty 数据的过期周期,这是数据为 dirty 的最大时间。过了这个时间,dirty 数据会被周期性 write back 线程写回介质。换句话说,周期性 write back 线程每 dirty-writeback-centisecs 时间唤醒,然后同步那些dirty_expire_centisecs 时间之前就已经 dirty 的数据。3.dity_background_ratio:dirty 数据与全部内存的最大百分比。当脏数据变多的时候

16、,周期性的 write back 线程开始同步数据使得脏数据比例变小。这个过程包括那些 non-expired 的数据。 这个可以认为是系统 dirty 数据的 soft limit。4.dirty_ratio:dirty 数据与全部内存的最大百分比,超过这个显示,写同步数据先于增加 dirty 数据,这个是系统 diry 数据的 hard limit。UBIFS 写缓存区UBIFS 是一个异步文件系统,UBIFS 利用了 page cache。page cache 是一个通用的linux 内存管理机制,page cache 可以非常大以缓存更多的数据。当你写一个文件时,首先写到 page c

17、ache 中,置为 dirty,然后 write 操作返回(同步的文件是例外),然后数据会通过 write back 机制回写。Write buffer 是 UBIFS 特定的 buffer,它位于 page cache 和 flash 介质之间。这意味着 write buffer 只是写到 write buffer 上而不是 flash 介质。Write buffer 是用来优化 UBIFS 在 NAND flashes 上的速度。NAND flashes 包含 NAND pages,页是 NAND flash 的最小读写单位,通常为 512, 2KiB 或者 4KiB。Write buff

18、er尺寸等于 NAND page size。他的目的是积累 samll writes 为一个满的或者部分满的page。考虑下面的例子,假定在半秒内写了 4x512bytes nodes,page size 是 2kiB 的情况下,如果没有 write buffer,那么分开的写会使用 4 个 page,浪费 6KiB 的空间,而write buffer 可以仅写一次,并且没有空间浪费。所以 write buffer 避免生成过多的dirty space,UBIFS 的垃圾收集所做的工作就越少。当然上面的例子是一个理想状态,即便 write buffer 也可能浪费空间,比如使用同步I/O 或者

19、数据抵达的时间间隔较大。因为 write buffer 也有个过期时间,每 3-5 秒即便write buffer 不满,也会写出,这是为了数据完整性的原因。当然,如果 UBIFS 写大量的数据,那么就不使用 write buffer,仅仅数据的最后一部分由于小于 NAND page 尺寸需要等待填满 page 的数据,直到 write buffer 的定时器到时。Write buffer 实现上有一点复杂,UBIFS 中使用了一些 write buffer,每个 journal head 都有一个,当然这并不改变 write buffer 的基本机制。关于同步有几点需要注意的:1.sycn(

20、)会同步所有的 write buffers。2.fsync(fd)也会同步 fd 相关的所有 write buffers。3.用 O_SYNC 打开文件,会忽略 write buffers,所以 I/O 会直接写入介质。4.如果文件系统 mount 时使用了-o sync 选项,那么 write buffers 也会被忽略。数据同步时要考虑 write buffer 的 timer 时间,在 dirty_expire_centisecs(同步时间)加上额外的 3-5 秒,当然由于 write buffer 很小,所以 delay 的数据很少。UBIFS 同步模式 vs JFFS2 同步模式Mo

21、unt UBIFS 文件系统使用-o sync 标志,所有文件系统的操作都变成了同步模式,意味着在文件系统操作返回前,所有的数据都写入了 flash 存储介质中。例如,如果你使用 write()写 10MB 数据到文件 f.data,并且 UBIFS 是同步模式的。在write 操作返回前所有的 10M 文件数据以及 meta data(file size, date changes)也写入了 flash 介质。此时即便掉电,这个文件的数据也会包含所有的 10MB 数据。在打开文件时,使用 O_SYNC 标志也有同样的效果。在突然掉电的情况下,UBIFS 并不能像 JFFS2 那样提供较多的保

22、证,在 JFFS2 中所有的 meta data 存储在 data node headers 中,数据节点包含 4KiB 的压缩数据。这意味 meta data 信息在 flash 有多个版本,每次 JFFS2 写一个data node 到 flash 介质上时,都会更新文件的 inode size。当 JFFS2 mount 时,会扫描flash 介质,发现最后的 data node,同时获取 inode 的 size。在实际使用中,JFFS2 会顺序的写这 10M 数据,从头到尾。如果中间发生掉电,那么就丢失掉结尾的数据。也就是说如果写 10M 的数据到 JFFS2 中,写了 5M,此时掉

23、电发生,那么可以得到一个 5MB 的文件,而丢掉了未写入的 5MB。对于 UBIFS 来说有一点点复杂,数据被存储在 data nodes 中,而meta data 被存储在分离的 inode nodes 中。Meta data 在每个数据节点中没有像 JFFS2 一样有 duplicated 的版本。UBIFS 从来不会写 on flash inode size 外的数据节点。如果不得不写 data node, 并且 data node 是在 on flash inode size 之外(in memory inodes已经更新为 up-to-data 尺寸,但是脏的还没更新到 flash

24、上),那么 UBIFS 首先要把inode 写入介质,然后才能开始写数据,此时掉电就可能会产生 holes 文件,看下面的例子1.用户创建一个空文件 f.dat. 文件是同步的或者 UBIFS 文件系统被 mount 为同步模式。user 调用 write()函数来写一个 10MB buffer.2.kernel 首先拷贝所有的 10MB 数据到 page cache。inode size 被修改为 10MB 并且inode 被 mark 为 dirty。没有任何数据和 meta data 写入 flash media,此时如果发生掉电,那么 user 看到的是一个空文件 f.data。3.U

25、BIFS 看到 I/O 是同步的,那么首先开始同步 inode,首先写 inode node 到 flash media 中,此时如果发生掉电,那么 user 会看到一个 10MiB 大小的空文件。4. UBIFS 开始写数据,如果掉电发生在这一点上,那么 user 看到一个 10Mib 大小的文件,在文件后部是有个 hole。注意,即便 I/O 不是同步的,UBIFS 在开始写数据 meta data 到 flash 之前就返回。Write back 将在某个时刻开始写 flash media, 如果在 write back 过程发生掉电,那么同样会产生 hole。因此,UBIFS 并不能像

26、 JFFS2 那样,很完美的保留掉电前写下的数据以及文件尺寸,主流文件系统比如 ext3 也没有提供 JFFS2 类似的功能。虽然,有时人们用 UBIFS 替代JFFS2,人们希望 UBIFS 能够像 JFFS2 一样行事,这是可行的,需要 hack 一下 UBIFS 代码。之所以 UBIFS 还没有这样实现,是因为这个需求并没有那么强烈。UBIFS 作为一个异步的文件系统,应用程序应该在需要的时候同步他们的文件,这同样适用于大部分 linux 文件系统,然而,一些应用忽略了这一点,没能够正确的同步文件。UBIFS 快速压缩支持UBIFS 支持快速的压缩,UBIFS 在把数据写入 flash

27、存储介质之前压缩数据,在读出来时解压数据,这个压缩/解压缩过程对与用户来说是完全透明的。UBIFS 仅仅压缩文件数据,而目录,设备节点等是不压缩的。Meta data 和 indexing 信息也是不压缩的。当前UBIFS 支持 LZO 和 zlib 压缩器。ZLib 提供了更好的压缩率,但是 LZO 在压缩和解压时的速度更快。LZO 是 UBIFS 和 mkfs.ubifs 的缺省压缩处理器,当然你可以在 mkfs.ubifs 命令选项中使用-x 来 disable UBIFS 压缩。UBIFS 把数据分割为 4KiB 的块然后对每一个 chunks 进行单独压缩。这不是最优的,因为大块的数

28、据压缩效果更好,即便如此仍然提供了客观的 flash 空间效益。比如,一个真实的 root file system 镜像利用 LZO 压缩器可以减小 40%空间,而用 zlib 压缩器则减少 50%空间。这意味如果你可以把一个 300MB 的文件系统放到 256MiB 的 UBI volume 中,而且任然有 100MiB 的空闲空间。然而这可能随着文件系统存放的内容不同而不同,比如,如果你的文件系统保存的都是 mp3 文件,UBIFS 无法有效的压缩他们,因为 mp3 文件本身就是被压缩的。在 UBIFS 中是可以针对每个文件节点来 disable/enable 压缩功能的,方法是设置或者清

29、除 inode 节点的 compression 标志。注意,这个压缩标志对于目录是可继承的,也就是说这个目录下的文件和子文件在创建时,他们的压缩标志是继承自父目录的。还要注意的是 JFFS2 LZO 压缩和 UBIFS 的 zlib 压缩有轻微不同,UBIFS 使用 crypto-API 缩小方法,而 JFFS2 直接使用 zlib 库。导致 UBIFS 和 JFFS2 使用不同的 zlib 压缩选项。名义上,JFFS2 使用缩小 level3,window bits15,而 UBIFS 使用 level6 windows bit -11(负号使得 zlib 避免放一个 header 到数据流

30、中)。经验显示 JFFS2 压缩率稍微小一些,解压速度慢一些,但是压缩速度要快一些。UBIFS CRC 校验操作UBIFS 写入到介质的每一片数据都有一个 CRC32 checksum,UBIFS 使用 CRC 来保护data 和 meta data。每次读 meta data 时,CRC 校验码都会被验证。CRC-32 校验是非常强大的,几乎所有的数据损坏都可以检查到。UBI 也是如此,验证每一片 meta data。data CRC 在缺省情况下是不验证的,这能改善文件系统的读速度,当然 UBIFS 可以在 mount 时用 chk_data_crc,来切换为 data 验证。这会减少 U

31、BIFS 的读速度,但是提供了更好的数据完成性保护。使用这个选项,UBIFS 读取的每一片信息都会被验证,任何数据损坏也都会被检查到。注意,当前 UBIFS 不能 disable CRC-32 的写计算,因为 UBIFS 在 recovery过程依赖于它,当从一个 unclean reboot 恢复,replay 日志时,UBIFS 需要检测 broken和写了一半的 UBIFS nodes 然后抛弃他们,在这里 UBIFS 依赖于 CRC-32 checksum。换句话来说,如果你使用 UBIFS 时 disable 掉 CRC-32,但是你仍然为每一片数据生成了 CRC-32 checks

32、um, 你可以随时激活读校验注意:在 2.6.39 之前 default UBIFS 行为是相反的, UBIFS 缺省支持 CRC-32, 使用no_chk_data_crc 来 disable 它。UBIFS 的 Read aheadRead ahead 是一个文件系统的优化技术,每次读取的数据比用户请求的数据多一些。这个主意是基于文件的访问一般都是从开始向后顺序进行的,所以文件系统试着把将来可能用到的数据提前读出了。LINUX VFS 本身会做这个 read ahead 而不需要 file system 的支持。这对于传统的块设备文件系统工作良好,但是 UBIFS 不会得益于此。UBIFS

33、 工作于 UBI API 之上,而 UBI工作与 MTD API 之上,MTD API 是同步地, MTD API 是非常简单的,没有任何请求队列。这意味这 VFS 阻塞住 UBIFS readers, 让他们等待 read ahead 过程。Block device API是异步的 readers 不需要等待 read ahead,VFS read ahead 是为 hard drives 设计的。但是 raw flash 设备和 hard drive 是非常不同的,raw flash 设备不需要耗时的寻道时间,所以适合 hard disk 的技术并不适合 flash 设备。也就是说,VFS

34、 的 read ahead 仅仅会使得 UBIFS 变慢,所以 UBIFS 会 disable 掉 VFS 的 read ahead。但是 UBIFS 有他自己内部的 read ahead,我们称之为 bulk read。你可以在 mount 时增加 bulk_read 选项来使能bulk read 功能。有些 flash 可能一次读出全部数据要比分多次读出数据要快。例如,OneNAND 可以做read-while-load 如果它读取超过一个 NAND page。所以 UBIFS 可以通过一次读取较大的data chunks 来获取性能上的提升,这就是 bulk read 要做的如果 UBI

35、FS 注意到一个文件正在被顺序的读取,UBIFS 看到接下来的数据就存放在相同的eraseblock 中,则 UBIFS 开始 read ahead 数据,通过使用大的 read request。UBIFS 把这些提前读取的数据放到文件的 cache 中,所以用户的进一步读取可以直接从 cache 中获得。很明显,bulk read 在某些情况下,可能会减慢 UBIFS。此外注意在高度碎片化的文件系统上,bulk read 并不适合,尽管 UBIFS 不会主动碎片文件系统,但是也不会 de-fragment 文件系统。比如数序的写一个文件,那么不会有变得碎片化。但是如果你同时写多个文件,他们就

36、可能变得碎片化(这也依赖于 write back 怎么样提交更新),UBIFS 是不会自动 deframent 他们。当然,可以实现一个 background 的 defragmenter。我们也可以使用 per inode 的日志头来避免在一个 LEB 上混合属于不同的 inode 的数据节点,所以仍然有改善的余地。UBIFS 超级用户空间UBIFS 向超级用户保留了一些空间,这意味着当文件系统对于普通用户为满时,仍然有一点保留空间给 super user。其他文件系统比如 ext2 也有类似的特点,mkfs.ubifs 有一个-R 选项可以用来标识保留空间的尺寸。缺省情况下仅仅 root

37、用户可以使用保留空间,但是可以扩展特权用户的列表。UBIFS 可以记录几个 user 和 group IDs 在超级块中,允许他们利用保留空间。尽管 mkfs.ubifs 工具没有相应的命令行选项,但是很容易实现这个功能。注意,UBIFS 在 mount 文件系统时会输出保留空间的数目。UBIFS 支持的 Mount 特定选项下面是 UBIFS-specifi 特定的 mount 选项 1. chk_data-crc2. no_chk_data-crc3. bulk_read4. no_bulk_read此外 UBIFS 支持标准的 sync mount 选项,可以用来 disable UBI

38、FS write back 和 write buffer,使得写过程完全同步。注意 UBIFS 不支持 atime,所有 atime mount 选项不起任何作用。UBIFS 对于空闲空间处理的缺陷传统的文件系统,比如 ext2 可以很容易的计算出空闲空间,计算是非常精确的,用户对此已经习以为常。然后,UBIFS 则完全不同了,UBIFS 无法汇报它还有多少空闲空间可用,只能汇报最少的可用空间数,这个数目通常会少于实际的数目,有时差错甚至很大。UBIFS汇报的空闲空间的数目少于实际拥有的,是基于以下几个理由:第一因素是 UBIFS 的快速压缩。用户一般认为文件系统汇报了 N bytes 空闲空

39、间,那么就意味着可以写入 N bytes 的文件数据。因为压缩的存在,这种想法就不成立了,根据数据压缩程度的不同,UBIFS 可以写入的数据可能数倍于汇报的空闲空间 。当 UBIFS 计算空闲空间时,他并不知道即将写入的数据的特性,因此无法考虑压缩,所以就假定为最坏的情况,数据没有压缩。虽然这看起来问题不大,但是综合考虑压缩和 write back,压缩就变成了估算空闲空间的大问题。换句话说,UBIFS 无法知道 cached dirty 数据的压缩,想知道结果的唯一办法就是执行压缩。第二因素是回写操作。假定在 page cache 中有 X bytes 的脏数据,他们将在某个时间被刷入 fl

40、ash 存储介质。UBIFS 当前需要 X+O bytes 空间来写这些数据,O 是文件系统开支(比如数据的 index,以及每个 data node 需要一个 header) 问题是 UBIFS 无法精确的计算出 X 和 O,它使用悲观的最坏情况的计算,所以当 cached data 被刷入 flash, 所需的 flash 空间可能原少于需要的 X+O,例如看下面的情况:$ dfFilesystem 1K-blocks Used Available Use% Mounted onubi0:ubifs 49568 49568 0 100% /mnt/ubifs$ sync$ dfFilesy

41、stem 1K-blocks Used Available Use% Mounted onubi0:ubifs 49568 39164 7428 85% /mnt/ubifs第一次 df 汇报 zero 空闲空间,但是 sync 后汇报了 15%的空闲空间,这是因为有很多cached 的 dirty data,UBIFS 为他们保留了所有的空闲空间,但是在 flash media 过程中,仅使用了部分 flash space。下面是 UBIFS 为什么保留这个多空闲空间的理由1.还是关于 compression。数据以 uncompressed 形式存储在缓存中,UBIFS 并不能预估这些数据

42、的压缩,所以它假定数据完全不能压缩。然而,现实生活数据是很容易压缩的,除非.tgz 或者.mp3 文件,这就导致了对 X 的过分估计。2.归咎于设计,UBIFS nodes 不会跨越 earseblock 的边界,所以在每个擦除块的末尾处都会有一些小的浪费空间,这个浪费的 flash 空间依赖于数据写入和更改的顺序,传统的UBIFS 会悲观的估计这个浪费空间为最大值,这也导致了对 O 的过份估计。因此 UBIFS 在同步后可以更精确的估计空闲空间值像上面提到的,UBIFS 不会跨越 LEB 边界。考虑下面数字: 1.UBIFS node 最大尺寸是 4256 字节2.UBIFS node 最小

43、尺寸是 56 字节3.依赖于名字长度,目录项节点占据 56304 字节4.LEB 尺寸:典型的 NAND flash 128KiB 的物理擦除块 2048 字节的 NAND page,LEB 的尺寸是 126KiB(或者 124KiB 如果 NAND chip 不支持 sub-pages)。因此如果大部分 flash 上的节点是非压缩的 data nodes, UBIFS 将会浪费 126KiB LEB 的最后 1344bytes。但是现实生活中的数据通常是压缩的,所以 node 尺寸可能发生变化,因此在删除块末尾的 wasted space 范围为 04255。UBIFS 把一些小的节点,比

44、如目录项节点放到 LEBs 末尾来减少wasted space,但是不理想,UBIFS 仍然在 LEB 的末尾浪费掉大块的空间。当汇报空闲空间时,UBIFS 不知道哪种数据,以何种顺序写入 flash media。因此,它评估每个 LEB 的wastage 为最大可能值 4255。这个计算对大多数现实世界都是太悲观了,真实的浪费要远少于 4255。然而,UBIFS 汇报给用户空间程序的是绝对最小值。以上意味着 LEB 越大,UBIFS 对空闲空间的预测越准确,比如 128KiB 擦除块要好于 16KiB 的参数块。Dirty space 是曾经被 UBIFS nodes 使用过的空间,但是由于

45、改变或者转移导致这个空间变得无效。例如,如果文件的内容被 re-write,那么相应的数据节点变成无效,当新的数据 data 写入 flash media,无效的节点包含 dirty space ,当然还有其他的机制会导致 dirty space 出现。 UBIFS 无法直接重用 dirty space,因为相应的 flash areas 没有包含所有的 0xff bytes。在 dirty space 可以重用前,UBIFS 不得不垃圾收集相应的LEBs,垃圾收集回收 dirty space 的方法和 JFFS2 是相同的。粗略的讲, UBIFS 垃圾收集选取一个 LEB,这个 LEB 包含

46、一些 dirty space,然后把这个 LEB 上的有效 UBIFS 节点移到GC reserverd LEB 上。这将消耗 GC reserved LEB 的一些空闲空间, GC 选取另外一个需要收集的 LEB,然后把有效数据移到这个 GC reserved LEB,持续这个过程直到 LEB 变满。GC选取另外一个 reserved LEB,继续这个过程。UBIFS 有一个概念叫最小 I/O 单位, 描述可以写入 flash 数据的最小数目,一般情况下 UBIFS 工作在 large-page NAND flash 上,最小 I/O 单位是 2KiB。事实上,UBIFS GC 虽然尝试不浪

47、费任何空间,但是有时并不能如愿,UBIFS 不一定能够回收那些 dirty 空间小于 I/O unit 的 dirty space。当 UBIFS 向 users汇报空闲空间时,对待 dirty space 为可用空间,因为 GC 可能会回收这部分空间为空闲空间,但如上面分析的,UBIFS 无法回收所有的 dirty space 为空闲空间,更坏的情况是UBIFS 无法确切知道它可以回收多少 dirty space,再一次 UBIFS 使用最悲观的计算。因此dirty space 越少,UBIFS 汇报的 free space 越准确。在实际应用中,这意味着一个满的文件系统要比一个空的文件系统

48、更难预测空闲空间,因为满的文件系统有太多的 dirty space。注意,解决这个问题,UBIFS 可以在 statfs()中运行 GC, GC 将把 dirty space 变为 free space, 因此预测空闲空间就变得更精确。然而,这将导致 statfs 变得非常的慢,因此调用 statfs 的应用的行为将不可预测。此外也可以使用 JFFS2 使用的 background GC。可能已经知道,UBIFS 在 flash media 上维护文件系统的 index。index 占据 flash 的一部分空间。UBIFS journal 保存着 FS data。journal 中的 FS

49、data 没有 index, 这意味着 on flash index 没有指向他们。 journal FS data 的 index 是建立在 RAM 中的,当文件系统被 mount 时,UBIFS 要扫描整个 journal 区,然后在 RAM 中重建 index。日志在某种程度像是 UBIFS 中的一个 JFFS2 文件系统。 journal data 在提交时会变成 indexed,在 UBIFS 提交时,更新 on flash index,使得index 指向 journal data,然后 UBIFS 挑选其他的 LEBs 作为新的 journal, 所以 journal在提交后会改变位置,这就是 UBIFS 的 journal 特点,日志区不是固定的。UBIFS 精确的记录着 index size。也就是,UBIFS 一直很清楚当前 on flash index 占据了多少空间。然而 UBIFS 无法精确的预测在提交后 on flash index 要增加或减少多少,再一次的,UBIFS考虑最坏的情况。当然在提交后 UBIFS 再次知道 index 的确切尺寸。sync()不仅仅 flush 左右的脏数据,而且也会提交 journal。这意味者同步过的文件系统对空闲空间的预测更准确。事实上

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 专业基础教材

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报