简单点说,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(前提条件是挂载点的propagation type是shared)spa
利用mount --bind命令,将会使源和目的挂载点属于同一个peer group,固然前提条件是‘源’必需要是一个挂载点。.net
当建立新的mount namespace时,新namespace会拷贝一份老namespace的挂载点信息,因而新的和老的namespace里面的相同挂载点就会属于同一个peer group。code
每一个挂载点都有一个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
#显式的以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
#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$
#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的下面也能够看到。