存儲基礎 | 神奇!我的文件有個“洞”
本文轉載自微信公眾號「奇伢云存儲」,作者奇伢 。轉載本文請聯(lián)系奇伢云存儲公眾號。
聊聊背景
文件還能打洞?
支持稀疏文件語義的文件系統(tǒng)就可以。
支持稀疏語義的文件系統(tǒng)有什么基本特征?
- 實現(xiàn) fallocate 接口,能夠滿足文件空間預分配和打洞;
- 實現(xiàn) fiemap 的功能,返回文件的具體物理塊分配信息;
打洞是什么意思?
英文是“punch hole”,就是在保證文件其他屬性不變(比如,文件大小,inode 編號,權限等等)的條件下,主動釋放一段文件所占的物理空間。
關于承諾的語義?
文件系統(tǒng):punch hole 成功,文件系統(tǒng)可能釋放,也可能沒釋放這部分空間,此結果不對用戶承諾。
程序猿:反而是程序猿要遵守承諾,一旦 puhch hole 成功,用戶將不能對這部分數(shù)據(jù)做任何假設,要當它已經沒了,無論它是不是真的沒了。
創(chuàng)建實分配的文件
為了打洞,我們需要先創(chuàng)建一個實際占用 4M 的文件,用 dd 命令如下:
- root@ubuntu:~/temp# dd if=/dev/urandom of=./test.txt.4M bs=1M count=4
可以用 du 命令看一下實際的物理空間:
- root@ubuntu:~/temp# du -sh ./test.txt.4M
- 4.0M ./test.txt.4M
確實是 4M,再用 stat 命令看一下:
- root@ubuntu:~/temp# stat ./test.txt.4M
- File: './test.txt.4M'
- Size: 4194304 Blocks: 8192 IO Block: 4096 regular file
- Device: fc00h/64512d Inode: 1335860 Links: 1
- Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
文件 Size 4194304 字節(jié),物理占用 Blocks 數(shù)是 8192,這里每個 Block 單位是 512 字節(jié),所以物理占用也是 4194304 字節(jié),剛好 4M。
文件打個洞
原材料準備好了,Go 程序怎么給文件打個洞呢 ?
關鍵在于 fallocate 系統(tǒng)調用。
這是一個跟平臺強相關的系統(tǒng)調用,非系統(tǒng)兼容的,下面以 Linux 為例。
由于這個非系統(tǒng)兼容的,類似于這類調用,一般都是用 syscall 這個標準庫,直接下發(fā)系統(tǒng)調用。
完整程序示例如下:
代碼關鍵幾個事項:
- 文件頭部要加上 // +build linux ;
- 調用的是 syscall.Fallocate 接口;
好了,編譯一下吧:
- go build -gcflags "-N -l" ./punchhole.go
把編譯出的二進制 punchhole 和 test.txt.4M 這兩個放在一個目錄下,實驗一下效果:
- root@ubuntu:~/temp# ./punchhole
- 2021/09/08 22:22:21 punch hole success.
du 看下文件結果:
- root@ubuntu:~/temp# du -sh ./test.txt.4M
- 2.0M ./test.txt.4M
嗷,確實變成了 2M,stat 再看一下:
- root@ubuntu:~/temp# stat ./test.txt.4M
- File: './test.txt.4M'
- Size: 4194304 Blocks: 4096 IO Block: 4096 regular file
- Device: fc00h/64512d Inode: 1335860 Links: 1
- Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
- Access: 2021-07-26 15:39:06.672000000 +0800
文件大小還是 4M,實際物理空間變成了 2M( 4096 * 512 ),inode 編號、權限都沒變。完美,一個空洞文件就誕生了。
文件解析:
這個文件 [ 0,2M ] 的位置是空洞,不占物理空間,讀出來會是 0 數(shù)據(jù);
[ 2M,4M ] 的數(shù)據(jù)還是原來從 /dev/urandom 設備讀出來的數(shù)據(jù),占用實際物理空間;
思考題
拋出幾個關鍵的思考問題,大家可以自行驗證。
如果 punchhole 傳參是非 4k 對齊的,會怎么樣?
劃重點:由于文件系統(tǒng)內部都是按照 4k 的單位管理空間的,所以非 4k 對齊的空間是釋放不掉的。 punch hole 一定要注意按照 4k 對齊。
特別還要注意一點,雖然非 4k 對齊釋放不掉,但是 fallocate 調用也不會報錯,這點很重要。最開始就提過,文件系統(tǒng)沒給你承諾過啥時候釋放啥。
大家可以手動驗證下。
文件 test.txt.4M 的 [ 0,2M ] 被打洞之后,這個區(qū)域會是什么數(shù)據(jù)?
**全 0 數(shù)據(jù),這個是稀疏文件系統(tǒng)給你的語義。**這個上面也提到過了。
奇伢教你快速用 hexdump 命令看一下:
- root@ubuntu:~/temp# hexdump ./test.txt.4M|more
- 0000000 0000 0000 0000 0000 0000 0000 0000 0000
- *
- 0200000 80e3 2c11 f8d8 256b 23b5 a191 fb80 eb5e
- 0200010 f454 e3e2 cb8b 664a a893 6f5a 2df0 99dd
- 0200020 9d30 4f19 144f b4f1 f2cd 7312 c16c 719f
- 0200030 2ef7 3195 48a1 b2c0 03f1 a08a aff3 a022
- .................
- .................
看到了嗎?
0x0000000 - 0x0200000 這個區(qū)域都是 0 數(shù)據(jù)。這是 16 進制表示,換算成 10 進制,就是 [ 0 ,2M ] 的區(qū)域。
大家也可以用程序去 read 驗證下。
總結
總結幾個關鍵點:
文件打洞用的是系統(tǒng)調用 fallocate ;
文件打洞的時候要注意 4k 對齊,不然非對齊部分釋放不掉,并且不會報錯;
文件系統(tǒng)沒承諾什么,所以當沒 4k 對齊的時候,雖然沒釋放空間,也不會報錯;
程序猿要遵守承諾,一旦聲明了某段空間要釋放,以后不能對此空間內容做假設;
文件打洞的位置,不占物理空間,后續(xù)讀是返回 0 數(shù)據(jù);