/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通常有 inode 2。等等。

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 认为文件的大小。在大多数情况下,它不会产生任何影响,因为空字节通常会被忽略。

相关内容