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

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

Eu crio um arquivo de 1 TB com dados aleatórios com extensão dd if=/dev/urandom of=file bs=1M count=1000000. Agora verifico 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 eine 800950+0 Datensätze aus? Após o aviso é +1. É uma contagem de erros?

Responder1

Resumo: ddé uma ferramenta complicada e difícil de usar corretamente. Não o use, apesar dos inúmeros tutoriais que dizem isso. ddtem uma vibração de “credibilidade de rua unix” associada a ele - mas se você realmente entende o que está fazendo, saberá que não deveria tocá-lo com uma vara de 3 metros.

ddfaz uma única chamada para a readchamada do sistema por bloco (definido pelo valor de bs). Não há garantia de que a readchamada do sistema 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. VerQuando o dd é adequado para copiar dados? (ou, quando read() e write() são parciais)Para maiores informações. Se a readchamada do sistema retornar menos de um bloco completo, ddtransfere um bloco parcial. Ele ainda copia o número especificado de blocos, portanto a quantidade total de bytes transferidos é menor que a solicitada.

O aviso sobre uma “leitura parcial” diz exatamente isso: uma das leituras foi parcial, então ddtransferiu um bloco incompleto. Nas contagens de blocos, +1significa que um bloco foi lido parcialmente; como a contagem de saída é +0, todos os blocos foram escritos como lidos.

Isso não afeta a aleatoriedade dos dados: todos os bytes gravados ddsão bytes lidos /dev/urandom. Mas você obteve menos bytes do que o esperado.

O Linux /dev/urandomacomoda grandes solicitações arbitrárias (fonte:extract_entropy_userin drivers/char/random.c), então ddnormalmente é seguro ao ler a partir dele. No entanto, a leitura de grandes quantidades de dados leva tempo. Se o processo receber um sinal, a readchamada do sistema retornará antes de preencher seu buffer de saída. Este é um comportamento normal e os aplicativos devem chamar readem loop; ddnão faz isso, por razões históricas ( ddas origens de são obscuras, mas parece ter começado como uma ferramenta de acesso a fitas, que possuem requisitos peculiares, e nunca foi adaptada para ser uma ferramenta de uso geral). Ao verificar o andamento, isso envia ao ddprocesso um sinal que interrompe a leitura. Você pode escolher entre saber quantos bytes ddserão copiados no total (certifique-se de não interrompê-lo - sem verificação de progresso, sem suspensão) ou saber quantos bytes ddforam copiados até agora; nesse caso, você não pode saber quantos mais bytes que ele copiará.

A versão deddem GNU coreutils(como encontrado no Linux não embarcado e no Cygwin) possui um sinalizador fullblockque informa ddpara chamar readum loop (e o mesmo para write) e, portanto, sempre transferir blocos completos. A mensagem de erro sugere que você o use; você deve sempre usá-lo (tanto nos sinalizadores de entrada quanto de saída), exceto em circunstâncias muito especiais (principalmente ao acessar fitas) — ddisto é, se você usar: geralmente há soluções melhores (veja abaixo).

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

Outra maneira possível de ter certeza do que ddacontecerá é passar um tamanho de bloco 1. Então você pode saber quantos bytes foram copiados da contagem de blocos, embora eu não tenha certeza do que acontecerá se a readfor 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, é muito lento.

O conselho geral sobre o uso ddénão usedd. Embora ddseja frequentemente anunciado como um comando de baixo nível para acessar dispositivos, na verdade não é tal coisa: toda a mágica acontece na parte do arquivo do dispositivo (a /dev/…parte ), ddé apenas uma ferramenta comum com alto potencial de uso indevido, resultando em perda de dados . Na maioria dos casos, existe uma maneira mais simples e segura de fazer o que você deseja, 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 um benchmark rápido em minha máquina e não observei nenhuma diferença de desempenho entre ddblocos grandes e head.

Se você precisar pular alguns bytes no início, canalize tailpara 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, ligue lsofpara ver o deslocamento do arquivo. Isso funciona apenas 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 ligarpvpara obter um relatório de progresso (melhor que ddo do), às custas de um item adicional no pipeline (em termos de desempenho, é quase imperceptível).

Responder2

O aviso ocorre quando ddnão foi possível obter dados suficientes para preencher um bloco em uma única leitura. Isso acontece com fontes de dados erráticas ou lentas, ou fontes que gravam dados em unidades menores que o tamanho de bloco solicitado.

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

Se você não estiver usando a countopção, o aviso pouco importa, é apenas uma consideração de desempenho. Mas com countvocê não obterá a quantidade de dados solicitada. Devido a leituras parciais, ofserá menor que count*bsno final.

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

Deve +xser o número de blocos parciais.

Responder3

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

^ Isso simplesmente funcionará. A desinformação aqui apresentada é manifestamente falsa. ddOs buffers de sãoexplícitoe assim, para armazenar em buffer a entrada paracontarocorrências que você precisa armazenar explicitamente em buffer. Isso é tudo. Não compre o fud.

informação relacionada