[RFC] vfs: Delay root FS switch after UMH completion
Commit Message
We want to make sure no UMHs started with an old root survive into the
world with the new root (they may fail when it is not expected).
Therefore, insert a wait for existing UMHs termination (this assumes UMH
runtime is finite).
A motivation are asynchronous module loads that start in initrd and they
may be (un)intentionally terminated by a userspace cleanup during rootfs
transition.
This is also inspired by an ancient problem [1].
This is just a rough idea, only superficially tested, no broader context
(VFS locking et al) is considered.
[1] https://kernelnewbies.org/KernelProjects/usermode-helper-enhancements#Filesystem_suspend
Signed-off-by: Michal Koutný <mkoutny@suse.com>
---
I'm not amused by this patch. I'm sending it to get some NAck reasons
(besides indefinite UMH lifetime) and get it off my head. Thanks.
fs/namespace.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
@@ -2931,6 +2931,7 @@ static int do_move_mount(struct path *old_path, struct path *new_path)
struct mount *old;
struct mount *parent;
struct mountpoint *mp, *old_mp;
+ struct path ns_root;
int err;
bool attached;
@@ -2985,6 +2986,14 @@ static int do_move_mount(struct path *old_path, struct path *new_path)
if (p == old)
goto out;
+ ns_root.mnt = ¤t->nsproxy->mnt_ns->root->mnt;
+ ns_root.dentry = ns_root.mnt->mnt_root;
+ path_get(&ns_root);
+ /* See argument in pivot_root() */
+ if (path_equal(new_path, &ns_root))
+ usermodehelper_disable();
+
+
err = attach_recursive_mnt(old, real_mount(new_path->mnt), mp,
attached);
if (err)
@@ -2996,6 +3005,9 @@ static int do_move_mount(struct path *old_path, struct path *new_path)
if (attached)
put_mountpoint(old_mp);
out:
+ if (path_equal(new_path, &ns_root))
+ usermodehelper_enable();
+
unlock_mount(mp);
if (!err) {
if (attached)
@@ -3997,6 +4009,8 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
goto out2;
get_fs_root(current->fs, &root);
+ /* UMHs started from old root should finish before we switch root under */
+ usermodehelper_disable(); // XXX error handling
old_mp = lock_mount(&old);
error = PTR_ERR(old_mp);
if (IS_ERR(old_mp))
@@ -4058,6 +4072,7 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
error = 0;
out4:
unlock_mount(old_mp);
+ usermodehelper_enable();
if (!error)
mntput_no_expire(ex_parent);
out3: