web-dev-qa-db-ja.com

ddでランダムデータを作成し、「部分的な読み取り警告」を取得します。警告後のデータは本当にランダムですか?

dd if=/dev/urandom of=file bs=1M count=1000000でランダムなデータを含む1TBのファイルを作成します。次に、kill -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

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

17
delete

概要:ddは、正しく使用するのが難しい、気難しいツールです。多数のチュートリアルで説明されていますが、使用しないでください。 ddには「unix street cred」という雰囲気が付いていますが、自分が何をしているのかを本当に理解していれば、10フィートのポールで触れてはならないことがわかります。

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

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

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

Linuxの/dev/urandomは、任意の大きなリクエストに対応します(ソース: extract_entropy_user in drivers/char/random.c)。そのため、ddは通常、そこから読み取るときに安全です。ただし、大量のデータを読み取るには時間がかかります。プロセスがシグナルを受信した場合、readシステムコールは、その出力バッファーがいっぱいになる前に戻ります。これは正常な動作であり、アプリケーションはreadをループで呼び出すことになっています。歴史的な理由により、ddはこれを行いません(ddの起源は曖昧ですが、テープにアクセスするためのツールとして開始されたようであり、固有の要件があり、汎用ツールとしては適応されていません)。進行状況を確認すると、ddプロセスに読み取りを中断するシグナルを送信します。合計でddがコピーするバイト数を知る(中断しないように注意してください—進行状況チェックなし、中断なし)か、これまでにddがコピーしたバイト数を知るか、その場合、方法を知ることができませんそれがコピーするより多くのバイト。

dd in GNU coreutils (非組み込みLinuxとCygwinにあります)のバージョンは、fullblockddにループでreadを呼び出すように指示します(およびwriteの場合はdittoを使用し、常に完全なブロックを転送します。エラーメッセージはそれを使用することを示唆しています。非常に特殊な状況(主にテープにアクセスする場合)を除いて、常に使用する必要があります(ddを使用する場合)つまり、通常、より優れたソリューションがあります(以下を参照)。

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

ddが何を行うかを確認するもう1つの方法は、ブロックサイズ1を渡すことです。その後、ブロックカウントからコピーされたバイト数を確認できますが、readが読み取られる前に中断された場合はどうなるかわかりません最初のバイト(実際にはあまりありませんが、発生する可能性があります)。ただし、機能しても、非常に低速です。

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

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

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

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

最初にいくつかのバイトをスキップする必要がある場合は、tailheadにパイプします。

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よりも優れています)。ただし、パイプラインに項目が追加されることになります(パフォーマンスの点では、ほとんど認識されません)。

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

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

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

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

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

9
frostschutz