总结一下:如果您在新的挂载命名空间之上绑定挂载了一个文件,但随后父命名空间中的 inode 发生了/tmp/a
变化,则该绑定挂载会在子命名空间中消失。我试图理解为什么。/tmp/b
/tmp/b
mount(8) 不会公开绑定挂载单个文件(仅目录)的功能,因此重现此操作需要一个额外的可执行文件来发出必要的 mount(2) 系统调用。下面是一个简单的例子(参考如下bmount
):
#include <sys/mount.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("requires exactly 2 args\n");
return 1;
}
int err = mount(argv[1], argv[2], "none", MS_BIND, NULL);
if (err == 0) {
return 0;
} else {
printf("mount error (%d): %s\n", errno, strerror(errno));
return 1;
}
}
设置测试用例:
# echo a > /tmp/a; echo b > /tmp/b; echo c > /tmp/c;
# ls -ldi /tmp/a /tmp/b /tmp/c
11403315 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/a
11403422 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/b
11403452 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/c
现在,在一个单独的 shell 中:
# unshare -m /bin/bash
# bmount /tmp/a /tmp/b
# ls -ldi /tmp/a /tmp/b /tmp/c
11403315 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/a
11403315 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/b
11403452 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/c
# cat /tmp/b
a
# grep "\/tmp\/" /proc/self/mounts
[redacted] /tmp/b ext4 rw,relatime,errors=remount-ro,data=ordered 0 0
在原始外壳中:
# mv /tmp/c /tmp/b
# ls -ldi /tmp/a /tmp/b /tmp/c
ls: cannot access '/tmp/c': No such file or directory
11403315 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/a
11403452 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/b
在unshare
外壳中:
# ls -ldi /tmp/a /tmp/b /tmp/c
ls: cannot access '/tmp/c': No such file or directory
11403315 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/a
11403452 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/b
# cat /tmp/b
c
# grep "\/tmp\/" /proc/self/mounts
#
绑定挂载已悄然消失,底层文件系统的/tmp/b
文件现在在命名空间内可见。
我找到了一个lwn.net 文章这里描述了语义上的变化:在 2013 年之前,挂载点上mv
的命令将失败并显示,但行为已更改,以便它会成功,然后挂载将被删除。相关的内核提交似乎是rename(2)
EBUSY
8ed936b5671。
我的问题是:
- 为什么在任何 inode 更改时都会删除挂载?它是否只是挂载系统的一个实现细节,其中挂载点由 dentry 而不是简单的路径来标识?
- 有没有一种方法可以使绑定安装变得不那么“脆弱”,因为它们不能被名称空间之外的文件系统操作覆盖或删除?
与实践相关的一种情况是ip-netns(8);ip netns exec
通过绑定安装/etc/netns/${NAMESPACE}/resolv.conf
在/etc/resolv.conf
.如果/etc/resolv.conf
resolvconf(8) 或 systemd-resolved 更改了inode ,则更新后的内容/etc/resolv.conf
对于命名空间内运行的进程将是可见的。
答案1
这就是安装传播。 Linux 默认情况下不启用它,但 systemd 会启用它。如果您不希望安装和卸载传播到新的命名空间,您可以。旁白:这不是挂载传播。mount --make-rprivate /
在其中运行。
为什么在任何 inode 更改时都会删除挂载?它是否只是挂载系统的一个实现细节,其中挂载点由 dentry 而不是简单的路径来标识?
我想说,你可以期望rm b; mv c b
和之间唯一的不同mv c b
是,不可能b
在任何时候观察到不存在。我将其描述为一个经过精心设计或维护的功能...我不确定历史上的多用户 Unix 系统在多大程度上是这样,但它确实被依赖于例如支持软件更新在正在运行的系统上。
我……能想到正是为您所谓的“inode 更改”而实现的另一项特定功能- 这是不情愿地完成的,并且是特定于文件系统的。