¿Por qué rsync no puede copiar archivos de / sys en Linux?

12

Tengo un script bash que usa rsyncpara hacer copias de seguridad de archivos en Archlinux. Noté que rsyncno se pudo copiar un archivo /sys, aunque cpfuncionó bien:

# rsync /sys/class/net/enp3s1/address /tmp    
rsync: read errors mapping "/sys/class/net/enp3s1/address": No data available (61)
rsync: read errors mapping "/sys/class/net/enp3s1/address": No data available (61)
ERROR: address failed verification -- update discarded.
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1052) [sender=3.0.9]

# cp  /sys/class/net/enp3s1/address /tmp   ## this works

Me pregunto por qué rsyncfalla y ¿es posible copiar el archivo con él?

Eugene Yarmash
fuente
44
¿Por qué quieres copiar /sys/?
frostschutz
1
@frostschutz Uso el comando en el OP para copiar la dirección MAC de una tarjeta de red (como un archivo)
Eugene Yarmash
@eugeney Entonces, ¿por qué no es suficiente hacer una copia de seguridad del archivo de configuración desde donde se establece la dirección MAC?
depquid
@eugeney ¿Es posible escribirle /sys/class/net/*/address(recibo un "permiso denegado" cuando lo intento)? De lo contrario, no está haciendo una copia de seguridad real / útil ya que no se puede restaurar.
depquid

Respuestas:

12

Rsync tiene un código que comprueba específicamente si un archivo se trunca durante la lectura y genera este error ENODATA. No sé por qué los archivos /systienen este comportamiento, pero como no son archivos reales, supongo que no es demasiado sorprendente. No parece haber una manera de decirle a rsync que omita esta verificación en particular.

Creo que probablemente sea mejor no sincronizar /sysy usar secuencias de comandos específicas para seleccionar la información particular que desea (como la dirección de la tarjeta de red).

mattdm
fuente
Pfft, ¿dónde está la diversión de no entender por qué falla rsync en particular?
Bratchley
Lo siento, no estaba claro. Rsync verifica específicamente los archivos truncados durante la lectura y arroja este error.
mattdm
44
Supongo que tienen este comportamiento porque hasta que realmente los lea, lo que está "allí" no es absolutamente seguro; la lectura es realmente una solicitud de información dinámica del núcleo. Por lo tanto, el kernel no intenta dar detalles precisos WRT al tamaño del archivo, etc., de antemano, y como usted señala, rsync toma esa discrepancia como una mala señal.
Ricitos de Oro
11

En primer lugar /syses un pseudo sistema de archivos . Si nos fijamos /proc/filesystems, encontrará una lista de sistemas de archivos registrados donde hay bastantes nodev por delante. Esto indica que son pseudo sistemas de archivos . Esto significa que existe en un núcleo en ejecución como un sistema de archivos basado en RAM. Además, no requieren un dispositivo de bloqueo.

$ cat /proc/filesystems
nodev   sysfs
nodev   rootfs
nodev   bdev
...

Al arrancar, el núcleo monta este sistema y actualiza las entradas cuando sea adecuado. Por ejemplo, cuando se encuentra nuevo hardware durante el arranque o por udev.

En /etc/mtabgeneral, encuentras el montaje por:

sysfs /sys sysfs rw,noexec,nosuid,nodev 0 0

Para un buen artículo sobre el tema, lea Patric Mochel's - El sistema de archivos sysfs .


stat de archivos / sys

Si va a un directorio debajo /sysy hace un ls -l, notará que todos los archivos tienen un tamaño. Típicamente 4096 bytes. Esto es informado por sysfs.

:/sys/devices/pci0000:00/0000:00:19.0/net/eth2$ ls -l
-r--r--r-- 1 root root 4096 Apr 24 20:09 addr_assign_type
-r--r--r-- 1 root root 4096 Apr 24 20:09 address
-r--r--r-- 1 root root 4096 Apr 24 20:09 addr_len
...

Además, puede hacer un staten un archivo y notar otra característica distinta; Ocupa 0 bloques. También el inodo de la raíz (stat / sys) es 1. /stat/fstípicamente tiene inodo 2. etc.

rsync vs. cp

La explicación más fácil para la falla rsync de sincronizar pseudo archivos es quizás por ejemplo.

Digamos que tenemos un archivo llamado addressque tiene 18 bytes. Una lso statdel archivo informa 4096 bytes.


rsync

  1. Abre el descriptor de archivo, fd.
  2. Utiliza fstat (fd) para obtener información como el tamaño.
  3. Establezca la lectura de bytes de tamaño, es decir, 4096. Esa sería la línea 253 del código vinculado por @mattdm .read_size == 4096
    1. Pedir; leer: 4096 bytes.
    2. Se lee una cadena corta, es decir, 18 bytes. nread == 18
    3. read_size = read_size - nread (4096 - 18 = 4078)
    4. Pedir; leer: 4078 bytes
    5. 0 bytes leídos (como la primera lectura consumió todos los bytes en el archivo).
    6. nread == 0, línea 255
    7. No se pueden leer los 4096bytes. Poner a cero el búfer.
    8. Set error ENODATA.
    9. Regreso.
  4. Informar error.
  5. Procesar de nuevo. (Por encima del bucle).
  6. Fallar.
  7. Informar error.
  8. MULTA.

Durante este proceso, en realidad lee todo el archivo. Pero sin tamaño disponible, no puede validar el resultado, por lo que el fracaso es la única opción.

cp

  1. Abre el descriptor de archivo, fd.
  2. Utiliza fstat (fd) para obtener información como st_size (también usa lstat y stat).
  3. Compruebe si es probable que el archivo sea escaso. Ese es el archivo tiene agujeros, etc.

    copy.c:1010
    /* Use a heuristic to determine whether SRC_NAME contains any sparse
     * blocks.  If the file has fewer blocks than would normally be
     * needed for a file of its size, then at least one of the blocks in
     * the file is a hole.  */
    sparse_src = is_probably_sparse (&src_open_sb);
    

    Como el statarchivo de informes tiene cero bloques, se clasifica como escaso.

  4. Intenta leer el archivo mediante la extensión-copia (una forma más eficiente de copiar archivos dispersos normales ), y falla.

  5. Copia por copia dispersa.
    1. Comienza con el tamaño máximo de lectura de MAXINT.
      Típicamente 18446744073709551615bytes en un sistema de 32 bits.
    2. Pedir; leer 4096 bytes. (Tamaño del búfer asignado en la memoria de la información estadística).
    3. Se lee una cadena corta, es decir, 18 bytes.
    4. Compruebe si se necesita un agujero, no.
    5. Escribir buffer al objetivo.
    6. Resta 18 del tamaño máximo de lectura.
    7. Pedir; leer 4096 bytes.
    8. 0 bytes ya que todo se consumió en la primera lectura.
    9. Devuelve el éxito.
  6. Todo bien. Actualizar banderas para el archivo.
  7. MULTA.
Runium
fuente
2

Puede estar relacionado, pero las llamadas de atributos extendidos fallarán en sysfs:

[root @ hypervisor eth0] # dirección lsattr

lsattr: ioctl inapropiado para dispositivo mientras lee banderas en la dirección

[root @ hypervisor eth0] #

Mirando mi strace parece que rsync intenta extraer atributos extendidos por defecto:

22964 <... getxattr resume>, 0x7fff42845110, 132) = -1 ENODATA (sin datos disponibles)

He intentado encontrar una bandera para dar rsync para ver si saltarse los atributos extendidos resuelve el problema, pero no era capaz de encontrar cualquier cosa ( --xattrslos vuelve sobre el destino).

Bratchley
fuente
0

Rsync normalmente lee la información del archivo, transfiere el contenido del archivo o delta a un archivo temporal en el directorio de destino, luego, después de verificar los datos del archivo, lo renombra al nombre del archivo de destino.

Creo que el problema con sysfs es que todos los archivos se muestran como 4k (una página de memoria) pero pueden contener solo unos pocos bytes. Para evitar copiar un archivo potencialmente dañado en el destino, rsync cancela la copia cuando ve una discrepancia entre los metadatos del archivo y lo que se copió realmente.

Al menos en rsync v3.0.6, este comportamiento se puede evitar con el modificador --inplace. Rsync aún detectará errores, pero dado que los archivos de destino ya se habrán sobrescrito cuando lo haga, dejará allí los archivos potencialmente corruptos.

Sin embargo, tenga en cuenta que un efecto secundario es que los archivos terminan con relleno de cero a 4k, ya que este es el tamaño que rsync cree que son los archivos. No debería hacer una diferencia en la mayoría de los casos, ya que los bytes nulos generalmente se ignoran.

Thomas Guyot-Sionnest
fuente