Blame view

fs/pnode.c 11.4 KB
07b20889e   Ram Pai   [PATCH] beginning...
1
2
3
4
5
6
7
8
  /*
   *  linux/fs/pnode.c
   *
   * (C) Copyright IBM Corporation 2005.
   *	Released under GPL v2.
   *	Author : Ram Pai (linuxram@us.ibm.com)
   *
   */
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
9
  #include <linux/mnt_namespace.h>
07b20889e   Ram Pai   [PATCH] beginning...
10
11
  #include <linux/mount.h>
  #include <linux/fs.h>
132c94e31   Eric W. Biederman   vfs: Carefully pr...
12
  #include <linux/nsproxy.h>
6d59e7f58   Al Viro   [PATCH] move a bu...
13
  #include "internal.h"
07b20889e   Ram Pai   [PATCH] beginning...
14
  #include "pnode.h"
03e06e68f   Ram Pai   [PATCH] introduce...
15
  /* return the next shared peer mount of @p */
c937135d9   Al Viro   vfs: spread struc...
16
  static inline struct mount *next_peer(struct mount *p)
03e06e68f   Ram Pai   [PATCH] introduce...
17
  {
6776db3d3   Al Viro   vfs: take mnt_sha...
18
  	return list_entry(p->mnt_share.next, struct mount, mnt_share);
03e06e68f   Ram Pai   [PATCH] introduce...
19
  }
c937135d9   Al Viro   vfs: spread struc...
20
  static inline struct mount *first_slave(struct mount *p)
5afe00221   Ram Pai   [PATCH] handling ...
21
  {
6776db3d3   Al Viro   vfs: take mnt_sha...
22
  	return list_entry(p->mnt_slave_list.next, struct mount, mnt_slave);
5afe00221   Ram Pai   [PATCH] handling ...
23
  }
c937135d9   Al Viro   vfs: spread struc...
24
  static inline struct mount *next_slave(struct mount *p)
5afe00221   Ram Pai   [PATCH] handling ...
25
  {
6776db3d3   Al Viro   vfs: take mnt_sha...
26
  	return list_entry(p->mnt_slave.next, struct mount, mnt_slave);
5afe00221   Ram Pai   [PATCH] handling ...
27
  }
6fc7871fe   Al Viro   vfs: spread struc...
28
29
30
  static struct mount *get_peer_under_root(struct mount *mnt,
  					 struct mnt_namespace *ns,
  					 const struct path *root)
97e7e0f71   Miklos Szeredi   [patch 7/7] vfs: ...
31
  {
6fc7871fe   Al Viro   vfs: spread struc...
32
  	struct mount *m = mnt;
97e7e0f71   Miklos Szeredi   [patch 7/7] vfs: ...
33
34
35
  
  	do {
  		/* Check the namespace first for optimization */
143c8c91c   Al Viro   vfs: mnt_ns moved...
36
  		if (m->mnt_ns == ns && is_path_reachable(m, m->mnt.mnt_root, root))
6fc7871fe   Al Viro   vfs: spread struc...
37
  			return m;
97e7e0f71   Miklos Szeredi   [patch 7/7] vfs: ...
38

c937135d9   Al Viro   vfs: spread struc...
39
  		m = next_peer(m);
6fc7871fe   Al Viro   vfs: spread struc...
40
  	} while (m != mnt);
97e7e0f71   Miklos Szeredi   [patch 7/7] vfs: ...
41
42
43
44
45
46
47
48
49
50
  
  	return NULL;
  }
  
  /*
   * Get ID of closest dominating peer group having a representative
   * under the given root.
   *
   * Caller must hold namespace_sem
   */
6fc7871fe   Al Viro   vfs: spread struc...
51
  int get_dominating_id(struct mount *mnt, const struct path *root)
97e7e0f71   Miklos Szeredi   [patch 7/7] vfs: ...
52
  {
6fc7871fe   Al Viro   vfs: spread struc...
53
  	struct mount *m;
97e7e0f71   Miklos Szeredi   [patch 7/7] vfs: ...
54

32301920f   Al Viro   vfs: and now we c...
55
  	for (m = mnt->mnt_master; m != NULL; m = m->mnt_master) {
143c8c91c   Al Viro   vfs: mnt_ns moved...
56
  		struct mount *d = get_peer_under_root(m, mnt->mnt_ns, root);
97e7e0f71   Miklos Szeredi   [patch 7/7] vfs: ...
57
  		if (d)
15169fe78   Al Viro   vfs: mnt_id/mnt_g...
58
  			return d->mnt_group_id;
97e7e0f71   Miklos Szeredi   [patch 7/7] vfs: ...
59
60
61
62
  	}
  
  	return 0;
  }
6fc7871fe   Al Viro   vfs: spread struc...
63
  static int do_make_slave(struct mount *mnt)
a58b0eb8e   Ram Pai   [PATCH] introduce...
64
  {
32301920f   Al Viro   vfs: and now we c...
65
  	struct mount *peer_mnt = mnt, *master = mnt->mnt_master;
d10e8def0   Al Viro   vfs: take mnt_mas...
66
  	struct mount *slave_mnt;
a58b0eb8e   Ram Pai   [PATCH] introduce...
67
68
69
  
  	/*
  	 * slave 'mnt' to a peer mount that has the
796a6b521   Al Viro   Kill CL_PROPAGATI...
70
  	 * same root dentry. If none is available then
a58b0eb8e   Ram Pai   [PATCH] introduce...
71
72
  	 * slave it to anything that is available.
  	 */
c937135d9   Al Viro   vfs: spread struc...
73
  	while ((peer_mnt = next_peer(peer_mnt)) != mnt &&
6fc7871fe   Al Viro   vfs: spread struc...
74
  	       peer_mnt->mnt.mnt_root != mnt->mnt.mnt_root) ;
a58b0eb8e   Ram Pai   [PATCH] introduce...
75
76
  
  	if (peer_mnt == mnt) {
c937135d9   Al Viro   vfs: spread struc...
77
  		peer_mnt = next_peer(mnt);
a58b0eb8e   Ram Pai   [PATCH] introduce...
78
79
80
  		if (peer_mnt == mnt)
  			peer_mnt = NULL;
  	}
5d477b607   Takashi Iwai   vfs: Fix invalid ...
81
82
  	if (mnt->mnt_group_id && IS_MNT_SHARED(mnt) &&
  	    list_empty(&mnt->mnt_share))
6fc7871fe   Al Viro   vfs: spread struc...
83
  		mnt_release_group_id(mnt);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
84

6776db3d3   Al Viro   vfs: take mnt_sha...
85
  	list_del_init(&mnt->mnt_share);
15169fe78   Al Viro   vfs: mnt_id/mnt_g...
86
  	mnt->mnt_group_id = 0;
a58b0eb8e   Ram Pai   [PATCH] introduce...
87
88
89
90
91
  
  	if (peer_mnt)
  		master = peer_mnt;
  
  	if (master) {
6776db3d3   Al Viro   vfs: take mnt_sha...
92
  		list_for_each_entry(slave_mnt, &mnt->mnt_slave_list, mnt_slave)
32301920f   Al Viro   vfs: and now we c...
93
  			slave_mnt->mnt_master = master;
6776db3d3   Al Viro   vfs: take mnt_sha...
94
95
96
  		list_move(&mnt->mnt_slave, &master->mnt_slave_list);
  		list_splice(&mnt->mnt_slave_list, master->mnt_slave_list.prev);
  		INIT_LIST_HEAD(&mnt->mnt_slave_list);
a58b0eb8e   Ram Pai   [PATCH] introduce...
97
  	} else {
6776db3d3   Al Viro   vfs: take mnt_sha...
98
  		struct list_head *p = &mnt->mnt_slave_list;
a58b0eb8e   Ram Pai   [PATCH] introduce...
99
  		while (!list_empty(p)) {
b5e618181   Pavel Emelianov   Introduce a handy...
100
                          slave_mnt = list_first_entry(p,
6776db3d3   Al Viro   vfs: take mnt_sha...
101
102
  					struct mount, mnt_slave);
  			list_del_init(&slave_mnt->mnt_slave);
a58b0eb8e   Ram Pai   [PATCH] introduce...
103
104
105
  			slave_mnt->mnt_master = NULL;
  		}
  	}
32301920f   Al Viro   vfs: and now we c...
106
  	mnt->mnt_master = master;
fc7be130c   Al Viro   vfs: switch pnode...
107
  	CLEAR_MNT_SHARED(mnt);
a58b0eb8e   Ram Pai   [PATCH] introduce...
108
109
  	return 0;
  }
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
110
111
112
  /*
   * vfsmount lock must be held for write
   */
0f0afb1dc   Al Viro   vfs: spread struc...
113
  void change_mnt_propagation(struct mount *mnt, int type)
07b20889e   Ram Pai   [PATCH] beginning...
114
  {
03e06e68f   Ram Pai   [PATCH] introduce...
115
  	if (type == MS_SHARED) {
b90fa9ae8   Ram Pai   [PATCH] shared mo...
116
  		set_mnt_shared(mnt);
a58b0eb8e   Ram Pai   [PATCH] introduce...
117
118
  		return;
  	}
6fc7871fe   Al Viro   vfs: spread struc...
119
  	do_make_slave(mnt);
a58b0eb8e   Ram Pai   [PATCH] introduce...
120
  	if (type != MS_SLAVE) {
6776db3d3   Al Viro   vfs: take mnt_sha...
121
  		list_del_init(&mnt->mnt_slave);
d10e8def0   Al Viro   vfs: take mnt_mas...
122
  		mnt->mnt_master = NULL;
9676f0c63   Ram Pai   [PATCH] unbindabl...
123
  		if (type == MS_UNBINDABLE)
0f0afb1dc   Al Viro   vfs: spread struc...
124
  			mnt->mnt.mnt_flags |= MNT_UNBINDABLE;
0b03cfb25   Andries E. Brouwer   MNT_UNBINDABLE fix
125
  		else
0f0afb1dc   Al Viro   vfs: spread struc...
126
  			mnt->mnt.mnt_flags &= ~MNT_UNBINDABLE;
03e06e68f   Ram Pai   [PATCH] introduce...
127
  	}
07b20889e   Ram Pai   [PATCH] beginning...
128
  }
b90fa9ae8   Ram Pai   [PATCH] shared mo...
129
130
131
132
133
  
  /*
   * get the next mount in the propagation tree.
   * @m: the mount seen last
   * @origin: the original mount from where the tree walk initiated
796a6b521   Al Viro   Kill CL_PROPAGATI...
134
135
136
137
138
   *
   * Note that peer groups form contiguous segments of slave lists.
   * We rely on that in get_source() to be able to find out if
   * vfsmount found while iterating with propagation_next() is
   * a peer of one we'd found earlier.
b90fa9ae8   Ram Pai   [PATCH] shared mo...
139
   */
c937135d9   Al Viro   vfs: spread struc...
140
141
  static struct mount *propagation_next(struct mount *m,
  					 struct mount *origin)
b90fa9ae8   Ram Pai   [PATCH] shared mo...
142
  {
5afe00221   Ram Pai   [PATCH] handling ...
143
  	/* are there any slaves of this mount? */
143c8c91c   Al Viro   vfs: mnt_ns moved...
144
  	if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list))
5afe00221   Ram Pai   [PATCH] handling ...
145
146
147
  		return first_slave(m);
  
  	while (1) {
32301920f   Al Viro   vfs: and now we c...
148
  		struct mount *master = m->mnt_master;
5afe00221   Ram Pai   [PATCH] handling ...
149

32301920f   Al Viro   vfs: and now we c...
150
  		if (master == origin->mnt_master) {
c937135d9   Al Viro   vfs: spread struc...
151
152
  			struct mount *next = next_peer(m);
  			return (next == origin) ? NULL : next;
6776db3d3   Al Viro   vfs: take mnt_sha...
153
  		} else if (m->mnt_slave.next != &master->mnt_slave_list)
5afe00221   Ram Pai   [PATCH] handling ...
154
155
156
157
158
159
  			return next_slave(m);
  
  		/* back at master */
  		m = master;
  	}
  }
f2ebb3a92   Al Viro   smarter propagate...
160
  static struct mount *next_group(struct mount *m, struct mount *origin)
5afe00221   Ram Pai   [PATCH] handling ...
161
  {
f2ebb3a92   Al Viro   smarter propagate...
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
  	while (1) {
  		while (1) {
  			struct mount *next;
  			if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list))
  				return first_slave(m);
  			next = next_peer(m);
  			if (m->mnt_group_id == origin->mnt_group_id) {
  				if (next == origin)
  					return NULL;
  			} else if (m->mnt_slave.next != &next->mnt_slave)
  				break;
  			m = next;
  		}
  		/* m is the last peer */
  		while (1) {
  			struct mount *master = m->mnt_master;
  			if (m->mnt_slave.next != &master->mnt_slave_list)
  				return next_slave(m);
  			m = next_peer(master);
  			if (master->mnt_group_id == origin->mnt_group_id)
  				break;
  			if (master->mnt_slave.next == &m->mnt_slave)
  				break;
  			m = master;
  		}
  		if (m == origin)
  			return NULL;
5afe00221   Ram Pai   [PATCH] handling ...
189
  	}
f2ebb3a92   Al Viro   smarter propagate...
190
  }
5afe00221   Ram Pai   [PATCH] handling ...
191

f2ebb3a92   Al Viro   smarter propagate...
192
193
  /* all accesses are serialized by namespace_sem */
  static struct user_namespace *user_ns;
5ec0811d3   Eric W. Biederman   propogate_mnt: Ha...
194
  static struct mount *last_dest, *first_source, *last_source, *dest_master;
f2ebb3a92   Al Viro   smarter propagate...
195
196
  static struct mountpoint *mp;
  static struct hlist_head *list;
7ae8fd035   Maxim Patlasov   fs/pnode.c: treat...
197
198
199
200
  static inline bool peers(struct mount *m1, struct mount *m2)
  {
  	return m1->mnt_group_id == m2->mnt_group_id && m1->mnt_group_id;
  }
f2ebb3a92   Al Viro   smarter propagate...
201
202
203
204
205
206
207
208
209
210
  static int propagate_one(struct mount *m)
  {
  	struct mount *child;
  	int type;
  	/* skip ones added by this propagate_mnt() */
  	if (IS_MNT_NEW(m))
  		return 0;
  	/* skip if mountpoint isn't covered by it */
  	if (!is_subdir(mp->m_dentry, m->mnt.mnt_root))
  		return 0;
7ae8fd035   Maxim Patlasov   fs/pnode.c: treat...
211
  	if (peers(m, last_dest)) {
f2ebb3a92   Al Viro   smarter propagate...
212
213
214
  		type = CL_MAKE_SHARED;
  	} else {
  		struct mount *n, *p;
5ec0811d3   Eric W. Biederman   propogate_mnt: Ha...
215
  		bool done;
f2ebb3a92   Al Viro   smarter propagate...
216
217
  		for (n = m; ; n = p) {
  			p = n->mnt_master;
5ec0811d3   Eric W. Biederman   propogate_mnt: Ha...
218
  			if (p == dest_master || IS_MNT_MARKED(p))
f2ebb3a92   Al Viro   smarter propagate...
219
  				break;
796a6b521   Al Viro   Kill CL_PROPAGATI...
220
  		}
5ec0811d3   Eric W. Biederman   propogate_mnt: Ha...
221
222
223
224
225
226
227
228
229
  		do {
  			struct mount *parent = last_source->mnt_parent;
  			if (last_source == first_source)
  				break;
  			done = parent->mnt_master == p;
  			if (done && peers(n, parent))
  				break;
  			last_source = last_source->mnt_master;
  		} while (!done);
f2ebb3a92   Al Viro   smarter propagate...
230
231
232
233
  		type = CL_SLAVE;
  		/* beginning of peer group among the slaves? */
  		if (IS_MNT_SHARED(m))
  			type |= CL_MAKE_SHARED;
5afe00221   Ram Pai   [PATCH] handling ...
234
  	}
f2ebb3a92   Al Viro   smarter propagate...
235
236
237
238
239
240
241
  		
  	/* Notice when we are propagating across user namespaces */
  	if (m->mnt_ns->user_ns != user_ns)
  		type |= CL_UNPRIVILEGED;
  	child = copy_tree(last_source, last_source->mnt.mnt_root, type);
  	if (IS_ERR(child))
  		return PTR_ERR(child);
8486a7882   Eric W. Biederman   mnt: Move the cle...
242
  	child->mnt.mnt_flags &= ~MNT_LOCKED;
f2ebb3a92   Al Viro   smarter propagate...
243
244
245
246
247
248
249
250
251
  	mnt_set_mountpoint(m, mp, child);
  	last_dest = m;
  	last_source = child;
  	if (m->mnt_master != dest_master) {
  		read_seqlock_excl(&mount_lock);
  		SET_MNT_MARK(m->mnt_master);
  		read_sequnlock_excl(&mount_lock);
  	}
  	hlist_add_head(&child->mnt_hash, list);
d29216842   Eric W. Biederman   mnt: Add a per mo...
252
  	return count_mounts(m->mnt_ns, child);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
  }
  
  /*
   * mount 'source_mnt' under the destination 'dest_mnt' at
   * dentry 'dest_dentry'. And propagate that mount to
   * all the peer and slave mounts of 'dest_mnt'.
   * Link all the new mounts into a propagation tree headed at
   * source_mnt. Also link all the new mounts using ->mnt_list
   * headed at source_mnt's ->mnt_list
   *
   * @dest_mnt: destination mount.
   * @dest_dentry: destination dentry.
   * @source_mnt: source mount.
   * @tree_list : list of heads of trees to be attached.
   */
84d17192d   Al Viro   get rid of full-h...
268
  int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp,
38129a13e   Al Viro   switch mnt_hash t...
269
  		    struct mount *source_mnt, struct hlist_head *tree_list)
b90fa9ae8   Ram Pai   [PATCH] shared mo...
270
  {
f2ebb3a92   Al Viro   smarter propagate...
271
  	struct mount *m, *n;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
272
  	int ret = 0;
132c94e31   Eric W. Biederman   vfs: Carefully pr...
273

f2ebb3a92   Al Viro   smarter propagate...
274
275
276
277
278
279
280
  	/*
  	 * we don't want to bother passing tons of arguments to
  	 * propagate_one(); everything is serialized by namespace_sem,
  	 * so globals will do just fine.
  	 */
  	user_ns = current->nsproxy->mnt_ns->user_ns;
  	last_dest = dest_mnt;
5ec0811d3   Eric W. Biederman   propogate_mnt: Ha...
281
  	first_source = source_mnt;
f2ebb3a92   Al Viro   smarter propagate...
282
283
284
285
286
287
288
289
290
  	last_source = source_mnt;
  	mp = dest_mp;
  	list = tree_list;
  	dest_master = dest_mnt->mnt_master;
  
  	/* all peers of dest_mnt, except dest_mnt itself */
  	for (n = next_peer(dest_mnt); n != dest_mnt; n = next_peer(n)) {
  		ret = propagate_one(n);
  		if (ret)
b90fa9ae8   Ram Pai   [PATCH] shared mo...
291
  			goto out;
f2ebb3a92   Al Viro   smarter propagate...
292
  	}
b90fa9ae8   Ram Pai   [PATCH] shared mo...
293

f2ebb3a92   Al Viro   smarter propagate...
294
295
296
297
298
299
300
301
302
303
304
  	/* all slave groups */
  	for (m = next_group(dest_mnt, dest_mnt); m;
  			m = next_group(m, dest_mnt)) {
  		/* everything in that slave group */
  		n = m;
  		do {
  			ret = propagate_one(n);
  			if (ret)
  				goto out;
  			n = next_peer(n);
  		} while (n != m);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
305
306
  	}
  out:
f2ebb3a92   Al Viro   smarter propagate...
307
308
309
310
311
  	read_seqlock_excl(&mount_lock);
  	hlist_for_each_entry(n, tree_list, mnt_hash) {
  		m = n->mnt_parent;
  		if (m->mnt_master != dest_mnt->mnt_master)
  			CLEAR_MNT_MARK(m->mnt_master);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
312
  	}
f2ebb3a92   Al Viro   smarter propagate...
313
  	read_sequnlock_excl(&mount_lock);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
314
315
  	return ret;
  }
a05964f39   Ram Pai   [PATCH] shared mo...
316
317
318
319
  
  /*
   * return true if the refcount is greater than count
   */
1ab597386   Al Viro   vfs: spread struc...
320
  static inline int do_refcount_check(struct mount *mnt, int count)
a05964f39   Ram Pai   [PATCH] shared mo...
321
  {
aba809cf0   Al Viro   namespace.c: get ...
322
  	return mnt_get_count(mnt) > count;
a05964f39   Ram Pai   [PATCH] shared mo...
323
324
325
326
327
328
329
330
331
  }
  
  /*
   * check if the mount 'mnt' can be unmounted successfully.
   * @mnt: the mount to be checked for unmount
   * NOTE: unmounting 'mnt' would naturally propagate to all
   * other mounts its parent propagates to.
   * Check if any of these mounts that **do not have submounts**
   * have more references than 'refcnt'. If so return busy.
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
332
   *
b3e19d924   Nick Piggin   fs: scale mntget/...
333
   * vfsmount lock must be held for write
a05964f39   Ram Pai   [PATCH] shared mo...
334
   */
1ab597386   Al Viro   vfs: spread struc...
335
  int propagate_mount_busy(struct mount *mnt, int refcnt)
a05964f39   Ram Pai   [PATCH] shared mo...
336
  {
c937135d9   Al Viro   vfs: spread struc...
337
  	struct mount *m, *child;
0714a5338   Al Viro   vfs: now it can b...
338
  	struct mount *parent = mnt->mnt_parent;
a05964f39   Ram Pai   [PATCH] shared mo...
339
  	int ret = 0;
0714a5338   Al Viro   vfs: now it can b...
340
  	if (mnt == parent)
a05964f39   Ram Pai   [PATCH] shared mo...
341
342
343
344
345
346
347
  		return do_refcount_check(mnt, refcnt);
  
  	/*
  	 * quickly check if the current mount can be unmounted.
  	 * If not, we don't have to go checking for all other
  	 * mounts
  	 */
6b41d536f   Al Viro   vfs: take mnt_chi...
348
  	if (!list_empty(&mnt->mnt_mounts) || do_refcount_check(mnt, refcnt))
a05964f39   Ram Pai   [PATCH] shared mo...
349
  		return 1;
c937135d9   Al Viro   vfs: spread struc...
350
351
  	for (m = propagation_next(parent, parent); m;
  	     		m = propagation_next(m, parent)) {
474279dc0   Al Viro   split __lookup_mn...
352
  		child = __lookup_mnt_last(&m->mnt, mnt->mnt_mountpoint);
6b41d536f   Al Viro   vfs: take mnt_chi...
353
  		if (child && list_empty(&child->mnt_mounts) &&
1ab597386   Al Viro   vfs: spread struc...
354
  		    (ret = do_refcount_check(child, 1)))
a05964f39   Ram Pai   [PATCH] shared mo...
355
356
357
358
359
360
  			break;
  	}
  	return ret;
  }
  
  /*
5d88457eb   Eric W. Biederman   mnt: On an unmoun...
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
   * Clear MNT_LOCKED when it can be shown to be safe.
   *
   * mount_lock lock must be held for write
   */
  void propagate_mount_unlock(struct mount *mnt)
  {
  	struct mount *parent = mnt->mnt_parent;
  	struct mount *m, *child;
  
  	BUG_ON(parent == mnt);
  
  	for (m = propagation_next(parent, parent); m;
  			m = propagation_next(m, parent)) {
  		child = __lookup_mnt_last(&m->mnt, mnt->mnt_mountpoint);
  		if (child)
  			child->mnt.mnt_flags &= ~MNT_LOCKED;
  	}
  }
  
  /*
0c56fe314   Eric W. Biederman   mnt: Don't propag...
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
   * Mark all mounts that the MNT_LOCKED logic will allow to be unmounted.
   */
  static void mark_umount_candidates(struct mount *mnt)
  {
  	struct mount *parent = mnt->mnt_parent;
  	struct mount *m;
  
  	BUG_ON(parent == mnt);
  
  	for (m = propagation_next(parent, parent); m;
  			m = propagation_next(m, parent)) {
  		struct mount *child = __lookup_mnt_last(&m->mnt,
  						mnt->mnt_mountpoint);
  		if (child && (!IS_MNT_LOCKED(child) || IS_MNT_MARKED(m))) {
  			SET_MNT_MARK(child);
  		}
  	}
  }
  
  /*
a05964f39   Ram Pai   [PATCH] shared mo...
401
402
403
   * NOTE: unmounting 'mnt' naturally propagates to all other mounts its
   * parent propagates to.
   */
61ef47b1e   Al Viro   vfs: spread struc...
404
  static void __propagate_umount(struct mount *mnt)
a05964f39   Ram Pai   [PATCH] shared mo...
405
  {
0714a5338   Al Viro   vfs: now it can b...
406
  	struct mount *parent = mnt->mnt_parent;
c937135d9   Al Viro   vfs: spread struc...
407
  	struct mount *m;
a05964f39   Ram Pai   [PATCH] shared mo...
408

0714a5338   Al Viro   vfs: now it can b...
409
  	BUG_ON(parent == mnt);
a05964f39   Ram Pai   [PATCH] shared mo...
410

c937135d9   Al Viro   vfs: spread struc...
411
412
  	for (m = propagation_next(parent, parent); m;
  			m = propagation_next(m, parent)) {
a05964f39   Ram Pai   [PATCH] shared mo...
413

474279dc0   Al Viro   split __lookup_mn...
414
415
  		struct mount *child = __lookup_mnt_last(&m->mnt,
  						mnt->mnt_mountpoint);
a05964f39   Ram Pai   [PATCH] shared mo...
416
  		/*
0c56fe314   Eric W. Biederman   mnt: Don't propag...
417
418
  		 * umount the child only if the child has no children
  		 * and the child is marked safe to unmount.
a05964f39   Ram Pai   [PATCH] shared mo...
419
  		 */
0c56fe314   Eric W. Biederman   mnt: Don't propag...
420
421
422
423
  		if (!child || !IS_MNT_MARKED(child))
  			continue;
  		CLEAR_MNT_MARK(child);
  		if (list_empty(&child->mnt_mounts)) {
88b368f27   Al Viro   get rid of propag...
424
  			list_del_init(&child->mnt_child);
590ce4bcb   Eric W. Biederman   mnt: Add MNT_UMOU...
425
  			child->mnt.mnt_flags |= MNT_UMOUNT;
c003b26ff   Eric W. Biederman   mnt: In umount_tr...
426
  			list_move_tail(&child->mnt_list, &mnt->mnt_list);
38129a13e   Al Viro   switch mnt_hash t...
427
  		}
a05964f39   Ram Pai   [PATCH] shared mo...
428
429
430
431
432
433
434
  	}
  }
  
  /*
   * collect all mounts that receive propagation from the mount in @list,
   * and return these additional mounts in the same list.
   * @list: the list of mounts to be unmounted.
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
435
436
   *
   * vfsmount lock must be held for write
a05964f39   Ram Pai   [PATCH] shared mo...
437
   */
c003b26ff   Eric W. Biederman   mnt: In umount_tr...
438
  int propagate_umount(struct list_head *list)
a05964f39   Ram Pai   [PATCH] shared mo...
439
  {
61ef47b1e   Al Viro   vfs: spread struc...
440
  	struct mount *mnt;
a05964f39   Ram Pai   [PATCH] shared mo...
441

0c56fe314   Eric W. Biederman   mnt: Don't propag...
442
443
  	list_for_each_entry_reverse(mnt, list, mnt_list)
  		mark_umount_candidates(mnt);
c003b26ff   Eric W. Biederman   mnt: In umount_tr...
444
  	list_for_each_entry(mnt, list, mnt_list)
a05964f39   Ram Pai   [PATCH] shared mo...
445
446
447
  		__propagate_umount(mnt);
  	return 0;
  }