linux 中 ext2文件系统实现

ext2文件系统结构

图片的svg下载链接(图中关于buffer的部分,上下两部分是重复的,是从不同维度下看的buffer结构)

linux内核本身不提供ext2文件系统的格式化功能,可以参考busybox中对mkfs.ext2的实现(mkfs.ext2.c)格式化过程简述如下:

mkfs_ext2_main():
  计算每个部分的资源
  填充super_block
  填充group_desc_blocks,desc中主要包含三部分数据块的块号
    bg_block_bitmap,
    bg_inode_bitmap, 
    bg_inode_table
  在每个group的bitmap块中标记这些元数据块的位置为已分配(其中第一块还会有super_block)
  将inode_table空间初始化为0
  添加. .. lost_found 这三个目录项。

在busybox中块大小与总大小有关,总磁盘大小至少是64k,64k-512m是4096B,512m-4T是8192B(4T以上不考虑了)。一个group中装的block数是一块bitmap块所能承载的数(比如一块4096byte时,能代表的块数是4k*8=32k个块)

从代码流程可以看出ext2系统的布局如下:

没有引导块,super block存了整体信息,group desc存了group信息所在块号(最重要的是三种块的块号:block分配bitmap、inode分配的bitmap、inode 实际存储信息的多个块)。这两部分信息有多个备份。真正的inode和文件内容存在data block上。

ext2中inode分配

inode分配的实现在ext2_new_inode,每次尝试从inode数和block数都占用不多的group分配inode(find_group_orlov),然后从这组的bitmap中找一个合适的位置setbit,它对应了inode_table 中一段实际的磁盘空间。从slab中分配一个包含inode节点的struct ext2_inode_info,将找到的inode号填入inode->ino中,这里不需要访问设备。将inode_table对应位置所在块和inode bitmap 所在块标记为dirty(mark_buffer_dirty),之后就在合适时间等着刷盘就好了(这个链路可以参考linux buffer的回写的触发链路)。

注:存在设备上的inode状态中信息大部分来自于inode 结构。但在内存中会对这个inode结构做一个封装(ext2_inode_info),inode结构存在ext2_inode_info->vfs_inode位置。可以通过EXT2_I(struct inode *inode)函数找到inode对应的ext2_inode_info。

目录inode的分配

另外当分配一个路径时,每个dir inode有一个对应的block,上面存了ext2_dirent,它是可变长的结构(因为路径的名称可长可短)。当要删除一个路径时,不需要将后面的dirent向前补齐,而是将dirent与前一个dirent合并。所以在分配时也是同理,需要遍历dirent,将合适的dirent的空闲部分切下来作为新的dirent。

寻找目录分配在哪个group也有讲究(Orlov算法):有两个原则。1、新目录尽可能与父目录在同一个group或相近的group;2、如果未达到一定阈值,可直接分配,如果达到阈值则找离父group最近的,剩余空闲inode数大于平均的group分配。

阈值有三点(每个group的dir数之间不能差太多):

1、目录数的绝对上限:平均每group分配目录数+1/16每组分配上限(每个group的dir数不能太多)

2、空闲inode数和block数下限:group平均值-1/4每组分配上限(每个group的dir数不能太少)

3、debt = 分配目录-分配文件。要求debt * INODE_COST <  N_{group\_blocks}\times \frac{N_{dir}}{N_{block}}(根据平均每目录占用block数,计算的未来需要block数不能过载)

ext2中inode的访问

每个inode 的ext2_inode_info中有一个i_data数组,当一个inode文件中分配块数少于12时,可以直接使用i_data的前12个元素作为逻辑块1-12所对应的物理块号。当一个文件块数超过12小于1024(一个block所能装int类型的数量)时,i_data的第13位(index = 12)指向1级列表所在的块,这块中每一项表示对应逻辑块(12-1023)的物理块号。

依此类推,1K-1M之间的逻辑块用i_data[13]所指向的二级块表来索引,1M-1G之间的逻辑块用i_data[14]所指向的三级块表来索引。

当读取一个block时,首先通过inode的块表找到对应逻辑块的物理块号(ext2_block_to_path)。将物理块加载到内存中,封装成一个buffer_head结构,并返回(ext2_get_block)。

buffer_head是设备与buffer之间的一个扭带,它映射了设备上的一片区域(在代码中一个buffer_head对应几个连续的block)。真正的buffer内容存在struct page对应的页空间上(页与struct page的转换关系可以参考:linux中 struct page 与物理地址的关系)

下图中filio是对page的封装,可以理解为一段连续物理内存页的集合,第一页的folio->page上存了页区间的第一个struct page,其后连续的struct folio填满了folio对应的区间。(下图中画的page指向一段页,实际上不是指针关系,而是上面链接提到的,struct page结构地址本身映射了一块内存),这些实际的物理内存组成了一段buffer。区间第一页的folio->private是buffer_head的链表,其上存了这个buffer与块设备上block内容的对应关系,其中buffer_head->b_data指向一个block大小的buffer。(下图中更正:一个buffer_head不一定对应一个块,可以对应几个连续块(注:从grow_buffers函数的注释和grow_dev_page的实现可以看出,block的大小一定比页小))

当修改文件中一段内容时,它对应的块的buffer_head会链在inode->private_list所在链表上。等待后期刷盘时遍历。如下图所示:

这里想到一个问题,当父进程fork了一个子进程,这个子进程中通过copy on write 的方式修改了一个文件的内容,会发生什么改变呢?答案是什么也不会发生,因为copy on write是在逻辑地址上做的文章(原理可以参考这篇:理解linux中反向映射与应用),这里的buffer都是物理地址。

ext2中inode块的分配

由于底层访问接口中一次只加载一个block,为了让逻辑上连续的块在物理设备上也尽可能连续,每次为inode分配逻辑块时,会启发性地,一次分配多个连续的块(ext2_get_blocks),我们重点分析下这个启发式过程。

其中每个文件可能有自己的reserve window,但并不保证分配的块一定属于这个文件,有可能在分配reserve window之前其间的物理块早被多个其它文件分配过。reserve window的作用只是说先占着,别的文件分配时会跳过这个区域,从而保证一个文件在分配时物理块尽可能在一起。分配window时的算法保证这个reserve winodw的区域至少有一个空闲块(alloc_new_reservation)。

ext2_get_blocks():
  // 将块号分解为块表的分量
  ext2_block_to_path();
  // 将块表链路上的块都找到,收集到chain中
  // chain节点Indirect的key=下层物理块号,p=下层逻辑块号所在地址
  ext2_get_branch();
  
  // 选定一个目标块用来分配,原则是尽可能与同一文件分配过的块挨着
  // 如果上次分配的逻辑块号与物理块号刚好可用,则选定这个块号
  // 否则在这个块中向左找分配过的物理块号,选定接在它(逻辑上分配过的块的物理块号)后面。
  // 如果这一逻辑块中前面没有分配过的块,则选承载这级块表的物理块的后面一块。
  // 如果这是新文件,没有分配过块表,则在inode所在group的1/16*x分配
  // (x在0到15之间,目的是让新文件分配的物理块尽可能隔开,这样可以使同一文件的物理块尽可能挨着)
  ext2_find_goal();
  
  // 启发式计算一次性分配多少连续块(分配长度),
  // 这里不要求物理块连续,会在后面将分配长度削减到连续物理块数:
  // 如果块表的最后一级是中间块,则分配长度为传入的maxblocks块。
  // 如果maxblocks数量跨过了这个中间块,则分配长度为从逻辑块位置到这个中间块表结束的块数。
  // 如果块表的最后一级是叶子块,则分配长度为选定逻辑块后没有分配过的连续逻辑块块数。
  ext2_blks_to_allocate();

  // 分配块表子链
  // 传入参数indirect_blks指最后一级块表到分配data块还差几层
  // blks和goal指上面启发式计算的分配长度和启始分配块
  ext2_alloc_branch():
    ext2_alloc_blocks():
      // 尝试分配至少indirect_blks(新块表项)+1个块,
      // 其中前面的作为data块,后面的作为新块表块
      while (分配的连续块还不够用)
        ext2_new_blocks();

  // 将buffer_head与这个分配的连续data块绑定(不包含块表块)
  map_bh(bh_result, bno);

  // 如果分配的块数超过了最后一级块表的边界,只有一种可能
  // 就是新分配的块表块接在了新分配的data 块后面。
  // 则在buffer_head上标记一下,后面刷盘时,除了刷data block外,
  // 连带要检查一下后面的块,因为它可能是这个data block所在的块表块。
  // 一起刷盘更能保证原子性(write_boundary_block)
  set_buffer_boundary(bh_result);



ext2_new_blocks():
  先尝试从选定块的group上的reserve window分配
  如果不能分配,其它group只取free block大于reserve window 的一半的reserve window分配
  如果用reserve window分配不成功,尝试不用reserve window分配,还是先goal group,再其它group。
  实现用了同一个入口函数 ext2_try_to_allocate_with_rsv
  

ext2_try_to_allocate_with_rsv():
  在尝试reserve_window的场景,尝试通过扩张reserve window的方式来满足分配大小,
  在有指定目标物理块的情况下,尝试让window覆盖目标块
  如果忽略了目标物理块,则尝试从整个group去分配。
  扩张有几个原则:1、如果window内已经分配过一半以上,尝试扩张一倍大小。
  2、如果覆盖了目标块,尝试让reserve window覆盖请求的大小
  3、扩张后的块内必须至少有一个free的block
  然后调ext2_try_to_allocate从bitmap中去找一个空闲块。
  当扩张大小不足以覆盖请求大小时,尝试缩短请求连续块数
  在不尝试reserve_window的场景,直接调ext2_try_to_allocate找空闲块


ext2_try_to_allocate():
  // 找空闲块有一定算法:
  // 先从start位置到64 align 的位置结束找free bit.
  // 如果没找到,尝试找空字节(以8bit为单位找)。
  // 如果还没找到,才尝试从start位置开始,一个bit一个bit地找。
  find_next_usable_block();

  // 当找到空闲bit后,由于上面算法有以8bit为单位找的情况
  // 因而向前找7个bit,看有没有连续的空闲块可用
  for (i = 0; 
    i < 7 && grp_goal > start && !ext2_test_bit(grp_goal - 1,bitmap_bh->b_data);
    i++, grp_goal--);
  
  // 返回连续块的开始位置和块数
  *count = num;
  return grp_goal - num;
  

向ext2文件写内容

write的调用到真正操作如下:

write
 ->ksys_write
  ->vfs_write
   ->new_sync_write
    ->call_write_iter
     ->ext2_file_write_iter (ext2 的 op hook)
      ->generic_file_write_iter
       ->__generic_file_write_iter
        ->generic_perform_write
         ->file->f_mapping->a_ops

file的f_mapping就是inode->i_mapping,inode->i_mapping是在从slab拿一个ext2_inode_info时callback hook(init_once)中填充的。而file->f_mapping是在alloc_file时填充的(f_mapping = inode->i_mapping)。

写的过程分为write_begin,copy_page_from_iter_atomic,write_end三步。

第一步ext2_write_begin时,会做两件事,一个是准备buffer,为buffer分配页(会将folio->mapping 置为inode的i_mapping,filemap_add_folio),另一个是准备块,为刷盘区间的逻辑块分配物理块 (get_block)。

第二步迭代传入的用户空间的data,copy到buffer中(copy_page_from_iter_atomic)。

第三步ext2_write_end,标记buffer为dirty(__block_commit_write)。

在写完之后,会调一次sync,来刷盘(generic_file_write_iter->generic_write_sync)。从dirty到刷盘链路可以参考linux buffer的回写的触发链路

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/273795.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】顺序表与单链表的增删查改

文章目录 前言顺序表增删查改顺序表的定义与初始化增删查改操作测试代码完整代码 单链表的增删查改数据结构定义动态申请节点单链表的尾插和头插单链表的尾删和头删单链表的查找单链表的插入和删除销毁链表测试代码完整代码 总结 前言 在计算机编程领域&#xff0c;数据结构是…

安全运维是做什么的,主要工作内容是什么

安全运维&#xff0c;简称SecOps&#xff0c;是一种集成安全措施和流程到信息技术运维的实践。它的目的是确保在日常运维活动中&#xff0c;如网络管理、系统维护、软件更新等&#xff0c;均考虑并融入安全策略。安全运维的核心是实现安全和运维团队的密切协作&#xff0c;以快…

前端map标签(创建热点区域或是点击图片指定区域跳转对应链接))

前言 点击整张图片的某一部分,可以实现自定义跳转或者一些事件 利用img和map和area标签实现 先来看下实现 https://www.w3cschool.cn/tryrun/showhtml/tryhtml_areamap <img src"/statics/images/course/planets.gif" width"145" height"126&…

条件覆盖和条件组合覆盖测试设计-实验八例题

目录 条件覆盖 判定-条件覆盖 条件组合覆盖 实验内容&#xff1a; 以银行内部转账为实例&#xff0c;针对内部转账业务逻辑代码进行分析&#xff0c;运用条件覆盖和条件组合覆盖进行测试用例设计。 实验过程&#xff1a; 条件覆盖 条件覆盖&#xff08;Condition Cover…

java中XML格式转换

之前很少用xml格式&#xff0c;但是有些老系统还是需要使用xml格式进行对接&#xff0c;所以干脆总结一下&#xff0c;方便以后使用。 关于xml: 即可扩展标记语言&#xff0c;xml是互联网数据传输的重要工具&#xff0c;它可以跨越互联网任何的平台&#xff0c;不受编程语言和操…

Word中插入mathtype的行内公式显示不全,设置行距,最小值

Word中插入mathtype的行内公式显示不全 如下图&#xff1a;公式上下被遮住 解决方式&#xff1a; 设置所在段落的行距&#xff1a;最小值--xx磅。同时取消勾选 “如果定义了文档网格&#xff0c;则对齐到网格” 处理后效果&#xff1a;

Flash芯片W25Q系列驱动注意事项以及跨页读写操作

一、硬件 二、W25Q64简介与API函数 1) W25Q有很多系列&#xff0c;其区别就是存储容量不一样 以我现在使用的举例W25Q64 64指的是64Mbit&#xff0c;不是64M字节要区分清楚 64Mbit 8Mbyte,所以总的容量能存储8MByte 2) W25q64的存储分为块、扇区、页 一页&#xff1…

人类偏好导向:DPO技术重塑SDXL-1.0图像生成

引言 在AI领域&#xff0c;适应和理解人类偏好一直是技术发展的重要方向。斯坦福大学研究团队最近提出的Diffusion-DPO方法&#xff0c;旨在将这一理念应用于图像生成模型&#xff0c;特别是在文本到图像的转换领域。 Huggingface模型下载: https://huggingface.co/mhdang/ A…

windows搭建MySQL 8.25主从配置

1.本次搭建的版本 mysql-8.0.25-win-x64 2.在解压完成后的文件内并没有对应的my.ini的配置文件这个my.ini是需要的主配置文件需要自行创建。 注&#xff1a;安装路径及数据存放路径需根据实际安装情况进行修改&#xff08;其它配置信息可结合实际情况进行修改&#xff09; 3.在…

【Vue】响应式中数组的特殊处理

Vue 响应式中对数组的处理 前两节的内容&#xff1a; Vue 数据劫持 Vue 响应式初步 0. 为什么需要对数组特殊处理&#xff1f; 在响应式初步那一篇文章的最后&#xff0c;我们提到过&#xff0c;需要对数组进行特殊的处理&#xff0c;为什么&#xff1f; 如果仍然用我们之…

vue3(六)-基础入门之自定义组件与插槽、ref通信

一、全局组件 html: <div id"app"><mytemplace></mytemplace> </div>javascript: <script>const { createApp } Vueconst app createApp({})app.component(mytemplace, {template: <div><button>返回</button>…

Resnet

是什么样的原因导致更深的网络导致的训练效果更差呢&#xff1f; 梯度消失和梯度爆炸 随着网络层数的不断加深&#xff0c;梯度消失和梯度爆炸的现象会越来越明显&#xff0c; 梯度消失&#xff1a;假设每一层的误差梯度是一个小于1的数&#xff0c;那么在我们反向传播过程中…

<软考高项备考>《论文专题 - 26 整合管理(4) 》

6 过程5-监控项目工作 6.1 问题 4W1H过程1-制定项目章程做什么跟踪、审查和报告整体项目进展&#xff0c;以实现项目管理计划中确定的绩效目标的过程&#xff1b;作用&#xff1a;①让干系人了解项目的当前状态并认可为处理绩效问题而采取的行动;②通过成本和进度预测&#x…

Docker 高级网络 - 自定义网桥实现容器间通信

目录 一、容器间容通信 1.1、解释 1.2、网络相关操作指令 1.2.1、查看 docker 的网络列表 1.2.2、创建网络自定义桥 1.2.3、删除某一个网络 1.2.4、查看某一个网络细节 1.2.5、运行多个容器在指定的网络中 一、容器间容通信 1.1、解释 简单来讲就是&#xff1a;容器间通…

华为Auth-HTTP服务器任意文件读取漏洞

华为Auth-Http Server 1.0存在任意文件读取&#xff0c;攻击者可通过该漏洞读取任意文件。 1.漏洞级别 高危 2.漏洞搜索 fofa server"Huawei Auth-Http Server 1.0"3.漏洞复现 构造 GET /umweb/passwd HTTP/1.1 Host: User-Agent: Mozilla/5.0 (Macintosh; I…

APP开发详解:数字药店系统源码

数字药店系统的兴起&#xff0c;不仅为消费者提供了更加便捷的购药体验&#xff0c;也为药店管理和药品销售带来了全新的机遇。 一、明确系统的基本功能&#xff1a; 1.用户注册与登录 2.药品浏览与搜索 3.购物车与结算。 4.在线支付与订单管理 二、开发环境与技术栈选择 …

blackbox黑盒监控部署(k8s内)tensuns专用

一、前言 部署在k8s中需要用到deployment、configmap、service服务 二、部署 创建存放yaml的目录 mkdir /opt/blackbox-exporter && cd /opt/blackbox-exporter 编辑blackbox配置文件&#xff0c;使用configmap挂在这 vi configmap.yaml apiVersion: v1 kind: Confi…

c语言-表达式求值

目录 前言一、隐式类型转换1.1 整型提升 二、算术转换三、操作符的属性四、问题表达式总结 前言 表达式求值的顺序一部分由操作符的优先级和结合性决定。 有些表达式的操作数在求值的过程中可能需要转换为其他类型 一、隐式类型转换 隐式类型转换是在编译器自动进行的类型转换…

TYPE C 接口知识

1、Type C 概述 Type-C口有4对TX/RX分线&#xff0c;2对USBD/D-&#xff0c;一对SBU&#xff0c;2个CC&#xff0c;另外还有4个VBUS和4个地线。 当Type-C接口仅用作传输DP信号时&#xff0c;则可利用4对TX/RX&#xff0c;从而实现4Lane传输&#xff0c;这种模式称为DPonly模式…

手持机定制_手持终端_rfid手持终端设备开发解决方案

智物通讯PDA手持终端方案以联发科64位八核MT6771芯片为核心&#xff0c;配备Android 10系统&#xff0c;以提供更高的运行速度和更低的功耗。存储器方面&#xff0c;则有2GB LPDDR332GB eMMC&#xff0c;同时也可选择4GB64GB、8GB128GB的配置&#xff0c;以确保设备的顺畅运行。…