Linuxでは、スパースファイルが与えられた場合、そのファイルを非スパースにする方法を教えてください。
それはcp --sparse=never ...
、ただし、ファイルが10Gで、ホールが2Gの場合(つまり、割り当てられたスペースが8Gの場合)、元の8Gを新しいファイルにコピーせずに、ファイルシステムに残りの2Gを割り当てる方法は?
一見すると、それは単純な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
のサイズです。これには2つのエクステントがあり、1つ目は0-1048575
をカバーし、2つ目は1572864-2621439
をカバーします。これは、ホールが1048576-1572864
であることを意味します(filefrag
で示される4kサイズのブロック)。 hdparm
で表示される情報は同じで、表示が異なるだけです(最初のエクステントは、0から始まる8388608
512バイトセクターをカバーしているため、0-4294967295
バイトなので、ホールは4294967296-6442450944
バイトです。
断片化があると、とにかくかなり多くのエクステントが表示される場合があることに注意してください。残念ながら、どちらのコマンドもホールを直接表示せず、そのようなホールを私は知らないので、表示された論理オフセットからそれを推定する必要があります。
ここで、上記のように1048576-1572864
ホールをdd
で埋めるには、適切な(同一の)seek
/skip
値とcount
を追加します。 bs=
は、上記のfilefrag
で使用される4k
セクターを使用するように調整されていることに注意してください。 (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
これは、ブロックデバイスから直接正しいデータを読み取ることができる場合には、十分ではありません。将来の書き込みに必要なストレージ領域を予約するだけです。