Commit 5afe00221389998a25d611dc7941c06580c29eb6
Committed by
Linus Torvalds
1 parent
a58b0eb8e6
Exists in
master
and in
4 other branches
[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
fs/namespace.c
... | ... | @@ -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. |
fs/pnode.c
... | ... | @@ -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; |