Skip to content

Commit 1dd5915

Browse files
committed
Merge tag 'fs.move_mount.move_mount_set_group.v5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux
Pull move_mount updates from Christian Brauner: "This contains an extension to the move_mount() syscall making it possible to add a single private mount into an existing propagation tree. The use-case comes from the criu folks which have been struggling with restoring complex mount trees for a long time. Variations of this work have been discussed at Plumbers before, e.g. https://www.linuxplumbersconf.org/event/7/contributions/640/ The extension to move_mount() enables criu to restore any set of mount namespaces, mount trees and sharing group trees without introducing yet more complexity into mount propagation itself. The changes required to criu to make use of this and restore complex propagation trees are available at https://github.com/Snorch/criu/commits/mount-v2-poc A cleaned-up version of this will go up for merging into the main criu repo after this lands" * tag 'fs.move_mount.move_mount_set_group.v5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux: tests: add move_mount(MOVE_MOUNT_SET_GROUP) selftest move_mount: allow to add a mount into an existing group
2 parents 0ee7c3e + 8374f43 commit 1dd5915

File tree

7 files changed

+463
-2
lines changed

7 files changed

+463
-2
lines changed

fs/namespace.c

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2694,6 +2694,78 @@ static bool check_for_nsfs_mounts(struct mount *subtree)
26942694
return ret;
26952695
}
26962696

2697+
static int do_set_group(struct path *from_path, struct path *to_path)
2698+
{
2699+
struct mount *from, *to;
2700+
int err;
2701+
2702+
from = real_mount(from_path->mnt);
2703+
to = real_mount(to_path->mnt);
2704+
2705+
namespace_lock();
2706+
2707+
err = -EINVAL;
2708+
/* To and From must be mounted */
2709+
if (!is_mounted(&from->mnt))
2710+
goto out;
2711+
if (!is_mounted(&to->mnt))
2712+
goto out;
2713+
2714+
err = -EPERM;
2715+
/* We should be allowed to modify mount namespaces of both mounts */
2716+
if (!ns_capable(from->mnt_ns->user_ns, CAP_SYS_ADMIN))
2717+
goto out;
2718+
if (!ns_capable(to->mnt_ns->user_ns, CAP_SYS_ADMIN))
2719+
goto out;
2720+
2721+
err = -EINVAL;
2722+
/* To and From paths should be mount roots */
2723+
if (from_path->dentry != from_path->mnt->mnt_root)
2724+
goto out;
2725+
if (to_path->dentry != to_path->mnt->mnt_root)
2726+
goto out;
2727+
2728+
/* Setting sharing groups is only allowed across same superblock */
2729+
if (from->mnt.mnt_sb != to->mnt.mnt_sb)
2730+
goto out;
2731+
2732+
/* From mount root should be wider than To mount root */
2733+
if (!is_subdir(to->mnt.mnt_root, from->mnt.mnt_root))
2734+
goto out;
2735+
2736+
/* From mount should not have locked children in place of To's root */
2737+
if (has_locked_children(from, to->mnt.mnt_root))
2738+
goto out;
2739+
2740+
/* Setting sharing groups is only allowed on private mounts */
2741+
if (IS_MNT_SHARED(to) || IS_MNT_SLAVE(to))
2742+
goto out;
2743+
2744+
/* From should not be private */
2745+
if (!IS_MNT_SHARED(from) && !IS_MNT_SLAVE(from))
2746+
goto out;
2747+
2748+
if (IS_MNT_SLAVE(from)) {
2749+
struct mount *m = from->mnt_master;
2750+
2751+
list_add(&to->mnt_slave, &m->mnt_slave_list);
2752+
to->mnt_master = m;
2753+
}
2754+
2755+
if (IS_MNT_SHARED(from)) {
2756+
to->mnt_group_id = from->mnt_group_id;
2757+
list_add(&to->mnt_share, &from->mnt_share);
2758+
lock_mount_hash();
2759+
set_mnt_shared(to);
2760+
unlock_mount_hash();
2761+
}
2762+
2763+
err = 0;
2764+
out:
2765+
namespace_unlock();
2766+
return err;
2767+
}
2768+
26972769
static int do_move_mount(struct path *old_path, struct path *new_path)
26982770
{
26992771
struct mnt_namespace *ns;
@@ -3678,7 +3750,10 @@ SYSCALL_DEFINE5(move_mount,
36783750
if (ret < 0)
36793751
goto out_to;
36803752

3681-
ret = do_move_mount(&from_path, &to_path);
3753+
if (flags & MOVE_MOUNT_SET_GROUP)
3754+
ret = do_set_group(&from_path, &to_path);
3755+
else
3756+
ret = do_move_mount(&from_path, &to_path);
36823757

36833758
out_to:
36843759
path_put(&to_path);

include/uapi/linux/mount.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@
7373
#define MOVE_MOUNT_T_SYMLINKS 0x00000010 /* Follow symlinks on to path */
7474
#define MOVE_MOUNT_T_AUTOMOUNTS 0x00000020 /* Follow automounts on to path */
7575
#define MOVE_MOUNT_T_EMPTY_PATH 0x00000040 /* Empty to path permitted */
76-
#define MOVE_MOUNT__MASK 0x00000077
76+
#define MOVE_MOUNT_SET_GROUP 0x00000100 /* Set sharing group instead */
77+
#define MOVE_MOUNT__MASK 0x00000177
7778

7879
/*
7980
* fsopen() flags.

tools/testing/selftests/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ TARGETS += memory-hotplug
3535
TARGETS += mincore
3636
TARGETS += mount
3737
TARGETS += mount_setattr
38+
TARGETS += move_mount_set_group
3839
TARGETS += mqueue
3940
TARGETS += nci
4041
TARGETS += net
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
move_mount_set_group_test
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
# Makefile for mount selftests.
3+
CFLAGS = -g -I../../../../usr/include/ -Wall -O2
4+
5+
TEST_GEN_FILES += move_mount_set_group_test
6+
7+
include ../lib.mk
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CONFIG_USER_NS=y

0 commit comments

Comments
 (0)