]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
propagate_one(): get rid of dest_master
authorAl Viro <viro@zeniv.linux.org.uk>
Sat, 21 Jun 2025 21:41:40 +0000 (17:41 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Sun, 29 Jun 2025 23:03:29 +0000 (19:03 -0400)
propagate_mnt() takes the subtree we are about to attach and creates
its copies, setting the propagation between those.  Each copy is cloned
either from the original or from one of the already created copies.
The tricky part is choosing the right copy to serve as a master when we
are starting a new peer group.

The algorithm for doing that selection puts temporary marks on the masters
of mountpoints that already got a copy created for them; since the initial
peer group might have no master at all, we need to special-case that when
looking for the mark.  Currently we do that by memorizing the master of
original peer group.  It works, but we get yet another piece of data to
pass from propagate_mnt() to propagate_one().

Alternative is to mark the master of original peer group if not NULL,
turning the check into "master is NULL or marked".  Less data to pass
around and memory safety is more obvious that way...

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/pnode.c

index b997663de6d0b987f54fb690da08b60ba55679ee..870ebced10aa77b2589fe451ca23467233c366d5 100644 (file)
@@ -215,7 +215,7 @@ static struct mount *next_group(struct mount *m, struct mount *origin)
 }
 
 /* all accesses are serialized by namespace_sem */
-static struct mount *last_dest, *first_source, *last_source, *dest_master;
+static struct mount *last_dest, *first_source, *last_source;
 static struct hlist_head *list;
 
 static int propagate_one(struct mount *m, struct mountpoint *dest_mp)
@@ -239,7 +239,7 @@ static int propagate_one(struct mount *m, struct mountpoint *dest_mp)
                bool done;
                for (n = m; ; n = p) {
                        p = n->mnt_master;
-                       if (p == dest_master || IS_MNT_MARKED(p))
+                       if (!p || IS_MNT_MARKED(p))
                                break;
                }
                do {
@@ -264,7 +264,7 @@ static int propagate_one(struct mount *m, struct mountpoint *dest_mp)
        read_seqlock_excl(&mount_lock);
        mnt_set_mountpoint(m, dest_mp, child);
        read_sequnlock_excl(&mount_lock);
-       if (m->mnt_master != dest_master)
+       if (m->mnt_master)
                SET_MNT_MARK(m->mnt_master);
        last_dest = m;
        last_source = child;
@@ -300,7 +300,8 @@ int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp,
        first_source = source_mnt;
        last_source = source_mnt;
        list = tree_list;
-       dest_master = dest_mnt->mnt_master;
+       if (dest_mnt->mnt_master)
+               SET_MNT_MARK(dest_mnt->mnt_master);
 
        /* all peers of dest_mnt, except dest_mnt itself */
        for (n = next_peer(dest_mnt); n != dest_mnt; n = next_peer(n)) {
@@ -324,9 +325,11 @@ int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp,
 out:
        hlist_for_each_entry(n, tree_list, mnt_hash) {
                m = n->mnt_parent;
-               if (m->mnt_master != dest_mnt->mnt_master)
+               if (m->mnt_master)
                        CLEAR_MNT_MARK(m->mnt_master);
        }
+       if (dest_mnt->mnt_master)
+               CLEAR_MNT_MARK(dest_mnt->mnt_master);
        return ret;
 }