unlink/rm 打开符号链接的目标

unlink/rm 打开符号链接的目标

我遇到了一个问题,如果我.so在进程仍在运行时更新加载符号链接 .so 文件的进程,则会崩溃。

我有长时间运行的进程,它们在首次启动时加载共享库 (.so),并且可能会在进程运行后很长时间后最终使用这些共享库。进程加载的共享库实际上是实际.sos 的符号链接(将所有.sos 放在与每个进程相关的结构化目录中)。有时我需要应用一些修复并重新编译 .so 文件,但我发现当我这样做时,一些长时间运行的进程在访问我更新的 .so 中的符号时会崩溃。

根据我的理解,如果进程加载实际的 .so 而不是符号链接,我不应该看到这种行为,因为当我重新编译 .so (它删除并使用新的 inode 重新创建 .so 文件)时,旧的 inode .so 应该仍然存在,直到所有打开它的进程都将其关闭。我认为我看到的问题是由于进程打开符号链接而不是目标 .so,因此长时间运行的进程仅保留符号链接 inode 而不是目标.sos inode。但我没有足够的信息来证实我的理论是正确的。

  1. 文件的索引节点是否会一直存在,直到所有处理器都关闭它?这是否适用于映射文件但不为其打开文件描述符的进程?

  2. 符号链接的 open/mmap 是否只跟踪符号链接的索引节点?或者它是否也可以防止操作系统破坏目标文件的索引节点?

答案1

  1. 是的,在 Linux(以及所有其他 POSIX 兼容内核)上,文件的索引节点确实会一直存在,直到所有处理器都关闭它。这包括映射文件。

    这是由POSIX:

    mmap() 函数添加对与文件描述符 fildes 关联的文件的额外引用,该文件描述符上的后续 close() 不会删除该引用。当不再有到该文件的映射时,该引用将被删除。

  2. 符号链接的 Open/mmap 仅跟踪该索引节点目标文件(除了使用 的边缘情况O_PATH)。调用时会解析路径中的所有符号链接open(),文件描述符仅引用目标文件。

    你可以测试一下:

    1. 创建一个文件/tmp/original
    2. 创建一个符号链接/tmp/symlink指向/tmp/original
    3. /tmp/symlink在程序中 打开,例如在 Python shell 中输入f = open('/tmp/symlink', 'r')
    4. 看着/proc/<pid of the program>/fd
    5. 文件描述符将指向/tmp/original

请检查重新编译时,.so 文件是否确实被删除并重新创建,而不是直接写入,并且长时间运行的进程没有使用例如dlopen动态重新打开 .so 文件。

我能想到的另一种可能性是,延迟绑定会导致长时间运行的进程中 .so 文件的加载被推迟。

您可以尝试在环境中启动长时间运行的进程LD_BIND_NOW=1,然后观察重新编译是否仍然使进程崩溃,以检查问题是否是由延迟绑定引起的。

相关内容