mount propagation
特定のマウント処理を他のディレクトリやnamespaceで認識できるようにするかどうかを、制御する仕組みとしてshared subtreeが存在する。
例としてプロセスのカレントディレクトリや、chrootで変更した配下に対して、外部ディレクトリのマウント処理を反映したい場合などが挙げられる。 また特定のマウントポイント配下に更にマウントポイントを追加した場合に、マウント元にディレクトリには反映されるかどうか などがある。
これらをshared subtreeのpropagationという仕組みによって、mountに関するインベントの伝搬を制御することが可能となる。
Peer group
propagationではpeer groupという概念が存在しpeer group間でマウントイベントが伝搬される。 peer groupは複数のmount pointの集合であり、以下を契機にメンバが追加される。
- 新しいnamespaceの作成
- これによってマウントポイントが新しいnamepsaceに複製されるので、それぞれのマウントポイントは同一のpeer groupに所属する
- bind mountのソースとして利用されたとき
メンバが削除されるトリガーは以下のものがある - unmountの実行 - namespaceの削除 - namespace内のプロセスがすべて終了した - namespace内のプロセスすべて該当namespace外に移動した
4つのpropagation type
マウントポイントはpropagation typeという属性を持っている。 これはマウントイベントをpeer group内に伝搬するかどうかを制御するために設定され4つ種類がある。
- shared
- private
- slave
- unvindable
そしてデフォルトでは、親のマウントポイントのpropagation typeを継承する。
それぞれをマウントポイントに設定した場合にどのような挙動になるのかを確認する。
shared
同じピアグループ内でマウントイベントは伝搬され共有される。 マウントポイント配下にマウントポイントが追加削除された際は、同じpeer group内のマウントポイント配下でも反映される。
オプションとしてmountコマンドに--makes-shared
を付加する。
下記の例ではまず、/A
を/B
にbind マウントした。
$ mkdir /A /B $ touch /A/test $ tree /A /B C /A └── test /B $ mount --bind --make-shared /A /B $ tree /A /B /A └── test /B └── test
各マウントポイントの情報は/proc/{PID}/mountinfo
で参照できる.
下記の例ではshared:1
となっておりsharedはpropagation typeがsharedで、peer groupが1であることを表している。この数字が同じであれば同じpeer groupに所属する。
# /proc/self/mountinfo 実行結果を抜粋 85 40 8:1 /A /B rw,relatime shared:1 - xfs /dev/sda1 rw,seclabel,attr2,inode64,noquota
/C
を作成し、/B/mnt
にマウントする。すると/A
配下でもmnt/test2
を参照することがき、マウント情報が伝搬され反映されていることが確認できる。
$ mkdir /C /B/mnt $ touch /C/test2 $ tree /A /B /C /A └── test /B ├── mnt └── test /C └── test2 $ mount --bind --make-shared /C /B/mnt/ $ tree /A /B /C /A ├── mnt │ └── test2 └── test /B ├── mnt │ └── test2 └── test /C └── test2
マウント情報にはコマンド実行した/A
をマウントポイントとした情報以外に、伝搬された情報である/A/mnt
も記載されており、いずれのpeer group番号は1となっている。
# /proc/self/mountinfo 実行結果を抜粋 85 40 8:1 /A /B rw,relatime shared:1 - xfs /dev/sda1 rw,seclabel,attr2,inode64,noquota 91 85 8:1 /C /B/mnt rw,relatime shared:1 - xfs /dev/sda1 rw,seclabel,attr2,inode64,noquota 92 40 8:1 /C /A/mnt rw,relatime shared:1 - xfs /dev/sda1 rw,seclabel,attr2,inode64,noquota
private
aharedとは対象的にピアグループ内にイベントは共有されない。
/A
を/B
にbind mountして作業前の初期状態とする。
マウンポイントをprivateとするためには、オプションとして--make-private
をmountコマンドに使用する。
$ tree /A /B /C /A └── test /B /C └── test2 $ mount --bind --make-private /A /B tree /A /B /C /A └── test /B └── test /C └── test2
マウント情報を確認するとprivateではpeer groupに関する情報は記載されていないことがわかる。
# /proc/self/mountinfo 実行結果を抜粋 85 40 8:1 /A /B rw,relatime - xfs /dev/sda1 rw,seclabel,attr2,inode64,noquota
/C
を/B/mnt/
にマウントしても、/A/mnt/test2
は参照できず/A
には反映されていない。
$ mount --bind /C /B/mnt/ $ tree /A /B /C /A ├── mnt └── test /B ├── mnt │ └── test2 └── test /C └── test2
マウント情報は実行したコマンドと同様の2種類のエントリが存在する。
# /proc/self/mountinfo 実行結果を抜粋 85 40 8:1 /A /B rw,relatime - xfs /dev/sda1 rw,seclabel,attr2,inode64,noquota 87 85 8:1 /C /B/mnt rw,relatime shared:1 - xfs /dev/sda1 rw,seclabel,attr2,inode64,noquota
逆に/A/mnt
に/C
をマウントしてみるとこれも同じ結果となり反映されない
$ tree /A /B /C /A ├── mnt └── test /B /C └── test2 $ mount --bind --make-private /A /B $ tree /A /B /C /A ├── mnt └── test /B ├── mnt └── test /C └── test2
$ mount --bind /C /A/mnt/ $ tree /A /B /C /A ├── mnt │ └── test2 └── test /B ├── mnt └── test /C └── test2
85 40 8:1 /A /B rw,relatime - xfs /dev/sda1 rw,seclabel,attr2,inode64,noquota 87 40 8:1 /C /A/mnt rw,relatime shared:1 - xfs /dev/sda1 rw,seclabel,attr2,inode64,noquota
slave
イベントの伝播は一方通行となる。同じpeer group内でマスタとなるマウントポイントが変更された場合に、スレーブ側のマウントポイントも変更される。 しかしその逆は発生しない。
マスタ側のディスクドライブマウントなどをスレーブ側で利用したい場合で、かつ逆にスレーブ側の変更で影響を与えたくない場合に利用する。
bindコマンドに--make-slave
オプションを利用して/A
を/B
にマウントする。
$ tree /A /B /C /A └── test /B /C └── test2 $ mount --bind --make-slave /A /B tree /A /B /C /A └── test /B └── test /C └── test2
マウント情報にはmaster:1
# /proc/self/mountinfo 実行結果を抜粋 85 40 8:1 /A /B rw,relatime master:1 - xfs /dev/sda1 rw,seclabel,attr2,inode64,noquota
/C
を/B/mnt
にsharedマウントすると、/A
配下には反映されていない。
$ mkdir /B/mnt $ mount --bind /C /B/mnt $ tree /A /B /C /A ├── mnt └── test /B ├── mnt │ └── test2 └── test /C └── test2
85 40 8:1 /A /B rw,relatime master:1 - xfs /dev/sda1 rw,seclabel,attr2,inode64,noquota 87 85 8:1 /C /B/mnt rw,relatime shared:1 - xfs /dev/sda1 rw,seclabel,attr2,inode64,noquota
一旦/B/mnt
をunmountして元の状態に戻す。
$ umount /B/mnt/ $ tree /A /B /C /A ├── mnt └── test /B ├── mnt └── test /C └── test2
そして今度は逆に/A配下にマウントする。
この場合は/A
がmasterとなっているので、マウント情報は/B
に伝搬され/B/mnt/test2
の存在が確認できる。
$ mount --bind /C /A/mnt/ $ tree /A /B /C /A ├── mnt │ └── test2 └── test /B ├── mnt │ └── test2 └── test /C └── test2
unvindable
privateと同様にマウントイベントの伝播はしないが、その挙動に加えてbind mountのソースとして利用することができなくなるという制約が追加される。
mountコマンドの実行時には--make-unbindable
を付与する。ここでは/A
を/B
にマウントする。
$ tree /A /B /C /A └── test /B /C └── test2 $ mount --bind --make-unbindable /A /B $ tree /A /B /C /A └── test /B └── test /C └── test2
マウント情報にはunbindableであることが記されている。
85 40 8:1 /A /B rw,relatime unbindable - xfs /dev/sda1 rw,seclabel,attr2,inode64,noquota
当然privateと同様の挙動のため、/C
を/B/mnt
にマウントしても/A/mnt
では参照することはできない。
$ mkdir /B/mnt $ tree /A /B /C /A ├── mnt └── test /B ├── mnt └── test /C └── test2
さらに/B
を/C/mnt
をマウントしようとしてもbind mountのソースとして利用できないため失敗する。
$ mkdir /C/mnt $ tree /A /B /C /A ├── mnt └── test /B ├── mnt └── test /C ├── mnt └── test2 $ mount --bind /B /C/mnt/ $ mount: wrong fs type, bad option, bad superblock on /B, missing codepage or helper program, or other error In some cases useful info is found in syslog - try dmesg | tail or so.
unvindableは再起にマウントした際にマウントポイントが指数関数的に増加するのを防ぐ目的で利用されるようだ。
/A
配下に2つのディレクトリを用意した。まずは/A
を配下のdir1
にマウントする。
$ tree /A /A ├── dir1 └── dir2 $ mount --rbind /A /A/dir1 /A ├── dir1 │ ├── dir1 │ └── dir2 └── dir2
そして次は/A
を/A/dir2
にマウントする
$ mount --rbind /A /A/dir2 $ tree /A /A ├── dir1 │ ├── dir1 │ └── dir2 │ ├── dir1 │ │ ├── dir1 │ │ └── dir2 │ └── dir2 └── dir2 ├── dir1 │ ├── dir1 │ └── dir2 └── dir2
マウントコマンドを2回実行したがこのときのmountinfoはこのようになっている。 手動実行分以外に再帰的なマウントポイントが増えていることがわかる。同時にこれを繰り返せばマウントポイントの量が指数関数的に増加するのも納得がいく。
そのために途中のマウントポイントをバインドマウント不可とすることで、爆発的な増加を防止する仕組みがunbindableというわけだ。
85 40 8:1 /A /A/dir1 rw,relatime shared:1 - xfs /dev/sda1 rw,seclabel,attr2,inode64,noquota 87 40 8:1 /A /A/dir2 rw,relatime shared:1 - xfs /dev/sda1 rw,seclabel,attr2,inode64,noquota 88 87 8:1 /A /A/dir2/dir1 rw,relatime shared:1 - xfs /dev/sda1 rw,seclabel,attr2,inode64,noquota 89 85 8:1 /A /A/dir1/dir2 rw,relatime shared:1 - xfs /dev/sda1 rw,seclabel,attr2,inode64,noquota 90 89 8:1 /A /A/dir1/dir2/dir1 rw,relatime shared:1 - xfs /dev/sda1 rw,seclabel,attr2,inode64,noquota
参照
- Linux Kernel Doc
- LWN
- Mount namespaces and shared subtrees
- Shared subtrees
- Mount namespaces, mount propagation, and unbindable mounts