Considere um dispositivo de bloco bruto de 100 MB como um exemplo simples. Ou seja, 204800 blocos de 512 bytes cada para um total de 102760448 bytes.
O desafio é mudar os primeiros 98 MB (200704 blocos) para que haja uma diferença de 2 MB (4096 blocos) à sua frente. Fazer isso no local requer que nada seja gravado em um setor que não foi lido. Uma maneira de conseguir isso é introduzir um buffer:
$ dd if=/dev/sdj2 count=200704 | mbuffer -s 512 -b 4096 -P 100 | dd of=/dev/sdj2 seek=4096
A expectativa é que mbuffer
ele armazene 4096 blocos antes de passar qualquer coisa para o gravador, garantindo assim que nada seja gravado em uma área que não tenha sido lida e que o gravador fique atrasado no tamanho do buffer. O buffer deve permitir que o leitor e o gravador operem o mais rápido possível dentro desses constrangimentos.
No entanto, parece não funcionar de maneira confiável. Eu tentei usar dispositivos reais, mas nunca funciona neles, enquanto as experiências com um arquivo funcionavam na minha caixa de 64 bits, mas não na minha caixa de 32 bits.
Primeiro, alguma preparação:
$ dd if=/dev/sdj2 count=200704 | md5sum
0f0727f6644dac7a6ec60ea98ffc6da9
$ dd if=/dev/sdj2 count=200704 of=testfile
Isso não funciona:
$ dd if=/dev/sdj2 count=200704 | mbuffer -s 512 -b 4096 -P 100 -H | dd of=/dev/sdj2 seek=4096
summary: 98.0 MiByte in 4.4sec - average of 22.0 MiB/s
md5 hash: 3cbf1ca59a250d19573285458e320ade
Isso funciona no sistema de 64 bits, mas não no sistema de 32 bits:
$ dd if=testfile count=200704 | mbuffer -s 512 -b 4096 -P 100 -H | dd of=testfile seek=4096 conv=notrunc
summary: 98.0 MiByte in 0.9sec - average of 111 MiB/s
md5 hash: 0f0727f6644dac7a6ec60ea98ffc6da9
Como isso pode ser feito de maneira confiável?
notas
Eu li outras perguntas sobre buffering e olhei pv
, buffer
e mbuffer
. Só consegui que o último funcionasse com o tamanho de buffer necessário.
Usar o armazenamento intermediário é uma solução óbvia para o problema que sempre funciona, mas não é prático quando não há capacidade disponível suficiente disponível.
Plataformas de teste executando o Arch Linux com a mbuffer
versão 20140302.
fonte
mbuffer
? Por que não fazer add
leitura de todo o conteúdo do dispositivo de bloco de uma só vezdd bs=102760448
? Obviamente, de uma forma ou de outra, é armazenado em buffer na RAM.mbuffer
fato deve forçar o segundodd
a ficar para trás em primeiro lugar e você só precisa de RAM suficiente para armazenar em buffer o tamanho do turno. Penadd
que não suporta blocos de leitura e gravação em ordem inversa, pois isso eliminaria o problema!-H
argumento ativa esse recurso).Respostas:
Sem um buffer, você poderia voltar atrás, um bloco de cada vez.
Observe que este exemplo é perigoso devido à falta de verificação de erros.
Também é lento devido à quantidade de
dd
chamadas. Se você tiver memória de sobra, poderá usar um tamanho de bloco maior.Com um buffer, cuidado com as armadilhas . É não suficiente para garantir uma Prefill 100%. O que você precisa é de um preenchimento mínimo durante todo o processo. O buffer nunca deve cair abaixo,
2M
pois, caso contrário, você substituirá os dados ainda a serem lidos novamente.Portanto, enquanto na teoria você poderia fazer sem qualquer tipo de buffer e apenas encadear
dd
:Na prática, isso não funciona de maneira confiável, porque não há garantia de que o primeiro
dd
consiga continuar lendo os dados, enquanto o últimodd
(com2M
"buffer" no meio) já está gravando.Você pode aumentar suas chances consideravelmente, tornando o buffer intermediário consideravelmente maior, mas, mesmo assim, não é confiável.
Infelizmente, não conheço um bom programa de buffer com propriedade mínima de preenchimento. Você precisa de um que interrompa a saída desde que haja menos do que sua margem de segurança no buffer.
fonte
dd
poderia ser usado. Penso, no entanto, que a solução real não é usar,dd
mas sim optar por algo que é projetado para rodar para trásddrescue
. Eu descrevi uma maneira de fazer isso em uma resposta.ddrescue
aqui. Não, se espera trabalhar em diferentes dispositivos, e você deve enganá-lo para aceitar seus argumentos. Também pode não ter a propriedade "mínimo de preenchimento do buffer" internamente (já que em dispositivos diferentes não é necessário), portanto, novamente, pode corromper seus dados. Você precisaria verificar o código-fonte se ele foi realmente projetado para o seu caso de uso.Você está lendo 4096 blocos e, em seguida, gravando esses 4096 blocos nos próximos 4096 blocos do disco, substituindo, assim, os segundos 4096 blocos antes que possam ser lidos. Você precisa ler 8129 blocos para obter esses segundos 4096 antes de iniciar qualquer gravação e, em seguida, só precisa escrever 4096 blocos antes de ler os próximos 4096.
Você não mencionou que tipo de sistema de arquivos é esse. Se for ext [234] e você tiver uma versão recente do e2fsprogs, poderá usar
e2image -ra -O 512 /dev/sdj2
. Isso também tem o benefício adicional de ser inteligente o suficiente para pular o espaço livre no volume.fonte
ext4
mas para a cópia dispositivo de bloco, qualquer sistema de arquivos deve ser irrelevante.dd
não funciona.Uma solução confiável exige que você garanta que nada seja gravado em uma área que pode não ter sido lida e a única maneira real de conseguir isso é executar a cópia na direção inversa.
A
ddrescue
ferramenta pode trabalhar na direção inversa, mas se recusa a executar com a entrada e a saída iguais. No entanto, é possível enganá-lo duplicando o nó do dispositivo.Realizei algumas experiências rápidas e parece funcionar. A linha de comando é:
Os argumentos são
-f
é necessário para forçá-lo a gravar em um dispositivo de saída existente-R
diz para ele trabalhar na direção inversa-s
informa quanto da entrada a copiar (usei os
sufixo para especificar o número de setores)-o
diz para procurar no dispositivo de saída antes de escrever (especificado em setores novamente com os
sufixo)/dev/sdj11
é o dispositivo de bloco para ler/dev/sdj11_copy
é o dispositivo de bloco para escreverEu criei
/dev/sdj11_copy
commknod
para combinar com os parâmetros de/dev/sdj11
.Eu fiz apenas alguns testes muito rápidos, mas isso parece funcionar bem para copiar um dispositivo bruto. Ele não funciona em um arquivo (eu não poderia induzi-lo a ir além dos arquivos iguais)
Isso não responde à minha pergunta original, que perguntou como conseguir isso,
dd
mas acho que, depois de ler as outras respostas, a resposta é quedd
não é possível.fonte
ddrescue
descobrir um bloco defeituoso nesse cenário? Se ele pular para outra área do disco (para evitar blocos defeituosos) e continuar copiando a partir daí, substituirá novamente partes ainda não copiadas dos seus dados. Se ele não espera trabalhar com o mesmo dispositivo, não há motivos para tomar medidas especiais para evitar vários possíveis casos de corrupção de dados.ddrescue
opções para limitar suas tentativas de recuperar dados incorretos, mas não tentei usá-los.