/sys 檔案的統計訊息

/sys 檔案的統計訊息

我有一個 bash 腳本,用於rsync在 Archlinux 中備份檔案。我注意到無法rsync從 複製文件/sys,但cp工作得很好:

# 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

我想知道為什麼會rsync失敗,是否可以用它複製文件?

答案1

首先/sys是一個偽檔案系統。如果您查看,/proc/filesystems您會發現一個已註冊文件系統的列表,其中有不少nodev 位於前面。這表明他們是偽檔案系統。這意味著它們作為基於 RAM 的檔案系統存在於正在運行的核心上。此外,它們不需要塊設備。

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

啟動時,核心會掛載該系統並在適當時更新條目。例如,當在引導期間或通過udev.

通常,/etc/mtab您可以透過以下方式找到安裝座:

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

有關該主題的一篇好論文請閱讀 Patric Mochel 的 – sysfs 檔案系統


/sys 檔案的統計訊息

如果您進入下面的目錄/sys並執行 a,ls -l您會發現所有檔案都有一個大小。通常為 4096 位元組。這是由 報道的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
...

stat此外,您可以對文件進行操作並注意到另一個明顯的特徵;它佔用0塊。另外,根節點 (stat /sys) 的 inode 為 1 /stat/fs

rsync 與 cp

對於 rsync 同步偽文件失敗的最簡單解釋可能是透過範例。

假設我們有一個名為address18 位元組的檔案。文件的lsor報告4096 位元組。stat


同步

  1. 開啟檔案描述符 fd。
  2. 使用 fstat(fd) 取得大小等資訊。
  3. 開始讀取大小字節,即 4096。第253行連結的程式碼的@馬特德姆read_size == 4096
    1. 問;讀取:4096 位元組。
    2. 讀取一個短字串,即 18 個位元組。nread == 18
    3. read_size = read_size - nread (4096 - 18 = 4078)
    4. 問;讀取:4078 位元組
    5. 讀取 0 個位元組(因為第一次讀取消耗了檔案中的所有位元組)。
    6. nread == 0,255號線
    7. 無法讀取4096位元組。將緩衝區清零。
    8. 設定錯誤ENODATA
    9. 返回。
  4. 報告錯誤。
  5. 重試。 (以上循環)。
  6. 失敗。
  7. 報告錯誤。
  8. 美好的。

在此過程中,它實際上讀取整個文件。但由於沒有可用的尺寸,它無法驗證結果 - 因此失敗是唯一的選擇。

CP

  1. 開啟檔案描述符 fd。
  2. 使用 fstat(fd) 取得 st_size 等資訊(也使用 lstat 和 stat)。
  3. 檢查文件是否可能稀疏。那就是文件有漏洞等。

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

    由於stat報告文件有零個區塊,因此它被歸類為稀疏。

  4. 嘗試透過範圍複製來讀取檔案(一種更有效的複製方式普通的 稀疏文件),並且失敗。

  5. 透過稀疏複製進行複製。
    1. 從最大讀取大小 MAXINT 開始。在 32 位元系統上
      通常 為位元組。18446744073709551615
    2. 問;讀取 4096 位元組。 (根據統計資料在記憶體中分配的緩衝區大小。)
    3. 讀取一個短字串,即 18 個位元組。
    4. 檢查是否需要打孔,不需要。
    5. 將緩衝區寫入目標。
    6. 從最大讀取大小中減去 18。
    7. 問;讀取 4096 位元組。
    8. 0 字節,因為第一次讀取時全部被消耗。
    9. 返回成功。
  6. 一切都好。更新文件的標誌。
  7. 美好的。

答案2

Rsync 有程式碼它專門檢查文件在讀取過程中是否被截斷並給出此錯誤 - ENODATA。我不知道為什麼中的文件/sys有這種行為,但由於它們不是真正的文件,我想這並不太令人驚訝。似乎沒有辦法告訴 rsync 跳過這個特定的檢查。

我認為您最好不要進行 rsync/sys並使用特定腳本來挑選您想要的特定資訊(例如網卡地址)。

答案3

可能相關,但擴充屬性呼叫將在 sysfs 上失敗:

[root@hypervisor eth0]# lsattr 位址

lsattr:讀取位址上的標誌時,裝置的 ioctl 不合適

[root@hypervisor eth0]#

看看我的 strace,看起來 rsync 預設會嘗試引入擴充屬性:

22964 <... getxattr 恢復> , 0x7fff42845110, 132) = -1 ENODATA (無可用資料)

我嘗試找到一個標誌來提供 rsync 以查看跳過擴展屬性是否可以解決問題,但無法找到任何內容(--xattrs將它們變成到達目的地)。

答案4

Rsync 通常會讀取檔案的訊息,將檔案內容或增量傳輸到目標目錄中的暫存文件,然後在驗證檔案資料後將其重新命名為目標檔案名稱。

我認為 sysfs 的問題是所有檔案都顯示為 4k(一個記憶體頁),但它們可能只包含幾個位元組。為了避免將可能損壞的檔案複製到目標,當 rsync 發現檔案的元資料與實際複製的內容不符時,它會取消複製。

至少在 rsync v3.0.6 上可以使用--inplace開關來避免這種行為。 Rsync 仍會偵測錯誤,但由於目標檔案在偵測時已被覆蓋,因此可能會將潛在損壞的檔案留在那裡。

請注意,它的一個副作用是檔案最終會被零填充到 4k,因為這是 rsync 認為檔案的大小。在大多數情況下,它不會產生任何影響,因為空位元組通常會被忽略。

相關內容