这个函数 ext2_new_inode
是为 EXT2 文件系统分配一个新的 inode。它是一个核心函数,涉及 inode 的分配、初始化,以及与文件系统数据结构的协调工作,函数源码位于fs/ext2/ialloc.c下。以下是对函数的详细解读:
struct inode *ext2_new_inode(struct inode *dir, umode_t mode,
const struct qstr *qstr)
{
struct super_block *sb;
struct buffer_head *bitmap_bh = NULL;
struct buffer_head *bh2;
int group, i;
ino_t ino = 0;
struct inode * inode;
struct ext2_group_desc *gdp;
struct ext2_super_block *es;
struct ext2_inode_info *ei;
struct ext2_sb_info *sbi;
int err;
...
}
函数概览
- 目标:为目录
dir
创建一个新 inode,根据指定的模式mode
和名称信息qstr
初始化。 - 返回值:成功时返回新分配的
inode
结构指针;失败时返回一个错误指针。
主要流程
1. 环境初始化
sb = dir->i_sb
:获取超级块。new_inode(sb)
:分配新的 inode 结构,若分配失败返回-ENOMEM
。- 提取与 EXT2 文件系统相关的数据结构,例如超级块信息、组描述符等。
2. 选择块组
- 目录 inode:
- 如果启用了
OLDALLOC
策略,调用find_group_dir
寻找合适的块组。 - 否则调用
find_group_orlov
(更复杂但优化更好)。
- 如果启用了
- 非目录 inode:
- 调用
find_group_other
。
- 调用
如果无法找到可用块组,返回 -ENOSPC
。
3. 尝试分配 inode
-
遍历所有块组:
- 获取组描述符
gdp
和位图缓存bitmap_bh
。 - 使用
ext2_find_next_zero_bit
找到位图中第一个空闲 inode。 - 如果分配失败或冲突,尝试分配下一个 inode 或换组重试。
- 成功分配后,更新位图并标记为脏数据。
- 获取组描述符
-
分配完成后计算全局 inode 号
ino
,并检查其合法性。
4. 更新文件系统元数据
- 减少空闲 inode 计数、更新目录 inode 计数(如适用)。
- 调整块组的相关计数器(如
bg_free_inodes_count
和bg_used_dirs_count
)。 - 根据文件系统的
GRPID
选项初始化 inode 的所有权。
5. 初始化 inode
- 填充 inode 结构的字段,包括时间戳、模式、数据块指针等。
- 初始化 ACL 和安全属性。
- 将 inode 标记为脏数据,并插入到 inode 表中。
6. 处理失败情况
- 各个阶段都有失败处理逻辑,确保释放资源、清理数据,避免泄漏。
关键逻辑和细节
-
块组选择策略:
find_group_dir
和find_group_orlov
针对目录优化,通过分析组的空闲 inode 和块情况选择最合适的块组。find_group_other
适用于文件,优先选择非目录组或负载较轻的组。
-
位图操作:
- 使用
ext2_find_next_zero_bit
寻找空闲 inode。 - 用
ext2_set_bit_atomic
设置位图中的 inode 位,避免并发冲突。
- 使用
-
元数据更新:
- 更新超级块和块组描述符的计数器,反映 inode 使用状态。
percpu_counter
提供性能优化的计数更新。
-
错误处理:
- 多层次的失败处理,确保已分配的 inode 结构或文件系统资源在失败时被正确释放。
重要的数据结构
ext2_super_block
:超级块,存储全局文件系统信息。ext2_group_desc
:块组描述符,记录每个块组的元数据。ext2_inode_info
:扩展的 inode 结构,包含 EXT2 特定的信息。
常见错误码
-ENOMEM
:内存不足,分配 inode 或位图缓存失败。-ENOSPC
:空间不足,无法找到可用的 inode。-EIO
:I/O 错误,例如读取位图失败。
总结
这个函数体现了 EXT2 文件系统的核心设计,包括 inode 分配的高效性、错误恢复能力,以及针对目录和文件的不同策略。它结合了并发控制、位图操作和元数据管理等技术,是学习文件系统设计的重要范例。