简短的回答:看起来挂载传播的类型设置不正确。
解释
Linux 内核默认所有挂载为MS_PRIVATE
,但 systemd在早期启动时会覆盖它MS_SHARED
,以方便 nspawn。这可以通过查看 的可选字段来观察/proc/$PID/mountinfo
。例如,可能会出现这样的情况:
$ cat /proc/self/mountinfo
. . .
25 0 8:6 / / rw,relatime shared:1 - ext4 /dev/sda6 rw,errors=remount-ro,data=ordered
^^^^^^
. . .
注意上面带下划线的(by me)shared:1
字段,表示当前/
挂载点的传播类型是MS_SHARED
,peer group ID 是1
(在我们的例子中我们根本不关心peer group ID)。
当在新的挂载命名空间上使用该CLONE_NEWNS
标志时,clone(2)
会创建一个新的挂载命名空间,该命名空间被初始化为调用者的挂载命名空间的副本。新命名空间的新复制挂载点与调用者挂载命名空间中它们各自的原始挂载点加入同一个对等组。
父传播类型为MS_SHARED
,的新挂载点的传播类型MS_SHARED
也是。因此,当您的“包含”进程mount()
是循环设备上的文件系统时,默认情况下挂载是MS_SHARED
. 后来,它下面的所有挂载也传播到“主”进程的命名空间,这就是“主”进程可以看到它们的原因。
为了满足您的请求(对于“主”进程看不到“包含”进程的挂载点),您寻求的挂载传播类型是MS_SLAVE
或MS_PRIVATE
,具体取决于您是否希望“包含”进程的根挂载点接收传播是否来自其他对等方的事件,分别。显然,MS_PRIVATE
提供了比 更大的隔离MS_SLAVE
。
因此,在您的情况下,将“包含”进程的根安装点的传播类型更改为MS_PRIVATE
或在安装其余文件系统MS_SLAVE
之前就足够了,因此安装不会传播到“主”进程的命名空间。
编码
首先,当“包含”进程创建其根挂载点时,会尝试正确设置传播类型。
man 8 mount
但是,我在(引用)中注意到以下内容:
请注意,Linux 内核不允许使用单个 mount(2) 系统调用更改多个传播标志,并且这些标志不能与其他挂载选项混合使用。
从 util-linux 2.23 开始, mount 命令允许一起使用多个传播标志,也可以与其他挂载操作一起使用。此功能是实验性的。当前面的挂载操作成功时,附加的 mount(2) 系统调用会应用传播标志。
查看您的代码,“包含”进程,在它mount()
成为循环设备上的文件系统之后,它会chroot()
向它发出。此时,您可以通过注入此mount(2)
调用来设置其传播类型:
if (chroot(".") < 0) {
// handle error
}
if (mount("/", "/", c->fstype, MS_PRIVATE, "") < 0) {
// handle error
}
if (mkdir(...)) {
// handle error
}
现在传播类型设置为MS_PRIVATE
,“包含”进程执行的所有后续挂载/
都不会传播,因此不会在“主”进程的命名空间中可见,正如您可以在/proc/mounts
或中观察到的那样/proc/$PID/mountinfo
。
资源