diff options
-rw-r--r-- | fs/namespace.c | 77 | ||||
-rw-r--r-- | fs/pnode.c | 81 |
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 | ||
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 | static int do_make_slave(struct vfsmount *mnt) | 30 | static 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) | |||
83 | static struct vfsmount *propagation_next(struct vfsmount *m, | 93 | static 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 | */ | ||
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; | ||
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; |