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。