Dlaczego rsync nie kopiuje plików z / sys w systemie Linux?

12

Mam skrypt bash, który służy rsyncdo tworzenia kopii zapasowych plików w Archlinux. Zauważyłem, że rsyncnie udało się skopiować pliku /sys, ale cpdziałało dobrze:

# 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

Zastanawiam się, dlaczego się nie rsyncudaje i czy można z nim skopiować plik?

Eugene Yarmash
źródło
4
Dlaczego chcesz skopiować /sys/?
frostschutz
1
@frostschutz Korzystam z polecenia w OP, aby skopiować adres MAC karty sieciowej (jako plik)
Eugene Yarmash 24.04.13
@eugeney Dlaczego więc nie wystarczy wykonać kopię zapasową pliku konfiguracji, z którego ustawiony jest adres MAC?
depquid
@eugeney Czy można nawet napisać na adres /sys/class/net/*/address(gdy próbuję uzyskać „odmowę dostępu ”)? Jeśli nie, to nie tworzysz prawdziwej / przydatnej kopii zapasowej, ponieważ nie można jej przywrócić.
depquid

Odpowiedzi:

12

Rsync ma kod, który konkretnie sprawdza, czy plik jest obcinany podczas odczytu i podaje ten błąd - ENODATA. Nie wiem, dlaczego pliki /sysmają takie zachowanie, ale ponieważ nie są to prawdziwe pliki, myślę, że nie jest to zbyt zaskakujące. Wydaje się, że nie ma sposobu, aby powiedzieć rsync, aby pomijał ten konkretny test.

Myślę, że lepiej, żebyś nie rsynchronizował /sysi nie używał określonych skryptów do wybrania konkretnych informacji (takich jak adres karty sieciowej).

mattdm
źródło
Pfft, gdzie jest fajnie nie wiedzieć, dlaczego w szczególności rsync zawodzi?
Bratchley,
Przepraszam, nie było jasne. Rsync w szczególności sprawdza pliki obcięte podczas odczytu i zgłasza ten błąd.
mattdm 24.04.13
4
Zakładam, że mają takie zachowanie, ponieważ dopóki ich nie przeczytasz, to, co „tam” nie jest absolutnie pewne; odczyt jest tak naprawdę żądaniem dynamicznych informacji z jądra. Dlatego jądro nie próbuje podać dokładnych szczegółów WRT do rozmiaru pliku itp., A jak zauważyłeś, rsync przyjmuje taką rozbieżność jako zły znak.
goldilocks 24.04.13
11

Po pierwsze /systo pseudo system plików . Jeśli na nie spojrzysz /proc/filesystems, znajdziesz listę zarejestrowanych systemów plików, z których kilka ma nodev przed sobą. Oznacza to, że są to pseudo systemy plików . Oznacza to, że istnieją w działającym jądrze jako system plików oparty na pamięci RAM. Ponadto nie wymagają urządzenia blokującego.

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

Podczas rozruchu jądro montuje ten system i aktualizuje wpisy, gdy są odpowiednie. Np. Gdy nowy sprzęt zostanie znaleziony podczas rozruchu lub przez udev.

W /etc/mtabzwykle znajdujesz mount według:

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

Aby uzyskać miły artykuł na ten temat, przeczytaj artykuł Patrica Mochela - System plików sysfs .


stat plików / sys

Jeśli przejdziesz do katalogu poniżej /sysi zrobisz to ls -l, zauważysz, że wszystkie pliki mają jeden rozmiar. Zazwyczaj 4096 bajtów. Jest to zgłaszane przez 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
...

Ponadto możesz zrobić statna pliku i zauważyć inną wyraźną funkcję; zajmuje 0 bloków. Również i-węzeł root (stat / sys) to 1. /stat/fszwykle ma i-węzeł 2. itd.

rsync vs. cp

Najłatwiejszym wyjaśnieniem niepowodzenia synchronizacji pseudoplików przez rsync jest być może przykład.

Powiedzmy, że mamy plik o nazwie address18 bajtów. Plik lslub statzgłasza 4096 bajtów.


rsync

  1. Otwiera deskryptor pliku, fd.
  2. Używa fstat (fd), aby uzyskać informacje, takie jak rozmiar.
  3. Ustaw, aby odczytać bajty wielkości, tj. 4096. To byłaby linia 253 kodu połączona przez @mattdm .read_size == 4096
    1. Zapytać; odczyt: 4096 bajtów.
    2. Czyta się krótki ciąg znaków, tj. 18 bajtów. nread == 18
    3. read_size = read_size - nread (4096 - 18 = 4078)
    4. Zapytać; odczyt: 4078 bajtów
    5. 0 bajtów odczytanych (jako pierwszy odczyt zużył wszystkie bajty w pliku).
    6. nread == 0, linia 255
    7. Nie można odczytać 4096bajtów. Bufor zerowy.
    8. Ustaw błąd ENODATA.
    9. Powrót.
  4. Zgłoś błąd.
  5. Spróbować ponownie. (Powyżej pętli).
  6. Zawieść.
  7. Zgłoś błąd.
  8. W PORZĄDKU.

Podczas tego procesu faktycznie odczytuje cały plik. Ale przy braku dostępnego rozmiaru nie można zweryfikować wyniku - dlatego niepowodzenie jest tylko opcją.

cp

  1. Otwiera deskryptor pliku, fd.
  2. Używa fstat (fd), aby uzyskać informacje, takie jak st_size (używa również lstat i stat).
  3. Sprawdź, czy plik może być rzadki. To znaczy, że plik ma dziury itp.

    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);
    

    Jako statplik raportów mieć zero bloków jest skategoryzowane jako rzadki.

  4. Próbuje odczytać plik według zakresu-kopiowania (bardziej efektywny sposób kopiowania normalnych plików rzadkich) i kończy się niepowodzeniem.

  5. Kopiuj przez rzadkie kopiowanie.
    1. Zaczyna się od maksymalnego rozmiaru odczytu MAXINT.
      Zazwyczaj 18446744073709551615bajty w systemie 32-bitowym.
    2. Zapytać; odczytać 4096 bajtów. (Rozmiar bufora przydzielony w pamięci na podstawie informacji statystycznych).
    3. Czyta się krótki ciąg znaków, tj. 18 bajtów.
    4. Sprawdź, czy potrzebna jest dziura, nie.
    5. Zapisz bufor do celu.
    6. Odejmij 18 od maksymalnego rozmiaru odczytu.
    7. Zapytać; odczytać 4096 bajtów.
    8. 0 bajtów, ponieważ wszystkie zostały zużyte w pierwszym czytaniu.
    9. Sukces zwrotu
  6. Wszystko ok. Zaktualizuj flagi pliku.
  7. W PORZĄDKU.
Runium
źródło
2

Być może są powiązane, ale rozszerzone wywołania atrybutów nie będą działać na sysfs:

[root @ hypervisor eth0] # lsattr adres

lsattr: Niewłaściwy ioctl dla urządzenia Podczas odczytu flag na adres

[root @ hypervisor eth0] #

Patrząc na moją ścieżkę, wygląda na to, że rsync próbuje domyślnie rozszerzyć atrybuty:

22964 <... getxattr wznowione>, 0x7fff42845110, 132) = -1 ENODATA (Brak danych)

Próbowałem znaleźć flagę dać rsync, aby sprawdzić, czy pomijanie atrybutów rozszerzonych rozwiązuje problem, ale nie był w stanie znaleźć coś ( --xattrszamienia je na w miejscu przeznaczenia).

Bratchley
źródło
0

Rsync zwykle odczytuje informacje o pliku, przenosi zawartość pliku lub deltę do pliku tymczasowego w katalogu docelowym, a następnie po zweryfikowaniu danych pliku zmienia nazwę na docelową nazwę pliku.

Uważam, że problem z sysfs polega na tym, że wszystkie pliki są wyświetlane jako 4k (jedna strona pamięci), ale mogą zawierać tylko kilka bajtów. Aby uniknąć kopiowania potencjalnie uszkodzonego pliku do miejsca docelowego, rsync anuluje kopię, gdy zobaczy niezgodność między metadanymi pliku a tym, co zostało skopiowane.

Przynajmniej w rsync v3.0.6 tego zachowania można uniknąć za pomocą --inplaceprzełącznika. Rsync nadal wykrywa błędy, ale ponieważ pliki docelowe zostały już nadpisane, pozostawia tam potencjalnie uszkodzone pliki.

Zauważ jednak, że efektem ubocznym jest to, że pliki są zerowane do 4k, ponieważ taki rozmiar rsync uważa za pliki. W większości przypadków nie powinno to mieć znaczenia, ponieważ bajty zerowe są zwykle ignorowane.

Thomas Guyot-Sionnest
źródło