为什么即使升级了软件包,软件包也能正常运行?


29

假设我正在运行一个软件,然后运行软件包管理器来升级软件,我注意到Linux并没有降低正在运行的软件包升级过程-它仍然可以正常运行。Linux如何做到这一点?

Answers:


35

原因是Unix在执行时不会锁定可执行文件,即使它像Linux一样,该锁定也适用于inode,而不适用于文件名。这意味着即使文件已被删除(实际上未链接)并由具有相同名称的新文件替换(实际上是软件包更新所做的)后,保持打开状态的进程仍在访问相同(旧)数据。

这是Unix和Windows之间的主要区别之一。后者无法更新被锁定的文件,因为它缺少文件名和inode之间的层,这使更新或什至安装某些软件包变得很麻烦,因为它通常需要完全重新启动。


10
需要说明的是,在Linux下,您无法在可执行文件运行时对其进行修改。但是您可以取消链接该文件,并将其替换为同名的新文件。
cjm

在Linux下,您可以在可执行文件运行时对其进行修改。但是,除非您真的知道自己在做什么,否则结果可能是不可预测的。添加了未明确说明的“相同名称”点。
jlliagre

4
@jlliagre除非我有误会,否则我不会知道:sprunge.us/egiR
Chris Down

2
但是,关于NFTS的一件整洁的事情-如果您从命令行或其他程序执行重命名,则可以将同名文件放在那里,并且不会影响打开了原始文件的程序。(资源管理器中的重命名命令对此不起作用)
Steffan Donal

1
@cjm您对Linux下的“文件文本忙”保护是正确的,答案已更新。我更熟悉的Solaris没有这种限制。但是,您仍然可以同时使用两个OS修改共享库。
jlliagre 2013年

18

可执行文件通常打开一次,附加到文件描述符,并且在单个执行期间重新打开二进制文件时没有文件描述符。例如,如果执行bashexec()通常仅/bin/bash在调用时为一次指向的索引节点创建文件描述符。

这通常意味着,对于在执行过程中不尝试重新读取自身的简单二进制文件(通过使用调用它们的路径),缓存的内容将作为悬挂的inode保持有效。这意味着该可执行文件实际上是先前版本的副本。

在更复杂的情况下,这可能会引起问题。例如,配置文件可以升级并随后重新读取,或者程序可以通过其执行路径重新执行自身。如果程序是互连的,并且在升级之前执行一个程序,然后在升级之后执行一个程序(可能是第一个程序执行),则也会出现问题。对于某些库也是如此。

但是,对于简单的用例,无需重新启动过程即可安全升级。


1
即使在简单的情况下,另一个危险是,由于正在运行的应用程序正在使用二进制文件的缓存副本,因此除非您手动重新启动应用程序,否则它仍在运行旧版本的代码。虽然这在大多数时候都不重要;如果升级包含安全修补程序,尽管安装了补丁,您的系统仍然容易受到攻击,因为旧版本仍在运行。
Dan Neely

1
恐怕您的第一段不正确。Unix / Linux内核不会立即加载可执行程序,而是通过内存映射它们。这意味着只有实际使用的页面最终才能进入RAM。这是Linux下“文本文件繁忙”保护的全部要点。无法保证可执行文件的某些部分在启动后不会被长时间读取。而且,某些页面永远不会为足够大的程序加载,而对于动态加载的库则更是如此。例如,bash二进制文件大约有200个4K页,请确保在一次平均会话中都不会使用它们。
jlliagre 2013年

@jlliagre我在说的是ialloc()读取时读取内核结构,而不是页面本身的内存映射。我是否不认为在现代ext *文件系统上,inode最终在内核(以及VM子系统内部)是一致的?
克里斯·

不能保证可执行内容的某些部分在运行后很长一段时间不会被读取,也不保证在执行期间过一会儿不会再次读取相同的页面。
jlliagre 2013年

@jlliagre是的,但这不是我的意思。也许我在回答中说了一些话,我会尽力使我的意思更清楚。
克里斯·
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.