aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/namespace.c77
-rw-r--r--fs/pnode.c81
2 files changed, 121 insertions, 37 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 46f99bc585bd..089670363704 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -227,8 +227,17 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
227 mnt->mnt_mountpoint = mnt->mnt_root; 227 mnt->mnt_mountpoint = mnt->mnt_root;
228 mnt->mnt_parent = mnt; 228 mnt->mnt_parent = mnt;
229 229
230 if ((flag & CL_PROPAGATION) || IS_MNT_SHARED(old)) 230 if (flag & CL_SLAVE) {
231 list_add(&mnt->mnt_share, &old->mnt_share); 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 if (flag & CL_MAKE_SHARED) 241 if (flag & CL_MAKE_SHARED)
233 set_mnt_shared(mnt); 242 set_mnt_shared(mnt);
234 243
@@ -689,18 +698,18 @@ Enomem:
689 * 698 *
690 * NOTE: in the table below explains the semantics when a source mount 699 * NOTE: in the table below explains the semantics when a source mount
691 * of a given type is attached to a destination mount of a given type. 700 * of a given type is attached to a destination mount of a given type.
692 * --------------------------------------------- 701 * -------------------------------------------------------------
693 * | BIND MOUNT OPERATION | 702 * | BIND MOUNT OPERATION |
694 * |******************************************** 703 * |*************************************************************
695 * | source-->| shared | private | 704 * | source-->| shared | private | slave |
696 * | dest | | | 705 * | dest | | | |
697 * | | | | | 706 * | | | | | |
698 * | v | | | 707 * | v | | | |
699 * |******************************************** 708 * |*************************************************************
700 * | shared | shared (++) | shared (+) | 709 * | shared | shared (++) | shared (+) | shared(+++)|
701 * | | | | 710 * | | | | |
702 * |non-shared| shared (+) | private | 711 * |non-shared| shared (+) | private | slave (*) |
703 * ********************************************* 712 * **************************************************************
704 * A bind operation clones the source mount and mounts the clone on the 713 * A bind operation clones the source mount and mounts the clone on the
705 * destination mount. 714 * destination mount.
706 * 715 *
@@ -710,21 +719,33 @@ Enomem:
710 * (+) the cloned mount is created under the destination mount and is marked 719 * (+) the cloned mount is created under the destination mount and is marked
711 * as shared. The cloned mount is added to the peer group of the source 720 * as shared. The cloned mount is added to the peer group of the source
712 * mount. 721 * mount.
713 * --------------------------------------------- 722 * (+++) the mount is propagated to all the mounts in the propagation tree
714 * | MOVE MOUNT OPERATION | 723 * of the destination mount and the cloned mount is made slave
715 * |******************************************** 724 * of the same master as that of the source mount. The cloned mount
716 * | source-->| shared | private | 725 * is marked as 'shared and slave'.
717 * | dest | | | 726 * (*) the cloned mount is made a slave of the same master as that of the
718 * | | | | | 727 * source mount.
719 * | v | | | 728 *
720 * |******************************************** 729 * --------------------------------------------------------------
721 * | shared | shared (+) | shared (+) | 730 * | MOVE MOUNT OPERATION |
722 * | | | | 731 * |*************************************************************
723 * |non-shared| shared (+*) | private | 732 * | source-->| shared | private | slave |
724 * ********************************************* 733 * | dest | | | |
725 * (+) the mount is moved to the destination. And is then propagated to all 734 * | | | | | |
726 * the mounts in the propagation tree of the destination mount. 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 * (+*) the mount is moved to the destination. 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 * if the source mount is a tree, the operations explained above is 750 * if the source mount is a tree, the operations explained above is
730 * applied to each mount in the tree. 751 * applied to each mount in the tree.
diff --git a/fs/pnode.c b/fs/pnode.c
index f73eba24f1d1..3e266c5a3071 100644
--- a/fs/pnode.c
+++ b/fs/pnode.c
@@ -17,6 +17,16 @@ static inline struct vfsmount *next_peer(struct vfsmount *p)
17 return list_entry(p->mnt_share.next, struct vfsmount, mnt_share); 17 return list_entry(p->mnt_share.next, struct vfsmount, mnt_share);
18} 18}
19 19
20static inline struct vfsmount *first_slave(struct vfsmount *p)
21{
22 return list_entry(p->mnt_slave_list.next, struct vfsmount, mnt_slave);
23}
24
25static inline struct vfsmount *next_slave(struct vfsmount *p)
26{
27 return list_entry(p->mnt_slave.next, struct vfsmount, mnt_slave);
28}
29
20static int do_make_slave(struct vfsmount *mnt) 30static int do_make_slave(struct vfsmount *mnt)
21{ 31{
22 struct vfsmount *peer_mnt = mnt, *master = mnt->mnt_master; 32 struct vfsmount *peer_mnt = mnt, *master = mnt->mnt_master;
@@ -83,10 +93,64 @@ void change_mnt_propagation(struct vfsmount *mnt, int type)
83static struct vfsmount *propagation_next(struct vfsmount *m, 93static struct vfsmount *propagation_next(struct vfsmount *m,
84 struct vfsmount *origin) 94 struct vfsmount *origin)
85{ 95{
86 m = next_peer(m); 96 /* are there any slaves of this mount? */
87 if (m == origin) 97 if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list))
88 return NULL; 98 return first_slave(m);
89 return 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 }
113}
114
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 */
124static 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;
90} 154}
91 155
92/* 156/*
@@ -114,16 +178,15 @@ int propagate_mnt(struct vfsmount *dest_mnt, struct dentry *dest_dentry,
114 178
115 for (m = propagation_next(dest_mnt, dest_mnt); m; 179 for (m = propagation_next(dest_mnt, dest_mnt); m;
116 m = propagation_next(m, dest_mnt)) { 180 m = propagation_next(m, dest_mnt)) {
117 int type = CL_PROPAGATION; 181 int type;
182 struct vfsmount *source;
118 183
119 if (IS_MNT_NEW(m)) 184 if (IS_MNT_NEW(m))
120 continue; 185 continue;
121 186
122 if (IS_MNT_SHARED(m)) 187 source = get_source(m, prev_dest_mnt, prev_src_mnt, &type);
123 type |= CL_MAKE_SHARED;
124 188
125 if (!(child = copy_tree(source_mnt, source_mnt->mnt_root, 189 if (!(child = copy_tree(source, source->mnt_root, type))) {
126 type))) {
127 ret = -ENOMEM; 190 ret = -ENOMEM;
128 list_splice(tree_list, tmp_list.prev); 191 list_splice(tree_list, tmp_list.prev);
129 goto out; 192 goto out;