Mengapa rsync gagal menyalin file dari / sys di Linux?

12

Saya memiliki skrip bash yang digunakan rsyncuntuk membuat cadangan file di Archlinux. Saya perhatikan bahwa rsyncgagal menyalin file dari /sys, sementara cpberfungsi dengan baik:

# 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

Saya bertanya-tanya mengapa rsyncgagal, dan apakah mungkin menyalin file dengan itu?

Eugene Yarmash
sumber
4
Mengapa Anda ingin menyalin /sys/?
frostschutz
1
@ frostschutz Saya menggunakan perintah di OP untuk menyalin alamat MAC dari kartu jaringan (sebagai file)
Eugene Yarmash
@ eugeney Jadi, mengapa tidak mencukupi untuk mencadangkan file konfigurasi tempat alamat MAC ditetapkan?
depquid
@eugeney Mungkinkah menulis surat /sys/class/net/*/address(saya mendapat "izin ditolak" ketika saya mencobanya)? Jika tidak, maka Anda tidak membuat cadangan nyata / berguna karena tidak dapat dipulihkan.
depquid

Jawaban:

12

Rsync memiliki kode yang secara khusus memeriksa apakah file terpotong saat membaca dan memberikan kesalahan ini - ENODATA. Saya tidak tahu mengapa file-file /sysini memiliki perilaku ini, tetapi karena mereka bukan file nyata, saya kira itu tidak terlalu mengejutkan. Sepertinya tidak ada cara untuk memberitahu rsync untuk melewatkan pemeriksaan khusus ini.

Saya pikir Anda mungkin lebih baik tidak melakukan sinkronisasi /sysdan menggunakan skrip khusus untuk memilih informasi tertentu yang Anda inginkan (seperti alamat kartu jaringan).

mattdm
sumber
Pfft, di mana kesenangan dalam tidak mencari tahu mengapa rsync gagal?
Bratchley
Maaf, saya tidak jelas. Rsync secara khusus memeriksa file yang terpotong saat membaca dan melempar kesalahan ini.
mattdm
4
Saya kira mereka memiliki perilaku ini karena sampai Anda benar-benar membacanya, apa yang "ada" tidak sepenuhnya pasti; membaca sebenarnya adalah permintaan untuk informasi dinamis dari kernel. Jadi kernel tidak mencoba untuk memberikan rincian akurat WRT ke ukuran file, dll, sebelumnya, dan seperti yang Anda tunjukkan, rsync menganggap perbedaan tersebut sebagai pertanda buruk.
goldilocks
11

Pertama /sysadalah sistem file pseudo . Jika Anda melihat, /proc/filesystemsAnda akan menemukan daftar sistem file terdaftar di mana beberapa memiliki nodev di depan. Ini menunjukkan mereka adalah sistem file semu . Ini berarti mereka ada pada kernel yang berjalan sebagai sistem file berbasis RAM. Selanjutnya mereka tidak memerlukan perangkat blok.

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

Pada saat boot kernel mount sistem ini dan memperbarui entri bila sesuai. Misalnya ketika perangkat keras baru ditemukan saat boot atau oleh udev.

Di /etc/mtabAnda biasanya menemukan mount dengan:

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

Untuk makalah yang bagus tentang hal ini, baca Patric Mochel's - The sysfs Filesystem .


file stat / sys

Jika Anda masuk ke direktori di bawah /sysdan melakukan ls -lAnda akan melihat bahwa semua file memiliki satu ukuran. Biasanya 4.096 byte. Ini dilaporkan oleh 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
...

Selanjutnya Anda dapat melakukan statpada file dan melihat fitur berbeda lainnya; ini menempati 0 blok. Juga inode root (stat / sys) adalah 1. /stat/fsbiasanya memiliki inode 2. dll.

rsync vs. cp

Penjelasan termudah untuk kegagalan rsync menyinkronkan file pseudo mungkin dengan contoh.

Katakanlah kita memiliki file yang bernama address18 byte. Sebuah lsatau statdari file melaporkan 4096 byte.


rsync

  1. Buka deskriptor file, fd.
  2. Menggunakan fstat (fd) untuk mendapatkan informasi seperti ukuran.
  3. Set untuk membaca byte ukuran, yaitu 4096. Itu akan menjadi baris 253 dari kode yang dihubungkan oleh @mattdm .read_size == 4096
    1. Meminta; baca: 4096 byte.
    2. Sebuah string pendek dibaca yaitu 18 byte. nread == 18
    3. read_size = read_size - nread (4096 - 18 = 4078)
    4. Meminta; baca: 4078 byte
    5. 0 byte baca (sebagai pembacaan pertama dikonsumsi semua byte dalam file).
    6. nread == 0, baris 255
    7. Tidak dapat membaca 4096byte. Zero out buffer.
    8. Setel kesalahan ENODATA.
    9. Kembali.
  4. Laporan kesalahan.
  5. Mencoba kembali. (Di atas lingkaran).
  6. Gagal.
  7. Laporan kesalahan.
  8. BAIK.

Selama proses ini sebenarnya membaca seluruh file. Tetapi tanpa ukuran yang tersedia itu tidak dapat memvalidasi hasilnya - dengan demikian kegagalan hanya pilihan.

cp

  1. Buka deskriptor file, fd.
  2. Menggunakan fstat (fd) untuk mendapatkan informasi seperti st_size (juga menggunakan lstat dan stat).
  3. Periksa apakah file cenderung jarang. Itu adalah file berlubang dll.

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

    Sebagai statfile laporan memiliki nol blok itu dikategorikan jarang.

  4. Mencoba membaca file dengan cara copy-copy (cara yang lebih efisien untuk menyalin file jarang yang normal ), dan gagal.

  5. Salin dengan jarang-salin.
    1. Mulai dengan ukuran baca maks MAXINT.
      Biasanya 18446744073709551615byte pada sistem 32 bit.
    2. Meminta; baca 4096 byte. (Ukuran buffer dialokasikan dalam memori dari informasi stat.)
    3. Sebuah string pendek dibaca yaitu 18 byte.
    4. Periksa apakah lubang diperlukan, tidak.
    5. Tulis buffer ke target.
    6. Kurangi 18 dari ukuran baca maksimal.
    7. Meminta; baca 4096 byte.
    8. 0 byte karena semua telah dikonsumsi dalam pembacaan pertama.
    9. Kembali sukses.
  6. Semua baik-baik saja Perbarui flag untuk file.
  7. BAIK.
Runium
sumber
2

Mungkin terkait, tetapi panggilan atribut panjang akan gagal di sysfs:

[root @ hypervisor eth0] # alamat lsattr

lsattr: ioctl tidak sesuai untuk perangkat Saat membaca tanda pada alamat

[root @ hypervisor eth0] #

Melihat strace saya sepertinya rsync mencoba menarik atribut yang diperluas secara default:

22964 <... getxattr dilanjutkan>, 0x7fff42845110, 132) = -1 ENODATA (Tidak ada data tersedia)

Saya mencoba mencari bendera untuk memberikan rsync untuk melihat apakah skipping atribut diperpanjang menyelesaikan masalah tetapi tidak dapat menemukan apa pun ( --xattrsternyata mereka pada di tempat tujuan).

Bratchley
sumber
0

Rsync biasanya membaca informasi file, mentransfer konten file atau delta ke file sementara di direktori tujuan, kemudian setelah memverifikasi data file itu berganti nama menjadi nama file tujuan.

Saya percaya masalah dengan sysfs adalah bahwa semua file menunjukkan sebagai 4k (satu halaman memori) namun mereka mungkin hanya mengandung beberapa byte. Untuk menghindari menyalin file yang berpotensi rusak ke tujuan, rsync membatalkan salinan ketika melihat ketidakcocokan antara metadata file dan apa yang sebenarnya disalin.

Setidaknya pada rsync v3.0.6 perilaku ini dapat dihindari menggunakan --inplacesakelar. Rsync masih akan mendeteksi kesalahan tetapi karena file tujuan sudah ditimpa ketika itu akan meninggalkan file yang berpotensi rusak di sana.

Perhatikan bahwa efek sampingnya adalah bahwa file akhirnya menjadi nol-empuk menjadi 4k karena ini adalah ukuran yang menurut rsync file tersebut. Seharusnya tidak membuat perbedaan dalam banyak kasus karena null byte biasanya diabaikan.

Thomas Guyot-Sionnest
sumber