]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
new predicate: mount_is_ancestor()
authorAl Viro <viro@zeniv.linux.org.uk>
Mon, 9 Jun 2025 03:10:33 +0000 (23:10 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Sun, 29 Jun 2025 22:13:41 +0000 (18:13 -0400)
mount_is_ancestor(p1, p2) returns true iff there is a possibly
empty ancestry chain from p1 to p2.

Convert the open-coded checks.  Unlike those open-coded variants
it does not depend upon p1 not being root...

Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/namespace.c

index f0a56dbceff907d2c79fed30010b3808df55d0c6..aa93e1a48b5da6e561c11161ac28cd60f0b44ea4 100644 (file)
@@ -3483,6 +3483,17 @@ static inline bool path_overmounted(const struct path *path)
        return unlikely(!no_child);
 }
 
+/*
+ * Check if there is a possibly empty chain of descent from p1 to p2.
+ * Locks: namespace_sem (shared) or mount_lock (read_seqlock_excl).
+ */
+static bool mount_is_ancestor(const struct mount *p1, const struct mount *p2)
+{
+       while (p2 != p1 && mnt_has_parent(p2))
+               p2 = p2->mnt_parent;
+       return p2 == p1;
+}
+
 /**
  * can_move_mount_beneath - check that we can mount beneath the top mount
  * @from: mount to mount beneath
@@ -3534,9 +3545,8 @@ static int can_move_mount_beneath(const struct path *from,
        if (parent_mnt_to == current->nsproxy->mnt_ns->root)
                return -EINVAL;
 
-       for (struct mount *p = mnt_from; mnt_has_parent(p); p = p->mnt_parent)
-               if (p == mnt_to)
-                       return -EINVAL;
+       if (mount_is_ancestor(mnt_to, mnt_from))
+               return -EINVAL;
 
        /*
         * If the parent mount propagates to the child mount this would
@@ -3705,9 +3715,8 @@ static int do_move_mount(struct path *old_path,
        err = -ELOOP;
        if (!check_for_nsfs_mounts(old))
                goto out;
-       for (; mnt_has_parent(p); p = p->mnt_parent)
-               if (p == old)
-                       goto out;
+       if (mount_is_ancestor(old, p))
+               goto out;
 
        err = attach_recursive_mnt(old, real_mount(new_path->mnt), mp, flags);
        if (err)