Ext2数据块分配

本文深入探讨了Ext2文件系统中数据块的分配机制,包括数据块寻址的四步过程,文件洞的实现原理以及如何避免磁盘空间浪费。在分配数据块时,Ext2采用动态分配策略,优先考虑在文件最后一个块附近找空闲块,并支持预分配以减少文件碎片。此外,文件的洞允许部分文件内容不占用磁盘空间,提高空间利用率。
摘要由CSDN通过智能技术生成

跟索引节点一样,Ext2也对磁盘数据块进行分配与释放。在详细分析相关代码之前,先引出两个重要的预备,一个是数据块寻址,一个是文件的洞

 

 

1 数据块寻址

 

 

每个非空的普通文件都由一组数据块组成。这些块或者由文件内的相对位置(它们的文件块号)来标识,或者由磁盘分区内的位置(它们的逻辑块号)来标识。

 

从文件内的偏移量 f 导出相应数据块的逻辑块号需要两个步骤:

1. 从偏移量f导出文件的块号,即在偏移量f处的字符所在的块索引。

2. 把文件的块号转化为相应的逻辑块号。

 

因为Unix文件不包含任何控制字符,因此,导出文件的第f个字符所在的文件块号当容易的,只是用f除以文件系统块的大小,并取整即可。

例如,让我们假定块的大小为4KB。如果f小于4096,那么这个字符就在文件的第一数据块中,其文件的块号为O。如果f等于或大于4096而小于8192,则这个字符就在文件块号为1的数据块中,以此类推。

 

得到了文件的块号是第一步。但是,由于Ext2文件的数据块在磁盘上不必是相邻的,因此把文件的块号转化为相应的逻辑块号可不是这么直截了当的了。因此,Ext2文件系统必须提供一种方法,用这种方法可以在磁盘上建立每个文件块号与相应逻辑块号之间的关系。在索引节点内部部分实现了这种映射(回到了AT&T Unix的早期版本)。这种映射也涉及一些包含额外指针的专用块,这些块用来处理大型文件的索引节点的扩展。

 

ext2磁盘索引节点ext2_inode的i_block字段是一个有EXT2_N_BLOCKS个元素且包含逻辑块号的数组。在下面的讨论中,我们假定EXT2_N_BLOCKS的默认值为15(实际上到2.6.18这个值都一直是15)。如图所示,这个数组表示一个大型数据结构的初始化部分。

正如从图中所看到的,数组的15个元素有4种不同的类型:

 

- 最初的12个元素产生的逻辑块号与文件最初的12个块对应,即对应的文件块号从0 - 11。

 

- 下标12中的元素包含一个块的逻辑块号(叫做间接块),这个块中存放着一个表示逻辑块号的二级数组。这个数组的元素对应的文件块号从12 到 b/4+11,这里b是文件系统的块大小(每个逻辑块号占4个字节,因此我们在式子中用4作除数,如果块大小是4096,则该数组对应文件块号从12到1035)。因此,内核为了查找指向一个块的指针必须先访问这个元素,然后,在这个块中找到另一个指向最终块(包含文件内容)的指针。

 

- 下标13中的元素包含一个间接块的逻辑块号,而这个块包含逻辑块号的一个二级数组,这个二级数组的数组项依次指向三级数组,这个三级数组存放的才是文件块号对应的逻辑块号,范围从b/4+12到(b/4)^2+(b/4)+11。如果块大小是4096,则范围是从1036到1049611。

 

- 最后,下标14中的元素使用三级间接索引,第四级数组中存放的才是文件块号对应的逻辑块号,范围从(b/4)^2+(b/4)+12到(b/4)^3+(b/4)^2+(b/4)+11。

 

在图中,块内的数字表示相应的文件块号。箭头(表示存放在数组元素中的逻辑块号)指示了内核如何通过间接块找到包含文件实际内容的块。

 

注意这种机制是如何支持小文件的。如果文件需要的数据块小于12,那么两次磁盘访问就可以检索到任何数据:一次是读磁盘索引节点i_block数组的一个元素,另一次是读所需要的数据块。对于大文件来说,可能需要三四次的磁盘访问才能找到需要的块。实际上,这是一种最坏的估计,因为目录项、索引节点、页高速缓存都有助于极大地减少实际访问磁盘的次数。

 

还要注意文件系统的块大小是如何影响寻址机制的,因为大的块允许Ext2把更多的逻辑块号存放在一个单独的块中。例如,如果块的大小是1024字节,并且文件包含的数据最多为268KB,那么,通过直接映射可以访问文件最初的12KB数据,通过简单的间接映射可以访问剩的13KB到268KB的数据。大于2GB的大型文件通过指定O_LARGEFILE打开标志必须在32位体系结构上进行打开。

 

 

2 文件的洞

 

 

文件的洞(file hole)是普通文件的一部分,它是一些空字符但没有存放在磁盘的任何数据块中。洞是Unix文件一直存在的一个特点。例如,下列的Unix命令创建了第一个字节是洞的文件:


[root@localhost]# echo -n "X" | dd of=/tmp/hole bs=1024 seek=6

 

现在,/tmp/hole有6145个字符(6144个空字符加一个X字符),然而,这个文件在磁盘上只占一个数据块。

 

引人文件的洞是为了避免磁盘空间的浪费。它们因此被广泛地用在数据库应用中,更一般地说,用于在文件上进行散列的所有应用。

 

文件洞在Ext2中的实现是基于动态数据块的分配的:只有当进程需要向一个块写数据时,才真正把这个块分配给文件。每个索引节点的i_size字段定义程序所看到的文件大小,包括洞,而i_blocks字段存放分配给文件有效的数据块数(以512字节为单位)。

 

在前面dd命令的例子中,假定/tmp/hole文件创建在块大小为4096的Ext2分区上。其相应磁盘索引节点的i_size字段存放的数为6145,而i_blocks字段存放的数为8(因为每4096字节的逻辑块包含8个512字节的物理块)。i_block数组的第二个元素(对应块的文件块号为1)存放已分配块的逻辑块号,而数组中的其他元素都为空(参看下图)。

 

3 分配数据块

 

 

当内核要分配一个数据块来保存Ext2普通文件的数据时,就调用ext2_get_block()函数。如果块不存在,该函数就自动为文件分配块。请记住,每当内核在Ext2普通文件上执行读或写操作时就调用这个函数;显然,这个函数只在页高速缓存内没有相应的块时才被调用。


ext2_get_block()函数处理在刚才“数据块寻址”描述的数据结构,并在必要时调用ext2_alloc_block()函数在Ext2分区真正搜索一个空闲块。如果需要,该函数还为间接寻址分配相应的块(参见本篇博文第一个图)。

 

为了减少文件的碎片,Ext2文件系统尽力在已分配给文件的最后一个块附近找一个新块分配给该文件。如果失败,Ext2文件系统又在包含这个文件索引节点的块组中搜寻一个新的块。如果还是失败,作为最后一个办法,可以从其他一个块组中获得空闲块。

 

Ext2文件系统使用数据块的预分配策略。文件并不仅仅获得所需要的块,而是获得一组多达8个邻接的块。ext2_inode_info结构的i_prealloc_count字段存放预分配给某一文件但还没有使用的数据块的数量,而i_prealloc_block字段存放下一次要使用的预分配块的逻辑块号。当下列情况发生时,释放预分配而一直没有使用的块:当文件被关闭时,当文件被缩短时,或者当一个写操作相对于引发块预分配的写操作不是顺序的时。

 

ext2_alloc_block()函数接收的参数为指向索引节点对象的指针、目标(goal)和存放错误码的变量地址。目标是一个逻辑块号,表示新块的首选位置:

static unsigned long ext2_alloc_block (struct inode * inode, unsigned long goal, int *err)
{
#ifdef EXT2FS_DEBUG
      static unsigned long alloc_hits, alloc_attempts;
#endif
      unsigned long result;


#ifdef EXT2_PREALLOCATE
      struct ext2_inode_info *ei = EXT2_I(inode);
      write_lock(&ei

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值