{"id":218,"date":"2008-12-13T12:45:47","date_gmt":"2008-12-13T10:45:47","guid":{"rendered":"http:\/\/glandium.org\/blog\/?p=218"},"modified":"2010-01-27T08:52:26","modified_gmt":"2010-01-27T07:52:26","slug":"shared-subtrees","status":"publish","type":"post","link":"https:\/\/glandium.org\/blog\/?p=218","title":{"rendered":"Shared subtrees"},"content":{"rendered":"<p>As reply to my <a href=\"\/blog\/?p=217\">previous post about per-process namespaces<\/a>, <a href=\"http:\/\/etbe.coker.com.au\/2008\/12\/13\/per-process-namespaces-pam-namespace\/\">Russell wrote about pam-namespace and shared subtrees<\/a>. As he reports, pam-namespace (that I discovered by the occasion) can do what I was suggesting would be nice for pam-tmpdir.<\/p>\n<p>Anyways, I was actually already planning to write about shared subtrees and how they can be useful with namespaces. In this first post, I will introduce shared subtrees, while in a follow-up post I will introduce how they can usefully be used with namespaces.<\/p>\n<p>As a preliminary note, you should know that while etch's kernel supports shared subtrees, etch's <code>mount<\/code> doesn't support the necessary options. Lenny's mount is unfortunately uninstallable on etch due to its dependency on a newer libc. But you can find a <code>smount<\/code> utility's source code in Documentation\/filesystems\/sharedsubtree.txt in the kernel source, where other explanations about the feature are available. So, you can either backport lenny's util-linux to etch, or build <code>smount<\/code> to replicate what I will be doing below. If you are using <code>smount<\/code>, just replace <\/p>\n<blockquote><p><code>mount --make-<em>type<\/em> <em>path<\/em><\/code><\/p><\/blockquote>\n<p> with <\/p>\n<blockquote><p><code>smount <em>path<\/em> <em>type<\/em><\/code><\/p><\/blockquote>\n<p>As seen in my <a href=\"\/blog\/?p=217\">previous post<\/a>, bind-mounting allows to attach a file hierarchy at some other place in the virtual file system.<\/p>\n<blockquote><p><code>mount --bind \/ \/mnt<\/code><\/p><\/blockquote>\n<p>will make all the contents of <code>\/<\/code> (<code>\/bin<\/code>, <code>\/etc<\/code>, ...) available through <code>\/mnt<\/code> (<code>\/mnt\/bin<\/code>, <code>\/mnt\/etc<\/code>, ...).<\/p>\n<p>On the other hand, sub-mounts will be ignored in such a case. For instance, <code>\/usr<\/code> is usually a different mount point from <code>\/<\/code>. It means <code>\/mnt\/usr<\/code> will be empty (provided it is empty in the underlying physical filesystem), instead of containing the same as <code>\/usr<\/code>:<\/p>\n<blockquote><p><code>$ mount --bind \/ \/mnt<br \/>\n$ ls \/mnt\/usr<br \/>\n$ ls \/usr<br \/>\nbin  games  include  lib  lib32  lib64  local  sbin  share  src  X11R6<br \/>\n$ umount \/mnt<br \/>\n<\/code><\/p><\/blockquote>\n<p>If you also want <code>\/usr<\/code> to be bind-mounted, you must use <code>--rbind<\/code> instead of <code>--bind<\/code>:<\/p>\n<blockquote><p><code>$ mount --rbind \/ \/mnt<br \/>\n$ ls \/mnt\/usr<br \/>\nbin  games  include  lib  lib32  lib64  local  sbin  share  src  X11R6<br \/>\n$ ls \/usr<br \/>\nbin  games  include  lib  lib32  lib64  local  sbin  share  src  X11R6<br \/>\n<\/code><\/p><\/blockquote>\n<p>Obviously, sub-sub-mounts will also be propagated.<\/p>\n<p>Since recursively bind-mounting will create a bunch of mount points, unmounting can become a hassle. You can use the following command to unmount everything:<\/p>\n<blockquote><p><code>$ awk '$2 ~ \/^\\\/mnt\/ {print $2}' \/proc\/mounts | sort -r | xargs umount<\/code><\/p><\/blockquote>\n<p>Now, this is where shared subtrees come in. After the bind mount has been done, if you mount something on either side of the bind mount, the new mount is not propagated. This is called <code>private<\/code> subtrees, and is the default. But before doing anything else, let's setup our testing environment:<\/p>\n<blockquote><p><code>$ mkdir -p \/a\/a \/b<br \/>\n$ touch \/a\/b \/a\/c<br \/>\n$ ls \/a<br \/>\na b c<br \/>\n$ ls \/b<br \/>\n<\/code><code><\/code><\/p><\/blockquote>\n<p>After, bind-mounting <code>\/a<\/code> onto <code>\/b<\/code>, let's see what happens when mounting something under <code>\/a<\/code>, then under <code>\/b<\/code>:<\/p>\n<blockquote><p><code>$ mount --bind \/a \/b<br \/>\n$ ls \/b<br \/>\na b c<br \/>\n$ mount --bind \/usr \/a\/a<br \/>\n$ ls \/a\/a<br \/>\nbin  games  include  lib  lib32  lib64\tlocal  sbin  share\tsrc  X11R6<br \/>\n$ ls \/b\/a<br \/>\n$ umount \/a\/a<br \/>\n$ mount --bind \/usr \/b\/a<br \/>\n$ ls \/a\/a<br \/>\n$ ls \/b\/a<br \/>\nbin  games  include  lib  lib32  lib64\tlocal  sbin  share\tsrc  X11R6<br \/>\n$ umount \/b\/a<br \/>\n<\/code><\/p><\/blockquote>\n<p>As I said earlier, these new mounts are not propagated. Note that I used bind-mounts as sub mounts, but it would work all the same with other kind of mounts (device, fuse, etc.).<\/p>\n<p>There are 2 other modes that allow to have some propagation: <code>shared<\/code> and <code>slave<\/code>.<\/p>\n<p><code>shared<\/code> allows mounts on both ends to be shared. Note you need to set the mode before bind-mounting:<\/p>\n<blockquote><p><code>$ umount \/b<br \/>\n$ mount --bind \/a \/a<\/code>   # This is needed because <code>\/a<\/code> is not initially a mount point and you can only apply subtree modes to mount points.<br \/>\n<code>$ mount --make-shared \/a<br \/>\n$ mount --bind \/a \/b<br \/>\n$ mount \/dev\/sda1 \/a\/a<br \/>\n$ ls \/a\/a<br \/>\nconfig-2.6.26-1-amd64  grub  initrd.img-2.6.26-1-amd64\tSystem.map-2.6.26-1-amd64  vmlinuz-2.6.26-1-amd64<br \/>\n$ ls \/b\/a<br \/>\nconfig-2.6.26-1-amd64  grub  initrd.img-2.6.26-1-amd64\tSystem.map-2.6.26-1-amd64  vmlinuz-2.6.26-1-amd64<br \/>\n$ umount \/a\/a<br \/>\n$ mount \/dev\/sda1 \/b\/a<br \/>\n$ ls \/a\/a<br \/>\nconfig-2.6.26-1-amd64  grub  initrd.img-2.6.26-1-amd64\tSystem.map-2.6.26-1-amd64  vmlinuz-2.6.26-1-amd64<br \/>\n$ ls \/b\/a<br \/>\nconfig-2.6.26-1-amd64  grub  initrd.img-2.6.26-1-amd64\tSystem.map-2.6.26-1-amd64  vmlinuz-2.6.26-1-amd64<br \/>\n$ umount \/b\/a<br \/>\n<\/code><\/p><\/blockquote>\n<p>You can even mount on one end and unmount from the other:<\/p>\n<blockquote><p><code>$ mount \/dev\/sda1 \/a\/a<br \/>\n$ umount \/b\/a<br \/>\n$ ls \/a\/a<br \/>\n<\/code><\/p><\/blockquote>\n<p><code>slave<\/code> allows mounts on the \"master\" end (<code>\/a<\/code> in our case) to propagate to the \"slave\" end (<code>\/b<\/code>), but not the other way around. The \"master\" end need to be <code>shared<\/code> :<\/p>\n<blockquote><p><code>$ umount \/b<br \/>\n$ mount --make-shared \/a<\/code>  # Only for completeness, we already set <code>\/a<\/code> as <code>shared<\/code> earlier.<br \/>\n<code>$ mount --bind \/a \/b<br \/>\n$ mount --make-slave \/b<br \/>\n$ mount \/dev\/sda1 \/a\/a<br \/>\n$ ls \/a\/a<br \/>\nconfig-2.6.26-1-amd64  grub  initrd.img-2.6.26-1-amd64\tSystem.map-2.6.26-1-amd64  vmlinuz-2.6.26-1-amd64<br \/>\n$ ls \/b\/a<br \/>\nconfig-2.6.26-1-amd64  grub  initrd.img-2.6.26-1-amd64\tSystem.map-2.6.26-1-amd64  vmlinuz-2.6.26-1-amd64<br \/>\n$ umount \/a\/a<br \/>\n$ mount \/dev\/sda1 \/b\/a<br \/>\n$ ls \/a\/a<br \/>\n$ ls \/b\/a<br \/>\nconfig-2.6.26-1-amd64  grub  initrd.img-2.6.26-1-amd64\tSystem.map-2.6.26-1-amd64  vmlinuz-2.6.26-1-amd64<br \/>\n$ umount \/b\/a<br \/>\n<\/code><\/p><\/blockquote>\n<p>There is a third mode, <code>unbindable<\/code>, that does something different:<\/p>\n<blockquote><p><code>$ umount \/b<br \/>\n$ mount --make-unbindable \/a<br \/>\n$ mount --bind \/a \/b<br \/>\nmount: wrong fs type, bad option, bad superblock on \/a,<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;missing codepage or helper program, or other error<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;In some cases useful info is found in syslog - try<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dmesg | tail  or so<br \/>\n$ mount --bind \/a\/a \/b<br \/>\nmount: wrong fs type, bad option, bad superblock on \/a,<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;missing codepage or helper program, or other error<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;In some cases useful info is found in syslog - try<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dmesg | tail  or so<br \/>\n<\/code><\/p><\/blockquote>\n<p>As you can see, it disallows bind mounting of <code>\/a<\/code> and its subdirectories to some other place.<\/p>\n<p>Finally, to put back the default mode, you can use:<\/p>\n<blockquote><p><code>$ mount --make-private \/a<\/code><\/p><\/blockquote>\n<p>Similarly to <code>--bind<\/code>, there is also a recursive version of each: <code>rshared<\/code>, <code>rslave<\/code>, <code>runbindable<\/code> and <code>rprivate<\/code>, to apply these to sub-mounts.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>As reply to my previous post about per-process namespaces, Russell wrote about pam-namespace and shared subtrees. As he reports, pam-namespace (that I discovered by the occasion) can do what I was suggesting would be nice for pam-tmpdir. Anyways, I was actually already planning to write about shared subtrees and how they can be useful with [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[23],"class_list":["post-218","post","type-post","status-publish","format-standard","hentry","category-pdo","tag-en"],"_links":{"self":[{"href":"https:\/\/glandium.org\/blog\/index.php?rest_route=\/wp\/v2\/posts\/218","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/glandium.org\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/glandium.org\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/glandium.org\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/glandium.org\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=218"}],"version-history":[{"count":3,"href":"https:\/\/glandium.org\/blog\/index.php?rest_route=\/wp\/v2\/posts\/218\/revisions"}],"predecessor-version":[{"id":661,"href":"https:\/\/glandium.org\/blog\/index.php?rest_route=\/wp\/v2\/posts\/218\/revisions\/661"}],"wp:attachment":[{"href":"https:\/\/glandium.org\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=218"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/glandium.org\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=218"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/glandium.org\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=218"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}