Filesystems

過度分配的稀疏文件沒有寫入失敗

  • August 29, 2017

我一直在使用稀疏文件,以便在 Windows samba 上複製 Linux fs 權限,從這里安裝一個想法:https ://www.thanassis.space/backup.html 。

雖然在測試稀疏文件時,我發現了一個有趣的問題,其中“完整”的主機驅動器不會報告為應用程序的寫入失敗。相反,當主機驅動器填滿時,寫入會繼續並成功完成,即使驅動器已滿。

為了測試這一點,我有以下設置。

[root@ip-172-31-61-147 ~]# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1      8.0G  944M  7.1G  12% /
devtmpfs        1.9G     0  1.9G   0% /dev
tmpfs           1.8G     0  1.8G   0% /dev/shm
tmpfs           1.8G   49M  1.7G   3% /run
tmpfs           1.8G     0  1.8G   0% /sys/fs/cgroup
tmpfs           354M     0  354M   0% /run/user/1000
/dev/xvdb1      4.0G   33M  4.0G   1% /mnt
tmpfs           354M     0  354M   0% /run/user/0

我已經安裝了一個 4G 分區/mnt,我將在該分區上創建一個 10G 稀疏文件。

[root@ip-172-31-61-147 ~]# dd of=/mnt/file bs=1G count=0 seek=10
0+0 records in
0+0 records out
0 bytes (0 B) copied, 3.0097e-05 s, 0.0 kB/s

該文件已正確創建並且不佔用分區上的實際空間,但似乎是一個 10G 文件。

[root@ip-172-31-61-147 ~]# ls -lh /mnt/
total 0
-rw-r--r--. 1 root root 10G Aug 28 21:10 file
[root@ip-172-31-61-147 ~]# du -h /mnt/
0       /mnt/

我在空間中分配一個文件系統並掛載它(通過 losttup 驗證)。

[root@ip-172-31-61-147 ~]# mkfs.xfs /mnt/file
meta-data=/mnt/file              isize=512    agcount=4, agsize=655360 blks
        =                       sectsz=512   attr=2, projid32bit=1
        =                       crc=1        finobt=0, sparse=0
data     =                       bsize=4096   blocks=2621440, imaxpct=25
        =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
        =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

[root@ip-172-31-61-147 ~]# mount /mnt/file /srv/
[root@ip-172-31-61-147 ~]# losetup -j /mnt/file
/dev/loop0: [51729]:67 (/mnt/file)
[root@ip-172-31-61-147 ~]# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1      8.0G  945M  7.1G  12% /
devtmpfs        1.9G     0  1.9G   0% /dev
tmpfs           1.8G     0  1.8G   0% /dev/shm
tmpfs           1.8G   49M  1.7G   3% /run
tmpfs           1.8G     0  1.8G   0% /sys/fs/cgroup
tmpfs           354M     0  354M   0% /run/user/1000
/dev/xvdb1      4.0G   43M  4.0G   2% /mnt
tmpfs           354M     0  354M   0% /run/user/0
/dev/loop0       10G   33M   10G   1% /srv
[root@ip-172-31-61-147 ~]#

在這個掛載點上,我可以正常寫入文件,表明它工作正常。

[root@ip-172-31-61-147 ~]# dd if=/dev/zero of=/srv/init_file bs=1GiB count=1
1+0 records in
1+0 records out
1073741824 bytes (1.1 GB) copied, 8.22444 s, 131 MB/s
[root@ip-172-31-61-147 ~]# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1      8.0G  945M  7.1G  12% /
devtmpfs        1.9G     0  1.9G   0% /dev
tmpfs           1.8G     0  1.8G   0% /dev/shm
tmpfs           1.8G   49M  1.7G   3% /run
tmpfs           1.8G     0  1.8G   0% /sys/fs/cgroup
tmpfs           354M     0  354M   0% /run/user/1000
/dev/xvdb1      4.0G  1.1G  3.0G  27% /mnt
tmpfs           354M     0  354M   0% /run/user/0
/dev/loop0       10G  1.1G  9.0G  11% /srv
[root@ip-172-31-61-147 ~]# ls -lh /srv/
total 1.0G
-rw-r--r--. 1 root root 1.0G Aug 28 21:19 init_file
[root@ip-172-31-61-147 ~]#
[root@ip-172-31-61-147 ~]# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1      8.0G  945M  7.1G  12% /
devtmpfs        1.9G     0  1.9G   0% /dev
tmpfs           1.8G     0  1.8G   0% /dev/shm
tmpfs           1.8G   49M  1.7G   3% /run
tmpfs           1.8G     0  1.8G   0% /sys/fs/cgroup
tmpfs           354M     0  354M   0% /run/user/1000
/dev/xvdb1      4.0G  1.1G  3.0G  27% /mnt
tmpfs           354M     0  354M   0% /run/user/0
/dev/loop0       10G  1.1G  9.0G  11% /srv

現在,當我嘗試創建一個應該超出主機驅動器的文件時,它也會正確寫入並且不會報告錯誤。

[root@ip-172-31-61-147 ~]# dd if=/dev/zero of=/srv/too_large_a_file bs=1GiB count=4
4+0 records in
4+0 records out
4294967296 bytes (4.3 GB) copied, 49.9905 s, 85.9 MB/s
[root@ip-172-31-61-147 ~]# echo $?
0

相關數據:

[root@ip-172-31-61-147 ~]# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1      8.0G  949M  7.1G  12% /
devtmpfs        1.9G     0  1.9G   0% /dev
tmpfs           1.8G     0  1.8G   0% /dev/shm
tmpfs           1.8G   49M  1.7G   3% /run
tmpfs           1.8G     0  1.8G   0% /sys/fs/cgroup
tmpfs           354M     0  354M   0% /run/user/1000
/dev/xvdb1      4.0G  4.0G   20K 100% /mnt
tmpfs           354M     0  354M   0% /run/user/0
/dev/loop0       10G  5.1G  5.0G  51% /srv
[root@ip-172-31-61-147 ~]# du -h /srv/
5.0G    /srv/
[root@ip-172-31-61-147 ~]# du -h /srv/*
1.0G    /srv/init_file
4.0G    /srv/too_large_a_file
[root@ip-172-31-61-147 ~]# ls -lh /srv/
total 5.0G
-rw-r--r--. 1 root root 1.0G Aug 28 21:19 init_file
-rw-r--r--. 1 root root 4.0G Aug 28 21:24 too_large_a_file
[root@ip-172-31-61-147 ~]#

我嘗試使用其他實用程序(例如rsync和)來複製這種行為cp。也不會報告錯誤,而是靜默失敗。

使用 cp:

[root@ip-172-31-61-147 ~]# cp -v too_large_a_file /srv/
‘too_large_a_file’ -> ‘/srv/too_large_a_file’
[root@ip-172-31-61-147 ~]# echo $?
0
[root@ip-172-31-61-147 ~]# ls -lhtr /srv/
total 5.0G
-rw-r--r--. 1 root root 5.0G Aug 28 21:31 too_large_a_file
[root@ip-172-31-61-147 ~]# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1      8.0G  6.0G  2.1G  75% /
devtmpfs        1.9G     0  1.9G   0% /dev
tmpfs           1.8G     0  1.8G   0% /dev/shm
tmpfs           1.8G   57M  1.7G   4% /run
tmpfs           1.8G     0  1.8G   0% /sys/fs/cgroup
tmpfs           354M     0  354M   0% /run/user/1000
/dev/xvdb1      4.0G  4.0G   20K 100% /mnt
tmpfs           354M     0  354M   0% /run/user/0
/dev/loop0       10G  5.1G  5.0G  51% /srv

使用 rsync:

[root@ip-172-31-61-147 ~]# rsync -vvv too_large_a_file /srv/
[sender] make_file(too_large_a_file,*,0)
send_file_list done
send_files starting
server_recv(2) starting pid=16569
received 1 names
recv_file_list done
get_local_name count=1 /srv/
generator starting pid=16569
delta-transmission disabled for local transfer or --whole-file
recv_generator(too_large_a_file,0)
send_files(0, too_large_a_file)
send_files mapped too_large_a_file of size 5368709120
calling match_sums too_large_a_file
too_large_a_file
sending file_sum
false_alarms=0 hash_hits=0 matches=0
sender finished too_large_a_file
send_files phase=1
recv_files(1) starting
generate_files phase=1
recv_files(too_large_a_file)
got file_sum
renaming .too_large_a_file.CwVApY to too_large_a_file
recv_files phase=1
generate_files phase=2
send_files phase=2
send files finished
total: matches=0  hash_hits=0  false_alarms=0 data=5368709120
recv_files phase=2
generate_files phase=3
recv_files finished
generate_files finished

sent 5369364558 bytes  received 31 bytes  57426359.24 bytes/sec
total size is 5368709120  speedup is 1.00
[sender] _exit_cleanup(code=0, file=main.c, line=1052): about to call exit(0)
[root@ip-172-31-61-147 ~]# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1      8.0G  6.0G  2.1G  75% /
devtmpfs        1.9G     0  1.9G   0% /dev
tmpfs           1.8G     0  1.8G   0% /dev/shm
tmpfs           1.8G   73M  1.7G   5% /run
tmpfs           1.8G     0  1.8G   0% /sys/fs/cgroup
tmpfs           354M     0  354M   0% /run/user/1000
/dev/xvdb1      4.0G  4.0G   20K 100% /mnt
tmpfs           354M     0  354M   0% /run/user/0
/dev/loop0       10G  5.1G  5.0G  51% /srv

執行後md5sum我更加困惑:

[root@ip-172-31-61-147 ~]# md5sum /root/too_large_a_file
ec4bcc8776ea04479b786e063a9ace45  /root/too_large_a_file
[root@ip-172-31-61-147 ~]# md5sum /srv/too_large_a_file
ec4bcc8776ea04479b786e063a9ace45  /srv/too_large_a_file

似乎完整的文件被保留了,雖然我不知道如何。

在研究這個問題時,我發現有人在做同樣的事情但使用加密設置,他們發現了同樣的問題但無法解決它(事實上他們建議將它作為一個新問題打開!):使用 LUKS 按需增長加密卷

任何幫助都會很棒。

編輯:根據請求核心和系統資訊

[root@ip-172-31-61-147 ~]# uname -a
Linux ip-172-31-61-147 3.10.0-514.16.1.el7.x86_64 #1 SMP Wed Apr 12 15:04:24 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
[root@ip-172-31-61-147 ~]# cat /etc/redhat-release
CentOS Linux release 7.3.1611 (Core)

根據提供的答案,我創建了新文件來測試/dev/zero理論。我創建了一個包含所有文件的文件並嘗試複製我的發現並發現它仍然成功。

[root@ip-172-31-61-147 ~]# tr '\0' '\377' < /dev/zero | dd bs=1 count=5G of=~/too_large_a_file
[root@ip-172-31-61-147 ~]# du -h too_large_a_file
982M    too_large_a_file

然後我將該文件的多個副本放在稀疏文件掛載上(例如cp too_large_a_file /srv/too_large_a_file_1

我能夠將其中六個文件複製到外部,而沒有一個副本失敗。

[root@ip-172-31-61-147 ~]# ls -lh /srv/
total 4.8G
-rw-r--r--. 1 root root 982M Aug 29 00:14 too_large_a_file
-rw-r--r--. 1 root root 982M Aug 29 00:26 too_large_a_file_2
-rw-r--r--. 1 root root 982M Aug 29 02:34 too_large_a_file_3
-rw-r--r--. 1 root root 982M Aug 29 02:34 too_large_a_file_4
-rw-r--r--. 1 root root 982M Aug 29 02:35 too_large_a_file_5

驅動器顯然也在這裡最大化。

Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/xvda1       8377344 1975040   6402304  24% /
devtmpfs         1920720       0   1920720   0% /dev
tmpfs            1809256       0   1809256   0% /dev/shm
tmpfs            1809256   82192   1727064   5% /run
tmpfs            1809256       0   1809256   0% /sys/fs/cgroup
/dev/xvdb1       4183040 4183020        20 100% /mnt
tmpfs             361852       0    361852   0% /run/user/1000
/dev/loop0      10475520 5055864   5419656  49% /srv

所有文件和原始文件的 md5sum 如下。

[root@ip-172-31-61-147 ~]# md5sum too_large_a_file
e8154ef97a3eb2bd13aea04b823a4570  too_large_a_file

[root@ip-172-31-61-147 ~]# md5sum /srv/*
e8154ef97a3eb2bd13aea04b823a4570  /srv/too_large_a_file
e8154ef97a3eb2bd13aea04b823a4570  /srv/too_large_a_file_2
e8154ef97a3eb2bd13aea04b823a4570  /srv/too_large_a_file_3
e8154ef97a3eb2bd13aea04b823a4570  /srv/too_large_a_file_4
154248d2eeaf5791dfc8199e51daadbc  /srv/too_large_a_file_5

我會補充一點,這顯然會影響系統,因為添加第六個文件會使它崩潰。 注意:複製完成後系統再次響應。

**編輯 2:**添加du資訊。

[root@ip-172-31-61-147 ~]# du -h /srv/*
982M    /srv/too_large_a_file
982M    /srv/too_large_a_file_2
982M    /srv/too_large_a_file_3
982M    /srv/too_large_a_file_4
982M    /srv/too_large_a_file_5

**編輯3:**記憶體資訊我通過刪除“超出”緩衝區的文件來測試這一點,然後複製一個並刪除記憶體並查看發生了什麼。

[root@ip-172-31-61-147 ~]# rm /srv/too_large_a_file_5
rm: remove regular file ‘/srv/too_large_a_file_5’? y
[root@ip-172-31-61-147 ~]# cp too_large_a_file /srv/too_large_a_file_5
[root@ip-172-31-61-147 ~]# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1      8.0G  2.2G  5.9G  28% /
devtmpfs        1.9G     0  1.9G   0% /dev
tmpfs           1.8G     0  1.8G   0% /dev/shm
tmpfs           1.8G   97M  1.7G   6% /run
tmpfs           1.8G     0  1.8G   0% /sys/fs/cgroup
/dev/xvdb1      4.0G  4.0G   20K 100% /mnt
tmpfs           354M     0  354M   0% /run/user/1000
/dev/loop0       10G  4.9G  5.2G  49% /srv
[root@ip-172-31-61-147 ~]# free -m && sync && echo 3 > /proc/sys/vm/drop_caches && free -m
             total        used        free      shared  buff/cache   available
Mem:           3533          93        1210         104        2229        3091
Swap:             0           0           0

             total        used        free      shared  buff/cache   available
Mem:           3533          94        3281         104         157        3183
Swap:             0           0           0
[root@ip-172-31-61-147 ~]# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1      8.0G  2.2G  5.9G  28% /
devtmpfs        1.9G     0  1.9G   0% /dev
tmpfs           1.8G     0  1.8G   0% /dev/shm
tmpfs           1.8G  105M  1.7G   6% /run
tmpfs           1.8G     0  1.8G   0% /sys/fs/cgroup
/dev/xvdb1      4.0G  4.0G   20K 100% /mnt
tmpfs           354M     0  354M   0% /run/user/1000
/dev/loop0       10G  4.9G  5.2G  49% /srv
[root@ip-172-31-61-147 ~]# md5sum /srv/too_large_a_file_5
154248d2eeaf5791dfc8199e51daadbc  /srv/too_large_a_file_5
[root@ip-172-31-61-147 ~]# du -ah /srv/
982M    /srv/too_large_a_file
982M    /srv/too_large_a_file_2
982M    /srv/too_large_a_file_3
982M    /srv/too_large_a_file_4
982M    /srv/too_large_a_file_5
4.8G    /srv/
[root@ip-172-31-61-147 ~]# ls -lh /srv/
total 4.8G
-rw-r--r--. 1 root root 982M Aug 29 00:14 too_large_a_file
-rw-r--r--. 1 root root 982M Aug 29 00:26 too_large_a_file_2
-rw-r--r--. 1 root root 982M Aug 29 02:34 too_large_a_file_3
-rw-r--r--. 1 root root 982M Aug 29 12:16 too_large_a_file_4
-rw-r--r--. 1 root root 982M Aug 29 12:27 too_large_a_file_5
[root@ip-172-31-61-147 ~]#

**編輯4:**記憶資訊繼續我對我的發現持懷疑態度,我又做了一次測試,這似乎有點啟發性。似乎在轉儲記憶體後文件確實發生了變化,md5sum輸出確實更新了。

[root@ip-172-31-61-147 ~]# rm /srv/too_large_a_file_5
rm: remove regular file ‘/srv/too_large_a_file_5’? y
[root@ip-172-31-61-147 ~]# cp too_large_a_file /srv/too_large_a_file_5
(reverse-i-search)`m': r^C/srv/too_large_a_file_5
[root@ip-172-31-61-147 ~]# md5sum /srv/too_large_a_file_5
e8154ef97a3eb2bd13aea04b823a4570  /srv/too_large_a_file_5
[root@ip-172-31-61-147 ~]#
[root@ip-172-31-61-147 ~]#
[root@ip-172-31-61-147 ~]# md5sum /srv/too_large_a_file_5
e8154ef97a3eb2bd13aea04b823a4570  /srv/too_large_a_file_5
[root@ip-172-31-61-147 ~]# free -m && sync && echo 3 > /proc/sys/vm/drop_caches && free -m
             total        used        free      shared  buff/cache   available
Mem:           3533          93         298         104        3141        3091
Swap:             0           0           0
             total        used        free      shared  buff/cache   available
Mem:           3533          93        3274         112         166        3175
Swap:             0           0           0
[root@ip-172-31-61-147 ~]# md5sum /srv/too_large_a_file_5
154248d2eeaf5791dfc8199e51daadbc  /srv/too_large_a_file_5
[root@ip-172-31-61-147 ~]# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1      8.0G  2.2G  5.9G  28% /
devtmpfs        1.9G     0  1.9G   0% /dev
tmpfs           1.8G     0  1.8G   0% /dev/shm
tmpfs           1.8G  113M  1.7G   7% /run
tmpfs           1.8G     0  1.8G   0% /sys/fs/cgroup
/dev/xvdb1      4.0G  4.0G   20K 100% /mnt
tmpfs           354M     0  354M   0% /run/user/1000
/dev/loop0       10G  4.9G  5.2G  49% /srv

重啟後

[root@ip-172-31-61-147 ~]# mount /mnt/file /srv/
[root@ip-172-31-61-147 ~]# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1      8.0G  2.2G  5.9G  28% /
devtmpfs        1.9G     0  1.9G   0% /dev
tmpfs           1.8G     0  1.8G   0% /dev/shm
tmpfs           1.8G   17M  1.8G   1% /run
tmpfs           1.8G     0  1.8G   0% /sys/fs/cgroup
tmpfs           354M     0  354M   0% /run/user/1000
/dev/xvdb1      4.0G  4.0G   20K 100% /mnt
/dev/loop0       10G  4.9G  5.2G  49% /srv
[root@ip-172-31-61-147 ~]#

**編輯 5:**同步資訊

似乎以同步方式安裝文件會產生錯誤。

[root@ip-172-31-61-147 ~]# mount -odefaults,sync /mnt/file /srv/
[root@ip-172-31-61-147 ~]# mount
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime,seclabel)
..snip..
/dev/xvdb1 on /mnt type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
/mnt/file on /srv type xfs (rw,relatime,sync,seclabel,wsync,attr2,inode64,noquota)
[root@ip-172-31-61-147 ~]# cp too_large_a_file /srv/too_large_a_file_5
[root@ip-172-31-61-147 ~]# cp too_large_a_file /srv/too_large_a_file_5
cp: error writing ‘/srv/too_large_a_file_5’: Input/output error
cp: failed to extend ‘/srv/too_large_a_file_5’: Input/output error
[root@ip-172-31-61-147 ~]# ls /srv/
too_large_a_file  too_large_a_file_2  too_large_a_file_3  too_large_a_file_4  too_large_a_file_5

盒子上是否有足夠的記憶體來完全記憶體文件內容?無論如何,我認為這是一個在核心/文件系統實現中尚未解決的極端情況錯誤。畢竟,這裡有很多層在起作用。

“現在,當我嘗試創建一個應該超出主機驅動器的文件時,它也會正確寫入並且不會報告錯誤。”

[root@ip-172-31-61-147 ~]# dd if=/dev/zero of=/srv/too_large_a_file

是的,它會正確寫入,因為您正在寫入零,這是稀疏文件的內容,除非它被覆蓋到其他內容,因此您在此處所做的操作不會向稀疏文件寫入任何內容。如果你寫的不是零,寫就會失敗。

cp 和 rsync 可能會根據作業系統和核心版本保持稀疏性。

引用自:https://serverfault.com/questions/870913