结论:

结论:

在我的 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 来更改。可以通过单独的重新安装命令更改安装选项

并非所有发行版的行为都相同。 Arch 似乎默默地不尊重这些选项,而 Debian 在绑定挂载未获得只读挂载时会生成警告

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

有报道称此行为已在 Debian 中“修复”莱尼和挤压虽然它看起来不是一个通用修复它在 Debian Wheezy 中也不起作用。使绑定安装尊重初始安装上的只读选项有什么困难?

答案1

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

# 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 年 7 月 20 日更新:

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

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

  • MS_READONLY表示挂载是否为只读
  • MNT_READONLY指示“用户”是否希望它只读

在 4.5 内核上,执行 amount -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将创建to的只读绑定挂载/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

在第二行,您可以看到它同时显示了ro( MNT_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 年 7 月 20 日更新#2:

进一步深入研究表明,该行为实际上取决于 libmount 的版本,libmount 是 util-linux 的一部分。添加了对此的支持犯罪并随版本 2.27 一起发布:

提交 9ac77b8a78452eab0612523d27fee52159f5016a
作者:卡雷尔·扎克
日期:2015 年 8 月 17 日星期一 11:54:26 +0200

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

    现在有必要使用两个 mount(8) 调用来创建只读
    山:

      挂载 /foo /bar -o 绑定
      安装 /bar -o 重新安装,ro,绑定

    该补丁允许指定“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

答案2

正确的解决方案实际上是安装两次。在命令行上:

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

答案3

您是从命令行的角度提问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_RDONLYMS_BIND

因为mount(2)系统调用的语义有些奇怪:

  • 第一次调用创建绑定安装,所有其他标志都被忽略
  • 第二次调用(重新安装)设置挂载点标记为只读

相关内容