結論:

結論:

在我的 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)系統呼叫的語意有些奇怪:

  • 第一次呼叫建立綁定安裝,所有其他標誌都被忽略
  • 第二次調用(重新安裝)設定掛載點標記為唯讀

相關內容