Mengonversi file jarang menjadi non-jarang di tempat

8

Di Linux, diberi file jarang, bagaimana membuatnya non-jarang, di tempat?
Itu bisa disalin cp --sparse=never ..., tetapi jika file tersebut mengatakan 10G dan lubangnya adalah 2G (yaitu ruang yang dialokasikan adalah 8G), bagaimana membuat filesystem mengalokasikan 2G yang tersisa tanpa menyalin 8G asli ke file baru?

Ivan
sumber

Jawaban:

11

Secara sederhana, ini sederhana dd:

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

Itu membaca seluruh file, dan menulis seluruh konten kembali ke sana.

Untuk hanya menulis lubang itu sendiri, pertama-tama Anda harus menentukan di mana lubang itu berada. Anda dapat melakukannya dengan menggunakan baik filefragatau 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

Contoh file ini, seperti yang Anda katakan, 10Gberukuran 2Gberlubang. Ini memiliki dua luasan, penutup pertama 0-1048575, kedua 1572864-2621439, yang berarti bahwa lubang itu 1048576-1572864(dalam blok ukuran 4k, seperti yang ditunjukkan oleh filefrag). Info yang ditunjukkan oleh hdparmadalah sama, hanya ditampilkan secara berbeda (tingkat pertama mencakup 8388608sektor 512-byte mulai dari 0 sehingga 0-4294967295byte, sehingga lubang 4294967296-6442450944dalam byte.

Perhatikan bahwa Anda mungkin akan diperlihatkan jauh lebih luas jika ada fragmentasi. Sayangnya, tidak ada perintah yang menunjukkan lubang secara langsung, dan saya tidak tahu yang melakukannya, jadi Anda harus menyimpulkannya dari offset logis yang ditampilkan.

Sekarang, mengisi 1048576-1572864lubang itu dengan ddseperti yang ditunjukkan di atas, dapat dilakukan dengan menambahkan yang sesuai (identik) seek/ skipnilai dan count. Perhatikan bahwa bs=diadaptasi untuk menggunakan 4ksektor - sektor seperti yang digunakan oleh di filefragatas. (Untuk bs=1M, Anda harus menyesuaikan nilai pencarian / lewati / hitung untuk mencerminkan 1Mblok berukuran).

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

Meskipun Anda dapat mengisi lubang dengan /dev/zeroalih - alih membaca lubang file itu sendiri (yang juga akan menghasilkan angka nol), tetap lebih aman untuk membaca dari yang lain sparsefilesehingga Anda tidak akan merusak data Anda jika Anda mendapat offset yang salah.

Dalam versi yang lebih baru GNU dd, Anda dapat tetap menggunakan blocksize yang lebih besar dan menentukan semua nilai dalam byte:

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 setelah menjalankan itu:

# 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

Karena fragmentasi, itu masih dua tingkat. Namun, offset logis menunjukkan bahwa kali ini, tidak ada lubang, sehingga file tidak lagi jarang.

Secara alami, ddsolusi ini adalah pendekatan yang sangat manual untuk berbagai hal. Jika Anda membutuhkan ini secara teratur, akan mudah untuk menulis sebuah program kecil yang mengisi kekosongan tersebut. Jika sudah ada sebagai alat standar, saya belum pernah mendengarnya.


Lagipula ada alat, fallocatesepertinya berfungsi, setelah mode:

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

Namun pada akhirnya dalam kasus XFS, meskipun tidak mengalokasikan area fisik untuk file ini, sebenarnya tidak nol. filefragmenunjukkan luasan seperti yang dialokasikan, tetapi tidak tertulis.

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

Ini tidak cukup baik jika tujuannya adalah untuk dapat membaca data yang benar langsung dari perangkat blok. Ini hanya menyimpan ruang penyimpanan yang dibutuhkan untuk penulisan di masa mendatang.

frostschutz
sumber
1
Atau cat sparsefile 1<> sparsefile. Anda mungkin dapat menggunakan fallocateLinux untuk menghindari keharusan menulis byte NUL itu jika yang Anda inginkan adalah ruang yang dialokasikan.
Stéphane Chazelas
@ StéphaneChazelas, terima kasih, lupakan fallocate. Memiliki --dig-holestetapi tidak ada --fill-holes. Namun, tampaknya berfungsi cukup baik ketika Anda menentukan ukurannya. Saya akan mengedit jawaban saya.
frostschutz
Pada NFS atau ext3 fallocate tidak didukung.
Ivan
Newer fallocatememiliki -zyang dapat digunakan di Linux 3.14 dan di atas pada ext4 dan xfs (Anda harus menjalankannya dengan -odan -luntuk semua bagian yang jarang saya kira).
Stéphane Chazelas
@ StéphaneChazelas, ya, tapi ini -ztidak menyimpan data Anda jika Anda salah offset, jadi saya akan tetap di ddsana ...
frostschutz