スパースファイルを非スパースファイルにインプレースで変換する


8

Linuxでは、スパースファイルが与えられた場合、そのファイルを非スパースにする方法を教えてください。
でコピーすることもできcp --sparse=never ...ますが、ファイルが10Gで、穴が2Gの場合(つまり、割り当てられたスペースは8Gです)、元の8Gを新しいファイルにコピーせずに、ファイルシステムに残りの2Gを割り当てる方法は?

回答:


11

一見、それはシンプルddです:

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

これにより、ファイル全体が読み取られ、内容全体がファイルに書き戻されます。

穴自体のみを書き込むには、まずそれらの穴がどこにあるかを判別する必要があります。あなたはいずれかを使用してそれを行うことができますfilefraghdparm

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

この例のファイルは、あなたが言うように10G2G穴のあるサイズです。最初のカバー0-1048575と2番目の2つのエクステントがあります。1572864-2621439これは、穴が1048576-1572864(で示される4kサイズのブロックでfilefrag)であることを意味します。によって表示される情報hdparmは同じですが、表示が異なるだけです(最初のエクステントは83886080から始まる512バイトのセクターをカバーしている0-4294967295ため、バイトなので、ホールは4294967296-6442450944バイト単位です。

断片化があると、とにかくかなり多くのエクステントが表示される場合があることに注意してください。残念ながら、どちらのコマンドもホールを直接表示しません。また、そのようなホールを私は知らないので、表示された論理オフセットからそれを推定する必要があります。

ここで、上記のようにその1048576-1572864穴を埋めるには、dd適切な(同一の)seek/ skip値とを追加しますcountbs=4kfilefrag上記で使用されたセクターを使用するように適合されていることに注意してください。(の場合bs=1M1Mサイズ設定されたブロックを反映するようにシーク/スキップ/カウント値を調整する必要があります)。

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

これは、ブロックデバイスから直接正しいデータを読み取ることができる場合には、十分ではありません。将来の書き込みに必要なストレージスペースのみを予約します。


1
またはcat sparsefile 1<> sparsefilefallocateLinuxでを使用して、割り当てたいスペースだけが必要な場合は、NULバイトを書き込む必要をなくすことができます。
ステファンChazelas

@StéphaneChazelas、ありがとう、忘れてしまいましたfallocate。それはあり--dig-holesません--fill-holes。ただし、サイズを指定すると十分機能するようです。回答を編集します。
frostschutz 2014年

NFSまたはext3では、fallocateはサポートされていません。
Ivan、

新しいfallocate持ち-zのext4とXFS上のLinux 3.14にして上で使用することができます(あなたがそれを実行する必要があるだろう-o-l私が思う、すべてのスパースセクションのため)。
ステファンChazelas

@StéphaneChazelas、うん、-zでも、オフセットが誤って取得された場合、データは保持されないので、それに固執しddます...
frostschutz 2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.