Blame view

fs/pnode.c 15.3 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
  }
54fcb2303   Eric W. Biederman   mnt: Make propaga...
24
25
26
27
  static inline struct mount *last_slave(struct mount *p)
  {
  	return list_entry(p->mnt_slave_list.prev, struct mount, mnt_slave);
  }
c937135d9   Al Viro   vfs: spread struc...
28
  static inline struct mount *next_slave(struct mount *p)
5afe00221   Ram Pai   [PATCH] handling ...
29
  {
6776db3d3   Al Viro   vfs: take mnt_sha...
30
  	return list_entry(p->mnt_slave.next, struct mount, mnt_slave);
5afe00221   Ram Pai   [PATCH] handling ...
31
  }
6fc7871fe   Al Viro   vfs: spread struc...
32
33
34
  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: ...
35
  {
6fc7871fe   Al Viro   vfs: spread struc...
36
  	struct mount *m = mnt;
97e7e0f71   Miklos Szeredi   [patch 7/7] vfs: ...
37
38
39
  
  	do {
  		/* Check the namespace first for optimization */
143c8c91c   Al Viro   vfs: mnt_ns moved...
40
  		if (m->mnt_ns == ns && is_path_reachable(m, m->mnt.mnt_root, root))
6fc7871fe   Al Viro   vfs: spread struc...
41
  			return m;
97e7e0f71   Miklos Szeredi   [patch 7/7] vfs: ...
42

c937135d9   Al Viro   vfs: spread struc...
43
  		m = next_peer(m);
6fc7871fe   Al Viro   vfs: spread struc...
44
  	} while (m != mnt);
97e7e0f71   Miklos Szeredi   [patch 7/7] vfs: ...
45
46
47
48
49
50
51
52
53
54
  
  	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...
55
  int get_dominating_id(struct mount *mnt, const struct path *root)
97e7e0f71   Miklos Szeredi   [patch 7/7] vfs: ...
56
  {
6fc7871fe   Al Viro   vfs: spread struc...
57
  	struct mount *m;
97e7e0f71   Miklos Szeredi   [patch 7/7] vfs: ...
58

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

6776db3d3   Al Viro   vfs: take mnt_sha...
89
  	list_del_init(&mnt->mnt_share);
15169fe78   Al Viro   vfs: mnt_id/mnt_g...
90
  	mnt->mnt_group_id = 0;
a58b0eb8e   Ram Pai   [PATCH] introduce...
91
92
93
94
95
  
  	if (peer_mnt)
  		master = peer_mnt;
  
  	if (master) {
6776db3d3   Al Viro   vfs: take mnt_sha...
96
  		list_for_each_entry(slave_mnt, &mnt->mnt_slave_list, mnt_slave)
32301920f   Al Viro   vfs: and now we c...
97
  			slave_mnt->mnt_master = master;
6776db3d3   Al Viro   vfs: take mnt_sha...
98
99
100
  		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...
101
  	} else {
6776db3d3   Al Viro   vfs: take mnt_sha...
102
  		struct list_head *p = &mnt->mnt_slave_list;
a58b0eb8e   Ram Pai   [PATCH] introduce...
103
  		while (!list_empty(p)) {
b5e618181   Pavel Emelianov   Introduce a handy...
104
                          slave_mnt = list_first_entry(p,
6776db3d3   Al Viro   vfs: take mnt_sha...
105
106
  					struct mount, mnt_slave);
  			list_del_init(&slave_mnt->mnt_slave);
a58b0eb8e   Ram Pai   [PATCH] introduce...
107
108
109
  			slave_mnt->mnt_master = NULL;
  		}
  	}
32301920f   Al Viro   vfs: and now we c...
110
  	mnt->mnt_master = master;
fc7be130c   Al Viro   vfs: switch pnode...
111
  	CLEAR_MNT_SHARED(mnt);
a58b0eb8e   Ram Pai   [PATCH] introduce...
112
113
  	return 0;
  }
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
114
115
116
  /*
   * vfsmount lock must be held for write
   */
0f0afb1dc   Al Viro   vfs: spread struc...
117
  void change_mnt_propagation(struct mount *mnt, int type)
07b20889e   Ram Pai   [PATCH] beginning...
118
  {
03e06e68f   Ram Pai   [PATCH] introduce...
119
  	if (type == MS_SHARED) {
b90fa9ae8   Ram Pai   [PATCH] shared mo...
120
  		set_mnt_shared(mnt);
a58b0eb8e   Ram Pai   [PATCH] introduce...
121
122
  		return;
  	}
6fc7871fe   Al Viro   vfs: spread struc...
123
  	do_make_slave(mnt);
a58b0eb8e   Ram Pai   [PATCH] introduce...
124
  	if (type != MS_SLAVE) {
6776db3d3   Al Viro   vfs: take mnt_sha...
125
  		list_del_init(&mnt->mnt_slave);
d10e8def0   Al Viro   vfs: take mnt_mas...
126
  		mnt->mnt_master = NULL;
9676f0c63   Ram Pai   [PATCH] unbindabl...
127
  		if (type == MS_UNBINDABLE)
0f0afb1dc   Al Viro   vfs: spread struc...
128
  			mnt->mnt.mnt_flags |= MNT_UNBINDABLE;
0b03cfb25   Andries E. Brouwer   MNT_UNBINDABLE fix
129
  		else
0f0afb1dc   Al Viro   vfs: spread struc...
130
  			mnt->mnt.mnt_flags &= ~MNT_UNBINDABLE;
03e06e68f   Ram Pai   [PATCH] introduce...
131
  	}
07b20889e   Ram Pai   [PATCH] beginning...
132
  }
b90fa9ae8   Ram Pai   [PATCH] shared mo...
133
134
135
136
137
  
  /*
   * 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...
138
139
140
141
142
   *
   * 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...
143
   */
c937135d9   Al Viro   vfs: spread struc...
144
145
  static struct mount *propagation_next(struct mount *m,
  					 struct mount *origin)
b90fa9ae8   Ram Pai   [PATCH] shared mo...
146
  {
5afe00221   Ram Pai   [PATCH] handling ...
147
  	/* are there any slaves of this mount? */
143c8c91c   Al Viro   vfs: mnt_ns moved...
148
  	if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list))
5afe00221   Ram Pai   [PATCH] handling ...
149
150
151
  		return first_slave(m);
  
  	while (1) {
32301920f   Al Viro   vfs: and now we c...
152
  		struct mount *master = m->mnt_master;
5afe00221   Ram Pai   [PATCH] handling ...
153

32301920f   Al Viro   vfs: and now we c...
154
  		if (master == origin->mnt_master) {
c937135d9   Al Viro   vfs: spread struc...
155
156
  			struct mount *next = next_peer(m);
  			return (next == origin) ? NULL : next;
6776db3d3   Al Viro   vfs: take mnt_sha...
157
  		} else if (m->mnt_slave.next != &master->mnt_slave_list)
5afe00221   Ram Pai   [PATCH] handling ...
158
159
160
161
162
163
  			return next_slave(m);
  
  		/* back at master */
  		m = master;
  	}
  }
54fcb2303   Eric W. Biederman   mnt: Make propaga...
164
165
166
167
168
169
170
171
172
173
174
175
  static struct mount *skip_propagation_subtree(struct mount *m,
  						struct mount *origin)
  {
  	/*
  	 * Advance m such that propagation_next will not return
  	 * the slaves of m.
  	 */
  	if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list))
  		m = last_slave(m);
  
  	return m;
  }
f2ebb3a92   Al Viro   smarter propagate...
176
  static struct mount *next_group(struct mount *m, struct mount *origin)
5afe00221   Ram Pai   [PATCH] handling ...
177
  {
f2ebb3a92   Al Viro   smarter propagate...
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
  	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 ...
205
  	}
f2ebb3a92   Al Viro   smarter propagate...
206
  }
5afe00221   Ram Pai   [PATCH] handling ...
207

f2ebb3a92   Al Viro   smarter propagate...
208
209
  /* all accesses are serialized by namespace_sem */
  static struct user_namespace *user_ns;
5ec0811d3   Eric W. Biederman   propogate_mnt: Ha...
210
  static struct mount *last_dest, *first_source, *last_source, *dest_master;
f2ebb3a92   Al Viro   smarter propagate...
211
212
  static struct mountpoint *mp;
  static struct hlist_head *list;
7ae8fd035   Maxim Patlasov   fs/pnode.c: treat...
213
214
215
216
  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...
217
218
219
220
221
222
223
224
225
226
  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...
227
  	if (peers(m, last_dest)) {
f2ebb3a92   Al Viro   smarter propagate...
228
229
230
  		type = CL_MAKE_SHARED;
  	} else {
  		struct mount *n, *p;
5ec0811d3   Eric W. Biederman   propogate_mnt: Ha...
231
  		bool done;
f2ebb3a92   Al Viro   smarter propagate...
232
233
  		for (n = m; ; n = p) {
  			p = n->mnt_master;
5ec0811d3   Eric W. Biederman   propogate_mnt: Ha...
234
  			if (p == dest_master || IS_MNT_MARKED(p))
f2ebb3a92   Al Viro   smarter propagate...
235
  				break;
796a6b521   Al Viro   Kill CL_PROPAGATI...
236
  		}
5ec0811d3   Eric W. Biederman   propogate_mnt: Ha...
237
238
239
240
241
242
243
244
245
  		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...
246
247
248
249
  		type = CL_SLAVE;
  		/* beginning of peer group among the slaves? */
  		if (IS_MNT_SHARED(m))
  			type |= CL_MAKE_SHARED;
5afe00221   Ram Pai   [PATCH] handling ...
250
  	}
f2ebb3a92   Al Viro   smarter propagate...
251
252
253
254
255
256
257
  		
  	/* 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...
258
  	child->mnt.mnt_flags &= ~MNT_LOCKED;
f2ebb3a92   Al Viro   smarter propagate...
259
260
261
262
263
264
265
266
267
  	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...
268
  	return count_mounts(m->mnt_ns, child);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
  }
  
  /*
   * 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...
284
  int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp,
38129a13e   Al Viro   switch mnt_hash t...
285
  		    struct mount *source_mnt, struct hlist_head *tree_list)
b90fa9ae8   Ram Pai   [PATCH] shared mo...
286
  {
f2ebb3a92   Al Viro   smarter propagate...
287
  	struct mount *m, *n;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
288
  	int ret = 0;
132c94e31   Eric W. Biederman   vfs: Carefully pr...
289

f2ebb3a92   Al Viro   smarter propagate...
290
291
292
293
294
295
296
  	/*
  	 * 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...
297
  	first_source = source_mnt;
f2ebb3a92   Al Viro   smarter propagate...
298
299
300
301
302
303
304
305
306
  	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...
307
  			goto out;
f2ebb3a92   Al Viro   smarter propagate...
308
  	}
b90fa9ae8   Ram Pai   [PATCH] shared mo...
309

f2ebb3a92   Al Viro   smarter propagate...
310
311
312
313
314
315
316
317
318
319
320
  	/* 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...
321
322
  	}
  out:
f2ebb3a92   Al Viro   smarter propagate...
323
324
325
326
327
  	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...
328
  	}
f2ebb3a92   Al Viro   smarter propagate...
329
  	read_sequnlock_excl(&mount_lock);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
330
331
  	return ret;
  }
a05964f39   Ram Pai   [PATCH] shared mo...
332

808e83e5a   Eric W. Biederman   mnt: Tuck mounts ...
333
334
335
336
337
338
339
340
341
342
343
344
345
346
  static struct mount *find_topper(struct mount *mnt)
  {
  	/* If there is exactly one mount covering mnt completely return it. */
  	struct mount *child;
  
  	if (!list_is_singular(&mnt->mnt_mounts))
  		return NULL;
  
  	child = list_first_entry(&mnt->mnt_mounts, struct mount, mnt_child);
  	if (child->mnt_mountpoint != mnt->mnt.mnt_root)
  		return NULL;
  
  	return child;
  }
a05964f39   Ram Pai   [PATCH] shared mo...
347
348
349
  /*
   * return true if the refcount is greater than count
   */
1ab597386   Al Viro   vfs: spread struc...
350
  static inline int do_refcount_check(struct mount *mnt, int count)
a05964f39   Ram Pai   [PATCH] shared mo...
351
  {
aba809cf0   Al Viro   namespace.c: get ...
352
  	return mnt_get_count(mnt) > count;
a05964f39   Ram Pai   [PATCH] shared mo...
353
354
355
356
357
358
359
360
361
  }
  
  /*
   * 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...
362
   *
b3e19d924   Nick Piggin   fs: scale mntget/...
363
   * vfsmount lock must be held for write
a05964f39   Ram Pai   [PATCH] shared mo...
364
   */
1ab597386   Al Viro   vfs: spread struc...
365
  int propagate_mount_busy(struct mount *mnt, int refcnt)
a05964f39   Ram Pai   [PATCH] shared mo...
366
  {
808e83e5a   Eric W. Biederman   mnt: Tuck mounts ...
367
  	struct mount *m, *child, *topper;
0714a5338   Al Viro   vfs: now it can b...
368
  	struct mount *parent = mnt->mnt_parent;
a05964f39   Ram Pai   [PATCH] shared mo...
369

0714a5338   Al Viro   vfs: now it can b...
370
  	if (mnt == parent)
a05964f39   Ram Pai   [PATCH] shared mo...
371
372
373
374
375
376
377
  		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...
378
  	if (!list_empty(&mnt->mnt_mounts) || do_refcount_check(mnt, refcnt))
a05964f39   Ram Pai   [PATCH] shared mo...
379
  		return 1;
c937135d9   Al Viro   vfs: spread struc...
380
381
  	for (m = propagation_next(parent, parent); m;
  	     		m = propagation_next(m, parent)) {
808e83e5a   Eric W. Biederman   mnt: Tuck mounts ...
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
  		int count = 1;
  		child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint);
  		if (!child)
  			continue;
  
  		/* Is there exactly one mount on the child that covers
  		 * it completely whose reference should be ignored?
  		 */
  		topper = find_topper(child);
  		if (topper)
  			count += 1;
  		else if (!list_empty(&child->mnt_mounts))
  			continue;
  
  		if (do_refcount_check(child, count))
  			return 1;
a05964f39   Ram Pai   [PATCH] shared mo...
398
  	}
808e83e5a   Eric W. Biederman   mnt: Tuck mounts ...
399
  	return 0;
a05964f39   Ram Pai   [PATCH] shared mo...
400
401
402
  }
  
  /*
5d88457eb   Eric W. Biederman   mnt: On an unmoun...
403
404
405
406
407
408
409
410
411
412
413
414
415
   * 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)) {
808e83e5a   Eric W. Biederman   mnt: Tuck mounts ...
416
  		child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint);
5d88457eb   Eric W. Biederman   mnt: On an unmoun...
417
418
419
420
  		if (child)
  			child->mnt.mnt_flags &= ~MNT_LOCKED;
  	}
  }
bb4fbf094   Eric W. Biederman   mnt: In propgate_...
421
  static void umount_one(struct mount *mnt, struct list_head *to_umount)
0c56fe314   Eric W. Biederman   mnt: Don't propag...
422
  {
bb4fbf094   Eric W. Biederman   mnt: In propgate_...
423
424
425
426
427
  	CLEAR_MNT_MARK(mnt);
  	mnt->mnt.mnt_flags |= MNT_UMOUNT;
  	list_del_init(&mnt->mnt_child);
  	list_del_init(&mnt->mnt_umounting);
  	list_move_tail(&mnt->mnt_list, to_umount);
0c56fe314   Eric W. Biederman   mnt: Don't propag...
428
429
430
  }
  
  /*
a05964f39   Ram Pai   [PATCH] shared mo...
431
432
433
   * NOTE: unmounting 'mnt' naturally propagates to all other mounts its
   * parent propagates to.
   */
bb4fbf094   Eric W. Biederman   mnt: In propgate_...
434
435
436
  static bool __propagate_umount(struct mount *mnt,
  			       struct list_head *to_umount,
  			       struct list_head *to_restore)
a05964f39   Ram Pai   [PATCH] shared mo...
437
  {
bb4fbf094   Eric W. Biederman   mnt: In propgate_...
438
439
  	bool progress = false;
  	struct mount *child;
a05964f39   Ram Pai   [PATCH] shared mo...
440

bb4fbf094   Eric W. Biederman   mnt: In propgate_...
441
442
443
444
445
446
  	/*
  	 * The state of the parent won't change if this mount is
  	 * already unmounted or marked as without children.
  	 */
  	if (mnt->mnt.mnt_flags & (MNT_UMOUNT | MNT_MARKED))
  		goto out;
a05964f39   Ram Pai   [PATCH] shared mo...
447

bb4fbf094   Eric W. Biederman   mnt: In propgate_...
448
449
450
451
452
  	/* Verify topper is the only grandchild that has not been
  	 * speculatively unmounted.
  	 */
  	list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) {
  		if (child->mnt_mountpoint == mnt->mnt.mnt_root)
0c56fe314   Eric W. Biederman   mnt: Don't propag...
453
  			continue;
bb4fbf094   Eric W. Biederman   mnt: In propgate_...
454
455
456
457
458
  		if (!list_empty(&child->mnt_umounting) && IS_MNT_MARKED(child))
  			continue;
  		/* Found a mounted child */
  		goto children;
  	}
808e83e5a   Eric W. Biederman   mnt: Tuck mounts ...
459

bb4fbf094   Eric W. Biederman   mnt: In propgate_...
460
461
462
  	/* Mark mounts that can be unmounted if not locked */
  	SET_MNT_MARK(mnt);
  	progress = true;
808e83e5a   Eric W. Biederman   mnt: Tuck mounts ...
463

bb4fbf094   Eric W. Biederman   mnt: In propgate_...
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
  	/* If a mount is without children and not locked umount it. */
  	if (!IS_MNT_LOCKED(mnt)) {
  		umount_one(mnt, to_umount);
  	} else {
  children:
  		list_move_tail(&mnt->mnt_umounting, to_restore);
  	}
  out:
  	return progress;
  }
  
  static void umount_list(struct list_head *to_umount,
  			struct list_head *to_restore)
  {
  	struct mount *mnt, *child, *tmp;
  	list_for_each_entry(mnt, to_umount, mnt_list) {
  		list_for_each_entry_safe(child, tmp, &mnt->mnt_mounts, mnt_child) {
  			/* topper? */
  			if (child->mnt_mountpoint == mnt->mnt.mnt_root)
  				list_move_tail(&child->mnt_umounting, to_restore);
  			else
  				umount_one(child, to_umount);
38129a13e   Al Viro   switch mnt_hash t...
486
  		}
a05964f39   Ram Pai   [PATCH] shared mo...
487
488
  	}
  }
bb4fbf094   Eric W. Biederman   mnt: In propgate_...
489
  static void restore_mounts(struct list_head *to_restore)
e260db757   Eric W. Biederman   mnt: In umount pr...
490
  {
bb4fbf094   Eric W. Biederman   mnt: In propgate_...
491
492
  	/* Restore mounts to a clean working state */
  	while (!list_empty(to_restore)) {
e260db757   Eric W. Biederman   mnt: In umount pr...
493
494
  		struct mount *mnt, *parent;
  		struct mountpoint *mp;
bb4fbf094   Eric W. Biederman   mnt: In propgate_...
495
496
497
  		mnt = list_first_entry(to_restore, struct mount, mnt_umounting);
  		CLEAR_MNT_MARK(mnt);
  		list_del_init(&mnt->mnt_umounting);
e260db757   Eric W. Biederman   mnt: In umount pr...
498

bb4fbf094   Eric W. Biederman   mnt: In propgate_...
499
  		/* Should this mount be reparented? */
e260db757   Eric W. Biederman   mnt: In umount pr...
500
501
502
503
504
505
  		mp = mnt->mnt_mp;
  		parent = mnt->mnt_parent;
  		while (parent->mnt.mnt_flags & MNT_UMOUNT) {
  			mp = parent->mnt_mp;
  			parent = parent->mnt_parent;
  		}
bb4fbf094   Eric W. Biederman   mnt: In propgate_...
506
507
  		if (parent != mnt->mnt_parent)
  			mnt_change_mountpoint(parent, mp, mnt);
e260db757   Eric W. Biederman   mnt: In umount pr...
508
509
  	}
  }
54fcb2303   Eric W. Biederman   mnt: Make propaga...
510
511
512
513
514
515
516
517
  static void cleanup_umount_visitations(struct list_head *visited)
  {
  	while (!list_empty(visited)) {
  		struct mount *mnt =
  			list_first_entry(visited, struct mount, mnt_umounting);
  		list_del_init(&mnt->mnt_umounting);
  	}
  }
a05964f39   Ram Pai   [PATCH] shared mo...
518
519
520
521
  /*
   * 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...
522
523
   *
   * vfsmount lock must be held for write
a05964f39   Ram Pai   [PATCH] shared mo...
524
   */
c003b26ff   Eric W. Biederman   mnt: In umount_tr...
525
  int propagate_umount(struct list_head *list)
a05964f39   Ram Pai   [PATCH] shared mo...
526
  {
61ef47b1e   Al Viro   vfs: spread struc...
527
  	struct mount *mnt;
bb4fbf094   Eric W. Biederman   mnt: In propgate_...
528
529
  	LIST_HEAD(to_restore);
  	LIST_HEAD(to_umount);
54fcb2303   Eric W. Biederman   mnt: Make propaga...
530
  	LIST_HEAD(visited);
bb4fbf094   Eric W. Biederman   mnt: In propgate_...
531

54fcb2303   Eric W. Biederman   mnt: Make propaga...
532
533
  	/* Find candidates for unmounting */
  	list_for_each_entry_reverse(mnt, list, mnt_list) {
bb4fbf094   Eric W. Biederman   mnt: In propgate_...
534
535
  		struct mount *parent = mnt->mnt_parent;
  		struct mount *m;
54fcb2303   Eric W. Biederman   mnt: Make propaga...
536
537
538
539
540
541
542
543
544
545
  		/*
  		 * If this mount has already been visited it is known that it's
  		 * entire peer group and all of their slaves in the propagation
  		 * tree for the mountpoint has already been visited and there is
  		 * no need to visit them again.
  		 */
  		if (!list_empty(&mnt->mnt_umounting))
  			continue;
  
  		list_add_tail(&mnt->mnt_umounting, &visited);
bb4fbf094   Eric W. Biederman   mnt: In propgate_...
546
547
548
549
550
551
  		for (m = propagation_next(parent, parent); m;
  		     m = propagation_next(m, parent)) {
  			struct mount *child = __lookup_mnt(&m->mnt,
  							   mnt->mnt_mountpoint);
  			if (!child)
  				continue;
54fcb2303   Eric W. Biederman   mnt: Make propaga...
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
  			if (!list_empty(&child->mnt_umounting)) {
  				/*
  				 * If the child has already been visited it is
  				 * know that it's entire peer group and all of
  				 * their slaves in the propgation tree for the
  				 * mountpoint has already been visited and there
  				 * is no need to visit this subtree again.
  				 */
  				m = skip_propagation_subtree(m, parent);
  				continue;
  			} else if (child->mnt.mnt_flags & MNT_UMOUNT) {
  				/*
  				 * We have come accross an partially unmounted
  				 * mount in list that has not been visited yet.
  				 * Remember it has been visited and continue
  				 * about our merry way.
  				 */
  				list_add_tail(&child->mnt_umounting, &visited);
  				continue;
  			}
bb4fbf094   Eric W. Biederman   mnt: In propgate_...
572
573
574
575
576
577
578
579
580
581
  			/* Check the child and parents while progress is made */
  			while (__propagate_umount(child,
  						  &to_umount, &to_restore)) {
  				/* Is the parent a umount candidate? */
  				child = child->mnt_parent;
  				if (list_empty(&child->mnt_umounting))
  					break;
  			}
  		}
  	}
e260db757   Eric W. Biederman   mnt: In umount pr...
582

bb4fbf094   Eric W. Biederman   mnt: In propgate_...
583
584
  	umount_list(&to_umount, &to_restore);
  	restore_mounts(&to_restore);
54fcb2303   Eric W. Biederman   mnt: Make propaga...
585
  	cleanup_umount_visitations(&visited);
bb4fbf094   Eric W. Biederman   mnt: In propgate_...
586
  	list_splice_tail(&to_umount, list);
e260db757   Eric W. Biederman   mnt: In umount pr...
587

a05964f39   Ram Pai   [PATCH] shared mo...
588
589
  	return 0;
  }