Linux:如何為分層綁定掛載保留只讀模式
讓我們為這個問題提供一些背景資訊:
- 有
/foo/bar
目錄處於讀寫模式- 有
/bar
綁定掛載指向/foo/bar
- 在
/foo/bar
其中有bar
必須處於只讀模式的目錄(/foo/bar/baz
和/bar/baz
)為了使
/foo/bar/baz
只讀我這樣做另一個綁定:$ sudo mount -o bind,ro /foo/bar/baz /foo/bar/baz $ sudo touch /foo/bar/baz/test touch: cannot touch '/foo/bar/baz/test': Read-only file system $ mount | grep bar /dev/vda1 on /bar type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota) /dev/vda1 on /foo/bar/baz type xfs (ro,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota) /dev/vda1 on /bar/baz type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota)
PS 有
/foo/bar/baz
,/bar/baz
但後者不是只讀的。但是
/bar/baz
是可寫的:$ sudo touch /bar/baz/test $ echo $? 0
嘗試進行另一個綁定:
$ sudo mount -o bind,ro /bar/baz /bar/baz $ mount | grep bar /dev/vda1 on /bar type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota) /dev/vda1 on /foo/bar/baz type xfs (ro,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota) /dev/vda1 on /bar/baz type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota) /dev/vda1 on /bar/baz type xfs (ro,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota) /dev/vda1 on /foo/bar/baz type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota) /dev/vda1 on /foo/bar/baz type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota) /dev/vda1 on /bar/baz type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota)
真正讓我困惑的是:
- 為什麼現在有3個相同的坐騎
/bar/baz
?沒有,一次綁定後我得到三個:/dev/vda1 on /bar/baz type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota) /dev/vda1 on /bar/baz type xfs (ro,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota) /dev/vda1 on /bar/baz type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota)
兩個是讀寫的,一個是只讀的。哪個優先?似乎是只讀的:
$ sudo touch /bar/baz/test touch: cannot touch '/bar/baz/test': Read-only file system
但這不是最後一個,只讀的在中間。 2. 為什麼現在有 3 個掛載
/foo/bar/baz
,只有一個只讀的,現在我有 3 個:/dev/vda1 on /foo/bar/baz type xfs (ro,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota) /dev/vda1 on /foo/bar/baz type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota) /dev/vda1 on /foo/bar/baz type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota)
一個只讀,兩個讀寫。什麼優先?結果不是只讀的,因為它是可寫的:
$ sudo touch /foo/bar/baz/test $ echo $? 0
為什麼會這樣?以及如何避免?使兩者
/foo/bar/baz
同時/bar/baz
成為只讀的正確方法是什麼?
aviro的回答完全涵蓋了解釋部分: https ://unix.stackexchange.com/a/689950/513617
我找到了一個很好的解決方案,它不添加任何額外的讀寫掛載。是
remount
選項。
mount -o bind /foo/bar /bar
mount -o bind,ro /foo/bar/baz /foo/bar/baz
- 然後採用現有的讀寫
/bar/baz
傳播綁定和remount
它:
mount -o bind,ro,remount /foo/bar/baz /bar/baz
之後你只得到這些:
$ mount | grep bar /dev/vda1 on /bar type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota) /dev/vda1 on /foo/bar/baz type xfs (ro,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota) /dev/vda1 on /bar/baz type xfs (ro,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota)
TL;博士
預設情況下,
/bar
和/foo/bar
是共享掛載。這意味著在您將某些內容綁定到文件夾中後/foo/bar
,它會傳播到/bar
,而且當您將某些內容安裝到文件夾中時/bar
,它也會傳播回/foo/bar
。從手冊頁
mount(8)
:…共享掛載提供了創建該掛載的鏡像的能力,以便任何鏡像中的掛載和解除安裝傳播到另一個鏡像。…
由於您綁定 mount
/bar/baz
on/bar/baz
,因此它會傳播回/foo/bar/baz
(asrw
)。有兩種選擇:
選項1
而不是執行:
mount -o bind,ro /bar/baz /bar/baz
跑:
mount -o bind,ro /foo/bar/baz /bar/baz
由於您現在從 original 掛載
/foo/bar
,因此它不會被傳播回那裡。選項 #2
你需要做
/bar
一個奴隸。/foo/bar
同樣,從手冊頁
mount(8)
:…從掛載接收來自其主掛載的傳播,但反之則不然。…
所以不要執行:
mount -o bind /foo/bar /bar
跑:
mount --make-rslave -o bind /foo/bar /bar
這是唯一的區別。然後您可以將 mount 綁定
/foo/bar/baz
為只讀(此時/bar/baz
仍然是讀/寫),然後將 mount 綁定/bar/baz
為只讀,而不會干擾您之前在/foo/bar/baz
.解釋問題
如果我們重新創建您的步驟,我們將看到以下內容:
(1)
mount -o bind /foo/bar /bar
您可以在 中查看結果
/proc/self/mountinfo
。為了了解不同的欄位,您需要閱讀以下手冊頁
proc(5)
:/proc/[pid]/mountinfo (since Linux 2.6.26) This file contains information about mount points. It contains lines of the form: 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) The numbers in parentheses are labels for the descriptions below: (1) mount ID: unique identifier of the mount (may be reused after umount(2)). (2) parent ID: ID of parent mount (or of self for the top of the mount tree).
現在讓我們檢查一下
/proc/self/mountinfo
:# grep bar /proc/self/mountinfo 146 65 8:1 /foo/bar /bar rw,relatime shared:1 - xfs /dev/sda1 rw,attr2,inode64,logbsize=256k,sunit=512,swidth=512,noquota # grep ^65 /proc/self/mountinfo 65 0 8:1 / / rw,relatime shared:1 - xfs /dev/sda1 rw,attr2,inode64,logbsize=256k,sunit=512,swidth=512,noquota
- 安裝 ID 146,
/foo/bar
是安裝在/bar
.- 它的父 ID 是65,即根分區 (
/
)。另外,請注意
/foo/bar
安裝/bar
為shared。(2)
mount -o bind,ro /foo/bar/baz /foo/bar/baz
- 這會創建一個從 /foo/bar/baz 到 /foo/bar/baz 的只讀綁定掛載。
- 它也傳播到
/bar
這意味著它/foo/bar/baz
也安裝在/bar/baz
.- 但正如我所說,該
ro
選項沒有傳播,所以/bar/baz
仍然是rw
.你可以看到它
/proc/self/mountinfo
:# grep bar /proc/self/mountinfo 146 65 8:1 /foo/bar /bar rw,relatime shared:1 - xfs /dev/sda1 rw,attr2,inode64,logbsize=256k,sunit=512,swidth=512,noquota 182 65 8:1 /foo/bar/baz /foo/bar/baz ro,relatime shared:1 - xfs /dev/sda1 rw,attr2,inode64,logbsize=256k,sunit=512,swidth=512,noquota 183 146 8:1 /foo/bar/baz /bar/baz rw,relatime shared:1 - xfs /dev/sda1 rw,attr2,inode64,logbsize=256k,sunit=512,swidth=512,noquota
1. 結果182
/foo/bar/baz
安裝在頂部/foo/bar/baz
(2)ro
2. 146
/foo/bar
安裝上/bar
作為**(1)**的結果。
- 結果, 183
/foo/bar/baz
再次安裝在頂部/bar/baz
( **2)**上。rw
重要的注意事項是掛載選項(例如,
ro
)不會與掛載一起傳播。/foo/bar/baz
被傳播到/bar/baz
,但沒有ro
選項。所以 now
/foo/bar/baz
被掛載一次/foo/bar/baz
(作為只讀)和一次/bar/baz
(作為讀/寫,作為從 傳播的結果/foo/bar
)。(3)
mount -o bind,ro /bar/baz /bar/baz
- 這會創建一個從 /bar/baz 到 /bar/baz 的只讀綁定掛載。
- 它也傳播到
/foo/bar
這意味著它/bar/baz
也安裝在/foo/bar/baz
.- 但同樣,該
ro
選項沒有傳播,所以/foo/bar/baz
現在是讀寫。# grep bar /proc/self/mountinfo 146 65 8:1 /foo/bar /bar rw,relatime shared:1 - xfs /dev/sda1 rw,attr2,inode64,logbsize=256k,sunit=512,swidth=512,noquota 182 202 8:1 /foo/bar/baz /foo/bar/baz ro,relatime shared:1 - xfs /dev/sda1 rw,attr2,inode64,logbsize=256k,sunit=512,swidth=512,noquota 183 201 8:1 /foo/bar/baz /bar/baz rw,relatime shared:1 - xfs /dev/sda1 rw,attr2,inode64,logbsize=256k,sunit=512,swidth=512,noquota 200 183 8:1 /foo/bar/baz /bar/baz ro,relatime shared:1 - xfs /dev/sda1 rw,attr2,inode64,logbsize=256k,sunit=512,swidth=512,noquota 203 182 8:1 /foo/bar/baz /foo/bar/baz rw,relatime shared:1 - xfs /dev/sda1 rw,attr2,inode64,logbsize=256k,sunit=512,swidth=512,noquota 202 65 8:1 /foo/bar/baz /foo/bar/baz rw,relatime shared:1 - xfs /dev/sda1 rw,attr2,inode64,logbsize=256k,sunit=512,swidth=512,noquota 201 146 8:1 /foo/bar/baz /bar/baz rw,relatime shared:1 - xfs /dev/sda1 rw,attr2,inode64,logbsize=256k,sunit=512,swidth=512,noquota
1. 146
/foo/bar
安裝上/bar
作為**(1)**的結果。
201
/foo/bar/baz
安裝在/bar/baz
.
- 結果183
/foo/bar/baz
然後再次安裝在頂部/bar/baz
( 2)rw
- 200 上面的再
/foo/bar/baz
安裝是由於**(3)**。/bar/baz``ro
2. 202
/foo/bar/baz
是原來的文件夾/
。
- 結果182
/foo/bar/baz
安裝在頂部/foo/bar/baz
( 2)ro
- 由於**(3)的結果,203
/foo/bar/baz
被重新**安裝。/foo/bar/baz``rw
現在
/foo/bar/baz
安裝一次/bar/baz
(作為只讀)和一次/foo/bar/baz
(作為讀/寫)。解決方案
(1)
mount --make-rslave -o bind /foo/bar /bar
# grep bar /proc/self/mountinfo 146 65 8:1 /foo/bar /bar rw,relatime master:1 - xfs /dev/sda1 rw,attr2,inode64,logbsize=256k,sunit=512,swidth=512,noquota
現在
/foo/bar
是大師:/bar
您可以從/foo/bar
to傳播 mounts/bar
,但 mounts on/bar
不會被傳播回 to/foo/bar
。(2)
mount -o bind,ro /foo/bar/baz /foo/bar/baz
# grep bar /proc/self/mountinfo 146 65 8:1 /foo/bar /bar rw,relatime master:1 - xfs /dev/sda1 rw,attr2,inode64,logbsize=256k,sunit=512,swidth=512,noquota 182 65 8:1 /foo/bar/baz /foo/bar/baz ro,relatime shared:1 - xfs /dev/sda1 rw,attr2,inode64,logbsize=256k,sunit=512,swidth=512,noquota 183 146 8:1 /foo/bar/baz /bar/baz rw,relatime master:1 - xfs /dev/sda1 rw,attr2,inode64,logbsize=256k,sunit=512,swidth=512,noquota
它類似於我們之前看到的,只是現在
/foo/bar
是 的主人/bar
,並且/foo/bar/baz
是 的主人/bar/baz
。(3)
mount -o bind,ro /bar/baz /bar/baz
# grep bar /proc/self/mountinfo 146 65 8:1 /foo/bar /bar rw,relatime master:1 - xfs /dev/sda1 rw,attr2,inode64,logbsize=256k,sunit=512,swidth=512,noquota 182 65 8:1 /foo/bar/baz /foo/bar/baz ro,relatime shared:1 - xfs /dev/sda1 rw,attr2,inode64,logbsize=256k,sunit=512,swidth=512,noquota 183 146 8:1 /foo/bar/baz /bar/baz rw,relatime master:1 - xfs /dev/sda1 rw,attr2,inode64,logbsize=256k,sunit=512,swidth=512,noquota 200 183 8:1 /foo/bar/baz /bar/baz ro,relatime master:1 - xfs /dev/sda1 rw,attr2,inode64,logbsize=256k,sunit=512,swidth=512,noquota
這是主要區別:現在只創建了新的坐騎,編號為200。
其餘的沒有改變。此掛載未傳播回
/foo/bar
,因此由於( 2)/foo/bar/baz
仍被掛載。/foo/bar/baz``ro
所以 now在和
/foo/bar/baz
上都以只讀方式掛載。/foo/bar/baz``/bar/baz