Por que o rsync falha ao copiar arquivos de / sys no Linux?

12

Eu tenho um script bash que usa rsyncpara fazer backup de arquivos no Archlinux. Notei que rsyncnão conseguiu copiar um arquivo /sys, enquanto cpfuncionava bem:

# 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

Eu me pergunto por que rsyncfalha, e é possível copiar o arquivo com ele?

Eugene Yarmash
fonte
4
Por que você quer copiar /sys/?
Frostschutz
1
@frostschutz eu uso o comando no OP para copiar o endereço MAC de uma placa de rede (como um arquivo)
Eugene Yarmash
@eugeney Então, por que não é suficiente fazer backup do arquivo de configuração de onde o endereço MAC está definido?
depquid
@eugeney É possível escrever para /sys/class/net/*/address(recebo "permissão negada" quando o tento)? Caso contrário, você não está fazendo um backup real / útil, pois não pode ser restaurado.
depquid

Respostas:

12

O Rsync possui um código que verifica especificamente se um arquivo está truncado durante a leitura e gera esse erro - ENODATA. Não sei por que os arquivos /systêm esse comportamento, mas como não são arquivos reais, acho que não é tão surpreendente. Não parece haver uma maneira de dizer ao rsync para ignorar essa verificação específica.

Acho que é melhor você não sincronizar /syse usar scripts específicos para escolher as informações específicas que você deseja (como o endereço da placa de rede).

mattdm
fonte
Pfft, onde está a graça de não descobrir por que o rsync em particular falha?
Bratchley
Desculpe, eu não estava claro. O Rsync verifica especificamente arquivos truncados durante a leitura e gera esse erro.
mattdm
4
Eu presumo que eles tenham esse comportamento, porque até você realmente lê-los, o que está "lá" não é absolutamente certo; a leitura é realmente um pedido de informações dinâmicas do kernel. Portanto, o kernel não tenta fornecer detalhes precisos do WRT para o tamanho do arquivo, etc, com antecedência e, como você ressalta, o rsync aceita uma discrepância como um sinal ruim.
Goldilocks
11

Primeiro, /sysé um sistema de pseudo arquivos . Se você olhar /proc/filesystems, encontrará uma lista de sistemas de arquivos registrados, onde muitos têm nodev pela frente. Isso indica que eles são pseudo sistemas de arquivos . Isso significa que eles existem em um kernel em execução como um sistema de arquivos baseado em RAM. Além disso, eles não precisam de um dispositivo de bloco.

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

Na inicialização, o kernel monta esse sistema e atualiza as entradas quando adequado. Por exemplo, quando um novo hardware é encontrado durante a inicialização ou por udev.

Em /etc/mtabvocê normalmente encontra a montagem por:

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

Para um bom artigo sobre o assunto, leia Patric Mochel's - The sysfs Filesystem .


arquivos stat / / sys

Se você entrar em um diretório /syse fizer um ls -l, notará que todos os arquivos têm um tamanho. Normalmente, 4096 bytes. Isso é relatado 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
...

Além disso, você pode fazer um statarquivo e perceber outro recurso distinto; ocupa 0 quarteirões. Também o inode da raiz (stat / sys) é 1. /stat/fsnormalmente possui o inode 2. etc.

rsync vs. cp

A explicação mais fácil para a falha do rsync na sincronização de pseudo arquivos é talvez pelo exemplo.

Digamos que tenhamos um arquivo com address18 bytes. Um lsou statdo arquivo relata 4096 bytes.


rsync

  1. Abre o descritor de arquivo, fd.
  2. Usa fstat (fd) para obter informações como tamanho.
  3. Decida ler bytes de tamanho, ou seja, 4096. Essa seria a linha 253 do código vinculado por @mattdm .read_size == 4096
    1. Ask; leitura: 4096 bytes.
    2. Uma string curta é lida, isto é, 18 bytes. nread == 18
    3. read_size = read_size - nread (4096 - 18 = 4078)
    4. Ask; leitura: 4078 bytes
    5. 0 bytes lidos (como a primeira leitura consumiu todos os bytes no arquivo).
    6. nread == 0, linha 255
    7. Não foi possível ler os 4096bytes. Zerar o buffer.
    8. Definir erro ENODATA.
    9. Retorna.
  4. Reportar erro.
  5. Repetir. (Loop acima).
  6. Falhou.
  7. Reportar erro.
  8. BEM.

Durante esse processo, ele realmente lê o arquivo inteiro. Mas, sem tamanho disponível, ele não pode validar o resultado - portanto, a falha é a única opção.

cp

  1. Abre o descritor de arquivo, fd.
  2. Usa fstat (fd) para obter informações como st_size (também usa lstat e stat).
  3. Verifique se é provável que o arquivo seja escasso. Esse é o arquivo tem buracos, 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 o statarquivo de relatórios possui zero blocos, é classificado como esparso.

  4. Tenta ler o arquivo por extensão-cópia (uma maneira mais eficiente de copiar arquivos esparsos normais ) e falha.

  5. Copie com cópia esparsa.
    1. Começa com o tamanho máximo de leitura de MAXINT.
      Normalmente, 18446744073709551615bytes em um sistema de 32 bits.
    2. Ask; leia 4096 bytes. (Tamanho do buffer alocado na memória a partir de informações estatísticas.)
    3. Uma string curta é lida, isto é, 18 bytes.
    4. Verifique se é necessário um orifício, não.
    5. Grave o buffer no destino.
    6. Subtraia 18 do tamanho máximo de leitura.
    7. Ask; leia 4096 bytes.
    8. 0 bytes, todos consumidos na primeira leitura.
    9. Retornar com sucesso.
  6. Tudo bem. Atualize sinalizadores para o arquivo.
  7. BEM.
Runium
fonte
2

Pode estar relacionado, mas as chamadas de atributo estendidas falharão no sysfs:

[root @ hypervisor eth0] # endereço lsattr

lsattr: ioctl inadequado para o dispositivo Ao ler sinalizadores no endereço

[root @ hypervisor eth0] #

Olhando para o meu rastreio, parece que o rsync tenta extrair atributos estendidos por padrão:

22964 <... getxattr resumido>, 0x7fff42845110, 132) = -1 ENODATA (dados não disponíveis)

Tentei encontrar uma bandeira para dar rsync para ver se pular atributos estendidos resolve o problema, mas não foi capaz de encontrar qualquer coisa ( --xattrstransforma-los em no destino).

Bratchley
fonte
0

O Rsync normalmente lê as informações do arquivo, transfere o conteúdo ou delta para um arquivo temporário no diretório de destino e, depois de verificar os dados do arquivo, o renomeia para o nome do arquivo de destino.

Acredito que o problema com o sysfs é que todos os arquivos são exibidos como 4k (uma página de memória), mas podem conter apenas alguns bytes. Para evitar copiar um arquivo potencialmente corrompido para o destino, o rsync cancela a cópia quando vê uma incompatibilidade entre os metadados do arquivo e o que realmente foi copiado.

Pelo menos no rsync v3.0.6, esse comportamento pode ser evitado usando o --inplaceswitch. O Rsync ainda detectará erros, mas como os arquivos de destino já foram substituídos, isso deixará os arquivos potencialmente corrompidos lá.

Observe, porém, que um efeito colateral disso é que os arquivos acabam sendo preenchidos com zero a 4k, pois esse é o tamanho que o rsync pensa que são. Na maioria dos casos, não deve fazer diferença, pois os bytes nulos geralmente são ignorados.

Thomas Guyot-Sionnest
fonte