JFFS2中的metadata
在JFFS2中的代码中你会经常见到metadata这个东西,但是,你可能未必清楚它到底是干什么用的。metadata在创建文件的时候被建立,而在第一次写的时候被废弃;挂载或者其他地方也经常见到这样的判断:如果metadata存在,则废弃它。那么它到底是干什么用的,既然处处都要废弃它,为什么还要生成它?
grep一下代码量并不大的JFFS2代码,你就能很快的得出所有用到metadata的地方,归结起来就一下几个地方:
1. 创建文件时
2. 设置文件属性时
3. 写操作时
4. 读取inode时
通过阅读相关的代码,我们可以知道:
1)在创建文件的时候,JFFS2系统会往flash上写一个jffs2_raw_inode结构,这个动作是由jffs2_write_dnode实现的。我们知道jffs2_write_dnode除了往flash上写一个jffs2_raw_inode结构之外,后面还会跟上一定的数据,数据的长度由前面的结构成员来指定,最后返回一个jffs2_full_dnode结构,简称fn。在创建文件的时候,这个后面的数据内容会为空,并将生成的fn做为metadata。
2)在设置属性的时候,如果只是修改一些时间属性之类的,而文件大小没有发生改变,JFFS2也会写一个新的jffs2_raw_inode结构,同样后面的数据长度为0,也会将生成的fn作为新的metadata。
3)写操作,任何一个写操作,都会让已经存在的metadata被废弃!
4)readinode,会将所有属于同一个inode number的节点组织起来,在这个过程中,如果发现一个节点所对应的fn结构的数据大小为0,且metadata不存在,就会将这个节点作为metadata;如果发现一个新的节点,它的版本号大于metadata的版本号,就会废弃掉这个metadata;如果相同,则忽略掉新的节点,标记为废弃。
5)在扫描过程中关于metadata的动作和readinode基本是一样的。
从上面我们得出metadata的作用大概是这样的:
为什么metadata生成的时候,它所对应的数据节点的数据大小都为0呢?确切的说,正是由于写入的数据大小为0,才需要metadata的存在。我们来看,在创建文件的时候,我们没有一个数据节点来表示文件的存在,所以我们需要一个标示;而同样,修改文件属性的时候,也没有一个有数据的节点能表示文件的最新状态,所以我们需要一个metadata来表示文件的最新状态。
而当有新的写动作发生时,就意味着有一个数据节点可以表示文件的最新状态了,这个时候metadata就失去了他的作用,为了节省宝贵的flash空间(Nor Flash一般就只有几兆到一百来兆的空间,而且很贵) ,我们就要废弃掉这个节点,这样垃圾回收的时候就可以回收metadata对应的jffs2_raw_inode这个空间(在2.4内核中是68个字节)。
既然每次写操作都会让metadata被废弃,为什么在readinode的时候和挂载的时候还要有判断废弃的动作呢?因为在嵌入式领域中,掉电是很容易发生的。于是就容易出现这种情况:刚写完新的节点,但还没来得及废弃metadata对应的jffs2_raw_inode结构,就掉电了,这样在readinode和挂载的时候就会扫描到已经过时但是却没有被标记为过时的metadata节点。
普通文件和目录文件都是这样处理的,实际上,2.4中链接文件和设备文件的metadata有点不一样。我认为,确切的说,他们的metadata不能算是真正的metadata,因为,他们的metadata对应的数据大小是不为0的(储存的是被链接的文件名或设备号) 。在创建文件生成jffs2_raw_inode时,后面直接就跟了数据,虽然也把生成的fn作为metadata,但是在挂载的扫描过程,这个节点不会被当成metadata,因为他对应的数据大小不为0,该节点会被当作唯一的数据节点。而在readinode的时候,在完成扫描之后,针对这两种特殊文件,会特殊的将他们唯一的数据节点当成metadata挂上去。