• 隐藏侧边栏
  • 展开分类目录
  • 关注微信公众号
  • 我的GitHub
  • QQ:1753970025
Chen Jiehua

Linux文件系统·Ext2 

历史

Linux 的第一个文件系统是 Minix, 不过它有几个主要的缺限:

  • 磁盘分区大小必须小于 64MB;
  • 必须使用 14 个字符定长的文件名;
  • 难于扩展。

在 VFS 被加入内核后,1992年第一个专门为 Linux 所写的文件系统 Ext(Extended File System)被加入了 0.96c 这个版本。

Ext最大可支持 2GB的磁盘分区,其文件名最长可达 255 个字符。不过由于它用链表管理未分配的数据块和节点,这样当文件系统投入使用后,链表变得杂乱无序,文件系统中会产生很多碎片。

1993年,Ext的下一个版本Ext2诞生了:

  • 它的节点中使用了 15 个数据块指针,这样它最大可支持 4TB 的磁盘分区。
  • 它使用变长的目录项,这样既可以不浪费磁盘空间,又能支持最长 255 个字符的文件名。
  • 使用位图来管理数据块和节点的使用情况,解决了 Ext 出现的问题。
  • 最重要的一点是,它在磁盘上的布局做了改进,即使用了块组的概念,从而使数据的读和写更快、更有效,也便系统变得更安全可靠。
  • 易于扩展。

此后,Ext系列的文件系统也逐渐加入了很多新特性,比如 Ext3 支持日志,在数据异常时可以快速进行修复。

Linux文件系统

Linux一切皆文件,文件存储在磁盘上,而文件的管理则依赖文件系统。

➜ ls -alhi
total 363M
1317058 drwxrwxr-x  4 jachua jachua 4.0K May 11 03:38 .
1310722 drwxr-xr-x 18 jachua jachua 4.0K May 11 08:02 ..
1317060 -rw-r--r--  1 jachua jachua 129M Oct 15  2021 go1.17.2.linux-amd64.tar.gz
1319244 drwxrwxr-x 18 jachua jachua 4.0K Mar  2  2005 linux-2.6.11
1315920 -rw-rw-r--  1 jachua jachua  45M May  8 16:25 linux-2.6.11.tar.gz
1322899 drwxrwxr-x 24 jachua jachua 4.0K Mar 20 20:14 linux-5.17
1322898 -rw-rw-r--  1 jachua jachua 190M May 11 03:37 linux-5.17.tar.gz

文件的元数据(权限、用户、时间等)、文件的实际数据要怎么存储?

实际上,Ext2文件系统将这两部分存放在不同的区块,权限和属性存放在inode,实际数据存放在data block区块中;此外还有一个super block记录整个文件系统的整体信息,包括inode和block的用量。

  • superblock:记录此 filesystem 的整体信息,包括 inode/block 的总量、使用量、剩余量, 以及文件系统的格式与相关信息等;
  • inode:记录文件的属性,一个文件占用一个 inode,同时记录此文件的数据所在的 block 号码;
  • block:实际记录文件的内容,若文件太大时,会占用多个 block 。

上面这种方式称为索引式文件系统,对比FAT文件系统:

Ext2 是索引式文件系统,一般不需要进行碎片整理。

文件系统 Ext2

文件系统一开始就将 inode 与 block 规划好了,除非重新格式化(或者利用 resize2fs 等指令变更文件系统大小),否则 inode 与 block 固定后就不再变动。

此外,Ext2在格式化的时候会分为多个区块群组 (block group) ,每个区块群组都有独立的 inode/block/superblock,如图:

文件系统最前面有一个启动扇区(boot sector),这个启动扇区可以安装开机管理程序。

Block Group

Data Block

块大小支持1k、2k、4k三种,在格式化的时候就固定了,每个block都有编号,方便inode记录。根据不同的block大小,文件系统对单个文件大小和文件系统总容量有不同限制:

Block大小1k2k4k
单文件16G256G2T
总容量2T8T16T
  • 原则上, block 的大小与数量在格式化完就不能够再改变了(除非重新格式化);
  • 每个 block 内最多只能够放置一个文件的数据;
  • 承上,如果文件大于 block 的大小,则一个文件会占用多个 block 数量;
  • 承上,若文件小于 block ,则该 block 的剩余容量就不能够再被使用了(磁盘空间会浪费)

inode table

inode 记录的内容:

  • 文件的读取模式(rwx)、拥有者和群组(owner/group)、大小、时间、特殊标记;
  • 文件实际数据的指向(pointer);

inode 的特点:

  • 每个 inode 大小均固定为 128 bytes (ext4 可设定到 256 bytes);
  • 每个文件都仅会占用一个 inode 而已;
  • 承上,因此文件系统能够建立的文件数量与 inode 的数量有关;
  • 系统读取文件时需要先找到 inode,并分析 inode 所记录的权限与用户是否符合,若符合才能够开始实际读取 block 的内容;

inode仅有128byte,但记录一个block需要4byte,如果文件很大,那它是怎么记录的?

答:文件系统将 inode 记录 block 号码的区域定义为 12 个直接,一个间接, 一个双间接与一个三间接记录区。

以block 1k为例,12x1k + 256x1k + 256x256x1k + 256x256x256x1k = 16G

Ext4的inode为256byte,可以达到更大上限。

Superblock

superblock 记录整个文件系统的相关信息:

  • block 与 inode 的总量;
  • 未使用与已使用的 inode / block 数量;
  • block 与 inode 的大小 (block 为 1, 2, 4K, inode 为 128bytes 或 256bytes);
  • filesystem 的挂载时间、最近一次写入数据的时间、最近一次检验磁盘 (fsck) 的时间等文件系统的相关信息;

每个 block group 都可能含有 superblock,但是其实一个文件系统应该仅需一个superblock,所以除了第一个superblock外,其它都是备份而已。

Filesystem Description

文件系统描述说明,描述每个 block group 的开始与结束的 block 号码,以及说明每个区段 (superblock, bitmap, inodemap, data block) 分别介于哪一个 block 号码之间。

block bitmap

block bitmap 记录每个block是否被使用,写入文件时需要先查找bitmap找到空先的block,删除文件时也需要将对应的bitmap清掉。

inode bitmap

与block bitmap类似,用来记录inode的使用情况。

dumpe2fs

如何查看系统中已经初始化的分区和文件系统:

➜ blkid
/dev/vda1: LABEL="/" UUID="75e8b5c0-ce5d-4fbd-8c4b-a9053a8c7c81" TYPE="ext4" PARTUUID="f5f93563-01"

➜ lsblk
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
vda    252:0    0   40G  0 disk
└─vda1 252:1    0   40G  0 part /

➜ df -h
Filesystem      Size  Used Avail Use% Mounted on
udev            967M     0  967M   0% /dev
tmpfs           199M  996K  198M   1% /run
/dev/vda1        40G   19G   19G  51% /
tmpfs           994M     0  994M   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           994M     0  994M   0% /sys/fs/cgroup
tmpfs           199M     0  199M   0% /run/user/1000

查看文件系统的具体信息:

➜ sudo dumpe2fs /dev/vda1
dumpe2fs 1.45.5 (07-Jan-2020)
Filesystem volume name:   /
Last mounted on:          /
Filesystem UUID:          75e8b5c0-ce5d-4fbd-8c4b-a9053a8c7c81
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype needs_recovery extent flex_bg sparse_super large_file huge_file dir_nlink extra_isize
Filesystem flags:         signed_directory_hash
Default mount options:    user_xattr acl
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              2621440
Block count:              10485499
Reserved block count:     471818
Free blocks:              7497668
Free inodes:              2434363
First block:              0
Block size:               4096
Fragment size:            4096
Reserved GDT blocks:      1021
Blocks per group:         32768
Fragments per group:      32768
Inodes per group:         8192
Inode blocks per group:   512
Flex block group size:    16
Filesystem created:       Fri May 22 11:33:57 2020
Last mount time:          Mon Nov 30 17:17:22 2020
Last write time:          Tue Dec  1 01:17:21 2020
Mount count:              13
Maximum mount count:      -1
Last checked:             Fri May 22 11:33:57 2020
Check interval:           0 (<none>)
Lifetime writes:          388 GB
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:               256
Required extra isize:     32
Desired extra isize:      32
Journal inode:            8
First orphan inode:       405000
Default directory hash:   half_md4
Directory Hash Seed:      18a5e288-556a-4cd2-b7ed-5c1af7e5d89d
Journal backup:           inode blocks
Journal features:         journal_incompat_revoke
Journal size:             128M
Journal length:           32768
Journal sequence:         0x01d7821f
Journal start:            1228


Group 0: (Blocks 0-32767)
  Primary superblock at 0, Group descriptors at 1-3
  Reserved GDT blocks at 4-1024
  Block bitmap at 1025 (+1025)
  Inode bitmap at 1041 (+1041)
  Inode table at 1057-1568 (+1057)
  23513 free blocks, 8174 free inodes, 2 directories
  Free blocks: 9255-32767
  Free inodes: 19-8192
Group 1: (Blocks 32768-65535)
  Backup superblock at 32768, Group descriptors at 32769-32771
  Reserved GDT blocks at 32772-33792
  Block bitmap at 1026 (bg #0 + 1026)
  Inode bitmap at 1042 (bg #0 + 1042)
  Inode table at 1569-2080 (bg #0 + 1569)
  1467 free blocks, 8192 free inodes, 0 directories
  Free blocks: 33794-33919, 33985-34303, 34488-34559, 34674-35547, 36788-36863
  Free inodes: 8193-16384
......
Group 319: (Blocks 10452992-10485498)
  Block bitmap at 9961487 (bg #304 + 15)
  Inode bitmap at 9961503 (bg #304 + 31)
  Inode table at 9969184-9969695 (bg #304 + 7712)
  32507 free blocks, 8192 free inodes, 0 directories
  Free blocks: 10452992-10485498
  Free inodes: 2613249-2621440

文件系统与目录树

目录记录了文件名,文件才记录了实际的数据。

当我们在Linux下创建一个目录时,文件系统会分配一个 inode 与至少一块 block 给该目录。其中, inode 记录该目录的相关权限与属性,并可记录分配到的那块 block 号码; 而 block 则是记录在这个目录下的文件名与该文件名占用的 inode 号码数据。

➜ ls -alhi
total 363M
1317058 drwxrwxr-x  4 jachua jachua 4.0K May 11 03:38 .
1310722 drwxr-xr-x 18 jachua jachua 4.0K May 11 08:02 ..
1317060 -rw-r--r--  1 jachua jachua 129M Oct 15  2021 go1.17.2.linux-amd64.tar.gz
1319244 drwxrwxr-x 18 jachua jachua 4.0K Mar  2  2005 linux-2.6.11
1315920 -rw-rw-r--  1 jachua jachua  45M May  8 16:25 linux-2.6.11.tar.gz
1322899 drwxrwxr-x 24 jachua jachua 4.0K Mar 20 20:14 linux-5.17
1322898 -rw-rw-r--  1 jachua jachua 190M May 11 03:37 linux-5.17.tar.gz

Ext2源码

在线源码

磁盘数据结构

  • struct ext2_super_block: include/linux/ext2_fs.h
  • struct ext2_inode: include/linux/ext2_fs.h
  • struct ext2_group_desc: include/linux/ext2_fs.h

内存数据结构

因为 VFS 的超级块必须兼容各种文件系统的不同的超级块结构,所以对某个文件系统超级块自己的特性必须用另一个结构保存于内存中, 以加快对文件的操作。

  • struct ext2_sb_info: include/linux/ext2_fs_sb.h
  • struct ext2_inode_info: fs/ext2/ext2.h

读取指定的inode节点信息:

  • void ext2_read_inode(struct inode *): fs/ext2/inode.c
    • void ext2_get_inode()

目录

  • struct ext2_dir_entry_2: include/linux/ext2_fs.h

文件定位:

  • ext2_find_entry(): fs/ext2/dir.c

扩展阅读

  • 《鸟哥的Linux私房菜-基础篇》第4版
  • 《深入理解Linux内核》第3版(linux 2.6)
码字很辛苦,转载请注明来自ChenJiehua《Linux文件系统·Ext2》

评论