mirror of https://github.com/mkerrisk/man-pages
mount_namespaces.7: New page describing mount namespaces
Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
This commit is contained in:
parent
20eed1b32f
commit
98c28960c3
|
@ -0,0 +1,806 @@
|
|||
.\" Copyright (c) 2016 by Michael Kerrisk <mtk.manpages@gmail.com>
|
||||
.\"
|
||||
.\" %%%LICENSE_START(VERBATIM)
|
||||
.\" Permission is granted to make and distribute verbatim copies of this
|
||||
.\" manual provided the copyright notice and this permission notice are
|
||||
.\" preserved on all copies.
|
||||
.\"
|
||||
.\" Permission is granted to copy and distribute modified versions of this
|
||||
.\" manual under the conditions for verbatim copying, provided that the
|
||||
.\" entire resulting derived work is distributed under the terms of a
|
||||
.\" permission notice identical to this one.
|
||||
.\"
|
||||
.\" Since the Linux kernel and libraries are constantly changing, this
|
||||
.\" manual page may be incorrect or out-of-date. The author(s) assume no
|
||||
.\" responsibility for errors or omissions, or for damages resulting from
|
||||
.\" the use of the information contained herein. The author(s) may not
|
||||
.\" have taken the same level of care in the production of this manual,
|
||||
.\" which is licensed free of charge, as they might when working
|
||||
.\" professionally.
|
||||
.\"
|
||||
.\" Formatted or processed versions of this manual, if unaccompanied by
|
||||
.\" the source, must acknowledge the copyright and authors of this work.
|
||||
.\" %%%LICENSE_END
|
||||
.\"
|
||||
.\"
|
||||
.TH MOUNT_NAMESPACES 7 2016-05-05 "Linux" "Linux Programmer's Manual"
|
||||
.SH NAME
|
||||
mount_namespaces \- overview of Linux mount namespaces
|
||||
.SH DESCRIPTION
|
||||
For an overview of namespaces, see
|
||||
.BR namespaces (7).
|
||||
|
||||
Mount namespaces provide isolation of the list of mount points seen
|
||||
by the processes in each namespace instance.
|
||||
Thus, the processes in each of the mount namespace instances
|
||||
will see distinct single-directory hierarchies.
|
||||
|
||||
The views provided by the
|
||||
.IR /proc/[pid]/mounts ,
|
||||
.IR /proc/[pid]/mountinfo ,
|
||||
and
|
||||
.IR /proc/[pid]/mountstats
|
||||
files (all described in
|
||||
.BR proc (5))
|
||||
correspond to the mount namespace in which the process with the PID
|
||||
.IR [pid]
|
||||
resides.
|
||||
(All of the processes that reside in the same mount namespace
|
||||
will see the same view in these files.)
|
||||
|
||||
When a process creates a new mount namespace using
|
||||
.BR clone (2)
|
||||
or
|
||||
.BR unshare (2)
|
||||
with the
|
||||
.BR CLONE_NEWNS
|
||||
flag, the mount point list for the new namespace is a
|
||||
.I copy
|
||||
of the caller's mount point list.
|
||||
Subsequent modifications to the mount point list
|
||||
.RB ( mount (2)
|
||||
and
|
||||
.BR umount (2))
|
||||
in either mount namespace will not (by default) affect the
|
||||
mount point list seen in the other namespace
|
||||
(but see the following discussion of shared subtrees).
|
||||
.\"
|
||||
.SH SHARED SUBTREES
|
||||
After the implementation of mount namespaces was completed,
|
||||
experience showed that the isolation that they provided was,
|
||||
in some cases, too great.
|
||||
For example, in order to make a newly loaded optical disk
|
||||
available in all mount namespaces,
|
||||
a mount operation was required in each namespace.
|
||||
For this use case, and others,
|
||||
the shared subtree feature was introduced in Linux 2.6.15.
|
||||
This feature allows for automatic, controlled propagation of mount and unmount
|
||||
.I events
|
||||
between namespaces
|
||||
(or, more precisely, between the members of a
|
||||
.IR "peer group"
|
||||
that are propagating events to one another).
|
||||
|
||||
Each mount point is marked (via
|
||||
.BR mount (2))
|
||||
as having one of the following
|
||||
.IR "propagation types" :
|
||||
.TP
|
||||
.BR MS_SHARED
|
||||
This mount point shares events with members of a peer group.
|
||||
Mount and unmount events immediately under this mount point will propagate
|
||||
outward to the other mount points that are members of the peer group.
|
||||
.I Propagation
|
||||
here means that the same mount or unmount will automatically occur
|
||||
under all of the other mount points in the peer group.
|
||||
Conversely, mount and unmount events that take place under
|
||||
peer mount points will propagate inward to this mount point.
|
||||
.TP
|
||||
.BR MS_PRIVATE
|
||||
This mount point is private; it does not have a peer group.
|
||||
Mount and unmount events do not propagate into or out of this mount point.
|
||||
This is the default propagation type for newly created mount points
|
||||
(but see NOTES).
|
||||
.TP
|
||||
.BR MS_SLAVE
|
||||
Mount and unmount events propagate into this mount point from
|
||||
a (master) shared peer group.
|
||||
Mount and unmount events under this mount point do not propagate to any peer.
|
||||
|
||||
Note that a mount point can be the slave of another peer group
|
||||
while at the same time sharing mount and unmount events
|
||||
with a peer group of which it is a member.
|
||||
(More precisely, one peer group can be the slave of another peer group.)
|
||||
.TP
|
||||
.BR MS_UNBINDABLE
|
||||
This is like a private mount,
|
||||
and in addition this mount can't be bind mounted.
|
||||
Attempts to bind mount this mount
|
||||
.RB ( mount (2)
|
||||
with the
|
||||
.BR MS_BIND
|
||||
flag) will fail.
|
||||
|
||||
When a recursive bind mount
|
||||
.RB ( mount (2)
|
||||
with the
|
||||
.BR MS_BIND
|
||||
and
|
||||
.BR MS_REC
|
||||
flags) is performed on a directory subtree,
|
||||
any bind mounts within the subtree are automatically pruned
|
||||
(i.e., not replicated)
|
||||
when replicating that subtree to produce the target subtree.
|
||||
.PP
|
||||
The propagation type is a per-mount-point setting;
|
||||
some mount points may be marked as shared
|
||||
(with each shared mount point being a member of a distinct peer group),
|
||||
while others are private
|
||||
(or slaved or unbindable).
|
||||
|
||||
Note that a mount's propagation type determines whether
|
||||
mounts and unmounts of mount points
|
||||
.I "immediately under"
|
||||
the mount point are propagated.
|
||||
Thus, the propagation type does not affect propagation of events for
|
||||
grandchildren and further removed descendant mount points.
|
||||
What happens if the mount point itself is unmounted is determined by
|
||||
the propagation type that is in effect for the
|
||||
.I parent
|
||||
of the mount point.
|
||||
|
||||
Members are added to a
|
||||
.IR "peer group"
|
||||
when a mount point is marked as shared and either:
|
||||
.IP * 3
|
||||
the mount point is replicated during the creation of a new mount namespace; or
|
||||
.IP *
|
||||
a new bind mount is created from the mount point.
|
||||
.PP
|
||||
In both of these cases, the new mount point joins the peer group
|
||||
of which the existing mount point is a member.
|
||||
A mount ceases to be a member of a peer group when either
|
||||
the mount is explicitly unmounted,
|
||||
or when the mount is implicitly unmounted because a mount namespace is removed
|
||||
(because it has no more member processes).
|
||||
|
||||
The propagation type of the mount points in a mount namespace
|
||||
can be discovered via the "optional fields" exposed in
|
||||
.IR /proc/[pid]/mountinfo .
|
||||
(See
|
||||
.BR proc (5)
|
||||
for details of this file.)
|
||||
The following tags can appear in the optional fields
|
||||
for a record in that file:
|
||||
.TP
|
||||
.I shared:X
|
||||
This mount point is shared in peer group
|
||||
.IR X .
|
||||
Each peer group has a unique ID (a small integer) that is automatically
|
||||
generated by the kernel,
|
||||
and all mount points in the same peer group will show the same ID.
|
||||
(These IDs may be recycled when a peer group ceases to have any members.)
|
||||
.TP
|
||||
.I master:X
|
||||
This mount is a slave to shared peer group
|
||||
.IR X .
|
||||
.TP
|
||||
.IR propagate_from:X " (since Linux 2.6.26)"
|
||||
.\" commit 97e7e0f71d6d948c25f11f0a33878d9356d9579e
|
||||
This mount is a slave and receives propagation from shared peer group
|
||||
.IR X .
|
||||
This tag will always appear in conjunction with a
|
||||
.IR master:X
|
||||
tag.
|
||||
Here,
|
||||
.IR X
|
||||
is the closest dominant peer group under the process's root directory.
|
||||
If
|
||||
.IR X
|
||||
is the immediate master of the mount,
|
||||
or if there is no dominant peer group under the same root,
|
||||
then only the
|
||||
.IR master:X
|
||||
field is present and not the
|
||||
.IR propagate_from:X
|
||||
field.
|
||||
.TP
|
||||
.IR unbindable
|
||||
This is an unbindable mount.
|
||||
.PP
|
||||
If none of the above tags is present, then this is a private mount.
|
||||
.SS MS_SHARED and MS_PRIVATE example
|
||||
Suppose that on a terminal in the initial mount namespace,
|
||||
we mark one mount point as shared and another as private,
|
||||
and then view the mounts in
|
||||
.IR /proc/self/mountinfo :
|
||||
|
||||
.nf
|
||||
.in +4n
|
||||
sh1# \fBmount \-\-make\-private /mntB\fP
|
||||
sh1# \fBmount \-\-make\-shared /mntA\fP
|
||||
sh1# \fBcat /proc/self/mountinfo | grep \(aq/mnt[AB]\(aq | sed \(aqs/ \- .*//\(aq\fP
|
||||
77 61 8:17 / /mntA rw,relatime shared:1
|
||||
83 61 8:15 / /mntB rw,relatime
|
||||
.in
|
||||
.fi
|
||||
|
||||
From the
|
||||
.IR /proc/self/mountinfo
|
||||
output, we see that
|
||||
.IR /mntA
|
||||
is a shared mount in peer group 1, and that
|
||||
.IR /mntB
|
||||
has no optional tags, indicating that it is a private mount.
|
||||
The first two fields in each record in this file are the unique
|
||||
ID for this mount, and the mount ID of the parent mount.
|
||||
We can further inspect this file to see that the parent mount point of
|
||||
.IR /mntA
|
||||
and
|
||||
.IR /mntB
|
||||
is the root directory,
|
||||
.IR / ,
|
||||
which is mounted as private:
|
||||
|
||||
.nf
|
||||
.in +4n
|
||||
sh1# \fBcat /proc/self/mountinfo | awk \(aq$1 == 61\(aq | sed \(aqs/ \- .*//\(aq\fP
|
||||
61 0 8:2 / / rw,relatime
|
||||
.in
|
||||
.fi
|
||||
|
||||
On a second terminal,
|
||||
we create a new mount namespace where we run a second shell
|
||||
and inspect the mounts:
|
||||
|
||||
.nf
|
||||
.in +4n
|
||||
$ \fBPS1=\(aqsh2# \(aq sudo unshare \-m \-\-propagation unchanged sh\fP
|
||||
sh2# \fBcat /proc/self/mountinfo | grep \(aq/mnt[AB]\(aq | sed \(aqs/ \- .*//\(aq\fP
|
||||
222 145 8:17 / /mntA rw,relatime shared:1
|
||||
225 145 8:15 / /mntB rw,relatime
|
||||
.in
|
||||
.fi
|
||||
|
||||
The new mount namespace received a copy of the initial mount namespace's
|
||||
mount points.
|
||||
These new mount points maintain the same propagation types,
|
||||
but have unique mount IDs.
|
||||
(The
|
||||
.IR \-\-propagation\ unchanged
|
||||
option prevents
|
||||
.BR unshare (1)
|
||||
from marking all mounts as private when creating a new mount namespace,
|
||||
.\" Since util-linux 2.27
|
||||
which it does by default.)
|
||||
|
||||
In the second terminal, we then create submounts under each of
|
||||
.IR /mntA
|
||||
and
|
||||
.IR /mntB
|
||||
and inspect the set-up:
|
||||
|
||||
.nf
|
||||
.in +4n
|
||||
sh2# \fBmkdir /mntA/x\fP
|
||||
sh2# \fBmount /dev/sdb6 /mntA/x\fP
|
||||
sh2# \fBmkdir /mntB/y\fP
|
||||
sh2# \fBmount /dev/sdb7 /mntB/y\fP
|
||||
sh2# \fBcat /proc/self/mountinfo | grep \(aq/mnt[AB]\(aq | sed \(aqs/ \- .*//\(aq\fP
|
||||
222 145 8:17 / /mntA rw,relatime shared:1
|
||||
225 145 8:15 / /mntB rw,relatime
|
||||
178 222 8:22 / /mntA/x rw,relatime shared:2
|
||||
230 225 8:23 / /mntB/y rw,relatime
|
||||
.in
|
||||
.fi
|
||||
|
||||
From the above, it can be seen that
|
||||
.IR /mntA/x
|
||||
was created as shared (inheriting this setting from its parent mount) and
|
||||
.IR /mntB/y
|
||||
was created as a private mount.
|
||||
|
||||
Returning to the first terminal and inspecting the set-up,
|
||||
we see that the new mount created under the shared mount point
|
||||
.IR /mntA
|
||||
propagated to its peer mount (in the initial mount namespace),
|
||||
but the new mount created under the private mount point
|
||||
.IR /mntB
|
||||
did not propagate:
|
||||
|
||||
.nf
|
||||
.in +4n
|
||||
sh1# \fBcat /proc/self/mountinfo | grep \(aq/mnt[AB]\(aq | sed \(aqs/ \- .*//\(aq\fP
|
||||
77 61 8:17 / /mntA rw,relatime shared:1
|
||||
83 61 8:15 / /mntB rw,relatime
|
||||
179 77 8:22 / /mntA/x rw,relatime shared:2
|
||||
.in
|
||||
.fi
|
||||
.\"
|
||||
.SS MS_SLAVE example
|
||||
Making a mount point a slave allows it to receive propagated
|
||||
mount and unmount events from a master shared peer group,
|
||||
while preventing it from propagating events outward to that master.
|
||||
This is useful if we want to (say) receive a mount event when
|
||||
an optical disk is mounted in the master shared peer group
|
||||
(in another mount namespace),
|
||||
but want to prevent mount and unmount events under the slave mount
|
||||
from having side effects in other namespaces.
|
||||
|
||||
We can demonstrate the effect of slaving by first marking
|
||||
two mount points as shared in the initial mount namespace:
|
||||
|
||||
.nf
|
||||
.in +4n
|
||||
sh1# \fBmount \-\-make\-shared /mntX\fP
|
||||
sh1# \fBmount \-\-make\-shared /mntY\fP
|
||||
sh1# \fBcat /proc/self/mountinfo | grep \(aq/mnt\(aq | sed \(aqs/ \- .*//\(aq\fP
|
||||
132 83 8:23 / /mntX rw,relatime shared:1
|
||||
133 83 8:22 / /mntY rw,relatime shared:2
|
||||
.in
|
||||
.fi
|
||||
|
||||
On a second terminal,
|
||||
we create a new mount namespace and inspect the mount points:
|
||||
|
||||
.nf
|
||||
.in +4n
|
||||
sh2# \fBunshare \-m \-\-propagation unchanged sh\fP
|
||||
sh2# \fBcat /proc/self/mountinfo | grep \(aq/mnt\(aq | sed \(aqs/ \- .*//\(aq\fP
|
||||
168 167 8:23 / /mntX rw,relatime shared:1
|
||||
169 167 8:22 / /mntY rw,relatime shared:2
|
||||
.in
|
||||
.fi
|
||||
|
||||
In the new mount namespace, we then mark one of the mount points as a slave:
|
||||
|
||||
.nf
|
||||
.in +4n
|
||||
sh2# \fBmount \-\-make\-slave /mntY\fP
|
||||
sh2# \fBcat /proc/self/mountinfo | grep \(aq/mnt\(aq | sed \(aqs/ \- .*//\(aq\fP
|
||||
168 167 8:23 / /mntX rw,relatime shared:1
|
||||
169 167 8:22 / /mntY rw,relatime master:2
|
||||
.in
|
||||
.fi
|
||||
|
||||
From the above output, we see that
|
||||
.IR /mntY
|
||||
is now a slave mount that is receiving propagation events from
|
||||
the shared peer group with the ID 2.
|
||||
|
||||
Continuing in the new namespace, we create submounts under each of
|
||||
.IR /mntX
|
||||
and
|
||||
.IR /mntY :
|
||||
|
||||
.nf
|
||||
.in +4n
|
||||
sh2# \fBmkdir /mntX/aaa\fP
|
||||
sh2# \fBmount /dev/sda3 /mntX/aaa\fP
|
||||
sh2# \fBmkdir /mntY/bbb\fP
|
||||
sh2# \fBmount /dev/sda5 /mntY/bbb\fP
|
||||
.in
|
||||
.fi
|
||||
|
||||
When we inspect the state of the mount points in the new mount namespace,
|
||||
we see that
|
||||
.IR /mntX/aaa
|
||||
was created as a new shared mount
|
||||
(inheriting the "shared" setting from its parent mount) and
|
||||
.IR /mntY/bbb
|
||||
was created as a private mount:
|
||||
|
||||
.nf
|
||||
.in +4n
|
||||
sh2# \fBcat /proc/self/mountinfo | grep \(aq/mnt\(aq | sed \(aqs/ \- .*//\(aq\fP
|
||||
168 167 8:23 / /mntX rw,relatime shared:1
|
||||
169 167 8:22 / /mntY rw,relatime master:2
|
||||
173 168 8:3 / /mntX/aaa rw,relatime shared:3
|
||||
175 169 8:5 / /mntY/bbb rw,relatime
|
||||
.in
|
||||
.fi
|
||||
|
||||
Returning to the first terminal (in the initial mount namespace),
|
||||
we see that the mount
|
||||
.IR /mntX/aaa
|
||||
propagated to the peer (the shared
|
||||
.IR /mntX ),
|
||||
but the mount
|
||||
.IR /mntY/bbb
|
||||
was not propagated:
|
||||
|
||||
.nf
|
||||
.in +4n
|
||||
sh1# \fBcat /proc/self/mountinfo | grep \(aq/mnt\(aq | sed \(aqs/ \- .*//\(aq\fP
|
||||
132 83 8:23 / /mntX rw,relatime shared:1
|
||||
133 83 8:22 / /mntY rw,relatime shared:2
|
||||
174 132 8:3 / /mntX/aaa rw,relatime shared:3
|
||||
.in
|
||||
.fi
|
||||
|
||||
Now we create a new mount point under
|
||||
.IR /mntY
|
||||
in the first shell:
|
||||
|
||||
.nf
|
||||
.in +4n
|
||||
sh1# \fBmkdir /mntY/ccc\fP
|
||||
sh1# \fBmount /dev/sda1 /mntY/ccc\fP
|
||||
sh1# \fBcat /proc/self/mountinfo | grep '/mnt' | sed 's/ \- .*//'\fP
|
||||
132 83 8:23 / /mntX rw,relatime shared:1
|
||||
133 83 8:22 / /mntY rw,relatime shared:2
|
||||
174 132 8:3 / /mntX/aaa rw,relatime shared:3
|
||||
178 133 8:1 / /mntY/ccc rw,relatime shared:4
|
||||
.in
|
||||
.fi
|
||||
|
||||
When we examine the mount points in the second mount namespace,
|
||||
we see that in this case the new mount has been propagated
|
||||
to the slave mount point,
|
||||
and that the new mount is itself a slave mount (to peer group 4):
|
||||
|
||||
.nf
|
||||
.in +4n
|
||||
sh2# \fBcat /proc/self/mountinfo | grep \(aq/mnt\(aq | sed \(aqs/ \- .*//\(aq\fP
|
||||
168 167 8:23 / /mntX rw,relatime shared:1
|
||||
169 167 8:22 / /mntY rw,relatime master:2
|
||||
173 168 8:3 / /mntX/aaa rw,relatime shared:3
|
||||
175 169 8:5 / /mntY/bbb rw,relatime
|
||||
179 169 8:1 / /mntY/ccc rw,relatime master:4
|
||||
.in
|
||||
.fi
|
||||
.\"
|
||||
.SS MS_UNBINDABLE example
|
||||
One of the primary purposes of unbindable mounts is to avoid
|
||||
the "mount point explosion" problem when repeatedly performing bind mounts
|
||||
of a higher-level subtree at a lower-level mount point.
|
||||
The problem is illustrated by the following shell session.
|
||||
|
||||
Suppose we have a system with the following mount points:
|
||||
|
||||
.nf
|
||||
.in +4n
|
||||
# \fBmount | awk \(aq{print $1, $2, $3}\(aq\fP
|
||||
/dev/sda1 on /
|
||||
/dev/sdb6 on /mntX
|
||||
/dev/sdb7 on /mntY
|
||||
.in
|
||||
.fi
|
||||
|
||||
Suppose furthermore that we wish to recursively bind mount
|
||||
the root directory under several users' home directories.
|
||||
We do this for the first user, and inspect the mount points:
|
||||
|
||||
.nf
|
||||
.in +4n
|
||||
# \fBmount \-\-rbind / /home/cecilia/\fP
|
||||
# \fBmount | awk \(aq{print $1, $2, $3}\(aq\fP
|
||||
/dev/sda1 on /
|
||||
/dev/sdb6 on /mntX
|
||||
/dev/sdb7 on /mntY
|
||||
/dev/sda1 on /home/cecilia
|
||||
/dev/sdb6 on /home/cecilia/mntX
|
||||
/dev/sdb7 on /home/cecilia/mntY
|
||||
.in
|
||||
.fi
|
||||
|
||||
When we repeat this operation for the second user,
|
||||
we start to see the explosion problem:
|
||||
|
||||
.nf
|
||||
.in +4n
|
||||
# \fBmount \-\-rbind / /home/henry\fP
|
||||
# \fBmount | awk \(aq{print $1, $2, $3}\(aq\fP
|
||||
/dev/sda1 on /
|
||||
/dev/sdb6 on /mntX
|
||||
/dev/sdb7 on /mntY
|
||||
/dev/sda1 on /home/cecilia
|
||||
/dev/sdb6 on /home/cecilia/mntX
|
||||
/dev/sdb7 on /home/cecilia/mntY
|
||||
/dev/sda1 on /home/henry
|
||||
/dev/sdb6 on /home/henry/mntX
|
||||
/dev/sdb7 on /home/henry/mntY
|
||||
/dev/sda1 on /home/henry/home/cecilia
|
||||
/dev/sdb6 on /home/henry/home/cecilia/mntX
|
||||
/dev/sdb7 on /home/henry/home/cecilia/mntY
|
||||
.in
|
||||
.fi
|
||||
|
||||
Under
|
||||
.IR /home/henry ,
|
||||
we have not only recursively added the
|
||||
.IR /mntX
|
||||
and
|
||||
.IR /mntY
|
||||
mounts, but also the recursive mounts of those directories under
|
||||
.IR /home/cecilia
|
||||
that were created in the previous step.
|
||||
Upon repeating the step for a third user,
|
||||
it becomes obvious that the explosion is exponential in nature:
|
||||
|
||||
.nf
|
||||
.in +4n
|
||||
# \fBmount \-\-rbind / /home/otto\fP
|
||||
# \fBmount | awk \(aq{print $1, $2, $3}\(aq\fP
|
||||
/dev/sda1 on /
|
||||
/dev/sdb6 on /mntX
|
||||
/dev/sdb7 on /mntY
|
||||
/dev/sda1 on /home/cecilia
|
||||
/dev/sdb6 on /home/cecilia/mntX
|
||||
/dev/sdb7 on /home/cecilia/mntY
|
||||
/dev/sda1 on /home/henry
|
||||
/dev/sdb6 on /home/henry/mntX
|
||||
/dev/sdb7 on /home/henry/mntY
|
||||
/dev/sda1 on /home/henry/home/cecilia
|
||||
/dev/sdb6 on /home/henry/home/cecilia/mntX
|
||||
/dev/sdb7 on /home/henry/home/cecilia/mntY
|
||||
/dev/sda1 on /home/otto
|
||||
/dev/sdb6 on /home/otto/mntX
|
||||
/dev/sdb7 on /home/otto/mntY
|
||||
/dev/sda1 on /home/otto/home/cecilia
|
||||
/dev/sdb6 on /home/otto/home/cecilia/mntX
|
||||
/dev/sdb7 on /home/otto/home/cecilia/mntY
|
||||
/dev/sda1 on /home/otto/home/henry
|
||||
/dev/sdb6 on /home/otto/home/henry/mntX
|
||||
/dev/sdb7 on /home/otto/home/henry/mntY
|
||||
/dev/sda1 on /home/otto/home/henry/home/cecilia
|
||||
/dev/sdb6 on /home/otto/home/henry/home/cecilia/mntX
|
||||
/dev/sdb7 on /home/otto/home/henry/home/cecilia/mntY
|
||||
.in
|
||||
.fi
|
||||
|
||||
The mount explosion problem in the above scenario can be avoided
|
||||
by making each of the new mounts unbindable.
|
||||
The effect of doing this is that recursive mounts of the root
|
||||
directory will not replicate the unbindable mounts.
|
||||
We make such a mount for the first user:
|
||||
|
||||
.nf
|
||||
.in +4n
|
||||
# \fBmount \-\-rbind \-\-make\-unbindable / /home/cecilia\fP
|
||||
.in
|
||||
.fi
|
||||
|
||||
Before going further, we show that unbindable mounts are indeed unbindable:
|
||||
|
||||
.nf
|
||||
.in +4n
|
||||
# \fBmkdir /mntZ\fP
|
||||
# \fBmount \-\-bind /home/cecilia /mntZ\fP
|
||||
mount: wrong fs type, bad option, bad superblock on /home/cecilia,
|
||||
missing codepage or helper program, or other error
|
||||
|
||||
In some cases useful info is found in syslog \- try
|
||||
dmesg | tail or so.
|
||||
.in
|
||||
.fi
|
||||
|
||||
Now we create unbindable recursive bind mounts for the other two users:
|
||||
|
||||
.nf
|
||||
.in +4n
|
||||
# \fBmount \-\-rbind \-\-make\-unbindable / /home/henry\fP
|
||||
# \fBmount \-\-rbind \-\-make\-unbindable / /home/otto\fP
|
||||
.in
|
||||
.fi
|
||||
|
||||
Upon examining the list of mount points,
|
||||
we see there has been no explosion of mount points,
|
||||
because the unbindable mounts were not replicated
|
||||
under each user's directory:
|
||||
|
||||
.nf
|
||||
.in +4n
|
||||
# \fBmount | awk \(aq{print $1, $2, $3}\(aq\fP
|
||||
/dev/sda1 on /
|
||||
/dev/sdb6 on /mntX
|
||||
/dev/sdb7 on /mntY
|
||||
/dev/sda1 on /home/cecilia
|
||||
/dev/sdb6 on /home/cecilia/mntX
|
||||
/dev/sdb7 on /home/cecilia/mntY
|
||||
/dev/sda1 on /home/henry
|
||||
/dev/sdb6 on /home/henry/mntX
|
||||
/dev/sdb7 on /home/henry/mntY
|
||||
/dev/sda1 on /home/otto
|
||||
/dev/sdb6 on /home/otto/mntX
|
||||
/dev/sdb7 on /home/otto/mntY
|
||||
.in
|
||||
.fi
|
||||
.\"
|
||||
.SS Propagation type transitions
|
||||
The following table shows the effect that applying a new propagation type
|
||||
(i.e.,
|
||||
.IR "mount \-\-make\-xxxx")
|
||||
has on the existing propagation type of a mount point.
|
||||
The rows correspond to existing propagation types,
|
||||
and the columns are the new propagation settings.
|
||||
For reasons of space, "private" is abbreviated as "priv" and
|
||||
"unbindable" as "unbind".
|
||||
.TS
|
||||
lb2 lb2 lb2 lb2 lb1
|
||||
lb l l l l l.
|
||||
make-shared make-slave make-priv make-unbind
|
||||
shared shared slave/priv [1] priv unbind
|
||||
slave slave+shared slave [2] priv unbind
|
||||
slave+shared slave+shared slave priv unbind
|
||||
private shared priv [2] priv unbind
|
||||
unbindable shared unbind [2] priv unbind
|
||||
.TE
|
||||
|
||||
Note the following details to the table:
|
||||
.IP [1] 4
|
||||
If a shared mount is the only mount in its peer group,
|
||||
making it a slave automatically makes it private.
|
||||
.IP [2]
|
||||
Slaving a nonshared mount has no effect on the mount.
|
||||
.\"
|
||||
.SS Bind (MS_BIND) semantics
|
||||
Suppose that the following command is performed:
|
||||
|
||||
mount \-\-bind A/a B/b
|
||||
|
||||
Here,
|
||||
.I A
|
||||
is the source mount point,
|
||||
.I B
|
||||
is the destination mount point,
|
||||
.I a
|
||||
is a subdirectory path under the mount point
|
||||
.IR A ,
|
||||
and
|
||||
.I b
|
||||
is a subdirectory path under the mount point
|
||||
.IR B .
|
||||
The propagation type of the resulting mount,
|
||||
.IR B/b ,
|
||||
depends on the propagation types of the mount points
|
||||
.IR A
|
||||
and
|
||||
.IR B ,
|
||||
and is summarized in the following table.
|
||||
|
||||
.TS
|
||||
lb2 lb1 lb2 lb2 lb2 lb0
|
||||
lb2 lb1 lb2 lb2 lb2 lb0
|
||||
lb lb l l l l l.
|
||||
source(A)
|
||||
shared private slave unbind
|
||||
_
|
||||
dest(B) shared | shared shared slave+shared invalid
|
||||
nonshared | shared private slave invalid
|
||||
.TE
|
||||
|
||||
Note that a recursive bind of a subtree follows the same semantics
|
||||
as for a bind operation on each mount in the subtree.
|
||||
(Unbindable mounts are automatically pruned at the target mount point.)
|
||||
|
||||
For further details, see
|
||||
.I Documenation/filesystems/sharedsubtrees.txt
|
||||
in the kernel source tree.
|
||||
.\"
|
||||
.SS Move (MS_MOVE) semantics
|
||||
Suppose that the following command is performed:
|
||||
|
||||
mount \-\-move A B/b
|
||||
|
||||
Here,
|
||||
.I A
|
||||
is the source mount point,
|
||||
.I B
|
||||
is the destination mount point, and
|
||||
.I b
|
||||
is a subdirectory path under the mount point
|
||||
.IR B .
|
||||
The propagation type of the resulting mount,
|
||||
.IR B/b ,
|
||||
depends on the propagation types of the mount points
|
||||
.IR A
|
||||
and
|
||||
.IR B ,
|
||||
and is summarized in the following table.
|
||||
|
||||
.TS
|
||||
lb2 lb1 lb2 lb2 lb2 lb0
|
||||
lb2 lb1 lb2 lb2 lb2 lb0
|
||||
lb lb l l l l l.
|
||||
source(A)
|
||||
shared private slave unbind
|
||||
_
|
||||
dest(B) shared | shared shared slave+shared invalid
|
||||
nonshared | shared private slave unbindable
|
||||
.TE
|
||||
|
||||
Note: moving a mount that resides under a shared mount is invalid.
|
||||
|
||||
For further details, see
|
||||
.I Documenation/filesystems/sharedsubtrees.txt
|
||||
in the kernel source tree.
|
||||
.\"
|
||||
.SS Mount semantics
|
||||
Suppose that we use the following command to create a mount point:
|
||||
|
||||
mount device B/b
|
||||
|
||||
Here,
|
||||
.I B
|
||||
is the destination mount point, and
|
||||
.I b
|
||||
is a subdirectory path under the mount point
|
||||
.IR B .
|
||||
The propagation type of the resulting mount,
|
||||
.IR B/b ,
|
||||
follows the same rules as for a bind mount,
|
||||
where the propagation type of the source mount
|
||||
is considered always to be private.
|
||||
.\"
|
||||
.SS Unmount semantics
|
||||
Suppose that we use the following command to tear down a mount point:
|
||||
|
||||
unmount A
|
||||
|
||||
Here,
|
||||
.I A
|
||||
is a mount point on
|
||||
.IR B/b ,
|
||||
where
|
||||
.I B
|
||||
is the parent mount and
|
||||
.I b
|
||||
is a subdirectory path under the mount point
|
||||
.IR B .
|
||||
If
|
||||
.B B
|
||||
is shared, then all most-recently-mounted mounts at
|
||||
.I b
|
||||
on mounts that receive propagation from mount
|
||||
.I B
|
||||
and do not have submounts under them are unmounted.
|
||||
.\"
|
||||
.SH NOTES
|
||||
The kernel default propagation type for mount points is
|
||||
.BR MS_PRIVATE .
|
||||
However,
|
||||
.BR MS_SHARED
|
||||
is typically more commonly required, and for this reason,
|
||||
.BR systemd (1)
|
||||
automatically remounts all mount points as
|
||||
.BR MS_SHARED
|
||||
on system startup.
|
||||
|
||||
Since, when one uses
|
||||
.BR unshare (1)
|
||||
to create a mount namespace,
|
||||
the goal is commonly to provide full isolation of the mount points
|
||||
in the new namespace,
|
||||
.BR unshare (1)
|
||||
(since
|
||||
.IR util-linux
|
||||
version 2.27) in turn reverses the step performed by
|
||||
.BR systemd (1),
|
||||
by making all mount points private in the new namespace.
|
||||
That is,
|
||||
.BR unshare (1)
|
||||
performs the equivalent of the following in the new mount namespace:
|
||||
|
||||
mount \-\-make\-rprivate /
|
||||
|
||||
To prevent this, one can use the
|
||||
.IR "\-\-propagation\ unchanged"
|
||||
option to
|
||||
.BR unshare (1).
|
||||
.SH VERSIONS
|
||||
Mount namespaces first appeared in Linux 2.4.19.
|
||||
.SH CONFORMING TO
|
||||
Namespaces are a Linux-specific feature.
|
||||
.SH SEE ALSO
|
||||
.BR unshare (1),
|
||||
.BR clone (2),
|
||||
.BR mount (2),
|
||||
.BR setns (2),
|
||||
.BR umount (2),
|
||||
.BR unshare (2),
|
||||
.BR proc (5),
|
||||
.BR namespaces (7)
|
||||
|
||||
.IR Documentation/filesystems/sharedsubtree.txt
|
||||
in the kernel source tree.
|
Loading…
Reference in New Issue