Commit 5afe00221389998a25d611dc7941c06580c29eb6

Authored by Ram Pai
Committed by Linus Torvalds
1 parent a58b0eb8e6

[PATCH] handling of slave mounts

This makes bind, rbind, move, clone namespace and umount operations
aware of the semantics of slave mount (see Documentation/sharedsubtree.txt
in the last patch of the series for detailed description).

Signed-off-by: Ram Pai <linuxram@us.ibm.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

Showing 2 changed files with 121 additions and 37 deletions Side-by-side Diff

... ... @@ -227,8 +227,17 @@
227 227 mnt->mnt_mountpoint = mnt->mnt_root;
228 228 mnt->mnt_parent = mnt;
229 229  
230   - if ((flag & CL_PROPAGATION) || IS_MNT_SHARED(old))
231   - list_add(&mnt->mnt_share, &old->mnt_share);
  230 + if (flag & CL_SLAVE) {
  231 + list_add(&mnt->mnt_slave, &old->mnt_slave_list);
  232 + mnt->mnt_master = old;
  233 + CLEAR_MNT_SHARED(mnt);
  234 + } else {
  235 + if ((flag & CL_PROPAGATION) || IS_MNT_SHARED(old))
  236 + list_add(&mnt->mnt_share, &old->mnt_share);
  237 + if (IS_MNT_SLAVE(old))
  238 + list_add(&mnt->mnt_slave, &old->mnt_slave);
  239 + mnt->mnt_master = old->mnt_master;
  240 + }
232 241 if (flag & CL_MAKE_SHARED)
233 242 set_mnt_shared(mnt);
234 243  
... ... @@ -689,18 +698,18 @@
689 698 *
690 699 * NOTE: in the table below explains the semantics when a source mount
691 700 * of a given type is attached to a destination mount of a given type.
692   - * ---------------------------------------------
693   - * | BIND MOUNT OPERATION |
694   - * |********************************************
695   - * | source-->| shared | private |
696   - * | dest | | |
697   - * | | | | |
698   - * | v | | |
699   - * |********************************************
700   - * | shared | shared (++) | shared (+) |
701   - * | | | |
702   - * |non-shared| shared (+) | private |
703   - * *********************************************
  701 + * -------------------------------------------------------------
  702 + * | BIND MOUNT OPERATION |
  703 + * |*************************************************************
  704 + * | source-->| shared | private | slave |
  705 + * | dest | | | |
  706 + * | | | | | |
  707 + * | v | | | |
  708 + * |*************************************************************
  709 + * | shared | shared (++) | shared (+) | shared(+++)|
  710 + * | | | | |
  711 + * |non-shared| shared (+) | private | slave (*) |
  712 + * **************************************************************
704 713 * A bind operation clones the source mount and mounts the clone on the
705 714 * destination mount.
706 715 *
707 716  
... ... @@ -710,21 +719,33 @@
710 719 * (+) the cloned mount is created under the destination mount and is marked
711 720 * as shared. The cloned mount is added to the peer group of the source
712 721 * mount.
713   - * ---------------------------------------------
714   - * | MOVE MOUNT OPERATION |
715   - * |********************************************
716   - * | source-->| shared | private |
717   - * | dest | | |
718   - * | | | | |
719   - * | v | | |
720   - * |********************************************
721   - * | shared | shared (+) | shared (+) |
722   - * | | | |
723   - * |non-shared| shared (+*) | private |
724   - * *********************************************
725   - * (+) the mount is moved to the destination. And is then propagated to all
726   - * the mounts in the propagation tree of the destination mount.
  722 + * (+++) the mount is propagated to all the mounts in the propagation tree
  723 + * of the destination mount and the cloned mount is made slave
  724 + * of the same master as that of the source mount. The cloned mount
  725 + * is marked as 'shared and slave'.
  726 + * (*) the cloned mount is made a slave of the same master as that of the
  727 + * source mount.
  728 + *
  729 + * --------------------------------------------------------------
  730 + * | MOVE MOUNT OPERATION |
  731 + * |*************************************************************
  732 + * | source-->| shared | private | slave |
  733 + * | dest | | | |
  734 + * | | | | | |
  735 + * | v | | | |
  736 + * |*************************************************************
  737 + * | shared | shared (+) | shared (+) | shared(+++) |
  738 + * | | | | |
  739 + * |non-shared| shared (+*) | private | slave (*) |
  740 + * **************************************************************
  741 + *
  742 + * (+) the mount is moved to the destination. And is then propagated to
  743 + * all the mounts in the propagation tree of the destination mount.
727 744 * (+*) the mount is moved to the destination.
  745 + * (+++) the mount is moved to the destination and is then propagated to
  746 + * all the mounts belonging to the destination mount's propagation tree.
  747 + * the mount is marked as 'shared and slave'.
  748 + * (*) the mount continues to be a slave at the new location.
728 749 *
729 750 * if the source mount is a tree, the operations explained above is
730 751 * applied to each mount in the tree.
... ... @@ -17,6 +17,16 @@
17 17 return list_entry(p->mnt_share.next, struct vfsmount, mnt_share);
18 18 }
19 19  
  20 +static inline struct vfsmount *first_slave(struct vfsmount *p)
  21 +{
  22 + return list_entry(p->mnt_slave_list.next, struct vfsmount, mnt_slave);
  23 +}
  24 +
  25 +static inline struct vfsmount *next_slave(struct vfsmount *p)
  26 +{
  27 + return list_entry(p->mnt_slave.next, struct vfsmount, mnt_slave);
  28 +}
  29 +
20 30 static int do_make_slave(struct vfsmount *mnt)
21 31 {
22 32 struct vfsmount *peer_mnt = mnt, *master = mnt->mnt_master;
23 33  
... ... @@ -83,13 +93,67 @@
83 93 static struct vfsmount *propagation_next(struct vfsmount *m,
84 94 struct vfsmount *origin)
85 95 {
86   - m = next_peer(m);
87   - if (m == origin)
88   - return NULL;
89   - return m;
  96 + /* are there any slaves of this mount? */
  97 + if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list))
  98 + return first_slave(m);
  99 +
  100 + while (1) {
  101 + struct vfsmount *next;
  102 + struct vfsmount *master = m->mnt_master;
  103 +
  104 + if ( master == origin->mnt_master ) {
  105 + next = next_peer(m);
  106 + return ((next == origin) ? NULL : next);
  107 + } else if (m->mnt_slave.next != &master->mnt_slave_list)
  108 + return next_slave(m);
  109 +
  110 + /* back at master */
  111 + m = master;
  112 + }
90 113 }
91 114  
92 115 /*
  116 + * return the source mount to be used for cloning
  117 + *
  118 + * @dest the current destination mount
  119 + * @last_dest the last seen destination mount
  120 + * @last_src the last seen source mount
  121 + * @type return CL_SLAVE if the new mount has to be
  122 + * cloned as a slave.
  123 + */
  124 +static struct vfsmount *get_source(struct vfsmount *dest,
  125 + struct vfsmount *last_dest,
  126 + struct vfsmount *last_src,
  127 + int *type)
  128 +{
  129 + struct vfsmount *p_last_src = NULL;
  130 + struct vfsmount *p_last_dest = NULL;
  131 + *type = CL_PROPAGATION;;
  132 +
  133 + if (IS_MNT_SHARED(dest))
  134 + *type |= CL_MAKE_SHARED;
  135 +
  136 + while (last_dest != dest->mnt_master) {
  137 + p_last_dest = last_dest;
  138 + p_last_src = last_src;
  139 + last_dest = last_dest->mnt_master;
  140 + last_src = last_src->mnt_master;
  141 + }
  142 +
  143 + if (p_last_dest) {
  144 + do {
  145 + p_last_dest = next_peer(p_last_dest);
  146 + } while (IS_MNT_NEW(p_last_dest));
  147 + }
  148 +
  149 + if (dest != p_last_dest) {
  150 + *type |= CL_SLAVE;
  151 + return last_src;
  152 + } else
  153 + return p_last_src;
  154 +}
  155 +
  156 +/*
93 157 * mount 'source_mnt' under the destination 'dest_mnt' at
94 158 * dentry 'dest_dentry'. And propagate that mount to
95 159 * all the peer and slave mounts of 'dest_mnt'.
96 160  
97 161  
... ... @@ -114,16 +178,15 @@
114 178  
115 179 for (m = propagation_next(dest_mnt, dest_mnt); m;
116 180 m = propagation_next(m, dest_mnt)) {
117   - int type = CL_PROPAGATION;
  181 + int type;
  182 + struct vfsmount *source;
118 183  
119 184 if (IS_MNT_NEW(m))
120 185 continue;
121 186  
122   - if (IS_MNT_SHARED(m))
123   - type |= CL_MAKE_SHARED;
  187 + source = get_source(m, prev_dest_mnt, prev_src_mnt, &type);
124 188  
125   - if (!(child = copy_tree(source_mnt, source_mnt->mnt_root,
126   - type))) {
  189 + if (!(child = copy_tree(source, source->mnt_root, type))) {
127 190 ret = -ENOMEM;
128 191 list_splice(tree_list, tmp_list.prev);
129 192 goto out;