Branch data Line data Source code
1 : : /*
2 : : * linux/fs/pnode.c
3 : : *
4 : : * (C) Copyright IBM Corporation 2005.
5 : : * Released under GPL v2.
6 : : * Author : Ram Pai (linuxram@us.ibm.com)
7 : : *
8 : : */
9 : : #include <linux/mnt_namespace.h>
10 : : #include <linux/mount.h>
11 : : #include <linux/fs.h>
12 : : #include <linux/nsproxy.h>
13 : : #include "internal.h"
14 : : #include "pnode.h"
15 : :
16 : : /* return the next shared peer mount of @p */
17 : : static inline struct mount *next_peer(struct mount *p)
18 : : {
19 : : return list_entry(p->mnt_share.next, struct mount, mnt_share);
20 : : }
21 : :
22 : : static inline struct mount *first_slave(struct mount *p)
23 : : {
24 : : return list_entry(p->mnt_slave_list.next, struct mount, mnt_slave);
25 : : }
26 : :
27 : : static inline struct mount *next_slave(struct mount *p)
28 : : {
29 : : return list_entry(p->mnt_slave.next, struct mount, mnt_slave);
30 : : }
31 : :
32 : 0 : static struct mount *get_peer_under_root(struct mount *mnt,
33 : : struct mnt_namespace *ns,
34 : : const struct path *root)
35 : : {
36 : 0 : struct mount *m = mnt;
37 : :
38 : : do {
39 : : /* Check the namespace first for optimization */
40 [ # # ][ # # ]: 0 : if (m->mnt_ns == ns && is_path_reachable(m, m->mnt.mnt_root, root))
41 : : return m;
42 : :
43 : 0 : m = next_peer(m);
44 [ # # ]: 0 : } while (m != mnt);
45 : :
46 : : return NULL;
47 : : }
48 : :
49 : : /*
50 : : * Get ID of closest dominating peer group having a representative
51 : : * under the given root.
52 : : *
53 : : * Caller must hold namespace_sem
54 : : */
55 : 0 : int get_dominating_id(struct mount *mnt, const struct path *root)
56 : : {
57 : : struct mount *m;
58 : :
59 [ # # ]: 0 : for (m = mnt->mnt_master; m != NULL; m = m->mnt_master) {
60 : 0 : struct mount *d = get_peer_under_root(m, mnt->mnt_ns, root);
61 [ # # ]: 0 : if (d)
62 : 0 : return d->mnt_group_id;
63 : : }
64 : :
65 : : return 0;
66 : : }
67 : :
68 : 0 : static int do_make_slave(struct mount *mnt)
69 : : {
70 : 3177 : struct mount *peer_mnt = mnt, *master = mnt->mnt_master;
71 : : struct mount *slave_mnt;
72 : :
73 : : /*
74 : : * slave 'mnt' to a peer mount that has the
75 : : * same root dentry. If none is available then
76 : : * slave it to anything that is available.
77 : : */
78 [ + + ][ + + ]: 1673 : while ((peer_mnt = next_peer(peer_mnt)) != mnt &&
79 : 697 : peer_mnt->mnt.mnt_root != mnt->mnt.mnt_root) ;
80 : :
81 [ + + ]: 1504 : if (peer_mnt == mnt) {
82 : 976 : peer_mnt = next_peer(mnt);
83 [ + + ]: 976 : if (peer_mnt == mnt)
84 : : peer_mnt = NULL;
85 : : }
86 [ + + ][ + - ]: 1504 : if (mnt->mnt_group_id && IS_MNT_SHARED(mnt) &&
[ + + ]
87 : 988 : list_empty(&mnt->mnt_share))
88 : 398 : mnt_release_group_id(mnt);
89 : :
90 : 3008 : list_del_init(&mnt->mnt_share);
91 : 3008 : mnt->mnt_group_id = 0;
92 : :
93 [ + + ]: 3008 : if (peer_mnt)
94 : : master = peer_mnt;
95 : :
96 [ + + ]: 3008 : if (master) {
97 [ + + ]: 702 : list_for_each_entry(slave_mnt, &mnt->mnt_slave_list, mnt_slave)
98 : 46 : slave_mnt->mnt_master = master;
99 : 656 : list_move(&mnt->mnt_slave, &master->mnt_slave_list);
100 : 656 : list_splice(&mnt->mnt_slave_list, master->mnt_slave_list.prev);
101 : : INIT_LIST_HEAD(&mnt->mnt_slave_list);
102 : : } else {
103 : 848 : struct list_head *p = &mnt->mnt_slave_list;
104 [ + + ]: 883 : while (!list_empty(p)) {
105 : : slave_mnt = list_first_entry(p,
106 : : struct mount, mnt_slave);
107 : 35 : list_del_init(&slave_mnt->mnt_slave);
108 : 35 : slave_mnt->mnt_master = NULL;
109 : : }
110 : : }
111 : 1504 : mnt->mnt_master = master;
112 : 1504 : CLEAR_MNT_SHARED(mnt);
113 : 1504 : return 0;
114 : : }
115 : :
116 : : /*
117 : : * vfsmount lock must be held for write
118 : : */
119 : 0 : void change_mnt_propagation(struct mount *mnt, int type)
120 : : {
121 [ + + ]: 1759 : if (type == MS_SHARED) {
122 : : set_mnt_shared(mnt);
123 : 0 : return;
124 : : }
125 : 1504 : do_make_slave(mnt);
126 [ + ]: 1504 : if (type != MS_SLAVE) {
127 : 1458 : list_del_init(&mnt->mnt_slave);
128 : 1458 : mnt->mnt_master = NULL;
129 [ + + ]: 3217 : if (type == MS_UNBINDABLE)
130 : 36 : mnt->mnt.mnt_flags |= MNT_UNBINDABLE;
131 : : else
132 : 1422 : mnt->mnt.mnt_flags &= ~MNT_UNBINDABLE;
133 : : }
134 : : }
135 : :
136 : : /*
137 : : * get the next mount in the propagation tree.
138 : : * @m: the mount seen last
139 : : * @origin: the original mount from where the tree walk initiated
140 : : *
141 : : * Note that peer groups form contiguous segments of slave lists.
142 : : * We rely on that in get_source() to be able to find out if
143 : : * vfsmount found while iterating with propagation_next() is
144 : : * a peer of one we'd found earlier.
145 : : */
146 : 3905 : static struct mount *propagation_next(struct mount *m,
147 : : struct mount *origin)
148 : : {
149 : : /* are there any slaves of this mount? */
150 [ + - ][ + + ]: 5621 : if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list))
[ + - ][ + + ]
[ + + ][ + ]
[ + - ][ + + ]
[ + - ][ + + ]
[ + + ][ + + ]
151 : 4773 : return first_slave(m);
152 : :
153 : : while (1) {
154 : 4026 : struct mount *master = m->mnt_master;
155 : :
156 [ + - ][ + + ]: 4026 : if (master == origin->mnt_master) {
[ + - ][ + + ]
[ + - ][ + + ]
157 : 3905 : struct mount *next = next_peer(m);
158 [ + + ][ + + ]: 3905 : return (next == origin) ? NULL : next;
[ + + ][ + + ]
[ + + ][ + + ]
159 [ # # ][ + + ]: 121 : } else if (m->mnt_slave.next != &master->mnt_slave_list)
[ # # ][ + + ]
[ # # ][ + + ]
160 : 1588 : return next_slave(m);
161 : :
162 : : /* back at master */
163 : : m = master;
164 : : }
165 : : }
166 : :
167 : : /*
168 : : * return the source mount to be used for cloning
169 : : *
170 : : * @dest the current destination mount
171 : : * @last_dest the last seen destination mount
172 : : * @last_src the last seen source mount
173 : : * @type return CL_SLAVE if the new mount has to be
174 : : * cloned as a slave.
175 : : */
176 : 0 : static struct mount *get_source(struct mount *dest,
177 : : struct mount *last_dest,
178 : : struct mount *last_src,
179 : : int *type)
180 : : {
181 : : struct mount *p_last_src = NULL;
182 : 372 : struct mount *p_last_dest = NULL;
183 : :
184 [ + + ]: 735 : while (last_dest != dest->mnt_master) {
185 : : p_last_dest = last_dest;
186 : : p_last_src = last_src;
187 : 352 : last_dest = last_dest->mnt_master;
188 : 352 : last_src = last_src->mnt_master;
189 : : }
190 : :
191 [ + + ]: 383 : if (p_last_dest) {
192 : : do {
193 : 372 : p_last_dest = next_peer(p_last_dest);
194 [ + + ]: 372 : } while (IS_MNT_NEW(p_last_dest));
195 : : /* is that a peer of the earlier? */
196 [ + + ]: 352 : if (dest == p_last_dest) {
197 : 342 : *type = CL_MAKE_SHARED;
198 : 342 : return p_last_src;
199 : : }
200 : : }
201 : : /* slave of the earlier, then */
202 : 41 : *type = CL_SLAVE;
203 : : /* beginning of peer group among the slaves? */
204 [ + + ]: 41 : if (IS_MNT_SHARED(dest))
205 : 10 : *type |= CL_MAKE_SHARED;
206 : 41 : return last_src;
207 : : }
208 : :
209 : : /*
210 : : * mount 'source_mnt' under the destination 'dest_mnt' at
211 : : * dentry 'dest_dentry'. And propagate that mount to
212 : : * all the peer and slave mounts of 'dest_mnt'.
213 : : * Link all the new mounts into a propagation tree headed at
214 : : * source_mnt. Also link all the new mounts using ->mnt_list
215 : : * headed at source_mnt's ->mnt_list
216 : : *
217 : : * @dest_mnt: destination mount.
218 : : * @dest_dentry: destination dentry.
219 : : * @source_mnt: source mount.
220 : : * @tree_list : list of heads of trees to be attached.
221 : : */
222 : 0 : int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp,
223 : : struct mount *source_mnt, struct list_head *tree_list)
224 : : {
225 : 846 : struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns;
226 : : struct mount *m, *child;
227 : : int ret = 0;
228 : : struct mount *prev_dest_mnt = dest_mnt;
229 : : struct mount *prev_src_mnt = source_mnt;
230 : 846 : LIST_HEAD(tmp_list);
231 : :
232 [ + + ]: 1312 : for (m = propagation_next(dest_mnt, dest_mnt); m;
233 : : m = propagation_next(m, dest_mnt)) {
234 : : int type;
235 : : struct mount *source;
236 : :
237 [ + ]: 466 : if (IS_MNT_NEW(m))
238 : 929 : continue;
239 : :
240 : 0 : source = get_source(m, prev_dest_mnt, prev_src_mnt, &type);
241 : :
242 : : /* Notice when we are propagating across user namespaces */
243 [ - + ]: 383 : if (m->mnt_ns->user_ns != user_ns)
244 : 0 : type |= CL_UNPRIVILEGED;
245 : :
246 : 383 : child = copy_tree(source, source->mnt.mnt_root, type);
247 [ - + ]: 383 : if (IS_ERR(child)) {
248 : : ret = PTR_ERR(child);
249 : 0 : list_splice(tree_list, tmp_list.prev);
250 : 0 : goto out;
251 : : }
252 : :
253 [ + + ]: 383 : if (is_subdir(dest_mp->m_dentry, m->mnt.mnt_root)) {
254 : 321 : mnt_set_mountpoint(m, dest_mp, child);
255 : 321 : list_add_tail(&child->mnt_hash, tree_list);
256 : : } else {
257 : : /*
258 : : * This can happen if the parent mount was bind mounted
259 : : * on some subdirectory of a shared/slave mount.
260 : : */
261 : 62 : list_add_tail(&child->mnt_hash, &tmp_list);
262 : : }
263 : : prev_dest_mnt = m;
264 : : prev_src_mnt = child;
265 : : }
266 : : out:
267 : : lock_mount_hash();
268 [ + + ]: 908 : while (!list_empty(&tmp_list)) {
269 : : child = list_first_entry(&tmp_list, struct mount, mnt_hash);
270 : 62 : umount_tree(child, 0);
271 : : }
272 : : unlock_mount_hash();
273 : 846 : return ret;
274 : : }
275 : :
276 : : /*
277 : : * return true if the refcount is greater than count
278 : : */
279 : : static inline int do_refcount_check(struct mount *mnt, int count)
280 : : {
281 : 1105 : return mnt_get_count(mnt) > count;
282 : : }
283 : :
284 : : /*
285 : : * check if the mount 'mnt' can be unmounted successfully.
286 : : * @mnt: the mount to be checked for unmount
287 : : * NOTE: unmounting 'mnt' would naturally propagate to all
288 : : * other mounts its parent propagates to.
289 : : * Check if any of these mounts that **do not have submounts**
290 : : * have more references than 'refcnt'. If so return busy.
291 : : *
292 : : * vfsmount lock must be held for write
293 : : */
294 : 0 : int propagate_mount_busy(struct mount *mnt, int refcnt)
295 : : {
296 : : struct mount *m, *child;
297 : 747 : struct mount *parent = mnt->mnt_parent;
298 : : int ret = 0;
299 : :
300 [ - + ]: 747 : if (mnt == parent)
301 : 0 : return do_refcount_check(mnt, refcnt);
302 : :
303 : : /*
304 : : * quickly check if the current mount can be unmounted.
305 : : * If not, we don't have to go checking for all other
306 : : * mounts
307 : : */
308 [ + + + ]: 1491 : if (!list_empty(&mnt->mnt_mounts) || do_refcount_check(mnt, refcnt))
309 : : return 1;
310 : :
311 [ + + ]: 2052 : for (m = propagation_next(parent, parent); m;
312 : : m = propagation_next(m, parent)) {
313 : 561 : child = __lookup_mnt_last(&m->mnt, mnt->mnt_mountpoint);
314 [ + + ]: 922 : if (child && list_empty(&child->mnt_mounts) &&
[ + + + - ]
315 : : (ret = do_refcount_check(child, 1)))
316 : : break;
317 : : }
318 : 744 : return ret;
319 : : }
320 : :
321 : : /*
322 : : * NOTE: unmounting 'mnt' naturally propagates to all other mounts its
323 : : * parent propagates to.
324 : : */
325 : 0 : static void __propagate_umount(struct mount *mnt)
326 : : {
327 : 848 : struct mount *parent = mnt->mnt_parent;
328 : : struct mount *m;
329 : :
330 [ - + ]: 848 : BUG_ON(parent == mnt);
331 : :
332 [ + + ]: 1409 : for (m = propagation_next(parent, parent); m;
333 : : m = propagation_next(m, parent)) {
334 : :
335 : 561 : struct mount *child = __lookup_mnt_last(&m->mnt,
336 : : mnt->mnt_mountpoint);
337 : : /*
338 : : * umount the child only if the child has no
339 : : * other children
340 : : */
341 [ + + ][ + + ]: 1409 : if (child && list_empty(&child->mnt_mounts))
342 : 361 : list_move_tail(&child->mnt_hash, &mnt->mnt_hash);
343 : : }
344 : 848 : }
345 : :
346 : : /*
347 : : * collect all mounts that receive propagation from the mount in @list,
348 : : * and return these additional mounts in the same list.
349 : : * @list: the list of mounts to be unmounted.
350 : : *
351 : : * vfsmount lock must be held for write
352 : : */
353 : 0 : int propagate_umount(struct list_head *list)
354 : : {
355 : : struct mount *mnt;
356 : :
357 [ + + ]: 1682 : list_for_each_entry(mnt, list, mnt_hash)
358 : 848 : __propagate_umount(mnt);
359 : 834 : return 0;
360 : : }
|