Linux mount (第二部分 - Shared subtrees)

簡單點說,Shared subtrees就是一種控制子掛載點可否在其餘地方被看到的技術,它只會在bind mount和mount namespace中用到,屬於不怎麼經常使用的功能。本篇將以bind mount爲例對Shared subtrees作一個簡單介紹,ubuntu

本篇全部例子都在ubuntu-server-x86_64 16.04下執行經過segmentfault

概述

回想一下上一篇中介紹的bind mount部分,若是bind在一塊兒的兩個目錄下的子目錄再掛載了設備的話,他們之間還能相互看到子目錄裏掛載的內容嗎? 好比在第一個目錄下的子目錄裏面再mount了一個設備,那麼在另外一個目錄下面能看到這個mount的設備裏面的東西嗎?答案是要看bind mount的propagation type。那什麼是propagation type呢?bash

peer group和propagation type都是隨着shared subtrees一塊兒被引入的概念,下面分別對他們作一個介紹。測試

peer group

peer group就是一個或多個掛載點的集合,他們之間能夠共享掛載信息。目前在下面兩種狀況下會使兩個掛載點屬於同一個peer group(前提條件是掛載點的propagation type是shared)spa

  • 利用mount --bind命令,將會使源和目的掛載點屬於同一個peer group,固然前提條件是‘源’必需要是一個掛載點。.net

  • 當建立新的mount namespace時,新namespace會拷貝一份老namespace的掛載點信息,因而新的和老的namespace裏面的相同掛載點就會屬於同一個peer group。code

propagation type

每一個掛載點都有一個propagation type標誌, 由它來決定當一個掛載點的下面建立和移除掛載點的時候,是否會傳播到屬於相同peer group的其餘掛載點下去,也即同一個peer group裏的其餘的掛載點下面是否是也會建立和移除相應的掛載點.如今有4種不一樣類型的propagation type:server

  • MS_SHARED: 從名字就能夠看出,掛載信息會在同一個peer group的不一樣掛載點之間共享傳播. 當一個掛載點下面添加或者刪除掛載點的時候,同一個peer group裏的其餘掛載點下面也會掛載和卸載一樣的掛載點繼承

  • MS_PRIVATE: 跟上面的恰好相反,掛載信息根本就不共享,也即private的掛載點不會屬於任何peer group遞歸

  • MS_SLAVE: 跟名字同樣,信息的傳播是單向的,在同一個peer group裏面,master的掛載點下面發生變化的時候,slave的掛載點下面也跟着變化,但反之則否則,slave下發生變化的時候不會通知master,master不會發生變化。

  • MS_UNBINDABLE: 這個和MS_PRIVATE相同,只是這種類型的掛載點不能做爲bind mount的源,主要用來防止遞歸嵌套狀況的出現。這種類型不常見,本篇將不介紹這種類型,有興趣的同窗請參考這裏的例子

還有一些概念須要澄清一下:

  • propagation type是掛載點的屬性,每一個掛載點都是獨立的

  • 掛載點是有父子關係的,好比掛載點/和/mnt/cdrom,/mnt/cdrom都是‘/’的子掛載點,‘/’是/mnt/cdrom的父掛載點

  • 默認狀況下,若是父掛載點是MS_SHARED,那麼子掛載點也是MS_SHARED的,不然子掛載點將會是MS_PRIVATE,跟爺爺掛載點沒有關係

示例

這裏將只演示bind mount的狀況,mount namespace的狀況請參考這裏

準備環境

#準備4個虛擬的disk,並在上面建立ext2文件系統,用於後續的mount測試
dev@ubuntu:~$ mkdir disks && cd disks
dev@ubuntu:~/disks$ dd if=/dev/zero bs=1M count=32 of=./disk1.img
dev@ubuntu:~/disks$ dd if=/dev/zero bs=1M count=32 of=./disk2.img
dev@ubuntu:~/disks$ dd if=/dev/zero bs=1M count=32 of=./disk3.img
dev@ubuntu:~/disks$ dd if=/dev/zero bs=1M count=32 of=./disk4.img
dev@ubuntu:~/disks$ mkfs.ext2 ./disk1.img
dev@ubuntu:~/disks$ mkfs.ext2 ./disk2.img
dev@ubuntu:~/disks$ mkfs.ext2 ./disk3.img
dev@ubuntu:~/disks$ mkfs.ext2 ./disk4.img
#準備兩個目錄用於掛載上面建立的disk
dev@ubuntu:~/disks$ mkdir disk1 disk2
dev@ubuntu:~/disks$ ls
disk1  disk1.img  disk2  disk2.img  disk3.img  disk4.img

#確保根目錄的propagation type是shared,
#這一步是爲了保證你們的操做結果和示例中的同樣
dev@ubuntu:~/disks$ sudo mount --make-shared /

查看propagation type和peer group

默認狀況下,子掛載點會繼承父掛載點的propagation type

#顯式的以shared方式掛載disk1
dev@ubuntu:~/disks$ sudo mount --make-shared ./disk1.img ./disk1
#顯式的以private方式掛載disk2
dev@ubuntu:~/disks$ sudo mount --make-private ./disk2.img ./disk2

#mountinfo比mounts文件包含有更多的關於掛載點的信息
#這裏sed主要用來過濾掉跟當前主題無關的信息
#shared:105表示掛載點/home/dev/disks/disk1是以shared方式掛載,且peer group id爲105
#而掛載點/home/dev/disks/disk2沒有相關信息,表示是以private方式掛載
dev@ubuntu:~/disks$ cat /proc/self/mountinfo |grep disk | sed 's/ - .*//'
164 24 7:1 / /home/dev/disks/disk1 rw,relatime shared:105
173 24 7:2 / /home/dev/disks/disk2 rw,relatime

#分別在disk1和disk2目錄下建立目錄disk3和disk4,而後掛載disk3,disk4到這兩個目錄
dev@ubuntu:~/disks$ sudo mkdir ./disk1/disk3 ./disk2/disk4
dev@ubuntu:~/disks$ sudo mount ./disk3.img ./disk1/disk3
dev@ubuntu:~/disks$ sudo mount ./disk4.img ./disk2/disk4

#查看掛載信息,第一列的數字是掛載點ID,第二例是父掛載點ID,
#從結果來看,176和164的類型都是shared,而179和173的類型都是private的,
#說明在默認mount的狀況下,子掛載點會繼承父掛載點的propagation type
dev@ubuntu:~/disks$ cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'
164 24 7:1 / /home/dev/disks/disk1 rw,relatime shared:105 
173 24 7:2 / /home/dev/disks/disk2 rw,relatime 
176 164 7:3 / /home/dev/disks/disk1/disk3 rw,relatime shared:107 
179 173 7:4 / /home/dev/disks/disk2/disk4 rw,relatime

shared 和 private mount

#umount掉disk3和disk4,建立兩個新的目錄bind1和bind2用於bind測試
dev@ubuntu:~/disks$ sudo umount /home/dev/disks/disk1/disk3
dev@ubuntu:~/disks$ sudo umount /home/dev/disks/disk2/disk4
dev@ubuntu:~/disks$ mkdir bind1 bind2

#bind的方式掛載disk1到bind1,disk2到bind2
dev@ubuntu:~/disks$ sudo mount --bind ./disk1 ./bind1
dev@ubuntu:~/disks$ sudo mount --bind ./disk2 ./bind2

#查看掛載信息,顯然默認狀況下bind1和bind2的propagation type繼承自父掛載點24(/),都是shared。
#因爲bind2的源掛載點disk2是private的,因此bind2沒有和disk2在同一個peer group裏面,
#而是從新建立了一個新的peer group,這個group裏面就只有它一個。
#由於164和176都是shared類型且是經過bind方式mount在一塊兒的,因此他們屬於同一個peer group 105。
dev@ubuntu:~/disks$ cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'
164 24 7:1 / /home/dev/disks/disk1 rw,relatime shared:105 
173 24 7:2 / /home/dev/disks/disk2 rw,relatime 
176 24 7:1 / /home/dev/disks/bind1 rw,relatime shared:105 
179 24 7:2 / /home/dev/disks/bind2 rw,relatime shared:109 

#ID爲24的掛載點爲根目錄的掛載點
dev@ubuntu:~/disks$ cat /proc/self/mountinfo |grep ^24| sed 's/ - .*//'
24 0 252:0 / / rw,relatime shared:1

#這時disk3和disk4目錄都是空的
dev@ubuntu:~/disks$ ls bind1/disk3/
dev@ubuntu:~/disks$ ls bind2/disk4/
dev@ubuntu:~/disks$ ls disk1/disk3/
dev@ubuntu:~/disks$ ls disk2/disk4/

#從新掛載disk3和disk4
dev@ubuntu:~/disks$ sudo mount ./disk3.img ./disk1/disk3
dev@ubuntu:~/disks$ sudo mount ./disk4.img ./disk2/disk4

#因爲disk1/和bind1/屬於同一個peer group,
#因此在掛載了disk3後,在兩個目錄下都能看到disk3下的內容
dev@ubuntu:~/disks$ ls disk1/disk3/
lost+found
dev@ubuntu:~/disks$ ls bind1/disk3/
lost+found

#而disk2/是private類型的,因此在他下面掛載disk4不會通知bind2,
#因而bind2下的disk4目錄是空的
dev@ubuntu:~/disks$ ls disk2/disk4/
lost+found
dev@ubuntu:~/disks$ ls bind2/disk4/
dev@ubuntu:~/disks$

#再看看disk3,雖然182和183的父掛載點不同,但因爲他們父掛載點屬於同一個peer group,
#且disk3是以默認方式掛載的,因此他們屬於同一個peer group
dev@ubuntu:~/disks$ cat /proc/self/mountinfo |egrep "disk3"| sed 's/ - .*//'
182 164 7:3 / /home/dev/disks/disk1/disk3 rw,relatime shared:111 
183 176 7:3 / /home/dev/disks/bind1/disk3 rw,relatime shared:111 

#umount bind1/disk3後,disk1/disk3也相應的自動umount掉了
dev@ubuntu:~/disks$ sudo umount bind1/disk3
dev@ubuntu:~/disks$ cat /proc/self/mountinfo |grep disk3
dev@ubuntu:~/disks$

slave mount

#umount除disk1的全部其餘掛載點
dev@ubuntu:~/disks$ sudo umount ./disk2/disk4
dev@ubuntu:~/disks$ sudo umount /home/dev/disks/bind1
dev@ubuntu:~/disks$ sudo umount /home/dev/disks/bind2
dev@ubuntu:~/disks$ sudo umount /home/dev/disks/disk2
#確認只剩disk1
dev@ubuntu:~/disks$ cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'
164 24 7:1 / /home/dev/disks/disk1 rw,relatime shared:105 

#分別顯式的用shared和slave的方式bind disk1
dev@ubuntu:~/disks$ sudo mount --bind --make-shared ./disk1 ./bind1
dev@ubuntu:~/disks$ sudo mount --bind --make-slave ./bind1 ./bind2

#16四、173和176都屬於同一個peer group,
#master:105表示/home/dev/disks/bind2是peer group 105的slave
dev@ubuntu:~/disks$ cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'
164 24 7:1 / /home/dev/disks/disk1 rw,relatime shared:105 
173 24 7:1 / /home/dev/disks/bind1 rw,relatime shared:105 
176 24 7:1 / /home/dev/disks/bind2 rw,relatime master:105 

#mount disk3到disk1的子目錄disk3下
dev@ubuntu:~/disks$ sudo mount ./disk3.img ./disk1/disk3/
#其餘兩個目錄bin1和bind2裏面也掛載成功,說明master發生變化的時候,slave會跟着變化
dev@ubuntu:~/disks$ cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'
164 24 7:1 / /home/dev/disks/disk1 rw,relatime shared:105 
173 24 7:1 / /home/dev/disks/bind1 rw,relatime shared:105 
176 24 7:1 / /home/dev/disks/bind2 rw,relatime master:105 
179 164 7:2 / /home/dev/disks/disk1/disk3 rw,relatime shared:109 
181 176 7:2 / /home/dev/disks/bind2/disk3 rw,relatime master:109 
180 173 7:2 / /home/dev/disks/bind1/disk3 rw,relatime shared:109 

#umount disk3,而後mount disk3到bind2目錄下
dev@ubuntu:~/disks$ sudo umount ./disk1/disk3/
dev@ubuntu:~/disks$ sudo mount ./disk3.img ./bind2/disk3/

#因爲bind2的propagation type是slave,因此disk1和bind1兩個掛載點下面不會掛載disk3
#從179的類型能夠看出,當父掛載點176是slave類型時,默認狀況下其子掛載點179是private類型
dev@ubuntu:~/disks$ cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'
164 24 7:1 / /home/dev/disks/disk1 rw,relatime shared:105 
173 24 7:1 / /home/dev/disks/bind1 rw,relatime shared:105 
176 24 7:1 / /home/dev/disks/bind2 rw,relatime master:105 
179 176 7:2 / /home/dev/disks/bind2/disk3 rw,relatime -

結束語

若是用到了bind mount和mount namespace,在掛載設備的時候就須要注意一下父掛載點是否和其餘掛載點有peer group關係,若是有且父掛載點是shared,就說明你掛載的設備除了在當前掛載點能夠看到,在父掛載點的peer group的下面也能夠看到。

參考

相關文章
相關標籤/搜索