Создайте случайные данные с помощью dd и получите "частичное предупреждение о чтении". Данные после предупреждения теперь действительно случайны?

Создайте случайные данные с помощью dd и получите "частичное предупреждение о чтении". Данные после предупреждения теперь действительно случайны?

Я создаю файл размером 1 ТБ со случайными данными с помощью dd if=/dev/urandom of=file bs=1M count=1000000. Теперь я проверяю 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

Я не могу интерпретировать предупреждение. Что оно говорит? Действительно ли мой файл случайный после предупреждения или есть проблема? Что означает +0 или +1 в 800950+1 Datensätze einи 800950+0 Datensätze aus? После предупреждения это +1. Это errorcount?

решение1

Резюме: ddкапризный инструмент, который трудно использовать правильно. Не используйте его, несмотря на многочисленные руководства, которые говорят вам об этом. ddимеет привкус «unix street cred» — но если вы действительно понимаете, что делаете, вы будете знать, что вам не следует трогать его даже 10-футовым шестом.

ddделает один вызов системного readвызова на блок (определяется значением bs). Нет гарантии, что readсистемный вызов вернет столько данных, сколько указан размер буфера. Это обычно работает для обычных файлов и блочных устройств, но не для каналов и некоторых символьных устройств. СмотритеКогда dd подходит для копирования данных? (или когда read() и write() являются частичными)для получения дополнительной информации. Если readсистемный вызов возвращает менее одного полного блока, то ddпередает частичный блок. Он все равно копирует указанное количество блоков, поэтому общее количество переданных байтов меньше запрошенного.

Предупреждение о «частичном чтении» говорит вам именно об этом: одно из чтений было частичным, поэтому ddбыл передан неполный блок. В счетчиках блоков +1означает, что один блок был прочитан частично; поскольку выходной счетчик равен +0, все блоки были записаны как прочитанные.

Это не влияет на случайность данных: все байты, которые ddзаписываются, являются байтами, которые он считывает /dev/urandom. Но вы получили меньше байтов, чем ожидали.

Linux /dev/urandomобрабатывает произвольно большие запросы (источник:extract_entropy_userв drivers/char/random.c), поэтому ddобычно безопасен при чтении из него. Однако чтение больших объемов данных занимает время. Если процесс получает сигнал, системный readвызов возвращается до заполнения своего выходного буфера. Это нормальное поведение, и приложения должны вызывать readв цикле; ddне делает этого по историческим причинам ( ddпроисхождение неясно, но, похоже, он начинался как инструмент для доступа к лентам, которые имеют особые требования, и никогда не был адаптирован как инструмент общего назначения). Когда вы проверяете ход выполнения, это посылает процессу ddсигнал, который прерывает чтение. У вас есть выбор между знанием того, сколько байт ddбудет скопировано в общей сложности (убедитесь, что не прерываете его — нет проверки хода выполнения, нет приостановки), или знанием того, сколько байт ddскопировано на данный момент, в этом случае вы не можете знать, сколько еще байт он скопирует.

Версияddв GNU coreutils(как в невстроенном Linux и в Cygwin) имеет флаг fullblock, который говорит ddвызывать readв цикле (и то же самое для write) и таким образом всегда передавать полные блоки. Сообщение об ошибке предполагает, что вы используете его; вы всегда должны использовать его (как во входных, так и в выходных флагах), за исключением очень особых обстоятельств (в основном при доступе к лентам) — если вы вообще используете его dd, то есть: обычно есть лучшие решения (см. ниже).

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

Другой возможный способ убедиться в том, что ddбудет сделано, — это передать размер блока 1. Тогда вы сможете узнать, сколько байт было скопировано из количества блоков, хотя я не уверен, что произойдет, если a 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

Предупреждение появляется, когда ddне удалось получить достаточно данных для заполнения блока за одно чтение. Это происходит с нестабильными или медленными источниками данных или источниками, которые записывают данные в меньших единицах, чем запрошенный вами размер блока.

Проблем с целостностью данных нет, но проблема в том, что 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Буферыявныйи так, для буферизации входных данныхсчитатьвхождения, которые вам нужно явно буферизировать. Вот и все. Не покупайтесь на эту чушь.

Связанный контент