為什麼 mount 不尊重綁定掛載的只讀選項?
在我的 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 核心上,執行 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
將創建一個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