Blame view

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

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

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

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

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

d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
201
202
203
204
  #ifdef CONFIG_SMP
  out_free_devname:
  	kfree(mnt->mnt_devname);
  #endif
88b387824   Li Zefan   [PATCH] vfs: use ...
205
206
207
208
209
  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
210
  }
8366025eb   Dave Hansen   [PATCH] r/o bind ...
211
212
213
214
215
216
217
218
  /*
   * 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 ...
219
220
221
222
223
224
225
226
227
228
229
230
231
  /*
   * __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 ...
232
233
234
235
236
  	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 ...
237
238
  }
  EXPORT_SYMBOL_GPL(__mnt_is_readonly);
c6653a838   Nick Piggin   fs: rename vfsmou...
239
  static inline void mnt_inc_writers(struct vfsmount *mnt)
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
240
241
  {
  #ifdef CONFIG_SMP
b3e19d924   Nick Piggin   fs: scale mntget/...
242
  	this_cpu_inc(mnt->mnt_pcp->mnt_writers);
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
243
244
245
246
  #else
  	mnt->mnt_writers++;
  #endif
  }
3d733633a   Dave Hansen   [PATCH] r/o bind ...
247

c6653a838   Nick Piggin   fs: rename vfsmou...
248
  static inline void mnt_dec_writers(struct vfsmount *mnt)
3d733633a   Dave Hansen   [PATCH] r/o bind ...
249
  {
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
250
  #ifdef CONFIG_SMP
b3e19d924   Nick Piggin   fs: scale mntget/...
251
  	this_cpu_dec(mnt->mnt_pcp->mnt_writers);
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
252
253
254
  #else
  	mnt->mnt_writers--;
  #endif
3d733633a   Dave Hansen   [PATCH] r/o bind ...
255
  }
3d733633a   Dave Hansen   [PATCH] r/o bind ...
256

c6653a838   Nick Piggin   fs: rename vfsmou...
257
  static unsigned int mnt_get_writers(struct vfsmount *mnt)
3d733633a   Dave Hansen   [PATCH] r/o bind ...
258
  {
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
259
260
  #ifdef CONFIG_SMP
  	unsigned int count = 0;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
261
  	int cpu;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
262
263
  
  	for_each_possible_cpu(cpu) {
b3e19d924   Nick Piggin   fs: scale mntget/...
264
  		count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_writers;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
265
  	}
3d733633a   Dave Hansen   [PATCH] r/o bind ...
266

d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
267
268
269
270
  	return count;
  #else
  	return mnt->mnt_writers;
  #endif
3d733633a   Dave Hansen   [PATCH] r/o bind ...
271
272
273
274
275
276
277
278
279
280
  }
  
  /*
   * 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 ...
281
282
283
284
285
286
287
288
289
290
291
292
  /**
   * 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 ...
293
  	int ret = 0;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
294

d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
295
  	preempt_disable();
c6653a838   Nick Piggin   fs: rename vfsmou...
296
  	mnt_inc_writers(mnt);
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
297
  	/*
c6653a838   Nick Piggin   fs: rename vfsmou...
298
  	 * The store to mnt_inc_writers must be visible before we pass
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
299
300
301
302
303
304
305
306
307
308
309
310
  	 * 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 ...
311
  	if (__mnt_is_readonly(mnt)) {
c6653a838   Nick Piggin   fs: rename vfsmou...
312
  		mnt_dec_writers(mnt);
3d733633a   Dave Hansen   [PATCH] r/o bind ...
313
314
315
  		ret = -EROFS;
  		goto out;
  	}
3d733633a   Dave Hansen   [PATCH] r/o bind ...
316
  out:
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
317
  	preempt_enable();
3d733633a   Dave Hansen   [PATCH] r/o bind ...
318
  	return ret;
8366025eb   Dave Hansen   [PATCH] r/o bind ...
319
320
321
322
  }
  EXPORT_SYMBOL_GPL(mnt_want_write);
  
  /**
96029c4e0   npiggin@suse.de   fs: introduce mnt...
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
   * mnt_clone_write - get write access to a mount
   * @mnt: the mount on which to take a write
   *
   * This is effectively like mnt_want_write, except
   * it must only be used to take an extra write reference
   * on a mountpoint that we already know has a write reference
   * on it. This allows some optimisation.
   *
   * After finished, mnt_drop_write must be called as usual to
   * drop the reference.
   */
  int mnt_clone_write(struct vfsmount *mnt)
  {
  	/* superblock may be r/o */
  	if (__mnt_is_readonly(mnt))
  		return -EROFS;
  	preempt_disable();
c6653a838   Nick Piggin   fs: rename vfsmou...
340
  	mnt_inc_writers(mnt);
96029c4e0   npiggin@suse.de   fs: introduce mnt...
341
342
343
344
345
346
347
348
349
350
351
352
353
354
  	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...
355
356
  	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...
357
358
359
360
361
362
363
  		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 ...
364
365
366
367
368
369
370
371
372
   * 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...
373
  	preempt_disable();
c6653a838   Nick Piggin   fs: rename vfsmou...
374
  	mnt_dec_writers(mnt);
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
375
  	preempt_enable();
8366025eb   Dave Hansen   [PATCH] r/o bind ...
376
377
  }
  EXPORT_SYMBOL_GPL(mnt_drop_write);
2a79f17e4   Al Viro   vfs: mnt_drop_wri...
378
379
380
381
382
  void mnt_drop_write_file(struct file *file)
  {
  	mnt_drop_write(file->f_path.mnt);
  }
  EXPORT_SYMBOL(mnt_drop_write_file);
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
383
  static int mnt_make_readonly(struct vfsmount *mnt)
8366025eb   Dave Hansen   [PATCH] r/o bind ...
384
  {
3d733633a   Dave Hansen   [PATCH] r/o bind ...
385
  	int ret = 0;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
386
  	br_write_lock(vfsmount_lock);
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
387
  	mnt->mnt_flags |= MNT_WRITE_HOLD;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
388
  	/*
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
389
390
  	 * 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 ...
391
  	 */
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
392
  	smp_mb();
3d733633a   Dave Hansen   [PATCH] r/o bind ...
393
  	/*
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
394
395
396
397
398
399
400
401
402
403
404
405
406
407
  	 * 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 ...
408
  	 */
c6653a838   Nick Piggin   fs: rename vfsmou...
409
  	if (mnt_get_writers(mnt) > 0)
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
410
411
  		ret = -EBUSY;
  	else
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
412
  		mnt->mnt_flags |= MNT_READONLY;
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
413
414
415
416
417
418
  	/*
  	 * MNT_READONLY must become visible before ~MNT_WRITE_HOLD, so writers
  	 * that become unheld will see MNT_READONLY.
  	 */
  	smp_wmb();
  	mnt->mnt_flags &= ~MNT_WRITE_HOLD;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
419
  	br_write_unlock(vfsmount_lock);
3d733633a   Dave Hansen   [PATCH] r/o bind ...
420
  	return ret;
8366025eb   Dave Hansen   [PATCH] r/o bind ...
421
  }
8366025eb   Dave Hansen   [PATCH] r/o bind ...
422

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

5afe00221   Ram Pai   [PATCH] handling ...
673
674
675
676
  		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...
677
  		} else if (!(flag & CL_PRIVATE)) {
796a6b521   Al Viro   Kill CL_PROPAGATI...
678
  			if ((flag & CL_MAKE_SHARED) || IS_MNT_SHARED(old))
5afe00221   Ram Pai   [PATCH] handling ...
679
680
681
682
683
  				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...
684
685
  		if (flag & CL_MAKE_SHARED)
  			set_mnt_shared(mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
687
688
  
  		/* stick the duplicate mount on the same expiry list
  		 * as the original if that was on one */
36341f645   Ram Pai   [PATCH] mount exp...
689
  		if (flag & CL_EXPIRE) {
36341f645   Ram Pai   [PATCH] mount exp...
690
691
  			if (!list_empty(&old->mnt_expire))
  				list_add(&mnt->mnt_expire, &old->mnt_expire);
36341f645   Ram Pai   [PATCH] mount exp...
692
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
694
  	}
  	return mnt;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
695
696
697
698
  
   out_free:
  	free_vfsmnt(mnt);
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
  }
b3e19d924   Nick Piggin   fs: scale mntget/...
700
  static inline void mntfree(struct vfsmount *mnt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
702
  {
  	struct super_block *sb = mnt->mnt_sb;
b3e19d924   Nick Piggin   fs: scale mntget/...
703

3d733633a   Dave Hansen   [PATCH] r/o bind ...
704
  	/*
3d733633a   Dave Hansen   [PATCH] r/o bind ...
705
706
707
708
709
  	 * 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...
710
  	/*
b3e19d924   Nick Piggin   fs: scale mntget/...
711
712
  	 * The locking used to deal with mnt_count decrement provides barriers,
  	 * so mnt_get_writers() below is safe.
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
713
  	 */
c6653a838   Nick Piggin   fs: rename vfsmou...
714
  	WARN_ON(mnt_get_writers(mnt));
ca9c726ee   Andreas Gruenbacher   fsnotify: Infrast...
715
  	fsnotify_vfsmount_delete(mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
716
717
718
719
  	dput(mnt->mnt_root);
  	free_vfsmnt(mnt);
  	deactivate_super(sb);
  }
f03c65993   Al Viro   sanitize vfsmount...
720
  static void mntput_no_expire(struct vfsmount *mnt)
b3e19d924   Nick Piggin   fs: scale mntget/...
721
  {
b3e19d924   Nick Piggin   fs: scale mntget/...
722
  put_again:
f03c65993   Al Viro   sanitize vfsmount...
723
724
725
  #ifdef CONFIG_SMP
  	br_read_lock(vfsmount_lock);
  	if (likely(atomic_read(&mnt->mnt_longterm))) {
aa9c0e07b   Al Viro   vfs: kill pointle...
726
  		mnt_add_count(mnt, -1);
b3e19d924   Nick Piggin   fs: scale mntget/...
727
  		br_read_unlock(vfsmount_lock);
f03c65993   Al Viro   sanitize vfsmount...
728
  		return;
b3e19d924   Nick Piggin   fs: scale mntget/...
729
  	}
f03c65993   Al Viro   sanitize vfsmount...
730
  	br_read_unlock(vfsmount_lock);
b3e19d924   Nick Piggin   fs: scale mntget/...
731

99b7db7b8   Nick Piggin   fs: brlock vfsmou...
732
  	br_write_lock(vfsmount_lock);
aa9c0e07b   Al Viro   vfs: kill pointle...
733
  	mnt_add_count(mnt, -1);
b3e19d924   Nick Piggin   fs: scale mntget/...
734
  	if (mnt_get_count(mnt)) {
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
735
736
737
  		br_write_unlock(vfsmount_lock);
  		return;
  	}
b3e19d924   Nick Piggin   fs: scale mntget/...
738
  #else
aa9c0e07b   Al Viro   vfs: kill pointle...
739
  	mnt_add_count(mnt, -1);
b3e19d924   Nick Piggin   fs: scale mntget/...
740
  	if (likely(mnt_get_count(mnt)))
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
741
  		return;
b3e19d924   Nick Piggin   fs: scale mntget/...
742
  	br_write_lock(vfsmount_lock);
f03c65993   Al Viro   sanitize vfsmount...
743
  #endif
b3e19d924   Nick Piggin   fs: scale mntget/...
744
745
746
747
748
749
  	if (unlikely(mnt->mnt_pinned)) {
  		mnt_add_count(mnt, mnt->mnt_pinned + 1);
  		mnt->mnt_pinned = 0;
  		br_write_unlock(vfsmount_lock);
  		acct_auto_close_mnt(mnt);
  		goto put_again;
7b7b1ace2   Al Viro   [PATCH] saner han...
750
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
751
  	br_write_unlock(vfsmount_lock);
b3e19d924   Nick Piggin   fs: scale mntget/...
752
753
  	mntfree(mnt);
  }
b3e19d924   Nick Piggin   fs: scale mntget/...
754
755
756
757
758
759
760
  
  void mntput(struct vfsmount *mnt)
  {
  	if (mnt) {
  		/* avoid cacheline pingpong, hope gcc doesn't get "smart" */
  		if (unlikely(mnt->mnt_expiry_mark))
  			mnt->mnt_expiry_mark = 0;
f03c65993   Al Viro   sanitize vfsmount...
761
  		mntput_no_expire(mnt);
b3e19d924   Nick Piggin   fs: scale mntget/...
762
763
764
765
766
767
768
  	}
  }
  EXPORT_SYMBOL(mntput);
  
  struct vfsmount *mntget(struct vfsmount *mnt)
  {
  	if (mnt)
aa9c0e07b   Al Viro   vfs: kill pointle...
769
  		mnt_add_count(mnt, 1);
b3e19d924   Nick Piggin   fs: scale mntget/...
770
771
772
  	return mnt;
  }
  EXPORT_SYMBOL(mntget);
7b7b1ace2   Al Viro   [PATCH] saner han...
773
774
  void mnt_pin(struct vfsmount *mnt)
  {
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
775
  	br_write_lock(vfsmount_lock);
7b7b1ace2   Al Viro   [PATCH] saner han...
776
  	mnt->mnt_pinned++;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
777
  	br_write_unlock(vfsmount_lock);
7b7b1ace2   Al Viro   [PATCH] saner han...
778
  }
7b7b1ace2   Al Viro   [PATCH] saner han...
779
780
781
782
  EXPORT_SYMBOL(mnt_pin);
  
  void mnt_unpin(struct vfsmount *mnt)
  {
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
783
  	br_write_lock(vfsmount_lock);
7b7b1ace2   Al Viro   [PATCH] saner han...
784
  	if (mnt->mnt_pinned) {
aa9c0e07b   Al Viro   vfs: kill pointle...
785
  		mnt_add_count(mnt, 1);
7b7b1ace2   Al Viro   [PATCH] saner han...
786
787
  		mnt->mnt_pinned--;
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
788
  	br_write_unlock(vfsmount_lock);
7b7b1ace2   Al Viro   [PATCH] saner han...
789
  }
7b7b1ace2   Al Viro   [PATCH] saner han...
790
  EXPORT_SYMBOL(mnt_unpin);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791

b3b304a23   Miklos Szeredi   mount options: ad...
792
793
794
795
796
797
798
799
800
801
802
803
804
805
  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 ...
806
807
808
809
  	const char *options;
  
  	rcu_read_lock();
  	options = rcu_dereference(mnt->mnt_sb->s_options);
b3b304a23   Miklos Szeredi   mount options: ad...
810
811
812
813
814
  
  	if (options != NULL && options[0]) {
  		seq_putc(m, ',');
  		mangle(m, options);
  	}
2a32cebd6   Al Viro   Fix races around ...
815
  	rcu_read_unlock();
b3b304a23   Miklos Szeredi   mount options: ad...
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
  
  	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 ...
836
837
  	BUG_ON(sb->s_options);
  	rcu_assign_pointer(sb->s_options, kstrdup(options, GFP_KERNEL));
b3b304a23   Miklos Szeredi   mount options: ad...
838
839
  }
  EXPORT_SYMBOL(save_mount_options);
2a32cebd6   Al Viro   Fix races around ...
840
841
842
843
844
845
846
847
848
849
  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: ...
850
  #ifdef CONFIG_PROC_FS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
851
852
853
  /* iterator */
  static void *m_start(struct seq_file *m, loff_t *pos)
  {
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
854
  	struct proc_mounts *p = m->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
855

390c68436   Ram Pai   [PATCH] making na...
856
  	down_read(&namespace_sem);
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
857
  	return seq_list_start(&p->ns->list, *pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858
859
860
861
  }
  
  static void *m_next(struct seq_file *m, void *v, loff_t *pos)
  {
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
862
  	struct proc_mounts *p = m->private;
b0765fb85   Pavel Emelianov   Make /proc/self/m...
863

a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
864
  	return seq_list_next(v, &p->ns->list, pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865
866
867
868
  }
  
  static void m_stop(struct seq_file *m, void *v)
  {
390c68436   Ram Pai   [PATCH] making na...
869
  	up_read(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
870
  }
9f5596af4   Al Viro   take check for ne...
871
872
873
874
  int mnt_had_events(struct proc_mounts *p)
  {
  	struct mnt_namespace *ns = p->ns;
  	int res = 0;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
875
  	br_read_lock(vfsmount_lock);
f15146380   Kay Sievers   fs: seq_file - ad...
876
877
  	if (p->m.poll_event != ns->event) {
  		p->m.poll_event = ns->event;
9f5596af4   Al Viro   take check for ne...
878
879
  		res = 1;
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
880
  	br_read_unlock(vfsmount_lock);
9f5596af4   Al Viro   take check for ne...
881
882
883
  
  	return res;
  }
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
884
885
886
887
  struct proc_fs_info {
  	int flag;
  	const char *str;
  };
2069f4578   Eric Paris   LSM/SELinux: show...
888
  static int show_sb_opts(struct seq_file *m, struct super_block *sb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889
  {
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
890
  	static const struct proc_fs_info fs_info[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
891
892
893
  		{ MS_SYNCHRONOUS, ",sync" },
  		{ MS_DIRSYNC, ",dirsync" },
  		{ MS_MANDLOCK, ",mand" },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
895
  		{ 0, NULL }
  	};
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
896
897
898
899
900
901
  	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...
902
903
  
  	return security_sb_show_options(m, sb);
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
904
905
906
907
908
  }
  
  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
909
910
911
  		{ MNT_NOSUID, ",nosuid" },
  		{ MNT_NODEV, ",nodev" },
  		{ MNT_NOEXEC, ",noexec" },
fc33a7bb9   Christoph Hellwig   [PATCH] per-mount...
912
913
  		{ MNT_NOATIME, ",noatime" },
  		{ MNT_NODIRATIME, ",nodiratime" },
47ae32d6a   Valerie Henson   [PATCH] relative ...
914
  		{ MNT_RELATIME, ",relatime" },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
915
916
  		{ 0, NULL }
  	};
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
  	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_...
938
  	struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939

c7f404b40   Al Viro   vfs: new superblo...
940
941
942
943
944
945
946
  	if (mnt->mnt_sb->s_op->show_devname) {
  		err = mnt->mnt_sb->s_op->show_devname(m, mnt);
  		if (err)
  			goto out;
  	} else {
  		mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947
  	seq_putc(m, ' ');
c32c2f63a   Jan Blunck   d_path: Make seq_...
948
949
  	seq_path(m, &mnt_path, " \t
  \\");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
  	seq_putc(m, ' ');
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
951
  	show_type(m, mnt->mnt_sb);
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
952
  	seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw");
2069f4578   Eric Paris   LSM/SELinux: show...
953
954
955
  	err = show_sb_opts(m, mnt->mnt_sb);
  	if (err)
  		goto out;
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
956
  	show_mnt_opts(m, mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
958
959
960
  	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...
961
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
962
963
  	return err;
  }
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
964
  const struct seq_operations mounts_op = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
965
966
967
968
969
  	.start	= m_start,
  	.next	= m_next,
  	.stop	= m_stop,
  	.show	= show_vfsmnt
  };
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
970
971
972
973
974
975
976
977
978
979
980
  static int show_mountinfo(struct seq_file *m, void *v)
  {
  	struct proc_mounts *p = m->private;
  	struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list);
  	struct super_block *sb = mnt->mnt_sb;
  	struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
  	struct path root = p->root;
  	int err = 0;
  
  	seq_printf(m, "%i %i %u:%u ", mnt->mnt_id, mnt->mnt_parent->mnt_id,
  		   MAJOR(sb->s_dev), MINOR(sb->s_dev));
c7f404b40   Al Viro   vfs: new superblo...
981
982
983
984
985
986
987
  	if (sb->s_op->show_path)
  		err = sb->s_op->show_path(m, mnt);
  	else
  		seq_dentry(m, mnt->mnt_root, " \t
  \\");
  	if (err)
  		goto out;
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
988
  	seq_putc(m, ' ');
02125a826   Al Viro   fix apparmor dere...
989
990
991
992
993
994
  
  	/* mountpoints outside of chroot jail will give SEQ_SKIP on this */
  	err = seq_path_root(m, &mnt_path, &root, " \t
  \\");
  	if (err)
  		goto out;
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
995
996
997
998
999
1000
  	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: ...
1001
1002
1003
1004
1005
1006
1007
  	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: ...
1008
1009
1010
1011
1012
1013
1014
  	if (IS_MNT_UNBINDABLE(mnt))
  		seq_puts(m, " unbindable");
  
  	/* Filesystem specific data */
  	seq_puts(m, " - ");
  	show_type(m, sb);
  	seq_putc(m, ' ');
c7f404b40   Al Viro   vfs: new superblo...
1015
1016
1017
1018
1019
1020
  	if (sb->s_op->show_devname)
  		err = sb->s_op->show_devname(m, mnt);
  	else
  		mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
  	if (err)
  		goto out;
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
1021
  	seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw");
2069f4578   Eric Paris   LSM/SELinux: show...
1022
1023
1024
  	err = show_sb_opts(m, sb);
  	if (err)
  		goto out;
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
1025
1026
1027
1028
  	if (sb->s_op->show_options)
  		err = sb->s_op->show_options(m, mnt);
  	seq_putc(m, '
  ');
2069f4578   Eric Paris   LSM/SELinux: show...
1029
  out:
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
1030
1031
1032
1033
1034
1035
1036
1037
1038
  	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...
1039
1040
  static int show_vfsstat(struct seq_file *m, void *v)
  {
b0765fb85   Pavel Emelianov   Make /proc/self/m...
1041
  	struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list);
c32c2f63a   Jan Blunck   d_path: Make seq_...
1042
  	struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
b4629fe2f   Chuck Lever   VFS: New /proc fi...
1043
1044
1045
  	int err = 0;
  
  	/* device */
c7f404b40   Al Viro   vfs: new superblo...
1046
  	if (mnt->mnt_sb->s_op->show_devname) {
a877ee03a   Bryan Schumaker   vfs: add "device"...
1047
  		seq_puts(m, "device ");
c7f404b40   Al Viro   vfs: new superblo...
1048
1049
1050
1051
1052
1053
1054
1055
  		err = mnt->mnt_sb->s_op->show_devname(m, mnt);
  	} else {
  		if (mnt->mnt_devname) {
  			seq_puts(m, "device ");
  			mangle(m, mnt->mnt_devname);
  		} else
  			seq_puts(m, "no device");
  	}
b4629fe2f   Chuck Lever   VFS: New /proc fi...
1056
1057
1058
  
  	/* mount point */
  	seq_puts(m, " mounted on ");
c32c2f63a   Jan Blunck   d_path: Make seq_...
1059
1060
  	seq_path(m, &mnt_path, " \t
  \\");
b4629fe2f   Chuck Lever   VFS: New /proc fi...
1061
1062
1063
1064
  	seq_putc(m, ' ');
  
  	/* file system type */
  	seq_puts(m, "with fstype ");
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
1065
  	show_type(m, mnt->mnt_sb);
b4629fe2f   Chuck Lever   VFS: New /proc fi...
1066
1067
1068
1069
  
  	/* optional statistics */
  	if (mnt->mnt_sb->s_op->show_stats) {
  		seq_putc(m, ' ');
c7f404b40   Al Viro   vfs: new superblo...
1070
1071
  		if (!err)
  			err = mnt->mnt_sb->s_op->show_stats(m, mnt);
b4629fe2f   Chuck Lever   VFS: New /proc fi...
1072
1073
1074
1075
1076
1077
  	}
  
  	seq_putc(m, '
  ');
  	return err;
  }
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
1078
  const struct seq_operations mountstats_op = {
b4629fe2f   Chuck Lever   VFS: New /proc fi...
1079
1080
1081
1082
1083
  	.start	= m_start,
  	.next	= m_next,
  	.stop	= m_stop,
  	.show	= show_vfsstat,
  };
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
1084
  #endif  /* CONFIG_PROC_FS */
b4629fe2f   Chuck Lever   VFS: New /proc fi...
1085

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
  /**
   * 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...
1096
1097
1098
  	int actual_refs = 0;
  	int minimum_refs = 0;
  	struct vfsmount *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1099

b3e19d924   Nick Piggin   fs: scale mntget/...
1100
1101
  	/* write lock needed for mnt_get_count */
  	br_write_lock(vfsmount_lock);
36341f645   Ram Pai   [PATCH] mount exp...
1102
  	for (p = mnt; p; p = next_mnt(p, mnt)) {
b3e19d924   Nick Piggin   fs: scale mntget/...
1103
  		actual_refs += mnt_get_count(p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1104
  		minimum_refs += 2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1105
  	}
b3e19d924   Nick Piggin   fs: scale mntget/...
1106
  	br_write_unlock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1107
1108
  
  	if (actual_refs > minimum_refs)
e3474a8eb   Ian Kent   [PATCH] autofs4: ...
1109
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1110

e3474a8eb   Ian Kent   [PATCH] autofs4: ...
1111
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
  }
  
  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: ...
1131
  	int ret = 1;
8ad08d8a0   Al Viro   may_umount() need...
1132
  	down_read(&namespace_sem);
b3e19d924   Nick Piggin   fs: scale mntget/...
1133
  	br_write_lock(vfsmount_lock);
a05964f39   Ram Pai   [PATCH] shared mo...
1134
  	if (propagate_mount_busy(mnt, 2))
e3474a8eb   Ian Kent   [PATCH] autofs4: ...
1135
  		ret = 0;
b3e19d924   Nick Piggin   fs: scale mntget/...
1136
  	br_write_unlock(vfsmount_lock);
8ad08d8a0   Al Viro   may_umount() need...
1137
  	up_read(&namespace_sem);
a05964f39   Ram Pai   [PATCH] shared mo...
1138
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1139
1140
1141
  }
  
  EXPORT_SYMBOL(may_umount);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1142
  void release_mounts(struct list_head *head)
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1143
1144
  {
  	struct vfsmount *mnt;
bf066c7db   Miklos Szeredi   [PATCH] shared mo...
1145
  	while (!list_empty(head)) {
b5e618181   Pavel Emelianov   Introduce a handy...
1146
  		mnt = list_first_entry(head, struct vfsmount, mnt_hash);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1147
  		list_del_init(&mnt->mnt_hash);
b2dba1af3   Al Viro   vfs: new internal...
1148
  		if (mnt_has_parent(mnt)) {
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1149
1150
  			struct dentry *dentry;
  			struct vfsmount *m;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1151
1152
  
  			br_write_lock(vfsmount_lock);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1153
1154
1155
1156
  			dentry = mnt->mnt_mountpoint;
  			m = mnt->mnt_parent;
  			mnt->mnt_mountpoint = mnt->mnt_root;
  			mnt->mnt_parent = mnt;
7c4b93d82   Al Viro   [PATCH] count gho...
1157
  			m->mnt_ghosts--;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1158
  			br_write_unlock(vfsmount_lock);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1159
1160
1161
  			dput(dentry);
  			mntput(m);
  		}
f03c65993   Al Viro   sanitize vfsmount...
1162
  		mntput(mnt);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1163
1164
  	}
  }
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1165
1166
1167
1168
  /*
   * vfsmount lock must be held for write
   * namespace_sem must be held for write
   */
a05964f39   Ram Pai   [PATCH] shared mo...
1169
  void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1170
  {
7b8a53fd8   Al Viro   fix old umount_tr...
1171
  	LIST_HEAD(tmp_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1172
  	struct vfsmount *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1173

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

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

7b8a53fd8   Al Viro   fix old umount_tr...
1180
  	list_for_each_entry(p, &tmp_list, mnt_hash) {
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1181
1182
  		list_del_init(&p->mnt_expire);
  		list_del_init(&p->mnt_list);
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
1183
1184
  		__touch_mnt_namespace(p->mnt_ns);
  		p->mnt_ns = NULL;
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
1185
  		__mnt_make_shortterm(p);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1186
  		list_del_init(&p->mnt_child);
b2dba1af3   Al Viro   vfs: new internal...
1187
  		if (mnt_has_parent(p)) {
7c4b93d82   Al Viro   [PATCH] count gho...
1188
  			p->mnt_parent->mnt_ghosts++;
aa0a4cf0a   Al Viro   vfs: dentry_reset...
1189
  			dentry_reset_mounted(p->mnt_mountpoint);
7c4b93d82   Al Viro   [PATCH] count gho...
1190
  		}
a05964f39   Ram Pai   [PATCH] shared mo...
1191
  		change_mnt_propagation(p, MS_PRIVATE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1192
  	}
7b8a53fd8   Al Viro   fix old umount_tr...
1193
  	list_splice(&tmp_list, kill);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1194
  }
c35038bec   Al Viro   [PATCH] do shrink...
1195
  static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1196
1197
  static int do_umount(struct vfsmount *mnt, int flags)
  {
b58fed8b1   Ram Pai   [PATCH] lindent f...
1198
  	struct super_block *sb = mnt->mnt_sb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1199
  	int retval;
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1200
  	LIST_HEAD(umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
  
  	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...
1213
  		if (mnt == current->fs->root.mnt ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1214
1215
  		    flags & (MNT_FORCE | MNT_DETACH))
  			return -EINVAL;
b3e19d924   Nick Piggin   fs: scale mntget/...
1216
1217
1218
1219
1220
1221
  		/*
  		 * probably don't strictly need the lock here if we examined
  		 * all race cases, but it's a slowpath.
  		 */
  		br_write_lock(vfsmount_lock);
  		if (mnt_get_count(mnt) != 2) {
bf9faa2aa   J. R. Okajima   Unlock vfsmount_l...
1222
  			br_write_unlock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1223
  			return -EBUSY;
b3e19d924   Nick Piggin   fs: scale mntget/...
1224
1225
  		}
  		br_write_unlock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
  
  		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...
1240
  	if (flags & MNT_FORCE && sb->s_op->umount_begin) {
42faad996   Al Viro   [PATCH] restore s...
1241
  		sb->s_op->umount_begin(sb);
42faad996   Al Viro   [PATCH] restore s...
1242
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
  
  	/*
  	 * 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...
1253
  	if (mnt == current->fs->root.mnt && !(flags & MNT_DETACH)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1254
1255
1256
1257
1258
  		/*
  		 * Special case for "unmounting" root ...
  		 * we just try to remount it readonly.
  		 */
  		down_write(&sb->s_umount);
4aa98cf76   Al Viro   Push BKL down int...
1259
  		if (!(sb->s_flags & MS_RDONLY))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1260
  			retval = do_remount_sb(sb, MS_RDONLY, NULL, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1261
1262
1263
  		up_write(&sb->s_umount);
  		return retval;
  	}
390c68436   Ram Pai   [PATCH] making na...
1264
  	down_write(&namespace_sem);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1265
  	br_write_lock(vfsmount_lock);
5addc5dd8   Al Viro   [PATCH] make /pro...
1266
  	event++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1267

c35038bec   Al Viro   [PATCH] do shrink...
1268
1269
  	if (!(flags & MNT_DETACH))
  		shrink_submounts(mnt, &umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1270
  	retval = -EBUSY;
a05964f39   Ram Pai   [PATCH] shared mo...
1271
  	if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1272
  		if (!list_empty(&mnt->mnt_list))
a05964f39   Ram Pai   [PATCH] shared mo...
1273
  			umount_tree(mnt, 1, &umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1274
1275
  		retval = 0;
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1276
  	br_write_unlock(vfsmount_lock);
390c68436   Ram Pai   [PATCH] making na...
1277
  	up_write(&namespace_sem);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1278
  	release_mounts(&umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
  	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...
1289
  SYSCALL_DEFINE2(umount, char __user *, name, int, flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1290
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
1291
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1292
  	int retval;
db1f05bb8   Miklos Szeredi   vfs: add NOFOLLOW...
1293
  	int lookup_flags = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1294

db1f05bb8   Miklos Szeredi   vfs: add NOFOLLOW...
1295
1296
1297
1298
1299
1300
1301
  	if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW))
  		return -EINVAL;
  
  	if (!(flags & UMOUNT_NOFOLLOW))
  		lookup_flags |= LOOKUP_FOLLOW;
  
  	retval = user_path_at(AT_FDCWD, name, lookup_flags, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1302
1303
1304
  	if (retval)
  		goto out;
  	retval = -EINVAL;
2d8f30380   Al Viro   [PATCH] sanitize ...
1305
  	if (path.dentry != path.mnt->mnt_root)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1306
  		goto dput_and_out;
2d8f30380   Al Viro   [PATCH] sanitize ...
1307
  	if (!check_mnt(path.mnt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1308
1309
1310
1311
1312
  		goto dput_and_out;
  
  	retval = -EPERM;
  	if (!capable(CAP_SYS_ADMIN))
  		goto dput_and_out;
2d8f30380   Al Viro   [PATCH] sanitize ...
1313
  	retval = do_umount(path.mnt, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1314
  dput_and_out:
429731b15   Jan Blunck   Remove path_relea...
1315
  	/* we mustn't call path_put() as that would clear mnt_expiry_mark */
2d8f30380   Al Viro   [PATCH] sanitize ...
1316
1317
  	dput(path.dentry);
  	mntput_no_expire(path.mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1318
1319
1320
1321
1322
1323
1324
  out:
  	return retval;
  }
  
  #ifdef __ARCH_WANT_SYS_OLDUMOUNT
  
  /*
b58fed8b1   Ram Pai   [PATCH] lindent f...
1325
   *	The 2.0 compatible umount. No flags.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1326
   */
bdc480e3b   Heiko Carstens   [CVE-2009-0029] S...
1327
  SYSCALL_DEFINE1(oldumount, char __user *, name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1328
  {
b58fed8b1   Ram Pai   [PATCH] lindent f...
1329
  	return sys_umount(name, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1330
1331
1332
  }
  
  #endif
2d92ab3c6   Al Viro   [PATCH] finally g...
1333
  static int mount_is_safe(struct path *path)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1334
1335
1336
1337
1338
  {
  	if (capable(CAP_SYS_ADMIN))
  		return 0;
  	return -EPERM;
  #ifdef notyet
2d92ab3c6   Al Viro   [PATCH] finally g...
1339
  	if (S_ISLNK(path->dentry->d_inode->i_mode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1340
  		return -EPERM;
2d92ab3c6   Al Viro   [PATCH] finally g...
1341
  	if (path->dentry->d_inode->i_mode & S_ISVTX) {
da9592ede   David Howells   CRED: Wrap task c...
1342
  		if (current_uid() != path->dentry->d_inode->i_uid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1343
1344
  			return -EPERM;
  	}
2d92ab3c6   Al Viro   [PATCH] finally g...
1345
  	if (inode_permission(path->dentry->d_inode, MAY_WRITE))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1346
1347
1348
1349
  		return -EPERM;
  	return 0;
  #endif
  }
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1350
  struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry,
36341f645   Ram Pai   [PATCH] mount exp...
1351
  					int flag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1352
1353
  {
  	struct vfsmount *res, *p, *q, *r, *s;
1a3906895   Al Viro   [PATCH] reduce st...
1354
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1355

9676f0c63   Ram Pai   [PATCH] unbindabl...
1356
1357
  	if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(mnt))
  		return NULL;
36341f645   Ram Pai   [PATCH] mount exp...
1358
  	res = q = clone_mnt(mnt, dentry, flag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1359
1360
1361
1362
1363
  	if (!q)
  		goto Enomem;
  	q->mnt_mountpoint = mnt->mnt_mountpoint;
  
  	p = mnt;
fdadd65fb   Domen Puncer   [PATCH] janitor: ...
1364
  	list_for_each_entry(r, &mnt->mnt_mounts, mnt_child) {
7ec02ef15   Jan Blunck   vfs: remove lives...
1365
  		if (!is_subdir(r->mnt_mountpoint, dentry))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1366
1367
1368
  			continue;
  
  		for (s = r; s; s = next_mnt(s, r)) {
9676f0c63   Ram Pai   [PATCH] unbindabl...
1369
1370
1371
1372
  			if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(s)) {
  				s = skip_mnt_tree(s);
  				continue;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1373
1374
1375
1376
1377
  			while (p != s->mnt_parent) {
  				p = p->mnt_parent;
  				q = q->mnt_parent;
  			}
  			p = s;
1a3906895   Al Viro   [PATCH] reduce st...
1378
1379
  			path.mnt = q;
  			path.dentry = p->mnt_mountpoint;
36341f645   Ram Pai   [PATCH] mount exp...
1380
  			q = clone_mnt(p, p->mnt_root, flag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1381
1382
  			if (!q)
  				goto Enomem;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1383
  			br_write_lock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1384
  			list_add_tail(&q->mnt_list, &res->mnt_list);
1a3906895   Al Viro   [PATCH] reduce st...
1385
  			attach_mnt(q, &path);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1386
  			br_write_unlock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1387
1388
1389
  		}
  	}
  	return res;
b58fed8b1   Ram Pai   [PATCH] lindent f...
1390
  Enomem:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1391
  	if (res) {
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1392
  		LIST_HEAD(umount_list);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1393
  		br_write_lock(vfsmount_lock);
a05964f39   Ram Pai   [PATCH] shared mo...
1394
  		umount_tree(res, 0, &umount_list);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1395
  		br_write_unlock(vfsmount_lock);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1396
  		release_mounts(&umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1397
1398
1399
  	}
  	return NULL;
  }
589ff870e   Al Viro   Switch collect_mo...
1400
  struct vfsmount *collect_mounts(struct path *path)
8aec08094   Al Viro   [PATCH] new helpe...
1401
1402
  {
  	struct vfsmount *tree;
1a60a2807   Al Viro   [PATCH] lock excl...
1403
  	down_write(&namespace_sem);
589ff870e   Al Viro   Switch collect_mo...
1404
  	tree = copy_tree(path->mnt, path->dentry, CL_COPY_ALL | CL_PRIVATE);
1a60a2807   Al Viro   [PATCH] lock excl...
1405
  	up_write(&namespace_sem);
8aec08094   Al Viro   [PATCH] new helpe...
1406
1407
1408
1409
1410
1411
  	return tree;
  }
  
  void drop_collected_mounts(struct vfsmount *mnt)
  {
  	LIST_HEAD(umount_list);
1a60a2807   Al Viro   [PATCH] lock excl...
1412
  	down_write(&namespace_sem);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1413
  	br_write_lock(vfsmount_lock);
8aec08094   Al Viro   [PATCH] new helpe...
1414
  	umount_tree(mnt, 0, &umount_list);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1415
  	br_write_unlock(vfsmount_lock);
1a60a2807   Al Viro   [PATCH] lock excl...
1416
  	up_write(&namespace_sem);
8aec08094   Al Viro   [PATCH] new helpe...
1417
1418
  	release_mounts(&umount_list);
  }
1f707137b   Al Viro   new helper: itera...
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
  int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg,
  		   struct vfsmount *root)
  {
  	struct vfsmount *mnt;
  	int res = f(root, arg);
  	if (res)
  		return res;
  	list_for_each_entry(mnt, &root->mnt_list, mnt_list) {
  		res = f(mnt, arg);
  		if (res)
  			return res;
  	}
  	return 0;
  }
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
  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...
1459
1460
  /*
   *  @source_mnt : mount tree to be attached
214444032   Ram Pai   [PATCH] shared mo...
1461
1462
1463
1464
   *  @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...
1465
1466
1467
   *
   *  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...
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
   * ---------------------------------------------------------------------------
   * |         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...
1480
1481
1482
1483
1484
1485
1486
1487
1488
   * 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 ...
1489
1490
1491
1492
1493
1494
1495
   * (+++) 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...
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
   * ---------------------------------------------------------------------------
   * |         		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 ...
1508
1509
1510
   *
   * (+)  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...
1511
   * (+*)  the mount is moved to the destination.
5afe00221   Ram Pai   [PATCH] handling ...
1512
1513
1514
1515
   * (+++)  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...
1516
1517
1518
1519
1520
1521
1522
   *
   * 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...
1523
  			struct path *path, struct path *parent_path)
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1524
1525
  {
  	LIST_HEAD(tree_list);
1a3906895   Al Viro   [PATCH] reduce st...
1526
1527
  	struct vfsmount *dest_mnt = path->mnt;
  	struct dentry *dest_dentry = path->dentry;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1528
  	struct vfsmount *child, *p;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1529
  	int err;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1530

719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1531
1532
1533
1534
1535
1536
1537
1538
  	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...
1539

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

b90fa9ae8   Ram Pai   [PATCH] shared mo...
1542
1543
1544
1545
  	if (IS_MNT_SHARED(dest_mnt)) {
  		for (p = source_mnt; p; p = next_mnt(p, source_mnt))
  			set_mnt_shared(p);
  	}
1a3906895   Al Viro   [PATCH] reduce st...
1546
1547
1548
  	if (parent_path) {
  		detach_mnt(source_mnt, parent_path);
  		attach_mnt(source_mnt, path);
e5d67f071   Al Viro   Touch all affecte...
1549
  		touch_mnt_namespace(parent_path->mnt->mnt_ns);
214444032   Ram Pai   [PATCH] shared mo...
1550
1551
1552
1553
  	} else {
  		mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt);
  		commit_tree(source_mnt);
  	}
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1554
1555
1556
1557
1558
  
  	list_for_each_entry_safe(child, p, &tree_list, mnt_hash) {
  		list_del_init(&child->mnt_hash);
  		commit_tree(child);
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1559
  	br_write_unlock(vfsmount_lock);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1560
  	return 0;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1561
1562
1563
1564
1565
1566
  
   out_cleanup_ids:
  	if (IS_MNT_SHARED(dest_mnt))
  		cleanup_group_ids(source_mnt, NULL);
   out:
  	return err;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1567
  }
b12cea919   Al Viro   change the lockin...
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
  static int lock_mount(struct path *path)
  {
  	struct vfsmount *mnt;
  retry:
  	mutex_lock(&path->dentry->d_inode->i_mutex);
  	if (unlikely(cant_mount(path->dentry))) {
  		mutex_unlock(&path->dentry->d_inode->i_mutex);
  		return -ENOENT;
  	}
  	down_write(&namespace_sem);
  	mnt = lookup_mnt(path);
  	if (likely(!mnt))
  		return 0;
  	up_write(&namespace_sem);
  	mutex_unlock(&path->dentry->d_inode->i_mutex);
  	path_put(path);
  	path->mnt = mnt;
  	path->dentry = dget(mnt->mnt_root);
  	goto retry;
  }
  
  static void unlock_mount(struct path *path)
  {
  	up_write(&namespace_sem);
  	mutex_unlock(&path->dentry->d_inode->i_mutex);
  }
8c3ee42e8   Al Viro   [PATCH] get rid o...
1594
  static int graft_tree(struct vfsmount *mnt, struct path *path)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1595
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1596
1597
  	if (mnt->mnt_sb->s_flags & MS_NOUSER)
  		return -EINVAL;
8c3ee42e8   Al Viro   [PATCH] get rid o...
1598
  	if (S_ISDIR(path->dentry->d_inode->i_mode) !=
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1599
1600
  	      S_ISDIR(mnt->mnt_root->d_inode->i_mode))
  		return -ENOTDIR;
b12cea919   Al Viro   change the lockin...
1601
1602
  	if (d_unlinked(path->dentry))
  		return -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1603

b12cea919   Al Viro   change the lockin...
1604
  	return attach_recursive_mnt(mnt, path, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1605
1606
1607
  }
  
  /*
7a2e8a8fa   Valerie Aurora   VFS: Sanity check...
1608
1609
1610
1611
1612
   * Sanity check the flags to change_mnt_propagation.
   */
  
  static int flags_to_propagation_type(int flags)
  {
7c6e984df   Roman Borisov   fs/namespace.c: b...
1613
  	int type = flags & ~(MS_REC | MS_SILENT);
7a2e8a8fa   Valerie Aurora   VFS: Sanity check...
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
  
  	/* Fail if any non-propagation flags are set */
  	if (type & ~(MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
  		return 0;
  	/* Only one propagation flag should be set */
  	if (!is_power_of_2(type))
  		return 0;
  	return type;
  }
  
  /*
07b20889e   Ram Pai   [PATCH] beginning...
1625
1626
   * recursively change the type of the mountpoint.
   */
0a0d8a467   Al Viro   [PATCH] no need f...
1627
  static int do_change_type(struct path *path, int flag)
07b20889e   Ram Pai   [PATCH] beginning...
1628
  {
2d92ab3c6   Al Viro   [PATCH] finally g...
1629
  	struct vfsmount *m, *mnt = path->mnt;
07b20889e   Ram Pai   [PATCH] beginning...
1630
  	int recurse = flag & MS_REC;
7a2e8a8fa   Valerie Aurora   VFS: Sanity check...
1631
  	int type;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1632
  	int err = 0;
07b20889e   Ram Pai   [PATCH] beginning...
1633

ee6f95829   Miklos Szeredi   check privileges ...
1634
1635
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
2d92ab3c6   Al Viro   [PATCH] finally g...
1636
  	if (path->dentry != path->mnt->mnt_root)
07b20889e   Ram Pai   [PATCH] beginning...
1637
  		return -EINVAL;
7a2e8a8fa   Valerie Aurora   VFS: Sanity check...
1638
1639
1640
  	type = flags_to_propagation_type(flag);
  	if (!type)
  		return -EINVAL;
07b20889e   Ram Pai   [PATCH] beginning...
1641
  	down_write(&namespace_sem);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1642
1643
1644
1645
1646
  	if (type == MS_SHARED) {
  		err = invent_group_ids(mnt, recurse);
  		if (err)
  			goto out_unlock;
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1647
  	br_write_lock(vfsmount_lock);
07b20889e   Ram Pai   [PATCH] beginning...
1648
1649
  	for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL))
  		change_mnt_propagation(m, type);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1650
  	br_write_unlock(vfsmount_lock);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1651
1652
  
   out_unlock:
07b20889e   Ram Pai   [PATCH] beginning...
1653
  	up_write(&namespace_sem);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1654
  	return err;
07b20889e   Ram Pai   [PATCH] beginning...
1655
1656
1657
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1658
1659
   * do loopback mount.
   */
0a0d8a467   Al Viro   [PATCH] no need f...
1660
  static int do_loopback(struct path *path, char *old_name,
2dafe1c4d   Eric Sandeen   reduce large do_m...
1661
  				int recurse)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1662
  {
b12cea919   Al Viro   change the lockin...
1663
  	LIST_HEAD(umount_list);
2d92ab3c6   Al Viro   [PATCH] finally g...
1664
  	struct path old_path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1665
  	struct vfsmount *mnt = NULL;
2d92ab3c6   Al Viro   [PATCH] finally g...
1666
  	int err = mount_is_safe(path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1667
1668
1669
1670
  	if (err)
  		return err;
  	if (!old_name || !*old_name)
  		return -EINVAL;
815d405ce   Trond Myklebust   VFS: Fix the rema...
1671
  	err = kern_path(old_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1672
1673
  	if (err)
  		return err;
b12cea919   Al Viro   change the lockin...
1674
1675
1676
  	err = lock_mount(path);
  	if (err)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1677
  	err = -EINVAL;
2d92ab3c6   Al Viro   [PATCH] finally g...
1678
  	if (IS_MNT_UNBINDABLE(old_path.mnt))
b12cea919   Al Viro   change the lockin...
1679
  		goto out2;
9676f0c63   Ram Pai   [PATCH] unbindabl...
1680

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

ccd48bc7f   Al Viro   [PATCH] cleanups ...
1684
1685
  	err = -ENOMEM;
  	if (recurse)
2d92ab3c6   Al Viro   [PATCH] finally g...
1686
  		mnt = copy_tree(old_path.mnt, old_path.dentry, 0);
ccd48bc7f   Al Viro   [PATCH] cleanups ...
1687
  	else
2d92ab3c6   Al Viro   [PATCH] finally g...
1688
  		mnt = clone_mnt(old_path.mnt, old_path.dentry, 0);
ccd48bc7f   Al Viro   [PATCH] cleanups ...
1689
1690
  
  	if (!mnt)
b12cea919   Al Viro   change the lockin...
1691
  		goto out2;
ccd48bc7f   Al Viro   [PATCH] cleanups ...
1692

2d92ab3c6   Al Viro   [PATCH] finally g...
1693
  	err = graft_tree(mnt, path);
ccd48bc7f   Al Viro   [PATCH] cleanups ...
1694
  	if (err) {
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1695
  		br_write_lock(vfsmount_lock);
a05964f39   Ram Pai   [PATCH] shared mo...
1696
  		umount_tree(mnt, 0, &umount_list);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1697
  		br_write_unlock(vfsmount_lock);
5b83d2c5c   Ram Pai   [PATCH] sanitize ...
1698
  	}
b12cea919   Al Viro   change the lockin...
1699
1700
1701
  out2:
  	unlock_mount(path);
  	release_mounts(&umount_list);
ccd48bc7f   Al Viro   [PATCH] cleanups ...
1702
  out:
2d92ab3c6   Al Viro   [PATCH] finally g...
1703
  	path_put(&old_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1704
1705
  	return err;
  }
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
  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
1722
1723
1724
1725
1726
  /*
   * 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...
1727
  static int do_remount(struct path *path, int flags, int mnt_flags,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1728
1729
1730
  		      void *data)
  {
  	int err;
2d92ab3c6   Al Viro   [PATCH] finally g...
1731
  	struct super_block *sb = path->mnt->mnt_sb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1732
1733
1734
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
2d92ab3c6   Al Viro   [PATCH] finally g...
1735
  	if (!check_mnt(path->mnt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1736
  		return -EINVAL;
2d92ab3c6   Al Viro   [PATCH] finally g...
1737
  	if (path->dentry != path->mnt->mnt_root)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1738
  		return -EINVAL;
ff36fe2c8   Eric Paris   LSM: Pass -o remo...
1739
1740
1741
  	err = security_sb_remount(sb, data);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1742
  	down_write(&sb->s_umount);
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
1743
  	if (flags & MS_BIND)
2d92ab3c6   Al Viro   [PATCH] finally g...
1744
  		err = change_mount_flags(path->mnt, flags);
4aa98cf76   Al Viro   Push BKL down int...
1745
  	else
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
1746
  		err = do_remount_sb(sb, flags, data, 0);
7b43a79f3   Al Viro   mnt_flags fixes i...
1747
  	if (!err) {
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1748
  		br_write_lock(vfsmount_lock);
495d6c9c6   Valerie Aurora   VFS: Clean up sha...
1749
  		mnt_flags |= path->mnt->mnt_flags & MNT_PROPAGATION_MASK;
2d92ab3c6   Al Viro   [PATCH] finally g...
1750
  		path->mnt->mnt_flags = mnt_flags;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1751
  		br_write_unlock(vfsmount_lock);
7b43a79f3   Al Viro   mnt_flags fixes i...
1752
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1753
  	up_write(&sb->s_umount);
0e55a7cca   Dan Williams   [RFC PATCH] touch...
1754
  	if (!err) {
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1755
  		br_write_lock(vfsmount_lock);
0e55a7cca   Dan Williams   [RFC PATCH] touch...
1756
  		touch_mnt_namespace(path->mnt->mnt_ns);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1757
  		br_write_unlock(vfsmount_lock);
0e55a7cca   Dan Williams   [RFC PATCH] touch...
1758
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1759
1760
  	return err;
  }
9676f0c63   Ram Pai   [PATCH] unbindabl...
1761
1762
1763
1764
1765
1766
1767
1768
1769
  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...
1770
  static int do_move_mount(struct path *path, char *old_name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1771
  {
2d92ab3c6   Al Viro   [PATCH] finally g...
1772
  	struct path old_path, parent_path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1773
1774
1775
1776
1777
1778
  	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...
1779
  	err = kern_path(old_name, LOOKUP_FOLLOW, &old_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1780
1781
  	if (err)
  		return err;
b12cea919   Al Viro   change the lockin...
1782
  	err = lock_mount(path);
cc53ce53c   David Howells   Add a dentry op t...
1783
1784
  	if (err < 0)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1785
  	err = -EINVAL;
2d92ab3c6   Al Viro   [PATCH] finally g...
1786
  	if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1787
  		goto out1;
f3da392e9   Alexey Dobriyan   dcache: extrace a...
1788
  	if (d_unlinked(path->dentry))
214444032   Ram Pai   [PATCH] shared mo...
1789
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1790
1791
  
  	err = -EINVAL;
2d92ab3c6   Al Viro   [PATCH] finally g...
1792
  	if (old_path.dentry != old_path.mnt->mnt_root)
214444032   Ram Pai   [PATCH] shared mo...
1793
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1794

b2dba1af3   Al Viro   vfs: new internal...
1795
  	if (!mnt_has_parent(old_path.mnt))
214444032   Ram Pai   [PATCH] shared mo...
1796
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1797

2d92ab3c6   Al Viro   [PATCH] finally g...
1798
1799
  	if (S_ISDIR(path->dentry->d_inode->i_mode) !=
  	      S_ISDIR(old_path.dentry->d_inode->i_mode))
214444032   Ram Pai   [PATCH] shared mo...
1800
1801
1802
1803
  		goto out1;
  	/*
  	 * Don't move a mount residing in a shared parent.
  	 */
afac7cba7   Al Viro   vfs: more mnt_par...
1804
  	if (IS_MNT_SHARED(old_path.mnt->mnt_parent))
214444032   Ram Pai   [PATCH] shared mo...
1805
  		goto out1;
9676f0c63   Ram Pai   [PATCH] unbindabl...
1806
1807
1808
1809
  	/*
  	 * Don't move a mount tree containing unbindable mounts to a destination
  	 * mount which is shared.
  	 */
2d92ab3c6   Al Viro   [PATCH] finally g...
1810
1811
  	if (IS_MNT_SHARED(path->mnt) &&
  	    tree_contains_unbindable(old_path.mnt))
9676f0c63   Ram Pai   [PATCH] unbindabl...
1812
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1813
  	err = -ELOOP;
b2dba1af3   Al Viro   vfs: new internal...
1814
  	for (p = path->mnt; mnt_has_parent(p); p = p->mnt_parent)
2d92ab3c6   Al Viro   [PATCH] finally g...
1815
  		if (p == old_path.mnt)
214444032   Ram Pai   [PATCH] shared mo...
1816
  			goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1817

2d92ab3c6   Al Viro   [PATCH] finally g...
1818
  	err = attach_recursive_mnt(old_path.mnt, path, &parent_path);
4ac913785   Jan Blunck   Embed a struct pa...
1819
  	if (err)
214444032   Ram Pai   [PATCH] shared mo...
1820
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1821
1822
1823
  
  	/* if the mount is moved, it should no longer be expire
  	 * automatically */
2d92ab3c6   Al Viro   [PATCH] finally g...
1824
  	list_del_init(&old_path.mnt->mnt_expire);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1825
  out1:
b12cea919   Al Viro   change the lockin...
1826
  	unlock_mount(path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1827
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1828
  	if (!err)
1a3906895   Al Viro   [PATCH] reduce st...
1829
  		path_put(&parent_path);
2d92ab3c6   Al Viro   [PATCH] finally g...
1830
  	path_put(&old_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1831
1832
  	return err;
  }
9d412a43c   Al Viro   vfs: split off vf...
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
  static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype)
  {
  	int err;
  	const char *subtype = strchr(fstype, '.');
  	if (subtype) {
  		subtype++;
  		err = -EINVAL;
  		if (!subtype[0])
  			goto err;
  	} else
  		subtype = "";
  
  	mnt->mnt_sb->s_subtype = kstrdup(subtype, GFP_KERNEL);
  	err = -ENOMEM;
  	if (!mnt->mnt_sb->s_subtype)
  		goto err;
  	return mnt;
  
   err:
  	mntput(mnt);
  	return ERR_PTR(err);
  }
79e801a90   Al Viro   vfs: make do_kern...
1855
  static struct vfsmount *
9d412a43c   Al Viro   vfs: split off vf...
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
  do_kern_mount(const char *fstype, int flags, const char *name, void *data)
  {
  	struct file_system_type *type = get_fs_type(fstype);
  	struct vfsmount *mnt;
  	if (!type)
  		return ERR_PTR(-ENODEV);
  	mnt = vfs_kern_mount(type, flags, name, data);
  	if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
  	    !mnt->mnt_sb->s_subtype)
  		mnt = fs_set_subtype(mnt, fstype);
  	put_filesystem(type);
  	return mnt;
  }
9d412a43c   Al Viro   vfs: split off vf...
1869
1870
1871
1872
1873
1874
1875
1876
1877
  
  /*
   * add a mount into a namespace's mount tree
   */
  static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags)
  {
  	int err;
  
  	mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL);
b12cea919   Al Viro   change the lockin...
1878
1879
1880
  	err = lock_mount(path);
  	if (err)
  		return err;
9d412a43c   Al Viro   vfs: split off vf...
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
  
  	err = -EINVAL;
  	if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt))
  		goto unlock;
  
  	/* Refuse the same filesystem on the same mount point */
  	err = -EBUSY;
  	if (path->mnt->mnt_sb == newmnt->mnt_sb &&
  	    path->mnt->mnt_root == path->dentry)
  		goto unlock;
  
  	err = -EINVAL;
  	if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode))
  		goto unlock;
  
  	newmnt->mnt_flags = mnt_flags;
  	err = graft_tree(newmnt, path);
  
  unlock:
b12cea919   Al Viro   change the lockin...
1900
  	unlock_mount(path);
9d412a43c   Al Viro   vfs: split off vf...
1901
1902
  	return err;
  }
b1e75df45   Al Viro   tidy up around fi...
1903

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1904
1905
1906
1907
  /*
   * create a new mount for userspace and request it to be added into the
   * namespace's tree
   */
0a0d8a467   Al Viro   [PATCH] no need f...
1908
  static int do_new_mount(struct path *path, char *type, int flags,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1909
1910
1911
  			int mnt_flags, char *name, void *data)
  {
  	struct vfsmount *mnt;
15f9a3f3e   Al Viro   don't drop newmnt...
1912
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1913

eca6f534e   Vegard Nossum   fs: fix overflow ...
1914
  	if (!type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1915
1916
1917
1918
1919
1920
1921
1922
1923
  		return -EINVAL;
  
  	/* we need capabilities... */
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  
  	mnt = do_kern_mount(type, flags, name, data);
  	if (IS_ERR(mnt))
  		return PTR_ERR(mnt);
15f9a3f3e   Al Viro   don't drop newmnt...
1924
1925
1926
1927
  	err = do_add_mount(mnt, path, mnt_flags);
  	if (err)
  		mntput(mnt);
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1928
  }
19a167af7   Al Viro   Take the completi...
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
  int finish_automount(struct vfsmount *m, struct path *path)
  {
  	int err;
  	/* The new mount record should have at least 2 refs to prevent it being
  	 * expired before we get a chance to add it
  	 */
  	BUG_ON(mnt_get_count(m) < 2);
  
  	if (m->mnt_sb == path->mnt->mnt_sb &&
  	    m->mnt_root == path->dentry) {
b1e75df45   Al Viro   tidy up around fi...
1939
1940
  		err = -ELOOP;
  		goto fail;
19a167af7   Al Viro   Take the completi...
1941
  	}
19a167af7   Al Viro   Take the completi...
1942
  	err = do_add_mount(m, path, path->mnt->mnt_flags | MNT_SHRINKABLE);
b1e75df45   Al Viro   tidy up around fi...
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
  	if (!err)
  		return 0;
  fail:
  	/* remove m from any expiration list it may be on */
  	if (!list_empty(&m->mnt_expire)) {
  		down_write(&namespace_sem);
  		br_write_lock(vfsmount_lock);
  		list_del_init(&m->mnt_expire);
  		br_write_unlock(vfsmount_lock);
  		up_write(&namespace_sem);
19a167af7   Al Viro   Take the completi...
1953
  	}
b1e75df45   Al Viro   tidy up around fi...
1954
1955
  	mntput(m);
  	mntput(m);
19a167af7   Al Viro   Take the completi...
1956
1957
  	return err;
  }
ea5b778a8   David Howells   Unexport do_add_m...
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
  /**
   * mnt_set_expiry - Put a mount on an expiration list
   * @mnt: The mount to list.
   * @expiry_list: The list to add the mount to.
   */
  void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list)
  {
  	down_write(&namespace_sem);
  	br_write_lock(vfsmount_lock);
  
  	list_add_tail(&mnt->mnt_expire, expiry_list);
  
  	br_write_unlock(vfsmount_lock);
  	up_write(&namespace_sem);
  }
  EXPORT_SYMBOL(mnt_set_expiry);
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1976
1977
1978
1979
1980
1981
   * 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
1982
1983
  	struct vfsmount *mnt, *next;
  	LIST_HEAD(graveyard);
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
1984
  	LIST_HEAD(umounts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1985
1986
1987
  
  	if (list_empty(mounts))
  		return;
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
1988
  	down_write(&namespace_sem);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1989
  	br_write_lock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1990
1991
1992
1993
1994
1995
1996
  
  	/* 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...
1997
  	list_for_each_entry_safe(mnt, next, mounts, mnt_expire) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1998
  		if (!xchg(&mnt->mnt_expiry_mark, 1) ||
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
1999
  			propagate_mount_busy(mnt, 1))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2000
  			continue;
55e700b92   Miklos Szeredi   [PATCH] namespace...
2001
  		list_move(&mnt->mnt_expire, &graveyard);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2002
  	}
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
2003
2004
2005
2006
2007
  	while (!list_empty(&graveyard)) {
  		mnt = list_first_entry(&graveyard, struct vfsmount, mnt_expire);
  		touch_mnt_namespace(mnt->mnt_ns);
  		umount_tree(mnt, 1, &umounts);
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2008
  	br_write_unlock(vfsmount_lock);
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
2009
2010
2011
  	up_write(&namespace_sem);
  
  	release_mounts(&umounts);
5528f911b   Trond Myklebust   VFS: Add shrink_s...
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
  }
  
  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
2037
  			continue;
5528f911b   Trond Myklebust   VFS: Add shrink_s...
2038
2039
2040
2041
2042
2043
2044
  		/*
  		 * 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
2045

5528f911b   Trond Myklebust   VFS: Add shrink_s...
2046
  		if (!propagate_mount_busy(mnt, 1)) {
5528f911b   Trond Myklebust   VFS: Add shrink_s...
2047
2048
2049
  			list_move_tail(&mnt->mnt_expire, graveyard);
  			found++;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2050
  	}
5528f911b   Trond Myklebust   VFS: Add shrink_s...
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
  	/*
  	 * All done at this level ... ascend and resume the search
  	 */
  	if (this_parent != parent) {
  		next = this_parent->mnt_child.next;
  		this_parent = this_parent->mnt_parent;
  		goto resume;
  	}
  	return found;
  }
  
  /*
   * process a list of expirable mountpoints with the intent of discarding any
   * submounts of a specific parent mountpoint
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2065
2066
   *
   * vfsmount_lock must be held for write
5528f911b   Trond Myklebust   VFS: Add shrink_s...
2067
   */
c35038bec   Al Viro   [PATCH] do shrink...
2068
  static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts)
5528f911b   Trond Myklebust   VFS: Add shrink_s...
2069
2070
  {
  	LIST_HEAD(graveyard);
c35038bec   Al Viro   [PATCH] do shrink...
2071
  	struct vfsmount *m;
5528f911b   Trond Myklebust   VFS: Add shrink_s...
2072

5528f911b   Trond Myklebust   VFS: Add shrink_s...
2073
  	/* extract submounts of 'mountpoint' from the expiration list */
c35038bec   Al Viro   [PATCH] do shrink...
2074
  	while (select_submounts(mnt, &graveyard)) {
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
2075
  		while (!list_empty(&graveyard)) {
c35038bec   Al Viro   [PATCH] do shrink...
2076
  			m = list_first_entry(&graveyard, struct vfsmount,
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
2077
  						mnt_expire);
afef80b3d   Eric W. Biederman   vfs: fix shrink_s...
2078
2079
  			touch_mnt_namespace(m->mnt_ns);
  			umount_tree(m, 1, umounts);
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
2080
2081
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2082
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2083
2084
2085
2086
2087
2088
  /*
   * 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...
2089
2090
  static long exact_copy_from_user(void *to, const void __user * from,
  				 unsigned long n)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
  {
  	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...
2110
  int copy_mount_options(const void __user * data, unsigned long *where)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2111
2112
2113
2114
  {
  	int i;
  	unsigned long page;
  	unsigned long size;
b58fed8b1   Ram Pai   [PATCH] lindent f...
2115

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
  	*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...
2134
  		free_page(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2135
2136
2137
2138
2139
2140
2141
  		return -EFAULT;
  	}
  	if (i != PAGE_SIZE)
  		memset((char *)page + i, 0, PAGE_SIZE - i);
  	*where = page;
  	return 0;
  }
eca6f534e   Vegard Nossum   fs: fix overflow ...
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
  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
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
  /*
   * 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...
2172
  long do_mount(char *dev_name, char *dir_name, char *type_page,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2173
2174
  		  unsigned long flags, void *data_page)
  {
2d92ab3c6   Al Viro   [PATCH] finally g...
2175
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
  	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
2187
2188
2189
  
  	if (data_page)
  		((char *)data_page)[PAGE_SIZE - 1] = 0;
a27ab9f26   Tetsuo Handa   LSM: Pass origina...
2190
2191
2192
2193
2194
2195
2196
2197
2198
  	/* ... and get the mountpoint */
  	retval = kern_path(dir_name, LOOKUP_FOLLOW, &path);
  	if (retval)
  		return retval;
  
  	retval = security_sb_mount(dev_name, &path,
  				   type_page, flags, data_page);
  	if (retval)
  		goto dput_out;
613cbe3d4   Andi Kleen   Don't set relatim...
2199
2200
2201
  	/* Default to relatime unless overriden */
  	if (!(flags & MS_NOATIME))
  		mnt_flags |= MNT_RELATIME;
0a1c01c94   Matthew Garrett   Make relatime def...
2202

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2203
2204
2205
2206
2207
2208
2209
  	/* 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...
2210
2211
2212
2213
  	if (flags & MS_NOATIME)
  		mnt_flags |= MNT_NOATIME;
  	if (flags & MS_NODIRATIME)
  		mnt_flags |= MNT_NODIRATIME;
d0adde574   Matthew Garrett   Add a strictatime...
2214
2215
  	if (flags & MS_STRICTATIME)
  		mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME);
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
2216
2217
  	if (flags & MS_RDONLY)
  		mnt_flags |= MNT_READONLY;
fc33a7bb9   Christoph Hellwig   [PATCH] per-mount...
2218

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2223
  	if (flags & MS_REMOUNT)
2d92ab3c6   Al Viro   [PATCH] finally g...
2224
  		retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2225
2226
  				    data_page);
  	else if (flags & MS_BIND)
2d92ab3c6   Al Viro   [PATCH] finally g...
2227
  		retval = do_loopback(&path, dev_name, flags & MS_REC);
9676f0c63   Ram Pai   [PATCH] unbindabl...
2228
  	else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
2d92ab3c6   Al Viro   [PATCH] finally g...
2229
  		retval = do_change_type(&path, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2230
  	else if (flags & MS_MOVE)
2d92ab3c6   Al Viro   [PATCH] finally g...
2231
  		retval = do_move_mount(&path, dev_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2232
  	else
2d92ab3c6   Al Viro   [PATCH] finally g...
2233
  		retval = do_new_mount(&path, type_page, flags, mnt_flags,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2234
2235
  				      dev_name, data_page);
  dput_out:
2d92ab3c6   Al Viro   [PATCH] finally g...
2236
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2237
2238
  	return retval;
  }
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
  static struct mnt_namespace *alloc_mnt_ns(void)
  {
  	struct mnt_namespace *new_ns;
  
  	new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL);
  	if (!new_ns)
  		return ERR_PTR(-ENOMEM);
  	atomic_set(&new_ns->count, 1);
  	new_ns->root = NULL;
  	INIT_LIST_HEAD(&new_ns->list);
  	init_waitqueue_head(&new_ns->poll);
  	new_ns->event = 0;
  	return new_ns;
  }
f03c65993   Al Viro   sanitize vfsmount...
2253
2254
  void mnt_make_longterm(struct vfsmount *mnt)
  {
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
2255
  	__mnt_make_longterm(mnt);
f03c65993   Al Viro   sanitize vfsmount...
2256
2257
2258
2259
  }
  
  void mnt_make_shortterm(struct vfsmount *mnt)
  {
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
2260
  #ifdef CONFIG_SMP
f03c65993   Al Viro   sanitize vfsmount...
2261
2262
2263
2264
2265
  	if (atomic_add_unless(&mnt->mnt_longterm, -1, 1))
  		return;
  	br_write_lock(vfsmount_lock);
  	atomic_dec(&mnt->mnt_longterm);
  	br_write_unlock(vfsmount_lock);
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
2266
  #endif
f03c65993   Al Viro   sanitize vfsmount...
2267
  }
741a29513   JANAK DESAI   [PATCH] unshare s...
2268
2269
2270
2271
  /*
   * 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()...
2272
  static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2273
  		struct fs_struct *fs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2274
  {
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2275
  	struct mnt_namespace *new_ns;
7f2da1e7d   Al Viro   [PATCH] kill altroot
2276
  	struct vfsmount *rootmnt = NULL, *pwdmnt = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2277
  	struct vfsmount *p, *q;
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2278
2279
2280
  	new_ns = alloc_mnt_ns();
  	if (IS_ERR(new_ns))
  		return new_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2281

390c68436   Ram Pai   [PATCH] making na...
2282
  	down_write(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2283
  	/* First pass: copy the tree topology */
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2284
  	new_ns->root = copy_tree(mnt_ns->root, mnt_ns->root->mnt_root,
9676f0c63   Ram Pai   [PATCH] unbindabl...
2285
  					CL_COPY_ALL | CL_EXPIRE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2286
  	if (!new_ns->root) {
390c68436   Ram Pai   [PATCH] making na...
2287
  		up_write(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2288
  		kfree(new_ns);
5cc4a0341   Julia Lawall   fs/namespace.c: d...
2289
  		return ERR_PTR(-ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2290
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2291
  	br_write_lock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2292
  	list_add_tail(&new_ns->list, &new_ns->root->mnt_list);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2293
  	br_write_unlock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2294
2295
2296
2297
2298
2299
  
  	/*
  	 * 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...
2300
  	p = mnt_ns->root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2301
2302
  	q = new_ns->root;
  	while (p) {
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2303
  		q->mnt_ns = new_ns;
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
2304
  		__mnt_make_longterm(q);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2305
  		if (fs) {
6ac08c39a   Jan Blunck   Use struct path i...
2306
  			if (p == fs->root.mnt) {
f03c65993   Al Viro   sanitize vfsmount...
2307
  				fs->root.mnt = mntget(q);
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
2308
  				__mnt_make_longterm(q);
f03c65993   Al Viro   sanitize vfsmount...
2309
  				mnt_make_shortterm(p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2310
  				rootmnt = p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2311
  			}
6ac08c39a   Jan Blunck   Use struct path i...
2312
  			if (p == fs->pwd.mnt) {
f03c65993   Al Viro   sanitize vfsmount...
2313
  				fs->pwd.mnt = mntget(q);
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
2314
  				__mnt_make_longterm(q);
f03c65993   Al Viro   sanitize vfsmount...
2315
  				mnt_make_shortterm(p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2316
  				pwdmnt = p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2317
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2318
  		}
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2319
  		p = next_mnt(p, mnt_ns->root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2320
2321
  		q = next_mnt(q, new_ns->root);
  	}
390c68436   Ram Pai   [PATCH] making na...
2322
  	up_write(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2323

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2324
  	if (rootmnt)
f03c65993   Al Viro   sanitize vfsmount...
2325
  		mntput(rootmnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2326
  	if (pwdmnt)
f03c65993   Al Viro   sanitize vfsmount...
2327
  		mntput(pwdmnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2328

741a29513   JANAK DESAI   [PATCH] unshare s...
2329
2330
  	return new_ns;
  }
213dd266d   Eric W. Biederman   namespace: ensure...
2331
  struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
2332
  		struct fs_struct *new_fs)
741a29513   JANAK DESAI   [PATCH] unshare s...
2333
  {
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2334
  	struct mnt_namespace *new_ns;
741a29513   JANAK DESAI   [PATCH] unshare s...
2335

e3222c4ec   Badari Pulavarty   Merge sys_clone()...
2336
  	BUG_ON(!ns);
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2337
  	get_mnt_ns(ns);
741a29513   JANAK DESAI   [PATCH] unshare s...
2338
2339
  
  	if (!(flags & CLONE_NEWNS))
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
2340
  		return ns;
741a29513   JANAK DESAI   [PATCH] unshare s...
2341

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

6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2344
  	put_mnt_ns(ns);
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
2345
  	return new_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2346
  }
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2347
2348
2349
2350
  /**
   * create_mnt_ns - creates a private namespace and adds a root filesystem
   * @mnt: pointer to the new root filesystem mountpoint
   */
6c449c8df   Al Viro   unexport put_mnt_...
2351
  static struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt)
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2352
2353
2354
2355
2356
2357
  {
  	struct mnt_namespace *new_ns;
  
  	new_ns = alloc_mnt_ns();
  	if (!IS_ERR(new_ns)) {
  		mnt->mnt_ns = new_ns;
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
2358
  		__mnt_make_longterm(mnt);
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2359
2360
  		new_ns->root = mnt;
  		list_add(&new_ns->list, &new_ns->root->mnt_list);
c13344958   Al Viro   switch create_mnt...
2361
2362
  	} else {
  		mntput(mnt);
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2363
2364
2365
  	}
  	return new_ns;
  }
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2366

ea441d110   Al Viro   new helper: mount...
2367
2368
2369
  struct dentry *mount_subtree(struct vfsmount *mnt, const char *name)
  {
  	struct mnt_namespace *ns;
d31da0f0b   Al Viro   mount_subtree() p...
2370
  	struct super_block *s;
ea441d110   Al Viro   new helper: mount...
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
  	struct path path;
  	int err;
  
  	ns = create_mnt_ns(mnt);
  	if (IS_ERR(ns))
  		return ERR_CAST(ns);
  
  	err = vfs_path_lookup(mnt->mnt_root, mnt,
  			name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path);
  
  	put_mnt_ns(ns);
  
  	if (err)
  		return ERR_PTR(err);
  
  	/* trade a vfsmount reference for active sb one */
d31da0f0b   Al Viro   mount_subtree() p...
2387
2388
  	s = path.mnt->mnt_sb;
  	atomic_inc(&s->s_active);
ea441d110   Al Viro   new helper: mount...
2389
2390
  	mntput(path.mnt);
  	/* lock the sucker */
d31da0f0b   Al Viro   mount_subtree() p...
2391
  	down_write(&s->s_umount);
ea441d110   Al Viro   new helper: mount...
2392
2393
2394
2395
  	/* ... and return the root of (sub)tree on it */
  	return path.dentry;
  }
  EXPORT_SYMBOL(mount_subtree);
bdc480e3b   Heiko Carstens   [CVE-2009-0029] S...
2396
2397
  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
2398
  {
eca6f534e   Vegard Nossum   fs: fix overflow ...
2399
2400
2401
2402
  	int ret;
  	char *kernel_type;
  	char *kernel_dir;
  	char *kernel_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2403
  	unsigned long data_page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2404

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

eca6f534e   Vegard Nossum   fs: fix overflow ...
2409
2410
2411
2412
2413
  	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
2414

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

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

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

eca6f534e   Vegard Nossum   fs: fix overflow ...
2426
2427
2428
2429
2430
2431
2432
2433
2434
  	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
2435
2436
2437
  }
  
  /*
afac7cba7   Al Viro   vfs: more mnt_par...
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
   * Return true if path is reachable from root
   *
   * namespace_sem or vfsmount_lock is held
   */
  bool is_path_reachable(struct vfsmount *mnt, struct dentry *dentry,
  			 const struct path *root)
  {
  	while (mnt != root->mnt && mnt_has_parent(mnt)) {
  		dentry = mnt->mnt_mountpoint;
  		mnt = mnt->mnt_parent;
  	}
  	return mnt == root->mnt && is_subdir(dentry, root->dentry);
  }
  
  int path_is_under(struct path *path1, struct path *path2)
  {
  	int res;
  	br_read_lock(vfsmount_lock);
  	res = is_path_reachable(path1->mnt, path1->dentry, path2);
  	br_read_unlock(vfsmount_lock);
  	return res;
  }
  EXPORT_SYMBOL(path_is_under);
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
   * 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...
2475
2476
2477
2478
   * 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
2479
2480
2481
2482
2483
2484
2485
2486
   * 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...
2487
2488
  SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
  		const char __user *, put_old)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2489
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
2490
  	struct path new, old, parent_path, root_parent, root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2491
2492
2493
2494
  	int error;
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
2d8f30380   Al Viro   [PATCH] sanitize ...
2495
  	error = user_path_dir(new_root, &new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2496
2497
  	if (error)
  		goto out0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2498

2d8f30380   Al Viro   [PATCH] sanitize ...
2499
  	error = user_path_dir(put_old, &old);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2500
2501
  	if (error)
  		goto out1;
2d8f30380   Al Viro   [PATCH] sanitize ...
2502
  	error = security_sb_pivotroot(&old, &new);
b12cea919   Al Viro   change the lockin...
2503
2504
  	if (error)
  		goto out2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2505

f7ad3c6be   Miklos Szeredi   vfs: add helpers ...
2506
  	get_fs_root(current->fs, &root);
b12cea919   Al Viro   change the lockin...
2507
2508
2509
  	error = lock_mount(&old);
  	if (error)
  		goto out3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2510
  	error = -EINVAL;
2d8f30380   Al Viro   [PATCH] sanitize ...
2511
2512
  	if (IS_MNT_SHARED(old.mnt) ||
  		IS_MNT_SHARED(new.mnt->mnt_parent) ||
8c3ee42e8   Al Viro   [PATCH] get rid o...
2513
  		IS_MNT_SHARED(root.mnt->mnt_parent))
b12cea919   Al Viro   change the lockin...
2514
  		goto out4;
27cb1572e   Al Viro   fix deadlock in p...
2515
  	if (!check_mnt(root.mnt) || !check_mnt(new.mnt))
b12cea919   Al Viro   change the lockin...
2516
  		goto out4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2517
  	error = -ENOENT;
f3da392e9   Alexey Dobriyan   dcache: extrace a...
2518
  	if (d_unlinked(new.dentry))
b12cea919   Al Viro   change the lockin...
2519
  		goto out4;
f3da392e9   Alexey Dobriyan   dcache: extrace a...
2520
  	if (d_unlinked(old.dentry))
b12cea919   Al Viro   change the lockin...
2521
  		goto out4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2522
  	error = -EBUSY;
2d8f30380   Al Viro   [PATCH] sanitize ...
2523
2524
  	if (new.mnt == root.mnt ||
  	    old.mnt == root.mnt)
b12cea919   Al Viro   change the lockin...
2525
  		goto out4; /* loop, on the same file system  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2526
  	error = -EINVAL;
8c3ee42e8   Al Viro   [PATCH] get rid o...
2527
  	if (root.mnt->mnt_root != root.dentry)
b12cea919   Al Viro   change the lockin...
2528
  		goto out4; /* not a mountpoint */
b2dba1af3   Al Viro   vfs: new internal...
2529
  	if (!mnt_has_parent(root.mnt))
b12cea919   Al Viro   change the lockin...
2530
  		goto out4; /* not attached */
2d8f30380   Al Viro   [PATCH] sanitize ...
2531
  	if (new.mnt->mnt_root != new.dentry)
b12cea919   Al Viro   change the lockin...
2532
  		goto out4; /* not a mountpoint */
b2dba1af3   Al Viro   vfs: new internal...
2533
  	if (!mnt_has_parent(new.mnt))
b12cea919   Al Viro   change the lockin...
2534
  		goto out4; /* not attached */
4ac913785   Jan Blunck   Embed a struct pa...
2535
  	/* make sure we can reach put_old from new_root */
afac7cba7   Al Viro   vfs: more mnt_par...
2536
  	if (!is_path_reachable(old.mnt, old.dentry, &new))
b12cea919   Al Viro   change the lockin...
2537
  		goto out4;
27cb1572e   Al Viro   fix deadlock in p...
2538
  	br_write_lock(vfsmount_lock);
2d8f30380   Al Viro   [PATCH] sanitize ...
2539
  	detach_mnt(new.mnt, &parent_path);
8c3ee42e8   Al Viro   [PATCH] get rid o...
2540
  	detach_mnt(root.mnt, &root_parent);
4ac913785   Jan Blunck   Embed a struct pa...
2541
  	/* mount old root on put_old */
2d8f30380   Al Viro   [PATCH] sanitize ...
2542
  	attach_mnt(root.mnt, &old);
4ac913785   Jan Blunck   Embed a struct pa...
2543
  	/* mount new_root on / */
2d8f30380   Al Viro   [PATCH] sanitize ...
2544
  	attach_mnt(new.mnt, &root_parent);
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2545
  	touch_mnt_namespace(current->nsproxy->mnt_ns);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2546
  	br_write_unlock(vfsmount_lock);
2d8f30380   Al Viro   [PATCH] sanitize ...
2547
  	chroot_fs_refs(&root, &new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2548
  	error = 0;
b12cea919   Al Viro   change the lockin...
2549
2550
2551
2552
2553
2554
2555
  out4:
  	unlock_mount(&old);
  	if (!error) {
  		path_put(&root_parent);
  		path_put(&parent_path);
  	}
  out3:
8c3ee42e8   Al Viro   [PATCH] get rid o...
2556
  	path_put(&root);
b12cea919   Al Viro   change the lockin...
2557
  out2:
2d8f30380   Al Viro   [PATCH] sanitize ...
2558
  	path_put(&old);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2559
  out1:
2d8f30380   Al Viro   [PATCH] sanitize ...
2560
  	path_put(&new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2561
  out0:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2562
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2563
2564
2565
2566
2567
  }
  
  static void __init init_mount_tree(void)
  {
  	struct vfsmount *mnt;
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2568
  	struct mnt_namespace *ns;
ac748a09f   Jan Blunck   Make set_fs_{root...
2569
  	struct path root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2570
2571
2572
2573
  
  	mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
  	if (IS_ERR(mnt))
  		panic("Can't create rootfs");
b3e19d924   Nick Piggin   fs: scale mntget/...
2574

3b22edc57   Trond Myklebust   VFS: Switch init_...
2575
2576
  	ns = create_mnt_ns(mnt);
  	if (IS_ERR(ns))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2577
  		panic("Can't allocate initial namespace");
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2578
2579
2580
  
  	init_task.nsproxy->mnt_ns = ns;
  	get_mnt_ns(ns);
ac748a09f   Jan Blunck   Make set_fs_{root...
2581
2582
2583
2584
2585
  	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
2586
  }
74bf17cff   Denis Cheng   fs: remove the un...
2587
  void __init mnt_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2588
  {
13f14b4d8   Eric Dumazet   Use ilog2() in fs...
2589
  	unsigned u;
15a67dd8c   Randy Dunlap   [PATCH] fs/namesp...
2590
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2591

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

b58fed8b1   Ram Pai   [PATCH] lindent f...
2596
  	mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2597
2598
2599
2600
  
  	if (!mount_hashtable)
  		panic("Failed to allocate mount hash table
  ");
80cdc6dae   Mandeep Singh Baines   fs: use appropria...
2601
2602
  	printk(KERN_INFO "Mount-cache hash table entries: %lu
  ", HASH_SIZE);
13f14b4d8   Eric Dumazet   Use ilog2() in fs...
2603
2604
2605
  
  	for (u = 0; u < HASH_SIZE; u++)
  		INIT_LIST_HEAD(&mount_hashtable[u]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2606

99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2607
  	br_lock_init(vfsmount_lock);
15a67dd8c   Randy Dunlap   [PATCH] fs/namesp...
2608
2609
2610
2611
  	err = sysfs_init();
  	if (err)
  		printk(KERN_WARNING "%s: sysfs_init error: %d
  ",
8e24eea72   Harvey Harrison   fs: replace remai...
2612
  			__func__, err);
00d266662   Greg Kroah-Hartman   kobject: convert ...
2613
2614
  	fs_kobj = kobject_create_and_add("fs", NULL);
  	if (!fs_kobj)
8e24eea72   Harvey Harrison   fs: replace remai...
2615
2616
  		printk(KERN_WARNING "%s: kobj create error
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2617
2618
2619
  	init_rootfs();
  	init_mount_tree();
  }
616511d03   Trond Myklebust   VFS: Uninline the...
2620
  void put_mnt_ns(struct mnt_namespace *ns)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2621
  {
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
2622
  	LIST_HEAD(umount_list);
616511d03   Trond Myklebust   VFS: Uninline the...
2623

d498b25a4   Al Viro   get rid of useles...
2624
  	if (!atomic_dec_and_test(&ns->count))
616511d03   Trond Myklebust   VFS: Uninline the...
2625
  		return;
390c68436   Ram Pai   [PATCH] making na...
2626
  	down_write(&namespace_sem);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2627
  	br_write_lock(vfsmount_lock);
d498b25a4   Al Viro   get rid of useles...
2628
  	umount_tree(ns->root, 0, &umount_list);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2629
  	br_write_unlock(vfsmount_lock);
390c68436   Ram Pai   [PATCH] making na...
2630
  	up_write(&namespace_sem);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
2631
  	release_mounts(&umount_list);
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2632
  	kfree(ns);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2633
  }
9d412a43c   Al Viro   vfs: split off vf...
2634
2635
2636
  
  struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
  {
423e0ab08   Tim Chen   VFS : mount lock ...
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
  	struct vfsmount *mnt;
  	mnt = vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);
  	if (!IS_ERR(mnt)) {
  		/*
  		 * it is a longterm mount, don't release mnt until
  		 * we unmount before file sys is unregistered
  		*/
  		mnt_make_longterm(mnt);
  	}
  	return mnt;
9d412a43c   Al Viro   vfs: split off vf...
2647
2648
  }
  EXPORT_SYMBOL_GPL(kern_mount_data);
423e0ab08   Tim Chen   VFS : mount lock ...
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
  
  void kern_unmount(struct vfsmount *mnt)
  {
  	/* release long term mount so mount point can be released */
  	if (!IS_ERR_OR_NULL(mnt)) {
  		mnt_make_shortterm(mnt);
  		mntput(mnt);
  	}
  }
  EXPORT_SYMBOL(kern_unmount);
02125a826   Al Viro   fix apparmor dere...
2659
2660
2661
2662
2663
  
  bool our_mnt(struct vfsmount *mnt)
  {
  	return check_mnt(mnt);
  }