OpenWRT下jffs2文件系统

背景知识

  某项目中,设备无故无法登陆,发现设备中/etc/config/network配置文件恢复到出差配置,但是同分区中的其它文件未丢失。

nor Flash特性

  1. 闪存的最小寻址单位是字节(byte),而不是磁盘上的扇区(sector)。这意味着我们可以从一块闪存的任意偏移(offset)读数据,但并不表明对闪存写操作也是以字节为单位进行的。
  2. 当一块闪存处在干净的状态时(被擦写过,但是还没有写操作发生),在这块flash上的每一位(bit)都是逻辑1。
  3. 闪存上的每一位(bit)可以被写操作置成逻辑0。 可是把逻辑 0 置成逻辑 1 却不能按位(bit)来操作,而只能按擦写块(erase block)为单位进行擦写操作。擦写块的大小从 4K 到128K 不等。从上层来看,擦写所完成的功能就是把擦写块内的每一位都重设置(reset)成逻辑 1
  4. 闪存的使用寿命是有限的。具体来说,闪存的使用寿命是由擦写块的最大可擦写次数来决定的。超过了最大可擦写次数,这个擦写块就成为坏块(bad block)了。因此为了避免某个擦写块被过度擦写,以至于它先于其他的擦写块达到最大可擦写次数,我们应该在尽量小的影响性能的前提下,使擦写操作均匀的分布在每个擦写块上。这个过程叫做磨损平衡(wear leveling)

jffs2文件系统特性

  有 JFFS2 就要有 JFFS v1,没错,JFFS v1 最初是由瑞典的 Axis Communications AB 公司开发的,使用在他们的嵌入式设备中,并且在 1999 年末基于 GNU GPL 发布出来。最初的发布版本基于 Linux 内核 2.0,后来 RedHat 将它移植到 Linux 内核 2.2,做了大量的测试和 bug fix 的工作使它稳定下来,并且对签约客户提供商业支持。但是在使用的过程中,JFFS v1 设计中的局限被不断的暴露出来。于是在 2001 年初的时候,RedHat 决定实现一个新的闪存文件系统,这就是现在的 JFFS2。下面将详细介绍 JFFS2 设计中主要的思想,关键的数据结构和垃圾收集机制。这将为我们实现一个闪存上的文件系统提供很好的启示。 首先,JFFS2 是一个日志结构(log-structured)的文件系统,包含数据和原数据(meta-data)的节点在闪存上顺序的存储。JFFS2 之所以选择日志结构的存储方式,是因为对闪存的更新应该是 out-of-place 的更新方式,而不是对磁盘的 in-place 的更新方式。在闪存上 in-place 更新方式的问题我们已经在闪存转换层一节描述过了。

  1. 节点头部定义和兼容性
    JFFS2 将文件系统的数据和原数据以节点的形式存储在闪存上,具体来说节点头部的定义如下:
    jffs2节点结构
    幻数屏蔽位:0x1985 用来标识 JFFS2 文件系统。
    节点类型:JFFS2 自身定义了三种节点类型,但是考虑到文件系统可扩展性和兼容性,JFFS2从 ext2 借鉴了经验,节点类型的最高两位被用来定义节点的兼容属性,具体来说有下面几种兼容属性:
    JFFS2_FEATURE_INCOMPAT:当 JFFS2 发现了一个不能识别的节点类型,并且它的兼容属性是 JFFS2_FEATURE_INCOMPAT,那么 JFFS2 必须拒绝挂载(mount)文件系统。
    JFFS2_FEATURE_ROCOMPAT:当 JFFS2 发现了一个不能识别的节点类型,并且它的兼容属性是 JFFS2_FEATURE_ROCOMPAT,那么 JFFS2 必须以只读的方式挂载文件系统。
    JFFS2_FEATURE_RWCOMPAT_DELETE:当 JFFS2 发现了一个不能识别的节点类型,并且它的兼容属性是 JFFS2_FEATURE_RWCOMPAT_DELETE,那么在垃圾回收的时候,这个节点可以被删除。
    JFFS2_FEATURE_RWCOMPAT_COPY:当 JFFS2 发现了一个不能识别的节点类型,并且它的兼容属性是 JFFS2_FEATURE_RWCOMPAT_COPY,那么在垃圾回收的时候,这个节点要被拷贝到新的位置。
    节点总长度:包括节点头和数据的长度。
    节点头部 CRC 校验:包含节点头部的校验码,为文件系统的可靠性提供了支持。

  2. 节点类型
    JFFS2 定义了三种节点类型:
    JFFS2_NODETYPE_INODE: INODE 节点包含了i-节点的原数据(i节点号,文件的组 ID, 属主 id, 访问时间,偏移,长度等),文件数据被附在 INODE 节点之后。除此之外,每个 INODE 节点还有一个版本号,它被用来维护属于一个i-节点的所有 INODE 节点的全序关系。下面举例来说明这个全序关系在 JFFS2 的使用:
    在这里插入图片描述
    因此,当文件系统从闪存上读节点信息后,会生成下面的映射信息:
    在这里插入图片描述
      根据这个映射信息表,文件系统就知道到相应的 INODE 节点去读取相应的文件内容。 最后要说明的是,JFFS2 支持文件数据的压缩存储,因此在 INODE 节点中还包含了所使用的压缩算法,在读取数据的时候选择相应的压缩算法来解压缩。
    JFFS2_NODETYPE_DIRENT:DIRENT 节点就是把文件名与 i 节点对应起来。在 DIRENT节点中也有一个版本号,这个版本号的作用主要是用来删除一个 dentry。具体来说,当我们要从一个目录中删除一个 dentry 时,我们要写一个 DIRENT 节点,节点中的文件名与被删除的 dentry 中的文件名相同,i 节点号置为 0,同时设置一个更高的版本号。
    JFFS2_NODETYPE_CLEANMARKER:当一个擦写块被擦写完毕后,CLEANMARKER 节点会被写在 NOR flash 的开头,或 NAND flash 的 OOB(Out-Of-Band) 区域来表明这是一个干净,可写的擦写块。在 JFFS v1 中,如果扫描到开头的 1K 都是 0xFF 就认为这个擦写块是干净的。但是在实际的测试中发现,如果在擦写的过程中突然掉电,擦写块上也可能会有大块连续 0xFF,但是这并不表明这个擦写块是干净的。于是我们需要 CLEANMARKER 节点来确切的标识一个干净的擦写块。

  3. JFFS2节点,擦写块在内存中的表示和操作
    JFFS2 维护了几个链表来管理擦写块,根据擦写块上的内容,一个擦写块会在不同的链表上。具体来说,当一个擦写块上都是合法(valid)的节点时,它会在 clean_list 上;当一个擦写块包含至少一个过时(obsolete)的节点时,它会在 dirty_list 上;当一个擦写块被擦写完毕,并被写入 CLEANMARKER 节点后,它会在 free_list 上。
      通常情况下,JFFS2 顺序的在擦写块上写入不同的节点,直到一个擦写块被写满。此时 JFFS2 从 free_list 上取下一个擦写块,继续从擦写块的开头开始写入节点。当 free_list 上擦写块的数量逐

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值