reorganize do_make_slave()
authorAl Viro <viro@zeniv.linux.org.uk>
Mon, 21 Nov 2016 00:33:09 +0000 (19:33 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Fri, 16 Dec 2016 21:30:49 +0000 (16:30 -0500)
Make sure that clone_mnt() never returns a mount with MNT_SHARED in
flags, but without a valid ->mnt_group_id.  That allows to demystify
do_make_slave() quite a bit, among other things.

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

index ec726ae..141d577 100644 (file)
@@ -1030,6 +1030,8 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
                if (IS_MNT_SLAVE(old))
                        list_add(&mnt->mnt_slave, &old->mnt_slave);
                mnt->mnt_master = old->mnt_master;
+       } else {
+               CLEAR_MNT_SHARED(mnt);
        }
        if (flag & CL_MAKE_SHARED)
                set_mnt_shared(mnt);
index 234a9ac..06a793f 100644 (file)
@@ -67,49 +67,47 @@ int get_dominating_id(struct mount *mnt, const struct path *root)
 
 static int do_make_slave(struct mount *mnt)
 {
-       struct mount *peer_mnt = mnt, *master = mnt->mnt_master;
-       struct mount *slave_mnt;
+       struct mount *master, *slave_mnt;
 
-       /*
-        * slave 'mnt' to a peer mount that has the
-        * same root dentry. If none is available then
-        * slave it to anything that is available.
-        */
-       while ((peer_mnt = next_peer(peer_mnt)) != mnt &&
-              peer_mnt->mnt.mnt_root != mnt->mnt.mnt_root) ;
-
-       if (peer_mnt == mnt) {
-               peer_mnt = next_peer(mnt);
-               if (peer_mnt == mnt)
-                       peer_mnt = NULL;
-       }
-       if (mnt->mnt_group_id && IS_MNT_SHARED(mnt) &&
-           list_empty(&mnt->mnt_share))
-               mnt_release_group_id(mnt);
-
-       list_del_init(&mnt->mnt_share);
-       mnt->mnt_group_id = 0;
-
-       if (peer_mnt)
-               master = peer_mnt;
-
-       if (master) {
-               list_for_each_entry(slave_mnt, &mnt->mnt_slave_list, mnt_slave)
-                       slave_mnt->mnt_master = master;
-               list_move(&mnt->mnt_slave, &master->mnt_slave_list);
-               list_splice(&mnt->mnt_slave_list, master->mnt_slave_list.prev);
-               INIT_LIST_HEAD(&mnt->mnt_slave_list);
+       if (list_empty(&mnt->mnt_share)) {
+               if (IS_MNT_SHARED(mnt)) {
+                       mnt_release_group_id(mnt);
+                       CLEAR_MNT_SHARED(mnt);
+               }
+               master = mnt->mnt_master;
+               if (!master) {
+                       struct list_head *p = &mnt->mnt_slave_list;
+                       while (!list_empty(p)) {
+                               slave_mnt = list_first_entry(p,
+                                               struct mount, mnt_slave);
+                               list_del_init(&slave_mnt->mnt_slave);
+                               slave_mnt->mnt_master = NULL;
+                       }
+                       return 0;
+               }
        } else {
-               struct list_head *p = &mnt->mnt_slave_list;
-               while (!list_empty(p)) {
-                        slave_mnt = list_first_entry(p,
-                                       struct mount, mnt_slave);
-                       list_del_init(&slave_mnt->mnt_slave);
-                       slave_mnt->mnt_master = NULL;
+               struct mount *m;
+               /*
+                * slave 'mnt' to a peer mount that has the
+                * same root dentry. If none is available then
+                * slave it to anything that is available.
+                */
+               for (m = master = next_peer(mnt); m != mnt; m = next_peer(m)) {
+                       if (m->mnt.mnt_root == mnt->mnt.mnt_root) {
+                               master = m;
+                               break;
+                       }
                }
+               list_del_init(&mnt->mnt_share);
+               mnt->mnt_group_id = 0;
+               CLEAR_MNT_SHARED(mnt);
        }
+       list_for_each_entry(slave_mnt, &mnt->mnt_slave_list, mnt_slave)
+               slave_mnt->mnt_master = master;
+       list_move(&mnt->mnt_slave, &master->mnt_slave_list);
+       list_splice(&mnt->mnt_slave_list, master->mnt_slave_list.prev);
+       INIT_LIST_HEAD(&mnt->mnt_slave_list);
        mnt->mnt_master = master;
-       CLEAR_MNT_SHARED(mnt);
        return 0;
 }