Skip to content

Commit d1ddc6f

Browse files
author
Al Viro
committed
fix IS_MNT_PROPAGATING uses
propagate_mnt() does not attach anything to mounts created during propagate_mnt() itself. What's more, anything on ->mnt_slave_list of such new mount must also be new, so we don't need to even look there. When move_mount() had been introduced, we've got an additional class of mounts to skip - if we are moving from anon namespace, we do not want to propagate to mounts we are moving (i.e. all mounts in that anon namespace). Unfortunately, the part about "everything on their ->mnt_slave_list will also be ignorable" is not true - if we have propagation graph A -> B -> C and do OPEN_TREE_CLONE open_tree() of B, we get A -> [B <-> B'] -> C as propagation graph, where B' is a clone of B in our detached tree. Making B private will result in A -> B' -> C C still gets propagation from A, as it would after making B private if we hadn't done that open_tree(), but now the propagation goes through B'. Trying to move_mount() our detached tree on subdirectory in A should have * moved B' on that subdirectory in A * skipped the corresponding subdirectory in B' itself * copied B' on the corresponding subdirectory in C. As it is, the logics in propagation_next() and friends ends up skipping propagation into C, since it doesn't consider anything downstream of B'. IOW, walking the propagation graph should only skip the ->mnt_slave_list of new mounts; the only places where the check for "in that one anon namespace" are applicable are propagate_one() (where we should treat that as the same kind of thing as "mountpoint we are looking at is not visible in the mount we are looking at") and propagation_would_overmount(). The latter is better dealt with in the caller (can_move_mount_beneath()); on the first call of propagation_would_overmount() the test is always false, on the second it is always true in "move from anon namespace" case and always false in "move within our namespace" one, so it's easier to just use check_mnt() before bothering with the second call and be done with that. Fixes: 064fe6e ("mount: handle mount propagation for detached mount trees") Reviewed-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
1 parent 267fc3a commit d1ddc6f

File tree

3 files changed

+12
-10
lines changed

3 files changed

+12
-10
lines changed

fs/namespace.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3557,7 +3557,8 @@ static int can_move_mount_beneath(const struct path *from,
35573557
* @mnt_from itself. This defeats the whole purpose of mounting
35583558
* @mnt_from beneath @mnt_to.
35593559
*/
3560-
if (propagation_would_overmount(parent_mnt_to, mnt_from, mp))
3560+
if (check_mnt(mnt_from) &&
3561+
propagation_would_overmount(parent_mnt_to, mnt_from, mp))
35613562
return -EINVAL;
35623563

35633564
return 0;

fs/pnode.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ static struct mount *propagation_next(struct mount *m,
150150
struct mount *origin)
151151
{
152152
/* are there any slaves of this mount? */
153-
if (!IS_MNT_PROPAGATED(m) && !list_empty(&m->mnt_slave_list))
153+
if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list))
154154
return first_slave(m);
155155

156156
while (1) {
@@ -174,7 +174,7 @@ static struct mount *skip_propagation_subtree(struct mount *m,
174174
* Advance m such that propagation_next will not return
175175
* the slaves of m.
176176
*/
177-
if (!IS_MNT_PROPAGATED(m) && !list_empty(&m->mnt_slave_list))
177+
if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list))
178178
m = last_slave(m);
179179

180180
return m;
@@ -185,7 +185,7 @@ static struct mount *next_group(struct mount *m, struct mount *origin)
185185
while (1) {
186186
while (1) {
187187
struct mount *next;
188-
if (!IS_MNT_PROPAGATED(m) && !list_empty(&m->mnt_slave_list))
188+
if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list))
189189
return first_slave(m);
190190
next = next_peer(m);
191191
if (m->mnt_group_id == origin->mnt_group_id) {
@@ -226,11 +226,15 @@ static int propagate_one(struct mount *m, struct mountpoint *dest_mp)
226226
struct mount *child;
227227
int type;
228228
/* skip ones added by this propagate_mnt() */
229-
if (IS_MNT_PROPAGATED(m))
229+
if (IS_MNT_NEW(m))
230230
return 0;
231-
/* skip if mountpoint isn't covered by it */
231+
/* skip if mountpoint isn't visible in m */
232232
if (!is_subdir(dest_mp->m_dentry, m->mnt.mnt_root))
233233
return 0;
234+
/* skip if m is in the anon_ns we are emptying */
235+
if (m->mnt_ns->mntns_flags & MNTNS_PROPAGATING)
236+
return 0;
237+
234238
if (peers(m, last_dest)) {
235239
type = CL_MAKE_SHARED;
236240
} else {
@@ -380,9 +384,6 @@ bool propagation_would_overmount(const struct mount *from,
380384
if (!IS_MNT_SHARED(from))
381385
return false;
382386

383-
if (IS_MNT_PROPAGATED(to))
384-
return false;
385-
386387
if (to->mnt.mnt_root != mp->m_dentry)
387388
return false;
388389

fs/pnode.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
#define IS_MNT_SHARED(m) ((m)->mnt.mnt_flags & MNT_SHARED)
1414
#define IS_MNT_SLAVE(m) ((m)->mnt_master)
15-
#define IS_MNT_PROPAGATED(m) (!(m)->mnt_ns || ((m)->mnt_ns->mntns_flags & MNTNS_PROPAGATING))
15+
#define IS_MNT_NEW(m) (!(m)->mnt_ns)
1616
#define CLEAR_MNT_SHARED(m) ((m)->mnt.mnt_flags &= ~MNT_SHARED)
1717
#define IS_MNT_UNBINDABLE(m) ((m)->mnt.mnt_flags & MNT_UNBINDABLE)
1818
#define IS_MNT_MARKED(m) ((m)->mnt.mnt_flags & MNT_MARKED)

0 commit comments

Comments
 (0)