回答:
一見、それはシンプルdd
です:
dd if=sparsefile of=sparsefile conv=notrunc bs=1M
これにより、ファイル全体が読み取られ、内容全体がファイルに書き戻されます。
穴自体のみを書き込むには、まずそれらの穴がどこにあるかを判別する必要があります。あなたはいずれかを使用してそれを行うことができますfilefrag
かhdparm
。
filefrag:
# 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:
# 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
と2番目の2つのエクステントがあります。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
断片化のため、それはまだ2つのエクステントです。ただし、論理オフセットは、今回は穴がないため、ファイルがスパースではなくなったことを示しています。
当然のことながら、このdd
ソリューションは非常に手作業によるアプローチです。これを定期的に必要とする場合、そのようなギャップを埋める小さなプログラムを書くのは簡単でしょう。すでに標準ツールとして存在している場合、まだ聞いたことがありません。
結局のところ、fallocate
ファッションの後に機能するように見えるツールがあります。
fallocate -l $(stat --format="%s" sparsefile) sparsefile
ただし、XFSの場合、ついに、このファイルに物理領域を割り当てますが、実際にはゼロになりません。filefrag
このようなエクステントは割り当てられているが、書き込まれていません。
2: 3.. 15: 7628851.. 7628863: 13: 7629020: unwritten
これは、ブロックデバイスから直接正しいデータを読み取ることができる場合には、十分ではありません。将来の書き込みに必要なストレージスペースのみを予約します。
fallocate
。それはあり--dig-holes
ません--fill-holes
。ただし、サイズを指定すると十分機能するようです。回答を編集します。
fallocate
持ち-z
のext4とXFS上のLinux 3.14にして上で使用することができます(あなたがそれを実行する必要があるだろう-o
と-l
私が思う、すべてのスパースセクションのため)。
-z
でも、オフセットが誤って取得された場合、データは保持されないので、それに固執しdd
ます...
cat sparsefile 1<> sparsefile
。fallocate
Linuxでを使用して、割り当てたいスペースだけが必要な場合は、NULバイトを書き込む必要をなくすことができます。