为什么不挂载尊重绑定挂载的只读选项?


35

在我的Arch Linux系统(Linux Kernel 3.14.2)上,绑定安装不遵守只读选项

# mkdir test
# mount --bind -o ro test/ /mnt
# touch /mnt/foo

创建文件/mnt/foo。中的相关条目/proc/mounts

/dev/sda2 /mnt ext4 rw,noatime,data=ordered 0 0

安装选项不符合我要求的选择,但这样做同时匹配绑定的读/写性能和安装使用的选项最初安装/dev/sda2/

/dev/sda2 / ext4 rw,noatime,data=ordered 0 0

但是,如果我重新安装了安装座,那么它将遵循只读选项

# mount --bind -o remount,ro test/ /mnt
# touch /mnt/bar
touch: cannot touch ‘/mnt/bar’: Read-only file system

和中的相关条目 /proc/mounts/

/dev/sda2 /mnt ext4 ro,relatime,data=ordered 0 0

看起来像我可能期望的(尽管实际上我期望看到test目录的完整路径)。on /proc/mounts/的原始安装的条目也未更改,并且保持读/写状态/dev/sda2//

/dev/sda2 / ext4 rw,noatime,data=ordered 0 0

此行为和解决方法至少从2008年开始就为人所知,并记录在mount

请注意,文件系统挂载选项将与原始挂载点上的选项相同,并且不能通过将-o选项与--bind /-rbind一起传递来更改。可以通过单独的重新安装命令更改安装选项

并非所有发行版的行为都相同。当绑定安装未获得只读安装时,Debian生成警告时,Arch似乎默默地不遵守这些选项

mount: warning: /mnt seems to be mounted read-write.

有报道称,这种行为在Debian Lenny和Squeeze中已“修复”,尽管它似乎不是通用解决方案,但在Debian Wheezy中仍然不起作用。使绑定安装尊重初始安装上的只读选项有何困难?


您有/ etc / mtab吗?
eyoung100 2014年


@ECarterYoung是的,我有一个/etc/mtab。初始安装后,该条目显示安装为rw,重新安装后显示为ro,因此它正确报告了安装状态。只是mount命令失败。
StrongBad 2014年

3
我在两台Debian测试/不稳定的机器上进行了测试,其中一台运行Debian内核,一台运行kernel.org内核,两者都不兼容mount --bind -o ro,它们都发出一条消息,mount: warning: «mountpoint» seems to be mounted read-write.因此Debian似乎在某个时候掉线或丢失了补丁...重新安装虽然有效。
德罗伯特2014年

2
@StrongBad根据要求测试了该方法,它也不起作用。
derobert

Answers:


21

绑定安装只是...好...绑定安装。也就是说,这不是一个新的坐骑。它只是“链接” /“公开” /“考虑”子目录作为新的安装点。因此,它不能更改安装参数。这就是为什么您会收到投诉的原因:

# mount /mnt/1/lala /mnt/2 -o bind,ro
mount: warning: /mnt/2 seems to be mounted read-write.

但是正如您所说,正常的绑定安装有效:

# mount /mnt/1/lala /mnt/2 -o bind

然后重新安装ro也可以:

# mount /mnt/1/lala /mnt/2 -o bind,remount,ro 

但是,发生的是您正在更改整个安装,而不仅仅是此绑定安装。如果查看/ proc / mounts,您会发现绑定安装和原始安装都变为只读:

/dev/loop0 /mnt/1 ext2 ro,relatime,errors=continue,user_xattr,acl 0 0
/dev/loop0 /mnt/2 ext2 ro,relatime,errors=continue,user_xattr,acl 0 0

因此,您要做的就像将初始安装更改为只读安装,然后执行绑定安装,该安装当然将是只读的。

更新2016-07-20:

以下内容适用于4.5内核,但不适用于4.3内核(这是错误的。请参见下面的更新#2):

内核有两个控制只读的标志:

  • MS_READONLY:指示是否安装为只读
  • MNT_READONLY:表示“用户”是否需要它只读

在4.5内核上,执行a mount -o bind,ro实际上可以解决问题。例如,这:

# mkdir /tmp/test
# mkdir /tmp/test/a /tmp/test/b
# mount -t tmpfs none /tmp/test/a
# mkdir /tmp/test/a/d
# mount -o bind,ro /tmp/test/a/d /tmp/test/b

将创建一个只读的绑定安装的/tmp/test/a/d/tmp/test/b,这将是可见/proc/mounts的:

none /tmp/test/a tmpfs rw,relatime 0 0
none /tmp/test/b tmpfs ro,relatime 0 0

在中可以看到更详细的视图/proc/self/mountinfo,其中考虑了用户视图(命名空间)。相关行如下:

363 74 0:49 / /tmp/test/a rw,relatime shared:273 - tmpfs none rw
368 74 0:49 /d /tmp/test/b ro,relatime shared:273 - tmpfs none rw

在第二行的第二行中,您会看到它同时显示roMNT_READONLY)和rw!MS_READONLY)。

最终结果是这样的:

# echo a > /tmp/test/a/d/f
# echo a > /tmp/test/b/f
-su: /tmp/test/b/f: Read-only file system

更新2016-07-20#2:

进一步研究表明,该行为实际上取决于util-linux一部分的libmount版本。为此提交添加了对此的支持,并在2.27版中发布了该支持:

提交9ac77b8a78452eab0612523d27fee52159f5016a
作者:Karel Zak 
日期:2015年8月17日星期一11:54:26 +0200

    libmount:添加对“ bind,ro”的支持

    现在必须使用两个mount(8)调用来创建一个只读
    安装:

      挂载/ foo / bar -o绑定
      挂载/ bar -o remount,ro,bind

    此修补程序允许指定“ bind,ro”,并且重新安装完成
    由libmount自动执行,由附加的mount(2)系统调用执行。不是
    当然是原子的。

    签字人:Karel Zak 

这也提供了解决方法。可以在较旧和较新的安装上使用strace看到此行为:

旧:

mount("/tmp/test/a/d", "/tmp/test/b", 0x222e240, MS_MGC_VAL|MS_RDONLY|MS_BIND, NULL) = 0 <0.000681>

新:

mount("/tmp/test/a/d", "/tmp/test/b", 0x1a8ee90, MS_MGC_VAL|MS_RDONLY|MS_BIND, NULL) = 0 <0.011492>
mount("none", "/tmp/test/b", NULL, MS_RDONLY|MS_REMOUNT|MS_BIND, NULL) = 0 <0.006281>

结论:

为了获得理想的结果,需要运行两个命令(如@Thomas所述):

mount SRC DST -o bind
mount DST -o remount,ro,bind

较新版本的mount(util-linux> = 2.27)在运行时自动执行此操作

mount SRC DST -o bind,ro

3
是的,但是没有。IIRC在内核中对不同的挂载点(不是文件系统)有不同的支持。Debian曾经有一个补丁程序,可以mount -o bind,ro创建一个读写文件系统的只读视图(但是似乎不再像以前那样)。
吉尔(Gilles)'所以

我不认为这与上述矛盾。黑客可以允许各种各样的东西,包括没有太大意义的东西。当前,在3.14内核上的只读重新挂载最终由以下调用处理:mnt_make_readonly(real_mount(mnt)),如您所见,它使用real_mount(),因此实际上会影响实际挂载,并导致绑定挂载反映新的挂载。 (只读)安装标志。至少那是我的理解。
V13

因此,这可能是“扩展结构安装”补丁(特别是此commit)的结果,该补丁首先出现在内核3.3中。您知道是否在lkml或lwn上讨论了此补丁的后果吗?
吉尔斯(Gillles)“所以-别再作恶了”

7
mount --bind /tmp/ /mnt/tmp/; mount -o remount,bind,ro /mnt/tmp/...然后touch /tmp/a可以,但是touch /mnt/tmp/btouch: cannot touch ‘/mnt/tmp/b’: Read-only file system。这在Debian 3.13和kernel.org 3.14.2上均适用。因此,它不仅会改变整个安装。至少不是最近的内核。
德罗伯特

1
大概是“绑定安装只是...好...绑定安装”的陈述。真的很重要,但对我而言毫无意义。我也不明白为什么它第二次可以通过remount选项工作。
StrongBad 2014年

9

正确的解决方案是将它挂载两次。在命令行上:

mount -t none -o bind /source/dir /destination/dir
mount -t none -o bind,remount,ro /source/dir /destination/dir

/etc/fstab

/source/dir            /destination/dir    none  bind            0 0
/source/dir            /destination/dir    none  remount,bind,ro 0 0

手册(man mount)表示如下:

   The bind mounts.
          Since Linux 2.4.0 it is possible to remount part of the file hierarchy somewhere else. The call is
                 mount --bind olddir newdir
   [...]
          Note that the filesystem mount options will remain the same as those on the original mount point, and cannot be changed  by  passing  the  -o  option
          along with --bind/--rbind. The mount options can be changed by a separate remount command, for example:
          .
                 mount --bind olddir newdir
                 mount -o remount,ro newdir
          .
          Note  that  behavior  of  the remount operation depends on the /etc/mtab file. The first command stores the 'bind' flag to the /etc/mtab file and the
          second command reads the flag from the file.  If you have a system without the /etc/mtab file or if you explicitly define source and target  for  the
          remount command (then mount(8) does not read /etc/mtab), then you have to use bind flag (or option) for the remount command too. For example:
          .
                 mount --bind olddir newdir
                 mount -o remount,ro,bind olddir newdir

这似乎至少在Ubuntu 14.04 LTS和内核3.19.0-51-lowlatency上有效。真好!
Mikko Rantalainen

0

您是mount(8)从命令行角度询问的(在此站点上可以接受)。该命令已在其他答案中进行了讨论,在某些情况下,它抽象出了必要的第二个mount(2)系统调用。

但是为什么需要第二个系统调用?为什么一个mount(2)调用不能创建只读绑定安装?

mount(2)手册页解释说,有,正如其他人所指出的那样,两套标志是一套:

  • 基础文件系统标志
  • VFS安装点标志

它说:

从Linux 2.6.16开始,MS_RDONLY可以在每个安装点以及基础文件系统上进行设置或清除。仅当文件系统和挂载点均未标记为只读时,挂载的文件系统才可写。

关于MS_REMOUNT

从Linux 2.6.26开始,此标志可用于MS_BIND仅修改每个安装点标志。这对于在不更改基础文件系统的情况下设置或清除安装点上的“只读”标志特别有用。将mountflags指定为:

      MS_REMOUNT | MS_BIND | MS_RDONLY

将使通过此挂载点的访问为只读,而不会影响其他挂载点。

我认为问题出在绑定绑定首次引入时:

如果包含mountflags MS_BIND(自Linux 2.4起可用),请执行绑定安装。...除了以外,mountflags参数中的其余位也将被忽略MS_REC。(绑定安装具有与基础安装点相同的安装选项。)

看起来MS_BIND | MS_REMOUNT,与其使用信号作为仅设置VFS标志的替代方法,他们还可以选择MS_RDONLY与initial一起除外(并接受)MS_BIND并将其应用于安装点。

因此,由于mount(2)系统调用的语义有些奇怪:

  • 第一次调用将创建绑定安装,所有其他标志将被忽略
  • 第二个调用(带重新安装)将安装点标志设置为只读
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.