Files

將稀疏文件原地轉換為非稀疏文件

  • November 24, 2014

在 Linux 上,給定一個稀疏文件,如何使其不稀疏?

可以用 複製cp --sparse=never ...,但是如果文件是10G,洞是2G(即分配的空間是8G),如何讓文件系統分配剩餘的2G而不將原來的8G複製到新文件?

從表面上看,這很簡單dd

dd if=sparsefile of=sparsefile conv=notrunc bs=1M

它讀取整個文件,並將整個內容寫回它。

為了只寫孔本身,您首先必須確定這些孔在哪裡。您可以使用filefrag或來做到這一點hdparm

文件片段:

# filefrag -e sparsefile
Filesystem type is: 58465342
File size of sparsefile is 10737418240 (2621440 blocks of 4096 bytes)
ext:     logical_offset:        physical_offset: length:   expected: flags:
  0:        0.. 1048575:  187357696.. 188406271: 1048576:            
  1:  1572864.. 2621439:  200704128.. 201752703: 1048576:  188406272: last,eof
sparsefile: 2 extents found

高畫質晰度:

# hdparm --fibmap sparsefile

sparsefile:
filesystem blocksize 4096, begins at LBA 0; assuming 512 byte sectors.
byte_offset  begin_LBA    end_LBA    sectors
          0 1498861568 1507250175    8388608
 6442450944 1605633024 1614021631    8388608

正如你所說,這個範例文件10G的大小是2G帶孔的。它有兩個範圍,第一個覆蓋0-1048575,第二個1572864-2621439,這意味著孔是1048576-1572864(在 4k 大小的塊中,如圖所示filefrag)。顯示的資訊hdparm是相同的,只是顯示方式不同(第一個範圍覆蓋8388608從 0 開始的 512 字節扇區,所以它是0-4294967295字節,所以孔4294967296-6442450944以字節為單位。

請注意,如果有任何碎片,您可能會看到更多的範圍。不幸的是,這兩個命令都沒有直接顯示漏洞,而且我不知道有哪個命令會這樣做,因此您必須從顯示的邏輯偏移中推斷出它。

現在,可以通過添加適當的(相同的) /值和來填充該1048576-1572864孔,dd如上所示。請注意,已調整為使用上面使用的扇區。(對於,您必須調整搜尋/跳過/計數值以反映大小塊)。seek``skip``count``bs=``4k``filefrag``bs=1M``1M

dd if=sparsefile of=sparsefile conv=notrunc \
  bs=4k seek=1048576 skip=1048576 count=$((-1048576+1572864))

雖然您可以用填充孔/dev/zero而不是讀取文件本身的孔(這也只會產生零),但無論如何讀取它更安全,sparsefile這樣您就不會損壞數據,以防萬一偏移錯誤。

在較新版本的 中GNU dd,您可能會堅持使用更大的塊大小並以字節為單位指定所有值:

dd if=sparsefile of=sparsefile conv=notrunc bs=1M \
  iflag=skip_bytes,count_bytes oflag=seek_bytes \
  seek=4294967296 skip=4294967296 count=$((-4294967296+6442450944))

filefrag執行之後:

# sync
# filefrag -e sparsefile 
Filesystem type is: 58465342
File size of sparsefile is 10737418240 (2621440 blocks of 4096 bytes)
ext:     logical_offset:        physical_offset: length:   expected: flags:
  0:        0.. 1572863:  187357696.. 188930559: 1572864:            
  1:  1572864.. 2621439:  200704128.. 201752703: 1048576:  188930560: last,eof
sparsefile: 2 extents found

由於碎片化,它仍然是兩個範圍。但是,邏輯偏移顯示這一次,沒有洞,所以文件不再稀疏。

當然,這個dd解決方案是非常手動的方法。如果您經常需要它,那麼編寫一個填補這些空白的小程序會很容易。如果它已經作為標準工具存在,我還沒有聽說過。


畢竟有一個工具,fallocate似乎工作,在時尚之後:

fallocate -l $(stat --format="%s" sparsefile) sparsefile

然而,最後在 XFS 的情況下,雖然它確實為這個文件分配了物理區域,但它實際上並沒有將它歸零。filefrag顯示已分配但未寫入的範圍。

  2:        3..      15:    7628851..   7628863:     13:    7629020: unwritten

如果目的是能夠直接從塊設備讀取正確的數據,這還不夠好。它只保留未來寫入所需的儲存空間。

引用自:https://unix.stackexchange.com/questions/169669