Ext4文件系统架构分析(三)
ioctl源码分析之交换两个文件的物理extents
1. 交换两个文件的extents
Ext4 的EXT4_IOC_MOVE_EXT命令用于交换两个文件的extents,实际上是交换两个文件的对应逻辑长度的数据的物理存储空间(见下图),也是EXT4文件系统碎片整理的基础。

用户可以通过ioctl函数使用Ext4文件系统的Ioctl命令EXT4_IOC_MOVE_EXT将用户指定交换的两个文件及交换的范围的相关信息struct move_extent的地址传给ioctl的第三个参数unsigned int arg:

ioctl(fd, EXT4_IOC_GROUP_ADD, arg )
至于操作是否成功,结果验证可以使用filefrag命令,分别在执行转移前后使用该命令获取文件的区段信息,就可以判断是否执行的转移(交换)操作。
2. EXT4_IOC_MOVE_EXT交换文件extents的限制
利用Ext4 的EXT4_IOC_MOVE_EXT交换两个文件的extents的操作受到以下限制(这里将进行转移的文件称为源文件,参与转移操作正确执行的另一文件称为donor文件):
1. 文件自身的限制:
1)源文件与donor文件应该是不同的文件;
2)源文件与donor文件应该是常规文件;
2. 交换区段的参数限制(即调用mext_check_arguments()函数检查struct move_extent的元素数值是否有效):
1)donor文件都不能设置SUID或SGID;
2)两个文件都不能支持swapfile,也就是两个文件都不能是swapfile;
3)两个文件应当在同一个Ext4文件系统中;
4)两个文件都要是基于extent的;
5)两个文件都不能是0长度的;
6)交换的(逻辑)起始偏移应该相等;
7)两个文件的交换起始偏移块号、交换的数据块的个数以及转移的最后一个数据块的块号都不能超过一个文件的最大逻辑块(2^32 -1),这是因为Ext4文件系统支持的最大文件为16TB;
8)当源文件长度大于donor文件长度时:
a) 如果起始数据块大于等于donor文件的所有数据块个数,则退出;
b) 如果起始数据块加上转移数据块的个数得到的逻辑数据块号大于donor文件的最后一个逻辑数据块号,则需要对转移数据块的个数进行修改,新的转移长度为donor文件的长度减去起始逻辑数据块号;
9)当源文件长度小于等于donor文件长度时:
a) 如果起始数据块大于等于源文件的所有数据块个数,则退出;
b) 如果起始数据块加上转移数据块的个数得到的逻辑数据块号大于源文件的最后一个逻辑数据块号,则需要对转移数据块的个数进行修改,新的转移长度为源文件的长度减去起始逻辑数据块号;
10)经过以上检查后还有确定转移的数据块的个数不能为0;
3. 交换文件的extents的操作过程
1. 首先打开的文件不是用于读或写,那么这个描述符无效,则不对文件进行extents交换;

2. 将用户设置的转移信息struct move_extent拷贝到内核空间;
3. 设置已转移(交换)的数据块的数据块的个数为0;
4. 获取donor文件的描述符,然后确认donor文件以可写的方式打开;
5. 获取对文件系统的写权限;
6. 调用ext4_move_extents()函数,转移(交换)文件指定范围的数据的物理存储位置。该函数的操作流程如下:
1)判断文件自身是否受限制(标准见上一小节文件自身的限制);
2)获取源文件与donor文件的i_mutex锁,防止操作过程中文件被截断;
3)按inode号顺序获取两个inode的 i_data_sem写锁,防止extent tree被delalloc破坏;
4)调用mext_check_arguments()函数检查交换的两个文件及其指定的参数能否满足move extent的条件(步骤参见上一小节交换区段的参数限制);

5)先获取源文件的最后一个数据块的逻辑块号,然后获取源文件的待转移的extents中的最后一个数据块的逻辑块号;如果文件的最后一个数据块逻辑号小于待转移的extent中的最后一个数据块的逻辑块号,则重新修正转移长度为起始偏移到文件末尾;

6)为交换指定的起始逻辑块号block_start寻找一个extent path,也就是建立对这个新的extent的路径索引,主要通过调用get_ext_path()函数实现;

7)为交换指定的起始逻辑块号block_start寻找一个extent path以检查文件空洞情况;

8)获取源文件的extent树的深度;
9)根据指定的转移起始块是否在文件的hole中的情况,修正转移起始数据块;

10)判断以当前extent的起始块的extent是否有数据块位于待转移的数据块范围内(这种情况指定的范围可能是一个文件的空洞),不在则退出;
11)进行extent的转移(交换):
a)计算当前可转移(交换)的数据块的个数;
b)以当前extent为起点,首先修正当前extent中可被转移的数据块个数;
c)设置当前extent为前一个extent(ext_prev),然后确定下一个待转移的extent作为新的当前extent(ext_cur),计算下一个待转移的extent中包含的数据块的个数;

d)然后判断当前extent是否可以与前一个extent合并,可以的话,跳到b)继续执行,否则进入下一步;
e)判断当前extent的前一个extent是否未初始化(如果extent的长度大于一个块组的长度则被认为是未初始化的extent);

f)转移(交换)前一个extent中的数据块,首先释放两个inode的i_data_sem写锁,然后反复调用move_extent_per_page()函数,每次转移一个page中的extent中的数据。move_extent_per_page()函数的主要操作是通过调用mext_replace_branches()函数,首先保存源inode的数据块,然后使用donor inode的相应extents 替换源inode的extents,最后,将保存的源inode的数据写到源inode的新的数据块中,并返回替换的数据块的个数;mext_replace_branches()函数一页一页地使用donor inode的extents替换源inode的extents;按以下三步实现这种替换:

i 保存原始inode及donor inode的数据块信息到dummy extents中;
ii 改变源inode的数据块信息指向donor文件的数据块;
iii 改变donor inode的数据块信息指向保存在dummy extents中源inode的数据块的信息.
g)获取两个inode的 i_data_sem写锁;
h)获取下一个转移的extent;获取成功,则跳到b)继续执行;否则,表示需要转移的数据块都已转移完毕。

12)资源释放:
a)两次调用ext4_discard_preallocations()函数分别释放预分配给源inode和donor inode的数据块;
b)释放两个extent路径orig_path与holecheck_path占用的空间;
c)释放两个inode的i_data_sem写锁;

13)释放两个inode上的i_mutex 锁,转移(交换)操作结束;
7. 结束对文件系统的写操作;
8. 判断转移(交换)的数据块的个数是否不为0(不为0表示确实发生了数据存储位置的转移),如果不为0,那么移除donor文件的SUID (Set User ID);
9. 返回内核空间的struct move_extent信息到用户空间;
10. 释放donor文件描述符,转移操作结束,返回。
ioctl源码分析之强制立即分配延迟分配给文件的数据块
Ext4文件系统支持强制立即分配延迟分配给文件的数据块,本质上是强制立即进行数据同步,也就是立即刷新文件的写缓冲。在Ext4文件系统中,写文件产生新数据时,文件系统并不立即分配数据块存储这些新数据(脏数据),而是延时等待到不得不写数据到磁盘为止,才会为新数据分配磁盘空间。Ext4文件系统的Ioctl命令EXT4_IOC_ALLOC_DA_BLKS用于为单个文件破解这种延迟分配的方式,也就是与该文件相关操作产生的新数据,文件系统立即为其分配空间,不再等待以延时分配。使用以下命令就可实现调用EXT4_IOC_ALLOC_DA_BLKS命令为文件立即分配数据块:
ioctl(fd, EXT4_IOC_ALLOC_DA_BLKS, NULL)
ioctl 命令成功执行后。其中与 fd 所引用的文件相关的新数据,系统立即为其分配存储空间,不延时分配(这一结果可以从 /dev/sys/fs/ext4//delayed_allocation_blocks中查看,如果该文件内容为0,表示没有延迟分配的数据块,否则表示延迟分配的数据块的个数,其中,表示Ext4文件系统所在的设备,如果Ext4在/dev/sda5上,那么dev就表示sda5)。
强制立即分配延迟分配给文件的数据块的操作流程
(1) 判断执行强制立即分配操作的进程是否有相应的权限;
(2) 获取对文件系统的写操作权限;

(3) 调用ext4_alloc_da_blocks()函数,强制立即分配数据块;该函数首先调用函数trace_ext4_alloc_da_blocks(inode)获取延迟分配给文件的数据块的个数,然后判断文件是否为延迟分配预留有数据块或元数据块,如果都没有预留则,直接返回(文件系统认为没有给该文件开启延迟分配的特性).否者,调用filemap_flush(inode->i_mapping)函数,立即强制分配数据块。filemap_flush(inode->i_mapping)函数的工作仅仅是调用__filemap_fdatawrite(mapping,WB_SYNC_NONE)函数,其中WB_SYNC_NONE是一个同步标志,表示不进行任何等待。__filemap_fdatawrite(mapping,WB_SYNC_NONE)函数又调用了__filemap_fdatawrite_range(mapping, 0, LLONG_MAX, sync_mode)函数,该函数最终调用了do_writepages()函数,将文件的所有脏数据写到磁盘。




(4) 释放对文件系统的写操作权限,操作结束
ioctl源码分析之在线扩展Ext4文件系统
Ext4文件系统在线扩展大小的本质是将文件系统的数据块个数扩展到用户期望的数据块的个数。从功能上来看是扩展文件系统最后一个块组(EXT4_IOC_GROUP_EXTEND)与增加块组扩展文件系统(EXT4_IOC_GROUP_ADD)两种方式的结合,但是处理上稍微有点不同。Ext4文件系统的Ioctl命令EXT4_IOC_RESIZE_FS用于在线扩展Ext4文件系统的大小。使用以下命令就可实现调用EXT4_IOC_RESIZE_FS命令扩展Ext4文件系统:
ioctl(fd, EXT4_IOC_RESIZE_FS, arg )
参数arg为用户希望扩展后最终的文件系统所具有的(文件系统)数据块的个数unsigned int arg。
1. EXT4_IOC_RESIZE_FS扩展文件系统的限制
利用Ext4 的EXT4_IOC_RESIZE_FS命令扩展文件系统,它对文件系统的扩展结果受到以下限制:
(1)不支持缩小文件系统;
(2)如果Ext4文件系统开启了bigalloc(大数据块)特性,则不支持在线扩展;
(3)如果Ext4文件系统开启了元块组(meta_bg)特性,则不支持在线扩展;
(4)如果Ext4当前使用32位系统且系统不兼容64位,同时调整后的数据块的个数超过2^32,那么不支持在线扩展;
(5)如果新扩展的部分要使用新的块组描述符数据块,且Ext4中没有预留GDT数据块,则不进行在线扩展;
(6)如果用户期望扩展的文件系统大小超过实际分区,则不进行扩展。
2. 在线扩展Ext4文件系统的操作流程
(1) 依次判断当期Ext4是否开启bigalloc特性与元块组特性,如果开启,则不进行扩展文件系统的操作;

(2)如果当前Ext4文件系统使用32位数据块个数寻址且不支持64位兼容性,那么如果用户期望扩展文件系统使其超过2^32个,则不进行在线扩展;

(3) 设置ext4_sb_info->s_resize_flags标志位,表示将进行在线调整大小;
(4) 获取对文件系统的写权限;

(5) 调用ext4_resize_fs(sb, n_blocks_count)函数扩展文件系统,其中sb为要扩展的文件系统的超级块,n_blocks_count为期望扩展到的最终数据块个数。该函数实际执行如下操作:

a) 判断参数以及文件系统自身的配置是否满足扩展操作执行的条件。
i. 获取当前文件系统的数据块个数;
ii. 判断参数是否指向缩小文件系统,如果是,则推出。不支持缩小文件系统的在线扩展调整;
iii. 如果新增的部分的块组的描述符要在一个新的块组描述符数据块中分配,判断文件系统中是否有预留GDT数据块,如果没有,那么不能进行扩展。
b) 获取预留GDT数据块的Inode并进行有效性检查;
c) 查看硬件物理空间是否足够扩展文件系统;

d) 先将当前文件系统的最后一个块组扩充完整;

e) 以每次新增一个flex块组的方式扩展文件系统,具体步骤如下:
i. 调用alloc_flex_gd(flexbg_size)分配一个struct ext4_new_flex_group_data,用于增加一个flex块组,其中参数flexbg_size为每个flex块组中普通块组的个数;
ii. 反复调用ext4_setup_next_flex_gd(sb, flex_gd, n_blocks_count,flexbg_size)函数每次增加一个新的flex块组,直到所有新增数据块都增加到文件系统中。每次增加一个新的flex块组后,先调用ext4_alloc_group_tables(sb, flex_gd, flexbg_size)在创建的flex块组中分配块位图、Inode位图以及Inode表,然后调用ext4_flex_group_add(sb, resize_inode, flex_gd)函数将块组加到文件系统中。

f) 释放分配的struct ext4_new_flex_group_data空间,将预留GDT数据块的Inode的引用次数减1,返回。

(6) 建立日志事务锁(barrier机制),更新文件系统元数据;
(7) 释放对文件系统的写权限;

(8) 清除ext4_sb_info->s_resize_flags标志位,返回;扩展文件系统操作结束。
Ext4文件系统架构分析(三)的更多相关文章
- Ext4文件系统架构分析(三) ——目录哈希、扩展属性与日志
struct dx_root Htree的内部节点: struct dx_node Htree 树根和节点中都存在的 Hash map: struct dx_entry 1.20 扩展属性EA 扩展属 ...
- Ext4文件系统架构分析(二)
接着上一篇博文,继续分析Ext4磁盘布局中的元数据. 1.7 超级块 超级块记录整个文件系统的大量信息,如数据块个数.inode个数.支持的特性.管理信息,等待. 如果设置sparse_super特性 ...
- Ext4文件系统架构分析(一)
本文描述Ext4文件系统磁盘布局和元数据的一些分析,同样适用于Ext3和Ext2文件系统,除了它们不支持的Ext4的特性外.整个分析分两篇博文,分别概述布局和详细介绍各个布局的数据结构及组织寻址方式等 ...
- 使用hexdump工具追踪EXT4文件系统中的一个文件
昨天追踪EXT4文件系统的过程中出了点问题,就是找不到文件,于是试了一下追踪FAT32文件系统的,成功之后有了点信心,今天继续嗑EXT4文件系统,终于找到啦,记录一下. 操作系统:linux(cent ...
- ext4文件系统的delalloc选项造成单次写延迟增加的分析
最近我们的服务进程遇到kill -15后处于Z的状态,变为了僵尸进程,经过/proc/{thread_id}/stack查看其上线程的栈,发现是卡在了fwrite的过程中,而我们的系统中所有文件系统挂 ...
- [转载]ext4文件系统的delalloc选项造成单次写延迟增加的分析
转载http://www.cnblogs.com/cobbliu/p/5603472.html 最近我们的服务进程遇到kill -15后处于Z的状态,变为了僵尸进程,经过/proc/{thread_i ...
- NTFS文件系统详细分析
NTFS文件系统详细分析 第一部分 什么是NTFS文件系统 想要了解NTFS,我们首先应该认识一下FAT.FAT(File Allocation Table)是“文件分配表”的意思.对我们来说 ...
- [转帖]InfiniBand技术和协议架构分析
InfiniBand技术和协议架构分析 2017年06月06日 20:54:16 Hardy晗狄 阅读数:15207 标签: 云计算存储Infiniband 更多 个人分类: 存储云计算 版权声明 ...
- 【转载】Instagram架构分析笔记
原文地址:http://chengxu.org/p/401.html Instagram 架构分析笔记 全部 技术博客 Instagram团队上个月才迎来第 7 名员工,是的,7个人的团队.作为 iP ...
随机推荐
- Jquery中parent()和parents()
一.parent()方法 此方法取得匹配元素集合中每个元素的紧邻父元素,也就是第一级父元素,而不是所有的祖先元素.所取得的父元素集合也可以使用表达式进行筛选. 二.parents()方法 此方法取得一 ...
- ComboBoxEdit 数据绑定 使用模板
1)定义模板资源 <UserControl.Resources> <local:StatusConvertor x:Key="StatusConvertor"&g ...
- 2015年末分享:利用RS修改用户密码
马上就要2016农历新年了,送点什么给大家呢?我觉得还是分享点技术吧.前不久用户在抱怨为什么登录Cognos Connection的密码不能让我们自己改?相信Cognos开发的很多人知道,Cognos ...
- 1. Change the emulator screen size
1. "Windows" ==> "Android Virtual Device Manager" ==> Select one emulator ...
- 矩阵经典题目四:送给圣诞夜的礼品(使用m个置换实现对序列的转变)
https://vijos.org/p/1049 给出一个序列,含n个数.然后是m个置换,求对初始序列依次进行k次置换,求最后的序列. 先看一个置换.把置换表示成矩阵的形式.然后将m个置换乘起来.那么 ...
- PHPCMS增加投票选项代码
<script src="jquery-1.10.1.js"></script> <tr> <th width="20%&quo ...
- 4667 Building Fence 解题报告
题意:给n个圆和m个三角形,且保证互不相交,用一个篱笆把他们围起来,求最短的周长是多少. 解法1:在每个圆上均匀的取2000个点,求凸包周长就可以水过. 解法2:求出所有圆之间的外公切线的切点,以及过 ...
- Java IO--字节-字符流转换
OutputStreamWriter和InputStreamReader 一般在操作输入输出内容的就需要使用字节或字符流,但是有些时候需要将字符流变为字节流的形式,或者将字节流变为字符流的形式,所以, ...
- wepy - 与原生有什么不同(watcher监听器.)
<style> </style> <template> <view>监听值:{{num}}</view> </template> ...
- Python 的时间格式化
对于像'Wed, 11 Apr 2012 09:37:05 +0800'的时间格式化可如下解: >>> date='Wed, 11 Apr 2012 09:37:05 +0800'& ...