Blame view

fs/namespace.c 65.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
  /*
   *  linux/fs/namespace.c
   *
   * (C) Copyright Al Viro 2000, 2001
   *	Released under GPL v2.
   *
   * Based on code from fs/super.c, copyright Linus Torvalds and others.
   * Heavily rewritten.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
  #include <linux/syscalls.h>
  #include <linux/slab.h>
  #include <linux/sched.h>
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
13
14
  #include <linux/spinlock.h>
  #include <linux/percpu.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
  #include <linux/init.h>
15a67dd8c   Randy Dunlap   [PATCH] fs/namesp...
16
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
  #include <linux/acct.h>
16f7e0fe2   Randy Dunlap   [PATCH] capable/c...
18
  #include <linux/capability.h>
3d733633a   Dave Hansen   [PATCH] r/o bind ...
19
  #include <linux/cpumask.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
  #include <linux/module.h>
f20a9ead0   Andrew Morton   sysfs: add proper...
21
  #include <linux/sysfs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  #include <linux/seq_file.h>
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
23
  #include <linux/mnt_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
  #include <linux/namei.h>
b43f3cbd2   Alexey Dobriyan   headers: mnt_name...
25
  #include <linux/nsproxy.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
  #include <linux/security.h>
  #include <linux/mount.h>
07f3f05c1   David Howells   [PATCH] BLOCK: Mo...
28
  #include <linux/ramfs.h>
13f14b4d8   Eric Dumazet   Use ilog2() in fs...
29
  #include <linux/log2.h>
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
30
  #include <linux/idr.h>
5ad4e53bd   Al Viro   Get rid of indire...
31
  #include <linux/fs_struct.h>
2504c5d63   Andreas Gruenbacher   fsnotify/vfsmount...
32
  #include <linux/fsnotify.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
  #include <asm/uaccess.h>
  #include <asm/unistd.h>
07b20889e   Ram Pai   [PATCH] beginning...
35
  #include "pnode.h"
948730b0e   Adrian Bunk   fs/namespace.c sh...
36
  #include "internal.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37

13f14b4d8   Eric Dumazet   Use ilog2() in fs...
38
39
  #define HASH_SHIFT ilog2(PAGE_SIZE / sizeof(struct list_head))
  #define HASH_SIZE (1UL << HASH_SHIFT)
5addc5dd8   Al Viro   [PATCH] make /pro...
40
  static int event;
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
41
  static DEFINE_IDA(mnt_id_ida);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
42
  static DEFINE_IDA(mnt_group_ida);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
43
  static DEFINE_SPINLOCK(mnt_id_lock);
f21f62208   Al Viro   ... and the same ...
44
45
  static int mnt_id_start = 0;
  static int mnt_group_start = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46

fa3536cc1   Eric Dumazet   [PATCH] Use __rea...
47
  static struct list_head *mount_hashtable __read_mostly;
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
48
  static struct kmem_cache *mnt_cache __read_mostly;
390c68436   Ram Pai   [PATCH] making na...
49
  static struct rw_semaphore namespace_sem;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50

f87fd4c2a   Miklos Szeredi   [PATCH] add /sys/fs
51
  /* /sys/fs */
00d266662   Greg Kroah-Hartman   kobject: convert ...
52
53
  struct kobject *fs_kobj;
  EXPORT_SYMBOL_GPL(fs_kobj);
f87fd4c2a   Miklos Szeredi   [PATCH] add /sys/fs
54

99b7db7b8   Nick Piggin   fs: brlock vfsmou...
55
56
57
58
59
60
61
62
63
  /*
   * vfsmount lock may be taken for read to prevent changes to the
   * vfsmount hash, ie. during mountpoint lookups or walking back
   * up the tree.
   *
   * It should be taken for write in all cases where the vfsmount
   * tree or hash is modified or when a vfsmount structure is modified.
   */
  DEFINE_BRLOCK(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
  static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
  {
b58fed8b1   Ram Pai   [PATCH] lindent f...
66
67
  	unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES);
  	tmp += ((unsigned long)dentry / L1_CACHE_BYTES);
13f14b4d8   Eric Dumazet   Use ilog2() in fs...
68
69
  	tmp = tmp + (tmp >> HASH_SHIFT);
  	return tmp & (HASH_SIZE - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
  }
3d733633a   Dave Hansen   [PATCH] r/o bind ...
71
  #define MNT_WRITER_UNDERFLOW_LIMIT -(1<<16)
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
72
73
74
75
  /*
   * allocation is serialized by namespace_sem, but we need the spinlock to
   * serialize with freeing.
   */
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
76
77
78
79
80
81
  static int mnt_alloc_id(struct vfsmount *mnt)
  {
  	int res;
  
  retry:
  	ida_pre_get(&mnt_id_ida, GFP_KERNEL);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
82
  	spin_lock(&mnt_id_lock);
f21f62208   Al Viro   ... and the same ...
83
84
85
  	res = ida_get_new_above(&mnt_id_ida, mnt_id_start, &mnt->mnt_id);
  	if (!res)
  		mnt_id_start = mnt->mnt_id + 1;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
86
  	spin_unlock(&mnt_id_lock);
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
87
88
89
90
91
92
93
94
  	if (res == -EAGAIN)
  		goto retry;
  
  	return res;
  }
  
  static void mnt_free_id(struct vfsmount *mnt)
  {
f21f62208   Al Viro   ... and the same ...
95
  	int id = mnt->mnt_id;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
96
  	spin_lock(&mnt_id_lock);
f21f62208   Al Viro   ... and the same ...
97
98
99
  	ida_remove(&mnt_id_ida, id);
  	if (mnt_id_start > id)
  		mnt_id_start = id;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
100
  	spin_unlock(&mnt_id_lock);
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
101
  }
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
102
103
104
105
106
107
108
  /*
   * Allocate a new peer group ID
   *
   * mnt_group_ida is protected by namespace_sem
   */
  static int mnt_alloc_group_id(struct vfsmount *mnt)
  {
f21f62208   Al Viro   ... and the same ...
109
  	int res;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
110
111
  	if (!ida_pre_get(&mnt_group_ida, GFP_KERNEL))
  		return -ENOMEM;
f21f62208   Al Viro   ... and the same ...
112
113
114
115
116
117
118
  	res = ida_get_new_above(&mnt_group_ida,
  				mnt_group_start,
  				&mnt->mnt_group_id);
  	if (!res)
  		mnt_group_start = mnt->mnt_group_id + 1;
  
  	return res;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
119
120
121
122
123
124
125
  }
  
  /*
   * Release a peer group ID
   */
  void mnt_release_group_id(struct vfsmount *mnt)
  {
f21f62208   Al Viro   ... and the same ...
126
127
128
129
  	int id = mnt->mnt_group_id;
  	ida_remove(&mnt_group_ida, id);
  	if (mnt_group_start > id)
  		mnt_group_start = id;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
130
131
  	mnt->mnt_group_id = 0;
  }
b3e19d924   Nick Piggin   fs: scale mntget/...
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
  /*
   * vfsmount lock must be held for read
   */
  static inline void mnt_add_count(struct vfsmount *mnt, int n)
  {
  #ifdef CONFIG_SMP
  	this_cpu_add(mnt->mnt_pcp->mnt_count, n);
  #else
  	preempt_disable();
  	mnt->mnt_count += n;
  	preempt_enable();
  #endif
  }
  
  static inline void mnt_set_count(struct vfsmount *mnt, int n)
  {
  #ifdef CONFIG_SMP
  	this_cpu_write(mnt->mnt_pcp->mnt_count, n);
  #else
  	mnt->mnt_count = n;
  #endif
  }
  
  /*
   * vfsmount lock must be held for read
   */
  static inline void mnt_inc_count(struct vfsmount *mnt)
  {
  	mnt_add_count(mnt, 1);
  }
  
  /*
   * vfsmount lock must be held for read
   */
  static inline void mnt_dec_count(struct vfsmount *mnt)
  {
  	mnt_add_count(mnt, -1);
  }
  
  /*
   * vfsmount lock must be held for write
   */
  unsigned int mnt_get_count(struct vfsmount *mnt)
  {
  #ifdef CONFIG_SMP
f03c65993   Al Viro   sanitize vfsmount...
177
  	unsigned int count = 0;
b3e19d924   Nick Piggin   fs: scale mntget/...
178
179
180
181
182
183
184
185
186
187
188
  	int cpu;
  
  	for_each_possible_cpu(cpu) {
  		count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_count;
  	}
  
  	return count;
  #else
  	return mnt->mnt_count;
  #endif
  }
9d412a43c   Al Viro   vfs: split off vf...
189
  static struct vfsmount *alloc_vfsmnt(const char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
  {
c37622296   Robert P. J. Day   [PATCH] Transform...
191
  	struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
  	if (mnt) {
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
193
194
195
  		int err;
  
  		err = mnt_alloc_id(mnt);
88b387824   Li Zefan   [PATCH] vfs: use ...
196
197
198
199
200
201
202
  		if (err)
  			goto out_free_cache;
  
  		if (name) {
  			mnt->mnt_devname = kstrdup(name, GFP_KERNEL);
  			if (!mnt->mnt_devname)
  				goto out_free_id;
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
203
  		}
b3e19d924   Nick Piggin   fs: scale mntget/...
204
205
206
207
  #ifdef CONFIG_SMP
  		mnt->mnt_pcp = alloc_percpu(struct mnt_pcp);
  		if (!mnt->mnt_pcp)
  			goto out_free_devname;
f03c65993   Al Viro   sanitize vfsmount...
208
  		this_cpu_add(mnt->mnt_pcp->mnt_count, 1);
b3e19d924   Nick Piggin   fs: scale mntget/...
209
210
211
212
  #else
  		mnt->mnt_count = 1;
  		mnt->mnt_writers = 0;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
215
216
  		INIT_LIST_HEAD(&mnt->mnt_hash);
  		INIT_LIST_HEAD(&mnt->mnt_child);
  		INIT_LIST_HEAD(&mnt->mnt_mounts);
  		INIT_LIST_HEAD(&mnt->mnt_list);
55e700b92   Miklos Szeredi   [PATCH] namespace...
217
  		INIT_LIST_HEAD(&mnt->mnt_expire);
03e06e68f   Ram Pai   [PATCH] introduce...
218
  		INIT_LIST_HEAD(&mnt->mnt_share);
a58b0eb8e   Ram Pai   [PATCH] introduce...
219
220
  		INIT_LIST_HEAD(&mnt->mnt_slave_list);
  		INIT_LIST_HEAD(&mnt->mnt_slave);
2504c5d63   Andreas Gruenbacher   fsnotify/vfsmount...
221
222
223
  #ifdef CONFIG_FSNOTIFY
  		INIT_HLIST_HEAD(&mnt->mnt_fsnotify_marks);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
225
  	}
  	return mnt;
88b387824   Li Zefan   [PATCH] vfs: use ...
226

d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
227
228
229
230
  #ifdef CONFIG_SMP
  out_free_devname:
  	kfree(mnt->mnt_devname);
  #endif
88b387824   Li Zefan   [PATCH] vfs: use ...
231
232
233
234
235
  out_free_id:
  	mnt_free_id(mnt);
  out_free_cache:
  	kmem_cache_free(mnt_cache, mnt);
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
  }
8366025eb   Dave Hansen   [PATCH] r/o bind ...
237
238
239
240
241
242
243
244
  /*
   * Most r/o checks on a fs are for operations that take
   * discrete amounts of time, like a write() or unlink().
   * We must keep track of when those operations start
   * (for permission checks) and when they end, so that
   * we can determine when writes are able to occur to
   * a filesystem.
   */
3d733633a   Dave Hansen   [PATCH] r/o bind ...
245
246
247
248
249
250
251
252
253
254
255
256
257
  /*
   * __mnt_is_readonly: check whether a mount is read-only
   * @mnt: the mount to check for its write status
   *
   * This shouldn't be used directly ouside of the VFS.
   * It does not guarantee that the filesystem will stay
   * r/w, just that it is right *now*.  This can not and
   * should not be used in place of IS_RDONLY(inode).
   * mnt_want/drop_write() will _keep_ the filesystem
   * r/w.
   */
  int __mnt_is_readonly(struct vfsmount *mnt)
  {
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
258
259
260
261
262
  	if (mnt->mnt_flags & MNT_READONLY)
  		return 1;
  	if (mnt->mnt_sb->s_flags & MS_RDONLY)
  		return 1;
  	return 0;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
263
264
  }
  EXPORT_SYMBOL_GPL(__mnt_is_readonly);
c6653a838   Nick Piggin   fs: rename vfsmou...
265
  static inline void mnt_inc_writers(struct vfsmount *mnt)
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
266
267
  {
  #ifdef CONFIG_SMP
b3e19d924   Nick Piggin   fs: scale mntget/...
268
  	this_cpu_inc(mnt->mnt_pcp->mnt_writers);
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
269
270
271
272
  #else
  	mnt->mnt_writers++;
  #endif
  }
3d733633a   Dave Hansen   [PATCH] r/o bind ...
273

c6653a838   Nick Piggin   fs: rename vfsmou...
274
  static inline void mnt_dec_writers(struct vfsmount *mnt)
3d733633a   Dave Hansen   [PATCH] r/o bind ...
275
  {
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
276
  #ifdef CONFIG_SMP
b3e19d924   Nick Piggin   fs: scale mntget/...
277
  	this_cpu_dec(mnt->mnt_pcp->mnt_writers);
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
278
279
280
  #else
  	mnt->mnt_writers--;
  #endif
3d733633a   Dave Hansen   [PATCH] r/o bind ...
281
  }
3d733633a   Dave Hansen   [PATCH] r/o bind ...
282

c6653a838   Nick Piggin   fs: rename vfsmou...
283
  static unsigned int mnt_get_writers(struct vfsmount *mnt)
3d733633a   Dave Hansen   [PATCH] r/o bind ...
284
  {
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
285
286
  #ifdef CONFIG_SMP
  	unsigned int count = 0;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
287
  	int cpu;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
288
289
  
  	for_each_possible_cpu(cpu) {
b3e19d924   Nick Piggin   fs: scale mntget/...
290
  		count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_writers;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
291
  	}
3d733633a   Dave Hansen   [PATCH] r/o bind ...
292

d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
293
294
295
296
  	return count;
  #else
  	return mnt->mnt_writers;
  #endif
3d733633a   Dave Hansen   [PATCH] r/o bind ...
297
298
299
300
301
302
303
304
305
306
  }
  
  /*
   * Most r/o checks on a fs are for operations that take
   * discrete amounts of time, like a write() or unlink().
   * We must keep track of when those operations start
   * (for permission checks) and when they end, so that
   * we can determine when writes are able to occur to
   * a filesystem.
   */
8366025eb   Dave Hansen   [PATCH] r/o bind ...
307
308
309
310
311
312
313
314
315
316
317
318
  /**
   * mnt_want_write - get write access to a mount
   * @mnt: the mount on which to take a write
   *
   * This tells the low-level filesystem that a write is
   * about to be performed to it, and makes sure that
   * writes are allowed before returning success.  When
   * the write operation is finished, mnt_drop_write()
   * must be called.  This is effectively a refcount.
   */
  int mnt_want_write(struct vfsmount *mnt)
  {
3d733633a   Dave Hansen   [PATCH] r/o bind ...
319
  	int ret = 0;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
320

d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
321
  	preempt_disable();
c6653a838   Nick Piggin   fs: rename vfsmou...
322
  	mnt_inc_writers(mnt);
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
323
  	/*
c6653a838   Nick Piggin   fs: rename vfsmou...
324
  	 * The store to mnt_inc_writers must be visible before we pass
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
325
326
327
328
329
330
331
332
333
334
335
336
  	 * MNT_WRITE_HOLD loop below, so that the slowpath can see our
  	 * incremented count after it has set MNT_WRITE_HOLD.
  	 */
  	smp_mb();
  	while (mnt->mnt_flags & MNT_WRITE_HOLD)
  		cpu_relax();
  	/*
  	 * After the slowpath clears MNT_WRITE_HOLD, mnt_is_readonly will
  	 * be set to match its requirements. So we must not load that until
  	 * MNT_WRITE_HOLD is cleared.
  	 */
  	smp_rmb();
3d733633a   Dave Hansen   [PATCH] r/o bind ...
337
  	if (__mnt_is_readonly(mnt)) {
c6653a838   Nick Piggin   fs: rename vfsmou...
338
  		mnt_dec_writers(mnt);
3d733633a   Dave Hansen   [PATCH] r/o bind ...
339
340
341
  		ret = -EROFS;
  		goto out;
  	}
3d733633a   Dave Hansen   [PATCH] r/o bind ...
342
  out:
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
343
  	preempt_enable();
3d733633a   Dave Hansen   [PATCH] r/o bind ...
344
  	return ret;
8366025eb   Dave Hansen   [PATCH] r/o bind ...
345
346
347
348
  }
  EXPORT_SYMBOL_GPL(mnt_want_write);
  
  /**
96029c4e0   npiggin@suse.de   fs: introduce mnt...
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
   * mnt_clone_write - get write access to a mount
   * @mnt: the mount on which to take a write
   *
   * This is effectively like mnt_want_write, except
   * it must only be used to take an extra write reference
   * on a mountpoint that we already know has a write reference
   * on it. This allows some optimisation.
   *
   * After finished, mnt_drop_write must be called as usual to
   * drop the reference.
   */
  int mnt_clone_write(struct vfsmount *mnt)
  {
  	/* superblock may be r/o */
  	if (__mnt_is_readonly(mnt))
  		return -EROFS;
  	preempt_disable();
c6653a838   Nick Piggin   fs: rename vfsmou...
366
  	mnt_inc_writers(mnt);
96029c4e0   npiggin@suse.de   fs: introduce mnt...
367
368
369
370
371
372
373
374
375
376
377
378
379
380
  	preempt_enable();
  	return 0;
  }
  EXPORT_SYMBOL_GPL(mnt_clone_write);
  
  /**
   * mnt_want_write_file - get write access to a file's mount
   * @file: the file who's mount on which to take a write
   *
   * This is like mnt_want_write, but it takes a file and can
   * do some optimisations if the file is open for write already
   */
  int mnt_want_write_file(struct file *file)
  {
2d8dd38a5   OGAWA Hirofumi   vfs: mnt_want_wri...
381
382
  	struct inode *inode = file->f_dentry->d_inode;
  	if (!(file->f_mode & FMODE_WRITE) || special_file(inode->i_mode))
96029c4e0   npiggin@suse.de   fs: introduce mnt...
383
384
385
386
387
388
389
  		return mnt_want_write(file->f_path.mnt);
  	else
  		return mnt_clone_write(file->f_path.mnt);
  }
  EXPORT_SYMBOL_GPL(mnt_want_write_file);
  
  /**
8366025eb   Dave Hansen   [PATCH] r/o bind ...
390
391
392
393
394
395
396
397
398
   * mnt_drop_write - give up write access to a mount
   * @mnt: the mount on which to give up write access
   *
   * Tells the low-level filesystem that we are done
   * performing writes to it.  Must be matched with
   * mnt_want_write() call above.
   */
  void mnt_drop_write(struct vfsmount *mnt)
  {
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
399
  	preempt_disable();
c6653a838   Nick Piggin   fs: rename vfsmou...
400
  	mnt_dec_writers(mnt);
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
401
  	preempt_enable();
8366025eb   Dave Hansen   [PATCH] r/o bind ...
402
403
  }
  EXPORT_SYMBOL_GPL(mnt_drop_write);
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
404
  static int mnt_make_readonly(struct vfsmount *mnt)
8366025eb   Dave Hansen   [PATCH] r/o bind ...
405
  {
3d733633a   Dave Hansen   [PATCH] r/o bind ...
406
  	int ret = 0;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
407
  	br_write_lock(vfsmount_lock);
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
408
  	mnt->mnt_flags |= MNT_WRITE_HOLD;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
409
  	/*
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
410
411
  	 * After storing MNT_WRITE_HOLD, we'll read the counters. This store
  	 * should be visible before we do.
3d733633a   Dave Hansen   [PATCH] r/o bind ...
412
  	 */
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
413
  	smp_mb();
3d733633a   Dave Hansen   [PATCH] r/o bind ...
414
  	/*
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
415
416
417
418
419
420
421
422
423
424
425
426
427
428
  	 * With writers on hold, if this value is zero, then there are
  	 * definitely no active writers (although held writers may subsequently
  	 * increment the count, they'll have to wait, and decrement it after
  	 * seeing MNT_READONLY).
  	 *
  	 * It is OK to have counter incremented on one CPU and decremented on
  	 * another: the sum will add up correctly. The danger would be when we
  	 * sum up each counter, if we read a counter before it is incremented,
  	 * but then read another CPU's count which it has been subsequently
  	 * decremented from -- we would see more decrements than we should.
  	 * MNT_WRITE_HOLD protects against this scenario, because
  	 * mnt_want_write first increments count, then smp_mb, then spins on
  	 * MNT_WRITE_HOLD, so it can't be decremented by another CPU while
  	 * we're counting up here.
3d733633a   Dave Hansen   [PATCH] r/o bind ...
429
  	 */
c6653a838   Nick Piggin   fs: rename vfsmou...
430
  	if (mnt_get_writers(mnt) > 0)
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
431
432
  		ret = -EBUSY;
  	else
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
433
  		mnt->mnt_flags |= MNT_READONLY;
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
434
435
436
437
438
439
  	/*
  	 * MNT_READONLY must become visible before ~MNT_WRITE_HOLD, so writers
  	 * that become unheld will see MNT_READONLY.
  	 */
  	smp_wmb();
  	mnt->mnt_flags &= ~MNT_WRITE_HOLD;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
440
  	br_write_unlock(vfsmount_lock);
3d733633a   Dave Hansen   [PATCH] r/o bind ...
441
  	return ret;
8366025eb   Dave Hansen   [PATCH] r/o bind ...
442
  }
8366025eb   Dave Hansen   [PATCH] r/o bind ...
443

2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
444
445
  static void __mnt_unmake_readonly(struct vfsmount *mnt)
  {
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
446
  	br_write_lock(vfsmount_lock);
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
447
  	mnt->mnt_flags &= ~MNT_READONLY;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
448
  	br_write_unlock(vfsmount_lock);
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
449
  }
9d412a43c   Al Viro   vfs: split off vf...
450
  static void free_vfsmnt(struct vfsmount *mnt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
452
  {
  	kfree(mnt->mnt_devname);
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
453
  	mnt_free_id(mnt);
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
454
  #ifdef CONFIG_SMP
b3e19d924   Nick Piggin   fs: scale mntget/...
455
  	free_percpu(mnt->mnt_pcp);
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
456
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
458
459
460
  	kmem_cache_free(mnt_cache, mnt);
  }
  
  /*
a05964f39   Ram Pai   [PATCH] shared mo...
461
462
   * find the first or last mount at @dentry on vfsmount @mnt depending on
   * @dir. If @dir is set return the first mount else return the last mount.
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
463
   * vfsmount_lock must be held for read or write.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
   */
a05964f39   Ram Pai   [PATCH] shared mo...
465
466
  struct vfsmount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry,
  			      int dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
  {
b58fed8b1   Ram Pai   [PATCH] lindent f...
468
469
  	struct list_head *head = mount_hashtable + hash(mnt, dentry);
  	struct list_head *tmp = head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
  	struct vfsmount *p, *found = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
  	for (;;) {
a05964f39   Ram Pai   [PATCH] shared mo...
472
  		tmp = dir ? tmp->next : tmp->prev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
474
475
476
477
  		p = NULL;
  		if (tmp == head)
  			break;
  		p = list_entry(tmp, struct vfsmount, mnt_hash);
  		if (p->mnt_parent == mnt && p->mnt_mountpoint == dentry) {
a05964f39   Ram Pai   [PATCH] shared mo...
478
  			found = p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
480
481
  			break;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
  	return found;
  }
a05964f39   Ram Pai   [PATCH] shared mo...
484
485
486
487
  /*
   * lookup_mnt increments the ref count before returning
   * the vfsmount struct.
   */
1c755af4d   Al Viro   switch lookup_mnt()
488
  struct vfsmount *lookup_mnt(struct path *path)
a05964f39   Ram Pai   [PATCH] shared mo...
489
490
  {
  	struct vfsmount *child_mnt;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
491
492
  
  	br_read_lock(vfsmount_lock);
1c755af4d   Al Viro   switch lookup_mnt()
493
  	if ((child_mnt = __lookup_mnt(path->mnt, path->dentry, 1)))
a05964f39   Ram Pai   [PATCH] shared mo...
494
  		mntget(child_mnt);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
495
  	br_read_unlock(vfsmount_lock);
a05964f39   Ram Pai   [PATCH] shared mo...
496
497
  	return child_mnt;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498
499
  static inline int check_mnt(struct vfsmount *mnt)
  {
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
500
  	return mnt->mnt_ns == current->nsproxy->mnt_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
  }
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
502
503
504
  /*
   * vfsmount lock must be held for write
   */
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
505
  static void touch_mnt_namespace(struct mnt_namespace *ns)
5addc5dd8   Al Viro   [PATCH] make /pro...
506
507
508
509
510
511
  {
  	if (ns) {
  		ns->event = ++event;
  		wake_up_interruptible(&ns->poll);
  	}
  }
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
512
513
514
  /*
   * vfsmount lock must be held for write
   */
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
515
  static void __touch_mnt_namespace(struct mnt_namespace *ns)
5addc5dd8   Al Viro   [PATCH] make /pro...
516
517
518
519
520
521
  {
  	if (ns && ns->event != event) {
  		ns->event = event;
  		wake_up_interruptible(&ns->poll);
  	}
  }
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
522
  /*
5f57cbcc0   Nick Piggin   fs: dcache remove...
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
   * Clear dentry's mounted state if it has no remaining mounts.
   * vfsmount_lock must be held for write.
   */
  static void dentry_reset_mounted(struct vfsmount *mnt, struct dentry *dentry)
  {
  	unsigned u;
  
  	for (u = 0; u < HASH_SIZE; u++) {
  		struct vfsmount *p;
  
  		list_for_each_entry(p, &mount_hashtable[u], mnt_hash) {
  			if (p->mnt_mountpoint == dentry)
  				return;
  		}
  	}
  	spin_lock(&dentry->d_lock);
  	dentry->d_flags &= ~DCACHE_MOUNTED;
  	spin_unlock(&dentry->d_lock);
  }
  
  /*
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
544
545
   * vfsmount lock must be held for write
   */
1a3906895   Al Viro   [PATCH] reduce st...
546
  static void detach_mnt(struct vfsmount *mnt, struct path *old_path)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
  {
1a3906895   Al Viro   [PATCH] reduce st...
548
549
  	old_path->dentry = mnt->mnt_mountpoint;
  	old_path->mnt = mnt->mnt_parent;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
551
552
553
  	mnt->mnt_parent = mnt;
  	mnt->mnt_mountpoint = mnt->mnt_root;
  	list_del_init(&mnt->mnt_child);
  	list_del_init(&mnt->mnt_hash);
5f57cbcc0   Nick Piggin   fs: dcache remove...
554
  	dentry_reset_mounted(old_path->mnt, old_path->dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
  }
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
556
557
558
  /*
   * vfsmount lock must be held for write
   */
b90fa9ae8   Ram Pai   [PATCH] shared mo...
559
560
561
562
563
  void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry,
  			struct vfsmount *child_mnt)
  {
  	child_mnt->mnt_parent = mntget(mnt);
  	child_mnt->mnt_mountpoint = dget(dentry);
5f57cbcc0   Nick Piggin   fs: dcache remove...
564
565
566
  	spin_lock(&dentry->d_lock);
  	dentry->d_flags |= DCACHE_MOUNTED;
  	spin_unlock(&dentry->d_lock);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
567
  }
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
568
569
570
  /*
   * vfsmount lock must be held for write
   */
1a3906895   Al Viro   [PATCH] reduce st...
571
  static void attach_mnt(struct vfsmount *mnt, struct path *path)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
  {
1a3906895   Al Viro   [PATCH] reduce st...
573
  	mnt_set_mountpoint(path->mnt, path->dentry, mnt);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
574
  	list_add_tail(&mnt->mnt_hash, mount_hashtable +
1a3906895   Al Viro   [PATCH] reduce st...
575
576
  			hash(path->mnt, path->dentry));
  	list_add_tail(&mnt->mnt_child, &path->mnt->mnt_mounts);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
577
  }
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
578
579
580
581
582
583
584
585
586
587
588
589
590
591
  static inline void __mnt_make_longterm(struct vfsmount *mnt)
  {
  #ifdef CONFIG_SMP
  	atomic_inc(&mnt->mnt_longterm);
  #endif
  }
  
  /* needs vfsmount lock for write */
  static inline void __mnt_make_shortterm(struct vfsmount *mnt)
  {
  #ifdef CONFIG_SMP
  	atomic_dec(&mnt->mnt_longterm);
  #endif
  }
b90fa9ae8   Ram Pai   [PATCH] shared mo...
592
  /*
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
593
   * vfsmount lock must be held for write
b90fa9ae8   Ram Pai   [PATCH] shared mo...
594
595
596
597
598
599
   */
  static void commit_tree(struct vfsmount *mnt)
  {
  	struct vfsmount *parent = mnt->mnt_parent;
  	struct vfsmount *m;
  	LIST_HEAD(head);
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
600
  	struct mnt_namespace *n = parent->mnt_ns;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
601
602
603
604
  
  	BUG_ON(parent == mnt);
  
  	list_add_tail(&head, &mnt->mnt_list);
f03c65993   Al Viro   sanitize vfsmount...
605
  	list_for_each_entry(m, &head, mnt_list) {
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
606
  		m->mnt_ns = n;
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
607
  		__mnt_make_longterm(m);
f03c65993   Al Viro   sanitize vfsmount...
608
  	}
b90fa9ae8   Ram Pai   [PATCH] shared mo...
609
610
611
612
613
  	list_splice(&head, n->list.prev);
  
  	list_add_tail(&mnt->mnt_hash, mount_hashtable +
  				hash(parent, mnt->mnt_mountpoint));
  	list_add_tail(&mnt->mnt_child, &parent->mnt_mounts);
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
614
  	touch_mnt_namespace(n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
  }
  
  static struct vfsmount *next_mnt(struct vfsmount *p, struct vfsmount *root)
  {
  	struct list_head *next = p->mnt_mounts.next;
  	if (next == &p->mnt_mounts) {
  		while (1) {
  			if (p == root)
  				return NULL;
  			next = p->mnt_child.next;
  			if (next != &p->mnt_parent->mnt_mounts)
  				break;
  			p = p->mnt_parent;
  		}
  	}
  	return list_entry(next, struct vfsmount, mnt_child);
  }
9676f0c63   Ram Pai   [PATCH] unbindabl...
632
633
634
635
636
637
638
639
640
  static struct vfsmount *skip_mnt_tree(struct vfsmount *p)
  {
  	struct list_head *prev = p->mnt_mounts.prev;
  	while (prev != &p->mnt_mounts) {
  		p = list_entry(prev, struct vfsmount, mnt_child);
  		prev = p->mnt_mounts.prev;
  	}
  	return p;
  }
9d412a43c   Al Viro   vfs: split off vf...
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
  struct vfsmount *
  vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
  {
  	struct vfsmount *mnt;
  	struct dentry *root;
  
  	if (!type)
  		return ERR_PTR(-ENODEV);
  
  	mnt = alloc_vfsmnt(name);
  	if (!mnt)
  		return ERR_PTR(-ENOMEM);
  
  	if (flags & MS_KERNMOUNT)
  		mnt->mnt_flags = MNT_INTERNAL;
  
  	root = mount_fs(type, flags, name, data);
  	if (IS_ERR(root)) {
  		free_vfsmnt(mnt);
  		return ERR_CAST(root);
  	}
  
  	mnt->mnt_root = root;
  	mnt->mnt_sb = root->d_sb;
  	mnt->mnt_mountpoint = mnt->mnt_root;
  	mnt->mnt_parent = mnt;
  	return mnt;
  }
  EXPORT_SYMBOL_GPL(vfs_kern_mount);
36341f645   Ram Pai   [PATCH] mount exp...
670
671
  static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
  					int flag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672
673
674
675
676
  {
  	struct super_block *sb = old->mnt_sb;
  	struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname);
  
  	if (mnt) {
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
677
678
679
680
681
682
683
684
685
686
  		if (flag & (CL_SLAVE | CL_PRIVATE))
  			mnt->mnt_group_id = 0; /* not a peer of original */
  		else
  			mnt->mnt_group_id = old->mnt_group_id;
  
  		if ((flag & CL_MAKE_SHARED) && !mnt->mnt_group_id) {
  			int err = mnt_alloc_group_id(mnt);
  			if (err)
  				goto out_free;
  		}
be1a16a0a   Miklos Szeredi   vfs: fix infinite...
687
  		mnt->mnt_flags = old->mnt_flags & ~MNT_WRITE_HOLD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688
689
690
691
692
  		atomic_inc(&sb->s_active);
  		mnt->mnt_sb = sb;
  		mnt->mnt_root = dget(root);
  		mnt->mnt_mountpoint = mnt->mnt_root;
  		mnt->mnt_parent = mnt;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
693

5afe00221   Ram Pai   [PATCH] handling ...
694
695
696
697
  		if (flag & CL_SLAVE) {
  			list_add(&mnt->mnt_slave, &old->mnt_slave_list);
  			mnt->mnt_master = old;
  			CLEAR_MNT_SHARED(mnt);
8aec08094   Al Viro   [PATCH] new helpe...
698
  		} else if (!(flag & CL_PRIVATE)) {
796a6b521   Al Viro   Kill CL_PROPAGATI...
699
  			if ((flag & CL_MAKE_SHARED) || IS_MNT_SHARED(old))
5afe00221   Ram Pai   [PATCH] handling ...
700
701
702
703
704
  				list_add(&mnt->mnt_share, &old->mnt_share);
  			if (IS_MNT_SLAVE(old))
  				list_add(&mnt->mnt_slave, &old->mnt_slave);
  			mnt->mnt_master = old->mnt_master;
  		}
b90fa9ae8   Ram Pai   [PATCH] shared mo...
705
706
  		if (flag & CL_MAKE_SHARED)
  			set_mnt_shared(mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
708
709
  
  		/* stick the duplicate mount on the same expiry list
  		 * as the original if that was on one */
36341f645   Ram Pai   [PATCH] mount exp...
710
  		if (flag & CL_EXPIRE) {
36341f645   Ram Pai   [PATCH] mount exp...
711
712
  			if (!list_empty(&old->mnt_expire))
  				list_add(&mnt->mnt_expire, &old->mnt_expire);
36341f645   Ram Pai   [PATCH] mount exp...
713
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714
715
  	}
  	return mnt;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
716
717
718
719
  
   out_free:
  	free_vfsmnt(mnt);
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
  }
b3e19d924   Nick Piggin   fs: scale mntget/...
721
  static inline void mntfree(struct vfsmount *mnt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
  {
  	struct super_block *sb = mnt->mnt_sb;
b3e19d924   Nick Piggin   fs: scale mntget/...
724

3d733633a   Dave Hansen   [PATCH] r/o bind ...
725
  	/*
3d733633a   Dave Hansen   [PATCH] r/o bind ...
726
727
728
729
730
  	 * This probably indicates that somebody messed
  	 * up a mnt_want/drop_write() pair.  If this
  	 * happens, the filesystem was probably unable
  	 * to make r/w->r/o transitions.
  	 */
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
731
  	/*
b3e19d924   Nick Piggin   fs: scale mntget/...
732
733
  	 * The locking used to deal with mnt_count decrement provides barriers,
  	 * so mnt_get_writers() below is safe.
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
734
  	 */
c6653a838   Nick Piggin   fs: rename vfsmou...
735
  	WARN_ON(mnt_get_writers(mnt));
ca9c726ee   Andreas Gruenbacher   fsnotify: Infrast...
736
  	fsnotify_vfsmount_delete(mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
738
739
740
  	dput(mnt->mnt_root);
  	free_vfsmnt(mnt);
  	deactivate_super(sb);
  }
f03c65993   Al Viro   sanitize vfsmount...
741
  static void mntput_no_expire(struct vfsmount *mnt)
b3e19d924   Nick Piggin   fs: scale mntget/...
742
  {
b3e19d924   Nick Piggin   fs: scale mntget/...
743
  put_again:
f03c65993   Al Viro   sanitize vfsmount...
744
745
746
747
  #ifdef CONFIG_SMP
  	br_read_lock(vfsmount_lock);
  	if (likely(atomic_read(&mnt->mnt_longterm))) {
  		mnt_dec_count(mnt);
b3e19d924   Nick Piggin   fs: scale mntget/...
748
  		br_read_unlock(vfsmount_lock);
f03c65993   Al Viro   sanitize vfsmount...
749
  		return;
b3e19d924   Nick Piggin   fs: scale mntget/...
750
  	}
f03c65993   Al Viro   sanitize vfsmount...
751
  	br_read_unlock(vfsmount_lock);
b3e19d924   Nick Piggin   fs: scale mntget/...
752

99b7db7b8   Nick Piggin   fs: brlock vfsmou...
753
  	br_write_lock(vfsmount_lock);
f03c65993   Al Viro   sanitize vfsmount...
754
  	mnt_dec_count(mnt);
b3e19d924   Nick Piggin   fs: scale mntget/...
755
  	if (mnt_get_count(mnt)) {
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
756
757
758
  		br_write_unlock(vfsmount_lock);
  		return;
  	}
b3e19d924   Nick Piggin   fs: scale mntget/...
759
  #else
b3e19d924   Nick Piggin   fs: scale mntget/...
760
761
  	mnt_dec_count(mnt);
  	if (likely(mnt_get_count(mnt)))
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
762
  		return;
b3e19d924   Nick Piggin   fs: scale mntget/...
763
  	br_write_lock(vfsmount_lock);
f03c65993   Al Viro   sanitize vfsmount...
764
  #endif
b3e19d924   Nick Piggin   fs: scale mntget/...
765
766
767
768
769
770
  	if (unlikely(mnt->mnt_pinned)) {
  		mnt_add_count(mnt, mnt->mnt_pinned + 1);
  		mnt->mnt_pinned = 0;
  		br_write_unlock(vfsmount_lock);
  		acct_auto_close_mnt(mnt);
  		goto put_again;
7b7b1ace2   Al Viro   [PATCH] saner han...
771
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
772
  	br_write_unlock(vfsmount_lock);
b3e19d924   Nick Piggin   fs: scale mntget/...
773
774
  	mntfree(mnt);
  }
b3e19d924   Nick Piggin   fs: scale mntget/...
775
776
777
778
779
780
781
  
  void mntput(struct vfsmount *mnt)
  {
  	if (mnt) {
  		/* avoid cacheline pingpong, hope gcc doesn't get "smart" */
  		if (unlikely(mnt->mnt_expiry_mark))
  			mnt->mnt_expiry_mark = 0;
f03c65993   Al Viro   sanitize vfsmount...
782
  		mntput_no_expire(mnt);
b3e19d924   Nick Piggin   fs: scale mntget/...
783
784
785
786
787
788
789
790
791
792
793
  	}
  }
  EXPORT_SYMBOL(mntput);
  
  struct vfsmount *mntget(struct vfsmount *mnt)
  {
  	if (mnt)
  		mnt_inc_count(mnt);
  	return mnt;
  }
  EXPORT_SYMBOL(mntget);
7b7b1ace2   Al Viro   [PATCH] saner han...
794
795
  void mnt_pin(struct vfsmount *mnt)
  {
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
796
  	br_write_lock(vfsmount_lock);
7b7b1ace2   Al Viro   [PATCH] saner han...
797
  	mnt->mnt_pinned++;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
798
  	br_write_unlock(vfsmount_lock);
7b7b1ace2   Al Viro   [PATCH] saner han...
799
  }
7b7b1ace2   Al Viro   [PATCH] saner han...
800
801
802
803
  EXPORT_SYMBOL(mnt_pin);
  
  void mnt_unpin(struct vfsmount *mnt)
  {
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
804
  	br_write_lock(vfsmount_lock);
7b7b1ace2   Al Viro   [PATCH] saner han...
805
  	if (mnt->mnt_pinned) {
b3e19d924   Nick Piggin   fs: scale mntget/...
806
  		mnt_inc_count(mnt);
7b7b1ace2   Al Viro   [PATCH] saner han...
807
808
  		mnt->mnt_pinned--;
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
809
  	br_write_unlock(vfsmount_lock);
7b7b1ace2   Al Viro   [PATCH] saner han...
810
  }
7b7b1ace2   Al Viro   [PATCH] saner han...
811
  EXPORT_SYMBOL(mnt_unpin);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
812

b3b304a23   Miklos Szeredi   mount options: ad...
813
814
815
816
817
818
819
820
821
822
823
824
825
826
  static inline void mangle(struct seq_file *m, const char *s)
  {
  	seq_escape(m, s, " \t
  \\");
  }
  
  /*
   * Simple .show_options callback for filesystems which don't want to
   * implement more complex mount option showing.
   *
   * See also save_mount_options().
   */
  int generic_show_options(struct seq_file *m, struct vfsmount *mnt)
  {
2a32cebd6   Al Viro   Fix races around ...
827
828
829
830
  	const char *options;
  
  	rcu_read_lock();
  	options = rcu_dereference(mnt->mnt_sb->s_options);
b3b304a23   Miklos Szeredi   mount options: ad...
831
832
833
834
835
  
  	if (options != NULL && options[0]) {
  		seq_putc(m, ',');
  		mangle(m, options);
  	}
2a32cebd6   Al Viro   Fix races around ...
836
  	rcu_read_unlock();
b3b304a23   Miklos Szeredi   mount options: ad...
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
  
  	return 0;
  }
  EXPORT_SYMBOL(generic_show_options);
  
  /*
   * If filesystem uses generic_show_options(), this function should be
   * called from the fill_super() callback.
   *
   * The .remount_fs callback usually needs to be handled in a special
   * way, to make sure, that previous options are not overwritten if the
   * remount fails.
   *
   * Also note, that if the filesystem's .remount_fs function doesn't
   * reset all options to their default value, but changes only newly
   * given options, then the displayed options will not reflect reality
   * any more.
   */
  void save_mount_options(struct super_block *sb, char *options)
  {
2a32cebd6   Al Viro   Fix races around ...
857
858
  	BUG_ON(sb->s_options);
  	rcu_assign_pointer(sb->s_options, kstrdup(options, GFP_KERNEL));
b3b304a23   Miklos Szeredi   mount options: ad...
859
860
  }
  EXPORT_SYMBOL(save_mount_options);
2a32cebd6   Al Viro   Fix races around ...
861
862
863
864
865
866
867
868
869
870
  void replace_mount_options(struct super_block *sb, char *options)
  {
  	char *old = sb->s_options;
  	rcu_assign_pointer(sb->s_options, options);
  	if (old) {
  		synchronize_rcu();
  		kfree(old);
  	}
  }
  EXPORT_SYMBOL(replace_mount_options);
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
871
  #ifdef CONFIG_PROC_FS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
873
874
  /* iterator */
  static void *m_start(struct seq_file *m, loff_t *pos)
  {
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
875
  	struct proc_mounts *p = m->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876

390c68436   Ram Pai   [PATCH] making na...
877
  	down_read(&namespace_sem);
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
878
  	return seq_list_start(&p->ns->list, *pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
879
880
881
882
  }
  
  static void *m_next(struct seq_file *m, void *v, loff_t *pos)
  {
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
883
  	struct proc_mounts *p = m->private;
b0765fb85   Pavel Emelianov   Make /proc/self/m...
884

a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
885
  	return seq_list_next(v, &p->ns->list, pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
886
887
888
889
  }
  
  static void m_stop(struct seq_file *m, void *v)
  {
390c68436   Ram Pai   [PATCH] making na...
890
  	up_read(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
891
  }
9f5596af4   Al Viro   take check for ne...
892
893
894
895
  int mnt_had_events(struct proc_mounts *p)
  {
  	struct mnt_namespace *ns = p->ns;
  	int res = 0;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
896
  	br_read_lock(vfsmount_lock);
f15146380   Kay Sievers   fs: seq_file - ad...
897
898
  	if (p->m.poll_event != ns->event) {
  		p->m.poll_event = ns->event;
9f5596af4   Al Viro   take check for ne...
899
900
  		res = 1;
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
901
  	br_read_unlock(vfsmount_lock);
9f5596af4   Al Viro   take check for ne...
902
903
904
  
  	return res;
  }
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
905
906
907
908
  struct proc_fs_info {
  	int flag;
  	const char *str;
  };
2069f4578   Eric Paris   LSM/SELinux: show...
909
  static int show_sb_opts(struct seq_file *m, struct super_block *sb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910
  {
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
911
  	static const struct proc_fs_info fs_info[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
913
914
  		{ MS_SYNCHRONOUS, ",sync" },
  		{ MS_DIRSYNC, ",dirsync" },
  		{ MS_MANDLOCK, ",mand" },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
915
916
  		{ 0, NULL }
  	};
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
917
918
919
920
921
922
  	const struct proc_fs_info *fs_infop;
  
  	for (fs_infop = fs_info; fs_infop->flag; fs_infop++) {
  		if (sb->s_flags & fs_infop->flag)
  			seq_puts(m, fs_infop->str);
  	}
2069f4578   Eric Paris   LSM/SELinux: show...
923
924
  
  	return security_sb_show_options(m, sb);
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
925
926
927
928
929
  }
  
  static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt)
  {
  	static const struct proc_fs_info mnt_info[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
930
931
932
  		{ MNT_NOSUID, ",nosuid" },
  		{ MNT_NODEV, ",nodev" },
  		{ MNT_NOEXEC, ",noexec" },
fc33a7bb9   Christoph Hellwig   [PATCH] per-mount...
933
934
  		{ MNT_NOATIME, ",noatime" },
  		{ MNT_NODIRATIME, ",nodiratime" },
47ae32d6a   Valerie Henson   [PATCH] relative ...
935
  		{ MNT_RELATIME, ",relatime" },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
937
  		{ 0, NULL }
  	};
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
  	const struct proc_fs_info *fs_infop;
  
  	for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) {
  		if (mnt->mnt_flags & fs_infop->flag)
  			seq_puts(m, fs_infop->str);
  	}
  }
  
  static void show_type(struct seq_file *m, struct super_block *sb)
  {
  	mangle(m, sb->s_type->name);
  	if (sb->s_subtype && sb->s_subtype[0]) {
  		seq_putc(m, '.');
  		mangle(m, sb->s_subtype);
  	}
  }
  
  static int show_vfsmnt(struct seq_file *m, void *v)
  {
  	struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list);
  	int err = 0;
c32c2f63a   Jan Blunck   d_path: Make seq_...
959
  	struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960

c7f404b40   Al Viro   vfs: new superblo...
961
962
963
964
965
966
967
  	if (mnt->mnt_sb->s_op->show_devname) {
  		err = mnt->mnt_sb->s_op->show_devname(m, mnt);
  		if (err)
  			goto out;
  	} else {
  		mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
968
  	seq_putc(m, ' ');
c32c2f63a   Jan Blunck   d_path: Make seq_...
969
970
  	seq_path(m, &mnt_path, " \t
  \\");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
971
  	seq_putc(m, ' ');
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
972
  	show_type(m, mnt->mnt_sb);
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
973
  	seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw");
2069f4578   Eric Paris   LSM/SELinux: show...
974
975
976
  	err = show_sb_opts(m, mnt->mnt_sb);
  	if (err)
  		goto out;
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
977
  	show_mnt_opts(m, mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
978
979
980
981
  	if (mnt->mnt_sb->s_op->show_options)
  		err = mnt->mnt_sb->s_op->show_options(m, mnt);
  	seq_puts(m, " 0 0
  ");
2069f4578   Eric Paris   LSM/SELinux: show...
982
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983
984
  	return err;
  }
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
985
  const struct seq_operations mounts_op = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
986
987
988
989
990
  	.start	= m_start,
  	.next	= m_next,
  	.stop	= m_stop,
  	.show	= show_vfsmnt
  };
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
991
992
993
994
995
996
997
998
999
1000
1001
  static int show_mountinfo(struct seq_file *m, void *v)
  {
  	struct proc_mounts *p = m->private;
  	struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list);
  	struct super_block *sb = mnt->mnt_sb;
  	struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
  	struct path root = p->root;
  	int err = 0;
  
  	seq_printf(m, "%i %i %u:%u ", mnt->mnt_id, mnt->mnt_parent->mnt_id,
  		   MAJOR(sb->s_dev), MINOR(sb->s_dev));
c7f404b40   Al Viro   vfs: new superblo...
1002
1003
1004
1005
1006
1007
1008
  	if (sb->s_op->show_path)
  		err = sb->s_op->show_path(m, mnt);
  	else
  		seq_dentry(m, mnt->mnt_root, " \t
  \\");
  	if (err)
  		goto out;
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
  	seq_putc(m, ' ');
  	seq_path_root(m, &mnt_path, &root, " \t
  \\");
  	if (root.mnt != p->root.mnt || root.dentry != p->root.dentry) {
  		/*
  		 * Mountpoint is outside root, discard that one.  Ugly,
  		 * but less so than trying to do that in iterator in a
  		 * race-free way (due to renames).
  		 */
  		return SEQ_SKIP;
  	}
  	seq_puts(m, mnt->mnt_flags & MNT_READONLY ? " ro" : " rw");
  	show_mnt_opts(m, mnt);
  
  	/* Tagged fields ("foo:X" or "bar") */
  	if (IS_MNT_SHARED(mnt))
  		seq_printf(m, " shared:%i", mnt->mnt_group_id);
97e7e0f71   Miklos Szeredi   [patch 7/7] vfs: ...
1026
1027
1028
1029
1030
1031
1032
  	if (IS_MNT_SLAVE(mnt)) {
  		int master = mnt->mnt_master->mnt_group_id;
  		int dom = get_dominating_id(mnt, &p->root);
  		seq_printf(m, " master:%i", master);
  		if (dom && dom != master)
  			seq_printf(m, " propagate_from:%i", dom);
  	}
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
1033
1034
1035
1036
1037
1038
1039
  	if (IS_MNT_UNBINDABLE(mnt))
  		seq_puts(m, " unbindable");
  
  	/* Filesystem specific data */
  	seq_puts(m, " - ");
  	show_type(m, sb);
  	seq_putc(m, ' ');
c7f404b40   Al Viro   vfs: new superblo...
1040
1041
1042
1043
1044
1045
  	if (sb->s_op->show_devname)
  		err = sb->s_op->show_devname(m, mnt);
  	else
  		mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
  	if (err)
  		goto out;
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
1046
  	seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw");
2069f4578   Eric Paris   LSM/SELinux: show...
1047
1048
1049
  	err = show_sb_opts(m, sb);
  	if (err)
  		goto out;
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
1050
1051
1052
1053
  	if (sb->s_op->show_options)
  		err = sb->s_op->show_options(m, mnt);
  	seq_putc(m, '
  ');
2069f4578   Eric Paris   LSM/SELinux: show...
1054
  out:
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
1055
1056
1057
1058
1059
1060
1061
1062
1063
  	return err;
  }
  
  const struct seq_operations mountinfo_op = {
  	.start	= m_start,
  	.next	= m_next,
  	.stop	= m_stop,
  	.show	= show_mountinfo,
  };
b4629fe2f   Chuck Lever   VFS: New /proc fi...
1064
1065
  static int show_vfsstat(struct seq_file *m, void *v)
  {
b0765fb85   Pavel Emelianov   Make /proc/self/m...
1066
  	struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list);
c32c2f63a   Jan Blunck   d_path: Make seq_...
1067
  	struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
b4629fe2f   Chuck Lever   VFS: New /proc fi...
1068
1069
1070
  	int err = 0;
  
  	/* device */
c7f404b40   Al Viro   vfs: new superblo...
1071
1072
1073
1074
1075
1076
1077
1078
1079
  	if (mnt->mnt_sb->s_op->show_devname) {
  		err = mnt->mnt_sb->s_op->show_devname(m, mnt);
  	} else {
  		if (mnt->mnt_devname) {
  			seq_puts(m, "device ");
  			mangle(m, mnt->mnt_devname);
  		} else
  			seq_puts(m, "no device");
  	}
b4629fe2f   Chuck Lever   VFS: New /proc fi...
1080
1081
1082
  
  	/* mount point */
  	seq_puts(m, " mounted on ");
c32c2f63a   Jan Blunck   d_path: Make seq_...
1083
1084
  	seq_path(m, &mnt_path, " \t
  \\");
b4629fe2f   Chuck Lever   VFS: New /proc fi...
1085
1086
1087
1088
  	seq_putc(m, ' ');
  
  	/* file system type */
  	seq_puts(m, "with fstype ");
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
1089
  	show_type(m, mnt->mnt_sb);
b4629fe2f   Chuck Lever   VFS: New /proc fi...
1090
1091
1092
1093
  
  	/* optional statistics */
  	if (mnt->mnt_sb->s_op->show_stats) {
  		seq_putc(m, ' ');
c7f404b40   Al Viro   vfs: new superblo...
1094
1095
  		if (!err)
  			err = mnt->mnt_sb->s_op->show_stats(m, mnt);
b4629fe2f   Chuck Lever   VFS: New /proc fi...
1096
1097
1098
1099
1100
1101
  	}
  
  	seq_putc(m, '
  ');
  	return err;
  }
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
1102
  const struct seq_operations mountstats_op = {
b4629fe2f   Chuck Lever   VFS: New /proc fi...
1103
1104
1105
1106
1107
  	.start	= m_start,
  	.next	= m_next,
  	.stop	= m_stop,
  	.show	= show_vfsstat,
  };
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
1108
  #endif  /* CONFIG_PROC_FS */
b4629fe2f   Chuck Lever   VFS: New /proc fi...
1109

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
  /**
   * may_umount_tree - check if a mount tree is busy
   * @mnt: root of mount tree
   *
   * This is called to check if a tree of mounts has any
   * open files, pwds, chroots or sub mounts that are
   * busy.
   */
  int may_umount_tree(struct vfsmount *mnt)
  {
36341f645   Ram Pai   [PATCH] mount exp...
1120
1121
1122
  	int actual_refs = 0;
  	int minimum_refs = 0;
  	struct vfsmount *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1123

b3e19d924   Nick Piggin   fs: scale mntget/...
1124
1125
  	/* write lock needed for mnt_get_count */
  	br_write_lock(vfsmount_lock);
36341f645   Ram Pai   [PATCH] mount exp...
1126
  	for (p = mnt; p; p = next_mnt(p, mnt)) {
b3e19d924   Nick Piggin   fs: scale mntget/...
1127
  		actual_refs += mnt_get_count(p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1128
  		minimum_refs += 2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129
  	}
b3e19d924   Nick Piggin   fs: scale mntget/...
1130
  	br_write_unlock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1131
1132
  
  	if (actual_refs > minimum_refs)
e3474a8eb   Ian Kent   [PATCH] autofs4: ...
1133
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1134

e3474a8eb   Ian Kent   [PATCH] autofs4: ...
1135
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
  }
  
  EXPORT_SYMBOL(may_umount_tree);
  
  /**
   * may_umount - check if a mount point is busy
   * @mnt: root of mount
   *
   * This is called to check if a mount point has any
   * open files, pwds, chroots or sub mounts. If the
   * mount has sub mounts this will return busy
   * regardless of whether the sub mounts are busy.
   *
   * Doesn't take quota and stuff into account. IOW, in some cases it will
   * give false negatives. The main reason why it's here is that we need
   * a non-destructive way to look for easily umountable filesystems.
   */
  int may_umount(struct vfsmount *mnt)
  {
e3474a8eb   Ian Kent   [PATCH] autofs4: ...
1155
  	int ret = 1;
8ad08d8a0   Al Viro   may_umount() need...
1156
  	down_read(&namespace_sem);
b3e19d924   Nick Piggin   fs: scale mntget/...
1157
  	br_write_lock(vfsmount_lock);
a05964f39   Ram Pai   [PATCH] shared mo...
1158
  	if (propagate_mount_busy(mnt, 2))
e3474a8eb   Ian Kent   [PATCH] autofs4: ...
1159
  		ret = 0;
b3e19d924   Nick Piggin   fs: scale mntget/...
1160
  	br_write_unlock(vfsmount_lock);
8ad08d8a0   Al Viro   may_umount() need...
1161
  	up_read(&namespace_sem);
a05964f39   Ram Pai   [PATCH] shared mo...
1162
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1163
1164
1165
  }
  
  EXPORT_SYMBOL(may_umount);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1166
  void release_mounts(struct list_head *head)
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1167
1168
  {
  	struct vfsmount *mnt;
bf066c7db   Miklos Szeredi   [PATCH] shared mo...
1169
  	while (!list_empty(head)) {
b5e618181   Pavel Emelianov   Introduce a handy...
1170
  		mnt = list_first_entry(head, struct vfsmount, mnt_hash);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1171
1172
1173
1174
  		list_del_init(&mnt->mnt_hash);
  		if (mnt->mnt_parent != mnt) {
  			struct dentry *dentry;
  			struct vfsmount *m;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1175
1176
  
  			br_write_lock(vfsmount_lock);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1177
1178
1179
1180
  			dentry = mnt->mnt_mountpoint;
  			m = mnt->mnt_parent;
  			mnt->mnt_mountpoint = mnt->mnt_root;
  			mnt->mnt_parent = mnt;
7c4b93d82   Al Viro   [PATCH] count gho...
1181
  			m->mnt_ghosts--;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1182
  			br_write_unlock(vfsmount_lock);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1183
1184
1185
  			dput(dentry);
  			mntput(m);
  		}
f03c65993   Al Viro   sanitize vfsmount...
1186
  		mntput(mnt);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1187
1188
  	}
  }
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1189
1190
1191
1192
  /*
   * vfsmount lock must be held for write
   * namespace_sem must be held for write
   */
a05964f39   Ram Pai   [PATCH] shared mo...
1193
  void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1194
  {
7b8a53fd8   Al Viro   fix old umount_tr...
1195
  	LIST_HEAD(tmp_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1196
  	struct vfsmount *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1197

1bfba4e8e   Akinobu Mita   [PATCH] core: use...
1198
  	for (p = mnt; p; p = next_mnt(p, mnt))
7b8a53fd8   Al Viro   fix old umount_tr...
1199
  		list_move(&p->mnt_hash, &tmp_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1200

a05964f39   Ram Pai   [PATCH] shared mo...
1201
  	if (propagate)
7b8a53fd8   Al Viro   fix old umount_tr...
1202
  		propagate_umount(&tmp_list);
a05964f39   Ram Pai   [PATCH] shared mo...
1203

7b8a53fd8   Al Viro   fix old umount_tr...
1204
  	list_for_each_entry(p, &tmp_list, mnt_hash) {
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1205
1206
  		list_del_init(&p->mnt_expire);
  		list_del_init(&p->mnt_list);
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
1207
1208
  		__touch_mnt_namespace(p->mnt_ns);
  		p->mnt_ns = NULL;
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
1209
  		__mnt_make_shortterm(p);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1210
  		list_del_init(&p->mnt_child);
7c4b93d82   Al Viro   [PATCH] count gho...
1211
1212
  		if (p->mnt_parent != p) {
  			p->mnt_parent->mnt_ghosts++;
5f57cbcc0   Nick Piggin   fs: dcache remove...
1213
  			dentry_reset_mounted(p->mnt_parent, p->mnt_mountpoint);
7c4b93d82   Al Viro   [PATCH] count gho...
1214
  		}
a05964f39   Ram Pai   [PATCH] shared mo...
1215
  		change_mnt_propagation(p, MS_PRIVATE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1216
  	}
7b8a53fd8   Al Viro   fix old umount_tr...
1217
  	list_splice(&tmp_list, kill);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1218
  }
c35038bec   Al Viro   [PATCH] do shrink...
1219
  static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1220
1221
  static int do_umount(struct vfsmount *mnt, int flags)
  {
b58fed8b1   Ram Pai   [PATCH] lindent f...
1222
  	struct super_block *sb = mnt->mnt_sb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1223
  	int retval;
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1224
  	LIST_HEAD(umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
  
  	retval = security_sb_umount(mnt, flags);
  	if (retval)
  		return retval;
  
  	/*
  	 * Allow userspace to request a mountpoint be expired rather than
  	 * unmounting unconditionally. Unmount only happens if:
  	 *  (1) the mark is already set (the mark is cleared by mntput())
  	 *  (2) the usage count == 1 [parent vfsmount] + 1 [sys_umount]
  	 */
  	if (flags & MNT_EXPIRE) {
6ac08c39a   Jan Blunck   Use struct path i...
1237
  		if (mnt == current->fs->root.mnt ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1238
1239
  		    flags & (MNT_FORCE | MNT_DETACH))
  			return -EINVAL;
b3e19d924   Nick Piggin   fs: scale mntget/...
1240
1241
1242
1243
1244
1245
  		/*
  		 * probably don't strictly need the lock here if we examined
  		 * all race cases, but it's a slowpath.
  		 */
  		br_write_lock(vfsmount_lock);
  		if (mnt_get_count(mnt) != 2) {
bf9faa2aa   J. R. Okajima   Unlock vfsmount_l...
1246
  			br_write_unlock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1247
  			return -EBUSY;
b3e19d924   Nick Piggin   fs: scale mntget/...
1248
1249
  		}
  		br_write_unlock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
  
  		if (!xchg(&mnt->mnt_expiry_mark, 1))
  			return -EAGAIN;
  	}
  
  	/*
  	 * If we may have to abort operations to get out of this
  	 * mount, and they will themselves hold resources we must
  	 * allow the fs to do things. In the Unix tradition of
  	 * 'Gee thats tricky lets do it in userspace' the umount_begin
  	 * might fail to complete on the first run through as other tasks
  	 * must return, and the like. Thats for the mount program to worry
  	 * about for the moment.
  	 */
42faad996   Al Viro   [PATCH] restore s...
1264
  	if (flags & MNT_FORCE && sb->s_op->umount_begin) {
42faad996   Al Viro   [PATCH] restore s...
1265
  		sb->s_op->umount_begin(sb);
42faad996   Al Viro   [PATCH] restore s...
1266
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
  
  	/*
  	 * No sense to grab the lock for this test, but test itself looks
  	 * somewhat bogus. Suggestions for better replacement?
  	 * Ho-hum... In principle, we might treat that as umount + switch
  	 * to rootfs. GC would eventually take care of the old vfsmount.
  	 * Actually it makes sense, especially if rootfs would contain a
  	 * /reboot - static binary that would close all descriptors and
  	 * call reboot(9). Then init(8) could umount root and exec /reboot.
  	 */
6ac08c39a   Jan Blunck   Use struct path i...
1277
  	if (mnt == current->fs->root.mnt && !(flags & MNT_DETACH)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1278
1279
1280
1281
1282
  		/*
  		 * Special case for "unmounting" root ...
  		 * we just try to remount it readonly.
  		 */
  		down_write(&sb->s_umount);
4aa98cf76   Al Viro   Push BKL down int...
1283
  		if (!(sb->s_flags & MS_RDONLY))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1284
  			retval = do_remount_sb(sb, MS_RDONLY, NULL, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1285
1286
1287
  		up_write(&sb->s_umount);
  		return retval;
  	}
390c68436   Ram Pai   [PATCH] making na...
1288
  	down_write(&namespace_sem);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1289
  	br_write_lock(vfsmount_lock);
5addc5dd8   Al Viro   [PATCH] make /pro...
1290
  	event++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1291

c35038bec   Al Viro   [PATCH] do shrink...
1292
1293
  	if (!(flags & MNT_DETACH))
  		shrink_submounts(mnt, &umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1294
  	retval = -EBUSY;
a05964f39   Ram Pai   [PATCH] shared mo...
1295
  	if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1296
  		if (!list_empty(&mnt->mnt_list))
a05964f39   Ram Pai   [PATCH] shared mo...
1297
  			umount_tree(mnt, 1, &umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1298
1299
  		retval = 0;
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1300
  	br_write_unlock(vfsmount_lock);
390c68436   Ram Pai   [PATCH] making na...
1301
  	up_write(&namespace_sem);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1302
  	release_mounts(&umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
  	return retval;
  }
  
  /*
   * Now umount can handle mount points as well as block devices.
   * This is important for filesystems which use unnamed block devices.
   *
   * We now support a flag for forced unmount like the other 'big iron'
   * unixes. Our API is identical to OSF/1 to avoid making a mess of AMD
   */
bdc480e3b   Heiko Carstens   [CVE-2009-0029] S...
1313
  SYSCALL_DEFINE2(umount, char __user *, name, int, flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1314
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
1315
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1316
  	int retval;
db1f05bb8   Miklos Szeredi   vfs: add NOFOLLOW...
1317
  	int lookup_flags = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1318

db1f05bb8   Miklos Szeredi   vfs: add NOFOLLOW...
1319
1320
1321
1322
1323
1324
1325
  	if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW))
  		return -EINVAL;
  
  	if (!(flags & UMOUNT_NOFOLLOW))
  		lookup_flags |= LOOKUP_FOLLOW;
  
  	retval = user_path_at(AT_FDCWD, name, lookup_flags, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1326
1327
1328
  	if (retval)
  		goto out;
  	retval = -EINVAL;
2d8f30380   Al Viro   [PATCH] sanitize ...
1329
  	if (path.dentry != path.mnt->mnt_root)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1330
  		goto dput_and_out;
2d8f30380   Al Viro   [PATCH] sanitize ...
1331
  	if (!check_mnt(path.mnt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1332
1333
1334
1335
1336
  		goto dput_and_out;
  
  	retval = -EPERM;
  	if (!capable(CAP_SYS_ADMIN))
  		goto dput_and_out;
2d8f30380   Al Viro   [PATCH] sanitize ...
1337
  	retval = do_umount(path.mnt, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1338
  dput_and_out:
429731b15   Jan Blunck   Remove path_relea...
1339
  	/* we mustn't call path_put() as that would clear mnt_expiry_mark */
2d8f30380   Al Viro   [PATCH] sanitize ...
1340
1341
  	dput(path.dentry);
  	mntput_no_expire(path.mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1342
1343
1344
1345
1346
1347
1348
  out:
  	return retval;
  }
  
  #ifdef __ARCH_WANT_SYS_OLDUMOUNT
  
  /*
b58fed8b1   Ram Pai   [PATCH] lindent f...
1349
   *	The 2.0 compatible umount. No flags.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1350
   */
bdc480e3b   Heiko Carstens   [CVE-2009-0029] S...
1351
  SYSCALL_DEFINE1(oldumount, char __user *, name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1352
  {
b58fed8b1   Ram Pai   [PATCH] lindent f...
1353
  	return sys_umount(name, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1354
1355
1356
  }
  
  #endif
2d92ab3c6   Al Viro   [PATCH] finally g...
1357
  static int mount_is_safe(struct path *path)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1358
1359
1360
1361
1362
  {
  	if (capable(CAP_SYS_ADMIN))
  		return 0;
  	return -EPERM;
  #ifdef notyet
2d92ab3c6   Al Viro   [PATCH] finally g...
1363
  	if (S_ISLNK(path->dentry->d_inode->i_mode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1364
  		return -EPERM;
2d92ab3c6   Al Viro   [PATCH] finally g...
1365
  	if (path->dentry->d_inode->i_mode & S_ISVTX) {
da9592ede   David Howells   CRED: Wrap task c...
1366
  		if (current_uid() != path->dentry->d_inode->i_uid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1367
1368
  			return -EPERM;
  	}
2d92ab3c6   Al Viro   [PATCH] finally g...
1369
  	if (inode_permission(path->dentry->d_inode, MAY_WRITE))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1370
1371
1372
1373
  		return -EPERM;
  	return 0;
  #endif
  }
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1374
  struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry,
36341f645   Ram Pai   [PATCH] mount exp...
1375
  					int flag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1376
1377
  {
  	struct vfsmount *res, *p, *q, *r, *s;
1a3906895   Al Viro   [PATCH] reduce st...
1378
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1379

9676f0c63   Ram Pai   [PATCH] unbindabl...
1380
1381
  	if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(mnt))
  		return NULL;
36341f645   Ram Pai   [PATCH] mount exp...
1382
  	res = q = clone_mnt(mnt, dentry, flag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1383
1384
1385
1386
1387
  	if (!q)
  		goto Enomem;
  	q->mnt_mountpoint = mnt->mnt_mountpoint;
  
  	p = mnt;
fdadd65fb   Domen Puncer   [PATCH] janitor: ...
1388
  	list_for_each_entry(r, &mnt->mnt_mounts, mnt_child) {
7ec02ef15   Jan Blunck   vfs: remove lives...
1389
  		if (!is_subdir(r->mnt_mountpoint, dentry))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1390
1391
1392
  			continue;
  
  		for (s = r; s; s = next_mnt(s, r)) {
9676f0c63   Ram Pai   [PATCH] unbindabl...
1393
1394
1395
1396
  			if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(s)) {
  				s = skip_mnt_tree(s);
  				continue;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1397
1398
1399
1400
1401
  			while (p != s->mnt_parent) {
  				p = p->mnt_parent;
  				q = q->mnt_parent;
  			}
  			p = s;
1a3906895   Al Viro   [PATCH] reduce st...
1402
1403
  			path.mnt = q;
  			path.dentry = p->mnt_mountpoint;
36341f645   Ram Pai   [PATCH] mount exp...
1404
  			q = clone_mnt(p, p->mnt_root, flag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1405
1406
  			if (!q)
  				goto Enomem;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1407
  			br_write_lock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1408
  			list_add_tail(&q->mnt_list, &res->mnt_list);
1a3906895   Al Viro   [PATCH] reduce st...
1409
  			attach_mnt(q, &path);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1410
  			br_write_unlock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1411
1412
1413
  		}
  	}
  	return res;
b58fed8b1   Ram Pai   [PATCH] lindent f...
1414
  Enomem:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1415
  	if (res) {
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1416
  		LIST_HEAD(umount_list);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1417
  		br_write_lock(vfsmount_lock);
a05964f39   Ram Pai   [PATCH] shared mo...
1418
  		umount_tree(res, 0, &umount_list);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1419
  		br_write_unlock(vfsmount_lock);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1420
  		release_mounts(&umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1421
1422
1423
  	}
  	return NULL;
  }
589ff870e   Al Viro   Switch collect_mo...
1424
  struct vfsmount *collect_mounts(struct path *path)
8aec08094   Al Viro   [PATCH] new helpe...
1425
1426
  {
  	struct vfsmount *tree;
1a60a2807   Al Viro   [PATCH] lock excl...
1427
  	down_write(&namespace_sem);
589ff870e   Al Viro   Switch collect_mo...
1428
  	tree = copy_tree(path->mnt, path->dentry, CL_COPY_ALL | CL_PRIVATE);
1a60a2807   Al Viro   [PATCH] lock excl...
1429
  	up_write(&namespace_sem);
8aec08094   Al Viro   [PATCH] new helpe...
1430
1431
1432
1433
1434
1435
  	return tree;
  }
  
  void drop_collected_mounts(struct vfsmount *mnt)
  {
  	LIST_HEAD(umount_list);
1a60a2807   Al Viro   [PATCH] lock excl...
1436
  	down_write(&namespace_sem);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1437
  	br_write_lock(vfsmount_lock);
8aec08094   Al Viro   [PATCH] new helpe...
1438
  	umount_tree(mnt, 0, &umount_list);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1439
  	br_write_unlock(vfsmount_lock);
1a60a2807   Al Viro   [PATCH] lock excl...
1440
  	up_write(&namespace_sem);
8aec08094   Al Viro   [PATCH] new helpe...
1441
1442
  	release_mounts(&umount_list);
  }
1f707137b   Al Viro   new helper: itera...
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
  int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg,
  		   struct vfsmount *root)
  {
  	struct vfsmount *mnt;
  	int res = f(root, arg);
  	if (res)
  		return res;
  	list_for_each_entry(mnt, &root->mnt_list, mnt_list) {
  		res = f(mnt, arg);
  		if (res)
  			return res;
  	}
  	return 0;
  }
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
  static void cleanup_group_ids(struct vfsmount *mnt, struct vfsmount *end)
  {
  	struct vfsmount *p;
  
  	for (p = mnt; p != end; p = next_mnt(p, mnt)) {
  		if (p->mnt_group_id && !IS_MNT_SHARED(p))
  			mnt_release_group_id(p);
  	}
  }
  
  static int invent_group_ids(struct vfsmount *mnt, bool recurse)
  {
  	struct vfsmount *p;
  
  	for (p = mnt; p; p = recurse ? next_mnt(p, mnt) : NULL) {
  		if (!p->mnt_group_id && !IS_MNT_SHARED(p)) {
  			int err = mnt_alloc_group_id(p);
  			if (err) {
  				cleanup_group_ids(mnt, p);
  				return err;
  			}
  		}
  	}
  
  	return 0;
  }
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1483
1484
  /*
   *  @source_mnt : mount tree to be attached
214444032   Ram Pai   [PATCH] shared mo...
1485
1486
1487
1488
   *  @nd         : place the mount tree @source_mnt is attached
   *  @parent_nd  : if non-null, detach the source_mnt from its parent and
   *  		   store the parent mount and mountpoint dentry.
   *  		   (done when source_mnt is moved)
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1489
1490
1491
   *
   *  NOTE: in the table below explains the semantics when a source mount
   *  of a given type is attached to a destination mount of a given type.
9676f0c63   Ram Pai   [PATCH] unbindabl...
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
   * ---------------------------------------------------------------------------
   * |         BIND MOUNT OPERATION                                            |
   * |**************************************************************************
   * | source-->| shared        |       private  |       slave    | unbindable |
   * | dest     |               |                |                |            |
   * |   |      |               |                |                |            |
   * |   v      |               |                |                |            |
   * |**************************************************************************
   * |  shared  | shared (++)   |     shared (+) |     shared(+++)|  invalid   |
   * |          |               |                |                |            |
   * |non-shared| shared (+)    |      private   |      slave (*) |  invalid   |
   * ***************************************************************************
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1504
1505
1506
1507
1508
1509
1510
1511
1512
   * A bind operation clones the source mount and mounts the clone on the
   * destination mount.
   *
   * (++)  the cloned mount is propagated to all the mounts in the propagation
   * 	 tree of the destination mount and the cloned mount is added to
   * 	 the peer group of the source mount.
   * (+)   the cloned mount is created under the destination mount and is marked
   *       as shared. The cloned mount is added to the peer group of the source
   *       mount.
5afe00221   Ram Pai   [PATCH] handling ...
1513
1514
1515
1516
1517
1518
1519
   * (+++) the mount is propagated to all the mounts in the propagation tree
   *       of the destination mount and the cloned mount is made slave
   *       of the same master as that of the source mount. The cloned mount
   *       is marked as 'shared and slave'.
   * (*)   the cloned mount is made a slave of the same master as that of the
   * 	 source mount.
   *
9676f0c63   Ram Pai   [PATCH] unbindabl...
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
   * ---------------------------------------------------------------------------
   * |         		MOVE MOUNT OPERATION                                 |
   * |**************************************************************************
   * | source-->| shared        |       private  |       slave    | unbindable |
   * | dest     |               |                |                |            |
   * |   |      |               |                |                |            |
   * |   v      |               |                |                |            |
   * |**************************************************************************
   * |  shared  | shared (+)    |     shared (+) |    shared(+++) |  invalid   |
   * |          |               |                |                |            |
   * |non-shared| shared (+*)   |      private   |    slave (*)   | unbindable |
   * ***************************************************************************
5afe00221   Ram Pai   [PATCH] handling ...
1532
1533
1534
   *
   * (+)  the mount is moved to the destination. And is then propagated to
   * 	all the mounts in the propagation tree of the destination mount.
214444032   Ram Pai   [PATCH] shared mo...
1535
   * (+*)  the mount is moved to the destination.
5afe00221   Ram Pai   [PATCH] handling ...
1536
1537
1538
1539
   * (+++)  the mount is moved to the destination and is then propagated to
   * 	all the mounts belonging to the destination mount's propagation tree.
   * 	the mount is marked as 'shared and slave'.
   * (*)	the mount continues to be a slave at the new location.
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1540
1541
1542
1543
1544
1545
1546
   *
   * if the source mount is a tree, the operations explained above is
   * applied to each mount in the tree.
   * Must be called without spinlocks held, since this function can sleep
   * in allocations.
   */
  static int attach_recursive_mnt(struct vfsmount *source_mnt,
1a3906895   Al Viro   [PATCH] reduce st...
1547
  			struct path *path, struct path *parent_path)
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1548
1549
  {
  	LIST_HEAD(tree_list);
1a3906895   Al Viro   [PATCH] reduce st...
1550
1551
  	struct vfsmount *dest_mnt = path->mnt;
  	struct dentry *dest_dentry = path->dentry;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1552
  	struct vfsmount *child, *p;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1553
  	int err;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1554

719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1555
1556
1557
1558
1559
1560
1561
1562
  	if (IS_MNT_SHARED(dest_mnt)) {
  		err = invent_group_ids(source_mnt, true);
  		if (err)
  			goto out;
  	}
  	err = propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list);
  	if (err)
  		goto out_cleanup_ids;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1563

99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1564
  	br_write_lock(vfsmount_lock);
df1a1ad29   Al Viro   attach_recursive_...
1565

b90fa9ae8   Ram Pai   [PATCH] shared mo...
1566
1567
1568
1569
  	if (IS_MNT_SHARED(dest_mnt)) {
  		for (p = source_mnt; p; p = next_mnt(p, source_mnt))
  			set_mnt_shared(p);
  	}
1a3906895   Al Viro   [PATCH] reduce st...
1570
1571
1572
  	if (parent_path) {
  		detach_mnt(source_mnt, parent_path);
  		attach_mnt(source_mnt, path);
e5d67f071   Al Viro   Touch all affecte...
1573
  		touch_mnt_namespace(parent_path->mnt->mnt_ns);
214444032   Ram Pai   [PATCH] shared mo...
1574
1575
1576
1577
  	} else {
  		mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt);
  		commit_tree(source_mnt);
  	}
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1578
1579
1580
1581
1582
  
  	list_for_each_entry_safe(child, p, &tree_list, mnt_hash) {
  		list_del_init(&child->mnt_hash);
  		commit_tree(child);
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1583
  	br_write_unlock(vfsmount_lock);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1584
  	return 0;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1585
1586
1587
1588
1589
1590
  
   out_cleanup_ids:
  	if (IS_MNT_SHARED(dest_mnt))
  		cleanup_group_ids(source_mnt, NULL);
   out:
  	return err;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1591
  }
b12cea919   Al Viro   change the lockin...
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
  static int lock_mount(struct path *path)
  {
  	struct vfsmount *mnt;
  retry:
  	mutex_lock(&path->dentry->d_inode->i_mutex);
  	if (unlikely(cant_mount(path->dentry))) {
  		mutex_unlock(&path->dentry->d_inode->i_mutex);
  		return -ENOENT;
  	}
  	down_write(&namespace_sem);
  	mnt = lookup_mnt(path);
  	if (likely(!mnt))
  		return 0;
  	up_write(&namespace_sem);
  	mutex_unlock(&path->dentry->d_inode->i_mutex);
  	path_put(path);
  	path->mnt = mnt;
  	path->dentry = dget(mnt->mnt_root);
  	goto retry;
  }
  
  static void unlock_mount(struct path *path)
  {
  	up_write(&namespace_sem);
  	mutex_unlock(&path->dentry->d_inode->i_mutex);
  }
8c3ee42e8   Al Viro   [PATCH] get rid o...
1618
  static int graft_tree(struct vfsmount *mnt, struct path *path)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1619
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1620
1621
  	if (mnt->mnt_sb->s_flags & MS_NOUSER)
  		return -EINVAL;
8c3ee42e8   Al Viro   [PATCH] get rid o...
1622
  	if (S_ISDIR(path->dentry->d_inode->i_mode) !=
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1623
1624
  	      S_ISDIR(mnt->mnt_root->d_inode->i_mode))
  		return -ENOTDIR;
b12cea919   Al Viro   change the lockin...
1625
1626
  	if (d_unlinked(path->dentry))
  		return -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1627

b12cea919   Al Viro   change the lockin...
1628
  	return attach_recursive_mnt(mnt, path, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1629
1630
1631
  }
  
  /*
7a2e8a8fa   Valerie Aurora   VFS: Sanity check...
1632
1633
1634
1635
1636
   * Sanity check the flags to change_mnt_propagation.
   */
  
  static int flags_to_propagation_type(int flags)
  {
7c6e984df   Roman Borisov   fs/namespace.c: b...
1637
  	int type = flags & ~(MS_REC | MS_SILENT);
7a2e8a8fa   Valerie Aurora   VFS: Sanity check...
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
  
  	/* Fail if any non-propagation flags are set */
  	if (type & ~(MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
  		return 0;
  	/* Only one propagation flag should be set */
  	if (!is_power_of_2(type))
  		return 0;
  	return type;
  }
  
  /*
07b20889e   Ram Pai   [PATCH] beginning...
1649
1650
   * recursively change the type of the mountpoint.
   */
0a0d8a467   Al Viro   [PATCH] no need f...
1651
  static int do_change_type(struct path *path, int flag)
07b20889e   Ram Pai   [PATCH] beginning...
1652
  {
2d92ab3c6   Al Viro   [PATCH] finally g...
1653
  	struct vfsmount *m, *mnt = path->mnt;
07b20889e   Ram Pai   [PATCH] beginning...
1654
  	int recurse = flag & MS_REC;
7a2e8a8fa   Valerie Aurora   VFS: Sanity check...
1655
  	int type;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1656
  	int err = 0;
07b20889e   Ram Pai   [PATCH] beginning...
1657

ee6f95829   Miklos Szeredi   check privileges ...
1658
1659
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
2d92ab3c6   Al Viro   [PATCH] finally g...
1660
  	if (path->dentry != path->mnt->mnt_root)
07b20889e   Ram Pai   [PATCH] beginning...
1661
  		return -EINVAL;
7a2e8a8fa   Valerie Aurora   VFS: Sanity check...
1662
1663
1664
  	type = flags_to_propagation_type(flag);
  	if (!type)
  		return -EINVAL;
07b20889e   Ram Pai   [PATCH] beginning...
1665
  	down_write(&namespace_sem);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1666
1667
1668
1669
1670
  	if (type == MS_SHARED) {
  		err = invent_group_ids(mnt, recurse);
  		if (err)
  			goto out_unlock;
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1671
  	br_write_lock(vfsmount_lock);
07b20889e   Ram Pai   [PATCH] beginning...
1672
1673
  	for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL))
  		change_mnt_propagation(m, type);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1674
  	br_write_unlock(vfsmount_lock);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1675
1676
  
   out_unlock:
07b20889e   Ram Pai   [PATCH] beginning...
1677
  	up_write(&namespace_sem);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1678
  	return err;
07b20889e   Ram Pai   [PATCH] beginning...
1679
1680
1681
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1682
1683
   * do loopback mount.
   */
0a0d8a467   Al Viro   [PATCH] no need f...
1684
  static int do_loopback(struct path *path, char *old_name,
2dafe1c4d   Eric Sandeen   reduce large do_m...
1685
  				int recurse)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1686
  {
b12cea919   Al Viro   change the lockin...
1687
  	LIST_HEAD(umount_list);
2d92ab3c6   Al Viro   [PATCH] finally g...
1688
  	struct path old_path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1689
  	struct vfsmount *mnt = NULL;
2d92ab3c6   Al Viro   [PATCH] finally g...
1690
  	int err = mount_is_safe(path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1691
1692
1693
1694
  	if (err)
  		return err;
  	if (!old_name || !*old_name)
  		return -EINVAL;
815d405ce   Trond Myklebust   VFS: Fix the rema...
1695
  	err = kern_path(old_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1696
1697
  	if (err)
  		return err;
b12cea919   Al Viro   change the lockin...
1698
1699
1700
  	err = lock_mount(path);
  	if (err)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1701
  	err = -EINVAL;
2d92ab3c6   Al Viro   [PATCH] finally g...
1702
  	if (IS_MNT_UNBINDABLE(old_path.mnt))
b12cea919   Al Viro   change the lockin...
1703
  		goto out2;
9676f0c63   Ram Pai   [PATCH] unbindabl...
1704

2d92ab3c6   Al Viro   [PATCH] finally g...
1705
  	if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt))
b12cea919   Al Viro   change the lockin...
1706
  		goto out2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1707

ccd48bc7f   Al Viro   [PATCH] cleanups ...
1708
1709
  	err = -ENOMEM;
  	if (recurse)
2d92ab3c6   Al Viro   [PATCH] finally g...
1710
  		mnt = copy_tree(old_path.mnt, old_path.dentry, 0);
ccd48bc7f   Al Viro   [PATCH] cleanups ...
1711
  	else
2d92ab3c6   Al Viro   [PATCH] finally g...
1712
  		mnt = clone_mnt(old_path.mnt, old_path.dentry, 0);
ccd48bc7f   Al Viro   [PATCH] cleanups ...
1713
1714
  
  	if (!mnt)
b12cea919   Al Viro   change the lockin...
1715
  		goto out2;
ccd48bc7f   Al Viro   [PATCH] cleanups ...
1716

2d92ab3c6   Al Viro   [PATCH] finally g...
1717
  	err = graft_tree(mnt, path);
ccd48bc7f   Al Viro   [PATCH] cleanups ...
1718
  	if (err) {
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1719
  		br_write_lock(vfsmount_lock);
a05964f39   Ram Pai   [PATCH] shared mo...
1720
  		umount_tree(mnt, 0, &umount_list);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1721
  		br_write_unlock(vfsmount_lock);
5b83d2c5c   Ram Pai   [PATCH] sanitize ...
1722
  	}
b12cea919   Al Viro   change the lockin...
1723
1724
1725
  out2:
  	unlock_mount(path);
  	release_mounts(&umount_list);
ccd48bc7f   Al Viro   [PATCH] cleanups ...
1726
  out:
2d92ab3c6   Al Viro   [PATCH] finally g...
1727
  	path_put(&old_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1728
1729
  	return err;
  }
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
  static int change_mount_flags(struct vfsmount *mnt, int ms_flags)
  {
  	int error = 0;
  	int readonly_request = 0;
  
  	if (ms_flags & MS_RDONLY)
  		readonly_request = 1;
  	if (readonly_request == __mnt_is_readonly(mnt))
  		return 0;
  
  	if (readonly_request)
  		error = mnt_make_readonly(mnt);
  	else
  		__mnt_unmake_readonly(mnt);
  	return error;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1746
1747
1748
1749
1750
  /*
   * change filesystem flags. dir should be a physical root of filesystem.
   * If you've mounted a non-root directory somewhere and want to do remount
   * on it - tough luck.
   */
0a0d8a467   Al Viro   [PATCH] no need f...
1751
  static int do_remount(struct path *path, int flags, int mnt_flags,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1752
1753
1754
  		      void *data)
  {
  	int err;
2d92ab3c6   Al Viro   [PATCH] finally g...
1755
  	struct super_block *sb = path->mnt->mnt_sb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1756
1757
1758
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
2d92ab3c6   Al Viro   [PATCH] finally g...
1759
  	if (!check_mnt(path->mnt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1760
  		return -EINVAL;
2d92ab3c6   Al Viro   [PATCH] finally g...
1761
  	if (path->dentry != path->mnt->mnt_root)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1762
  		return -EINVAL;
ff36fe2c8   Eric Paris   LSM: Pass -o remo...
1763
1764
1765
  	err = security_sb_remount(sb, data);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1766
  	down_write(&sb->s_umount);
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
1767
  	if (flags & MS_BIND)
2d92ab3c6   Al Viro   [PATCH] finally g...
1768
  		err = change_mount_flags(path->mnt, flags);
4aa98cf76   Al Viro   Push BKL down int...
1769
  	else
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
1770
  		err = do_remount_sb(sb, flags, data, 0);
7b43a79f3   Al Viro   mnt_flags fixes i...
1771
  	if (!err) {
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1772
  		br_write_lock(vfsmount_lock);
495d6c9c6   Valerie Aurora   VFS: Clean up sha...
1773
  		mnt_flags |= path->mnt->mnt_flags & MNT_PROPAGATION_MASK;
2d92ab3c6   Al Viro   [PATCH] finally g...
1774
  		path->mnt->mnt_flags = mnt_flags;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1775
  		br_write_unlock(vfsmount_lock);
7b43a79f3   Al Viro   mnt_flags fixes i...
1776
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1777
  	up_write(&sb->s_umount);
0e55a7cca   Dan Williams   [RFC PATCH] touch...
1778
  	if (!err) {
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1779
  		br_write_lock(vfsmount_lock);
0e55a7cca   Dan Williams   [RFC PATCH] touch...
1780
  		touch_mnt_namespace(path->mnt->mnt_ns);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1781
  		br_write_unlock(vfsmount_lock);
0e55a7cca   Dan Williams   [RFC PATCH] touch...
1782
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1783
1784
  	return err;
  }
9676f0c63   Ram Pai   [PATCH] unbindabl...
1785
1786
1787
1788
1789
1790
1791
1792
1793
  static inline int tree_contains_unbindable(struct vfsmount *mnt)
  {
  	struct vfsmount *p;
  	for (p = mnt; p; p = next_mnt(p, mnt)) {
  		if (IS_MNT_UNBINDABLE(p))
  			return 1;
  	}
  	return 0;
  }
0a0d8a467   Al Viro   [PATCH] no need f...
1794
  static int do_move_mount(struct path *path, char *old_name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1795
  {
2d92ab3c6   Al Viro   [PATCH] finally g...
1796
  	struct path old_path, parent_path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1797
1798
1799
1800
1801
1802
  	struct vfsmount *p;
  	int err = 0;
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  	if (!old_name || !*old_name)
  		return -EINVAL;
2d92ab3c6   Al Viro   [PATCH] finally g...
1803
  	err = kern_path(old_name, LOOKUP_FOLLOW, &old_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1804
1805
  	if (err)
  		return err;
b12cea919   Al Viro   change the lockin...
1806
  	err = lock_mount(path);
cc53ce53c   David Howells   Add a dentry op t...
1807
1808
  	if (err < 0)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1809
  	err = -EINVAL;
2d92ab3c6   Al Viro   [PATCH] finally g...
1810
  	if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1811
  		goto out1;
f3da392e9   Alexey Dobriyan   dcache: extrace a...
1812
  	if (d_unlinked(path->dentry))
214444032   Ram Pai   [PATCH] shared mo...
1813
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1814
1815
  
  	err = -EINVAL;
2d92ab3c6   Al Viro   [PATCH] finally g...
1816
  	if (old_path.dentry != old_path.mnt->mnt_root)
214444032   Ram Pai   [PATCH] shared mo...
1817
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1818

2d92ab3c6   Al Viro   [PATCH] finally g...
1819
  	if (old_path.mnt == old_path.mnt->mnt_parent)
214444032   Ram Pai   [PATCH] shared mo...
1820
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1821

2d92ab3c6   Al Viro   [PATCH] finally g...
1822
1823
  	if (S_ISDIR(path->dentry->d_inode->i_mode) !=
  	      S_ISDIR(old_path.dentry->d_inode->i_mode))
214444032   Ram Pai   [PATCH] shared mo...
1824
1825
1826
1827
  		goto out1;
  	/*
  	 * Don't move a mount residing in a shared parent.
  	 */
2d92ab3c6   Al Viro   [PATCH] finally g...
1828
1829
  	if (old_path.mnt->mnt_parent &&
  	    IS_MNT_SHARED(old_path.mnt->mnt_parent))
214444032   Ram Pai   [PATCH] shared mo...
1830
  		goto out1;
9676f0c63   Ram Pai   [PATCH] unbindabl...
1831
1832
1833
1834
  	/*
  	 * Don't move a mount tree containing unbindable mounts to a destination
  	 * mount which is shared.
  	 */
2d92ab3c6   Al Viro   [PATCH] finally g...
1835
1836
  	if (IS_MNT_SHARED(path->mnt) &&
  	    tree_contains_unbindable(old_path.mnt))
9676f0c63   Ram Pai   [PATCH] unbindabl...
1837
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1838
  	err = -ELOOP;
2d92ab3c6   Al Viro   [PATCH] finally g...
1839
1840
  	for (p = path->mnt; p->mnt_parent != p; p = p->mnt_parent)
  		if (p == old_path.mnt)
214444032   Ram Pai   [PATCH] shared mo...
1841
  			goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1842

2d92ab3c6   Al Viro   [PATCH] finally g...
1843
  	err = attach_recursive_mnt(old_path.mnt, path, &parent_path);
4ac913785   Jan Blunck   Embed a struct pa...
1844
  	if (err)
214444032   Ram Pai   [PATCH] shared mo...
1845
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1846
1847
1848
  
  	/* if the mount is moved, it should no longer be expire
  	 * automatically */
2d92ab3c6   Al Viro   [PATCH] finally g...
1849
  	list_del_init(&old_path.mnt->mnt_expire);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1850
  out1:
b12cea919   Al Viro   change the lockin...
1851
  	unlock_mount(path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1852
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1853
  	if (!err)
1a3906895   Al Viro   [PATCH] reduce st...
1854
  		path_put(&parent_path);
2d92ab3c6   Al Viro   [PATCH] finally g...
1855
  	path_put(&old_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1856
1857
  	return err;
  }
9d412a43c   Al Viro   vfs: split off vf...
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
  static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype)
  {
  	int err;
  	const char *subtype = strchr(fstype, '.');
  	if (subtype) {
  		subtype++;
  		err = -EINVAL;
  		if (!subtype[0])
  			goto err;
  	} else
  		subtype = "";
  
  	mnt->mnt_sb->s_subtype = kstrdup(subtype, GFP_KERNEL);
  	err = -ENOMEM;
  	if (!mnt->mnt_sb->s_subtype)
  		goto err;
  	return mnt;
  
   err:
  	mntput(mnt);
  	return ERR_PTR(err);
  }
  
  struct vfsmount *
  do_kern_mount(const char *fstype, int flags, const char *name, void *data)
  {
  	struct file_system_type *type = get_fs_type(fstype);
  	struct vfsmount *mnt;
  	if (!type)
  		return ERR_PTR(-ENODEV);
  	mnt = vfs_kern_mount(type, flags, name, data);
  	if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
  	    !mnt->mnt_sb->s_subtype)
  		mnt = fs_set_subtype(mnt, fstype);
  	put_filesystem(type);
  	return mnt;
  }
  EXPORT_SYMBOL_GPL(do_kern_mount);
  
  /*
   * add a mount into a namespace's mount tree
   */
  static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags)
  {
  	int err;
  
  	mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL);
b12cea919   Al Viro   change the lockin...
1905
1906
1907
  	err = lock_mount(path);
  	if (err)
  		return err;
9d412a43c   Al Viro   vfs: split off vf...
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
  
  	err = -EINVAL;
  	if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt))
  		goto unlock;
  
  	/* Refuse the same filesystem on the same mount point */
  	err = -EBUSY;
  	if (path->mnt->mnt_sb == newmnt->mnt_sb &&
  	    path->mnt->mnt_root == path->dentry)
  		goto unlock;
  
  	err = -EINVAL;
  	if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode))
  		goto unlock;
  
  	newmnt->mnt_flags = mnt_flags;
  	err = graft_tree(newmnt, path);
  
  unlock:
b12cea919   Al Viro   change the lockin...
1927
  	unlock_mount(path);
9d412a43c   Al Viro   vfs: split off vf...
1928
1929
  	return err;
  }
b1e75df45   Al Viro   tidy up around fi...
1930

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1931
1932
1933
1934
  /*
   * create a new mount for userspace and request it to be added into the
   * namespace's tree
   */
0a0d8a467   Al Viro   [PATCH] no need f...
1935
  static int do_new_mount(struct path *path, char *type, int flags,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1936
1937
1938
  			int mnt_flags, char *name, void *data)
  {
  	struct vfsmount *mnt;
15f9a3f3e   Al Viro   don't drop newmnt...
1939
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1940

eca6f534e   Vegard Nossum   fs: fix overflow ...
1941
  	if (!type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1942
1943
1944
1945
1946
1947
1948
1949
1950
  		return -EINVAL;
  
  	/* we need capabilities... */
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  
  	mnt = do_kern_mount(type, flags, name, data);
  	if (IS_ERR(mnt))
  		return PTR_ERR(mnt);
15f9a3f3e   Al Viro   don't drop newmnt...
1951
1952
1953
1954
  	err = do_add_mount(mnt, path, mnt_flags);
  	if (err)
  		mntput(mnt);
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1955
  }
19a167af7   Al Viro   Take the completi...
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
  int finish_automount(struct vfsmount *m, struct path *path)
  {
  	int err;
  	/* The new mount record should have at least 2 refs to prevent it being
  	 * expired before we get a chance to add it
  	 */
  	BUG_ON(mnt_get_count(m) < 2);
  
  	if (m->mnt_sb == path->mnt->mnt_sb &&
  	    m->mnt_root == path->dentry) {
b1e75df45   Al Viro   tidy up around fi...
1966
1967
  		err = -ELOOP;
  		goto fail;
19a167af7   Al Viro   Take the completi...
1968
  	}
19a167af7   Al Viro   Take the completi...
1969
  	err = do_add_mount(m, path, path->mnt->mnt_flags | MNT_SHRINKABLE);
b1e75df45   Al Viro   tidy up around fi...
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
  	if (!err)
  		return 0;
  fail:
  	/* remove m from any expiration list it may be on */
  	if (!list_empty(&m->mnt_expire)) {
  		down_write(&namespace_sem);
  		br_write_lock(vfsmount_lock);
  		list_del_init(&m->mnt_expire);
  		br_write_unlock(vfsmount_lock);
  		up_write(&namespace_sem);
19a167af7   Al Viro   Take the completi...
1980
  	}
b1e75df45   Al Viro   tidy up around fi...
1981
1982
  	mntput(m);
  	mntput(m);
19a167af7   Al Viro   Take the completi...
1983
1984
  	return err;
  }
ea5b778a8   David Howells   Unexport do_add_m...
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
  /**
   * mnt_set_expiry - Put a mount on an expiration list
   * @mnt: The mount to list.
   * @expiry_list: The list to add the mount to.
   */
  void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list)
  {
  	down_write(&namespace_sem);
  	br_write_lock(vfsmount_lock);
  
  	list_add_tail(&mnt->mnt_expire, expiry_list);
  
  	br_write_unlock(vfsmount_lock);
  	up_write(&namespace_sem);
  }
  EXPORT_SYMBOL(mnt_set_expiry);
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2003
2004
2005
2006
2007
2008
   * process a list of expirable mountpoints with the intent of discarding any
   * mountpoints that aren't in use and haven't been touched since last we came
   * here
   */
  void mark_mounts_for_expiry(struct list_head *mounts)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2009
2010
  	struct vfsmount *mnt, *next;
  	LIST_HEAD(graveyard);
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
2011
  	LIST_HEAD(umounts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2012
2013
2014
  
  	if (list_empty(mounts))
  		return;
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
2015
  	down_write(&namespace_sem);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2016
  	br_write_lock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2017
2018
2019
2020
2021
2022
2023
  
  	/* extract from the expiration list every vfsmount that matches the
  	 * following criteria:
  	 * - only referenced by its parent vfsmount
  	 * - still marked for expiry (marked on the last call here; marks are
  	 *   cleared by mntput())
  	 */
55e700b92   Miklos Szeredi   [PATCH] namespace...
2024
  	list_for_each_entry_safe(mnt, next, mounts, mnt_expire) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2025
  		if (!xchg(&mnt->mnt_expiry_mark, 1) ||
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
2026
  			propagate_mount_busy(mnt, 1))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2027
  			continue;
55e700b92   Miklos Szeredi   [PATCH] namespace...
2028
  		list_move(&mnt->mnt_expire, &graveyard);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2029
  	}
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
2030
2031
2032
2033
2034
  	while (!list_empty(&graveyard)) {
  		mnt = list_first_entry(&graveyard, struct vfsmount, mnt_expire);
  		touch_mnt_namespace(mnt->mnt_ns);
  		umount_tree(mnt, 1, &umounts);
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2035
  	br_write_unlock(vfsmount_lock);
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
2036
2037
2038
  	up_write(&namespace_sem);
  
  	release_mounts(&umounts);
5528f911b   Trond Myklebust   VFS: Add shrink_s...
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
  }
  
  EXPORT_SYMBOL_GPL(mark_mounts_for_expiry);
  
  /*
   * Ripoff of 'select_parent()'
   *
   * search the list of submounts for a given mountpoint, and move any
   * shrinkable submounts to the 'graveyard' list.
   */
  static int select_submounts(struct vfsmount *parent, struct list_head *graveyard)
  {
  	struct vfsmount *this_parent = parent;
  	struct list_head *next;
  	int found = 0;
  
  repeat:
  	next = this_parent->mnt_mounts.next;
  resume:
  	while (next != &this_parent->mnt_mounts) {
  		struct list_head *tmp = next;
  		struct vfsmount *mnt = list_entry(tmp, struct vfsmount, mnt_child);
  
  		next = tmp->next;
  		if (!(mnt->mnt_flags & MNT_SHRINKABLE))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2064
  			continue;
5528f911b   Trond Myklebust   VFS: Add shrink_s...
2065
2066
2067
2068
2069
2070
2071
  		/*
  		 * Descend a level if the d_mounts list is non-empty.
  		 */
  		if (!list_empty(&mnt->mnt_mounts)) {
  			this_parent = mnt;
  			goto repeat;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2072

5528f911b   Trond Myklebust   VFS: Add shrink_s...
2073
  		if (!propagate_mount_busy(mnt, 1)) {
5528f911b   Trond Myklebust   VFS: Add shrink_s...
2074
2075
2076
  			list_move_tail(&mnt->mnt_expire, graveyard);
  			found++;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2077
  	}
5528f911b   Trond Myklebust   VFS: Add shrink_s...
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
  	/*
  	 * All done at this level ... ascend and resume the search
  	 */
  	if (this_parent != parent) {
  		next = this_parent->mnt_child.next;
  		this_parent = this_parent->mnt_parent;
  		goto resume;
  	}
  	return found;
  }
  
  /*
   * process a list of expirable mountpoints with the intent of discarding any
   * submounts of a specific parent mountpoint
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2092
2093
   *
   * vfsmount_lock must be held for write
5528f911b   Trond Myklebust   VFS: Add shrink_s...
2094
   */
c35038bec   Al Viro   [PATCH] do shrink...
2095
  static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts)
5528f911b   Trond Myklebust   VFS: Add shrink_s...
2096
2097
  {
  	LIST_HEAD(graveyard);
c35038bec   Al Viro   [PATCH] do shrink...
2098
  	struct vfsmount *m;
5528f911b   Trond Myklebust   VFS: Add shrink_s...
2099

5528f911b   Trond Myklebust   VFS: Add shrink_s...
2100
  	/* extract submounts of 'mountpoint' from the expiration list */
c35038bec   Al Viro   [PATCH] do shrink...
2101
  	while (select_submounts(mnt, &graveyard)) {
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
2102
  		while (!list_empty(&graveyard)) {
c35038bec   Al Viro   [PATCH] do shrink...
2103
  			m = list_first_entry(&graveyard, struct vfsmount,
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
2104
  						mnt_expire);
afef80b3d   Eric W. Biederman   vfs: fix shrink_s...
2105
2106
  			touch_mnt_namespace(m->mnt_ns);
  			umount_tree(m, 1, umounts);
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
2107
2108
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2109
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2110
2111
2112
2113
2114
2115
  /*
   * Some copy_from_user() implementations do not return the exact number of
   * bytes remaining to copy on a fault.  But copy_mount_options() requires that.
   * Note that this function differs from copy_from_user() in that it will oops
   * on bad values of `to', rather than returning a short copy.
   */
b58fed8b1   Ram Pai   [PATCH] lindent f...
2116
2117
  static long exact_copy_from_user(void *to, const void __user * from,
  				 unsigned long n)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
  {
  	char *t = to;
  	const char __user *f = from;
  	char c;
  
  	if (!access_ok(VERIFY_READ, from, n))
  		return n;
  
  	while (n) {
  		if (__get_user(c, f)) {
  			memset(t, 0, n);
  			break;
  		}
  		*t++ = c;
  		f++;
  		n--;
  	}
  	return n;
  }
b58fed8b1   Ram Pai   [PATCH] lindent f...
2137
  int copy_mount_options(const void __user * data, unsigned long *where)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2138
2139
2140
2141
  {
  	int i;
  	unsigned long page;
  	unsigned long size;
b58fed8b1   Ram Pai   [PATCH] lindent f...
2142

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
  	*where = 0;
  	if (!data)
  		return 0;
  
  	if (!(page = __get_free_page(GFP_KERNEL)))
  		return -ENOMEM;
  
  	/* We only care that *some* data at the address the user
  	 * gave us is valid.  Just in case, we'll zero
  	 * the remainder of the page.
  	 */
  	/* copy_from_user cannot cross TASK_SIZE ! */
  	size = TASK_SIZE - (unsigned long)data;
  	if (size > PAGE_SIZE)
  		size = PAGE_SIZE;
  
  	i = size - exact_copy_from_user((void *)page, data, size);
  	if (!i) {
b58fed8b1   Ram Pai   [PATCH] lindent f...
2161
  		free_page(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2162
2163
2164
2165
2166
2167
2168
  		return -EFAULT;
  	}
  	if (i != PAGE_SIZE)
  		memset((char *)page + i, 0, PAGE_SIZE - i);
  	*where = page;
  	return 0;
  }
eca6f534e   Vegard Nossum   fs: fix overflow ...
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
  int copy_mount_string(const void __user *data, char **where)
  {
  	char *tmp;
  
  	if (!data) {
  		*where = NULL;
  		return 0;
  	}
  
  	tmp = strndup_user(data, PAGE_SIZE);
  	if (IS_ERR(tmp))
  		return PTR_ERR(tmp);
  
  	*where = tmp;
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
  /*
   * Flags is a 32-bit value that allows up to 31 non-fs dependent flags to
   * be given to the mount() call (ie: read-only, no-dev, no-suid etc).
   *
   * data is a (void *) that can point to any structure up to
   * PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent
   * information (or be NULL).
   *
   * Pre-0.97 versions of mount() didn't have a flags word.
   * When the flags word was introduced its top half was required
   * to have the magic value 0xC0ED, and this remained so until 2.4.0-test9.
   * Therefore, if this magic number is present, it carries no information
   * and must be discarded.
   */
b58fed8b1   Ram Pai   [PATCH] lindent f...
2199
  long do_mount(char *dev_name, char *dir_name, char *type_page,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2200
2201
  		  unsigned long flags, void *data_page)
  {
2d92ab3c6   Al Viro   [PATCH] finally g...
2202
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
  	int retval = 0;
  	int mnt_flags = 0;
  
  	/* Discard magic */
  	if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
  		flags &= ~MS_MGC_MSK;
  
  	/* Basic sanity checks */
  
  	if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE))
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2214
2215
2216
  
  	if (data_page)
  		((char *)data_page)[PAGE_SIZE - 1] = 0;
a27ab9f26   Tetsuo Handa   LSM: Pass origina...
2217
2218
2219
2220
2221
2222
2223
2224
2225
  	/* ... and get the mountpoint */
  	retval = kern_path(dir_name, LOOKUP_FOLLOW, &path);
  	if (retval)
  		return retval;
  
  	retval = security_sb_mount(dev_name, &path,
  				   type_page, flags, data_page);
  	if (retval)
  		goto dput_out;
613cbe3d4   Andi Kleen   Don't set relatim...
2226
2227
2228
  	/* Default to relatime unless overriden */
  	if (!(flags & MS_NOATIME))
  		mnt_flags |= MNT_RELATIME;
0a1c01c94   Matthew Garrett   Make relatime def...
2229

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2230
2231
2232
2233
2234
2235
2236
  	/* Separate the per-mountpoint flags */
  	if (flags & MS_NOSUID)
  		mnt_flags |= MNT_NOSUID;
  	if (flags & MS_NODEV)
  		mnt_flags |= MNT_NODEV;
  	if (flags & MS_NOEXEC)
  		mnt_flags |= MNT_NOEXEC;
fc33a7bb9   Christoph Hellwig   [PATCH] per-mount...
2237
2238
2239
2240
  	if (flags & MS_NOATIME)
  		mnt_flags |= MNT_NOATIME;
  	if (flags & MS_NODIRATIME)
  		mnt_flags |= MNT_NODIRATIME;
d0adde574   Matthew Garrett   Add a strictatime...
2241
2242
  	if (flags & MS_STRICTATIME)
  		mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME);
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
2243
2244
  	if (flags & MS_RDONLY)
  		mnt_flags |= MNT_READONLY;
fc33a7bb9   Christoph Hellwig   [PATCH] per-mount...
2245

7a4dec538   Al Viro   Fix sget() race w...
2246
  	flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN |
d0adde574   Matthew Garrett   Add a strictatime...
2247
2248
  		   MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT |
  		   MS_STRICTATIME);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2249

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2250
  	if (flags & MS_REMOUNT)
2d92ab3c6   Al Viro   [PATCH] finally g...
2251
  		retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2252
2253
  				    data_page);
  	else if (flags & MS_BIND)
2d92ab3c6   Al Viro   [PATCH] finally g...
2254
  		retval = do_loopback(&path, dev_name, flags & MS_REC);
9676f0c63   Ram Pai   [PATCH] unbindabl...
2255
  	else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
2d92ab3c6   Al Viro   [PATCH] finally g...
2256
  		retval = do_change_type(&path, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2257
  	else if (flags & MS_MOVE)
2d92ab3c6   Al Viro   [PATCH] finally g...
2258
  		retval = do_move_mount(&path, dev_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2259
  	else
2d92ab3c6   Al Viro   [PATCH] finally g...
2260
  		retval = do_new_mount(&path, type_page, flags, mnt_flags,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2261
2262
  				      dev_name, data_page);
  dput_out:
2d92ab3c6   Al Viro   [PATCH] finally g...
2263
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2264
2265
  	return retval;
  }
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
  static struct mnt_namespace *alloc_mnt_ns(void)
  {
  	struct mnt_namespace *new_ns;
  
  	new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL);
  	if (!new_ns)
  		return ERR_PTR(-ENOMEM);
  	atomic_set(&new_ns->count, 1);
  	new_ns->root = NULL;
  	INIT_LIST_HEAD(&new_ns->list);
  	init_waitqueue_head(&new_ns->poll);
  	new_ns->event = 0;
  	return new_ns;
  }
f03c65993   Al Viro   sanitize vfsmount...
2280
2281
  void mnt_make_longterm(struct vfsmount *mnt)
  {
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
2282
  	__mnt_make_longterm(mnt);
f03c65993   Al Viro   sanitize vfsmount...
2283
2284
2285
2286
  }
  
  void mnt_make_shortterm(struct vfsmount *mnt)
  {
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
2287
  #ifdef CONFIG_SMP
f03c65993   Al Viro   sanitize vfsmount...
2288
2289
2290
2291
2292
  	if (atomic_add_unless(&mnt->mnt_longterm, -1, 1))
  		return;
  	br_write_lock(vfsmount_lock);
  	atomic_dec(&mnt->mnt_longterm);
  	br_write_unlock(vfsmount_lock);
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
2293
  #endif
f03c65993   Al Viro   sanitize vfsmount...
2294
  }
741a29513   JANAK DESAI   [PATCH] unshare s...
2295
2296
2297
2298
  /*
   * Allocate a new namespace structure and populate it with contents
   * copied from the namespace of the passed in task structure.
   */
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
2299
  static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2300
  		struct fs_struct *fs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2301
  {
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2302
  	struct mnt_namespace *new_ns;
7f2da1e7d   Al Viro   [PATCH] kill altroot
2303
  	struct vfsmount *rootmnt = NULL, *pwdmnt = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2304
  	struct vfsmount *p, *q;
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2305
2306
2307
  	new_ns = alloc_mnt_ns();
  	if (IS_ERR(new_ns))
  		return new_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2308

390c68436   Ram Pai   [PATCH] making na...
2309
  	down_write(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2310
  	/* First pass: copy the tree topology */
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2311
  	new_ns->root = copy_tree(mnt_ns->root, mnt_ns->root->mnt_root,
9676f0c63   Ram Pai   [PATCH] unbindabl...
2312
  					CL_COPY_ALL | CL_EXPIRE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2313
  	if (!new_ns->root) {
390c68436   Ram Pai   [PATCH] making na...
2314
  		up_write(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2315
  		kfree(new_ns);
5cc4a0341   Julia Lawall   fs/namespace.c: d...
2316
  		return ERR_PTR(-ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2317
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2318
  	br_write_lock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2319
  	list_add_tail(&new_ns->list, &new_ns->root->mnt_list);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2320
  	br_write_unlock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2321
2322
2323
2324
2325
2326
  
  	/*
  	 * Second pass: switch the tsk->fs->* elements and mark new vfsmounts
  	 * as belonging to new namespace.  We have already acquired a private
  	 * fs_struct, so tsk->fs->lock is not needed.
  	 */
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2327
  	p = mnt_ns->root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2328
2329
  	q = new_ns->root;
  	while (p) {
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2330
  		q->mnt_ns = new_ns;
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
2331
  		__mnt_make_longterm(q);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2332
  		if (fs) {
6ac08c39a   Jan Blunck   Use struct path i...
2333
  			if (p == fs->root.mnt) {
f03c65993   Al Viro   sanitize vfsmount...
2334
  				fs->root.mnt = mntget(q);
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
2335
  				__mnt_make_longterm(q);
f03c65993   Al Viro   sanitize vfsmount...
2336
  				mnt_make_shortterm(p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2337
  				rootmnt = p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2338
  			}
6ac08c39a   Jan Blunck   Use struct path i...
2339
  			if (p == fs->pwd.mnt) {
f03c65993   Al Viro   sanitize vfsmount...
2340
  				fs->pwd.mnt = mntget(q);
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
2341
  				__mnt_make_longterm(q);
f03c65993   Al Viro   sanitize vfsmount...
2342
  				mnt_make_shortterm(p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2343
  				pwdmnt = p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2344
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2345
  		}
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2346
  		p = next_mnt(p, mnt_ns->root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2347
2348
  		q = next_mnt(q, new_ns->root);
  	}
390c68436   Ram Pai   [PATCH] making na...
2349
  	up_write(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2350

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2351
  	if (rootmnt)
f03c65993   Al Viro   sanitize vfsmount...
2352
  		mntput(rootmnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2353
  	if (pwdmnt)
f03c65993   Al Viro   sanitize vfsmount...
2354
  		mntput(pwdmnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2355

741a29513   JANAK DESAI   [PATCH] unshare s...
2356
2357
  	return new_ns;
  }
213dd266d   Eric W. Biederman   namespace: ensure...
2358
  struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
2359
  		struct fs_struct *new_fs)
741a29513   JANAK DESAI   [PATCH] unshare s...
2360
  {
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2361
  	struct mnt_namespace *new_ns;
741a29513   JANAK DESAI   [PATCH] unshare s...
2362

e3222c4ec   Badari Pulavarty   Merge sys_clone()...
2363
  	BUG_ON(!ns);
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2364
  	get_mnt_ns(ns);
741a29513   JANAK DESAI   [PATCH] unshare s...
2365
2366
  
  	if (!(flags & CLONE_NEWNS))
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
2367
  		return ns;
741a29513   JANAK DESAI   [PATCH] unshare s...
2368

e3222c4ec   Badari Pulavarty   Merge sys_clone()...
2369
  	new_ns = dup_mnt_ns(ns, new_fs);
741a29513   JANAK DESAI   [PATCH] unshare s...
2370

6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2371
  	put_mnt_ns(ns);
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
2372
  	return new_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2373
  }
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2374
2375
2376
2377
  /**
   * create_mnt_ns - creates a private namespace and adds a root filesystem
   * @mnt: pointer to the new root filesystem mountpoint
   */
a2770d86b   Linus Torvalds   Revert "fix misme...
2378
  struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt)
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2379
2380
2381
2382
2383
2384
  {
  	struct mnt_namespace *new_ns;
  
  	new_ns = alloc_mnt_ns();
  	if (!IS_ERR(new_ns)) {
  		mnt->mnt_ns = new_ns;
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
2385
  		__mnt_make_longterm(mnt);
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2386
2387
2388
2389
2390
  		new_ns->root = mnt;
  		list_add(&new_ns->list, &new_ns->root->mnt_list);
  	}
  	return new_ns;
  }
a2770d86b   Linus Torvalds   Revert "fix misme...
2391
  EXPORT_SYMBOL(create_mnt_ns);
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2392

bdc480e3b   Heiko Carstens   [CVE-2009-0029] S...
2393
2394
  SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
  		char __user *, type, unsigned long, flags, void __user *, data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2395
  {
eca6f534e   Vegard Nossum   fs: fix overflow ...
2396
2397
2398
2399
  	int ret;
  	char *kernel_type;
  	char *kernel_dir;
  	char *kernel_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2400
  	unsigned long data_page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2401

eca6f534e   Vegard Nossum   fs: fix overflow ...
2402
2403
2404
  	ret = copy_mount_string(type, &kernel_type);
  	if (ret < 0)
  		goto out_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2405

eca6f534e   Vegard Nossum   fs: fix overflow ...
2406
2407
2408
2409
2410
  	kernel_dir = getname(dir_name);
  	if (IS_ERR(kernel_dir)) {
  		ret = PTR_ERR(kernel_dir);
  		goto out_dir;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2411

eca6f534e   Vegard Nossum   fs: fix overflow ...
2412
2413
2414
  	ret = copy_mount_string(dev_name, &kernel_dev);
  	if (ret < 0)
  		goto out_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2415

eca6f534e   Vegard Nossum   fs: fix overflow ...
2416
2417
2418
  	ret = copy_mount_options(data, &data_page);
  	if (ret < 0)
  		goto out_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2419

eca6f534e   Vegard Nossum   fs: fix overflow ...
2420
2421
  	ret = do_mount(kernel_dev, kernel_dir, kernel_type, flags,
  		(void *) data_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2422

eca6f534e   Vegard Nossum   fs: fix overflow ...
2423
2424
2425
2426
2427
2428
2429
2430
2431
  	free_page(data_page);
  out_data:
  	kfree(kernel_dev);
  out_dev:
  	putname(kernel_dir);
  out_dir:
  	kfree(kernel_type);
  out_type:
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2432
2433
2434
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
   * pivot_root Semantics:
   * Moves the root file system of the current process to the directory put_old,
   * makes new_root as the new root file system of the current process, and sets
   * root/cwd of all processes which had them on the current root to new_root.
   *
   * Restrictions:
   * The new_root and put_old must be directories, and  must not be on the
   * same file  system as the current process root. The put_old  must  be
   * underneath new_root,  i.e. adding a non-zero number of /.. to the string
   * pointed to by put_old must yield the same directory as new_root. No other
   * file system may be mounted on put_old. After all, new_root is a mountpoint.
   *
4a0d11fae   Neil Brown   [PATCH] pivot_roo...
2447
2448
2449
2450
   * Also, the current root cannot be on the 'rootfs' (initial ramfs) filesystem.
   * See Documentation/filesystems/ramfs-rootfs-initramfs.txt for alternatives
   * in this situation.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2451
2452
2453
2454
2455
2456
2457
2458
   * Notes:
   *  - we don't move root/cwd if they are not at the root (reason: if something
   *    cared enough to change them, it's probably wrong to force them elsewhere)
   *  - it's okay to pick a root that isn't the root of a file system, e.g.
   *    /nfs/my_root where /nfs is the mount point. It must be a mountpoint,
   *    though, so you may need to say mount --bind /nfs/my_root /nfs/my_root
   *    first.
   */
3480b2574   Heiko Carstens   [CVE-2009-0029] S...
2459
2460
  SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
  		const char __user *, put_old)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2461
2462
  {
  	struct vfsmount *tmp;
2d8f30380   Al Viro   [PATCH] sanitize ...
2463
  	struct path new, old, parent_path, root_parent, root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2464
2465
2466
2467
  	int error;
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
2d8f30380   Al Viro   [PATCH] sanitize ...
2468
  	error = user_path_dir(new_root, &new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2469
2470
  	if (error)
  		goto out0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2471

2d8f30380   Al Viro   [PATCH] sanitize ...
2472
  	error = user_path_dir(put_old, &old);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2473
2474
  	if (error)
  		goto out1;
2d8f30380   Al Viro   [PATCH] sanitize ...
2475
  	error = security_sb_pivotroot(&old, &new);
b12cea919   Al Viro   change the lockin...
2476
2477
  	if (error)
  		goto out2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2478

f7ad3c6be   Miklos Szeredi   vfs: add helpers ...
2479
  	get_fs_root(current->fs, &root);
b12cea919   Al Viro   change the lockin...
2480
2481
2482
  	error = lock_mount(&old);
  	if (error)
  		goto out3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2483
  	error = -EINVAL;
2d8f30380   Al Viro   [PATCH] sanitize ...
2484
2485
  	if (IS_MNT_SHARED(old.mnt) ||
  		IS_MNT_SHARED(new.mnt->mnt_parent) ||
8c3ee42e8   Al Viro   [PATCH] get rid o...
2486
  		IS_MNT_SHARED(root.mnt->mnt_parent))
b12cea919   Al Viro   change the lockin...
2487
  		goto out4;
27cb1572e   Al Viro   fix deadlock in p...
2488
  	if (!check_mnt(root.mnt) || !check_mnt(new.mnt))
b12cea919   Al Viro   change the lockin...
2489
  		goto out4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2490
  	error = -ENOENT;
f3da392e9   Alexey Dobriyan   dcache: extrace a...
2491
  	if (d_unlinked(new.dentry))
b12cea919   Al Viro   change the lockin...
2492
  		goto out4;
f3da392e9   Alexey Dobriyan   dcache: extrace a...
2493
  	if (d_unlinked(old.dentry))
b12cea919   Al Viro   change the lockin...
2494
  		goto out4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2495
  	error = -EBUSY;
2d8f30380   Al Viro   [PATCH] sanitize ...
2496
2497
  	if (new.mnt == root.mnt ||
  	    old.mnt == root.mnt)
b12cea919   Al Viro   change the lockin...
2498
  		goto out4; /* loop, on the same file system  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2499
  	error = -EINVAL;
8c3ee42e8   Al Viro   [PATCH] get rid o...
2500
  	if (root.mnt->mnt_root != root.dentry)
b12cea919   Al Viro   change the lockin...
2501
  		goto out4; /* not a mountpoint */
8c3ee42e8   Al Viro   [PATCH] get rid o...
2502
  	if (root.mnt->mnt_parent == root.mnt)
b12cea919   Al Viro   change the lockin...
2503
  		goto out4; /* not attached */
2d8f30380   Al Viro   [PATCH] sanitize ...
2504
  	if (new.mnt->mnt_root != new.dentry)
b12cea919   Al Viro   change the lockin...
2505
  		goto out4; /* not a mountpoint */
2d8f30380   Al Viro   [PATCH] sanitize ...
2506
  	if (new.mnt->mnt_parent == new.mnt)
b12cea919   Al Viro   change the lockin...
2507
  		goto out4; /* not attached */
4ac913785   Jan Blunck   Embed a struct pa...
2508
  	/* make sure we can reach put_old from new_root */
2d8f30380   Al Viro   [PATCH] sanitize ...
2509
  	tmp = old.mnt;
2d8f30380   Al Viro   [PATCH] sanitize ...
2510
  	if (tmp != new.mnt) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2511
2512
  		for (;;) {
  			if (tmp->mnt_parent == tmp)
b12cea919   Al Viro   change the lockin...
2513
  				goto out4; /* already mounted on put_old */
2d8f30380   Al Viro   [PATCH] sanitize ...
2514
  			if (tmp->mnt_parent == new.mnt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2515
2516
2517
  				break;
  			tmp = tmp->mnt_parent;
  		}
2d8f30380   Al Viro   [PATCH] sanitize ...
2518
  		if (!is_subdir(tmp->mnt_mountpoint, new.dentry))
b12cea919   Al Viro   change the lockin...
2519
  			goto out4;
2d8f30380   Al Viro   [PATCH] sanitize ...
2520
  	} else if (!is_subdir(old.dentry, new.dentry))
b12cea919   Al Viro   change the lockin...
2521
  		goto out4;
27cb1572e   Al Viro   fix deadlock in p...
2522
  	br_write_lock(vfsmount_lock);
2d8f30380   Al Viro   [PATCH] sanitize ...
2523
  	detach_mnt(new.mnt, &parent_path);
8c3ee42e8   Al Viro   [PATCH] get rid o...
2524
  	detach_mnt(root.mnt, &root_parent);
4ac913785   Jan Blunck   Embed a struct pa...
2525
  	/* mount old root on put_old */
2d8f30380   Al Viro   [PATCH] sanitize ...
2526
  	attach_mnt(root.mnt, &old);
4ac913785   Jan Blunck   Embed a struct pa...
2527
  	/* mount new_root on / */
2d8f30380   Al Viro   [PATCH] sanitize ...
2528
  	attach_mnt(new.mnt, &root_parent);
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2529
  	touch_mnt_namespace(current->nsproxy->mnt_ns);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2530
  	br_write_unlock(vfsmount_lock);
2d8f30380   Al Viro   [PATCH] sanitize ...
2531
  	chroot_fs_refs(&root, &new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2532
  	error = 0;
b12cea919   Al Viro   change the lockin...
2533
2534
2535
2536
2537
2538
2539
  out4:
  	unlock_mount(&old);
  	if (!error) {
  		path_put(&root_parent);
  		path_put(&parent_path);
  	}
  out3:
8c3ee42e8   Al Viro   [PATCH] get rid o...
2540
  	path_put(&root);
b12cea919   Al Viro   change the lockin...
2541
  out2:
2d8f30380   Al Viro   [PATCH] sanitize ...
2542
  	path_put(&old);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2543
  out1:
2d8f30380   Al Viro   [PATCH] sanitize ...
2544
  	path_put(&new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2545
  out0:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2546
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2547
2548
2549
2550
2551
  }
  
  static void __init init_mount_tree(void)
  {
  	struct vfsmount *mnt;
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2552
  	struct mnt_namespace *ns;
ac748a09f   Jan Blunck   Make set_fs_{root...
2553
  	struct path root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2554
2555
2556
2557
  
  	mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
  	if (IS_ERR(mnt))
  		panic("Can't create rootfs");
b3e19d924   Nick Piggin   fs: scale mntget/...
2558

3b22edc57   Trond Myklebust   VFS: Switch init_...
2559
2560
  	ns = create_mnt_ns(mnt);
  	if (IS_ERR(ns))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2561
  		panic("Can't allocate initial namespace");
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2562
2563
2564
  
  	init_task.nsproxy->mnt_ns = ns;
  	get_mnt_ns(ns);
ac748a09f   Jan Blunck   Make set_fs_{root...
2565
2566
2567
2568
2569
  	root.mnt = ns->root;
  	root.dentry = ns->root->mnt_root;
  
  	set_fs_pwd(current->fs, &root);
  	set_fs_root(current->fs, &root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2570
  }
74bf17cff   Denis Cheng   fs: remove the un...
2571
  void __init mnt_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2572
  {
13f14b4d8   Eric Dumazet   Use ilog2() in fs...
2573
  	unsigned u;
15a67dd8c   Randy Dunlap   [PATCH] fs/namesp...
2574
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2575

390c68436   Ram Pai   [PATCH] making na...
2576
  	init_rwsem(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2577
  	mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct vfsmount),
20c2df83d   Paul Mundt   mm: Remove slab d...
2578
  			0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2579

b58fed8b1   Ram Pai   [PATCH] lindent f...
2580
  	mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2581
2582
2583
2584
  
  	if (!mount_hashtable)
  		panic("Failed to allocate mount hash table
  ");
80cdc6dae   Mandeep Singh Baines   fs: use appropria...
2585
2586
  	printk(KERN_INFO "Mount-cache hash table entries: %lu
  ", HASH_SIZE);
13f14b4d8   Eric Dumazet   Use ilog2() in fs...
2587
2588
2589
  
  	for (u = 0; u < HASH_SIZE; u++)
  		INIT_LIST_HEAD(&mount_hashtable[u]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2590

99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2591
  	br_lock_init(vfsmount_lock);
15a67dd8c   Randy Dunlap   [PATCH] fs/namesp...
2592
2593
2594
2595
  	err = sysfs_init();
  	if (err)
  		printk(KERN_WARNING "%s: sysfs_init error: %d
  ",
8e24eea72   Harvey Harrison   fs: replace remai...
2596
  			__func__, err);
00d266662   Greg Kroah-Hartman   kobject: convert ...
2597
2598
  	fs_kobj = kobject_create_and_add("fs", NULL);
  	if (!fs_kobj)
8e24eea72   Harvey Harrison   fs: replace remai...
2599
2600
  		printk(KERN_WARNING "%s: kobj create error
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2601
2602
2603
  	init_rootfs();
  	init_mount_tree();
  }
616511d03   Trond Myklebust   VFS: Uninline the...
2604
  void put_mnt_ns(struct mnt_namespace *ns)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2605
  {
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
2606
  	LIST_HEAD(umount_list);
616511d03   Trond Myklebust   VFS: Uninline the...
2607

d498b25a4   Al Viro   get rid of useles...
2608
  	if (!atomic_dec_and_test(&ns->count))
616511d03   Trond Myklebust   VFS: Uninline the...
2609
  		return;
390c68436   Ram Pai   [PATCH] making na...
2610
  	down_write(&namespace_sem);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2611
  	br_write_lock(vfsmount_lock);
d498b25a4   Al Viro   get rid of useles...
2612
  	umount_tree(ns->root, 0, &umount_list);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2613
  	br_write_unlock(vfsmount_lock);
390c68436   Ram Pai   [PATCH] making na...
2614
  	up_write(&namespace_sem);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
2615
  	release_mounts(&umount_list);
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2616
  	kfree(ns);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2617
  }
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2618
  EXPORT_SYMBOL(put_mnt_ns);
9d412a43c   Al Viro   vfs: split off vf...
2619
2620
2621
  
  struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
  {
423e0ab08   Tim Chen   VFS : mount lock ...
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
  	struct vfsmount *mnt;
  	mnt = vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);
  	if (!IS_ERR(mnt)) {
  		/*
  		 * it is a longterm mount, don't release mnt until
  		 * we unmount before file sys is unregistered
  		*/
  		mnt_make_longterm(mnt);
  	}
  	return mnt;
9d412a43c   Al Viro   vfs: split off vf...
2632
2633
  }
  EXPORT_SYMBOL_GPL(kern_mount_data);
423e0ab08   Tim Chen   VFS : mount lock ...
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
  
  void kern_unmount(struct vfsmount *mnt)
  {
  	/* release long term mount so mount point can be released */
  	if (!IS_ERR_OR_NULL(mnt)) {
  		mnt_make_shortterm(mnt);
  		mntput(mnt);
  	}
  }
  EXPORT_SYMBOL(kern_unmount);