Linux磁盘空闲空间调度管理

操作系统的磁盘管理为了和内存管理配合,也是将磁盘分割为最小单元进行统一调度,和内存的页帧概念对应,磁盘管理模块以磁盘块作为最小单元管理磁盘(常见的磁盘块为1KB,对应2个512B扇区,磁盘块是OS概念,磁盘驱动读取是以扇区作为最小单元)。

1.数组表格和链表管理

继承内存页帧的段页式管理思想,自然可以想到磁盘管理的空闲空间表法和空闲块链法。前者是指为所有空闲区建立一张空闲表,每个空闲项表示该空闲区的序号、第一个磁盘块号以及空闲盘块数目等信息。该表格管理的磁盘空闲区和内存的动态分配类似,以空间大小为评判标准,可采用首次适用匹配法、循环首次适用算法(平均各磁盘块出场机会),还可以采用合并措施增加某相邻两块空闲区,以提供更大的空闲区。可以预想这张表格将会很大(一般该空闲表都存在外存,需要多次低效率的I/O读操作分批次读入内存),并且由于各空闲区的大小不一致引入的变量,这导致在分配过程中需要增加遍历空闲表项匹配size需求,无疑为磁盘管理增加了不小的设计负担。

Linux磁盘空闲空间调度管理_第1张图片
Fig.1 空闲空间数组表格

空间块链表管理的思路,则是在每个空闲块中留出部分固定位用来指向下一块空闲磁盘块。这种思路当然是无需操作增加额外的辅助结构,但是由于若是需要分配多块空闲空间,则需要多次I/O操作以提取下一块空闲块,故而效率其实是很低的,而且是隐式链接,一旦磁盘某个空盘块的nextfree_block指针位置出现故障,很可能出现磁盘无法使用的情况,鲁棒性较差。

Linux磁盘空闲空间调度管理_第2张图片
Fig.2 空闲空间管理链表

2.Bitmap位图管理

其实从以上分析中可以发现,磁盘空闲块管理需要尽可能地加快磁盘块索引速度,同时又要尽可能地减少空闲块管理所需的辅助空间。考虑这些要求,显然Bitmap是不得不提的方法(位图算法也是布隆过滤器的基础)。用每个bit来表示一个盘块的使用情况(0为空,1为占用,则对于1KB的盘块,1G的磁盘,总共有2^20块,则需要128KB的空间来描述所有磁盘块)。但是这样子的话,磁盘直接以磁盘块与OS内核交互,需要CPU根据Bitmap中bit位置信息换算成盘块位置,增加了计算负担,同时粒度过小让磁盘块难以成片出现,这会导致一个文件分布在磁盘各个跨区很大的盘块中,增加了I/O操作时间(频繁更换磁头号,更换磁道位置)。

Linux磁盘空闲空间调度管理_第3张图片
Fig.3 空闲空间Bitmap

3. 空闲块成组链接法

其实上述方法都太适合大型文件系统,尤其是空闲表格法和空闲链表法,会导致索引结构过长。Linux内核则是融合两种算法,采用了“空闲块先成组,组和组间链表链接”的成组链接法。如100个空闲盘块构成一个空闲组,然后组和组之间通过指针构成链表,每个空闲组中单独拿出第一个空闲盘块来存放下一空闲组的情况(空闲盘块总数、空闲组组长盘块号、当前空闲组各空闲盘块号),组长盘块构成“指针”。如下图,对于空闲磁盘链表链首块组,其第一个磁盘块其实内容是存放下一组的详情信息,而剩余的99个磁盘号才是指向真正的空闲磁盘块,即图中黄色块。

Linux磁盘空闲空间调度管理_第4张图片
Fig.4 空闲空间块成组链接示意图

这里需要提及的另一个概念是内存中的”空闲盘块专用栈“,该对象是临界区( critical_section,互斥独占,保证任何时刻只有一个kernel thread在调用OS的空闲管理模块,进行空闲盘块操作)常驻内存,用来配合Linux磁盘管理模块管理磁盘空闲空间调度。该栈任意时刻都指向当前空间块链表链首组的分配情况,当Linux调用空闲磁盘调度进程,则该栈将根据链首指针装载链表最顶层空闲盘块组信息。
Linux磁盘空闲空间调度管理_第5张图片
Fig.5 空闲盘块专用栈使用原理

磁盘块分配过程
kernel thread调用空闲磁盘块调度进程,先给盘块专用栈加锁,然后根据盘块专用栈中的信息和磁盘容量分配磁盘块,每次分出一空闲磁盘块,则栈顶的freeblocks_sum减1,若是分配到最后,freeblocks_sum=1,即当前空闲盘块组只剩下组长盘块可以分配了,则首先将该组长盘块中指明一下组空闲盘块组的信息读入盘块专用栈,然后将该组长盘块分配出去。

磁盘块回收过程
磁盘回收过程显然是分配的逆过程,唯一需要说明的便是组与组之间交接的情况。假设当前freeblocks_sum=100,代表其实该盘块组已经满了,若是这是内核还需要回收一个新的磁盘块,则将内存中的盘块专用栈内容填写到该新的磁盘块中,然后清空盘块专用栈,并将该新盘块作为新组的组长添加到盘块专用栈中,并将freeblocks_sum置为1。

你可能感兴趣的:(Linux内核)