bigalloc机制
bigalloc机制
简介
概述: 用在初始化文件系统时,以cluster为分配单位而不是块,从而可以指定文件系统的最小分配单位,例如:
1 |
|
优点: 大幅减少元数据量(位图大小将至1/4),提升大文件分配效率
缺点: 小文件可能浪费cluster内空间(如inode所在块组)相邻的cluster,减少寻址开销
示例
4KB大小的bitmap大小:(此时block bitmap每一位表示一个block的状态) \[ 4 * 1024 * 8 * 4KB/bit / 1024 = 128MB \] 对于2TB文件系统,块组数量: \[ 2 * 1024 * 1024 / 128 = 16,384 \] 如果指定cluster大小为1MB,每个块组仍使用1个块(4KB)存储快位图,但每个bit管理1MB的cluster,则bitmap大小:(此时block bitmap每一位表示一个cluster的状态) \[ 4 * 1024 * 8 * 1MB/bit = 32GB \] 对于2TB文件系统,块组数量: \[ 2 * 1024 / 32 = 64个 \]
原理
概述:
传统ext4以4KB块为最小分配单元,每个块在块位图(block bitmap)中占用1bit。
启用bigalloc后,多个物理块组成一个块cluster,block bitmap不再对应一个块,而是一个cluster,分配单位以cluster为最小分配单元
用户态部分
mkfs.ext4源码: https://github.com/tytso/e2fsprogs.git
首先可以知道,mkfs.ext4通过以下选项可以开启bigalloc并指定cluster大小:
1 |
|
通过-O可以指定变量fs_features
为bigalloc,从而使能bigalloc特性
通过-C选项可以赋值变量cluster_size
,然后通过以下代码传递给struct ext4_super_block
字段s_log_cluster_size
:
1 |
|
然后在ext2fs_initialize()
中将fs的超级块标记为dirty:
1 |
|
这样在ext2fs_close2()
的时候,就可以通过ext2fs_flush2()
更新磁盘中的超级块信息,接下来在挂载文件系统的时候就是内核态做的事情了
内核态部分
设置cluster大小
与cluster相关结构体字段说明:
- struct
ext4_super_block:这个结构体只用于磁盘读取和写入,不能影响运行时状态,属于”磁盘上的superblock“
- s_log_cluster_size:superblock的cluster大小(log2后的),计算方式为
clustersize >> BLOCK_SIZE
,当要使用clustersize
转换回来BLOCK_SIZE << s_log_cluster_size
(BLOCK_SIZE一般为10) - s_clusters_per_group:每个块组的cluster数量
- s_blocks_per_group:每个块组的block数量
- s_log_cluster_size:superblock的cluster大小(log2后的),计算方式为
- struct
ext4_sb_info:这个结构体能够通过修改字段影响运行时状态,属于”内存上的superblock“
- s_cluster_ratio:表示每个cluster包含多少个block,计算方式为
clustersize / blocksize
- s_cluster_bits:表示
s_cluster_ratio
是2的几次方,可以理解为s_cluster_bits = log2(s_cluster_ratio)
,用于位运算优化 - s_clusters_per_group:每个块组的cluster数量
- s_blocks_per_group:每个块组的block数量
- s_cluster_ratio:表示每个cluster包含多少个block,计算方式为
通过上面的用户态代码,已经将磁盘块中的superblock更新。
挂载的时候,在sys_mount()
中,会通过ext4_fill_super()
的ext4_load_super()
加载磁盘中的超级块,具体调用链如下:
1 |
|
ext4_load_super()将磁盘中的超级块读取后存储到
struct ext4_super_block
在ext4_fill_super()
中调用ext4_handle_clustersize()
来赋值s_clusters_per_group
、s_cluster_ratio
和s_cluster_bits
,如下:
1 |
|
用户态中重新赋值s_blocks_per_group
的代码:
1 |
|
至此,在挂载文件系统后,与cluster相关结构体的字段已经成功初始化,接下来就是使用阶段,包括分配、回收、统计、bitmap操作时,代码是如何以cluster为分配单位进行执行的。
使用阶段
在使能bigalloc后:
- 逻辑块号在磁盘元数据中依然是以block号表示,即逻辑寻址仍使用block号
- 涉及分配、回收、统计、bitmap操作时,粒度就从block变成cluster(一般来说,会在入口处把block转换为cluster,在出口处把cluster转换为block)
需要先了解一下常用到的宏:
1 |
|
可以注意到,当没有使能bigalloc时,s_cluster_bits
和s_cluster_ratio
均为0,使用这几个宏并不会造成影响,所以只需要在用到block号的地方都用这些宏,这样使能bigalloc自然就以cluster为分配单位,而不使能bigalloc自然就以block为分配单位。
下面以ext4_init_block_bitmap()
作为一个示例,这个函数用于初始未初始化的block
bitmap,每个block group都有一个block
bitmap,它用于标记该组中的每个块是已用还是空闲:
- 这个函数会调用
ext4_num_base_meta_clusters()
来计算一个block group中元数据所占的cluster数,如果没有使能bigalloc,这里返回的是block数,函数中用到了EXT4_NUM_B2C
宏。 - 这个函数会调用
num_clusters_in_group()
来计算某个block group中的cluster数,同样使用了EXT4_NUM_B2C
宏,所以没有使能bigalloc这里返回的是block数
再比如说ext4_ext_map_blocks()
,这个函数负责处理文件逻辑块到物理块的映射关系,在文件读写操作中被调用,用于查找或分配磁盘块。在分配新块时,会用到EXT4_LBLK_COFF
宏、EXT4_NUM_B2C
宏和EXT4_C2B
宏。
一些常见的函数
- block group初始化
- ext4_init_block_bitmap()
- ext4_mb_init_group()
- ext4_mb_generate_buddy()
- ext4_mb_mark_free_simple() / ext4_mb_mark_used_simple()
- ext4_group_first_cluster() / ext4_group_last_cluster()
- mballoc相关
- ext4_mb_new_blocks()
- ext4_mb_normalize_request()
- ext4_mb_use_preallocated()
- ext4_mb_good_group()
- ext4_mb_clear_bb()
- ext4_mb_discard_preallocations()
- 释放与调整相关
- ext4_free_blocks()
- ext4_remove_space()
- ext4_ext_remove_space()
- ext4_ext_rm_leaf()
- ext4_remove_blocks()
- extent建立/修改
- ext4_ext_map_blocks()
- ext4_ext_insert_extent()
- ext4_punch_hole()
- ext4_zero_range()
- ext4_collapse_range()
- 统计、配额与statfs
- ext4_count_free_clusters()
- ext4_get_free_clusters()
- ext4_statfs()
- ext4_calculate_overhead() / ext4_update_overhead()
- 在线resize
- ext4_resize_fs()
- ext4_group_add_blocks()
- ext4_flex_group_add()
- 其他
- ext4_inode_block_valid() / ext4_inode_cluster_valid()
- ext4_mb_discard_group_preallocations()
- ext4_mb_release_group_pa()
- ext4_mb_free_metadata()