1 掉电与文件系统一致性
由上一节文件系统的布局分析可知,当操作一个文件时,比如往/a目录下添加一个b,即添加/a/b文件,需要修改inode bitmap, inode table, block bitmap, data block。
这一系列的操作是非原子的,假如任何一个环节掉电,造成某些步骤丢失,就会造成数据的不完整,文件将无法正常访问。
2 append一个文件的全流程
而硬件是不可能原子执行的,因此会造成不一致性。
3 模拟文件系统不一致性案例
(1) 做一个image,用来模拟磁盘
dd if=/dev/zero of=image bs=1024 count=4096
(2).格式化为ext4文件系统
mkfs.ext4 -b 4096 image
(3).mount到test目录,写入一个ok.txt文件
sudo mount -o loop image test/
cd test/
sudo touch ok.txt
cd ..
sudo umount test
(4).查看磁盘详细信息
(base) leon\@pc:\~/io\$ dumpe2fs image
dumpe2fs 1.42.13 (17-May-2015)
Filesystem volume name: <none>
Last mounted on: /home/leon/io/test
Filesystem UUID: 759835e3-9508-4c57-b511-9c4f7e13f0ad
Filesystem magic number: 0xEF53
Filesystem revision #: 1 (dynamic)
…
Inode count: 1024
Block count: 1024
Reserved block count: 51
Free blocks: 982
Free inodes: 1012
First block: 0
Block size: 4096
Fragment size: 4096
Blocks per group: 32768
Fragments per group: 32768
Inodes per group: 1024
…
First inode: 11
Inode size: 128
Default directory hash: half_md4
Directory Hash Seed: 9cf91d57-8528-4d39-b6ba-5f8e2e86fcb7
Group 0: (Blocks 0-1023) [ITABLE_ZEROED]
Checksum 0x240a, unused inodes 1012
主 superblock at 0, Group descriptors at 1-1
Block bitmap at 2 (+2), Inode bitmap at 18 (+18)
Inode表位于 34-65 (+34)
982 free blocks, 1012 free inodes, 2 directories, 1012个未使用的inodes
可用块数: 8-17, 19-33, 67-1023
可用inode数: 13-1024
(base)
可以看到inode bitmap在18个块。
(5).查看inodebitmap块
dd if=image bs=4096 skip=18 |
由于ext4默认用掉11个inode,新创建的ok.txt文件后,inode bitmap用掉12位。
(6).现在模拟掉电,修改inode bitmap
vim -b image
:%!xxd –g 1
:%!xxd –r
找到inode bitmap块对应地址4096*18=0x12000
将bitmap改为ff 07
(7).重新mount访问,查看出错信息
(base) leon@pc:~/io/test$ sudo touch bad.txt
touch: 无法创建'bad.txt': 输入/输出错误
(base) leon@pc:~/io/test$ dmesg
掉电导致的不一致性,会出现各种奇怪的问题,甚至都无法修复;
任何软件的手段只能保持一致性,无法保证不丢失数据。
4 fsck
人为破坏data block,用fsck修复
修复原理,扫描bitmap和inode table的一致性。
早期Linux/Windows系统异常掉电后启动,都用fsck修复磁盘,速度很慢。
为提高速度,新系统都采用日志系统方式。
5 文件系统的日志
将要修改的行为,记录为一个日志,若操作磁盘过程掉电,开机根据日志回放,将磁盘操作全部重做一遍。磁盘操作完成,删除日志。
优点:保持文件系统的一致性,也提高速度。
EXT2/3/4都采用日志系统。
日志的几个阶段:
1.开始写日志
2.日志区写完日志,commited;
3.执行完一条日志,磁盘操作完成,checkpoint。
4.操作完成,free日志。
完整的日志方式,相当于每个数据都写了两遍,让系统变很慢,实际工程上会根据数据情况,做部分日志,即日志方式分为三种:速度递增,安全性递减
data=journal: 完整日志;
data = ordered: 只写元数据,且先写完数据块,再写元数据
data=writeback 只写元数据,循序不确定;ubuntu默认方式;
这样日志就分为5个阶段:
6 文件系统的调试工具
创建一个文件t.txt,df –h
(base) leon@pc:~/io$ **sudo debugfs -R 'stat /home/leon/io/t.txt' /dev/sda7**
sudo: 无法解析主机:pc: 连接超时
debugfs 1.42.13 (17-May-2015)
Inode: 13896517 Type: regular Mode: 0664 Flags: 0x80000
Generation: 507799365 Version: 0x00000000:00000001
User: 1000 Group: 1000 Size: 17
File ACL: 0 Directory ACL: 0
Links: 1 Blockcount: 8
Fragment: Address: 0 Number: 0 Size: 0
ctime: 0x5f40e439:2182bba0 -- Sat Aug 22 17:24:09 2020
atime: 0x5f40e43b:c9589800 -- Sat Aug 22 17:24:11 2020
mtime: 0x5f40e439:2182bba0 -- Sat Aug 22 17:24:09 2020
crtime: 0x5f40e439:208e98b8 -- Sat Aug 22 17:24:09 2020
Size of extra inode fields: 32
EXTENTS:
(0):55636171
(END)
得到文件的数据块55636171
查看数据块内容
sudo
sudo dd if=/dev/sda of=1 skip=$((55636171*8+824123392)) bs=512c count=1
debugfs 根据块号查inode号
sudo debugfs -R 'icheck 55636171'
根据inode号,查文件路径
sudo debugfs -R 'ncheck 13896517'
7 Copy On Write文件系统: btrfs
不用日志,实现文件系统一致性。每次写磁盘时,先将更新数据写入一个新的block,当新数据写入成功之后,再更新相关的数据结构指向新block。
COW稳健性系统的实现方式,有利于实现子卷和snapshot,类似git的思想: