ext3、ext4 orphan inode机制分析
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
ext3、ext4的orphan inode机制分析
一、概述
orphan在英文中是孤儿的意思,在这里取被遗弃、被删除之意。
orphan inode是什么样的inode呢?这种inode是怎样产生的呢?
先介绍一个概念,文件的引用计数,准确地说应该是inode的引用计数,因为一般来说一个文件会对应
一个inode。文件的引用计数,简单地说是表示有多少个文件指向该文件,准确地说是文件的硬链接的个数。
情况1:设想一个进程,open一个文件,然后unlink该文件,然后进行文件读写。这是允许的,并且在进程退出时,内核会自动将引用计数为0的文件删除。
但是如果该进程尚未退出之前,系统崩溃了,那么,内核就没有机会将已被unlink、并且引用计数为0
的inode从磁盘上删除了。
情况2:设想我们正在截断一个大文件(系统调用truncate),但是操作尚未完成,系统就崩溃了。同样,内核也没有办法将该文件的所有数据块全部删除了。
ext3、ext4的orphan inode机制就是处理上述两种情况的。基本思想是这样的:如果要删除或截断一个inode,要先把这个inode记录到磁盘上的一个特殊的orphan inode链表上。如果删除或截断操作能够
正常完成,那么,就从磁盘上的orphan inode链表上删除该inode;否则,如果删除或截断操作未完成之前,系统就发生崩溃了,那么,系统重启后,文件系统会遍历磁盘上的orphan inode链表,对链表上的每一个inode都重新进行一遍删除或截断操作,以此来保证这些inode真正在磁盘上被删除,维护文
件系统的一致性。
内核版本:2.6.35
二、相关数据结构及之间的关系
先总体说一下orphan inode的组织。
orphan inode需要在两个地方组织,分别是在内存中和在磁盘上。不论在哪里,从抽象角度来看,orphan inode都被组织成一个单向链表。
1、ext4_inode
struct ext4_inode {
__le32 i_dtime; /* Deletion Time */
.........
}
这个是磁盘上的inode的结构,i_dtime本来表示该inode被删除的时间,在orphan inode机制中,因
为此时该域的值并不重要,故借用一下,用于记录下一个被unlink/truncate的inode号。
2、ext4_super_block
struct ext4_super_block {
__le32 s_last_orphan; /* start of list of inodes to delete */
.........
}
这个是磁盘上的superblock 结构。其中,s_last_orphan 记录的是最近一个被unlink/truncate 的inode 号,从抽象角度来看,它就代表磁盘上orphan inode 单链表的头。
新的inode 插入orphan inode 链表时采用“头插法”,也就是说,最近被unlink/truncate 的inode 号会放在s_last_orphan 中。
这样,磁盘上的orphan inode 单链表如下图1所示。
图1 磁盘上的orphan inode 链表结构图
3、ext4_inode_info
struct ext4_inode_info {
__u32 i_dtime;
struct list_head i_orphan; /* unlinked but open inodes */
.......
}
这个是内存中的inode 结构,即 磁盘上的ext4_inode 在内存中的表现。
其中,i_dtime 与ext4_inode 中的i_dtime 相对应,i_orphan 是个链表节点,用于在内存中组成orphan inode 链表。
4、ext4_sb_info
struct ext4_sb_info {
struct list_head s_orphan;
struct mutex s_orphan_lock;
.........
}
这个是内存中的superblock 结构,即磁盘上ext4_super_block 在内存中的表现。其中,s_orphan 代表链表头,s_orphan_lock 是用于保护链表的互斥锁。在内存中的orphan inode 链表结构与图1很类似,在此从略。
三、辅助函数
1、NEX T_ORPHAN(inode)
fs/ext4/ext4.h
1209 #define NEXT_ORPHAN(inode) EXT4_I(inode)->i_dtime
这个宏的作用是在磁盘orphan inode链表上取得下一个orphan inode号。
2、ext4_orphan_g et()
1074 struct inode *ext4_orphan_g et(struct super_block *sb, unsi g ned lon g ino)
{ .......
1104 inode = ext4_i g et(sb, ino);
.......
}
这个函数的主要作用是根据一个inode号ino,从磁盘上将该inode的信息读入内存,保存在
ext4_inode_info结构中。
3、ext4_orphan_add()
1984 int ext4_orphan_add(handle_t *handle, struct inode *inode)
{
.......
// 将“下一个”最近的inode号保存在本inode的ext4_inode_info->i_dtime中
// 这样,当本inode写回磁盘时,会将“下一个”orphan inode号写回磁盘。
2030 NEX T_ORPHAN(inode)= le32_to_cpu(EX T4_SB(sb)->s_es->s_last_orphan);
// 将最近的inode号保存在ext4_super_block->s_last_orphan中,
// 这样,当本超级块写回磁盘时,会将最近的orphan inode号写回磁盘。
2031 EX T4_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino);
.......
// 将内存中的ext4_inode_info结构链到ext4_sb_info->s_orphan链表的第一个位置。2046 if (!err)
2047 list_add(&EX T4_I(inode)->i_orphan,&EX T4_SB(sb)->s_orphan);
.......
}
总之,ext4_orphan_add()的作用是在内存中和磁盘上的orphan inode链表中分别添加一个inode节点。