dd でランダム データを作成すると、「部分読み取り警告」が表示されます。警告後のデータは本当にランダムですか?

dd でランダム データを作成すると、「部分読み取り警告」が表示されます。警告後のデータは本当にランダムですか?

でランダム データを含む 1TB のファイルを作成しますdd if=/dev/urandom of=file bs=1M count=1000000kill -SIGUSR1 <PID>進行状況を確認すると、次のようになります。

691581+0 Datensätze ein
691580+0 Datensätze aus
725174190080 Bytes (725 GB) kopiert, 86256,9 s, 8,4 MB/s
800950+1 Datensätze ein
800950+0 Datensätze aus
839856947200 Bytes (840 GB) kopiert, 99429,5 s, 8,4 MB/s
dd: warning: partial read (809620 bytes); suggest iflag=fullblock
803432+1 Datensätze ein
803431+1 Datensätze aus
842459273876 Bytes (842 GB) kopiert, 99791,3 s, 8,4 MB/s

警告を解釈できません。何と書いてあるのですか? 警告後、ファイルは本当にランダムですか、それとも何か問題がありますか? および の +0 または +1 はどういう意味ですか800950+1 Datensätze ein?800950+0 Datensätze aus警告後、+1 です。これはエラーカウントですか?

答え1

要約:ddは、正しく使用するのが難しい、扱いにくいツールです。多数のチュートリアルでそうするように指示されていますが、使用しないでくださいdd。このツールには「UNIX のストリート クレジット」の雰囲気が漂っていますが、自分が何をしているのかを本当に理解していれば、絶対に触れるべきではないことがわかります。

ddブロックごとにシステムコールを1回呼び出しますread( の値で定義されますbs)。システムコールが指定されたバッファサイズと同じ量のデータを返すという保証はありませんread。これは、通常のファイルやブロックデバイスでは機能しますが、パイプや一部のキャラクタデバイスでは機能しません。dd はいつデータのコピーに適しているのでしょうか? (または、read() と write() が不完全なのはいつでしょうか)詳細については、readシステム コールが 1 つの完全なブロックより少ないブロックを返す場合、dd部分的なブロックを転送します。指定された数のブロックがコピーされるため、転送されるバイトの合計量は要求された量より少なくなります。

「部分読み取り」に関する警告は、まさにこのことを示しています。読み取りの 1 つが部分的であったため、dd不完全なブロックが転送されました。ブロック カウントでは、 は+11 つのブロックが部分的に読み取られたことを意味します。出力カウントは であるため+0、すべてのブロックが読み取り済みとして書き出されました。

これはデータのランダム性には影響しません。dd書き出されるバイトはすべて、読み取られるバイトです/dev/urandom。ただし、予想よりも少ないバイト数しか取得されません。

Linux は/dev/urandom任意の大きなリクエストに対応します (出典:extract_entropy_userはで実行されるdrivers/char/random.cため、dd通常は読み取り時に安全です。ただし、大量のデータの読み取りには時間がかかります。プロセスがシグナルを受信すると、readシステム コールは出力バッファを埋める前に戻ります。これは正常な動作であり、アプリケーションはreadループ内で呼び出すことになっていddます。 は歴史的な理由により、これを行いません (ddの起源は不明瞭ですが、特殊な要件を持つテープにアクセスするためのツールとして始まったようで、汎用ツールとして採用されることはありませんでした)。進行状況を確認すると、dd読み取りを中断するシグナルがプロセスに送信されます。合計で何バイトddコピーされるかを知るか (中断しないように注意してください。進行状況チェックや一時停止はありません)、ddこれまでに何バイトコピーされたかを知るか (後者の場合は、あと何バイトコピーされるかわかりません) を選択できます。

バージョンddGNU coreutilsで(非組み込み Linux および Cygwin で見られるように) には、ループ内で を呼び出すようにfullblock指示するフラグがあり (についても同様)、常に完全なブロックを転送します。エラー メッセージは、このフラグを使用するように勧めています。非常に特殊な状況 (主にテープへのアクセス時) を除いて、常にこのフラグを使用する必要があります (入力フラグと出力フラグの両方で)。 使用する場合は、通常、より優れた解決策があります (以下を参照)。ddreadwritedd

dd if=/dev/urandom iflag=fullblock of=file bs=1M count=1000000

dd何が実行されるかを確実に知るためのもう 1 つの方法は、ブロック サイズとして 1 を渡すことです。すると、ブロック数からコピーされたバイト数がわかりますが、read最初のバイトを読み取る前に割り込みが発生した場合に何が起こるかはわかりません (実際にはあまり起こりませんが、発生する可能性があります)。ただし、動作したとしても、非常に低速です。

使用に関する一般的なアドバイスdd使ってはいけませんddはデバイスにアクセスするための低レベルのコマンドとして宣伝されることが多いですがdd、実際にはそのようなものではありません。すべての魔法はデバイス ファイル ( /dev/…) 部分で発生しますが、ddこれは誤用されてデータ損失につながる可能性が高い、単なる普通のツールです。ほとんどの場合、少なくとも Linux では、必要なことを実行するよりシンプルで安全な方法があります。

たとえば、ファイルの先頭にある特定のバイト数を読み取るには、次のように呼び出しますhead

head -c 1000000m </dev/urandom >file

私は自分のマシンで簡単なベンチマークを実行しましたが、dd大きなブロック サイズとの間でパフォーマンスの違いは観察されませんでしたhead

先頭でいくつかのバイトをスキップする必要がある場合は、次tailのようにパイプしますhead

dd if=input of=output count=C bs=B seek=S
<input tail -c +$((S*B+1)) | head -c $((C*B)) >output

進行状況を確認したい場合は、を呼び出してlsofファイル オフセットを確認してください。これは通常のファイル (例の出力ファイル) でのみ機能し、キャラクタ デバイスでは機能しません。

lsof -a -p 1234 -d 1
cat /proc/1234/fdinfo/1

電話をかけることができますpv進捗レポートを取得するには ( よりも優れていますdd)、パイプラインに追加の項目が必要になります (パフォーマンス的には、ほとんど気付かない程度です)。

答え2

この警告は、dd1 回の読み取りでブロックを埋めるのに十分なデータを取得できなかった場合に発生します。これは、不安定または低速のデータ ソース、または要求されたブロック サイズよりも小さい単位でデータを書き込むソースで発生します。

ddデータの整合性には問題はありませんが、部分的な読み取りが依然として読み取りブロックとしてカウントされるという問題があります。

オプションを使用していない場合はcount、警告はほとんど問題にはなりません。これはパフォーマンスに関する考慮事項にすぎません。ただしcount、を使用すると、要求したデータ量は取得されません。部分的な読み取りのため、は最後ofよりも小さくなります。count*bs

したがって、 を使用する場合はcount、技術的には常に も使用する必要がありますiflag=fullblock

+x部分ブロックの数である必要があります。

答え3

< /dev/urandom \
dd ibs=4k obs=64k |
dd bs=64k count=16000000 >file

^これでうまくいきます。ここでの誤った情報は明らかに誤りです。ddのバッファは明示的なそして入力をバッファリングするためにカウント明示的にバッファリングする必要がある発生。それだけです。FUD に騙されないでください。

関連情報