我遇到了一个问题,如果我.so
在进程仍在运行时更新加载符号链接 .so 文件的进程,则会崩溃。
我有长时间运行的进程,它们在首次启动时加载共享库 (.so),并且可能会在进程运行后很长时间后最终使用这些共享库。进程加载的共享库实际上是实际.so
s 的符号链接(将所有.so
s 放在与每个进程相关的结构化目录中)。有时我需要应用一些修复并重新编译 .so 文件,但我发现当我这样做时,一些长时间运行的进程在访问我更新的 .so 中的符号时会崩溃。
根据我的理解,如果进程加载实际的 .so 而不是符号链接,我不应该看到这种行为,因为当我重新编译 .so (它删除并使用新的 inode 重新创建 .so 文件)时,旧的 inode .so 应该仍然存在,直到所有打开它的进程都将其关闭。我认为我看到的问题是由于进程打开符号链接而不是目标 .so,因此长时间运行的进程仅保留符号链接 inode 而不是目标.so
s inode。但我没有足够的信息来证实我的理论是正确的。
文件的索引节点是否会一直存在,直到所有处理器都关闭它?这是否适用于映射文件但不为其打开文件描述符的进程?
符号链接的 open/mmap 是否只跟踪符号链接的索引节点?或者它是否也可以防止操作系统破坏目标文件的索引节点?
答案1
是的,在 Linux(以及所有其他 POSIX 兼容内核)上,文件的索引节点确实会一直存在,直到所有处理器都关闭它。这包括映射文件。
这是由POSIX:
mmap() 函数添加对与文件描述符 fildes 关联的文件的额外引用,该文件描述符上的后续 close() 不会删除该引用。当不再有到该文件的映射时,该引用将被删除。
符号链接的 Open/mmap 仅跟踪该索引节点目标文件(除了使用 的边缘情况
O_PATH
)。调用时会解析路径中的所有符号链接open()
,文件描述符仅引用目标文件。你可以测试一下:
- 创建一个文件
/tmp/original
- 创建一个符号链接
/tmp/symlink
指向/tmp/original
/tmp/symlink
在程序中 打开,例如在 Python shell 中输入f = open('/tmp/symlink', 'r')
- 看着
/proc/<pid of the program>/fd
- 文件描述符将指向
/tmp/original
- 创建一个文件
请检查重新编译时,.so 文件是否确实被删除并重新创建,而不是直接写入,并且长时间运行的进程没有使用例如dlopen
动态重新打开 .so 文件。
我能想到的另一种可能性是,延迟绑定会导致长时间运行的进程中 .so 文件的加载被推迟。
您可以尝试在环境中启动长时间运行的进程LD_BIND_NOW=1
,然后观察重新编译是否仍然使进程崩溃,以检查问题是否是由延迟绑定引起的。