`dd`を使用してデータブロックを右シフトするにはどうすればよいですか?


10

簡単な例として、100MBのrawブロックデバイスを考えます。つまり、合計512760バイトの512バイトの204800ブロックです。

最初の98MB(200704ブロック)をシフトして、その前に2MB(4096ブロック)のギャップを設けることが課題です。これをインプレースで行うには、読み取られていないセクターに何も書き込まれないことが必要です。これを実現する1つの方法は、バッファーを導入することです。

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

期待されるのはmbuffer、ライターに何かを渡す前に4096ブロックを格納することです。これにより、読み取られていない領域に何も書き込まれず、ライターがバッファーのサイズによってリーダーよりも遅れることが保証されます。バッファーは、リーダーとライターがそれらの制約内で可能な限り高速に動作できるようにする必要があります。

ただし、確実に機能するようには見えません。私は実際のデバイスを使ってみましたが、実際には機能しませんが、ファイルを使った実験は64ビットボックスでは機能しましたが、32ビットボックスでは機能しませんでした。

まず、いくつかの準備:

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

これは機能しません:

$ 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

これは64ビットシステムでは機能しますが、32ビットシステムでは機能しません。

$ 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

これをどのように確実に行うことができますか?


ノート

バッファリングに関する他の質問を読みpvbufferとを調べましたmbuffer。私は後者を必要なバッファサイズでのみ動作させることができました。

中間ストレージを使用することは、常に機能する問題の明白な解決策ですが、十分なスペア容量が利用できない場合は現実的ではありません。

mbufferバージョン20140302でArch Linuxを実行しているプラ​​ットフォームをテストします。


私はそれで問題が解決するとは思いませんが、好奇心から、なぜ使用mbufferするのですか?代わりddに、ブロックデバイスの内容全体を一度に読み取らせてみませんdd bs=102760448か?もちろん、いずれかの方法でRAMにバッファーされます。
Celada 2014年

@Celada-100MBの例は単なる例です。たとえば、1 TBを一度に読み取ることは、あまり良い考えではありません。
starfry 2014年

2
ああ、わかりました、ありがとう。mbuffer実際に二を強制すべきdd最初のために遅れするとあなただけのシフトの大きさをバッファするために十分なRAMが必要です。あまりにも悪いのは、ddそれが問題を排除するため、後方の順にブロックを読み込み、書き込みをサポートしていません!
Celada

2番目のmd5sumの計算方法をリストしていませんでした
psusi

@ psusi、2番目のmd5はmbufferによって出力されます(その-H引数はこの機能を有効にします)。
starfry

回答:


2

バッファがなければ、一度に1ブロックずつ逆戻りできます。

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

この例はエラーチェックがないため危険であることに注意してください。

また、dd呼び出しの量が原因で速度が低下します。メモリに余裕がある場合は、より大きなブロックサイズを使用できます。

バッファを使用すると、落とし穴注意してください。100%のプレフィルを保証するだけで不十分です。必要なのは、プロセス全体の最小充填です。バッファは決して下に落ちてはいけません。2Mそうしないと、まだ読み取られていないデータを再び上書きしてしまうからです。

したがって、理論的には、どのような種類のバッファもなしで連鎖するだけで済みます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

実際には、最後の(間に「バッファ」がある)がすでに書き込みを行っている間、最初のデータが何とかデータを読み続けることが保証されていないため、これは確実に機能しませdddd2M

中間バッファをかなり大きくすることで可能性を大幅に高めることができますが、それでも信頼性はありません。

残念ながら、フィルプロパティが最小限の適切なバッファプログラムはわかりません。バッファ内の安全マージンよりも少ない限り、出力を停止するものが必要です。


dd使用方法を示すことにより元の質問に答えるため、これを受け入れました。しかし、本当の解決策は使用するのではなく、のddように逆方向に実行するように設計されたものを選択することだと思いddrescueます。私は答えでそれを行う方法を説明しました。
starfry

1
@starfry:確かに、それを行うだけのプログラムは素晴らしい解決策になるでしょう。しかし、私はddrescueここについては全然わかりません。それが別のデバイスで動作することを期待しているのではなく、引数を受け入れるようにだまさなければなりません。また、内部に「最小バッファーフィル」プロパティがない場合があり(別のデバイスでは必要ないため)、データが破損する可能性があります。ソースコードが実際にユースケース用に設計されているかどうかをチェックする必要があります。
frostschutz 2014年

1

4096ブロックを読み取ってから、それらの4096ブロックをディスクの次の4096ブロックに書き込むため、2番目の4096ブロックが読み取られる前に上書きされます。書き込みを開始する前に、2番目の4096を取得するために8129ブロックを読み取る必要があり、次の4096を読み取る前に4096ブロックのみを書き込む必要があります。

これがどのようなファイルシステムであるかについては触れませんでした。ext [234]で、e2fsprogsの最新バージョンがある場合は、を使用できますe2image -ra -O 512 /dev/sdj2。これには、ボリュームの空きスペースをスキップするのに十分なほどスマートになるという追加の利点もあります。


それを読むときにそれは理にかなっているので、それに基づいてもう一度見てみましょう。ただし、テストファイルで機能した理由は説明されていません。
starfry 2014年

ファイルシステムについて、私のテストファイルを含むファイルシステムを参照していますか?これext4は、ブロックデバイスコピーの場合は関係ありません。
starfry 2014年

@starfry、私がこれを一般的な方法で行う唯一の方法は、エマニュエルが提案したアルゴリズム(最後から逆方向に作業する)を使用することです。これはgpartedが行うことです。
psusi

ブロックサイズについて、私はより大きなブロックを試しました(私はそれを質問に書いたはずです)。64Kセクターバッファーでも信頼性が高くならないことがわかりました。信頼できる解決策は、逆方向に実行することddです。
starfry

1

信頼性の高いソリューションでは、読み取られていない可能性がある領域に何も書き込まないようにする必要があります。これを実現する唯一の実際の方法は、逆方向にコピーを実行することです。

ddrescueこのツールは、逆方向に動作することができますが、それは入力と出力が同じであることを実行することはできません。ただし、デバイスノードを複製することでだまされる可能性があります。

私はいくつかの簡単な実験を行いましたが、うまくいくようです。コマンドラインは次のとおりです。

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

引数は

  • -f 既存の出力デバイスに強制的に書き込むために必要です
  • -R 逆方向に動作するように指示します
  • -sコピーする入力の量を示します(sサフィックスを使用してセクター数を指定します)
  • -o書き込む前に出力デバイスで転送をシークするように指示します(s接尾辞付きのセクターで再度指定)
  • /dev/sdj11 読み取るブロックデバイスです
  • /dev/sdj11_copy 書き込むブロックデバイスです

のパラメータと一致するように作成/dev/sdj11_copymknodました/dev/sdj11

私はいくつかの非常に簡単なテストしか行っていませんが、これはrawデバイスをコピーするのに問題がないようです。それはファイルでは機能しません(同じファイルであることを超えてそれをするようにそれをだますことができませんでした)

これでこれを達成する方法を尋ねた私の元の質問には答えませんddが、他の答えを読んだので、その答えはそれddを行うことができないと思います。


ddrescueこのシナリオで不良ブロックを発見した場合はどうなりますか?ディスクの別の領域にジャンプし(不良ブロックを回避するため)、そこからコピーを続行すると、データのまだコピーされていない部分が再び上書きされます。同じデバイスでの動作が想定されていない場合、考えられるさまざまなデータ破損のケースを防ぐために特別な対策を講じる理由はありません。
frostschutz 2014年

これは潜在的な問題であることに同意しますが、必要なことを行うためにそれを使用することができたので、エッジケースを見ていません。ddrescue不良データを回復する試みを制限するオプションがありますが、それらを使用することは検討していません。
starfry

入力と出力が同じ場合に動作を拒否するという事実は、おそらく安全ではないことを示す良い兆候です。
psusi 2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.