Tại sao rsync không sao chép tệp từ / sys trong Linux?


12

Tôi có một tập lệnh bash sử dụng rsyncđể sao lưu các tập tin trong Archlinux. Tôi nhận thấy rằng rsynckhông thể sao chép một tập tin từ /sys, trong khi vẫn cphoạt động tốt:

# 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

Tôi tự hỏi tại sao không thành rsynccông, và có thể sao chép các tập tin với nó?


4
Tại sao bạn muốn sao chép /sys/?
frostschutz

1
@frostschutz Tôi sử dụng lệnh trong OP để sao chép địa chỉ MAC của card mạng (dưới dạng tệp)
Eugene Yarmash

@eugeney Vậy, tại sao không đủ để sao lưu tệp cấu hình nơi đặt địa chỉ MAC?
depquid

@eugeney Thậm chí có thể viết thư cho /sys/class/net/*/address(Tôi nhận được "quyền bị từ chối" khi tôi thử nó)? Nếu không, thì bạn không tạo một bản sao lưu thực / hữu ích vì nó không thể được khôi phục.
depquid

Câu trả lời:


12

Rsync có kiểm tra cụ thể nếu một tệp bị cắt trong khi đọc và đưa ra lỗi này - ENODATA. Tôi không biết tại sao các tệp trong đó /syscó hành vi này, nhưng vì chúng không phải là tệp thực, tôi đoán nó không quá ngạc nhiên. Dường như không có cách nào để nói với rsync bỏ qua kiểm tra cụ thể này.

Tôi nghĩ có lẽ tốt hơn hết là bạn không nên tham gia /sysvà sử dụng các tập lệnh cụ thể để chọn ra thông tin cụ thể mà bạn muốn (như địa chỉ card mạng).


Pfft, đâu là niềm vui khi không tìm ra lý do tại sao rsync đặc biệt thất bại?
Bratchley

Xin lỗi, tôi đã không rõ ràng. Rsync đặc biệt kiểm tra các tệp bị cắt trong khi đọc và ném lỗi này.
mattdm

4
Tôi cho rằng họ có hành vi này bởi vì cho đến khi bạn thực sự đọc chúng, những gì "ở đó" không hoàn toàn chắc chắn; đọc thực sự là một yêu cầu cho thông tin động từ kernel. Vì vậy, kernel không cố gắng cung cấp chi tiết chính xác WRT cho kích thước tệp, v.v., và như bạn chỉ ra, rsync coi sự khác biệt đó là một dấu hiệu xấu.
goldilocks

11

Trước hết /syslà một hệ thống tập tin giả . Nếu bạn nhìn vào, /proc/filesystemsbạn sẽ tìm thấy một danh sách các hệ thống tập tin đã đăng ký, nơi có khá nhiều hệ thống có nodev ở phía trước. Điều này cho thấy chúng là các hệ thống tập tin giả . Điều này có nghĩa là chúng tồn tại trên một kernel đang chạy như một hệ thống tập tin dựa trên RAM. Hơn nữa họ không yêu cầu một thiết bị khối.

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

Khi khởi động, kernel gắn hệ thống này và cập nhật các mục khi phù hợp. Ví dụ: khi phần cứng mới được tìm thấy trong khi khởi động hoặc bởi udev.

Trong /etc/mtabbạn thường tìm thấy gắn kết bởi:

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

Để có một bài viết hay về chủ đề này, hãy đọc Patric Mochel's - Hệ thống tập tin sysfs .


stat của tập tin / sys

Nếu bạn đi vào một thư mục bên dưới /sysvà làm một ls -lbạn sẽ nhận thấy rằng tất cả các tệp có một kích thước. Thông thường là 4096 byte. Điều này được báo cáo bởi 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
...

Hơn nữa bạn có thể làm statmột tập tin và nhận thấy một tính năng khác biệt; nó chiếm 0 khối. Ngoài ra inode của root (stat / sys) là 1. /stat/fsthường có inode 2. vv

rsync so với cp

Ví dụ, lời giải thích dễ nhất cho sự thất bại của rsync khi đồng bộ hóa các tệp giả.

Giả sử chúng ta có một tệp có tên addresslà 18 byte. Một lshoặc statcủa tệp báo cáo 4096 byte.


rsync

  1. Mở mô tả tập tin, fd.
  2. Sử dụng fstat (fd) để lấy thông tin như kích thước.
  3. Đặt ra để đọc byte kích thước, tức là 4096. Đó sẽ là dòng 253 của mã được liên kết bởi @mattdm .read_size == 4096
    1. Hỏi; đọc: 4096 byte.
    2. Một chuỗi ngắn được đọc tức là 18 byte. nread == 18
    3. read_size = read_size - nread (4096 - 18 = 4078)
    4. Hỏi; đọc: 4078 byte
    5. 0 byte đọc (lần đọc đầu tiên đã tiêu thụ tất cả các byte trong tệp).
    6. nread == 0, dòng 255
    7. Không thể đọc 4096byte. Không có bộ đệm.
    8. Đặt lỗi ENODATA.
    9. Trở về.
  4. Báo cáo lỗi.
  5. Thử lại. (Vòng lặp trên).
  6. Thất bại.
  7. Báo cáo lỗi.
  8. KHỎE.

Trong quá trình này, nó thực sự đọc toàn bộ tập tin. Nhưng không có kích thước có sẵn, nó không thể xác nhận kết quả - do đó, thất bại chỉ là tùy chọn.

cp

  1. Mở mô tả tập tin, fd.
  2. Sử dụng fstat (fd) để lấy thông tin như st_size (cũng sử dụng lstat và stat).
  3. Kiểm tra nếu tập tin có khả năng là thưa thớt. Đó là tập tin có lỗ, v.v.

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

    Khi stattệp báo cáo có khối không, nó được phân loại là thưa thớt.

  4. Cố gắng đọc tệp theo mức độ sao chép (một cách hiệu quả hơn để sao chép các tệp thưa thớt bình thường ) và không thành công.

  5. Sao chép bằng cách sao chép thưa thớt.
    1. Bắt đầu với kích thước đọc tối đa MAXINT.
      Thông thường các 18446744073709551615byte trên hệ thống 32 bit.
    2. Hỏi; đọc 4096 byte. (Kích thước bộ đệm được phân bổ trong bộ nhớ từ thông tin thống kê.)
    3. Một chuỗi ngắn được đọc tức là 18 byte.
    4. Kiểm tra nếu một lỗ là cần thiết, không.
    5. Viết bộ đệm vào mục tiêu.
    6. Trừ 18 từ kích thước đọc tối đa.
    7. Hỏi; đọc 4096 byte.
    8. 0 byte như tất cả đã tiêu thụ trong lần đọc đầu tiên.
    9. Trở về thành công.
  6. Tất cả ok. Cập nhật cờ cho tập tin.
  7. KHỎE.

2

Có thể liên quan, nhưng các cuộc gọi thuộc tính mở rộng sẽ thất bại trên sysfs:

[root @ hypanneror eth0] # lsattr địa chỉ

lsattr: ioctl không phù hợp cho thiết bị Trong khi đọc cờ trên địa chỉ

[root @ hypanneror eth0] #

Nhìn vào dấu vết của tôi, có vẻ như rsync cố gắng kéo các thuộc tính mở rộng theo mặc định:

22964 <... getxattr đã tiếp tục>, 0x7fff42845110, 132) = -1 ENODATA (Không có sẵn dữ liệu)

Tôi cố gắng tìm một lá cờ để cung cấp cho rsync để xem nếu bỏ qua thuộc tính mở rộng giải quyết vấn đề này nhưng không thể tìm thấy bất cứ điều gì ( --xattrslượt chúng trên tại điểm đến).


0

Rupync thường đọc thông tin của tệp, chuyển nội dung tệp hoặc delta sang tệp tạm thời trong thư mục đích, sau đó sau khi xác minh dữ liệu của tệp, nó đổi tên thành tên tệp đích.

Tôi tin rằng vấn đề với sysfs là tất cả các tệp hiển thị là 4k (một trang bộ nhớ) nhưng chúng chỉ có thể chứa một vài byte. Để tránh sao chép tệp có khả năng bị hỏng vào rsync đích sẽ hủy bản sao khi thấy tệp không khớp giữa siêu dữ liệu của tệp và nội dung được sao chép thực sự.

Ít nhất trên rsync v3.0.6 hành vi này có thể tránh được bằng cách sử dụng công --inplacetắc. Rsync vẫn sẽ phát hiện lỗi nhưng vì các tệp đích sẽ bị ghi đè khi nó sẽ để các tệp có khả năng bị hỏng ở đó.

Lưu ý rằng mặc dù tác dụng phụ của nó là các tệp cuối cùng được đệm không đến 4k vì đây là kích thước mà rsync nghĩ là các tệp. Nó không nên tạo sự khác biệt trong hầu hết các trường hợp vì byte rỗng thường bị bỏ qua.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.