¿Cómo se puede usar `dd` para desplazar a la derecha los bloques de datos?


10

Considere un dispositivo de bloque sin procesar de 100 MB como un ejemplo simple. Es decir, 204800 bloques de 512 bytes cada uno para un total de 102760448 bytes.

El desafío es cambiar los primeros 98 MB (bloques 200704) para que haya un espacio de 2 MB (4096 bloques) delante. Hacer esto en el lugar requiere que no se escriba nada en un sector que no se haya leído. Una forma de lograr esto es introducir un búfer:

$ dd if=/dev/sdj2 count=200704 | mbuffer -s 512 -b 4096 -P 100 | dd of=/dev/sdj2 seek=4096

La expectativa es que mbufferalmacenará 4096 bloques antes de pasar cualquier cosa al escritor, asegurando así que no se escriba nada en un área que no se haya leído y que el escritor retrase al lector por el tamaño del búfer. El búfer debe permitir que el lector y el escritor operen lo más rápido posible dentro de esos constriantes.

Sin embargo, no parece funcionar de manera confiable. Intenté usar dispositivos reales pero nunca funciona en ellos, mientras que los experimentos con un archivo funcionaron en mi caja de 64 bits pero no en mi caja de 32 bits.

Primero, algo de preparación:

$ dd if=/dev/sdj2 count=200704 | md5sum
0f0727f6644dac7a6ec60ea98ffc6da9
$ dd if=/dev/sdj2 count=200704 of=testfile

Esto no 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

Esto funciona en el sistema de 64 bits pero no en el 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

¿Cómo se puede hacer esto de manera confiable?


notas

He leído otras preguntas acerca de búfer y mirado pv, buffery mbuffer. Solo pude hacer que este último funcione con el tamaño de búfer requerido.

El uso del almacenamiento intermedio es una solución obvia para el problema que siempre funciona, pero no es práctico cuando no hay suficiente capacidad disponible.

Pruebe las plataformas que ejecutan Arch Linux con la mbufferversión 20140302.


Supongo que no resolvería el problema, pero por curiosidad, ¿por qué usarlo mbuffer? ¿Por qué no hacer ddleer todo el contenido del dispositivo de bloque de una vez dd bs=102760448? Por supuesto, de una forma u otra está almacenado en la RAM.
Celada

@Celada: el ejemplo de 100 MB fue solo un ejemplo. Leer 1TB, por ejemplo, de una vez no sería una buena idea.
Starfry

2
Ah, ahora entiendo, gracias. En mbufferrealidad, debería forzar al segundo dda retrasarse por el primero y solo necesita suficiente RAM para amortiguar el tamaño del turno. Lástima ddque no admite bloques de lectura y escritura en orden inverso ya que eso eliminaría el problema
Celada


@psusi, el segundo md5 es emitido por mbuffer (su -Hargumento habilita esta función).
Starfry

Respuestas:


2

Sin un búfer, podría ir hacia atrás, un bloque a la vez.

for i in $(seq 100 -1 0)
do
    dd if=/dev/thing of=/dev/thing \
       bs=1M skip=$i seek=$(($i+2)) count=1
done

Tenga en cuenta que este ejemplo es peligroso debido a la falta de comprobación de errores.

También es lento debido a la cantidad de ddllamadas. Si tiene memoria de sobra, podría usar un tamaño de bloque más grande.

Con un amortiguador, tenga cuidado con las trampas . Es no suficiente para garantizar un llenado previo del 100%. Lo que necesita es un llenado mínimo durante todo el proceso. El búfer nunca debe caer a continuación 2Mporque, de lo contrario, habrá sobrescrito sus datos aún por leer nuevamente.

Entonces, en teoría, podría prescindir de cualquier tipo de búfer y solo encadenar dd:

dd if=/dev/thing bs=1M | \
dd bs=1M iflag=fullblock | \
dd bs=1M iflag=fullblock | \
dd of=/dev/thing bs=1M seek=2

En la práctica, esto no funciona de manera confiable porque no hay garantía de que el primero ddlogre seguir leyendo datos, mientras que el último dd(con 2M"buffer" en el medio) ya está escribiendo.

Puede aumentar sus posibilidades considerablemente haciendo que el buffer intermedio sea considerablemente mayor, pero aun así, no es confiable.

Lamentablemente, no conozco un buen programa de búfer con propiedad de relleno mínimo. Necesita uno que detenga la salida siempre que haya menos de su margen de seguridad dentro del búfer.


Acepté esto porque responde a la pregunta original al demostrar cómo ddpodría usarse. Sin embargo, creo que la solución real es no usar, ddsino optar por algo diseñado para funcionar al revés ddrescue. Describí una forma de hacerlo en una respuesta.
Starfry

1
@starfry: claro, un programa que simplemente lo haga será una buena solución. Sin embargo, no estoy del todo seguro ddrescueaquí. No si espera trabajar en diferentes dispositivos, y tienes que engañarlo para que acepte tus argumentos. Es posible que tampoco tenga la propiedad de "relleno mínimo de búfer" internamente (ya que con diferentes dispositivos no es necesaria), por lo que nuevamente podría dañar sus datos. Tendría que verificar en el código fuente si realmente está diseñado para su caso de uso.
frostschutz

1

Está leyendo 4096 bloques y luego escribe esos 4096 bloques en los siguientes 4096 bloques del disco, sobrescribiendo así los segundos 4096 bloques antes de que puedan leerse. Debe leer 8129 bloques para obtener esos segundos 4096 antes de comenzar cualquier escritura, y luego solo necesita escribir 4096 bloques antes de leer los siguientes 4096.

No mencionaste qué tipo de sistema de archivos es este. Si es ext [234] y tiene una versión reciente de e2fsprogs, puede usarla e2image -ra -O 512 /dev/sdj2. Esto también tiene el beneficio adicional de ser lo suficientemente inteligente como para omitir el espacio libre en el volumen.


Eso tiene sentido al leerlo y voy a echar otro vistazo basado en eso. Pero no explica por qué funcionó en el archivo de prueba.
Starfry

Re el sistema de archivos, ¿te refieres al sistema de archivos que contiene mi archivo de prueba? Eso es, ext4pero para la copia del dispositivo de bloque, cualquier sistema de archivos debería ser irrelevante.
Starfry

@starfry, la única forma en que sé hacer esto de manera genérica es usar el algoritmo que Emmanuel sugirió (trabajar hacia atrás desde el final), que es lo que hace gparted.
psusi

En cuanto al tamaño del bloque, había intentado bloques más grandes (debería haberlo escrito en la pregunta). Descubrí que no era más confiable ni siquiera un búfer de sector de 64K. La solución confiable es correr hacia atrás, algo que ddno funciona.
Starfry

1

Una solución confiable requiere que se asegure de que nada escriba en un área que podría no haber sido leída y la única forma real de lograrlo es realizar la copia en una dirección inversa.

los ddrescue herramienta puede funcionar en una dirección inversa, pero se niega a ejecutarse con la entrada y la salida iguales. Sin embargo, es posible engañarlo duplicando el nodo del dispositivo.

He realizado algunos experimentos rápidos y parece funcionar. La línea de comando es:

$ ddrescue -f -R -s 200704s -o 4096s /dev/sdj11 /dev/sdj11_copy

Los argumentos son

  • -f se requiere para forzarlo a escribir en un dispositivo de salida existente
  • -R le dice que trabaje en una dirección inversa
  • -sle dice cuánto de la entrada copiar (utilicé el ssufijo para especificar el número de sectores)
  • -ole dice que busque hacia delante en el dispositivo de salida antes de escribir (especificado en sectores nuevamente con el ssufijo)
  • /dev/sdj11 es el dispositivo de bloque para leer
  • /dev/sdj11_copy es el dispositivo de bloque para escribir

Creé /dev/sdj11_copycon mknodpara que coincida con los parámetros de /dev/sdj11.

Solo he hecho algunas pruebas muy rápidas, pero parece funcionar bien para copiar un dispositivo sin formato. No funciona en un archivo (no podría engañarlo para que vaya más allá de que los archivos sean iguales)

Esto no responde a mi pregunta original que preguntaba cómo lograr esto, ddpero creo que, después de leer las otras respuestas, la respuesta es que ddno puede hacerlo.


¿Qué sucede si ddrescuedescubre un bloqueo malo en este escenario? Si salta a otra área del disco (para evitar bloques defectuosos) y continúa copiando desde allí, sobrescribirá nuevamente las partes aún no copiadas de sus datos. Si no espera trabajar con el mismo dispositivo, no tiene ninguna razón para tomar medidas especiales para prevenir varios posibles casos de corrupción de datos.
frostschutz

Estoy de acuerdo en que este es un problema potencial, pero no he analizado los casos límite, ya que pude usarlo para hacer lo que necesitaba. Hay ddrescueopciones para limitar sus intentos de recuperar datos incorrectos, pero no he considerado usarlos.
Starfry

El hecho de que se niegue a funcionar si la entrada y la salida son iguales es probablemente una buena indicación de que no es seguro.
psusi
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.