浅谈ext4文件系统初始化

2022-08-17 12:59:29 浏览数 (1)

调试环境

代码语言:javascript复制
$ modprobe  -v ext4

$ dd if=/dev/zero of=/tmp/disk1 count=30 bs=1M

$ losetup --show -f /tmp/disk1 
/dev/loop0

$ mkfs.ext4 /dev/loop0

$ mount /tmp/disk1  /mnt/disk1

关于超级快基本知识

  • 当使用者适应mkfs.ext4 /dev/sdb时候,系统按照ext4内部的布局规则写入写入先关数据。mount时候按照内置的布局规则读取这些信息。ext4中涉及的的数据分为两大类,一类是数据;另外一类是元数据
  • 默认扇区大小是512个字节,而磁盘文件系统一般是按照block为单位管理磁盘,默认是4k大小。ext4文件系统为了减少碎片,使文件内容尽量落在相邻的block(这么做为了提高seek性能,尤其是在机械盘呢上)来提高访问的效率,ext4引入了block group,每个block group包含多个block,其中一个block用来这个block group中block使用情况。ext4把相邻的block group组成标记为一个flex_bg(flexible block group)。一个blex_bg中所有的block group的data block bitmapinode bitmapinode table存放在flex_bg的第一个block group,这样在flex_bg中除过第一个block group,其他的都可以存储实际的数据(其中有些block group还是要存储冗余的ext super block和group descriptors).ext4 super block和grouup descriptors会在每个block group中进行复制。下面简单介绍下block group的格式:
  • group 0 padding:第一个block group特有的,存储机器的启动信息;除过第一个block group有padding外,其他的block是没有的。
  • ext4 super block:包含整个磁盘的系统信息
  • group descriptors:所有block group的信息,每一个group descriptor和一个block group一一对应。这个包含block bimap/inode bitmap/ block从属的block group信息等;占用block是由磁盘大小决定
  • reserved gdt blocks:方便未来扩展而预留的空间
  • data block bitmap:存放block group的使用情况的位图。
  • inode bitmap:当前block group中inode使用情况位图
  • inode table:描述block group内所有inode的信息,占用大小是由block group中inode数乘以inode大小
  • data block:存储实际文件数据的block

ext4超级块内容分析

  • 在内核中vfs层定义了通用的struct super_block超级块,这个超级块中的s_fs_info指向ext4磁盘文件系统的struct ext4_sb_info的超级块。
代码语言:javascript复制
// 内核定义的通用超级块
struct super_block {
 // 省略字段
}

// 具体磁盘文件系统ext4的超级块
struct ext4_sb_info {
	// 每个  group descriptor 大小
	unsigned long s_desc_size;	
	// 每个block的inode数量
	unsigned long s_inodes_per_block;
	// 每个block group中的block数量
	unsigned long s_blocks_per_group;
	unsigned long s_clusters_per_group; 
	// 每个block group中inode数量
	unsigned long s_inodes_per_group;/* Number of inodes in a group */
	// 每个block group中inode table数量
	unsigned long s_itb_per_group;	/* Number of inode table blocks per group */
	// 省略其他字段
}
  • ext4文件系统中每个块组会有一个数据机构来描述它,内核使用struct ext4_group_desc结构来描述每个块组信息。dumpe2fs工具转储磁盘时候,Group 0Group N信息都是来自读取struct ext4_group_desc
代码语言:javascript复制
struct ext4_group_desc
{
	// 数据块位图所在的block号
	__le32	bg_block_bitmap_lo;	
	// inode位图所在的的数据块
	__le32	bg_inode_bitmap_lo;
	// inode table所在数据块
	__le32	bg_inode_table_lo;	
	// 空闲数据块数量
	__le16	bg_free_blocks_count_lo;
	// 空闲inodes数量
	__le16	bg_free_inodes_count_lo;
	// 当前目录的数量
	__le16	bg_used_dirs_count_lo;
	// falg信息
	__le16	bg_flags;		
	__le32  bg_exclude_bitmap_lo;   /* Exclude bitmap for snapshots */
	//  crc32c(s_uuid grp_num bbitmap) 低位校验
	__le16  bg_block_bitmap_csum_lo;/* crc32c(s_uuid grp_num bbitmap) LE */
	__le16  bg_inode_bitmap_csum_lo;/* crc32c(s_uuid grp_num ibitmap) LE */
	__le16  bg_itable_unused_lo;	/* Unused inodes count */
	__le16  bg_checksum;		/* crc16(sb_uuid group desc) */
	__le32	bg_block_bitmap_hi;	/* Blocks bitmap block MSB */
	__le32	bg_inode_bitmap_hi;	/* Inodes bitmap block MSB */
	__le32	bg_inode_table_hi;	/* Inodes table block MSB */
	__le16	bg_free_blocks_count_hi;/* Free blocks count MSB */
	__le16	bg_free_inodes_count_hi;/* Free inodes count MSB */
	__le16	bg_used_dirs_count_hi;	/* Directories count MSB */
	__le16  bg_itable_unused_hi;    /* Unused inodes count MSB */
	__le32  bg_exclude_bitmap_hi;   /* Exclude bitmap block MSB */
	// crc32c(s_uuid grp_num bbitmap) 高位校验
	__le16  bg_block_bitmap_csum_hi;
	__le16  bg_inode_bitmap_csum_hi;
	__u32   bg_reserved;
};
  • mkfs.ext4初始化过程,磁盘大小是30M,一共是标号从0~3的4个block group,当使用mkfs.ext4内核关联一个进程static struct task_struct *ext4_lazyinit_task来做初始化。
代码语言:javascript复制
static int ext4_run_lazyinit_thread(void)
{
	// 启动内核线程,调用ext4_lazyinit_thread 函数铏初始化
	ext4_lazyinit_task = kthread_run(ext4_lazyinit_thread,
					 ext4_li_info, "ext4lazyinit");
	if (IS_ERR(ext4_lazyinit_task)) {
		int err = PTR_ERR(ext4_lazyinit_task);
		ext4_clear_request_list();
		kfree(ext4_li_info);
		ext4_li_info = NULL;
		printk(KERN_CRIT "EXT4-fs: error %d creating inode table "
				 "initialization threadn",
				 err);
		return err;
	}
	ext4_li_info->li_state |= EXT4_LAZYINIT_RUNNING;
	return 0;
}

/********调用的函数路径******/

ext4_lazyinit_thread [ext4]() {
  // 加载block group
  ext4_get_group_desc [ext4]();
  // 初始化inode table
  ext4_init_inode_table [ext4]() {
	// 获取block group desc结构
    ext4_get_group_desc [ext4]();
    // 启动日志
    ext4_journal_check_start [ext4]();
    // 获取未使用的inode table数量
    ext4_itable_unused_count [ext4]();
    // 设置 block group中的标记位 bg_inode_table_hi
    ext4_inode_table [ext4]();
    // 设置 block group的crc
    ext4_group_desc_csum_set [ext4]() {
      ext4_group_desc_csum [ext4]();
    }
  }
  ext4_get_group_desc [ext4]();
  ext4_init_inode_table [ext4]() {
    ext4_get_group_desc [ext4]();
    ext4_journal_check_start [ext4]();
    ext4_inode_table [ext4]();
    ext4_group_desc_csum_set [ext4]() {
      ext4_group_desc_csum [ext4]();
    }
  }
  ext4_get_group_desc [ext4]();
  ext4_init_inode_table [ext4]() {
    ext4_get_group_desc [ext4]();
    ext4_journal_check_start [ext4]();
    ext4_inode_table [ext4]();
    ext4_group_desc_csum_set [ext4]() {
      ext4_group_desc_csum [ext4]();
    }
  }
  ext4_get_group_desc [ext4]();
  ext4_init_inode_table [ext4]() {
    ext4_get_group_desc [ext4]();
    ext4_journal_check_start [ext4]();
    ext4_inode_table [ext4]();
    ext4_group_desc_csum_set [ext4]() {
      ext4_group_desc_csum [ext4]();
    }
  }
  ext4_remove_li_request.part.119 [ext4]();
}
  • 使用mkfs.ext4命令后,初始化了磁盘的超级块。dumpe2fs把整个超级快dump出来,这里 磁盘大小一共是30M,dump出来后如下:
代码语言:javascript复制
$ dumpe2fs /dev/loop0
// 文件系统元数据
dumpe2fs 1.45.6 (20-Mar-2020)
Filesystem volume name:   <none>
Last mounted on:          <not available>
Filesystem UUID:          d0b48bf3-4aab-4019-8617-6f4fe1a20268
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize metadata_csum
Filesystem flags:         signed_directory_hash 
Default mount options:    user_xattr acl
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              7680
Block count:              30720
Reserved block count:     1536
Free blocks:              27990
Free inodes:              7669
First block:              1
Block size:               1024
Fragment size:            1024
Group descriptor size:    64
Reserved GDT blocks:      239
Blocks per group:         8192
Fragments per group:      8192
Inodes per group:         1920
Inode blocks per group:   240
Flex block group size:    16
Filesystem created:       Sun Mar 27 19:18:41 2022
Last mount time:          n/a
Last write time:          Sun Mar 27 19:18:41 2022
Mount count:              0
Maximum mount count:      -1
Last checked:             Sun Mar 27 19:18:41 2022
Check interval:           0 (<none>)
Lifetime writes:          261 kB
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:               128
Journal inode:            8
Default directory hash:   half_md4
Directory Hash Seed:      46745eac-889b-4456-91bc-989742111935
Journal backup:           inode blocks
Checksum type:            crc32c
Checksum:                 0xda84b217
Journal features:         (none)
Journal size:             1024k
Journal length:           1024
Journal sequence:         0x00000001
Journal start:            0


// 一共3个 block group,每个block group的block bitmap和inode bitmap都在第一个block group中存储
// block group 0 存储了其他block group的数据块位图、inode位图、inode table.
Group 0: (Blocks 1-8192) csum 0x2efa
  Primary superblock at 1, Group descriptors at 2-2
  Reserved GDT blocks at 3-241
  // block bitmap和inode bitmap 都存储在第一个block group中
  Block bitmap at 242 ( 241), csum 0x9d8af453
  Inode bitmap at 246 ( 245), csum 0x494ef22a
  Inode table at 250-489 ( 249)
  6969 free blocks, 1909 free inodes, 2 directories, 1909 unused inodes
  Free blocks: 1224-8192
  Free inodes: 12-1920
Group 1: (Blocks 8193-16384) csum 0xcb52 [INODE_UNINIT, BLOCK_UNINIT]
  Backup superblock at 8193, Group descriptors at 8194-8194
  Reserved GDT blocks at 8195-8433
  // 数据块的位图
  Block bitmap at 243 (bg #0   242), csum 0x00000000
  // inode的位图
  Inode bitmap at 247 (bg #0   246), csum 0x00000000
  // inode table
  Inode table at 490-729 (bg #0   489)
  // 空闲块
  7951 free blocks, 1920 free inodes, 0 directories, 1920 unused inodes
  Free blocks: 8434-16384
  Free inodes: 1921-3840
Group 2: (Blocks 16385-24576) csum 0xb0d5 [INODE_UNINIT]
  Block bitmap at 244 (bg #0   243), csum 0x1364dcda
  Inode bitmap at 248 (bg #0   247), csum 0x00000000
  Inode table at 730-969 (bg #0   729)
  7168 free blocks, 1920 free inodes, 0 directories, 1920 unused inodes
  Free blocks: 17409-24576
  Free inodes: 3841-5760
Group 3: (Blocks 24577-30719) csum 0x05de [INODE_UNINIT]
  Backup superblock at 24577, Group descriptors at 24578-24578
  Reserved GDT blocks at 24579-24817
  Block bitmap at 245 (bg #0   244), csum 0x628642b2
  Inode bitmap at 249 (bg #0   248), csum 0x00000000
  Inode table at 970-1209 (bg #0   969)
  5902 free blocks, 1920 free inodes, 0 directories, 1920 unused inodes
  Free blocks: 24818-30719
  Free inodes: 5761-7680

0 人点赞