Linux

為什麼 mount 不尊重綁定掛載的只讀選項?

  • January 4, 2019

在我的 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 中使用。使綁定掛載尊重初始掛載的只讀選項有什麼困難?

綁定掛載只是……嗯……綁定掛載。即它不是一個新的坐騎。它只是“連結”/“公開”/“考慮”一個子目錄作為新的掛載點。因此它不能改變掛載參數。這就是你收到投訴的原因:

# 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 remount 也可以:

# 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):

核心有兩個控制只讀的標誌:

  • The MS_READONLY: 表示掛載是否為只讀
  • The 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-07-20 #2:

對此進行深入研究表明,行為實際上取決於 libmount 的版本,它是 util-linux 的一部分。此送出添加了對此的支持,並與版本 2.27 一起發布:

送出 9ac77b8a78452eab0612523d27fee52159f5016a
作者:卡雷爾扎克
日期:2015 年 8 月 17 日星期一 11:54:26 +0200

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

現在有必要使用兩個 mount(8) 呼叫來創建一個只讀的
山:

mount /foo /bar -o 綁定
mount /bar -o remount,ro,bind

此更新檔允許指定“bind,ro”並完成重新掛載
通過額外的 mount(2) 系統呼叫由 libmount 自動執行。它不是
當然是原子的。

簽字人: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

引用自:https://unix.stackexchange.com/questions/128336