ext2_splice_branch解析

本文深入探讨了Ext2文件系统中ext2_splice_branch()函数的作用,即如何在ext2_allocate_branch()的基础上进一步建立和完善直接块与间接块之间的映射关系,确保文件系统的完整性和可用性。

        我们前面的博客中仔细阐述了ext2_allocate_branch()的实现原理,其主要作用是分配写所需的直接和间接块,并建立映射关系,但仔细分析后,我们可以发现,这种映射关系建立的不是很彻底,即有些该做的还未做,那么这些未做的留到哪了呢?就在本文所要分析的ext2_splice_branch()函数中来实现。

        首先,让我们来看看到底ext2_allocate_branch()中到底做了哪些,而哪些事情没有做:

        ext2_allocate_branch()做了的事情:

  1. 分配间接块和直接块;
  2. 如果分配了间接块,那么链接了间接块的索引(即索引路径上的间接块都初始化并在相应的偏移设置到下一级间接块的索引);
  3. 如果分配了间接块,那么最后一个间接块到直接块的映射也建立起来了。
        下图是2对应的情况:

该图中,由于分配了间接块(红色数据块)而使得间接块的映射建立成功了,但是我们注意到,在映射断裂的地方(ei->i_data[13])它和二级间接块的映射彼时还未建立起来,只是将二级间接块的块号记录在断裂的数据结构中了,即branch[0].key,branch[0].p则记录了该块号最终应该被写入的位置(本例中是i_data[13])。
        下图则描述了另外一种情形下ext2_allocate_branch做了哪些以及哪些尚未完成:

此时,在ext2_allocate_branch()中无需分配间接块,而是直接分配了两个数据块(右侧蓝色块),但在ext2_allocate_branch()实现时,并未将这两个数据块和索引块建立起映射,而只是在断裂位置处记录了分配的数据块号(branch[0].key的值)。

        尚未完成的事情:
  1. 如果没有分配间接块,那么从间接块到 直接数据块的索引就没有建立;
  2. 在链接断裂的地方,其索引并没有建立。
        因此,通过上面的两张图,我们知道了ext2_allocate_branch什么还没有做,我们就明白了ext2_splice_branch()到底应该需要做些什么。
static void ext2_splice_branch(struct inode *inode,
			long block, Indirect *where, int num, int blks)
{
	int i;
	struct ext2_block_alloc_info *block_i;
	ext2_fsblk_t current_block;

	block_i = EXT2_I(inode)->i_block_alloc_info;

	/* XXX LOCKING probably should have i_meta_lock ?*/
	/* That's it */

	*where->p = where->key;

	/*
	 * Update the host buffer_head or inode to point to more just allocated
	 * direct blocks blocks
	 */
	/* num == 0意味着之前没有分配间接块,
	** blks > 1意味着之前分配了超过1个直接块
	** blks = 1的情况已经在上面代码
	** *where->p = where->key中处理过了
	*/
	if (num == 0 && blks > 1) {
		current_block = le32_to_cpu(where->key) + 1;
		for (i = 1; i < blks; i++)
			*(where->p + i ) = cpu_to_le32(current_block++);
	}

	/*
	 * update the most recently allocated logical & physical block
	 * in i_block_alloc_info, to assist find the proper goal block for next
	 * allocation
	 */
	if (block_i) {
		block_i->last_alloc_logical_block = block + blks - 1;
		block_i->last_alloc_physical_block =
				le32_to_cpu(where[num].key) + blks - 1;
	}

	/* We are done with atomic stuff, now do the rest of housekeeping */

	/* had we spliced it onto indirect block? */
	if (where->bh)
		mark_buffer_dirty_inode(where->bh, inode);

	inode->i_ctime = CURRENT_TIME_SEC;
	mark_inode_dirty(inode);
}
让我们来看看这个函数的每一步都是在干什么:
*where->p = where->key:修复映射断裂,在索引块的特定偏移位置(where->p指向)记录被索引块的块号(无论被索引块是间接索引块还是直接数据块),这样,映射断裂处的断裂就不复存在了;
接下来的if(num == 0 && blks > 1)判断:这是针对上图2锁描述的情况:
num=0意味着前面没有分配间接块,而blks > 1则意味着分配了数据块,因为在上图2中索引块到数据块的映射并未建立,而上面的一句(*where->p = where->key)只是建立了第一个数据块的映射关系,如果当前分配的数据块数量大于1,那我们还必须将剩余的数据块的映射关系建立起来。而建立也很简单,
current_block = le32_to_cpu(where->key) + 1;
for (i = 1; i < blks; i++)
*(where->p + i ) = cpu_to_le32(current_block++);
这是建立在分配的数据块一定是连续的基础之上的。
到目前为止,整个映射关系才算是真正地建立起来,我们才可以使用。
接下来的是一些无关痛痒的倒也简单的功能,如修改预分配结构(因为本次新分配了数据块,所以需要更新预分配结构中的某些成员),另外因为可能修改间接块中的内容,所以必须将间接块所在的buffer_head标记为dirty,以等待合适的时机写入物理磁盘。

### 关于 `list_splice_init` 的用法 在 C++ 中,`std::list` 提供了一个名为 `splice` 的成员函数用于将另一个列表中的元素转移到当前列表中而不复制这些元素。这使得操作非常高效,因为只涉及指针调整而不是数据拷贝。 对于 `list_splice_init` 函数来说,在标准库文档里并没有直接找到这个名称的确切定义;但是可以推测这是基于 `splice` 方法的一个特定应用场景或者是某些实现细节上的变体。通常情况下讨论的是 `splice` 和其重载版本之一可能带有 `_init` 后缀来表示初始化行为或者特殊处理逻辑[^1]。 下面给出一般意义上的 `splice` 使用方法以及如何通过它完成两个列表之间的元素转移: #### 基本语法 ```cpp void splice(const_iterator position, list& other); void splice(const_iterator position, list&& other); template<class InputIt> void splice(const_iterator pos, list&, InputIt first, InputIt last); void splice(const_iterator pos, list&, const_iterator i); ``` 其中第一个参数是指定插入点的位置迭代器,第二个参数是要从中移除并插入到当前位置之前的列表对象或范围。 #### 示例代码 这里展示一个简单的例子说明怎样利用 `splice` 来组合两个不同的 `std::list<int>` 列表: ```cpp #include <iostream> #include <list> int main(){ std::list<int> lst1{0, 1, 2}; std::list<int> lst2{3, 4}; auto iter = lst1.begin(); ++iter; // 将lst2的所有元素移动至lst1的指定位置之后 lst1.splice(iter, lst2); for(auto elem : lst1){ std::cout << elem << " "; } } ``` 上述程序会输出:`0 1 3 4 2` 表明成功地把 `lst2` 插入到了 `lst1` 的适当位置,并且原 `lst2` 变为空. 如果确实存在名为 `list_splice_init` 的具体实现,则可能是为了某种特殊的场景设计的一种优化方式或是辅助工具,但这超出了标准 C++ 库所规定的接口范畴。因此建议查阅具体的编译环境下的官方手册获取最准确的信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值