Blame view

fs/pnode.c 8.83 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>
6d59e7f58   Al Viro   [PATCH] move a bu...
12
  #include "internal.h"
07b20889e   Ram Pai   [PATCH] beginning...
13
  #include "pnode.h"
03e06e68f   Ram Pai   [PATCH] introduce...
14
  /* return the next shared peer mount of @p */
c937135d9   Al Viro   vfs: spread struc...
15
  static inline struct mount *next_peer(struct mount *p)
03e06e68f   Ram Pai   [PATCH] introduce...
16
  {
6776db3d3   Al Viro   vfs: take mnt_sha...
17
  	return list_entry(p->mnt_share.next, struct mount, mnt_share);
03e06e68f   Ram Pai   [PATCH] introduce...
18
  }
c937135d9   Al Viro   vfs: spread struc...
19
  static inline struct mount *first_slave(struct mount *p)
5afe00221   Ram Pai   [PATCH] handling ...
20
  {
6776db3d3   Al Viro   vfs: take mnt_sha...
21
  	return list_entry(p->mnt_slave_list.next, struct mount, mnt_slave);
5afe00221   Ram Pai   [PATCH] handling ...
22
  }
c937135d9   Al Viro   vfs: spread struc...
23
  static inline struct mount *next_slave(struct mount *p)
5afe00221   Ram Pai   [PATCH] handling ...
24
  {
6776db3d3   Al Viro   vfs: take mnt_sha...
25
  	return list_entry(p->mnt_slave.next, struct mount, mnt_slave);
5afe00221   Ram Pai   [PATCH] handling ...
26
  }
6fc7871fe   Al Viro   vfs: spread struc...
27
28
29
  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: ...
30
  {
6fc7871fe   Al Viro   vfs: spread struc...
31
  	struct mount *m = mnt;
97e7e0f71   Miklos Szeredi   [patch 7/7] vfs: ...
32
33
34
  
  	do {
  		/* Check the namespace first for optimization */
143c8c91c   Al Viro   vfs: mnt_ns moved...
35
  		if (m->mnt_ns == ns && is_path_reachable(m, m->mnt.mnt_root, root))
6fc7871fe   Al Viro   vfs: spread struc...
36
  			return m;
97e7e0f71   Miklos Szeredi   [patch 7/7] vfs: ...
37

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

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

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

32301920f   Al Viro   vfs: and now we c...
148
  		if (master == origin->mnt_master) {
c937135d9   Al Viro   vfs: spread struc...
149
150
  			struct mount *next = next_peer(m);
  			return (next == origin) ? NULL : next;
6776db3d3   Al Viro   vfs: take mnt_sha...
151
  		} else if (m->mnt_slave.next != &master->mnt_slave_list)
5afe00221   Ram Pai   [PATCH] handling ...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  			return next_slave(m);
  
  		/* back at master */
  		m = master;
  	}
  }
  
  /*
   * return the source mount to be used for cloning
   *
   * @dest 	the current destination mount
   * @last_dest  	the last seen destination mount
   * @last_src  	the last seen source mount
   * @type	return CL_SLAVE if the new mount has to be
   * 		cloned as a slave.
   */
c937135d9   Al Viro   vfs: spread struc...
168
169
170
171
  static struct mount *get_source(struct mount *dest,
  				struct mount *last_dest,
  				struct mount *last_src,
  				int *type)
5afe00221   Ram Pai   [PATCH] handling ...
172
  {
c937135d9   Al Viro   vfs: spread struc...
173
174
  	struct mount *p_last_src = NULL;
  	struct mount *p_last_dest = NULL;
5afe00221   Ram Pai   [PATCH] handling ...
175

32301920f   Al Viro   vfs: and now we c...
176
  	while (last_dest != dest->mnt_master) {
5afe00221   Ram Pai   [PATCH] handling ...
177
178
  		p_last_dest = last_dest;
  		p_last_src = last_src;
32301920f   Al Viro   vfs: and now we c...
179
180
  		last_dest = last_dest->mnt_master;
  		last_src = last_src->mnt_master;
5afe00221   Ram Pai   [PATCH] handling ...
181
182
183
184
185
  	}
  
  	if (p_last_dest) {
  		do {
  			p_last_dest = next_peer(p_last_dest);
143c8c91c   Al Viro   vfs: mnt_ns moved...
186
  		} while (IS_MNT_NEW(p_last_dest));
796a6b521   Al Viro   Kill CL_PROPAGATI...
187
188
189
190
191
  		/* is that a peer of the earlier? */
  		if (dest == p_last_dest) {
  			*type = CL_MAKE_SHARED;
  			return p_last_src;
  		}
5afe00221   Ram Pai   [PATCH] handling ...
192
  	}
796a6b521   Al Viro   Kill CL_PROPAGATI...
193
194
195
  	/* slave of the earlier, then */
  	*type = CL_SLAVE;
  	/* beginning of peer group among the slaves? */
fc7be130c   Al Viro   vfs: switch pnode...
196
  	if (IS_MNT_SHARED(dest))
796a6b521   Al Viro   Kill CL_PROPAGATI...
197
198
  		*type |= CL_MAKE_SHARED;
  	return last_src;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
  }
  
  /*
   * 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.
   */
a8d56d8e4   Al Viro   vfs: spread struc...
214
215
  int propagate_mnt(struct mount *dest_mnt, struct dentry *dest_dentry,
  		    struct mount *source_mnt, struct list_head *tree_list)
b90fa9ae8   Ram Pai   [PATCH] shared mo...
216
  {
c937135d9   Al Viro   vfs: spread struc...
217
  	struct mount *m, *child;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
218
  	int ret = 0;
a8d56d8e4   Al Viro   vfs: spread struc...
219
220
  	struct mount *prev_dest_mnt = dest_mnt;
  	struct mount *prev_src_mnt  = source_mnt;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
221
222
  	LIST_HEAD(tmp_list);
  	LIST_HEAD(umount_list);
a8d56d8e4   Al Viro   vfs: spread struc...
223
224
  	for (m = propagation_next(dest_mnt, dest_mnt); m;
  			m = propagation_next(m, dest_mnt)) {
5afe00221   Ram Pai   [PATCH] handling ...
225
  		int type;
c937135d9   Al Viro   vfs: spread struc...
226
  		struct mount *source;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
227

143c8c91c   Al Viro   vfs: mnt_ns moved...
228
  		if (IS_MNT_NEW(m))
b90fa9ae8   Ram Pai   [PATCH] shared mo...
229
  			continue;
5afe00221   Ram Pai   [PATCH] handling ...
230
  		source =  get_source(m, prev_dest_mnt, prev_src_mnt, &type);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
231

c937135d9   Al Viro   vfs: spread struc...
232
  		if (!(child = copy_tree(source, source->mnt.mnt_root, type))) {
b90fa9ae8   Ram Pai   [PATCH] shared mo...
233
234
235
236
  			ret = -ENOMEM;
  			list_splice(tree_list, tmp_list.prev);
  			goto out;
  		}
c937135d9   Al Viro   vfs: spread struc...
237
  		if (is_subdir(dest_dentry, m->mnt.mnt_root)) {
14cf1fa8f   Al Viro   vfs: spread struc...
238
  			mnt_set_mountpoint(m, dest_dentry, child);
1b8e5564b   Al Viro   vfs: the first sp...
239
  			list_add_tail(&child->mnt_hash, tree_list);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
240
241
242
243
244
  		} else {
  			/*
  			 * This can happen if the parent mount was bind mounted
  			 * on some subdirectory of a shared/slave mount.
  			 */
1b8e5564b   Al Viro   vfs: the first sp...
245
  			list_add_tail(&child->mnt_hash, &tmp_list);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
246
247
  		}
  		prev_dest_mnt = m;
c937135d9   Al Viro   vfs: spread struc...
248
  		prev_src_mnt  = child;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
249
250
  	}
  out:
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
251
  	br_write_lock(vfsmount_lock);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
252
  	while (!list_empty(&tmp_list)) {
1b8e5564b   Al Viro   vfs: the first sp...
253
  		child = list_first_entry(&tmp_list, struct mount, mnt_hash);
761d5c38e   Al Viro   vfs: spread struc...
254
  		umount_tree(child, 0, &umount_list);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
255
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
256
  	br_write_unlock(vfsmount_lock);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
257
258
259
  	release_mounts(&umount_list);
  	return ret;
  }
a05964f39   Ram Pai   [PATCH] shared mo...
260
261
262
263
  
  /*
   * return true if the refcount is greater than count
   */
1ab597386   Al Viro   vfs: spread struc...
264
  static inline int do_refcount_check(struct mount *mnt, int count)
a05964f39   Ram Pai   [PATCH] shared mo...
265
  {
863d684f9   Al Viro   vfs: move the res...
266
  	int mycount = mnt_get_count(mnt) - mnt->mnt_ghosts;
a05964f39   Ram Pai   [PATCH] shared mo...
267
268
269
270
271
272
273
274
275
276
  	return (mycount > count);
  }
  
  /*
   * 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...
277
   *
b3e19d924   Nick Piggin   fs: scale mntget/...
278
   * vfsmount lock must be held for write
a05964f39   Ram Pai   [PATCH] shared mo...
279
   */
1ab597386   Al Viro   vfs: spread struc...
280
  int propagate_mount_busy(struct mount *mnt, int refcnt)
a05964f39   Ram Pai   [PATCH] shared mo...
281
  {
c937135d9   Al Viro   vfs: spread struc...
282
  	struct mount *m, *child;
0714a5338   Al Viro   vfs: now it can b...
283
  	struct mount *parent = mnt->mnt_parent;
a05964f39   Ram Pai   [PATCH] shared mo...
284
  	int ret = 0;
0714a5338   Al Viro   vfs: now it can b...
285
  	if (mnt == parent)
a05964f39   Ram Pai   [PATCH] shared mo...
286
287
288
289
290
291
292
  		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...
293
  	if (!list_empty(&mnt->mnt_mounts) || do_refcount_check(mnt, refcnt))
a05964f39   Ram Pai   [PATCH] shared mo...
294
  		return 1;
c937135d9   Al Viro   vfs: spread struc...
295
296
297
  	for (m = propagation_next(parent, parent); m;
  	     		m = propagation_next(m, parent)) {
  		child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint, 0);
6b41d536f   Al Viro   vfs: take mnt_chi...
298
  		if (child && list_empty(&child->mnt_mounts) &&
1ab597386   Al Viro   vfs: spread struc...
299
  		    (ret = do_refcount_check(child, 1)))
a05964f39   Ram Pai   [PATCH] shared mo...
300
301
302
303
304
305
306
307
308
  			break;
  	}
  	return ret;
  }
  
  /*
   * NOTE: unmounting 'mnt' naturally propagates to all other mounts its
   * parent propagates to.
   */
61ef47b1e   Al Viro   vfs: spread struc...
309
  static void __propagate_umount(struct mount *mnt)
a05964f39   Ram Pai   [PATCH] shared mo...
310
  {
0714a5338   Al Viro   vfs: now it can b...
311
  	struct mount *parent = mnt->mnt_parent;
c937135d9   Al Viro   vfs: spread struc...
312
  	struct mount *m;
a05964f39   Ram Pai   [PATCH] shared mo...
313

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

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

c937135d9   Al Viro   vfs: spread struc...
319
  		struct mount *child = __lookup_mnt(&m->mnt,
a73324da7   Al Viro   vfs: move mnt_mou...
320
  					mnt->mnt_mountpoint, 0);
a05964f39   Ram Pai   [PATCH] shared mo...
321
322
323
324
  		/*
  		 * umount the child only if the child has no
  		 * other children
  		 */
6b41d536f   Al Viro   vfs: take mnt_chi...
325
  		if (child && list_empty(&child->mnt_mounts))
1b8e5564b   Al Viro   vfs: the first sp...
326
  			list_move_tail(&child->mnt_hash, &mnt->mnt_hash);
a05964f39   Ram Pai   [PATCH] shared mo...
327
328
329
330
331
332
333
  	}
  }
  
  /*
   * 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...
334
335
   *
   * vfsmount lock must be held for write
a05964f39   Ram Pai   [PATCH] shared mo...
336
337
338
   */
  int propagate_umount(struct list_head *list)
  {
61ef47b1e   Al Viro   vfs: spread struc...
339
  	struct mount *mnt;
a05964f39   Ram Pai   [PATCH] shared mo...
340

1b8e5564b   Al Viro   vfs: the first sp...
341
  	list_for_each_entry(mnt, list, mnt_hash)
a05964f39   Ram Pai   [PATCH] shared mo...
342
343
344
  		__propagate_umount(mnt);
  	return 0;
  }