Crie dados aleatórios com dd e obtenha “aviso parcial de leitura”. Os dados após o aviso agora são realmente aleatórios?

17

Eu criei um arquivo de 1 TB com dados aleatórios com dd if=/dev/urandom of=file bs=1M count=1000000 . Agora eu verifico com kill -SIGUSR1 <PID> o progresso e obtenho o seguinte:

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

Não consigo interpretar o aviso. O que isso diz? Meu arquivo é realmente aleatório após o aviso ou há algum problema? O que significa +0 ou +1 em 800950+1 Datensätze ein e 800950+0 Datensätze aus ? Após o aviso, é +1. É uma contagem de erros?

    
por delete 27.03.2014 / 23:24

3 respostas

32

Resumo: dd é uma ferramenta irritada que é difícil de usar corretamente. Não o use, apesar dos inúmeros tutoriais que dizem isso. dd tem uma vibe de "unix street cred" ligada a ele - mas se você realmente entender o que está fazendo, saberá que não deve tocá-lo com um poste de 10 pés.

dd faz uma única chamada para a chamada de sistema read por bloco (definida pelo valor de bs ). Não há garantia de que a chamada do sistema read retorne tantos dados quanto o tamanho do buffer especificado. Isso tende a funcionar para arquivos regulares e dispositivos de bloco, mas não para pipes e alguns dispositivos de caracteres. Consulte Quando dd é adequado para copiar dados? (ou, quando são ler () e escrever () parcial) para mais informações. Se a chamada do sistema read retornar menos de um bloco inteiro, então dd transfere um bloqueio parcial. Ele ainda copia o número especificado de blocos, portanto, a quantidade total de bytes transferidos é menor que o solicitado.

O aviso sobre uma "leitura parcial" diz exatamente o seguinte: uma das leituras foi parcial, portanto dd transferiu um bloco incompleto. Na contagem de blocos, +1 significa que um bloco foi lido parcialmente; já que a contagem de saída é +0 , todos os blocos foram escritos como lidos.

Isso não afeta a aleatoriedade dos dados: todos os bytes que dd escrevem são bytes lidos de /dev/urandom . Mas você tem menos bytes do que o esperado.

O /dev/urandom do Linux acomoda solicitações grandes e arbitrárias (fonte: extract_entropy_user em drivers/char/random.c ), portanto dd é normalmente seguro ao ler a partir dele. No entanto, a leitura de grandes quantidades de dados leva tempo. Se o processo receber um sinal, a chamada do sistema read retorna antes de preencher seu buffer de saída. Esse é um comportamento normal e os aplicativos devem chamar read em um loop; dd não faz isso, por razões históricas (as origens de dd são obscuras, mas parece ter começado como uma ferramenta para acessar as fitas, que têm requisitos peculiares, e nunca foi adaptada para ser uma solução geral. ferramenta de finalidade). Quando você verifica o progresso, isso envia o processo dd a um sinal que interrompe a leitura. Você tem a opção de saber quantos bytes dd irá copiar no total (certifique-se de não interrompê-lo - nenhuma verificação de progresso, nenhuma suspensão) ou saber quantos bytes dd copiou até o momento. muitos bytes que serão copiados.

A versão de dd em GNU coreutils (conforme encontrado em Linux não embarcado e no Cygwin) tem um sinalizador fullblock que informa dd para chamar read em um loop (e idem para write ) e, portanto, sempre transfere blocos inteiros. A mensagem de erro sugere que você a use; você deve sempre usá-lo (em sinalizadores de entrada e saída), exceto em circunstâncias muito especiais (principalmente ao acessar fitas) - se você usa dd , isto é: geralmente há soluções melhores (veja abaixo).

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

Outra maneira possível de ter certeza do que dd fará é passar um tamanho de bloco igual a 1. Então você pode informar quantos bytes foram copiados da contagem de blocos, embora eu não tenha certeza do que acontecerá se um read é interrompido antes de ler o primeiro byte (o que não é muito provável na prática, mas pode acontecer). No entanto, mesmo que funcione, isso é muito lento.

O conselho geral sobre o uso de dd é não use dd . Embora dd seja frequentemente anunciado como um comando de baixo nível para acessar dispositivos, na verdade não existe: toda a mágica acontece no arquivo do dispositivo (a parte /dev/… ), dd é apenas uma ferramenta comum com um alto potencial para uso indevido, resultando em perda de dados. Na maioria dos casos, existe uma maneira mais simples e segura de fazer o que você quer, pelo menos no Linux.

Por exemplo, para ler um determinado número de bytes no início de um arquivo, basta chamar head :

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

Fiz uma referência rápida em minha máquina e não observei nenhuma diferença de desempenho entre dd com um tamanho de bloco grande e head .

Se você precisar pular alguns bytes no início, canalize tail em head :

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

Se você quiser ver o progresso, chame lsof para ver o deslocamento do arquivo. Isso só funciona em um arquivo normal (o arquivo de saída no seu exemplo), não em um dispositivo de caractere.

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

Você pode ligar para pv para obter um relatório de progresso (melhor que dd ), à custa de um item adicional no pipeline (em termos de desempenho, é quase imperceptível).

    
por 28.03.2014 / 02:53
7

O aviso ocorre quando dd não conseguiu obter dados suficientes para preencher um bloco em uma única leitura. Isso acontece com fontes de dados erradas ou lentas, ou fontes que gravam dados em unidades menores que o tamanho do bloco solicitado.

Não há problemas com a integridade dos dados, mas o problema é que dd conta uma leitura parcial como um bloco de leitura.

Se você não estiver usando a opção count , o aviso dificilmente é importante, é apenas uma consideração de desempenho. Mas com count , você não receberá a quantidade de dados solicitada. Devido a leituras parciais, of será menor que count*bs no final.

Então, quando você usa count , tecnicamente você deve sempre usar iflag=fullblock .

O +x deve ser o número de blocos parciais.

    
por 28.03.2014 / 00:06
-2
< /dev/urandom \
dd ibs=4k obs=64k |
dd bs=64k count=16000000 >file

^ Isso vai funcionar. A desinformação de outra forma é manifestamente falsa. Os buffers de dd são explícitos e, portanto, para armazenar em buffer as ocorrências de contagem que você precisa explicitamente armazenar em buffer. Isso é tudo. Não compre o fud.

    
por 13.01.2016 / 06:18

Tags