为什么rsync无法在Linux中从/ sys复制文件?


12

我有一个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失败,并且可以用它复制文件吗?


4
为什么要复制/sys/
frostschutz

1
@frostschutz我在OP中使用命令来复制网卡的MAC地址(作为文件)
Eugene Yarmash13年

@eugeney那么,为什么备份设置MAC地址的配置文件还不够呢?
2013年

@eugeney甚至可以写/sys/class/net/*/address(尝试时出现“权限被拒绝”)?如果没有,那么您将无法进行真实/有用的备份,因为它无法还原。
2013年

Answers:


12

Rsync的代码专门检查文件在读取过程中是否被截断,并给出此错误— ENODATA。我不知道为什么其中的文件/sys具有这种行为,但是由于它们不是真实文件,因此我认为这并不奇怪。似乎没有办法告诉rsync跳过此特定检查。

我认为您最好不要同步/sys并使用特定的脚本来挑选所需的特定信息(例如网卡地址)。


PFFT,为什么不弄清楚为什么rsync尤其会失败,这有什么乐趣呢?
Bratchley

抱歉,我不清楚。Rsync专门检查在读取过程中被截断的文件,并引发此错误。
mattdm

4
我认为它们具有这种行为,因为在您真正阅读它们之前,“那里”是不是绝对可以确定的。读取实际上是从内核请求动态信息。因此,内核不会尝试事先为文件大小等提供准确的WRT详细信息,并且正如您所指出的那样,rsync将这种差异视为不好的迹象。
goldilocks 2013年

11

首先/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并在其中执行操作,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块。根(状态/ sys)的/stat/fsinode也为1。通常具有inode2。依此类推。

rsync与cp

同步伪文件的rsync失败最简单的解释可能是示例。

假设我们有一个名为address18个字节的文件。文件中的lsstat报告4096个字节。


同步

  1. 打开文件描述符fd。
  2. 使用fstat(fd)获取信息,例如大小。
  3. 设置为读取大小字节,即4096。这是@mattdm链接的代码的第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开始。
      通常 18446744073709551615是32位系统上的字节。
    2. 问; 读取4096个字节。(根据统计信息在内存中分配的缓冲区大小。)
    3. 读取一个短字符串,即18个字节。
    4. 检查是否需要打孔,不。
    5. 将缓冲区写入目标。
    6. 从最大读取大小中减去18。
    7. 问; 读取4096个字节。
    8. 第一次读取时消耗了0个字节。
    9. 返回成功。
  6. 一切都好。更新文件标志。
  7. 精细。

2

可能相关,但是扩展属性调用将在sysfs上失败:

[root @ hypervisor eth0]#lsattr地址

lsattr:设备不正确的ioctl,同时读取地址上的标志

[root @ hypervisor eth0]#

查看我的strace,看起来rsync默认尝试拉入扩展属性:

22964 <... getxattr恢复>,0x7fff42845110,132)= -1 ENODATA(无可用数据)

我试图找到一个标记给rsync,以查看是否跳过扩展属性可以解决此问题,但什么也找不到(在目标位置--xattrs将其打开)。


0

Rsync通常读取文件信息,将文件内容或增量传输到目标目录中的临时文件,然后在验证文件数据后将其重命名为目标文件名。

我相信sysfs的问题在于所有文件都显示为4k(一个内存页),但它们可能仅包含几个字节。为了避免将可能损坏的文件复制到目标位置,rsync会在看到文件的元数据与实际复制的内容不匹配时取消复制。

至少在rsync v3.0.6上,使用--inplace开关可以避免此行为。Rsync仍会检测到错误,但由于目标文件在执行时已被覆盖,因此它将可能损坏的文件保留在那里。

请注意,尽管这样做的副作用是文件最终被零填充到4k,因为这是rsync认为文件的大小。在大多数情况下,它不应该有所作为,因为通常会忽略空字节。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.