Blame view

fs/namespace.c 57.2 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
13
14
  #include <linux/syscalls.h>
  #include <linux/slab.h>
  #include <linux/sched.h>
  #include <linux/smp_lock.h>
  #include <linux/init.h>
15a67dd8c   Randy Dunlap   [PATCH] fs/namesp...
15
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
  #include <linux/acct.h>
16f7e0fe2   Randy Dunlap   [PATCH] capable/c...
17
  #include <linux/capability.h>
3d733633a   Dave Hansen   [PATCH] r/o bind ...
18
  #include <linux/cpumask.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
  #include <linux/module.h>
f20a9ead0   Andrew Morton   sysfs: add proper...
20
  #include <linux/sysfs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
  #include <linux/seq_file.h>
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
22
  #include <linux/mnt_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
  #include <linux/namei.h>
b43f3cbd2   Alexey Dobriyan   headers: mnt_name...
24
  #include <linux/nsproxy.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
  #include <linux/security.h>
  #include <linux/mount.h>
07f3f05c1   David Howells   [PATCH] BLOCK: Mo...
27
  #include <linux/ramfs.h>
13f14b4d8   Eric Dumazet   Use ilog2() in fs...
28
  #include <linux/log2.h>
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
29
  #include <linux/idr.h>
5ad4e53bd   Al Viro   Get rid of indire...
30
  #include <linux/fs_struct.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
  #include <asm/uaccess.h>
  #include <asm/unistd.h>
07b20889e   Ram Pai   [PATCH] beginning...
33
  #include "pnode.h"
948730b0e   Adrian Bunk   fs/namespace.c sh...
34
  #include "internal.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35

13f14b4d8   Eric Dumazet   Use ilog2() in fs...
36
37
  #define HASH_SHIFT ilog2(PAGE_SIZE / sizeof(struct list_head))
  #define HASH_SIZE (1UL << HASH_SHIFT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
  /* spinlock for vfsmount related operations, inplace of dcache_lock */
5addc5dd8   Al Viro   [PATCH] make /pro...
39
40
41
  __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock);
  
  static int event;
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
42
  static DEFINE_IDA(mnt_id_ida);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
43
  static DEFINE_IDA(mnt_group_ida);
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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
  static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
  {
b58fed8b1   Ram Pai   [PATCH] lindent f...
57
58
  	unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES);
  	tmp += ((unsigned long)dentry / L1_CACHE_BYTES);
13f14b4d8   Eric Dumazet   Use ilog2() in fs...
59
60
  	tmp = tmp + (tmp >> HASH_SHIFT);
  	return tmp & (HASH_SIZE - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
  }
3d733633a   Dave Hansen   [PATCH] r/o bind ...
62
  #define MNT_WRITER_UNDERFLOW_LIMIT -(1<<16)
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
63
64
65
66
67
68
69
70
  /* allocation is serialized by namespace_sem */
  static int mnt_alloc_id(struct vfsmount *mnt)
  {
  	int res;
  
  retry:
  	ida_pre_get(&mnt_id_ida, GFP_KERNEL);
  	spin_lock(&vfsmount_lock);
f21f62208   Al Viro   ... and the same ...
71
72
73
  	res = ida_get_new_above(&mnt_id_ida, mnt_id_start, &mnt->mnt_id);
  	if (!res)
  		mnt_id_start = mnt->mnt_id + 1;
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
74
75
76
77
78
79
80
81
82
  	spin_unlock(&vfsmount_lock);
  	if (res == -EAGAIN)
  		goto retry;
  
  	return res;
  }
  
  static void mnt_free_id(struct vfsmount *mnt)
  {
f21f62208   Al Viro   ... and the same ...
83
  	int id = mnt->mnt_id;
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
84
  	spin_lock(&vfsmount_lock);
f21f62208   Al Viro   ... and the same ...
85
86
87
  	ida_remove(&mnt_id_ida, id);
  	if (mnt_id_start > id)
  		mnt_id_start = id;
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
88
89
  	spin_unlock(&vfsmount_lock);
  }
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
90
91
92
93
94
95
96
  /*
   * 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 ...
97
  	int res;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
98
99
  	if (!ida_pre_get(&mnt_group_ida, GFP_KERNEL))
  		return -ENOMEM;
f21f62208   Al Viro   ... and the same ...
100
101
102
103
104
105
106
  	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: ...
107
108
109
110
111
112
113
  }
  
  /*
   * Release a peer group ID
   */
  void mnt_release_group_id(struct vfsmount *mnt)
  {
f21f62208   Al Viro   ... and the same ...
114
115
116
117
  	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: ...
118
119
  	mnt->mnt_group_id = 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
121
  struct vfsmount *alloc_vfsmnt(const char *name)
  {
c37622296   Robert P. J. Day   [PATCH] Transform...
122
  	struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
  	if (mnt) {
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
124
125
126
  		int err;
  
  		err = mnt_alloc_id(mnt);
88b387824   Li Zefan   [PATCH] vfs: use ...
127
128
129
130
131
132
133
  		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: ...
134
  		}
b58fed8b1   Ram Pai   [PATCH] lindent f...
135
  		atomic_set(&mnt->mnt_count, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
138
139
  		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...
140
  		INIT_LIST_HEAD(&mnt->mnt_expire);
03e06e68f   Ram Pai   [PATCH] introduce...
141
  		INIT_LIST_HEAD(&mnt->mnt_share);
a58b0eb8e   Ram Pai   [PATCH] introduce...
142
143
  		INIT_LIST_HEAD(&mnt->mnt_slave_list);
  		INIT_LIST_HEAD(&mnt->mnt_slave);
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
144
145
146
147
148
149
150
  #ifdef CONFIG_SMP
  		mnt->mnt_writers = alloc_percpu(int);
  		if (!mnt->mnt_writers)
  			goto out_free_devname;
  #else
  		mnt->mnt_writers = 0;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
  	}
  	return mnt;
88b387824   Li Zefan   [PATCH] vfs: use ...
153

d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
154
155
156
157
  #ifdef CONFIG_SMP
  out_free_devname:
  	kfree(mnt->mnt_devname);
  #endif
88b387824   Li Zefan   [PATCH] vfs: use ...
158
159
160
161
162
  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
163
  }
8366025eb   Dave Hansen   [PATCH] r/o bind ...
164
165
166
167
168
169
170
171
  /*
   * 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 ...
172
173
174
175
176
177
178
179
180
181
182
183
184
  /*
   * __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 ...
185
186
187
188
189
  	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 ...
190
191
  }
  EXPORT_SYMBOL_GPL(__mnt_is_readonly);
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
192
193
194
195
196
197
198
199
  static inline void inc_mnt_writers(struct vfsmount *mnt)
  {
  #ifdef CONFIG_SMP
  	(*per_cpu_ptr(mnt->mnt_writers, smp_processor_id()))++;
  #else
  	mnt->mnt_writers++;
  #endif
  }
3d733633a   Dave Hansen   [PATCH] r/o bind ...
200

d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
201
  static inline void dec_mnt_writers(struct vfsmount *mnt)
3d733633a   Dave Hansen   [PATCH] r/o bind ...
202
  {
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
203
204
205
206
207
  #ifdef CONFIG_SMP
  	(*per_cpu_ptr(mnt->mnt_writers, smp_processor_id()))--;
  #else
  	mnt->mnt_writers--;
  #endif
3d733633a   Dave Hansen   [PATCH] r/o bind ...
208
  }
3d733633a   Dave Hansen   [PATCH] r/o bind ...
209

d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
210
  static unsigned int count_mnt_writers(struct vfsmount *mnt)
3d733633a   Dave Hansen   [PATCH] r/o bind ...
211
  {
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
212
213
  #ifdef CONFIG_SMP
  	unsigned int count = 0;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
214
  	int cpu;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
215
216
  
  	for_each_possible_cpu(cpu) {
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
217
  		count += *per_cpu_ptr(mnt->mnt_writers, cpu);
3d733633a   Dave Hansen   [PATCH] r/o bind ...
218
  	}
3d733633a   Dave Hansen   [PATCH] r/o bind ...
219

d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
220
221
222
223
  	return count;
  #else
  	return mnt->mnt_writers;
  #endif
3d733633a   Dave Hansen   [PATCH] r/o bind ...
224
225
226
227
228
229
230
231
232
233
  }
  
  /*
   * 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 ...
234
235
236
237
238
239
240
241
242
243
244
245
  /**
   * 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 ...
246
  	int ret = 0;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
247

d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
  	preempt_disable();
  	inc_mnt_writers(mnt);
  	/*
  	 * The store to inc_mnt_writers must be visible before we pass
  	 * 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 ...
264
  	if (__mnt_is_readonly(mnt)) {
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
265
  		dec_mnt_writers(mnt);
3d733633a   Dave Hansen   [PATCH] r/o bind ...
266
267
268
  		ret = -EROFS;
  		goto out;
  	}
3d733633a   Dave Hansen   [PATCH] r/o bind ...
269
  out:
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
270
  	preempt_enable();
3d733633a   Dave Hansen   [PATCH] r/o bind ...
271
  	return ret;
8366025eb   Dave Hansen   [PATCH] r/o bind ...
272
273
274
275
  }
  EXPORT_SYMBOL_GPL(mnt_want_write);
  
  /**
96029c4e0   npiggin@suse.de   fs: introduce mnt...
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
   * 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();
  	inc_mnt_writers(mnt);
  	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...
308
309
  	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...
310
311
312
313
314
315
316
  		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 ...
317
318
319
320
321
322
323
324
325
   * 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...
326
327
328
  	preempt_disable();
  	dec_mnt_writers(mnt);
  	preempt_enable();
8366025eb   Dave Hansen   [PATCH] r/o bind ...
329
330
  }
  EXPORT_SYMBOL_GPL(mnt_drop_write);
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
331
  static int mnt_make_readonly(struct vfsmount *mnt)
8366025eb   Dave Hansen   [PATCH] r/o bind ...
332
  {
3d733633a   Dave Hansen   [PATCH] r/o bind ...
333
  	int ret = 0;
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
334
335
  	spin_lock(&vfsmount_lock);
  	mnt->mnt_flags |= MNT_WRITE_HOLD;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
336
  	/*
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
337
338
  	 * 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 ...
339
  	 */
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
340
  	smp_mb();
3d733633a   Dave Hansen   [PATCH] r/o bind ...
341
  	/*
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
342
343
344
345
346
347
348
349
350
351
352
353
354
355
  	 * 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 ...
356
  	 */
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
357
358
359
  	if (count_mnt_writers(mnt) > 0)
  		ret = -EBUSY;
  	else
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
360
  		mnt->mnt_flags |= MNT_READONLY;
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
361
362
363
364
365
366
  	/*
  	 * 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;
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
367
  	spin_unlock(&vfsmount_lock);
3d733633a   Dave Hansen   [PATCH] r/o bind ...
368
  	return ret;
8366025eb   Dave Hansen   [PATCH] r/o bind ...
369
  }
8366025eb   Dave Hansen   [PATCH] r/o bind ...
370

2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
371
372
373
374
375
376
  static void __mnt_unmake_readonly(struct vfsmount *mnt)
  {
  	spin_lock(&vfsmount_lock);
  	mnt->mnt_flags &= ~MNT_READONLY;
  	spin_unlock(&vfsmount_lock);
  }
a3ec947c8   Sukadev Bhattiprolu   vfs: simple_set_m...
377
  void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb)
454e2398b   David Howells   [PATCH] VFS: Perm...
378
379
380
  {
  	mnt->mnt_sb = sb;
  	mnt->mnt_root = dget(sb->s_root);
454e2398b   David Howells   [PATCH] VFS: Perm...
381
382
383
  }
  
  EXPORT_SYMBOL(simple_set_mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
385
386
  void free_vfsmnt(struct vfsmount *mnt)
  {
  	kfree(mnt->mnt_devname);
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
387
  	mnt_free_id(mnt);
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
388
389
390
  #ifdef CONFIG_SMP
  	free_percpu(mnt->mnt_writers);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
392
393
394
  	kmem_cache_free(mnt_cache, mnt);
  }
  
  /*
a05964f39   Ram Pai   [PATCH] shared mo...
395
396
   * 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.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
   */
a05964f39   Ram Pai   [PATCH] shared mo...
398
399
  struct vfsmount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry,
  			      int dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
  {
b58fed8b1   Ram Pai   [PATCH] lindent f...
401
402
  	struct list_head *head = mount_hashtable + hash(mnt, dentry);
  	struct list_head *tmp = head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
  	struct vfsmount *p, *found = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
  	for (;;) {
a05964f39   Ram Pai   [PATCH] shared mo...
405
  		tmp = dir ? tmp->next : tmp->prev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
407
408
409
410
  		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...
411
  			found = p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
413
414
  			break;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
  	return found;
  }
a05964f39   Ram Pai   [PATCH] shared mo...
417
418
419
420
  /*
   * lookup_mnt increments the ref count before returning
   * the vfsmount struct.
   */
1c755af4d   Al Viro   switch lookup_mnt()
421
  struct vfsmount *lookup_mnt(struct path *path)
a05964f39   Ram Pai   [PATCH] shared mo...
422
423
424
  {
  	struct vfsmount *child_mnt;
  	spin_lock(&vfsmount_lock);
1c755af4d   Al Viro   switch lookup_mnt()
425
  	if ((child_mnt = __lookup_mnt(path->mnt, path->dentry, 1)))
a05964f39   Ram Pai   [PATCH] shared mo...
426
427
428
429
  		mntget(child_mnt);
  	spin_unlock(&vfsmount_lock);
  	return child_mnt;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
  static inline int check_mnt(struct vfsmount *mnt)
  {
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
432
  	return mnt->mnt_ns == current->nsproxy->mnt_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
  }
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
434
  static void touch_mnt_namespace(struct mnt_namespace *ns)
5addc5dd8   Al Viro   [PATCH] make /pro...
435
436
437
438
439
440
  {
  	if (ns) {
  		ns->event = ++event;
  		wake_up_interruptible(&ns->poll);
  	}
  }
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
441
  static void __touch_mnt_namespace(struct mnt_namespace *ns)
5addc5dd8   Al Viro   [PATCH] make /pro...
442
443
444
445
446
447
  {
  	if (ns && ns->event != event) {
  		ns->event = event;
  		wake_up_interruptible(&ns->poll);
  	}
  }
1a3906895   Al Viro   [PATCH] reduce st...
448
  static void detach_mnt(struct vfsmount *mnt, struct path *old_path)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
  {
1a3906895   Al Viro   [PATCH] reduce st...
450
451
  	old_path->dentry = mnt->mnt_mountpoint;
  	old_path->mnt = mnt->mnt_parent;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
453
454
455
  	mnt->mnt_parent = mnt;
  	mnt->mnt_mountpoint = mnt->mnt_root;
  	list_del_init(&mnt->mnt_child);
  	list_del_init(&mnt->mnt_hash);
1a3906895   Al Viro   [PATCH] reduce st...
456
  	old_path->dentry->d_mounted--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
  }
b90fa9ae8   Ram Pai   [PATCH] shared mo...
458
459
460
461
462
463
464
  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);
  	dentry->d_mounted++;
  }
1a3906895   Al Viro   [PATCH] reduce st...
465
  static void attach_mnt(struct vfsmount *mnt, struct path *path)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
  {
1a3906895   Al Viro   [PATCH] reduce st...
467
  	mnt_set_mountpoint(path->mnt, path->dentry, mnt);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
468
  	list_add_tail(&mnt->mnt_hash, mount_hashtable +
1a3906895   Al Viro   [PATCH] reduce st...
469
470
  			hash(path->mnt, path->dentry));
  	list_add_tail(&mnt->mnt_child, &path->mnt->mnt_mounts);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
471
472
473
474
475
476
477
478
479
480
  }
  
  /*
   * the caller must hold vfsmount_lock
   */
  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...
481
  	struct mnt_namespace *n = parent->mnt_ns;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
482
483
484
485
486
  
  	BUG_ON(parent == mnt);
  
  	list_add_tail(&head, &mnt->mnt_list);
  	list_for_each_entry(m, &head, mnt_list)
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
487
  		m->mnt_ns = n;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
488
489
490
491
492
  	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...
493
  	touch_mnt_namespace(n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
  }
  
  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...
511
512
513
514
515
516
517
518
519
  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;
  }
36341f645   Ram Pai   [PATCH] mount exp...
520
521
  static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
  					int flag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
523
524
525
526
  {
  	struct super_block *sb = old->mnt_sb;
  	struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname);
  
  	if (mnt) {
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
527
528
529
530
531
532
533
534
535
536
  		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;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
539
540
541
542
  		mnt->mnt_flags = old->mnt_flags;
  		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...
543

5afe00221   Ram Pai   [PATCH] handling ...
544
545
546
547
  		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...
548
  		} else if (!(flag & CL_PRIVATE)) {
5afe00221   Ram Pai   [PATCH] handling ...
549
550
551
552
553
554
  			if ((flag & CL_PROPAGATION) || IS_MNT_SHARED(old))
  				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...
555
556
  		if (flag & CL_MAKE_SHARED)
  			set_mnt_shared(mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
558
559
  
  		/* stick the duplicate mount on the same expiry list
  		 * as the original if that was on one */
36341f645   Ram Pai   [PATCH] mount exp...
560
  		if (flag & CL_EXPIRE) {
36341f645   Ram Pai   [PATCH] mount exp...
561
562
  			if (!list_empty(&old->mnt_expire))
  				list_add(&mnt->mnt_expire, &old->mnt_expire);
36341f645   Ram Pai   [PATCH] mount exp...
563
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
565
  	}
  	return mnt;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
566
567
568
569
  
   out_free:
  	free_vfsmnt(mnt);
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
  }
7b7b1ace2   Al Viro   [PATCH] saner han...
571
  static inline void __mntput(struct vfsmount *mnt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
573
  {
  	struct super_block *sb = mnt->mnt_sb;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
574
  	/*
3d733633a   Dave Hansen   [PATCH] r/o bind ...
575
576
577
578
579
  	 * 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...
580
581
582
583
584
  	/*
  	 * atomic_dec_and_lock() used to deal with ->mnt_count decrements
  	 * provides barriers, so count_mnt_writers() below is safe.  AV
  	 */
  	WARN_ON(count_mnt_writers(mnt));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
587
588
  	dput(mnt->mnt_root);
  	free_vfsmnt(mnt);
  	deactivate_super(sb);
  }
7b7b1ace2   Al Viro   [PATCH] saner han...
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
  void mntput_no_expire(struct vfsmount *mnt)
  {
  repeat:
  	if (atomic_dec_and_lock(&mnt->mnt_count, &vfsmount_lock)) {
  		if (likely(!mnt->mnt_pinned)) {
  			spin_unlock(&vfsmount_lock);
  			__mntput(mnt);
  			return;
  		}
  		atomic_add(mnt->mnt_pinned + 1, &mnt->mnt_count);
  		mnt->mnt_pinned = 0;
  		spin_unlock(&vfsmount_lock);
  		acct_auto_close_mnt(mnt);
  		security_sb_umount_close(mnt);
  		goto repeat;
  	}
  }
  
  EXPORT_SYMBOL(mntput_no_expire);
  
  void mnt_pin(struct vfsmount *mnt)
  {
  	spin_lock(&vfsmount_lock);
  	mnt->mnt_pinned++;
  	spin_unlock(&vfsmount_lock);
  }
  
  EXPORT_SYMBOL(mnt_pin);
  
  void mnt_unpin(struct vfsmount *mnt)
  {
  	spin_lock(&vfsmount_lock);
  	if (mnt->mnt_pinned) {
  		atomic_inc(&mnt->mnt_count);
  		mnt->mnt_pinned--;
  	}
  	spin_unlock(&vfsmount_lock);
  }
  
  EXPORT_SYMBOL(mnt_unpin);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629

b3b304a23   Miklos Szeredi   mount options: ad...
630
631
632
633
634
635
636
637
638
639
640
641
642
643
  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 ...
644
645
646
647
  	const char *options;
  
  	rcu_read_lock();
  	options = rcu_dereference(mnt->mnt_sb->s_options);
b3b304a23   Miklos Szeredi   mount options: ad...
648
649
650
651
652
  
  	if (options != NULL && options[0]) {
  		seq_putc(m, ',');
  		mangle(m, options);
  	}
2a32cebd6   Al Viro   Fix races around ...
653
  	rcu_read_unlock();
b3b304a23   Miklos Szeredi   mount options: ad...
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
  
  	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 ...
674
675
  	BUG_ON(sb->s_options);
  	rcu_assign_pointer(sb->s_options, kstrdup(options, GFP_KERNEL));
b3b304a23   Miklos Szeredi   mount options: ad...
676
677
  }
  EXPORT_SYMBOL(save_mount_options);
2a32cebd6   Al Viro   Fix races around ...
678
679
680
681
682
683
684
685
686
687
  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: ...
688
  #ifdef CONFIG_PROC_FS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689
690
691
  /* iterator */
  static void *m_start(struct seq_file *m, loff_t *pos)
  {
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
692
  	struct proc_mounts *p = m->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693

390c68436   Ram Pai   [PATCH] making na...
694
  	down_read(&namespace_sem);
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
695
  	return seq_list_start(&p->ns->list, *pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
697
698
699
  }
  
  static void *m_next(struct seq_file *m, void *v, loff_t *pos)
  {
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
700
  	struct proc_mounts *p = m->private;
b0765fb85   Pavel Emelianov   Make /proc/self/m...
701

a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
702
  	return seq_list_next(v, &p->ns->list, pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
703
704
705
706
  }
  
  static void m_stop(struct seq_file *m, void *v)
  {
390c68436   Ram Pai   [PATCH] making na...
707
  	up_read(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708
  }
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
709
710
711
712
  struct proc_fs_info {
  	int flag;
  	const char *str;
  };
2069f4578   Eric Paris   LSM/SELinux: show...
713
  static int show_sb_opts(struct seq_file *m, struct super_block *sb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714
  {
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
715
  	static const struct proc_fs_info fs_info[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
716
717
718
  		{ MS_SYNCHRONOUS, ",sync" },
  		{ MS_DIRSYNC, ",dirsync" },
  		{ MS_MANDLOCK, ",mand" },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
720
  		{ 0, NULL }
  	};
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
721
722
723
724
725
726
  	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...
727
728
  
  	return security_sb_show_options(m, sb);
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
729
730
731
732
733
  }
  
  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
734
735
736
  		{ MNT_NOSUID, ",nosuid" },
  		{ MNT_NODEV, ",nodev" },
  		{ MNT_NOEXEC, ",noexec" },
fc33a7bb9   Christoph Hellwig   [PATCH] per-mount...
737
738
  		{ MNT_NOATIME, ",noatime" },
  		{ MNT_NODIRATIME, ",nodiratime" },
47ae32d6a   Valerie Henson   [PATCH] relative ...
739
  		{ MNT_RELATIME, ",relatime" },
d0adde574   Matthew Garrett   Add a strictatime...
740
  		{ MNT_STRICTATIME, ",strictatime" },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741
742
  		{ 0, NULL }
  	};
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
  	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_...
764
  	struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
766
767
  
  	mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
  	seq_putc(m, ' ');
c32c2f63a   Jan Blunck   d_path: Make seq_...
768
769
  	seq_path(m, &mnt_path, " \t
  \\");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
  	seq_putc(m, ' ');
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
771
  	show_type(m, mnt->mnt_sb);
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
772
  	seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw");
2069f4578   Eric Paris   LSM/SELinux: show...
773
774
775
  	err = show_sb_opts(m, mnt->mnt_sb);
  	if (err)
  		goto out;
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
776
  	show_mnt_opts(m, mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
778
779
780
  	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...
781
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
782
783
  	return err;
  }
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
784
  const struct seq_operations mounts_op = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
786
787
788
789
  	.start	= m_start,
  	.next	= m_next,
  	.stop	= m_stop,
  	.show	= show_vfsmnt
  };
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
  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));
  	seq_dentry(m, mnt->mnt_root, " \t
  \\");
  	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: ...
820
821
822
823
824
825
826
  	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: ...
827
828
829
830
831
832
833
834
835
  	if (IS_MNT_UNBINDABLE(mnt))
  		seq_puts(m, " unbindable");
  
  	/* Filesystem specific data */
  	seq_puts(m, " - ");
  	show_type(m, sb);
  	seq_putc(m, ' ');
  	mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
  	seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw");
2069f4578   Eric Paris   LSM/SELinux: show...
836
837
838
  	err = show_sb_opts(m, sb);
  	if (err)
  		goto out;
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
839
840
841
842
  	if (sb->s_op->show_options)
  		err = sb->s_op->show_options(m, mnt);
  	seq_putc(m, '
  ');
2069f4578   Eric Paris   LSM/SELinux: show...
843
  out:
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
844
845
846
847
848
849
850
851
852
  	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...
853
854
  static int show_vfsstat(struct seq_file *m, void *v)
  {
b0765fb85   Pavel Emelianov   Make /proc/self/m...
855
  	struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list);
c32c2f63a   Jan Blunck   d_path: Make seq_...
856
  	struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
b4629fe2f   Chuck Lever   VFS: New /proc fi...
857
858
859
860
861
862
863
864
865
866
867
  	int err = 0;
  
  	/* device */
  	if (mnt->mnt_devname) {
  		seq_puts(m, "device ");
  		mangle(m, mnt->mnt_devname);
  	} else
  		seq_puts(m, "no device");
  
  	/* mount point */
  	seq_puts(m, " mounted on ");
c32c2f63a   Jan Blunck   d_path: Make seq_...
868
869
  	seq_path(m, &mnt_path, " \t
  \\");
b4629fe2f   Chuck Lever   VFS: New /proc fi...
870
871
872
873
  	seq_putc(m, ' ');
  
  	/* file system type */
  	seq_puts(m, "with fstype ");
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
874
  	show_type(m, mnt->mnt_sb);
b4629fe2f   Chuck Lever   VFS: New /proc fi...
875
876
877
878
879
880
881
882
883
884
885
  
  	/* optional statistics */
  	if (mnt->mnt_sb->s_op->show_stats) {
  		seq_putc(m, ' ');
  		err = mnt->mnt_sb->s_op->show_stats(m, mnt);
  	}
  
  	seq_putc(m, '
  ');
  	return err;
  }
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
886
  const struct seq_operations mountstats_op = {
b4629fe2f   Chuck Lever   VFS: New /proc fi...
887
888
889
890
891
  	.start	= m_start,
  	.next	= m_next,
  	.stop	= m_stop,
  	.show	= show_vfsstat,
  };
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
892
  #endif  /* CONFIG_PROC_FS */
b4629fe2f   Chuck Lever   VFS: New /proc fi...
893

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
895
896
897
898
899
900
901
902
903
  /**
   * 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...
904
905
906
  	int actual_refs = 0;
  	int minimum_refs = 0;
  	struct vfsmount *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
907
908
  
  	spin_lock(&vfsmount_lock);
36341f645   Ram Pai   [PATCH] mount exp...
909
  	for (p = mnt; p; p = next_mnt(p, mnt)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910
911
  		actual_refs += atomic_read(&p->mnt_count);
  		minimum_refs += 2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
913
914
915
  	}
  	spin_unlock(&vfsmount_lock);
  
  	if (actual_refs > minimum_refs)
e3474a8eb   Ian Kent   [PATCH] autofs4: ...
916
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917

e3474a8eb   Ian Kent   [PATCH] autofs4: ...
918
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
  }
  
  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: ...
938
  	int ret = 1;
a05964f39   Ram Pai   [PATCH] shared mo...
939
940
  	spin_lock(&vfsmount_lock);
  	if (propagate_mount_busy(mnt, 2))
e3474a8eb   Ian Kent   [PATCH] autofs4: ...
941
  		ret = 0;
a05964f39   Ram Pai   [PATCH] shared mo...
942
943
  	spin_unlock(&vfsmount_lock);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944
945
946
  }
  
  EXPORT_SYMBOL(may_umount);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
947
  void release_mounts(struct list_head *head)
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
948
949
  {
  	struct vfsmount *mnt;
bf066c7db   Miklos Szeredi   [PATCH] shared mo...
950
  	while (!list_empty(head)) {
b5e618181   Pavel Emelianov   Introduce a handy...
951
  		mnt = list_first_entry(head, struct vfsmount, mnt_hash);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
952
953
954
955
956
957
958
959
960
  		list_del_init(&mnt->mnt_hash);
  		if (mnt->mnt_parent != mnt) {
  			struct dentry *dentry;
  			struct vfsmount *m;
  			spin_lock(&vfsmount_lock);
  			dentry = mnt->mnt_mountpoint;
  			m = mnt->mnt_parent;
  			mnt->mnt_mountpoint = mnt->mnt_root;
  			mnt->mnt_parent = mnt;
7c4b93d82   Al Viro   [PATCH] count gho...
961
  			m->mnt_ghosts--;
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
962
963
964
965
966
967
968
  			spin_unlock(&vfsmount_lock);
  			dput(dentry);
  			mntput(m);
  		}
  		mntput(mnt);
  	}
  }
a05964f39   Ram Pai   [PATCH] shared mo...
969
  void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
970
971
  {
  	struct vfsmount *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972

1bfba4e8e   Akinobu Mita   [PATCH] core: use...
973
974
  	for (p = mnt; p; p = next_mnt(p, mnt))
  		list_move(&p->mnt_hash, kill);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
975

a05964f39   Ram Pai   [PATCH] shared mo...
976
977
  	if (propagate)
  		propagate_umount(kill);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
978
979
980
  	list_for_each_entry(p, kill, mnt_hash) {
  		list_del_init(&p->mnt_expire);
  		list_del_init(&p->mnt_list);
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
981
982
  		__touch_mnt_namespace(p->mnt_ns);
  		p->mnt_ns = NULL;
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
983
  		list_del_init(&p->mnt_child);
7c4b93d82   Al Viro   [PATCH] count gho...
984
985
  		if (p->mnt_parent != p) {
  			p->mnt_parent->mnt_ghosts++;
f30ac319f   Al Viro   [PATCH] umount_tr...
986
  			p->mnt_mountpoint->d_mounted--;
7c4b93d82   Al Viro   [PATCH] count gho...
987
  		}
a05964f39   Ram Pai   [PATCH] shared mo...
988
  		change_mnt_propagation(p, MS_PRIVATE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
989
990
  	}
  }
c35038bec   Al Viro   [PATCH] do shrink...
991
  static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
992
993
  static int do_umount(struct vfsmount *mnt, int flags)
  {
b58fed8b1   Ram Pai   [PATCH] lindent f...
994
  	struct super_block *sb = mnt->mnt_sb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
  	int retval;
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
996
  	LIST_HEAD(umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
  
  	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...
1009
  		if (mnt == current->fs->root.mnt ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
  		    flags & (MNT_FORCE | MNT_DETACH))
  			return -EINVAL;
  
  		if (atomic_read(&mnt->mnt_count) != 2)
  			return -EBUSY;
  
  		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...
1029
  	if (flags & MNT_FORCE && sb->s_op->umount_begin) {
42faad996   Al Viro   [PATCH] restore s...
1030
  		sb->s_op->umount_begin(sb);
42faad996   Al Viro   [PATCH] restore s...
1031
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
  
  	/*
  	 * 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...
1042
  	if (mnt == current->fs->root.mnt && !(flags & MNT_DETACH)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1043
1044
1045
1046
1047
  		/*
  		 * Special case for "unmounting" root ...
  		 * we just try to remount it readonly.
  		 */
  		down_write(&sb->s_umount);
4aa98cf76   Al Viro   Push BKL down int...
1048
  		if (!(sb->s_flags & MS_RDONLY))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1049
  			retval = do_remount_sb(sb, MS_RDONLY, NULL, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1050
1051
1052
  		up_write(&sb->s_umount);
  		return retval;
  	}
390c68436   Ram Pai   [PATCH] making na...
1053
  	down_write(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1054
  	spin_lock(&vfsmount_lock);
5addc5dd8   Al Viro   [PATCH] make /pro...
1055
  	event++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1056

c35038bec   Al Viro   [PATCH] do shrink...
1057
1058
  	if (!(flags & MNT_DETACH))
  		shrink_submounts(mnt, &umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1059
  	retval = -EBUSY;
a05964f39   Ram Pai   [PATCH] shared mo...
1060
  	if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1061
  		if (!list_empty(&mnt->mnt_list))
a05964f39   Ram Pai   [PATCH] shared mo...
1062
  			umount_tree(mnt, 1, &umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1063
1064
1065
1066
1067
  		retval = 0;
  	}
  	spin_unlock(&vfsmount_lock);
  	if (retval)
  		security_sb_umount_busy(mnt);
390c68436   Ram Pai   [PATCH] making na...
1068
  	up_write(&namespace_sem);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1069
  	release_mounts(&umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
  	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...
1080
  SYSCALL_DEFINE2(umount, char __user *, name, int, flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1081
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
1082
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1083
  	int retval;
2d8f30380   Al Viro   [PATCH] sanitize ...
1084
  	retval = user_path(name, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1085
1086
1087
  	if (retval)
  		goto out;
  	retval = -EINVAL;
2d8f30380   Al Viro   [PATCH] sanitize ...
1088
  	if (path.dentry != path.mnt->mnt_root)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1089
  		goto dput_and_out;
2d8f30380   Al Viro   [PATCH] sanitize ...
1090
  	if (!check_mnt(path.mnt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1091
1092
1093
1094
1095
  		goto dput_and_out;
  
  	retval = -EPERM;
  	if (!capable(CAP_SYS_ADMIN))
  		goto dput_and_out;
2d8f30380   Al Viro   [PATCH] sanitize ...
1096
  	retval = do_umount(path.mnt, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1097
  dput_and_out:
429731b15   Jan Blunck   Remove path_relea...
1098
  	/* we mustn't call path_put() as that would clear mnt_expiry_mark */
2d8f30380   Al Viro   [PATCH] sanitize ...
1099
1100
  	dput(path.dentry);
  	mntput_no_expire(path.mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1101
1102
1103
1104
1105
1106
1107
  out:
  	return retval;
  }
  
  #ifdef __ARCH_WANT_SYS_OLDUMOUNT
  
  /*
b58fed8b1   Ram Pai   [PATCH] lindent f...
1108
   *	The 2.0 compatible umount. No flags.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1109
   */
bdc480e3b   Heiko Carstens   [CVE-2009-0029] S...
1110
  SYSCALL_DEFINE1(oldumount, char __user *, name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1111
  {
b58fed8b1   Ram Pai   [PATCH] lindent f...
1112
  	return sys_umount(name, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1113
1114
1115
  }
  
  #endif
2d92ab3c6   Al Viro   [PATCH] finally g...
1116
  static int mount_is_safe(struct path *path)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1117
1118
1119
1120
1121
  {
  	if (capable(CAP_SYS_ADMIN))
  		return 0;
  	return -EPERM;
  #ifdef notyet
2d92ab3c6   Al Viro   [PATCH] finally g...
1122
  	if (S_ISLNK(path->dentry->d_inode->i_mode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1123
  		return -EPERM;
2d92ab3c6   Al Viro   [PATCH] finally g...
1124
  	if (path->dentry->d_inode->i_mode & S_ISVTX) {
da9592ede   David Howells   CRED: Wrap task c...
1125
  		if (current_uid() != path->dentry->d_inode->i_uid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1126
1127
  			return -EPERM;
  	}
2d92ab3c6   Al Viro   [PATCH] finally g...
1128
  	if (inode_permission(path->dentry->d_inode, MAY_WRITE))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129
1130
1131
1132
  		return -EPERM;
  	return 0;
  #endif
  }
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1133
  struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry,
36341f645   Ram Pai   [PATCH] mount exp...
1134
  					int flag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1135
1136
  {
  	struct vfsmount *res, *p, *q, *r, *s;
1a3906895   Al Viro   [PATCH] reduce st...
1137
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1138

9676f0c63   Ram Pai   [PATCH] unbindabl...
1139
1140
  	if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(mnt))
  		return NULL;
36341f645   Ram Pai   [PATCH] mount exp...
1141
  	res = q = clone_mnt(mnt, dentry, flag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1142
1143
1144
1145
1146
  	if (!q)
  		goto Enomem;
  	q->mnt_mountpoint = mnt->mnt_mountpoint;
  
  	p = mnt;
fdadd65fb   Domen Puncer   [PATCH] janitor: ...
1147
  	list_for_each_entry(r, &mnt->mnt_mounts, mnt_child) {
7ec02ef15   Jan Blunck   vfs: remove lives...
1148
  		if (!is_subdir(r->mnt_mountpoint, dentry))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1149
1150
1151
  			continue;
  
  		for (s = r; s; s = next_mnt(s, r)) {
9676f0c63   Ram Pai   [PATCH] unbindabl...
1152
1153
1154
1155
  			if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(s)) {
  				s = skip_mnt_tree(s);
  				continue;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1156
1157
1158
1159
1160
  			while (p != s->mnt_parent) {
  				p = p->mnt_parent;
  				q = q->mnt_parent;
  			}
  			p = s;
1a3906895   Al Viro   [PATCH] reduce st...
1161
1162
  			path.mnt = q;
  			path.dentry = p->mnt_mountpoint;
36341f645   Ram Pai   [PATCH] mount exp...
1163
  			q = clone_mnt(p, p->mnt_root, flag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1164
1165
1166
1167
  			if (!q)
  				goto Enomem;
  			spin_lock(&vfsmount_lock);
  			list_add_tail(&q->mnt_list, &res->mnt_list);
1a3906895   Al Viro   [PATCH] reduce st...
1168
  			attach_mnt(q, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1169
1170
1171
1172
  			spin_unlock(&vfsmount_lock);
  		}
  	}
  	return res;
b58fed8b1   Ram Pai   [PATCH] lindent f...
1173
  Enomem:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1174
  	if (res) {
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1175
  		LIST_HEAD(umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1176
  		spin_lock(&vfsmount_lock);
a05964f39   Ram Pai   [PATCH] shared mo...
1177
  		umount_tree(res, 0, &umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1178
  		spin_unlock(&vfsmount_lock);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1179
  		release_mounts(&umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1180
1181
1182
  	}
  	return NULL;
  }
589ff870e   Al Viro   Switch collect_mo...
1183
  struct vfsmount *collect_mounts(struct path *path)
8aec08094   Al Viro   [PATCH] new helpe...
1184
1185
  {
  	struct vfsmount *tree;
1a60a2807   Al Viro   [PATCH] lock excl...
1186
  	down_write(&namespace_sem);
589ff870e   Al Viro   Switch collect_mo...
1187
  	tree = copy_tree(path->mnt, path->dentry, CL_COPY_ALL | CL_PRIVATE);
1a60a2807   Al Viro   [PATCH] lock excl...
1188
  	up_write(&namespace_sem);
8aec08094   Al Viro   [PATCH] new helpe...
1189
1190
1191
1192
1193
1194
  	return tree;
  }
  
  void drop_collected_mounts(struct vfsmount *mnt)
  {
  	LIST_HEAD(umount_list);
1a60a2807   Al Viro   [PATCH] lock excl...
1195
  	down_write(&namespace_sem);
8aec08094   Al Viro   [PATCH] new helpe...
1196
1197
1198
  	spin_lock(&vfsmount_lock);
  	umount_tree(mnt, 0, &umount_list);
  	spin_unlock(&vfsmount_lock);
1a60a2807   Al Viro   [PATCH] lock excl...
1199
  	up_write(&namespace_sem);
8aec08094   Al Viro   [PATCH] new helpe...
1200
1201
  	release_mounts(&umount_list);
  }
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
  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...
1228
1229
  /*
   *  @source_mnt : mount tree to be attached
214444032   Ram Pai   [PATCH] shared mo...
1230
1231
1232
1233
   *  @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...
1234
1235
1236
   *
   *  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...
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
   * ---------------------------------------------------------------------------
   * |         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...
1249
1250
1251
1252
1253
1254
1255
1256
1257
   * 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 ...
1258
1259
1260
1261
1262
1263
1264
   * (+++) 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...
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
   * ---------------------------------------------------------------------------
   * |         		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 ...
1277
1278
1279
   *
   * (+)  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...
1280
   * (+*)  the mount is moved to the destination.
5afe00221   Ram Pai   [PATCH] handling ...
1281
1282
1283
1284
   * (+++)  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...
1285
1286
1287
1288
1289
1290
1291
   *
   * 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...
1292
  			struct path *path, struct path *parent_path)
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1293
1294
  {
  	LIST_HEAD(tree_list);
1a3906895   Al Viro   [PATCH] reduce st...
1295
1296
  	struct vfsmount *dest_mnt = path->mnt;
  	struct dentry *dest_dentry = path->dentry;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1297
  	struct vfsmount *child, *p;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1298
  	int err;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1299

719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1300
1301
1302
1303
1304
1305
1306
1307
  	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...
1308
1309
1310
1311
1312
1313
1314
  
  	if (IS_MNT_SHARED(dest_mnt)) {
  		for (p = source_mnt; p; p = next_mnt(p, source_mnt))
  			set_mnt_shared(p);
  	}
  
  	spin_lock(&vfsmount_lock);
1a3906895   Al Viro   [PATCH] reduce st...
1315
1316
1317
  	if (parent_path) {
  		detach_mnt(source_mnt, parent_path);
  		attach_mnt(source_mnt, path);
e5d67f071   Al Viro   Touch all affecte...
1318
  		touch_mnt_namespace(parent_path->mnt->mnt_ns);
214444032   Ram Pai   [PATCH] shared mo...
1319
1320
1321
1322
  	} else {
  		mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt);
  		commit_tree(source_mnt);
  	}
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1323
1324
1325
1326
1327
1328
1329
  
  	list_for_each_entry_safe(child, p, &tree_list, mnt_hash) {
  		list_del_init(&child->mnt_hash);
  		commit_tree(child);
  	}
  	spin_unlock(&vfsmount_lock);
  	return 0;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1330
1331
1332
1333
1334
1335
  
   out_cleanup_ids:
  	if (IS_MNT_SHARED(dest_mnt))
  		cleanup_group_ids(source_mnt, NULL);
   out:
  	return err;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1336
  }
8c3ee42e8   Al Viro   [PATCH] get rid o...
1337
  static int graft_tree(struct vfsmount *mnt, struct path *path)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1338
1339
1340
1341
  {
  	int err;
  	if (mnt->mnt_sb->s_flags & MS_NOUSER)
  		return -EINVAL;
8c3ee42e8   Al Viro   [PATCH] get rid o...
1342
  	if (S_ISDIR(path->dentry->d_inode->i_mode) !=
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1343
1344
1345
1346
  	      S_ISDIR(mnt->mnt_root->d_inode->i_mode))
  		return -ENOTDIR;
  
  	err = -ENOENT;
8c3ee42e8   Al Viro   [PATCH] get rid o...
1347
1348
  	mutex_lock(&path->dentry->d_inode->i_mutex);
  	if (IS_DEADDIR(path->dentry->d_inode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1349
  		goto out_unlock;
8c3ee42e8   Al Viro   [PATCH] get rid o...
1350
  	err = security_sb_check_sb(mnt, path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1351
1352
1353
1354
  	if (err)
  		goto out_unlock;
  
  	err = -ENOENT;
f3da392e9   Alexey Dobriyan   dcache: extrace a...
1355
  	if (!d_unlinked(path->dentry))
8c3ee42e8   Al Viro   [PATCH] get rid o...
1356
  		err = attach_recursive_mnt(mnt, path, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1357
  out_unlock:
8c3ee42e8   Al Viro   [PATCH] get rid o...
1358
  	mutex_unlock(&path->dentry->d_inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1359
  	if (!err)
8c3ee42e8   Al Viro   [PATCH] get rid o...
1360
  		security_sb_post_addmount(mnt, path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1361
1362
1363
1364
  	return err;
  }
  
  /*
07b20889e   Ram Pai   [PATCH] beginning...
1365
1366
   * recursively change the type of the mountpoint.
   */
0a0d8a467   Al Viro   [PATCH] no need f...
1367
  static int do_change_type(struct path *path, int flag)
07b20889e   Ram Pai   [PATCH] beginning...
1368
  {
2d92ab3c6   Al Viro   [PATCH] finally g...
1369
  	struct vfsmount *m, *mnt = path->mnt;
07b20889e   Ram Pai   [PATCH] beginning...
1370
1371
  	int recurse = flag & MS_REC;
  	int type = flag & ~MS_REC;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1372
  	int err = 0;
07b20889e   Ram Pai   [PATCH] beginning...
1373

ee6f95829   Miklos Szeredi   check privileges ...
1374
1375
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
2d92ab3c6   Al Viro   [PATCH] finally g...
1376
  	if (path->dentry != path->mnt->mnt_root)
07b20889e   Ram Pai   [PATCH] beginning...
1377
1378
1379
  		return -EINVAL;
  
  	down_write(&namespace_sem);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1380
1381
1382
1383
1384
  	if (type == MS_SHARED) {
  		err = invent_group_ids(mnt, recurse);
  		if (err)
  			goto out_unlock;
  	}
07b20889e   Ram Pai   [PATCH] beginning...
1385
1386
1387
1388
  	spin_lock(&vfsmount_lock);
  	for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL))
  		change_mnt_propagation(m, type);
  	spin_unlock(&vfsmount_lock);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1389
1390
  
   out_unlock:
07b20889e   Ram Pai   [PATCH] beginning...
1391
  	up_write(&namespace_sem);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1392
  	return err;
07b20889e   Ram Pai   [PATCH] beginning...
1393
1394
1395
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1396
1397
   * do loopback mount.
   */
0a0d8a467   Al Viro   [PATCH] no need f...
1398
  static int do_loopback(struct path *path, char *old_name,
2dafe1c4d   Eric Sandeen   reduce large do_m...
1399
  				int recurse)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1400
  {
2d92ab3c6   Al Viro   [PATCH] finally g...
1401
  	struct path old_path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1402
  	struct vfsmount *mnt = NULL;
2d92ab3c6   Al Viro   [PATCH] finally g...
1403
  	int err = mount_is_safe(path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1404
1405
1406
1407
  	if (err)
  		return err;
  	if (!old_name || !*old_name)
  		return -EINVAL;
2d92ab3c6   Al Viro   [PATCH] finally g...
1408
  	err = kern_path(old_name, LOOKUP_FOLLOW, &old_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1409
1410
  	if (err)
  		return err;
390c68436   Ram Pai   [PATCH] making na...
1411
  	down_write(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1412
  	err = -EINVAL;
2d92ab3c6   Al Viro   [PATCH] finally g...
1413
  	if (IS_MNT_UNBINDABLE(old_path.mnt))
4ac913785   Jan Blunck   Embed a struct pa...
1414
  		goto out;
9676f0c63   Ram Pai   [PATCH] unbindabl...
1415

2d92ab3c6   Al Viro   [PATCH] finally g...
1416
  	if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt))
ccd48bc7f   Al Viro   [PATCH] cleanups ...
1417
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1418

ccd48bc7f   Al Viro   [PATCH] cleanups ...
1419
1420
  	err = -ENOMEM;
  	if (recurse)
2d92ab3c6   Al Viro   [PATCH] finally g...
1421
  		mnt = copy_tree(old_path.mnt, old_path.dentry, 0);
ccd48bc7f   Al Viro   [PATCH] cleanups ...
1422
  	else
2d92ab3c6   Al Viro   [PATCH] finally g...
1423
  		mnt = clone_mnt(old_path.mnt, old_path.dentry, 0);
ccd48bc7f   Al Viro   [PATCH] cleanups ...
1424
1425
1426
  
  	if (!mnt)
  		goto out;
2d92ab3c6   Al Viro   [PATCH] finally g...
1427
  	err = graft_tree(mnt, path);
ccd48bc7f   Al Viro   [PATCH] cleanups ...
1428
  	if (err) {
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1429
  		LIST_HEAD(umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1430
  		spin_lock(&vfsmount_lock);
a05964f39   Ram Pai   [PATCH] shared mo...
1431
  		umount_tree(mnt, 0, &umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1432
  		spin_unlock(&vfsmount_lock);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1433
  		release_mounts(&umount_list);
5b83d2c5c   Ram Pai   [PATCH] sanitize ...
1434
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1435

ccd48bc7f   Al Viro   [PATCH] cleanups ...
1436
  out:
390c68436   Ram Pai   [PATCH] making na...
1437
  	up_write(&namespace_sem);
2d92ab3c6   Al Viro   [PATCH] finally g...
1438
  	path_put(&old_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1439
1440
  	return err;
  }
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
  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
1457
1458
1459
1460
1461
  /*
   * 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...
1462
  static int do_remount(struct path *path, int flags, int mnt_flags,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1463
1464
1465
  		      void *data)
  {
  	int err;
2d92ab3c6   Al Viro   [PATCH] finally g...
1466
  	struct super_block *sb = path->mnt->mnt_sb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1467
1468
1469
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
2d92ab3c6   Al Viro   [PATCH] finally g...
1470
  	if (!check_mnt(path->mnt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1471
  		return -EINVAL;
2d92ab3c6   Al Viro   [PATCH] finally g...
1472
  	if (path->dentry != path->mnt->mnt_root)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1473
1474
1475
  		return -EINVAL;
  
  	down_write(&sb->s_umount);
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
1476
  	if (flags & MS_BIND)
2d92ab3c6   Al Viro   [PATCH] finally g...
1477
  		err = change_mount_flags(path->mnt, flags);
4aa98cf76   Al Viro   Push BKL down int...
1478
  	else
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
1479
  		err = do_remount_sb(sb, flags, data, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1480
  	if (!err)
2d92ab3c6   Al Viro   [PATCH] finally g...
1481
  		path->mnt->mnt_flags = mnt_flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1482
  	up_write(&sb->s_umount);
0e55a7cca   Dan Williams   [RFC PATCH] touch...
1483
  	if (!err) {
2d92ab3c6   Al Viro   [PATCH] finally g...
1484
  		security_sb_post_remount(path->mnt, flags, data);
0e55a7cca   Dan Williams   [RFC PATCH] touch...
1485
1486
1487
1488
1489
  
  		spin_lock(&vfsmount_lock);
  		touch_mnt_namespace(path->mnt->mnt_ns);
  		spin_unlock(&vfsmount_lock);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1490
1491
  	return err;
  }
9676f0c63   Ram Pai   [PATCH] unbindabl...
1492
1493
1494
1495
1496
1497
1498
1499
1500
  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...
1501
  static int do_move_mount(struct path *path, char *old_name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1502
  {
2d92ab3c6   Al Viro   [PATCH] finally g...
1503
  	struct path old_path, parent_path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1504
1505
1506
1507
1508
1509
  	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...
1510
  	err = kern_path(old_name, LOOKUP_FOLLOW, &old_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1511
1512
  	if (err)
  		return err;
390c68436   Ram Pai   [PATCH] making na...
1513
  	down_write(&namespace_sem);
2d92ab3c6   Al Viro   [PATCH] finally g...
1514
  	while (d_mountpoint(path->dentry) &&
9393bd07c   Al Viro   switch follow_down()
1515
  	       follow_down(path))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1516
1517
  		;
  	err = -EINVAL;
2d92ab3c6   Al Viro   [PATCH] finally g...
1518
  	if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1519
1520
1521
  		goto out;
  
  	err = -ENOENT;
2d92ab3c6   Al Viro   [PATCH] finally g...
1522
1523
  	mutex_lock(&path->dentry->d_inode->i_mutex);
  	if (IS_DEADDIR(path->dentry->d_inode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1524
  		goto out1;
f3da392e9   Alexey Dobriyan   dcache: extrace a...
1525
  	if (d_unlinked(path->dentry))
214444032   Ram Pai   [PATCH] shared mo...
1526
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1527
1528
  
  	err = -EINVAL;
2d92ab3c6   Al Viro   [PATCH] finally g...
1529
  	if (old_path.dentry != old_path.mnt->mnt_root)
214444032   Ram Pai   [PATCH] shared mo...
1530
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1531

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

2d92ab3c6   Al Viro   [PATCH] finally g...
1535
1536
  	if (S_ISDIR(path->dentry->d_inode->i_mode) !=
  	      S_ISDIR(old_path.dentry->d_inode->i_mode))
214444032   Ram Pai   [PATCH] shared mo...
1537
1538
1539
1540
  		goto out1;
  	/*
  	 * Don't move a mount residing in a shared parent.
  	 */
2d92ab3c6   Al Viro   [PATCH] finally g...
1541
1542
  	if (old_path.mnt->mnt_parent &&
  	    IS_MNT_SHARED(old_path.mnt->mnt_parent))
214444032   Ram Pai   [PATCH] shared mo...
1543
  		goto out1;
9676f0c63   Ram Pai   [PATCH] unbindabl...
1544
1545
1546
1547
  	/*
  	 * Don't move a mount tree containing unbindable mounts to a destination
  	 * mount which is shared.
  	 */
2d92ab3c6   Al Viro   [PATCH] finally g...
1548
1549
  	if (IS_MNT_SHARED(path->mnt) &&
  	    tree_contains_unbindable(old_path.mnt))
9676f0c63   Ram Pai   [PATCH] unbindabl...
1550
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1551
  	err = -ELOOP;
2d92ab3c6   Al Viro   [PATCH] finally g...
1552
1553
  	for (p = path->mnt; p->mnt_parent != p; p = p->mnt_parent)
  		if (p == old_path.mnt)
214444032   Ram Pai   [PATCH] shared mo...
1554
  			goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1555

2d92ab3c6   Al Viro   [PATCH] finally g...
1556
  	err = attach_recursive_mnt(old_path.mnt, path, &parent_path);
4ac913785   Jan Blunck   Embed a struct pa...
1557
  	if (err)
214444032   Ram Pai   [PATCH] shared mo...
1558
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1559
1560
1561
  
  	/* if the mount is moved, it should no longer be expire
  	 * automatically */
2d92ab3c6   Al Viro   [PATCH] finally g...
1562
  	list_del_init(&old_path.mnt->mnt_expire);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1563
  out1:
2d92ab3c6   Al Viro   [PATCH] finally g...
1564
  	mutex_unlock(&path->dentry->d_inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1565
  out:
390c68436   Ram Pai   [PATCH] making na...
1566
  	up_write(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1567
  	if (!err)
1a3906895   Al Viro   [PATCH] reduce st...
1568
  		path_put(&parent_path);
2d92ab3c6   Al Viro   [PATCH] finally g...
1569
  	path_put(&old_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1570
1571
1572
1573
1574
1575
1576
  	return err;
  }
  
  /*
   * create a new mount for userspace and request it to be added into the
   * namespace's tree
   */
0a0d8a467   Al Viro   [PATCH] no need f...
1577
  static int do_new_mount(struct path *path, char *type, int flags,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1578
1579
1580
  			int mnt_flags, char *name, void *data)
  {
  	struct vfsmount *mnt;
eca6f534e   Vegard Nossum   fs: fix overflow ...
1581
  	if (!type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1582
1583
1584
1585
1586
  		return -EINVAL;
  
  	/* we need capabilities... */
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
7f78d4cd4   Al Viro   Push BKL down bey...
1587
  	lock_kernel();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1588
  	mnt = do_kern_mount(type, flags, name, data);
7f78d4cd4   Al Viro   Push BKL down bey...
1589
  	unlock_kernel();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1590
1591
  	if (IS_ERR(mnt))
  		return PTR_ERR(mnt);
2d92ab3c6   Al Viro   [PATCH] finally g...
1592
  	return do_add_mount(mnt, path, mnt_flags, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1593
1594
1595
1596
1597
1598
  }
  
  /*
   * add a mount into a namespace's mount tree
   * - provide the option of adding the new mount to an expiration list
   */
8d66bf548   Al Viro   [PATCH] pass stru...
1599
  int do_add_mount(struct vfsmount *newmnt, struct path *path,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1600
1601
1602
  		 int mnt_flags, struct list_head *fslist)
  {
  	int err;
390c68436   Ram Pai   [PATCH] making na...
1603
  	down_write(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1604
  	/* Something was mounted here while we slept */
8d66bf548   Al Viro   [PATCH] pass stru...
1605
  	while (d_mountpoint(path->dentry) &&
9393bd07c   Al Viro   switch follow_down()
1606
  	       follow_down(path))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1607
1608
  		;
  	err = -EINVAL;
dd5cae6e9   Al Viro   Don't bother with...
1609
  	if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1610
1611
1612
1613
  		goto unlock;
  
  	/* Refuse the same filesystem on the same mount point */
  	err = -EBUSY;
8d66bf548   Al Viro   [PATCH] pass stru...
1614
1615
  	if (path->mnt->mnt_sb == newmnt->mnt_sb &&
  	    path->mnt->mnt_root == path->dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1616
1617
1618
1619
1620
1621
1622
  		goto unlock;
  
  	err = -EINVAL;
  	if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode))
  		goto unlock;
  
  	newmnt->mnt_flags = mnt_flags;
8d66bf548   Al Viro   [PATCH] pass stru...
1623
  	if ((err = graft_tree(newmnt, path)))
5b83d2c5c   Ram Pai   [PATCH] sanitize ...
1624
  		goto unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1625

6758f953d   Al Viro   [PATCH] mnt_expir...
1626
  	if (fslist) /* add to the specified expiration list */
55e700b92   Miklos Szeredi   [PATCH] namespace...
1627
  		list_add_tail(&newmnt->mnt_expire, fslist);
6758f953d   Al Viro   [PATCH] mnt_expir...
1628

390c68436   Ram Pai   [PATCH] making na...
1629
  	up_write(&namespace_sem);
5b83d2c5c   Ram Pai   [PATCH] sanitize ...
1630
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1631
1632
  
  unlock:
390c68436   Ram Pai   [PATCH] making na...
1633
  	up_write(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1634
1635
1636
1637
1638
  	mntput(newmnt);
  	return err;
  }
  
  EXPORT_SYMBOL_GPL(do_add_mount);
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1639
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1640
1641
1642
1643
1644
1645
   * 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
1646
1647
  	struct vfsmount *mnt, *next;
  	LIST_HEAD(graveyard);
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
1648
  	LIST_HEAD(umounts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1649
1650
1651
  
  	if (list_empty(mounts))
  		return;
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
1652
  	down_write(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1653
1654
1655
1656
1657
1658
1659
1660
  	spin_lock(&vfsmount_lock);
  
  	/* 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...
1661
  	list_for_each_entry_safe(mnt, next, mounts, mnt_expire) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1662
  		if (!xchg(&mnt->mnt_expiry_mark, 1) ||
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
1663
  			propagate_mount_busy(mnt, 1))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1664
  			continue;
55e700b92   Miklos Szeredi   [PATCH] namespace...
1665
  		list_move(&mnt->mnt_expire, &graveyard);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1666
  	}
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
1667
1668
1669
1670
1671
  	while (!list_empty(&graveyard)) {
  		mnt = list_first_entry(&graveyard, struct vfsmount, mnt_expire);
  		touch_mnt_namespace(mnt->mnt_ns);
  		umount_tree(mnt, 1, &umounts);
  	}
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1672
  	spin_unlock(&vfsmount_lock);
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
1673
1674
1675
  	up_write(&namespace_sem);
  
  	release_mounts(&umounts);
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
  }
  
  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
1701
  			continue;
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1702
1703
1704
1705
1706
1707
1708
  		/*
  		 * 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
1709

5528f911b   Trond Myklebust   VFS: Add shrink_s...
1710
  		if (!propagate_mount_busy(mnt, 1)) {
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1711
1712
1713
  			list_move_tail(&mnt->mnt_expire, graveyard);
  			found++;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1714
  	}
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
  	/*
  	 * 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
   */
c35038bec   Al Viro   [PATCH] do shrink...
1730
  static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts)
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1731
1732
  {
  	LIST_HEAD(graveyard);
c35038bec   Al Viro   [PATCH] do shrink...
1733
  	struct vfsmount *m;
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1734

5528f911b   Trond Myklebust   VFS: Add shrink_s...
1735
  	/* extract submounts of 'mountpoint' from the expiration list */
c35038bec   Al Viro   [PATCH] do shrink...
1736
  	while (select_submounts(mnt, &graveyard)) {
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
1737
  		while (!list_empty(&graveyard)) {
c35038bec   Al Viro   [PATCH] do shrink...
1738
  			m = list_first_entry(&graveyard, struct vfsmount,
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
1739
  						mnt_expire);
afef80b3d   Eric W. Biederman   vfs: fix shrink_s...
1740
1741
  			touch_mnt_namespace(m->mnt_ns);
  			umount_tree(m, 1, umounts);
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
1742
1743
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1744
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1745
1746
1747
1748
1749
1750
  /*
   * 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...
1751
1752
  static long exact_copy_from_user(void *to, const void __user * from,
  				 unsigned long n)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
  {
  	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...
1772
  int copy_mount_options(const void __user * data, unsigned long *where)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1773
1774
1775
1776
  {
  	int i;
  	unsigned long page;
  	unsigned long size;
b58fed8b1   Ram Pai   [PATCH] lindent f...
1777

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
  	*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...
1796
  		free_page(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1797
1798
1799
1800
1801
1802
1803
  		return -EFAULT;
  	}
  	if (i != PAGE_SIZE)
  		memset((char *)page + i, 0, PAGE_SIZE - i);
  	*where = page;
  	return 0;
  }
eca6f534e   Vegard Nossum   fs: fix overflow ...
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
  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
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
  /*
   * 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...
1834
  long do_mount(char *dev_name, char *dir_name, char *type_page,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1835
1836
  		  unsigned long flags, void *data_page)
  {
2d92ab3c6   Al Viro   [PATCH] finally g...
1837
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
  	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
1849
1850
1851
  
  	if (data_page)
  		((char *)data_page)[PAGE_SIZE - 1] = 0;
613cbe3d4   Andi Kleen   Don't set relatim...
1852
1853
1854
  	/* Default to relatime unless overriden */
  	if (!(flags & MS_NOATIME))
  		mnt_flags |= MNT_RELATIME;
0a1c01c94   Matthew Garrett   Make relatime def...
1855

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1856
1857
1858
1859
1860
1861
1862
  	/* 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...
1863
1864
1865
1866
  	if (flags & MS_NOATIME)
  		mnt_flags |= MNT_NOATIME;
  	if (flags & MS_NODIRATIME)
  		mnt_flags |= MNT_NODIRATIME;
d0adde574   Matthew Garrett   Add a strictatime...
1867
1868
  	if (flags & MS_STRICTATIME)
  		mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME);
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
1869
1870
  	if (flags & MS_RDONLY)
  		mnt_flags |= MNT_READONLY;
fc33a7bb9   Christoph Hellwig   [PATCH] per-mount...
1871
1872
  
  	flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE |
d0adde574   Matthew Garrett   Add a strictatime...
1873
1874
  		   MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT |
  		   MS_STRICTATIME);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1875
1876
  
  	/* ... and get the mountpoint */
2d92ab3c6   Al Viro   [PATCH] finally g...
1877
  	retval = kern_path(dir_name, LOOKUP_FOLLOW, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1878
1879
  	if (retval)
  		return retval;
2d92ab3c6   Al Viro   [PATCH] finally g...
1880
  	retval = security_sb_mount(dev_name, &path,
b5266eb4c   Al Viro   [PATCH] switch a ...
1881
  				   type_page, flags, data_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1882
1883
1884
1885
  	if (retval)
  		goto dput_out;
  
  	if (flags & MS_REMOUNT)
2d92ab3c6   Al Viro   [PATCH] finally g...
1886
  		retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1887
1888
  				    data_page);
  	else if (flags & MS_BIND)
2d92ab3c6   Al Viro   [PATCH] finally g...
1889
  		retval = do_loopback(&path, dev_name, flags & MS_REC);
9676f0c63   Ram Pai   [PATCH] unbindabl...
1890
  	else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
2d92ab3c6   Al Viro   [PATCH] finally g...
1891
  		retval = do_change_type(&path, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1892
  	else if (flags & MS_MOVE)
2d92ab3c6   Al Viro   [PATCH] finally g...
1893
  		retval = do_move_mount(&path, dev_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1894
  	else
2d92ab3c6   Al Viro   [PATCH] finally g...
1895
  		retval = do_new_mount(&path, type_page, flags, mnt_flags,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1896
1897
  				      dev_name, data_page);
  dput_out:
2d92ab3c6   Al Viro   [PATCH] finally g...
1898
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1899
1900
  	return retval;
  }
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
  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;
  }
741a29513   JANAK DESAI   [PATCH] unshare s...
1915
1916
1917
1918
  /*
   * 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()...
1919
  static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
1920
  		struct fs_struct *fs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1921
  {
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
1922
  	struct mnt_namespace *new_ns;
7f2da1e7d   Al Viro   [PATCH] kill altroot
1923
  	struct vfsmount *rootmnt = NULL, *pwdmnt = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1924
  	struct vfsmount *p, *q;
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
1925
1926
1927
  	new_ns = alloc_mnt_ns();
  	if (IS_ERR(new_ns))
  		return new_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1928

390c68436   Ram Pai   [PATCH] making na...
1929
  	down_write(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1930
  	/* First pass: copy the tree topology */
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
1931
  	new_ns->root = copy_tree(mnt_ns->root, mnt_ns->root->mnt_root,
9676f0c63   Ram Pai   [PATCH] unbindabl...
1932
  					CL_COPY_ALL | CL_EXPIRE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1933
  	if (!new_ns->root) {
390c68436   Ram Pai   [PATCH] making na...
1934
  		up_write(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1935
  		kfree(new_ns);
5cc4a0341   Julia Lawall   fs/namespace.c: d...
1936
  		return ERR_PTR(-ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
  	}
  	spin_lock(&vfsmount_lock);
  	list_add_tail(&new_ns->list, &new_ns->root->mnt_list);
  	spin_unlock(&vfsmount_lock);
  
  	/*
  	 * 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...
1947
  	p = mnt_ns->root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1948
1949
  	q = new_ns->root;
  	while (p) {
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
1950
  		q->mnt_ns = new_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1951
  		if (fs) {
6ac08c39a   Jan Blunck   Use struct path i...
1952
  			if (p == fs->root.mnt) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1953
  				rootmnt = p;
6ac08c39a   Jan Blunck   Use struct path i...
1954
  				fs->root.mnt = mntget(q);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1955
  			}
6ac08c39a   Jan Blunck   Use struct path i...
1956
  			if (p == fs->pwd.mnt) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1957
  				pwdmnt = p;
6ac08c39a   Jan Blunck   Use struct path i...
1958
  				fs->pwd.mnt = mntget(q);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1959
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1960
  		}
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
1961
  		p = next_mnt(p, mnt_ns->root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1962
1963
  		q = next_mnt(q, new_ns->root);
  	}
390c68436   Ram Pai   [PATCH] making na...
1964
  	up_write(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1965

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1966
1967
1968
1969
  	if (rootmnt)
  		mntput(rootmnt);
  	if (pwdmnt)
  		mntput(pwdmnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1970

741a29513   JANAK DESAI   [PATCH] unshare s...
1971
1972
  	return new_ns;
  }
213dd266d   Eric W. Biederman   namespace: ensure...
1973
  struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
1974
  		struct fs_struct *new_fs)
741a29513   JANAK DESAI   [PATCH] unshare s...
1975
  {
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
1976
  	struct mnt_namespace *new_ns;
741a29513   JANAK DESAI   [PATCH] unshare s...
1977

e3222c4ec   Badari Pulavarty   Merge sys_clone()...
1978
  	BUG_ON(!ns);
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
1979
  	get_mnt_ns(ns);
741a29513   JANAK DESAI   [PATCH] unshare s...
1980
1981
  
  	if (!(flags & CLONE_NEWNS))
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
1982
  		return ns;
741a29513   JANAK DESAI   [PATCH] unshare s...
1983

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

6b3286ed1   Kirill Korotaev   [PATCH] rename st...
1986
  	put_mnt_ns(ns);
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
1987
  	return new_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1988
  }
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
  /**
   * create_mnt_ns - creates a private namespace and adds a root filesystem
   * @mnt: pointer to the new root filesystem mountpoint
   */
  struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt)
  {
  	struct mnt_namespace *new_ns;
  
  	new_ns = alloc_mnt_ns();
  	if (!IS_ERR(new_ns)) {
  		mnt->mnt_ns = new_ns;
  		new_ns->root = mnt;
  		list_add(&new_ns->list, &new_ns->root->mnt_list);
  	}
  	return new_ns;
  }
  EXPORT_SYMBOL(create_mnt_ns);
bdc480e3b   Heiko Carstens   [CVE-2009-0029] S...
2006
2007
  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
2008
  {
eca6f534e   Vegard Nossum   fs: fix overflow ...
2009
2010
2011
2012
  	int ret;
  	char *kernel_type;
  	char *kernel_dir;
  	char *kernel_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2013
  	unsigned long data_page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2014

eca6f534e   Vegard Nossum   fs: fix overflow ...
2015
2016
2017
  	ret = copy_mount_string(type, &kernel_type);
  	if (ret < 0)
  		goto out_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2018

eca6f534e   Vegard Nossum   fs: fix overflow ...
2019
2020
2021
2022
2023
  	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
2024

eca6f534e   Vegard Nossum   fs: fix overflow ...
2025
2026
2027
  	ret = copy_mount_string(dev_name, &kernel_dev);
  	if (ret < 0)
  		goto out_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2028

eca6f534e   Vegard Nossum   fs: fix overflow ...
2029
2030
2031
  	ret = copy_mount_options(data, &data_page);
  	if (ret < 0)
  		goto out_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2032

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

eca6f534e   Vegard Nossum   fs: fix overflow ...
2036
2037
2038
2039
2040
2041
2042
2043
2044
  	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
2045
2046
2047
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
   * 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...
2060
2061
2062
2063
   * 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
2064
2065
2066
2067
2068
2069
2070
2071
   * 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...
2072
2073
  SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
  		const char __user *, put_old)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2074
2075
  {
  	struct vfsmount *tmp;
2d8f30380   Al Viro   [PATCH] sanitize ...
2076
  	struct path new, old, parent_path, root_parent, root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2077
2078
2079
2080
  	int error;
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
2d8f30380   Al Viro   [PATCH] sanitize ...
2081
  	error = user_path_dir(new_root, &new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2082
2083
2084
  	if (error)
  		goto out0;
  	error = -EINVAL;
2d8f30380   Al Viro   [PATCH] sanitize ...
2085
  	if (!check_mnt(new.mnt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2086
  		goto out1;
2d8f30380   Al Viro   [PATCH] sanitize ...
2087
  	error = user_path_dir(put_old, &old);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2088
2089
  	if (error)
  		goto out1;
2d8f30380   Al Viro   [PATCH] sanitize ...
2090
  	error = security_sb_pivotroot(&old, &new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2091
  	if (error) {
2d8f30380   Al Viro   [PATCH] sanitize ...
2092
  		path_put(&old);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2093
2094
2095
2096
  		goto out1;
  	}
  
  	read_lock(&current->fs->lock);
8c3ee42e8   Al Viro   [PATCH] get rid o...
2097
  	root = current->fs->root;
6ac08c39a   Jan Blunck   Use struct path i...
2098
  	path_get(&current->fs->root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2099
  	read_unlock(&current->fs->lock);
390c68436   Ram Pai   [PATCH] making na...
2100
  	down_write(&namespace_sem);
2d8f30380   Al Viro   [PATCH] sanitize ...
2101
  	mutex_lock(&old.dentry->d_inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2102
  	error = -EINVAL;
2d8f30380   Al Viro   [PATCH] sanitize ...
2103
2104
  	if (IS_MNT_SHARED(old.mnt) ||
  		IS_MNT_SHARED(new.mnt->mnt_parent) ||
8c3ee42e8   Al Viro   [PATCH] get rid o...
2105
  		IS_MNT_SHARED(root.mnt->mnt_parent))
214444032   Ram Pai   [PATCH] shared mo...
2106
  		goto out2;
8c3ee42e8   Al Viro   [PATCH] get rid o...
2107
  	if (!check_mnt(root.mnt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2108
2109
  		goto out2;
  	error = -ENOENT;
2d8f30380   Al Viro   [PATCH] sanitize ...
2110
  	if (IS_DEADDIR(new.dentry->d_inode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2111
  		goto out2;
f3da392e9   Alexey Dobriyan   dcache: extrace a...
2112
  	if (d_unlinked(new.dentry))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2113
  		goto out2;
f3da392e9   Alexey Dobriyan   dcache: extrace a...
2114
  	if (d_unlinked(old.dentry))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2115
2116
  		goto out2;
  	error = -EBUSY;
2d8f30380   Al Viro   [PATCH] sanitize ...
2117
2118
  	if (new.mnt == root.mnt ||
  	    old.mnt == root.mnt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2119
2120
  		goto out2; /* loop, on the same file system  */
  	error = -EINVAL;
8c3ee42e8   Al Viro   [PATCH] get rid o...
2121
  	if (root.mnt->mnt_root != root.dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2122
  		goto out2; /* not a mountpoint */
8c3ee42e8   Al Viro   [PATCH] get rid o...
2123
  	if (root.mnt->mnt_parent == root.mnt)
0bb6fcc13   Miklos Szeredi   [PATCH] pivot_roo...
2124
  		goto out2; /* not attached */
2d8f30380   Al Viro   [PATCH] sanitize ...
2125
  	if (new.mnt->mnt_root != new.dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2126
  		goto out2; /* not a mountpoint */
2d8f30380   Al Viro   [PATCH] sanitize ...
2127
  	if (new.mnt->mnt_parent == new.mnt)
0bb6fcc13   Miklos Szeredi   [PATCH] pivot_roo...
2128
  		goto out2; /* not attached */
4ac913785   Jan Blunck   Embed a struct pa...
2129
  	/* make sure we can reach put_old from new_root */
2d8f30380   Al Viro   [PATCH] sanitize ...
2130
  	tmp = old.mnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2131
  	spin_lock(&vfsmount_lock);
2d8f30380   Al Viro   [PATCH] sanitize ...
2132
  	if (tmp != new.mnt) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2133
2134
2135
  		for (;;) {
  			if (tmp->mnt_parent == tmp)
  				goto out3; /* already mounted on put_old */
2d8f30380   Al Viro   [PATCH] sanitize ...
2136
  			if (tmp->mnt_parent == new.mnt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2137
2138
2139
  				break;
  			tmp = tmp->mnt_parent;
  		}
2d8f30380   Al Viro   [PATCH] sanitize ...
2140
  		if (!is_subdir(tmp->mnt_mountpoint, new.dentry))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2141
  			goto out3;
2d8f30380   Al Viro   [PATCH] sanitize ...
2142
  	} else if (!is_subdir(old.dentry, new.dentry))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2143
  		goto out3;
2d8f30380   Al Viro   [PATCH] sanitize ...
2144
  	detach_mnt(new.mnt, &parent_path);
8c3ee42e8   Al Viro   [PATCH] get rid o...
2145
  	detach_mnt(root.mnt, &root_parent);
4ac913785   Jan Blunck   Embed a struct pa...
2146
  	/* mount old root on put_old */
2d8f30380   Al Viro   [PATCH] sanitize ...
2147
  	attach_mnt(root.mnt, &old);
4ac913785   Jan Blunck   Embed a struct pa...
2148
  	/* mount new_root on / */
2d8f30380   Al Viro   [PATCH] sanitize ...
2149
  	attach_mnt(new.mnt, &root_parent);
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2150
  	touch_mnt_namespace(current->nsproxy->mnt_ns);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2151
  	spin_unlock(&vfsmount_lock);
2d8f30380   Al Viro   [PATCH] sanitize ...
2152
2153
  	chroot_fs_refs(&root, &new);
  	security_sb_post_pivotroot(&root, &new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2154
  	error = 0;
1a3906895   Al Viro   [PATCH] reduce st...
2155
2156
  	path_put(&root_parent);
  	path_put(&parent_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2157
  out2:
2d8f30380   Al Viro   [PATCH] sanitize ...
2158
  	mutex_unlock(&old.dentry->d_inode->i_mutex);
390c68436   Ram Pai   [PATCH] making na...
2159
  	up_write(&namespace_sem);
8c3ee42e8   Al Viro   [PATCH] get rid o...
2160
  	path_put(&root);
2d8f30380   Al Viro   [PATCH] sanitize ...
2161
  	path_put(&old);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2162
  out1:
2d8f30380   Al Viro   [PATCH] sanitize ...
2163
  	path_put(&new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2164
  out0:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2165
2166
2167
2168
2169
2170
2171
2172
2173
  	return error;
  out3:
  	spin_unlock(&vfsmount_lock);
  	goto out2;
  }
  
  static void __init init_mount_tree(void)
  {
  	struct vfsmount *mnt;
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2174
  	struct mnt_namespace *ns;
ac748a09f   Jan Blunck   Make set_fs_{root...
2175
  	struct path root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2176
2177
2178
2179
  
  	mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
  	if (IS_ERR(mnt))
  		panic("Can't create rootfs");
3b22edc57   Trond Myklebust   VFS: Switch init_...
2180
2181
  	ns = create_mnt_ns(mnt);
  	if (IS_ERR(ns))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2182
  		panic("Can't allocate initial namespace");
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2183
2184
2185
  
  	init_task.nsproxy->mnt_ns = ns;
  	get_mnt_ns(ns);
ac748a09f   Jan Blunck   Make set_fs_{root...
2186
2187
2188
2189
2190
  	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
2191
  }
74bf17cff   Denis Cheng   fs: remove the un...
2192
  void __init mnt_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2193
  {
13f14b4d8   Eric Dumazet   Use ilog2() in fs...
2194
  	unsigned u;
15a67dd8c   Randy Dunlap   [PATCH] fs/namesp...
2195
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2196

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

b58fed8b1   Ram Pai   [PATCH] lindent f...
2201
  	mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2202
2203
2204
2205
  
  	if (!mount_hashtable)
  		panic("Failed to allocate mount hash table
  ");
13f14b4d8   Eric Dumazet   Use ilog2() in fs...
2206
2207
2208
2209
2210
  	printk("Mount-cache hash table entries: %lu
  ", HASH_SIZE);
  
  	for (u = 0; u < HASH_SIZE; u++)
  		INIT_LIST_HEAD(&mount_hashtable[u]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2211

15a67dd8c   Randy Dunlap   [PATCH] fs/namesp...
2212
2213
2214
2215
  	err = sysfs_init();
  	if (err)
  		printk(KERN_WARNING "%s: sysfs_init error: %d
  ",
8e24eea72   Harvey Harrison   fs: replace remai...
2216
  			__func__, err);
00d266662   Greg Kroah-Hartman   kobject: convert ...
2217
2218
  	fs_kobj = kobject_create_and_add("fs", NULL);
  	if (!fs_kobj)
8e24eea72   Harvey Harrison   fs: replace remai...
2219
2220
  		printk(KERN_WARNING "%s: kobj create error
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2221
2222
2223
  	init_rootfs();
  	init_mount_tree();
  }
616511d03   Trond Myklebust   VFS: Uninline the...
2224
  void put_mnt_ns(struct mnt_namespace *ns)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2225
  {
616511d03   Trond Myklebust   VFS: Uninline the...
2226
  	struct vfsmount *root;
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
2227
  	LIST_HEAD(umount_list);
616511d03   Trond Myklebust   VFS: Uninline the...
2228
2229
2230
2231
  
  	if (!atomic_dec_and_lock(&ns->count, &vfsmount_lock))
  		return;
  	root = ns->root;
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2232
  	ns->root = NULL;
1ce88cf46   Miklos Szeredi   [PATCH] namespace...
2233
  	spin_unlock(&vfsmount_lock);
390c68436   Ram Pai   [PATCH] making na...
2234
  	down_write(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2235
  	spin_lock(&vfsmount_lock);
a05964f39   Ram Pai   [PATCH] shared mo...
2236
  	umount_tree(root, 0, &umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2237
  	spin_unlock(&vfsmount_lock);
390c68436   Ram Pai   [PATCH] making na...
2238
  	up_write(&namespace_sem);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
2239
  	release_mounts(&umount_list);
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2240
  	kfree(ns);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2241
  }
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2242
  EXPORT_SYMBOL(put_mnt_ns);