使用 rsync 覆盖正在使用的 .so 文件或可执行文件是否安全?

Is it safe to overwrite a .so file or an executable in use using rsync?

这不是真正的编程问题。我们有一个用 c++ 编写的大型系统,并在 Redhat Enterprise Linux 上使用许多共享对象 (.so) 和本机可执行文件。系统在多个主机上运行,​​我们使用 rsync 来保存部署的二进制文件(共享对象和可执行文件)

如果我们必须修复 .so(或可执行文件)中的错误,我们会将其部署到一个位置,然后在所有其他主机上进行 rsync

覆盖正在使用的 .so(或可执行文件)是否安全(或 运行)?我读到 rm & cp 是安全的,因为 *nix 如何处理 inode (某种引用计数)。但是当涉及到 rsync

时,我找不到满意的答案

简答

如果您不使用 --in-place.

,它在单个文件中是绝对安全的

对于多个相互依赖的文件来说,它基本上是安全的,但是有一些风险,使用 --delay-updates 可以将风险降到最低。


长答案

默认(即不使用--in-place时),rsync实际上会在新文件中创建内容,以临时名称命名(类似于 .__your_file),然后在完成后将其重命名为原始文件。

这个重命名是一个完全原子的操作:任何试图打开文件的人都会得到原始文件或替换文件(在替换完全完成之后)。

此外,如果原始文件正在使用中,那么即使在指向它的目录条目被指向不同 inode 的新条目覆盖之后,它的引用计数也将不为零,因此内容将保留在磁盘上(未删除)直到原始文件不再打开。

但是,对于多个文件, 您 运行 有这样的风险,即只有其中一些文件会被自动替换。如果您同时复制新的 foolibfoo.so,那么旧的 foo 将无法与新的 libfoo.so 和新的 foo 一起使用将无法与旧 libfoo.so 一起使用,如果您在新 libfoo.sorename() 就位后尝试启动可执行文件,则情况很糟糕,但是 foo 还没有。

rsync 可用的最接近此问题的修复方法是 --delay-updates 选项,它将等到它具有 .__foo.__libfoo.so 完成,然后将它们并排重命名。仍然没有操作系统级别的保证,您看不到一个文件的更新版本而不是另一个文件,但是发生这种情况的时间 window 大大缩短了。


如果使用 --in-place,则操作系统将由于文件正在使用而拒绝写入权限(并非对 UNIX 上的所有访问都强制执行,但特别使用 mmap(MAP_PRIVATE) 强制执行,用于可执行文件和共享库);这将是一个 "Text file busy" 错误。如果您的操作系统 没有 强制执行此操作,任何 mmap() 用于提供反映文件内容的内存区域(这通常是加载共享库的方式)的任何场景都会导致 Bad Things在就地覆盖的情况下发生。