2 puntos por GN⁺ 2024-03-13 | 1 comentarios | Compartir por WhatsApp
  • En lugar de volver a configurar una laptop nueva desde cero, se expuso el disco completo de la laptop existente mediante NVMe sobre TCP para clonarlo tal cual por la red
  • El entorno original usaba cifrado de disco completo y un disco de 512 GB, mientras que la laptop nueva tenía un NVMe de 1 TB, por lo que después de la clonación fue necesario ampliar la partición, LUKS y BTRFS
  • En vez de usar systemd-storagetm.service para exportar el disco, se arrancaron ambas laptops con GRML rescue CD y se configuró con nvmet-tcp y /sys/kernel/config/nvmet
  • La copia real se hizo con dd y, como la laptop nueva no tenía puerto Ethernet, solo se usó Wi‑Fi; clonar 512 GB tomó unas 7 horas y 30 minutos, con una velocidad de aproximadamente 18–20 MB/s
  • Después de la clonación, se ajustó para usar el TB completo con parted, growpart, cryptsetup resize y el redimensionado de BTRFS, lo que permitió seguir usando casi intacto el entorno de la laptop anterior

Exportar el disco existente mediante NVMe sobre TCP

  • Para no repetir el proceso de configuración de la laptop nueva, se optó por copiar el disco completo de la laptop existente, siguiendo la sugerencia de un colega

  • Antes de empezar había dos obstáculos

    • No había herramientas para abrir la laptop original y conectar el nuevo disco por USB
    • La laptop original usaba cifrado de disco completo y un disco de 512 GB, mientras que la nueva tenía un NVMe de 1 TB, así que era necesario redimensionar LUKS
  • El flujo de trabajo se dividió en tres etapas: exponer el disco, copiarlo y ampliar la capacidad

    • Exportar el disco desde la laptop original con nvmet-tcp
    • Copiar ese disco desde la laptop nueva
    • Ampliar la partición para ocupar el TB completo
    • Redimensionar LUKS
    • Por último, redimensionar el disco raíz BTRFS
  • Usar GRML en lugar de systemd-storagetm.service

    • La forma más sencilla habría sido usar systemd-storagetm.service
    • Se puede invocar arrancando en storage-target-mode.target con rd.systemd.unit=storage-target-mode.target
    • Sin embargo, este método requería incluir servicios de red en la imagen initrd de dracut y, además, configurar Wi‑Fi en ese modo era engorroso, por lo que se descartó
    • En su lugar, se arrancaron ambas laptops con GRML rescue CD y luego se exportó el disco NVMe desde la laptop original usando el módulo nvmet-tcp de Linux
    modprobe nvmet-tcp
    cd /sys/kernel/config/nvmet
    mkdir ports/0
    cd ports/0
    echo "ipv4" > addr_adrfam
    echo 0.0.0.0 > addr_traaddr
    echo 4420 > addr_trsvcid
    echo tcp > addr_trtype
    cd /sys/kernel/config/nvmet/subsystems
    mkdir testnqn
    echo 1 >testnqn/allow_any_host
    mkdir testnqn/namespaces/1
    cd testnqn
    
    
    # replace the device name with the disk you want to export
    echo "/dev/nvme0n1" > namespaces/1/device_path
    echo 1 > namespaces/1/enable
    ln -s "../../subsystems/testnqn" /sys/kernel/config/nvmet/ports/0/subsystems/testnqn
    
    • Con esta configuración, el dispositivo de destino quedó expuesto mediante NVMe sobre TCP
    • Desde la laptop nueva, se descubre el dispositivo exportado y se establece la conexión
    nvme discover -t tcp -a <ip> -s 4420
    nvme connectl-all -t tcp -a <> -s 4420
    
    • Después, se puede verificar el dispositivo conectado en la laptop nueva con nvme list y proceder con la copia del disco

Copia del disco y redimensionado

  • Copiar 512 GB con dd

    • La copia del disco raíz se realizó con el comando dd
    • Como la laptop nueva no tenía puerto Ethernet y solo usó Wi‑Fi, copiar los 512 GB completos tomó unas 7 horas y 30 minutos
    • La velocidad de transferencia fue de aproximadamente 18–20 MB/s
    • Otras opciones habrían sido crear primero las particiones y el sistema de archivos, luego copiar el disco raíz con rsync, o usar la transferencia propia del sistema de archivos BTRFS
    dd if=/dev/nvme2n1 of=/dev/nvme0n1 status=progress bs=40M
    
  • Ampliar partición, LUKS y BTRFS

    • parted detectó que la tabla de particiones no coincidía con el tamaño del disco y, tras pedir confirmación, la corrigió automáticamente
    • Para ampliar la segunda partición, se instaló cloud-guest-utils y se usó growpart
    growpart /dev/nvem0n1 p2
    
    • En el siguiente paso, se amplió el tamaño del contenedor LUKS con cryptsetup
    cryptsetup luksOpen /dev/nvme0n1p2 ENC
    cryptsetup resize ENC
    
    • Después se reinició desde el disco, se comprobó que todo funcionara correctamente y, tras iniciar sesión, se ajustó el tamaño del sistema de archivos BTRFS
    • Para redimensionar BTRFS, el sistema tenía que estar montado, así que no podía intentarse desde un arranque en vivo
    btfs fielsystem resize max /
    
    • Como resultado, en la laptop nueva se obtuvo prácticamente el mismo entorno que en la anterior
    • Normalmente, adaptarse por completo a una laptop nueva toma entre 1 y 2 semanas, pero este método redujo ese tiempo
    • Como beneficio adicional, también quedó aprendido el método para exportar un disco mediante NVMe sobre TCP

1 comentarios

 
GN⁺ 2024-03-13
Comentarios de Hacker News
  • En el escenario del autor, al final solo se hace una copia serial de bloques con dd(1), así que casi no hay ventaja en usar NVMe/TCP. Los comandos complejos se pueden reemplazar por un simple netcat
    Laptop de destino: $ nc -l -p 1234 | dd of=/dev/nvme0nX bs=1M
    Laptop de origen: $ nc x.x.x.x 1234
    El dd del lado de destino sirve para hacer buffering de la escritura y así volverla más rápida y eficiente. Si agregas gzip/gunzip en origen/destino, puede ser mucho más rápido cuando el disco no está lleno y hay muchos bloques en 0. Personalmente, es mi forma favorita de sacar una imagen de una PC por red y la he usado muchas veces
    En GigE, la compresión suele ser el cuello de botella, así que conviene pasar --fast a gzip, o mejor aún usar lz4/unlz4 en lugar de gzip/gunzip, porque es más rápido. Hace tiempo generé la imagen de una laptop nueva con Windows y un NVMe de 1TB por GigE, tardó unos 20 minutos, y como el espacio vacío se comprimió casi a 0, la imagen resultante ocupó 20GB. Normalmente guardo esa imagen lz4 como respaldo y años después, cuando dono la laptop, la restauro con unlz4 | dd, lo cual resulta muy práctico
    Dicho eso, no conocía el módulo del kernel de Linux nvme-tcp; todos los días se aprende algo nuevo. Esto parece más útil para montar un sistema de archivos sobre un NVMe remoto que para acceso crudo con dd
    Además, el tamaño máximo del búfer de pipe en Linux es 64 kB, así que técnicamente el argumento dd bs=X no necesita ser mayor que eso. Aun así, bs=1M no hace daño, agrupa lecturas de 64 kB hasta llegar a 1 MB y además queda preparado por si más adelante el tamaño del pipe aumenta. Algunas versiones de netcat tienen opciones de tamaño de bloque de entrada/salida, por lo que dd bs=X no haría falta, pero el netcat de un disco de rescate normalmente no trae esas opciones

    • El búfer de pipe de Linux se puede aumentar, y entiendo que el valor máximo predeterminado suele ser de alrededor de 1MB. Es un poco engorroso hacerlo desde la línea de comandos, pero aquí hay un ejemplo de implementación: https://unix.stackexchange.com/a/328364
    • Es un poco más desprolijo, pero si usas pv en ambos lados en vez de dd, no tienes que preocuparte por indicar un tamaño de bloque adecuado y además obtienes una bonita barra de progreso
    • Hace unos 9 años fui como consultor a una empresa que había sufrido un hackeo interno, donde un cofundador resentido había dejado algo así como un dead man's switch: copiaba los primeros 20MB de todos los discos a algún bucket y luego los sobrescribía con ceros. Para recuperar los datos hubo que reconstruir las tablas de particiones con testdisk, pero antes de eso no quería tocar los discos dañados, así que copiamos unos 40TB usando un disco flash de rescate, netcat y unidades
      Algunos servidores tenían todos los slots físicos de RAID ocupados, así que ni siquiera se podían usar bahías de disco libres, y usamos algo como dd if=/dev/sdc bs=xxx | gzip | nc -l -p 8888 con el comando inverso del otro lado. Sorprendentemente funcionó bien. Algo a tener en cuenta es probar combinaciones de dd bs alineadas con el tamaño de sector, porque el tamaño adecuado tenía un impacto grande en el rendimiento de dd
    • Este uso de dd puede causar corrupción. Para evitar que se corten bloques hace falta iflag=fullblock, y aunque puede ser una costumbre ciega, conv=sync tampoco hace daño. Yo personalmente prefiero simplemente nc -l -p 1234 > /dev/nvme0nX
    • Para la mayoría, la red local probablemente no será más rápida que la velocidad de transferencia del SSD. Aun así, me pregunto si existe alguna herramienta de clonación de dispositivos de bloques con E/S simultánea para quienes sí tengan ese entorno
      Si metes pv en el pipeline puedes ver el tiempo estimado de finalización, aunque puede afectar un poco el rendimiento
  • Gracias a AWS/Annapurna/Nitro/Lightbits por llevar NVMe-over-TCP a Linux
    https://www.techtarget.com/searchstorage/news/252459311/Ligh...
    “El consorcio NVM Express ratificó NVMe/TCP como capa de transporte vinculante en noviembre de 2018. El estándar evolucionó a partir de una base de código que el equipo de ingeniería de Lightbits presentó originalmente a NVM Express.”
    https://www.lightbitslabs.com/blog/linux-distributions-nvme-...
    https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/lin...

  • Esto se ve bastante más engorroso que: nbdkit file /dev/nvme0n1, nbdcopy nbd://otherlaptop localfile

    • En realidad este método es mucho mejor: nbdcopy puede manejar archivos dispersos, ajustar el número de conexiones e hilos al número de núcleos, forzar un flush antes de terminar y también activar una barra de progreso. Si la unidad no está cifrada, incluso soporta TLS
  • Hace poco tuve que instalar xubuntu en una laptop nueva. Antes la había clonado, pero esta vez quería reorganizar algunas configuraciones desde cero
    Hacer la transferencia a 10 Gb/s con un cable USB-C fue realmente útil, porque la única otra opción era WiFi
    Si conectas las computadoras entre sí, se forma una red temporal y puedes pasar todo simplemente con rsync. A simple vista, el enlace ya estaba saturado, así que no parecía tener mucho sentido usar otro protocolo. Claro, aprender algo nuevo está bien, pero quizá no justo en el momento de clonar una laptop

    • Me da curiosidad si simplemente funcionó de inmediato. La última vez que intenté una conexión directa que no fuera Ethernet fue en los 90, así que lo pregunto en serio
    • Yo también lo hice, pero para que funcionara la red tuve que comprar un cable Thunderbolt 4 de más de 30 dólares. Un cable USB3-C común no fue suficiente
      La transferencia en sí fue rapidísima: moví 1 TB en solo unos minutos. Esta vez no usé cifrado, así que fue mucho más simple
    • Me pregunto si arrancaste desde un disco live y moviste todo el sistema de archivos, o si instalaste primero el sistema base y luego solo copiaste los archivos
  • No entiendo por qué no hiciste un pipe de btrfs por la red. Primero haces un snapshot de btrfs y luego btrfs send => nc => network => nc => btrfs receive, así solo se transfieren los bloques realmente en uso

    • En cuanto vi que usaba btrfs, pensé exactamente lo mismo. Yo uso btrfs send/receive por SSH todo el tiempo y funciona muy bien. Incluso habría sido fácil levantar un servidor SSH desde una sesión live de GRML
      Eso sí, hay una advertencia: en btrfs no se pueden enviar snapshots de forma recursiva, así que si tienes muchos snapshots recursivos, reflejar la misma estructura en el disco nuevo es relativamente difícil. Eso puede pasar con Docker/LXD/Incus. Me gusta btrfs, pero send/receive recursivo es un punto en el que ZFS está mejor
  • Hace poco tuve que copiar unos 200 GB de archivos por WiFi. Usé rsync para no tener que empezar de cero si fallaba la conexión y para evitar pérdidas, pero tardó al menos 6 horas. Me pregunto si había una mejor forma
    Y también me pregunto qué garantías da el método con dd. ¿Hay que comparar el md5 del dispositivo de bloques resultante?

    • 6 horas para mover 200 GB por WiFi no es un rendimiento muy impresionante para una transferencia local. Probablemente deberías haber usado un cable Ethernet
      WiFi tiene muchas más posibles fuentes de cuello de botella. Incluso conectar por cable solo uno de los equipos al router y dejar el otro inalámbrico puede ayudar bastante
    • Si eran muchísimos archivos pequeños, es muy posible que el cuello de botella haya sido que rsync transfiere un solo archivo a la vez. Puedes dividir la lista de archivos y ejecutar varias instancias de rsync con xargs/parallel, o usar algo como rclone, que sí soporta transferencia en paralelo
    • 6 horas son más o menos 10 MB/s, así que probablemente se podía hacer bastante más rápido. Me pregunto si usaste -z para compresión. Si hubieras podido usar Ethernet, en la mayoría de los dispositivos habrías estado cerca de 100 MB/s, o sea unos 35 minutos
    • Si rsync estaba transfiriendo por SSH, muchas veces ese es el cuello de botella. OpenSSH históricamente tuvo limitaciones de rendimiento un poco extrañas, y hubo épocas en que se necesitaban parches poco conocidos para esquivarlas. Si la CPU no es el cuello de botella, activar la compresión también puede ayudar
    • WiFi comparte el aire como medio con todos los demás dispositivos inalámbricos. Si detecta una colisión, se detiene y luego espera una cantidad aleatoria de tiempo
      “En redes de computadoras, el acceso múltiple por detección de portadora con evitación de colisiones (CSMA/CA) es un método de acceso múltiple a redes que usa detección de portadora, pero intenta evitar colisiones iniciando la transmisión solo después de detectar que el canal está ‘libre’. Al transmitir, un nodo envía todos los datos del paquete completos
      Esto es particularmente importante en redes inalámbricas, donde no se puede usar el método de detección de colisiones CSMA/CD porque el transmisor inalámbrico desensibiliza o apaga su receptor durante la transmisión del paquete
      CSMA/CA tiene poca confiabilidad debido al problema del nodo oculto
      CSMA/CA es un protocolo que opera en la capa de enlace de datos.”
      https://en.wikipedia.org/wiki/Carrier-sense_multiple_access_...
  • Este enfoque tendrá sus ventajas, pero en el pasado, cuando migré una laptop, ejecuté el instalador en ambos lados y combiné dd con nc. Si no recuerdo mal, también le agregué gzip para transferir más rápido las grandes zonas nulas
    Si la laptop nueva no tenía puerto Ethernet, mi método medio hacky quizá hasta habría sido un poco más rápido gracias a la compresión, ya que no estaría ni cerca del límite adicional que impone la compresión en un enlace de red rápido

    • Si el disco estaba con cifrado completo, entonces, a menos que le hayas indicado a LUKS que permitiera el paso de TRIM, con el método que describió el autor en la práctica solo obtendrías datos aleatorios
  • ¿No bastaría con usar Clonezilla? Copia solo los bloques de datos reales y también puede redimensionar particiones automáticamente. Yo siempre lo hago así
    Aunque normalmente saco el disco NVMe de la laptop y lo conecto a un dock rápido

    • Clonezilla es excelente. Hace una sola cosa y normalmente sale bien al primer intento. Mi única queja es que, por la curva de aprendizaje inicial, hay que andar probando varias cosas
      Todavía no es algo en lo que confiaría ciegamente y dejaría corriendo sin más. Un backup no es lo mismo que la combinación de backup y restauración, así que conviene hacer pruebas. Clonezilla también puede tener problemas al recrear particiones en un disco muy distinto del original
  • Hace décadas que no “instalo” realmente un sistema operativo en una desktop o laptop; siempre copio los archivos y luego ajusto solo lo necesario. Normalmente aprovecho la oportunidad para crear un sistema de archivos nuevo y actualizar parámetros como el tipo de filesystem, el tamaño de bloque, el cifrado, etc., y después muevo los archivos con rsync
    Aun así, si eres de los que planifican con anticipación, un enfoque más declarativo como NixOS, donde copias solo la configuración y reinstalas automáticamente lo demás, probablemente sea mejor

  • Conectar los dispositivos directamente por WiFi, sin un AP intermedio, probablemente habría permitido duplicar la velocidad de transferencia. En esta situación quizá habría valido la pena intentarlo