Bagaimana `dd` dapat digunakan untuk menggeser blok data dengan benar?

10

Pertimbangkan perangkat blok mentah 100MB sebagai contoh sederhana. Itu adalah 2.048.000 blok masing-masing 512 byte untuk total 102760448 byte.

Tantangannya adalah untuk menggeser 98MB pertama (200704 blok) sehingga ada celah 2MB (4096 blok) di depannya. Untuk melakukan ini di tempat mengharuskan tidak ada yang ditulis untuk sektor yang belum dibaca. Salah satu cara untuk mencapai ini adalah dengan memperkenalkan buffer:

$ dd if=/dev/sdj2 count=200704 | mbuffer -s 512 -b 4096 -P 100 | dd of=/dev/sdj2 seek=4096

Harapannya adalah bahwa mbufferakan menyimpan 4.096 blok sebelum menyerahkan apa pun kepada penulis, sehingga memastikan bahwa tidak ada yang ditulis ke area yang belum dibaca dan bahwa penulis tertinggal pembaca dengan ukuran buffer. Buffer harus memungkinkan pembaca dan penulis beroperasi secepat mungkin dalam konstanta-konstanta itu.

Namun, sepertinya itu tidak berfungsi dengan baik. Saya sudah mencoba menggunakan perangkat nyata tetapi tidak pernah berhasil pada mereka, sedangkan percobaan dengan file bekerja pada kotak 64-bit saya tetapi tidak pada kotak 32-bit saya.

Pertama, beberapa persiapan:

$ dd if=/dev/sdj2 count=200704 | md5sum
0f0727f6644dac7a6ec60ea98ffc6da9
$ dd if=/dev/sdj2 count=200704 of=testfile

Ini tidak berfungsi:

$ dd if=/dev/sdj2 count=200704 | mbuffer -s 512 -b 4096 -P 100 -H | dd of=/dev/sdj2 seek=4096
summary: 98.0 MiByte in  4.4sec - average of 22.0 MiB/s
md5 hash: 3cbf1ca59a250d19573285458e320ade

Ini berfungsi pada sistem 64-bit tetapi tidak pada sistem 32-bit:

$ dd if=testfile count=200704 | mbuffer -s 512 -b 4096 -P 100 -H | dd of=testfile seek=4096 conv=notrunc
summary: 98.0 MiByte in  0.9sec - average of  111 MiB/s
md5 hash: 0f0727f6644dac7a6ec60ea98ffc6da9

Bagaimana ini bisa dilakukan dengan andal?


catatan

Saya telah membaca pertanyaan lain tentang buffering dan melihat pv, bufferdan mbuffer. Saya hanya bisa mendapatkan yang terakhir untuk bekerja dengan ukuran buffer yang diperlukan.

Menggunakan penyimpanan intermetiate adalah solusi yang jelas untuk masalah yang selalu berhasil tetapi tidak praktis ketika kapasitas cadangan yang memadai tidak tersedia.

Platform uji yang menjalankan Arch Linux dengan mbufferversi 20140302.

starfry
sumber
Saya tidak mengira itu akan menyelesaikan masalah, tetapi karena penasaran mengapa digunakan mbuffersama sekali? Mengapa tidak malah ddmembaca seluruh isi perangkat blok dalam sekali pakai dd bs=102760448? Tentu saja, satu atau lain cara itu buffered dalam RAM.
Celada
@Celada - contoh 100MB hanyalah contoh. Membaca 1TB, misalnya, dalam sekali jalan bukan ide yang bagus.
Starfry
2
Ah, saya mengerti sekarang, terima kasih. The mbufferharus benar-benar memaksa kedua ddtertinggal untuk pertama dan Anda hanya perlu cukup RAM untuk penyangga ukuran shift. Sayang sekali ddtidak mendukung membaca dan menulis blok dalam urutan terbalik karena itu akan menghilangkan masalah!
Celada
Anda tidak mencantumkan bagaimana Anda menghitung md5sum kedua
psusi
@psusi, md5 kedua adalah output oleh mbuffer ( -Hargumennya memungkinkan fitur ini).
Starfry

Jawaban:

2

Tanpa buffer, Anda bisa mundur, satu blok pada satu waktu.

for i in $(seq 100 -1 0)
do
    dd if=/dev/thing of=/dev/thing \
       bs=1M skip=$i seek=$(($i+2)) count=1
done

Harap perhatikan bahwa contoh ini berbahaya karena kurangnya pemeriksaan kesalahan.

Ini juga lambat karena jumlah ddpanggilan. Jika Anda memiliki memori yang tersisa, Anda dapat menggunakan ukuran blok yang lebih besar.

Dengan penyangga, berhati-hatilah dengan perangkap . Hal ini tidak cukup untuk menjamin 100% Prefill. Yang Anda butuhkan adalah pengisian minimum selama seluruh proses. Buffer tidak boleh pernah jatuh di bawah ini 2Mkarena jika tidak Anda akan menimpa data Anda yang belum dibaca lagi.

Jadi sementara secara teori Anda bisa melakukannya tanpa buffer dan hanya rantai dd:

dd if=/dev/thing bs=1M | \
dd bs=1M iflag=fullblock | \
dd bs=1M iflag=fullblock | \
dd of=/dev/thing bs=1M seek=2

Dalam praktiknya ini tidak bekerja dengan andal karena tidak ada jaminan yang pertama ddmengelola untuk terus membaca data, sedangkan yang terakhir dd(dengan 2M"buffer" di antaranya) sudah menulis.

Anda dapat meningkatkan peluang Anda secara signifikan dengan membuat di antara buffer jauh lebih besar, tetapi meskipun demikian, itu tidak dapat diandalkan.

Sayangnya saya tidak tahu program buffer yang baik dengan properti isi minimum. Anda memerlukan satu yang menghentikan output selama ada kurang dari margin keamanan Anda di dalam buffer.

frostschutz
sumber
Saya menerima ini karena menjawab pertanyaan asli dengan menunjukkan bagaimana ddbisa digunakan. Saya pikir, bagaimanapun, bahwa solusi sebenarnya adalah tidak menggunakan ddtetapi memilih untuk sesuatu yang dirancang untuk berjalan mundur seperti ddrescue. Saya telah menjelaskan cara untuk melakukan itu dalam sebuah jawaban.
Starfry
1
@ starfry: tentu saja, program yang baru saja melakukannya akan menjadi solusi yang bagus. Namun saya sama sekali tidak yakin tentang di ddrescuesini. Tidak jika itu diharapkan dapat bekerja pada perangkat yang berbeda, dan Anda harus mengelabui agar menerima argumen Anda. Mungkin tidak memiliki properti "isi buffer minimum" secara internal (karena dengan perangkat yang berbeda itu tidak diperlukan), jadi sekali lagi itu dapat merusak data Anda. Anda harus memeriksa dalam kode sumber apakah itu benar-benar dirancang untuk kasus penggunaan Anda.
frostschutz
1

Anda membaca 4096 blok, dan kemudian menulis 4096 blok ke 4096 blok berikutnya dari disk, sehingga menimpa blok 4096 kedua sebelum mereka dapat dibaca. Anda perlu membaca 8129 blok untuk mendapatkan yang kedua 4096 sebelum memulai penulisan apa pun, dan kemudian Anda hanya perlu menulis 4096 blok sebelum membaca 4096 berikutnya.

Anda tidak menyebutkan jenis filesystem apa ini. Jika ext [234], dan Anda memiliki versi terbaru dari e2fsprogs, maka Anda dapat menggunakannya e2image -ra -O 512 /dev/sdj2. Ini juga memiliki manfaat tambahan karena cukup pintar untuk melewati ruang kosong dalam volume.

psusi
sumber
Itu masuk akal ketika membacanya dan saya akan melihat lagi berdasarkan itu. Tetapi itu tidak menjelaskan mengapa itu bekerja pada file tes.
Starfry
Kembali ke filesystem, apakah Anda mengacu pada filesystem yang berisi file pengujian saya? Itu ext4tetapi untuk salinan perangkat blok, sistem file apa pun harus tidak relevan.
Starfry
@ Starfry, satu-satunya cara saya tahu untuk melakukan ini dengan cara yang umum adalah dengan menggunakan algoritma yang disarankan Emmanuel (bekerja mundur dari akhir), yang merupakan apa yang dilakukan gparted.
psusi
kembali ukuran blok, saya telah mencoba blok yang lebih besar (saya harus menulis itu dalam pertanyaan). Saya menemukan bahwa itu tidak menjadi lebih andal bahkan penyangga sektor 64K. Solusi yang dapat diandalkan adalah berjalan mundur, sesuatu yang ddtidak dilakukan.
Starfry
1

Solusi yang andal mengharuskan Anda memastikan bahwa tidak ada yang menulis ke area yang mungkin belum dibaca dan satu-satunya cara nyata untuk mencapai itu adalah dengan melakukan salinan dalam arah sebaliknya.

The ddrescuealat dapat bekerja dalam arah sebaliknya tetapi menolak untuk menjalankan dengan input dan output menjadi sama. Namun dimungkinkan untuk mengelabunya dengan menduplikasi node perangkat.

Saya telah melakukan beberapa percobaan cepat dan tampaknya berhasil. Baris perintah adalah:

$ ddrescue -f -R -s 200704s -o 4096s /dev/sdj11 /dev/sdj11_copy

Argumennya adalah

  • -f diperlukan untuk memaksanya menulis ke perangkat output yang ada
  • -R menyuruhnya bekerja ke arah sebaliknya
  • -smemberitahu berapa banyak input untuk disalin (saya menggunakan sakhiran untuk menentukan jumlah sektor)
  • -omemintanya untuk mencari ke depan dalam perangkat output sebelum menulis (ditentukan dalam sektor lagi dengan sakhiran)
  • /dev/sdj11 adalah perangkat blok untuk dibaca
  • /dev/sdj11_copy adalah perangkat blok untuk menulis

Saya buat /dev/sdj11_copydengan mknoduntuk mencocokkan parameter /dev/sdj11.

Saya hanya melakukan beberapa tes yang sangat cepat tetapi ini tampaknya berfungsi baik untuk menyalin perangkat mentah. Itu tidak bekerja pada file (saya tidak bisa mengelabui untuk melampaui file yang sama)

Ini tidak menjawab pertanyaan awal saya yang menanyakan bagaimana mencapainya, ddtetapi saya pikir, setelah membaca jawaban yang lain, jawabannya adalah ddtidak bisa melakukannya.

starfry
sumber
Apa yang terjadi jika ddrescuemenemukan blok buruk dalam skenario ini? Jika lompatan ke area lain dari disk (untuk menghindari blok buruk), dan terus menyalin dari sana, itu lagi akan menimpa belum menyalin bagian data Anda. Jika tidak berharap untuk bekerja dengan perangkat yang sama, tidak memiliki alasan untuk mengambil tindakan khusus untuk mencegah berbagai kemungkinan kasus korupsi data.
frostschutz
Saya setuju bahwa ini adalah masalah potensial tetapi saya belum melihat ujung kasus, karena saya dapat menggunakannya untuk melakukan apa yang saya butuhkan. Ada beberapa ddrescueopsi untuk membatasi upayanya untuk memulihkan data yang buruk, tetapi saya belum melihat untuk menggunakannya.
starfry
Fakta bahwa ia menolak untuk beroperasi jika input dan outputnya sama mungkin merupakan indikasi yang baik bahwa itu tidak aman.
psusi