Blame view

fs/namespace.c 63.2 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
  /*
   *  linux/fs/namespace.c
   *
   * (C) Copyright Al Viro 2000, 2001
   *	Released under GPL v2.
   *
   * Based on code from fs/super.c, copyright Linus Torvalds and others.
   * Heavily rewritten.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
  #include <linux/syscalls.h>
d10577a8d   Al Viro   vfs: trim include...
11
  #include <linux/export.h>
16f7e0fe2   Randy Dunlap   [PATCH] capable/c...
12
  #include <linux/capability.h>
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
13
  #include <linux/mnt_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
  #include <linux/namei.h>
  #include <linux/security.h>
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
16
  #include <linux/idr.h>
d10577a8d   Al Viro   vfs: trim include...
17
18
19
20
21
  #include <linux/acct.h>		/* acct_auto_close_mnt */
  #include <linux/ramfs.h>	/* init_rootfs */
  #include <linux/fs_struct.h>	/* get_fs_root et.al. */
  #include <linux/fsnotify.h>	/* fsnotify_vfsmount_delete */
  #include <linux/uaccess.h>
07b20889e   Ram Pai   [PATCH] beginning...
22
  #include "pnode.h"
948730b0e   Adrian Bunk   fs/namespace.c sh...
23
  #include "internal.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24

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

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

f87fd4c2a   Miklos Szeredi   [PATCH] add /sys/fs
38
  /* /sys/fs */
00d266662   Greg Kroah-Hartman   kobject: convert ...
39
40
  struct kobject *fs_kobj;
  EXPORT_SYMBOL_GPL(fs_kobj);
f87fd4c2a   Miklos Szeredi   [PATCH] add /sys/fs
41

99b7db7b8   Nick Piggin   fs: brlock vfsmou...
42
43
44
45
46
47
48
49
50
  /*
   * 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
51
52
  static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
  {
b58fed8b1   Ram Pai   [PATCH] lindent f...
53
54
  	unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES);
  	tmp += ((unsigned long)dentry / L1_CACHE_BYTES);
13f14b4d8   Eric Dumazet   Use ilog2() in fs...
55
56
  	tmp = tmp + (tmp >> HASH_SHIFT);
  	return tmp & (HASH_SIZE - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
  }
3d733633a   Dave Hansen   [PATCH] r/o bind ...
58
  #define MNT_WRITER_UNDERFLOW_LIMIT -(1<<16)
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
59
60
61
62
  /*
   * allocation is serialized by namespace_sem, but we need the spinlock to
   * serialize with freeing.
   */
b105e270b   Al Viro   vfs: spread struc...
63
  static int mnt_alloc_id(struct mount *mnt)
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
64
65
66
67
68
  {
  	int res;
  
  retry:
  	ida_pre_get(&mnt_id_ida, GFP_KERNEL);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
69
  	spin_lock(&mnt_id_lock);
15169fe78   Al Viro   vfs: mnt_id/mnt_g...
70
  	res = ida_get_new_above(&mnt_id_ida, mnt_id_start, &mnt->mnt_id);
f21f62208   Al Viro   ... and the same ...
71
  	if (!res)
15169fe78   Al Viro   vfs: mnt_id/mnt_g...
72
  		mnt_id_start = mnt->mnt_id + 1;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
73
  	spin_unlock(&mnt_id_lock);
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
74
75
76
77
78
  	if (res == -EAGAIN)
  		goto retry;
  
  	return res;
  }
b105e270b   Al Viro   vfs: spread struc...
79
  static void mnt_free_id(struct mount *mnt)
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
80
  {
15169fe78   Al Viro   vfs: mnt_id/mnt_g...
81
  	int id = mnt->mnt_id;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
82
  	spin_lock(&mnt_id_lock);
f21f62208   Al Viro   ... and the same ...
83
84
85
  	ida_remove(&mnt_id_ida, id);
  	if (mnt_id_start > id)
  		mnt_id_start = id;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
86
  	spin_unlock(&mnt_id_lock);
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
87
  }
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
88
89
90
91
92
  /*
   * Allocate a new peer group ID
   *
   * mnt_group_ida is protected by namespace_sem
   */
4b8b21f4f   Al Viro   vfs: spread struc...
93
  static int mnt_alloc_group_id(struct mount *mnt)
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
94
  {
f21f62208   Al Viro   ... and the same ...
95
  	int res;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
96
97
  	if (!ida_pre_get(&mnt_group_ida, GFP_KERNEL))
  		return -ENOMEM;
f21f62208   Al Viro   ... and the same ...
98
99
  	res = ida_get_new_above(&mnt_group_ida,
  				mnt_group_start,
15169fe78   Al Viro   vfs: mnt_id/mnt_g...
100
  				&mnt->mnt_group_id);
f21f62208   Al Viro   ... and the same ...
101
  	if (!res)
15169fe78   Al Viro   vfs: mnt_id/mnt_g...
102
  		mnt_group_start = mnt->mnt_group_id + 1;
f21f62208   Al Viro   ... and the same ...
103
104
  
  	return res;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
105
106
107
108
109
  }
  
  /*
   * Release a peer group ID
   */
4b8b21f4f   Al Viro   vfs: spread struc...
110
  void mnt_release_group_id(struct mount *mnt)
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
111
  {
15169fe78   Al Viro   vfs: mnt_id/mnt_g...
112
  	int id = mnt->mnt_group_id;
f21f62208   Al Viro   ... and the same ...
113
114
115
  	ida_remove(&mnt_group_ida, id);
  	if (mnt_group_start > id)
  		mnt_group_start = id;
15169fe78   Al Viro   vfs: mnt_id/mnt_g...
116
  	mnt->mnt_group_id = 0;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
117
  }
b3e19d924   Nick Piggin   fs: scale mntget/...
118
119
120
  /*
   * vfsmount lock must be held for read
   */
83adc7532   Al Viro   vfs: spread struc...
121
  static inline void mnt_add_count(struct mount *mnt, int n)
b3e19d924   Nick Piggin   fs: scale mntget/...
122
123
  {
  #ifdef CONFIG_SMP
68e8a9fea   Al Viro   vfs: all counters...
124
  	this_cpu_add(mnt->mnt_pcp->mnt_count, n);
b3e19d924   Nick Piggin   fs: scale mntget/...
125
126
  #else
  	preempt_disable();
68e8a9fea   Al Viro   vfs: all counters...
127
  	mnt->mnt_count += n;
b3e19d924   Nick Piggin   fs: scale mntget/...
128
129
130
  	preempt_enable();
  #endif
  }
b3e19d924   Nick Piggin   fs: scale mntget/...
131
132
133
  /*
   * vfsmount lock must be held for write
   */
83adc7532   Al Viro   vfs: spread struc...
134
  unsigned int mnt_get_count(struct mount *mnt)
b3e19d924   Nick Piggin   fs: scale mntget/...
135
136
  {
  #ifdef CONFIG_SMP
f03c65993   Al Viro   sanitize vfsmount...
137
  	unsigned int count = 0;
b3e19d924   Nick Piggin   fs: scale mntget/...
138
139
140
  	int cpu;
  
  	for_each_possible_cpu(cpu) {
68e8a9fea   Al Viro   vfs: all counters...
141
  		count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_count;
b3e19d924   Nick Piggin   fs: scale mntget/...
142
143
144
145
  	}
  
  	return count;
  #else
68e8a9fea   Al Viro   vfs: all counters...
146
  	return mnt->mnt_count;
b3e19d924   Nick Piggin   fs: scale mntget/...
147
148
  #endif
  }
b105e270b   Al Viro   vfs: spread struc...
149
  static struct mount *alloc_vfsmnt(const char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
  {
c63181e6b   Al Viro   vfs: move fsnotif...
151
152
  	struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
  	if (mnt) {
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
153
  		int err;
c63181e6b   Al Viro   vfs: move fsnotif...
154
  		err = mnt_alloc_id(mnt);
88b387824   Li Zefan   [PATCH] vfs: use ...
155
156
157
158
  		if (err)
  			goto out_free_cache;
  
  		if (name) {
c63181e6b   Al Viro   vfs: move fsnotif...
159
160
  			mnt->mnt_devname = kstrdup(name, GFP_KERNEL);
  			if (!mnt->mnt_devname)
88b387824   Li Zefan   [PATCH] vfs: use ...
161
  				goto out_free_id;
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
162
  		}
b3e19d924   Nick Piggin   fs: scale mntget/...
163
  #ifdef CONFIG_SMP
c63181e6b   Al Viro   vfs: move fsnotif...
164
165
  		mnt->mnt_pcp = alloc_percpu(struct mnt_pcp);
  		if (!mnt->mnt_pcp)
b3e19d924   Nick Piggin   fs: scale mntget/...
166
  			goto out_free_devname;
c63181e6b   Al Viro   vfs: move fsnotif...
167
  		this_cpu_add(mnt->mnt_pcp->mnt_count, 1);
b3e19d924   Nick Piggin   fs: scale mntget/...
168
  #else
c63181e6b   Al Viro   vfs: move fsnotif...
169
170
  		mnt->mnt_count = 1;
  		mnt->mnt_writers = 0;
b3e19d924   Nick Piggin   fs: scale mntget/...
171
  #endif
c63181e6b   Al Viro   vfs: move fsnotif...
172
173
174
175
176
177
178
179
  		INIT_LIST_HEAD(&mnt->mnt_hash);
  		INIT_LIST_HEAD(&mnt->mnt_child);
  		INIT_LIST_HEAD(&mnt->mnt_mounts);
  		INIT_LIST_HEAD(&mnt->mnt_list);
  		INIT_LIST_HEAD(&mnt->mnt_expire);
  		INIT_LIST_HEAD(&mnt->mnt_share);
  		INIT_LIST_HEAD(&mnt->mnt_slave_list);
  		INIT_LIST_HEAD(&mnt->mnt_slave);
2504c5d63   Andreas Gruenbacher   fsnotify/vfsmount...
180
181
182
  #ifdef CONFIG_FSNOTIFY
  		INIT_HLIST_HEAD(&mnt->mnt_fsnotify_marks);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
  	}
c63181e6b   Al Viro   vfs: move fsnotif...
184
  	return mnt;
88b387824   Li Zefan   [PATCH] vfs: use ...
185

d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
186
187
  #ifdef CONFIG_SMP
  out_free_devname:
c63181e6b   Al Viro   vfs: move fsnotif...
188
  	kfree(mnt->mnt_devname);
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
189
  #endif
88b387824   Li Zefan   [PATCH] vfs: use ...
190
  out_free_id:
c63181e6b   Al Viro   vfs: move fsnotif...
191
  	mnt_free_id(mnt);
88b387824   Li Zefan   [PATCH] vfs: use ...
192
  out_free_cache:
c63181e6b   Al Viro   vfs: move fsnotif...
193
  	kmem_cache_free(mnt_cache, mnt);
88b387824   Li Zefan   [PATCH] vfs: use ...
194
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
  }
8366025eb   Dave Hansen   [PATCH] r/o bind ...
196
197
198
199
200
201
202
203
  /*
   * 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 ...
204
205
206
207
208
209
210
211
212
213
214
215
216
  /*
   * __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 ...
217
218
219
220
221
  	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 ...
222
223
  }
  EXPORT_SYMBOL_GPL(__mnt_is_readonly);
83adc7532   Al Viro   vfs: spread struc...
224
  static inline void mnt_inc_writers(struct mount *mnt)
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
225
226
  {
  #ifdef CONFIG_SMP
68e8a9fea   Al Viro   vfs: all counters...
227
  	this_cpu_inc(mnt->mnt_pcp->mnt_writers);
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
228
  #else
68e8a9fea   Al Viro   vfs: all counters...
229
  	mnt->mnt_writers++;
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
230
231
  #endif
  }
3d733633a   Dave Hansen   [PATCH] r/o bind ...
232

83adc7532   Al Viro   vfs: spread struc...
233
  static inline void mnt_dec_writers(struct mount *mnt)
3d733633a   Dave Hansen   [PATCH] r/o bind ...
234
  {
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
235
  #ifdef CONFIG_SMP
68e8a9fea   Al Viro   vfs: all counters...
236
  	this_cpu_dec(mnt->mnt_pcp->mnt_writers);
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
237
  #else
68e8a9fea   Al Viro   vfs: all counters...
238
  	mnt->mnt_writers--;
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
239
  #endif
3d733633a   Dave Hansen   [PATCH] r/o bind ...
240
  }
3d733633a   Dave Hansen   [PATCH] r/o bind ...
241

83adc7532   Al Viro   vfs: spread struc...
242
  static unsigned int mnt_get_writers(struct mount *mnt)
3d733633a   Dave Hansen   [PATCH] r/o bind ...
243
  {
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
244
245
  #ifdef CONFIG_SMP
  	unsigned int count = 0;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
246
  	int cpu;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
247
248
  
  	for_each_possible_cpu(cpu) {
68e8a9fea   Al Viro   vfs: all counters...
249
  		count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_writers;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
250
  	}
3d733633a   Dave Hansen   [PATCH] r/o bind ...
251

d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
252
253
254
255
  	return count;
  #else
  	return mnt->mnt_writers;
  #endif
3d733633a   Dave Hansen   [PATCH] r/o bind ...
256
  }
4ed5e82fe   Miklos Szeredi   vfs: protect remo...
257
258
259
260
261
262
263
264
  static int mnt_is_readonly(struct vfsmount *mnt)
  {
  	if (mnt->mnt_sb->s_readonly_remount)
  		return 1;
  	/* Order wrt setting s_flags/s_readonly_remount in do_remount() */
  	smp_rmb();
  	return __mnt_is_readonly(mnt);
  }
3d733633a   Dave Hansen   [PATCH] r/o bind ...
265
266
267
268
269
270
271
272
  /*
   * 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 ...
273
274
  /**
   * mnt_want_write - get write access to a mount
83adc7532   Al Viro   vfs: spread struc...
275
   * @m: the mount on which to take a write
8366025eb   Dave Hansen   [PATCH] r/o bind ...
276
277
278
279
280
281
282
   *
   * 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.
   */
83adc7532   Al Viro   vfs: spread struc...
283
  int mnt_want_write(struct vfsmount *m)
8366025eb   Dave Hansen   [PATCH] r/o bind ...
284
  {
83adc7532   Al Viro   vfs: spread struc...
285
  	struct mount *mnt = real_mount(m);
3d733633a   Dave Hansen   [PATCH] r/o bind ...
286
  	int ret = 0;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
287

d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
288
  	preempt_disable();
c6653a838   Nick Piggin   fs: rename vfsmou...
289
  	mnt_inc_writers(mnt);
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
290
  	/*
c6653a838   Nick Piggin   fs: rename vfsmou...
291
  	 * The store to mnt_inc_writers must be visible before we pass
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
292
293
294
295
  	 * MNT_WRITE_HOLD loop below, so that the slowpath can see our
  	 * incremented count after it has set MNT_WRITE_HOLD.
  	 */
  	smp_mb();
83adc7532   Al Viro   vfs: spread struc...
296
  	while (mnt->mnt.mnt_flags & MNT_WRITE_HOLD)
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
297
298
299
300
301
302
303
  		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();
4ed5e82fe   Miklos Szeredi   vfs: protect remo...
304
  	if (mnt_is_readonly(m)) {
c6653a838   Nick Piggin   fs: rename vfsmou...
305
  		mnt_dec_writers(mnt);
3d733633a   Dave Hansen   [PATCH] r/o bind ...
306
  		ret = -EROFS;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
307
  	}
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
308
  	preempt_enable();
3d733633a   Dave Hansen   [PATCH] r/o bind ...
309
  	return ret;
8366025eb   Dave Hansen   [PATCH] r/o bind ...
310
311
312
313
  }
  EXPORT_SYMBOL_GPL(mnt_want_write);
  
  /**
96029c4e0   npiggin@suse.de   fs: introduce mnt...
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
   * 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();
83adc7532   Al Viro   vfs: spread struc...
331
  	mnt_inc_writers(real_mount(mnt));
96029c4e0   npiggin@suse.de   fs: introduce mnt...
332
333
334
335
336
337
338
339
340
341
342
343
344
345
  	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...
346
347
  	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...
348
349
350
351
352
353
354
  		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 ...
355
356
357
358
359
360
361
362
363
   * 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...
364
  	preempt_disable();
83adc7532   Al Viro   vfs: spread struc...
365
  	mnt_dec_writers(real_mount(mnt));
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
366
  	preempt_enable();
8366025eb   Dave Hansen   [PATCH] r/o bind ...
367
368
  }
  EXPORT_SYMBOL_GPL(mnt_drop_write);
2a79f17e4   Al Viro   vfs: mnt_drop_wri...
369
370
371
372
373
  void mnt_drop_write_file(struct file *file)
  {
  	mnt_drop_write(file->f_path.mnt);
  }
  EXPORT_SYMBOL(mnt_drop_write_file);
83adc7532   Al Viro   vfs: spread struc...
374
  static int mnt_make_readonly(struct mount *mnt)
8366025eb   Dave Hansen   [PATCH] r/o bind ...
375
  {
3d733633a   Dave Hansen   [PATCH] r/o bind ...
376
  	int ret = 0;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
377
  	br_write_lock(vfsmount_lock);
83adc7532   Al Viro   vfs: spread struc...
378
  	mnt->mnt.mnt_flags |= MNT_WRITE_HOLD;
3d733633a   Dave Hansen   [PATCH] r/o bind ...
379
  	/*
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
380
381
  	 * 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 ...
382
  	 */
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
383
  	smp_mb();
3d733633a   Dave Hansen   [PATCH] r/o bind ...
384
  	/*
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
385
386
387
388
389
390
391
392
393
394
395
396
397
398
  	 * 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 ...
399
  	 */
c6653a838   Nick Piggin   fs: rename vfsmou...
400
  	if (mnt_get_writers(mnt) > 0)
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
401
402
  		ret = -EBUSY;
  	else
83adc7532   Al Viro   vfs: spread struc...
403
  		mnt->mnt.mnt_flags |= MNT_READONLY;
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
404
405
406
407
408
  	/*
  	 * MNT_READONLY must become visible before ~MNT_WRITE_HOLD, so writers
  	 * that become unheld will see MNT_READONLY.
  	 */
  	smp_wmb();
83adc7532   Al Viro   vfs: spread struc...
409
  	mnt->mnt.mnt_flags &= ~MNT_WRITE_HOLD;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
410
  	br_write_unlock(vfsmount_lock);
3d733633a   Dave Hansen   [PATCH] r/o bind ...
411
  	return ret;
8366025eb   Dave Hansen   [PATCH] r/o bind ...
412
  }
8366025eb   Dave Hansen   [PATCH] r/o bind ...
413

83adc7532   Al Viro   vfs: spread struc...
414
  static void __mnt_unmake_readonly(struct mount *mnt)
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
415
  {
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
416
  	br_write_lock(vfsmount_lock);
83adc7532   Al Viro   vfs: spread struc...
417
  	mnt->mnt.mnt_flags &= ~MNT_READONLY;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
418
  	br_write_unlock(vfsmount_lock);
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
419
  }
4ed5e82fe   Miklos Szeredi   vfs: protect remo...
420
421
422
423
  int sb_prepare_remount_readonly(struct super_block *sb)
  {
  	struct mount *mnt;
  	int err = 0;
8e8b87964   Miklos Szeredi   vfs: prevent remo...
424
425
426
  	/* Racy optimization.  Recheck the counter under MNT_WRITE_HOLD */
  	if (atomic_long_read(&sb->s_remove_count))
  		return -EBUSY;
4ed5e82fe   Miklos Szeredi   vfs: protect remo...
427
428
429
430
431
432
433
434
435
436
437
  	br_write_lock(vfsmount_lock);
  	list_for_each_entry(mnt, &sb->s_mounts, mnt_instance) {
  		if (!(mnt->mnt.mnt_flags & MNT_READONLY)) {
  			mnt->mnt.mnt_flags |= MNT_WRITE_HOLD;
  			smp_mb();
  			if (mnt_get_writers(mnt) > 0) {
  				err = -EBUSY;
  				break;
  			}
  		}
  	}
8e8b87964   Miklos Szeredi   vfs: prevent remo...
438
439
  	if (!err && atomic_long_read(&sb->s_remove_count))
  		err = -EBUSY;
4ed5e82fe   Miklos Szeredi   vfs: protect remo...
440
441
442
443
444
445
446
447
448
449
450
451
  	if (!err) {
  		sb->s_readonly_remount = 1;
  		smp_wmb();
  	}
  	list_for_each_entry(mnt, &sb->s_mounts, mnt_instance) {
  		if (mnt->mnt.mnt_flags & MNT_WRITE_HOLD)
  			mnt->mnt.mnt_flags &= ~MNT_WRITE_HOLD;
  	}
  	br_write_unlock(vfsmount_lock);
  
  	return err;
  }
b105e270b   Al Viro   vfs: spread struc...
452
  static void free_vfsmnt(struct mount *mnt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
  {
52ba1621d   Al Viro   vfs: move mnt_dev...
454
  	kfree(mnt->mnt_devname);
73cd49ecd   Miklos Szeredi   [patch 3/7] vfs: ...
455
  	mnt_free_id(mnt);
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
456
  #ifdef CONFIG_SMP
68e8a9fea   Al Viro   vfs: all counters...
457
  	free_percpu(mnt->mnt_pcp);
d3ef3d735   npiggin@suse.de   fs: mnt_want_writ...
458
  #endif
b105e270b   Al Viro   vfs: spread struc...
459
  	kmem_cache_free(mnt_cache, mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
461
462
  }
  
  /*
a05964f39   Ram Pai   [PATCH] shared mo...
463
464
   * 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...
465
   * vfsmount_lock must be held for read or write.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
   */
c71053659   Al Viro   vfs: spread struc...
467
  struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry,
a05964f39   Ram Pai   [PATCH] shared mo...
468
  			      int dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
  {
b58fed8b1   Ram Pai   [PATCH] lindent f...
470
471
  	struct list_head *head = mount_hashtable + hash(mnt, dentry);
  	struct list_head *tmp = head;
c71053659   Al Viro   vfs: spread struc...
472
  	struct mount *p, *found = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
  	for (;;) {
a05964f39   Ram Pai   [PATCH] shared mo...
475
  		tmp = dir ? tmp->next : tmp->prev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
477
478
  		p = NULL;
  		if (tmp == head)
  			break;
1b8e5564b   Al Viro   vfs: the first sp...
479
  		p = list_entry(tmp, struct mount, mnt_hash);
a73324da7   Al Viro   vfs: move mnt_mou...
480
  		if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry) {
a05964f39   Ram Pai   [PATCH] shared mo...
481
  			found = p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
484
  			break;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
486
  	return found;
  }
a05964f39   Ram Pai   [PATCH] shared mo...
487
488
489
490
  /*
   * lookup_mnt increments the ref count before returning
   * the vfsmount struct.
   */
1c755af4d   Al Viro   switch lookup_mnt()
491
  struct vfsmount *lookup_mnt(struct path *path)
a05964f39   Ram Pai   [PATCH] shared mo...
492
  {
c71053659   Al Viro   vfs: spread struc...
493
  	struct mount *child_mnt;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
494
495
  
  	br_read_lock(vfsmount_lock);
c71053659   Al Viro   vfs: spread struc...
496
497
498
499
500
501
502
503
504
  	child_mnt = __lookup_mnt(path->mnt, path->dentry, 1);
  	if (child_mnt) {
  		mnt_add_count(child_mnt, 1);
  		br_read_unlock(vfsmount_lock);
  		return &child_mnt->mnt;
  	} else {
  		br_read_unlock(vfsmount_lock);
  		return NULL;
  	}
a05964f39   Ram Pai   [PATCH] shared mo...
505
  }
143c8c91c   Al Viro   vfs: mnt_ns moved...
506
  static inline int check_mnt(struct mount *mnt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
  {
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
508
  	return mnt->mnt_ns == current->nsproxy->mnt_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
  }
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
510
511
512
  /*
   * vfsmount lock must be held for write
   */
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
513
  static void touch_mnt_namespace(struct mnt_namespace *ns)
5addc5dd8   Al Viro   [PATCH] make /pro...
514
515
516
517
518
519
  {
  	if (ns) {
  		ns->event = ++event;
  		wake_up_interruptible(&ns->poll);
  	}
  }
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
520
521
522
  /*
   * vfsmount lock must be held for write
   */
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
523
  static void __touch_mnt_namespace(struct mnt_namespace *ns)
5addc5dd8   Al Viro   [PATCH] make /pro...
524
525
526
527
528
529
  {
  	if (ns && ns->event != event) {
  		ns->event = event;
  		wake_up_interruptible(&ns->poll);
  	}
  }
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
530
  /*
5f57cbcc0   Nick Piggin   fs: dcache remove...
531
532
533
   * Clear dentry's mounted state if it has no remaining mounts.
   * vfsmount_lock must be held for write.
   */
aa0a4cf0a   Al Viro   vfs: dentry_reset...
534
  static void dentry_reset_mounted(struct dentry *dentry)
5f57cbcc0   Nick Piggin   fs: dcache remove...
535
536
537
538
  {
  	unsigned u;
  
  	for (u = 0; u < HASH_SIZE; u++) {
d5e50f74d   Al Viro   vfs: spread struc...
539
  		struct mount *p;
5f57cbcc0   Nick Piggin   fs: dcache remove...
540

1b8e5564b   Al Viro   vfs: the first sp...
541
  		list_for_each_entry(p, &mount_hashtable[u], mnt_hash) {
a73324da7   Al Viro   vfs: move mnt_mou...
542
  			if (p->mnt_mountpoint == dentry)
5f57cbcc0   Nick Piggin   fs: dcache remove...
543
544
545
546
547
548
549
550
551
  				return;
  		}
  	}
  	spin_lock(&dentry->d_lock);
  	dentry->d_flags &= ~DCACHE_MOUNTED;
  	spin_unlock(&dentry->d_lock);
  }
  
  /*
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
552
553
   * vfsmount lock must be held for write
   */
419148da6   Al Viro   vfs: spread struc...
554
555
  static void detach_mnt(struct mount *mnt, struct path *old_path)
  {
a73324da7   Al Viro   vfs: move mnt_mou...
556
  	old_path->dentry = mnt->mnt_mountpoint;
0714a5338   Al Viro   vfs: now it can b...
557
558
  	old_path->mnt = &mnt->mnt_parent->mnt;
  	mnt->mnt_parent = mnt;
a73324da7   Al Viro   vfs: move mnt_mou...
559
  	mnt->mnt_mountpoint = mnt->mnt.mnt_root;
6b41d536f   Al Viro   vfs: take mnt_chi...
560
  	list_del_init(&mnt->mnt_child);
1b8e5564b   Al Viro   vfs: the first sp...
561
  	list_del_init(&mnt->mnt_hash);
aa0a4cf0a   Al Viro   vfs: dentry_reset...
562
  	dentry_reset_mounted(old_path->dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
  }
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
564
565
566
  /*
   * vfsmount lock must be held for write
   */
14cf1fa8f   Al Viro   vfs: spread struc...
567
  void mnt_set_mountpoint(struct mount *mnt, struct dentry *dentry,
44d964d60   Al Viro   vfs: spread struc...
568
  			struct mount *child_mnt)
b90fa9ae8   Ram Pai   [PATCH] shared mo...
569
  {
3a2393d71   Al Viro   vfs: opencode mnt...
570
  	mnt_add_count(mnt, 1);	/* essentially, that's mntget */
a73324da7   Al Viro   vfs: move mnt_mou...
571
  	child_mnt->mnt_mountpoint = dget(dentry);
3a2393d71   Al Viro   vfs: opencode mnt...
572
  	child_mnt->mnt_parent = mnt;
5f57cbcc0   Nick Piggin   fs: dcache remove...
573
574
575
  	spin_lock(&dentry->d_lock);
  	dentry->d_flags |= DCACHE_MOUNTED;
  	spin_unlock(&dentry->d_lock);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
576
  }
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
577
578
579
  /*
   * vfsmount lock must be held for write
   */
419148da6   Al Viro   vfs: spread struc...
580
  static void attach_mnt(struct mount *mnt, struct path *path)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581
  {
14cf1fa8f   Al Viro   vfs: spread struc...
582
  	mnt_set_mountpoint(real_mount(path->mnt), path->dentry, mnt);
1b8e5564b   Al Viro   vfs: the first sp...
583
  	list_add_tail(&mnt->mnt_hash, mount_hashtable +
1a3906895   Al Viro   [PATCH] reduce st...
584
  			hash(path->mnt, path->dentry));
6b41d536f   Al Viro   vfs: take mnt_chi...
585
  	list_add_tail(&mnt->mnt_child, &real_mount(path->mnt)->mnt_mounts);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
586
  }
83adc7532   Al Viro   vfs: spread struc...
587
  static inline void __mnt_make_longterm(struct mount *mnt)
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
588
589
  {
  #ifdef CONFIG_SMP
68e8a9fea   Al Viro   vfs: all counters...
590
  	atomic_inc(&mnt->mnt_longterm);
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
591
592
593
594
  #endif
  }
  
  /* needs vfsmount lock for write */
83adc7532   Al Viro   vfs: spread struc...
595
  static inline void __mnt_make_shortterm(struct mount *mnt)
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
596
597
  {
  #ifdef CONFIG_SMP
68e8a9fea   Al Viro   vfs: all counters...
598
  	atomic_dec(&mnt->mnt_longterm);
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
599
600
  #endif
  }
b90fa9ae8   Ram Pai   [PATCH] shared mo...
601
  /*
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
602
   * vfsmount lock must be held for write
b90fa9ae8   Ram Pai   [PATCH] shared mo...
603
   */
4b2619a57   Al Viro   vfs: spread struc...
604
  static void commit_tree(struct mount *mnt)
b90fa9ae8   Ram Pai   [PATCH] shared mo...
605
  {
0714a5338   Al Viro   vfs: now it can b...
606
  	struct mount *parent = mnt->mnt_parent;
83adc7532   Al Viro   vfs: spread struc...
607
  	struct mount *m;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
608
  	LIST_HEAD(head);
143c8c91c   Al Viro   vfs: mnt_ns moved...
609
  	struct mnt_namespace *n = parent->mnt_ns;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
610

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

1a4eeaf2a   Al Viro   vfs: move mnt_lis...
613
614
  	list_add_tail(&head, &mnt->mnt_list);
  	list_for_each_entry(m, &head, mnt_list) {
143c8c91c   Al Viro   vfs: mnt_ns moved...
615
  		m->mnt_ns = n;
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
616
  		__mnt_make_longterm(m);
f03c65993   Al Viro   sanitize vfsmount...
617
  	}
b90fa9ae8   Ram Pai   [PATCH] shared mo...
618
  	list_splice(&head, n->list.prev);
1b8e5564b   Al Viro   vfs: the first sp...
619
  	list_add_tail(&mnt->mnt_hash, mount_hashtable +
a73324da7   Al Viro   vfs: move mnt_mou...
620
  				hash(&parent->mnt, mnt->mnt_mountpoint));
6b41d536f   Al Viro   vfs: take mnt_chi...
621
  	list_add_tail(&mnt->mnt_child, &parent->mnt_mounts);
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
622
  	touch_mnt_namespace(n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
  }
909b0a88e   Al Viro   vfs: spread struc...
624
  static struct mount *next_mnt(struct mount *p, struct mount *root)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
  {
6b41d536f   Al Viro   vfs: take mnt_chi...
626
627
  	struct list_head *next = p->mnt_mounts.next;
  	if (next == &p->mnt_mounts) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
  		while (1) {
909b0a88e   Al Viro   vfs: spread struc...
629
  			if (p == root)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
  				return NULL;
6b41d536f   Al Viro   vfs: take mnt_chi...
631
632
  			next = p->mnt_child.next;
  			if (next != &p->mnt_parent->mnt_mounts)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633
  				break;
0714a5338   Al Viro   vfs: now it can b...
634
  			p = p->mnt_parent;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
636
  		}
  	}
6b41d536f   Al Viro   vfs: take mnt_chi...
637
  	return list_entry(next, struct mount, mnt_child);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
  }
315fc83e5   Al Viro   vfs: spread struc...
639
  static struct mount *skip_mnt_tree(struct mount *p)
9676f0c63   Ram Pai   [PATCH] unbindabl...
640
  {
6b41d536f   Al Viro   vfs: take mnt_chi...
641
642
643
644
  	struct list_head *prev = p->mnt_mounts.prev;
  	while (prev != &p->mnt_mounts) {
  		p = list_entry(prev, struct mount, mnt_child);
  		prev = p->mnt_mounts.prev;
9676f0c63   Ram Pai   [PATCH] unbindabl...
645
646
647
  	}
  	return p;
  }
9d412a43c   Al Viro   vfs: split off vf...
648
649
650
  struct vfsmount *
  vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
  {
b105e270b   Al Viro   vfs: spread struc...
651
  	struct mount *mnt;
9d412a43c   Al Viro   vfs: split off vf...
652
653
654
655
656
657
658
659
660
661
  	struct dentry *root;
  
  	if (!type)
  		return ERR_PTR(-ENODEV);
  
  	mnt = alloc_vfsmnt(name);
  	if (!mnt)
  		return ERR_PTR(-ENOMEM);
  
  	if (flags & MS_KERNMOUNT)
b105e270b   Al Viro   vfs: spread struc...
662
  		mnt->mnt.mnt_flags = MNT_INTERNAL;
9d412a43c   Al Viro   vfs: split off vf...
663
664
665
666
667
668
  
  	root = mount_fs(type, flags, name, data);
  	if (IS_ERR(root)) {
  		free_vfsmnt(mnt);
  		return ERR_CAST(root);
  	}
b105e270b   Al Viro   vfs: spread struc...
669
670
  	mnt->mnt.mnt_root = root;
  	mnt->mnt.mnt_sb = root->d_sb;
a73324da7   Al Viro   vfs: move mnt_mou...
671
  	mnt->mnt_mountpoint = mnt->mnt.mnt_root;
0714a5338   Al Viro   vfs: now it can b...
672
  	mnt->mnt_parent = mnt;
39f7c4db1   Miklos Szeredi   vfs: keep list of...
673
674
675
  	br_write_lock(vfsmount_lock);
  	list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts);
  	br_write_unlock(vfsmount_lock);
b105e270b   Al Viro   vfs: spread struc...
676
  	return &mnt->mnt;
9d412a43c   Al Viro   vfs: split off vf...
677
678
  }
  EXPORT_SYMBOL_GPL(vfs_kern_mount);
87129cc0e   Al Viro   vfs: spread struc...
679
  static struct mount *clone_mnt(struct mount *old, struct dentry *root,
36341f645   Ram Pai   [PATCH] mount exp...
680
  					int flag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
  {
87129cc0e   Al Viro   vfs: spread struc...
682
  	struct super_block *sb = old->mnt.mnt_sb;
52ba1621d   Al Viro   vfs: move mnt_dev...
683
  	struct mount *mnt = alloc_vfsmnt(old->mnt_devname);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684
685
  
  	if (mnt) {
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
686
  		if (flag & (CL_SLAVE | CL_PRIVATE))
15169fe78   Al Viro   vfs: mnt_id/mnt_g...
687
  			mnt->mnt_group_id = 0; /* not a peer of original */
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
688
  		else
15169fe78   Al Viro   vfs: mnt_id/mnt_g...
689
  			mnt->mnt_group_id = old->mnt_group_id;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
690

15169fe78   Al Viro   vfs: mnt_id/mnt_g...
691
  		if ((flag & CL_MAKE_SHARED) && !mnt->mnt_group_id) {
b105e270b   Al Viro   vfs: spread struc...
692
  			int err = mnt_alloc_group_id(mnt);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
693
694
695
  			if (err)
  				goto out_free;
  		}
87129cc0e   Al Viro   vfs: spread struc...
696
  		mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~MNT_WRITE_HOLD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
  		atomic_inc(&sb->s_active);
b105e270b   Al Viro   vfs: spread struc...
698
699
  		mnt->mnt.mnt_sb = sb;
  		mnt->mnt.mnt_root = dget(root);
a73324da7   Al Viro   vfs: move mnt_mou...
700
  		mnt->mnt_mountpoint = mnt->mnt.mnt_root;
0714a5338   Al Viro   vfs: now it can b...
701
  		mnt->mnt_parent = mnt;
39f7c4db1   Miklos Szeredi   vfs: keep list of...
702
703
704
  		br_write_lock(vfsmount_lock);
  		list_add_tail(&mnt->mnt_instance, &sb->s_mounts);
  		br_write_unlock(vfsmount_lock);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
705

5afe00221   Ram Pai   [PATCH] handling ...
706
  		if (flag & CL_SLAVE) {
6776db3d3   Al Viro   vfs: take mnt_sha...
707
  			list_add(&mnt->mnt_slave, &old->mnt_slave_list);
32301920f   Al Viro   vfs: and now we c...
708
  			mnt->mnt_master = old;
fc7be130c   Al Viro   vfs: switch pnode...
709
  			CLEAR_MNT_SHARED(mnt);
8aec08094   Al Viro   [PATCH] new helpe...
710
  		} else if (!(flag & CL_PRIVATE)) {
fc7be130c   Al Viro   vfs: switch pnode...
711
  			if ((flag & CL_MAKE_SHARED) || IS_MNT_SHARED(old))
6776db3d3   Al Viro   vfs: take mnt_sha...
712
  				list_add(&mnt->mnt_share, &old->mnt_share);
d10e8def0   Al Viro   vfs: take mnt_mas...
713
  			if (IS_MNT_SLAVE(old))
6776db3d3   Al Viro   vfs: take mnt_sha...
714
  				list_add(&mnt->mnt_slave, &old->mnt_slave);
d10e8def0   Al Viro   vfs: take mnt_mas...
715
  			mnt->mnt_master = old->mnt_master;
5afe00221   Ram Pai   [PATCH] handling ...
716
  		}
b90fa9ae8   Ram Pai   [PATCH] shared mo...
717
  		if (flag & CL_MAKE_SHARED)
0f0afb1dc   Al Viro   vfs: spread struc...
718
  			set_mnt_shared(mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
720
721
  
  		/* stick the duplicate mount on the same expiry list
  		 * as the original if that was on one */
36341f645   Ram Pai   [PATCH] mount exp...
722
  		if (flag & CL_EXPIRE) {
6776db3d3   Al Viro   vfs: take mnt_sha...
723
724
  			if (!list_empty(&old->mnt_expire))
  				list_add(&mnt->mnt_expire, &old->mnt_expire);
36341f645   Ram Pai   [PATCH] mount exp...
725
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726
  	}
cb338d06e   Al Viro   vfs: spread struc...
727
  	return mnt;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
728
729
730
731
  
   out_free:
  	free_vfsmnt(mnt);
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
  }
83adc7532   Al Viro   vfs: spread struc...
733
  static inline void mntfree(struct mount *mnt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
  {
83adc7532   Al Viro   vfs: spread struc...
735
736
  	struct vfsmount *m = &mnt->mnt;
  	struct super_block *sb = m->mnt_sb;
b3e19d924   Nick Piggin   fs: scale mntget/...
737

3d733633a   Dave Hansen   [PATCH] r/o bind ...
738
  	/*
3d733633a   Dave Hansen   [PATCH] r/o bind ...
739
740
741
742
743
  	 * 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...
744
  	/*
b3e19d924   Nick Piggin   fs: scale mntget/...
745
746
  	 * 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...
747
  	 */
c6653a838   Nick Piggin   fs: rename vfsmou...
748
  	WARN_ON(mnt_get_writers(mnt));
83adc7532   Al Viro   vfs: spread struc...
749
750
751
  	fsnotify_vfsmount_delete(m);
  	dput(m->mnt_root);
  	free_vfsmnt(mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
753
  	deactivate_super(sb);
  }
900148dca   Al Viro   vfs: spread struc...
754
  static void mntput_no_expire(struct mount *mnt)
b3e19d924   Nick Piggin   fs: scale mntget/...
755
  {
b3e19d924   Nick Piggin   fs: scale mntget/...
756
  put_again:
f03c65993   Al Viro   sanitize vfsmount...
757
758
  #ifdef CONFIG_SMP
  	br_read_lock(vfsmount_lock);
68e8a9fea   Al Viro   vfs: all counters...
759
  	if (likely(atomic_read(&mnt->mnt_longterm))) {
aa9c0e07b   Al Viro   vfs: kill pointle...
760
  		mnt_add_count(mnt, -1);
b3e19d924   Nick Piggin   fs: scale mntget/...
761
  		br_read_unlock(vfsmount_lock);
f03c65993   Al Viro   sanitize vfsmount...
762
  		return;
b3e19d924   Nick Piggin   fs: scale mntget/...
763
  	}
f03c65993   Al Viro   sanitize vfsmount...
764
  	br_read_unlock(vfsmount_lock);
b3e19d924   Nick Piggin   fs: scale mntget/...
765

99b7db7b8   Nick Piggin   fs: brlock vfsmou...
766
  	br_write_lock(vfsmount_lock);
aa9c0e07b   Al Viro   vfs: kill pointle...
767
  	mnt_add_count(mnt, -1);
b3e19d924   Nick Piggin   fs: scale mntget/...
768
  	if (mnt_get_count(mnt)) {
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
769
770
771
  		br_write_unlock(vfsmount_lock);
  		return;
  	}
b3e19d924   Nick Piggin   fs: scale mntget/...
772
  #else
aa9c0e07b   Al Viro   vfs: kill pointle...
773
  	mnt_add_count(mnt, -1);
b3e19d924   Nick Piggin   fs: scale mntget/...
774
  	if (likely(mnt_get_count(mnt)))
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
775
  		return;
b3e19d924   Nick Piggin   fs: scale mntget/...
776
  	br_write_lock(vfsmount_lock);
f03c65993   Al Viro   sanitize vfsmount...
777
  #endif
863d684f9   Al Viro   vfs: move the res...
778
779
780
  	if (unlikely(mnt->mnt_pinned)) {
  		mnt_add_count(mnt, mnt->mnt_pinned + 1);
  		mnt->mnt_pinned = 0;
b3e19d924   Nick Piggin   fs: scale mntget/...
781
  		br_write_unlock(vfsmount_lock);
900148dca   Al Viro   vfs: spread struc...
782
  		acct_auto_close_mnt(&mnt->mnt);
b3e19d924   Nick Piggin   fs: scale mntget/...
783
  		goto put_again;
7b7b1ace2   Al Viro   [PATCH] saner han...
784
  	}
39f7c4db1   Miklos Szeredi   vfs: keep list of...
785
  	list_del(&mnt->mnt_instance);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
786
  	br_write_unlock(vfsmount_lock);
b3e19d924   Nick Piggin   fs: scale mntget/...
787
788
  	mntfree(mnt);
  }
b3e19d924   Nick Piggin   fs: scale mntget/...
789
790
791
792
  
  void mntput(struct vfsmount *mnt)
  {
  	if (mnt) {
863d684f9   Al Viro   vfs: move the res...
793
  		struct mount *m = real_mount(mnt);
b3e19d924   Nick Piggin   fs: scale mntget/...
794
  		/* avoid cacheline pingpong, hope gcc doesn't get "smart" */
863d684f9   Al Viro   vfs: move the res...
795
796
797
  		if (unlikely(m->mnt_expiry_mark))
  			m->mnt_expiry_mark = 0;
  		mntput_no_expire(m);
b3e19d924   Nick Piggin   fs: scale mntget/...
798
799
800
801
802
803
804
  	}
  }
  EXPORT_SYMBOL(mntput);
  
  struct vfsmount *mntget(struct vfsmount *mnt)
  {
  	if (mnt)
83adc7532   Al Viro   vfs: spread struc...
805
  		mnt_add_count(real_mount(mnt), 1);
b3e19d924   Nick Piggin   fs: scale mntget/...
806
807
808
  	return mnt;
  }
  EXPORT_SYMBOL(mntget);
7b7b1ace2   Al Viro   [PATCH] saner han...
809
810
  void mnt_pin(struct vfsmount *mnt)
  {
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
811
  	br_write_lock(vfsmount_lock);
863d684f9   Al Viro   vfs: move the res...
812
  	real_mount(mnt)->mnt_pinned++;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
813
  	br_write_unlock(vfsmount_lock);
7b7b1ace2   Al Viro   [PATCH] saner han...
814
  }
7b7b1ace2   Al Viro   [PATCH] saner han...
815
  EXPORT_SYMBOL(mnt_pin);
863d684f9   Al Viro   vfs: move the res...
816
  void mnt_unpin(struct vfsmount *m)
7b7b1ace2   Al Viro   [PATCH] saner han...
817
  {
863d684f9   Al Viro   vfs: move the res...
818
  	struct mount *mnt = real_mount(m);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
819
  	br_write_lock(vfsmount_lock);
7b7b1ace2   Al Viro   [PATCH] saner han...
820
  	if (mnt->mnt_pinned) {
863d684f9   Al Viro   vfs: move the res...
821
  		mnt_add_count(mnt, 1);
7b7b1ace2   Al Viro   [PATCH] saner han...
822
823
  		mnt->mnt_pinned--;
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
824
  	br_write_unlock(vfsmount_lock);
7b7b1ace2   Al Viro   [PATCH] saner han...
825
  }
7b7b1ace2   Al Viro   [PATCH] saner han...
826
  EXPORT_SYMBOL(mnt_unpin);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827

b3b304a23   Miklos Szeredi   mount options: ad...
828
829
830
831
832
833
834
835
836
837
838
839
  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().
   */
34c80b1d9   Al Viro   vfs: switch ->sho...
840
  int generic_show_options(struct seq_file *m, struct dentry *root)
b3b304a23   Miklos Szeredi   mount options: ad...
841
  {
2a32cebd6   Al Viro   Fix races around ...
842
843
844
  	const char *options;
  
  	rcu_read_lock();
34c80b1d9   Al Viro   vfs: switch ->sho...
845
  	options = rcu_dereference(root->d_sb->s_options);
b3b304a23   Miklos Szeredi   mount options: ad...
846
847
848
849
850
  
  	if (options != NULL && options[0]) {
  		seq_putc(m, ',');
  		mangle(m, options);
  	}
2a32cebd6   Al Viro   Fix races around ...
851
  	rcu_read_unlock();
b3b304a23   Miklos Szeredi   mount options: ad...
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
  
  	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 ...
872
873
  	BUG_ON(sb->s_options);
  	rcu_assign_pointer(sb->s_options, kstrdup(options, GFP_KERNEL));
b3b304a23   Miklos Szeredi   mount options: ad...
874
875
  }
  EXPORT_SYMBOL(save_mount_options);
2a32cebd6   Al Viro   Fix races around ...
876
877
878
879
880
881
882
883
884
885
  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: ...
886
  #ifdef CONFIG_PROC_FS
0226f4923   Al Viro   vfs: take /proc/*...
887
  /* iterator; we want it to have access to namespace_sem, thus here... */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
889
  static void *m_start(struct seq_file *m, loff_t *pos)
  {
0226f4923   Al Viro   vfs: take /proc/*...
890
  	struct proc_mounts *p = container_of(m, struct proc_mounts, m);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
891

390c68436   Ram Pai   [PATCH] making na...
892
  	down_read(&namespace_sem);
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
893
  	return seq_list_start(&p->ns->list, *pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
895
896
897
  }
  
  static void *m_next(struct seq_file *m, void *v, loff_t *pos)
  {
0226f4923   Al Viro   vfs: take /proc/*...
898
  	struct proc_mounts *p = container_of(m, struct proc_mounts, m);
b0765fb85   Pavel Emelianov   Make /proc/self/m...
899

a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
900
  	return seq_list_next(v, &p->ns->list, pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
901
902
903
904
  }
  
  static void m_stop(struct seq_file *m, void *v)
  {
390c68436   Ram Pai   [PATCH] making na...
905
  	up_read(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906
  }
0226f4923   Al Viro   vfs: take /proc/*...
907
  static int m_show(struct seq_file *m, void *v)
2d4d4864a   Ram Pai   [patch 6/7] vfs: ...
908
  {
0226f4923   Al Viro   vfs: take /proc/*...
909
  	struct proc_mounts *p = container_of(m, struct proc_mounts, m);
1a4eeaf2a   Al Viro   vfs: move mnt_lis...
910
  	struct mount *r = list_entry(v, struct mount, mnt_list);
0226f4923   Al Viro   vfs: take /proc/*...
911
  	return p->show(m, &r->mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
  }
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
913
  const struct seq_operations mounts_op = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914
915
916
  	.start	= m_start,
  	.next	= m_next,
  	.stop	= m_stop,
0226f4923   Al Viro   vfs: take /proc/*...
917
  	.show	= m_show,
b4629fe2f   Chuck Lever   VFS: New /proc fi...
918
  };
a1a2c409b   Miklos Szeredi   [patch 5/7] vfs: ...
919
  #endif  /* CONFIG_PROC_FS */
b4629fe2f   Chuck Lever   VFS: New /proc fi...
920

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
921
922
923
924
925
926
927
928
  /**
   * 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.
   */
909b0a88e   Al Viro   vfs: spread struc...
929
  int may_umount_tree(struct vfsmount *m)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
930
  {
909b0a88e   Al Viro   vfs: spread struc...
931
  	struct mount *mnt = real_mount(m);
36341f645   Ram Pai   [PATCH] mount exp...
932
933
  	int actual_refs = 0;
  	int minimum_refs = 0;
315fc83e5   Al Viro   vfs: spread struc...
934
  	struct mount *p;
909b0a88e   Al Viro   vfs: spread struc...
935
  	BUG_ON(!m);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936

b3e19d924   Nick Piggin   fs: scale mntget/...
937
938
  	/* write lock needed for mnt_get_count */
  	br_write_lock(vfsmount_lock);
909b0a88e   Al Viro   vfs: spread struc...
939
  	for (p = mnt; p; p = next_mnt(p, mnt)) {
83adc7532   Al Viro   vfs: spread struc...
940
  		actual_refs += mnt_get_count(p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
941
  		minimum_refs += 2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942
  	}
b3e19d924   Nick Piggin   fs: scale mntget/...
943
  	br_write_unlock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944
945
  
  	if (actual_refs > minimum_refs)
e3474a8eb   Ian Kent   [PATCH] autofs4: ...
946
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947

e3474a8eb   Ian Kent   [PATCH] autofs4: ...
948
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
  }
  
  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: ...
968
  	int ret = 1;
8ad08d8a0   Al Viro   may_umount() need...
969
  	down_read(&namespace_sem);
b3e19d924   Nick Piggin   fs: scale mntget/...
970
  	br_write_lock(vfsmount_lock);
1ab597386   Al Viro   vfs: spread struc...
971
  	if (propagate_mount_busy(real_mount(mnt), 2))
e3474a8eb   Ian Kent   [PATCH] autofs4: ...
972
  		ret = 0;
b3e19d924   Nick Piggin   fs: scale mntget/...
973
  	br_write_unlock(vfsmount_lock);
8ad08d8a0   Al Viro   may_umount() need...
974
  	up_read(&namespace_sem);
a05964f39   Ram Pai   [PATCH] shared mo...
975
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976
977
978
  }
  
  EXPORT_SYMBOL(may_umount);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
979
  void release_mounts(struct list_head *head)
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
980
  {
d5e50f74d   Al Viro   vfs: spread struc...
981
  	struct mount *mnt;
bf066c7db   Miklos Szeredi   [PATCH] shared mo...
982
  	while (!list_empty(head)) {
1b8e5564b   Al Viro   vfs: the first sp...
983
984
  		mnt = list_first_entry(head, struct mount, mnt_hash);
  		list_del_init(&mnt->mnt_hash);
676da58df   Al Viro   vfs: spread struc...
985
  		if (mnt_has_parent(mnt)) {
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
986
  			struct dentry *dentry;
863d684f9   Al Viro   vfs: move the res...
987
  			struct mount *m;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
988
989
  
  			br_write_lock(vfsmount_lock);
a73324da7   Al Viro   vfs: move mnt_mou...
990
  			dentry = mnt->mnt_mountpoint;
863d684f9   Al Viro   vfs: move the res...
991
  			m = mnt->mnt_parent;
a73324da7   Al Viro   vfs: move mnt_mou...
992
  			mnt->mnt_mountpoint = mnt->mnt.mnt_root;
0714a5338   Al Viro   vfs: now it can b...
993
  			mnt->mnt_parent = mnt;
7c4b93d82   Al Viro   [PATCH] count gho...
994
  			m->mnt_ghosts--;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
995
  			br_write_unlock(vfsmount_lock);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
996
  			dput(dentry);
863d684f9   Al Viro   vfs: move the res...
997
  			mntput(&m->mnt);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
998
  		}
d5e50f74d   Al Viro   vfs: spread struc...
999
  		mntput(&mnt->mnt);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1000
1001
  	}
  }
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1002
1003
1004
1005
  /*
   * vfsmount lock must be held for write
   * namespace_sem must be held for write
   */
761d5c38e   Al Viro   vfs: spread struc...
1006
  void umount_tree(struct mount *mnt, int propagate, struct list_head *kill)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
  {
7b8a53fd8   Al Viro   fix old umount_tr...
1008
  	LIST_HEAD(tmp_list);
315fc83e5   Al Viro   vfs: spread struc...
1009
  	struct mount *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1010

909b0a88e   Al Viro   vfs: spread struc...
1011
  	for (p = mnt; p; p = next_mnt(p, mnt))
1b8e5564b   Al Viro   vfs: the first sp...
1012
  		list_move(&p->mnt_hash, &tmp_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1013

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

1b8e5564b   Al Viro   vfs: the first sp...
1017
  	list_for_each_entry(p, &tmp_list, mnt_hash) {
6776db3d3   Al Viro   vfs: take mnt_sha...
1018
  		list_del_init(&p->mnt_expire);
1a4eeaf2a   Al Viro   vfs: move mnt_lis...
1019
  		list_del_init(&p->mnt_list);
143c8c91c   Al Viro   vfs: mnt_ns moved...
1020
1021
  		__touch_mnt_namespace(p->mnt_ns);
  		p->mnt_ns = NULL;
83adc7532   Al Viro   vfs: spread struc...
1022
  		__mnt_make_shortterm(p);
6b41d536f   Al Viro   vfs: take mnt_chi...
1023
  		list_del_init(&p->mnt_child);
676da58df   Al Viro   vfs: spread struc...
1024
  		if (mnt_has_parent(p)) {
863d684f9   Al Viro   vfs: move the res...
1025
  			p->mnt_parent->mnt_ghosts++;
a73324da7   Al Viro   vfs: move mnt_mou...
1026
  			dentry_reset_mounted(p->mnt_mountpoint);
7c4b93d82   Al Viro   [PATCH] count gho...
1027
  		}
0f0afb1dc   Al Viro   vfs: spread struc...
1028
  		change_mnt_propagation(p, MS_PRIVATE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1029
  	}
7b8a53fd8   Al Viro   fix old umount_tr...
1030
  	list_splice(&tmp_list, kill);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031
  }
692afc312   Al Viro   vfs: spread struc...
1032
  static void shrink_submounts(struct mount *mnt, struct list_head *umounts);
c35038bec   Al Viro   [PATCH] do shrink...
1033

1ab597386   Al Viro   vfs: spread struc...
1034
  static int do_umount(struct mount *mnt, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1035
  {
1ab597386   Al Viro   vfs: spread struc...
1036
  	struct super_block *sb = mnt->mnt.mnt_sb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1037
  	int retval;
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1038
  	LIST_HEAD(umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1039

1ab597386   Al Viro   vfs: spread struc...
1040
  	retval = security_sb_umount(&mnt->mnt, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
  	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) {
1ab597386   Al Viro   vfs: spread struc...
1051
  		if (&mnt->mnt == current->fs->root.mnt ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1052
1053
  		    flags & (MNT_FORCE | MNT_DETACH))
  			return -EINVAL;
b3e19d924   Nick Piggin   fs: scale mntget/...
1054
1055
1056
1057
1058
  		/*
  		 * probably don't strictly need the lock here if we examined
  		 * all race cases, but it's a slowpath.
  		 */
  		br_write_lock(vfsmount_lock);
83adc7532   Al Viro   vfs: spread struc...
1059
  		if (mnt_get_count(mnt) != 2) {
bf9faa2aa   J. R. Okajima   Unlock vfsmount_l...
1060
  			br_write_unlock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1061
  			return -EBUSY;
b3e19d924   Nick Piggin   fs: scale mntget/...
1062
1063
  		}
  		br_write_unlock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1064

863d684f9   Al Viro   vfs: move the res...
1065
  		if (!xchg(&mnt->mnt_expiry_mark, 1))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
  			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...
1078
  	if (flags & MNT_FORCE && sb->s_op->umount_begin) {
42faad996   Al Viro   [PATCH] restore s...
1079
  		sb->s_op->umount_begin(sb);
42faad996   Al Viro   [PATCH] restore s...
1080
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
  
  	/*
  	 * 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.
  	 */
1ab597386   Al Viro   vfs: spread struc...
1091
  	if (&mnt->mnt == current->fs->root.mnt && !(flags & MNT_DETACH)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1092
1093
1094
1095
1096
  		/*
  		 * Special case for "unmounting" root ...
  		 * we just try to remount it readonly.
  		 */
  		down_write(&sb->s_umount);
4aa98cf76   Al Viro   Push BKL down int...
1097
  		if (!(sb->s_flags & MS_RDONLY))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1098
  			retval = do_remount_sb(sb, MS_RDONLY, NULL, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1099
1100
1101
  		up_write(&sb->s_umount);
  		return retval;
  	}
390c68436   Ram Pai   [PATCH] making na...
1102
  	down_write(&namespace_sem);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1103
  	br_write_lock(vfsmount_lock);
5addc5dd8   Al Viro   [PATCH] make /pro...
1104
  	event++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1105

c35038bec   Al Viro   [PATCH] do shrink...
1106
  	if (!(flags & MNT_DETACH))
1ab597386   Al Viro   vfs: spread struc...
1107
  		shrink_submounts(mnt, &umount_list);
c35038bec   Al Viro   [PATCH] do shrink...
1108

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1109
  	retval = -EBUSY;
a05964f39   Ram Pai   [PATCH] shared mo...
1110
  	if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) {
1a4eeaf2a   Al Viro   vfs: move mnt_lis...
1111
  		if (!list_empty(&mnt->mnt_list))
1ab597386   Al Viro   vfs: spread struc...
1112
  			umount_tree(mnt, 1, &umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1113
1114
  		retval = 0;
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1115
  	br_write_unlock(vfsmount_lock);
390c68436   Ram Pai   [PATCH] making na...
1116
  	up_write(&namespace_sem);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1117
  	release_mounts(&umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
  	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...
1128
  SYSCALL_DEFINE2(umount, char __user *, name, int, flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
1130
  	struct path path;
900148dca   Al Viro   vfs: spread struc...
1131
  	struct mount *mnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1132
  	int retval;
db1f05bb8   Miklos Szeredi   vfs: add NOFOLLOW...
1133
  	int lookup_flags = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1134

db1f05bb8   Miklos Szeredi   vfs: add NOFOLLOW...
1135
1136
1137
1138
1139
1140
1141
  	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
1142
1143
  	if (retval)
  		goto out;
900148dca   Al Viro   vfs: spread struc...
1144
  	mnt = real_mount(path.mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1145
  	retval = -EINVAL;
2d8f30380   Al Viro   [PATCH] sanitize ...
1146
  	if (path.dentry != path.mnt->mnt_root)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1147
  		goto dput_and_out;
143c8c91c   Al Viro   vfs: mnt_ns moved...
1148
  	if (!check_mnt(mnt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1149
1150
1151
1152
1153
  		goto dput_and_out;
  
  	retval = -EPERM;
  	if (!capable(CAP_SYS_ADMIN))
  		goto dput_and_out;
900148dca   Al Viro   vfs: spread struc...
1154
  	retval = do_umount(mnt, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1155
  dput_and_out:
429731b15   Jan Blunck   Remove path_relea...
1156
  	/* we mustn't call path_put() as that would clear mnt_expiry_mark */
2d8f30380   Al Viro   [PATCH] sanitize ...
1157
  	dput(path.dentry);
900148dca   Al Viro   vfs: spread struc...
1158
  	mntput_no_expire(mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1159
1160
1161
1162
1163
1164
1165
  out:
  	return retval;
  }
  
  #ifdef __ARCH_WANT_SYS_OLDUMOUNT
  
  /*
b58fed8b1   Ram Pai   [PATCH] lindent f...
1166
   *	The 2.0 compatible umount. No flags.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1167
   */
bdc480e3b   Heiko Carstens   [CVE-2009-0029] S...
1168
  SYSCALL_DEFINE1(oldumount, char __user *, name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1169
  {
b58fed8b1   Ram Pai   [PATCH] lindent f...
1170
  	return sys_umount(name, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1171
1172
1173
  }
  
  #endif
2d92ab3c6   Al Viro   [PATCH] finally g...
1174
  static int mount_is_safe(struct path *path)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1175
1176
1177
1178
1179
  {
  	if (capable(CAP_SYS_ADMIN))
  		return 0;
  	return -EPERM;
  #ifdef notyet
2d92ab3c6   Al Viro   [PATCH] finally g...
1180
  	if (S_ISLNK(path->dentry->d_inode->i_mode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1181
  		return -EPERM;
2d92ab3c6   Al Viro   [PATCH] finally g...
1182
  	if (path->dentry->d_inode->i_mode & S_ISVTX) {
da9592ede   David Howells   CRED: Wrap task c...
1183
  		if (current_uid() != path->dentry->d_inode->i_uid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1184
1185
  			return -EPERM;
  	}
2d92ab3c6   Al Viro   [PATCH] finally g...
1186
  	if (inode_permission(path->dentry->d_inode, MAY_WRITE))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1187
1188
1189
1190
  		return -EPERM;
  	return 0;
  #endif
  }
87129cc0e   Al Viro   vfs: spread struc...
1191
  struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
36341f645   Ram Pai   [PATCH] mount exp...
1192
  					int flag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1193
  {
a73324da7   Al Viro   vfs: move mnt_mou...
1194
  	struct mount *res, *p, *q, *r;
1a3906895   Al Viro   [PATCH] reduce st...
1195
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1196

fc7be130c   Al Viro   vfs: switch pnode...
1197
  	if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(mnt))
9676f0c63   Ram Pai   [PATCH] unbindabl...
1198
  		return NULL;
36341f645   Ram Pai   [PATCH] mount exp...
1199
  	res = q = clone_mnt(mnt, dentry, flag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1200
1201
  	if (!q)
  		goto Enomem;
a73324da7   Al Viro   vfs: move mnt_mou...
1202
  	q->mnt_mountpoint = mnt->mnt_mountpoint;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1203
1204
  
  	p = mnt;
6b41d536f   Al Viro   vfs: take mnt_chi...
1205
  	list_for_each_entry(r, &mnt->mnt_mounts, mnt_child) {
315fc83e5   Al Viro   vfs: spread struc...
1206
  		struct mount *s;
7ec02ef15   Jan Blunck   vfs: remove lives...
1207
  		if (!is_subdir(r->mnt_mountpoint, dentry))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1208
  			continue;
909b0a88e   Al Viro   vfs: spread struc...
1209
  		for (s = r; s; s = next_mnt(s, r)) {
fc7be130c   Al Viro   vfs: switch pnode...
1210
  			if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(s)) {
9676f0c63   Ram Pai   [PATCH] unbindabl...
1211
1212
1213
  				s = skip_mnt_tree(s);
  				continue;
  			}
0714a5338   Al Viro   vfs: now it can b...
1214
1215
1216
  			while (p != s->mnt_parent) {
  				p = p->mnt_parent;
  				q = q->mnt_parent;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1217
  			}
87129cc0e   Al Viro   vfs: spread struc...
1218
  			p = s;
cb338d06e   Al Viro   vfs: spread struc...
1219
  			path.mnt = &q->mnt;
a73324da7   Al Viro   vfs: move mnt_mou...
1220
  			path.dentry = p->mnt_mountpoint;
87129cc0e   Al Viro   vfs: spread struc...
1221
  			q = clone_mnt(p, p->mnt.mnt_root, flag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1222
1223
  			if (!q)
  				goto Enomem;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1224
  			br_write_lock(vfsmount_lock);
1a4eeaf2a   Al Viro   vfs: move mnt_lis...
1225
  			list_add_tail(&q->mnt_list, &res->mnt_list);
cb338d06e   Al Viro   vfs: spread struc...
1226
  			attach_mnt(q, &path);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1227
  			br_write_unlock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1228
1229
1230
  		}
  	}
  	return res;
b58fed8b1   Ram Pai   [PATCH] lindent f...
1231
  Enomem:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1232
  	if (res) {
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1233
  		LIST_HEAD(umount_list);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1234
  		br_write_lock(vfsmount_lock);
761d5c38e   Al Viro   vfs: spread struc...
1235
  		umount_tree(res, 0, &umount_list);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1236
  		br_write_unlock(vfsmount_lock);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
1237
  		release_mounts(&umount_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1238
1239
1240
  	}
  	return NULL;
  }
589ff870e   Al Viro   Switch collect_mo...
1241
  struct vfsmount *collect_mounts(struct path *path)
8aec08094   Al Viro   [PATCH] new helpe...
1242
  {
cb338d06e   Al Viro   vfs: spread struc...
1243
  	struct mount *tree;
1a60a2807   Al Viro   [PATCH] lock excl...
1244
  	down_write(&namespace_sem);
87129cc0e   Al Viro   vfs: spread struc...
1245
1246
  	tree = copy_tree(real_mount(path->mnt), path->dentry,
  			 CL_COPY_ALL | CL_PRIVATE);
1a60a2807   Al Viro   [PATCH] lock excl...
1247
  	up_write(&namespace_sem);
cb338d06e   Al Viro   vfs: spread struc...
1248
  	return tree ? &tree->mnt : NULL;
8aec08094   Al Viro   [PATCH] new helpe...
1249
1250
1251
1252
1253
  }
  
  void drop_collected_mounts(struct vfsmount *mnt)
  {
  	LIST_HEAD(umount_list);
1a60a2807   Al Viro   [PATCH] lock excl...
1254
  	down_write(&namespace_sem);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1255
  	br_write_lock(vfsmount_lock);
761d5c38e   Al Viro   vfs: spread struc...
1256
  	umount_tree(real_mount(mnt), 0, &umount_list);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1257
  	br_write_unlock(vfsmount_lock);
1a60a2807   Al Viro   [PATCH] lock excl...
1258
  	up_write(&namespace_sem);
8aec08094   Al Viro   [PATCH] new helpe...
1259
1260
  	release_mounts(&umount_list);
  }
1f707137b   Al Viro   new helper: itera...
1261
1262
1263
  int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg,
  		   struct vfsmount *root)
  {
1a4eeaf2a   Al Viro   vfs: move mnt_lis...
1264
  	struct mount *mnt;
1f707137b   Al Viro   new helper: itera...
1265
1266
1267
  	int res = f(root, arg);
  	if (res)
  		return res;
1a4eeaf2a   Al Viro   vfs: move mnt_lis...
1268
1269
  	list_for_each_entry(mnt, &real_mount(root)->mnt_list, mnt_list) {
  		res = f(&mnt->mnt, arg);
1f707137b   Al Viro   new helper: itera...
1270
1271
1272
1273
1274
  		if (res)
  			return res;
  	}
  	return 0;
  }
4b8b21f4f   Al Viro   vfs: spread struc...
1275
  static void cleanup_group_ids(struct mount *mnt, struct mount *end)
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1276
  {
315fc83e5   Al Viro   vfs: spread struc...
1277
  	struct mount *p;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1278

909b0a88e   Al Viro   vfs: spread struc...
1279
  	for (p = mnt; p != end; p = next_mnt(p, mnt)) {
fc7be130c   Al Viro   vfs: switch pnode...
1280
  		if (p->mnt_group_id && !IS_MNT_SHARED(p))
4b8b21f4f   Al Viro   vfs: spread struc...
1281
  			mnt_release_group_id(p);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1282
1283
  	}
  }
4b8b21f4f   Al Viro   vfs: spread struc...
1284
  static int invent_group_ids(struct mount *mnt, bool recurse)
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1285
  {
315fc83e5   Al Viro   vfs: spread struc...
1286
  	struct mount *p;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1287

909b0a88e   Al Viro   vfs: spread struc...
1288
  	for (p = mnt; p; p = recurse ? next_mnt(p, mnt) : NULL) {
fc7be130c   Al Viro   vfs: switch pnode...
1289
  		if (!p->mnt_group_id && !IS_MNT_SHARED(p)) {
4b8b21f4f   Al Viro   vfs: spread struc...
1290
  			int err = mnt_alloc_group_id(p);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1291
  			if (err) {
4b8b21f4f   Al Viro   vfs: spread struc...
1292
  				cleanup_group_ids(mnt, p);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1293
1294
1295
1296
1297
1298
1299
  				return err;
  			}
  		}
  	}
  
  	return 0;
  }
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1300
1301
  /*
   *  @source_mnt : mount tree to be attached
214444032   Ram Pai   [PATCH] shared mo...
1302
1303
1304
1305
   *  @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...
1306
1307
1308
   *
   *  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...
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
   * ---------------------------------------------------------------------------
   * |         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...
1321
1322
1323
1324
1325
1326
1327
1328
1329
   * 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 ...
1330
1331
1332
1333
1334
1335
1336
   * (+++) 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...
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
   * ---------------------------------------------------------------------------
   * |         		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 ...
1349
1350
1351
   *
   * (+)  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...
1352
   * (+*)  the mount is moved to the destination.
5afe00221   Ram Pai   [PATCH] handling ...
1353
1354
1355
1356
   * (+++)  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...
1357
1358
1359
1360
1361
1362
   *
   * 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.
   */
0fb54e505   Al Viro   vfs: spread struc...
1363
  static int attach_recursive_mnt(struct mount *source_mnt,
1a3906895   Al Viro   [PATCH] reduce st...
1364
  			struct path *path, struct path *parent_path)
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1365
1366
  {
  	LIST_HEAD(tree_list);
a8d56d8e4   Al Viro   vfs: spread struc...
1367
  	struct mount *dest_mnt = real_mount(path->mnt);
1a3906895   Al Viro   [PATCH] reduce st...
1368
  	struct dentry *dest_dentry = path->dentry;
315fc83e5   Al Viro   vfs: spread struc...
1369
  	struct mount *child, *p;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1370
  	int err;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1371

fc7be130c   Al Viro   vfs: switch pnode...
1372
  	if (IS_MNT_SHARED(dest_mnt)) {
0fb54e505   Al Viro   vfs: spread struc...
1373
  		err = invent_group_ids(source_mnt, true);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1374
1375
1376
  		if (err)
  			goto out;
  	}
a8d56d8e4   Al Viro   vfs: spread struc...
1377
  	err = propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1378
1379
  	if (err)
  		goto out_cleanup_ids;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1380

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

fc7be130c   Al Viro   vfs: switch pnode...
1383
  	if (IS_MNT_SHARED(dest_mnt)) {
909b0a88e   Al Viro   vfs: spread struc...
1384
  		for (p = source_mnt; p; p = next_mnt(p, source_mnt))
0f0afb1dc   Al Viro   vfs: spread struc...
1385
  			set_mnt_shared(p);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1386
  	}
1a3906895   Al Viro   [PATCH] reduce st...
1387
  	if (parent_path) {
0fb54e505   Al Viro   vfs: spread struc...
1388
1389
  		detach_mnt(source_mnt, parent_path);
  		attach_mnt(source_mnt, path);
143c8c91c   Al Viro   vfs: mnt_ns moved...
1390
  		touch_mnt_namespace(source_mnt->mnt_ns);
214444032   Ram Pai   [PATCH] shared mo...
1391
  	} else {
14cf1fa8f   Al Viro   vfs: spread struc...
1392
  		mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt);
0fb54e505   Al Viro   vfs: spread struc...
1393
  		commit_tree(source_mnt);
214444032   Ram Pai   [PATCH] shared mo...
1394
  	}
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1395

1b8e5564b   Al Viro   vfs: the first sp...
1396
1397
  	list_for_each_entry_safe(child, p, &tree_list, mnt_hash) {
  		list_del_init(&child->mnt_hash);
4b2619a57   Al Viro   vfs: spread struc...
1398
  		commit_tree(child);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1399
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1400
  	br_write_unlock(vfsmount_lock);
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1401
  	return 0;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1402
1403
  
   out_cleanup_ids:
fc7be130c   Al Viro   vfs: switch pnode...
1404
  	if (IS_MNT_SHARED(dest_mnt))
0fb54e505   Al Viro   vfs: spread struc...
1405
  		cleanup_group_ids(source_mnt, NULL);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1406
1407
   out:
  	return err;
b90fa9ae8   Ram Pai   [PATCH] shared mo...
1408
  }
b12cea919   Al Viro   change the lockin...
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
  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);
  }
95bc5f25c   Al Viro   vfs: spread struc...
1435
  static int graft_tree(struct mount *mnt, struct path *path)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1436
  {
95bc5f25c   Al Viro   vfs: spread struc...
1437
  	if (mnt->mnt.mnt_sb->s_flags & MS_NOUSER)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1438
  		return -EINVAL;
8c3ee42e8   Al Viro   [PATCH] get rid o...
1439
  	if (S_ISDIR(path->dentry->d_inode->i_mode) !=
95bc5f25c   Al Viro   vfs: spread struc...
1440
  	      S_ISDIR(mnt->mnt.mnt_root->d_inode->i_mode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1441
  		return -ENOTDIR;
b12cea919   Al Viro   change the lockin...
1442
1443
  	if (d_unlinked(path->dentry))
  		return -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1444

95bc5f25c   Al Viro   vfs: spread struc...
1445
  	return attach_recursive_mnt(mnt, path, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1446
1447
1448
  }
  
  /*
7a2e8a8fa   Valerie Aurora   VFS: Sanity check...
1449
1450
1451
1452
1453
   * Sanity check the flags to change_mnt_propagation.
   */
  
  static int flags_to_propagation_type(int flags)
  {
7c6e984df   Roman Borisov   fs/namespace.c: b...
1454
  	int type = flags & ~(MS_REC | MS_SILENT);
7a2e8a8fa   Valerie Aurora   VFS: Sanity check...
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
  
  	/* 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...
1466
1467
   * recursively change the type of the mountpoint.
   */
0a0d8a467   Al Viro   [PATCH] no need f...
1468
  static int do_change_type(struct path *path, int flag)
07b20889e   Ram Pai   [PATCH] beginning...
1469
  {
315fc83e5   Al Viro   vfs: spread struc...
1470
  	struct mount *m;
4b8b21f4f   Al Viro   vfs: spread struc...
1471
  	struct mount *mnt = real_mount(path->mnt);
07b20889e   Ram Pai   [PATCH] beginning...
1472
  	int recurse = flag & MS_REC;
7a2e8a8fa   Valerie Aurora   VFS: Sanity check...
1473
  	int type;
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1474
  	int err = 0;
07b20889e   Ram Pai   [PATCH] beginning...
1475

ee6f95829   Miklos Szeredi   check privileges ...
1476
1477
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
2d92ab3c6   Al Viro   [PATCH] finally g...
1478
  	if (path->dentry != path->mnt->mnt_root)
07b20889e   Ram Pai   [PATCH] beginning...
1479
  		return -EINVAL;
7a2e8a8fa   Valerie Aurora   VFS: Sanity check...
1480
1481
1482
  	type = flags_to_propagation_type(flag);
  	if (!type)
  		return -EINVAL;
07b20889e   Ram Pai   [PATCH] beginning...
1483
  	down_write(&namespace_sem);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1484
1485
1486
1487
1488
  	if (type == MS_SHARED) {
  		err = invent_group_ids(mnt, recurse);
  		if (err)
  			goto out_unlock;
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1489
  	br_write_lock(vfsmount_lock);
909b0a88e   Al Viro   vfs: spread struc...
1490
  	for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL))
0f0afb1dc   Al Viro   vfs: spread struc...
1491
  		change_mnt_propagation(m, type);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1492
  	br_write_unlock(vfsmount_lock);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1493
1494
  
   out_unlock:
07b20889e   Ram Pai   [PATCH] beginning...
1495
  	up_write(&namespace_sem);
719f5d7f0   Miklos Szeredi   [patch 4/7] vfs: ...
1496
  	return err;
07b20889e   Ram Pai   [PATCH] beginning...
1497
1498
1499
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1500
1501
   * do loopback mount.
   */
0a0d8a467   Al Viro   [PATCH] no need f...
1502
  static int do_loopback(struct path *path, char *old_name,
2dafe1c4d   Eric Sandeen   reduce large do_m...
1503
  				int recurse)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1504
  {
b12cea919   Al Viro   change the lockin...
1505
  	LIST_HEAD(umount_list);
2d92ab3c6   Al Viro   [PATCH] finally g...
1506
  	struct path old_path;
87129cc0e   Al Viro   vfs: spread struc...
1507
  	struct mount *mnt = NULL, *old;
2d92ab3c6   Al Viro   [PATCH] finally g...
1508
  	int err = mount_is_safe(path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1509
1510
1511
1512
  	if (err)
  		return err;
  	if (!old_name || !*old_name)
  		return -EINVAL;
815d405ce   Trond Myklebust   VFS: Fix the rema...
1513
  	err = kern_path(old_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1514
1515
  	if (err)
  		return err;
b12cea919   Al Viro   change the lockin...
1516
1517
1518
  	err = lock_mount(path);
  	if (err)
  		goto out;
87129cc0e   Al Viro   vfs: spread struc...
1519
  	old = real_mount(old_path.mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1520
  	err = -EINVAL;
fc7be130c   Al Viro   vfs: switch pnode...
1521
  	if (IS_MNT_UNBINDABLE(old))
b12cea919   Al Viro   change the lockin...
1522
  		goto out2;
9676f0c63   Ram Pai   [PATCH] unbindabl...
1523

143c8c91c   Al Viro   vfs: mnt_ns moved...
1524
  	if (!check_mnt(real_mount(path->mnt)) || !check_mnt(old))
b12cea919   Al Viro   change the lockin...
1525
  		goto out2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1526

ccd48bc7f   Al Viro   [PATCH] cleanups ...
1527
1528
  	err = -ENOMEM;
  	if (recurse)
87129cc0e   Al Viro   vfs: spread struc...
1529
  		mnt = copy_tree(old, old_path.dentry, 0);
ccd48bc7f   Al Viro   [PATCH] cleanups ...
1530
  	else
87129cc0e   Al Viro   vfs: spread struc...
1531
  		mnt = clone_mnt(old, old_path.dentry, 0);
ccd48bc7f   Al Viro   [PATCH] cleanups ...
1532
1533
  
  	if (!mnt)
b12cea919   Al Viro   change the lockin...
1534
  		goto out2;
ccd48bc7f   Al Viro   [PATCH] cleanups ...
1535

95bc5f25c   Al Viro   vfs: spread struc...
1536
  	err = graft_tree(mnt, path);
ccd48bc7f   Al Viro   [PATCH] cleanups ...
1537
  	if (err) {
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1538
  		br_write_lock(vfsmount_lock);
761d5c38e   Al Viro   vfs: spread struc...
1539
  		umount_tree(mnt, 0, &umount_list);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1540
  		br_write_unlock(vfsmount_lock);
5b83d2c5c   Ram Pai   [PATCH] sanitize ...
1541
  	}
b12cea919   Al Viro   change the lockin...
1542
1543
1544
  out2:
  	unlock_mount(path);
  	release_mounts(&umount_list);
ccd48bc7f   Al Viro   [PATCH] cleanups ...
1545
  out:
2d92ab3c6   Al Viro   [PATCH] finally g...
1546
  	path_put(&old_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1547
1548
  	return err;
  }
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
  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)
83adc7532   Al Viro   vfs: spread struc...
1560
  		error = mnt_make_readonly(real_mount(mnt));
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
1561
  	else
83adc7532   Al Viro   vfs: spread struc...
1562
  		__mnt_unmake_readonly(real_mount(mnt));
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
1563
1564
  	return error;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1565
1566
1567
1568
1569
  /*
   * 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...
1570
  static int do_remount(struct path *path, int flags, int mnt_flags,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1571
1572
1573
  		      void *data)
  {
  	int err;
2d92ab3c6   Al Viro   [PATCH] finally g...
1574
  	struct super_block *sb = path->mnt->mnt_sb;
143c8c91c   Al Viro   vfs: mnt_ns moved...
1575
  	struct mount *mnt = real_mount(path->mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1576
1577
1578
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
143c8c91c   Al Viro   vfs: mnt_ns moved...
1579
  	if (!check_mnt(mnt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1580
  		return -EINVAL;
2d92ab3c6   Al Viro   [PATCH] finally g...
1581
  	if (path->dentry != path->mnt->mnt_root)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1582
  		return -EINVAL;
ff36fe2c8   Eric Paris   LSM: Pass -o remo...
1583
1584
1585
  	err = security_sb_remount(sb, data);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1586
  	down_write(&sb->s_umount);
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
1587
  	if (flags & MS_BIND)
2d92ab3c6   Al Viro   [PATCH] finally g...
1588
  		err = change_mount_flags(path->mnt, flags);
4aa98cf76   Al Viro   Push BKL down int...
1589
  	else
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
1590
  		err = do_remount_sb(sb, flags, data, 0);
7b43a79f3   Al Viro   mnt_flags fixes i...
1591
  	if (!err) {
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1592
  		br_write_lock(vfsmount_lock);
143c8c91c   Al Viro   vfs: mnt_ns moved...
1593
1594
  		mnt_flags |= mnt->mnt.mnt_flags & MNT_PROPAGATION_MASK;
  		mnt->mnt.mnt_flags = mnt_flags;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1595
  		br_write_unlock(vfsmount_lock);
7b43a79f3   Al Viro   mnt_flags fixes i...
1596
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1597
  	up_write(&sb->s_umount);
0e55a7cca   Dan Williams   [RFC PATCH] touch...
1598
  	if (!err) {
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1599
  		br_write_lock(vfsmount_lock);
143c8c91c   Al Viro   vfs: mnt_ns moved...
1600
  		touch_mnt_namespace(mnt->mnt_ns);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1601
  		br_write_unlock(vfsmount_lock);
0e55a7cca   Dan Williams   [RFC PATCH] touch...
1602
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1603
1604
  	return err;
  }
cbbe362cd   Al Viro   vfs: spread struc...
1605
  static inline int tree_contains_unbindable(struct mount *mnt)
9676f0c63   Ram Pai   [PATCH] unbindabl...
1606
  {
315fc83e5   Al Viro   vfs: spread struc...
1607
  	struct mount *p;
909b0a88e   Al Viro   vfs: spread struc...
1608
  	for (p = mnt; p; p = next_mnt(p, mnt)) {
fc7be130c   Al Viro   vfs: switch pnode...
1609
  		if (IS_MNT_UNBINDABLE(p))
9676f0c63   Ram Pai   [PATCH] unbindabl...
1610
1611
1612
1613
  			return 1;
  	}
  	return 0;
  }
0a0d8a467   Al Viro   [PATCH] no need f...
1614
  static int do_move_mount(struct path *path, char *old_name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1615
  {
2d92ab3c6   Al Viro   [PATCH] finally g...
1616
  	struct path old_path, parent_path;
676da58df   Al Viro   vfs: spread struc...
1617
  	struct mount *p;
0fb54e505   Al Viro   vfs: spread struc...
1618
  	struct mount *old;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1619
1620
1621
1622
1623
  	int err = 0;
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  	if (!old_name || !*old_name)
  		return -EINVAL;
2d92ab3c6   Al Viro   [PATCH] finally g...
1624
  	err = kern_path(old_name, LOOKUP_FOLLOW, &old_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1625
1626
  	if (err)
  		return err;
b12cea919   Al Viro   change the lockin...
1627
  	err = lock_mount(path);
cc53ce53c   David Howells   Add a dentry op t...
1628
1629
  	if (err < 0)
  		goto out;
143c8c91c   Al Viro   vfs: mnt_ns moved...
1630
  	old = real_mount(old_path.mnt);
fc7be130c   Al Viro   vfs: switch pnode...
1631
  	p = real_mount(path->mnt);
143c8c91c   Al Viro   vfs: mnt_ns moved...
1632

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1633
  	err = -EINVAL;
fc7be130c   Al Viro   vfs: switch pnode...
1634
  	if (!check_mnt(p) || !check_mnt(old))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1635
  		goto out1;
f3da392e9   Alexey Dobriyan   dcache: extrace a...
1636
  	if (d_unlinked(path->dentry))
214444032   Ram Pai   [PATCH] shared mo...
1637
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1638
1639
  
  	err = -EINVAL;
2d92ab3c6   Al Viro   [PATCH] finally g...
1640
  	if (old_path.dentry != old_path.mnt->mnt_root)
214444032   Ram Pai   [PATCH] shared mo...
1641
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1642

676da58df   Al Viro   vfs: spread struc...
1643
  	if (!mnt_has_parent(old))
214444032   Ram Pai   [PATCH] shared mo...
1644
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1645

2d92ab3c6   Al Viro   [PATCH] finally g...
1646
1647
  	if (S_ISDIR(path->dentry->d_inode->i_mode) !=
  	      S_ISDIR(old_path.dentry->d_inode->i_mode))
214444032   Ram Pai   [PATCH] shared mo...
1648
1649
1650
1651
  		goto out1;
  	/*
  	 * Don't move a mount residing in a shared parent.
  	 */
fc7be130c   Al Viro   vfs: switch pnode...
1652
  	if (IS_MNT_SHARED(old->mnt_parent))
214444032   Ram Pai   [PATCH] shared mo...
1653
  		goto out1;
9676f0c63   Ram Pai   [PATCH] unbindabl...
1654
1655
1656
1657
  	/*
  	 * Don't move a mount tree containing unbindable mounts to a destination
  	 * mount which is shared.
  	 */
fc7be130c   Al Viro   vfs: switch pnode...
1658
  	if (IS_MNT_SHARED(p) && tree_contains_unbindable(old))
9676f0c63   Ram Pai   [PATCH] unbindabl...
1659
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1660
  	err = -ELOOP;
fc7be130c   Al Viro   vfs: switch pnode...
1661
  	for (; mnt_has_parent(p); p = p->mnt_parent)
676da58df   Al Viro   vfs: spread struc...
1662
  		if (p == old)
214444032   Ram Pai   [PATCH] shared mo...
1663
  			goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1664

0fb54e505   Al Viro   vfs: spread struc...
1665
  	err = attach_recursive_mnt(old, path, &parent_path);
4ac913785   Jan Blunck   Embed a struct pa...
1666
  	if (err)
214444032   Ram Pai   [PATCH] shared mo...
1667
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1668
1669
1670
  
  	/* if the mount is moved, it should no longer be expire
  	 * automatically */
6776db3d3   Al Viro   vfs: take mnt_sha...
1671
  	list_del_init(&old->mnt_expire);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1672
  out1:
b12cea919   Al Viro   change the lockin...
1673
  	unlock_mount(path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1674
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1675
  	if (!err)
1a3906895   Al Viro   [PATCH] reduce st...
1676
  		path_put(&parent_path);
2d92ab3c6   Al Viro   [PATCH] finally g...
1677
  	path_put(&old_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1678
1679
  	return err;
  }
9d412a43c   Al Viro   vfs: split off vf...
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
  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...
1702
  static struct vfsmount *
9d412a43c   Al Viro   vfs: split off vf...
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
  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...
1716
1717
1718
1719
  
  /*
   * add a mount into a namespace's mount tree
   */
95bc5f25c   Al Viro   vfs: spread struc...
1720
  static int do_add_mount(struct mount *newmnt, struct path *path, int mnt_flags)
9d412a43c   Al Viro   vfs: split off vf...
1721
1722
1723
1724
  {
  	int err;
  
  	mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL);
b12cea919   Al Viro   change the lockin...
1725
1726
1727
  	err = lock_mount(path);
  	if (err)
  		return err;
9d412a43c   Al Viro   vfs: split off vf...
1728
1729
  
  	err = -EINVAL;
143c8c91c   Al Viro   vfs: mnt_ns moved...
1730
  	if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(real_mount(path->mnt)))
9d412a43c   Al Viro   vfs: split off vf...
1731
1732
1733
1734
  		goto unlock;
  
  	/* Refuse the same filesystem on the same mount point */
  	err = -EBUSY;
95bc5f25c   Al Viro   vfs: spread struc...
1735
  	if (path->mnt->mnt_sb == newmnt->mnt.mnt_sb &&
9d412a43c   Al Viro   vfs: split off vf...
1736
1737
1738
1739
  	    path->mnt->mnt_root == path->dentry)
  		goto unlock;
  
  	err = -EINVAL;
95bc5f25c   Al Viro   vfs: spread struc...
1740
  	if (S_ISLNK(newmnt->mnt.mnt_root->d_inode->i_mode))
9d412a43c   Al Viro   vfs: split off vf...
1741
  		goto unlock;
95bc5f25c   Al Viro   vfs: spread struc...
1742
  	newmnt->mnt.mnt_flags = mnt_flags;
9d412a43c   Al Viro   vfs: split off vf...
1743
1744
1745
  	err = graft_tree(newmnt, path);
  
  unlock:
b12cea919   Al Viro   change the lockin...
1746
  	unlock_mount(path);
9d412a43c   Al Viro   vfs: split off vf...
1747
1748
  	return err;
  }
b1e75df45   Al Viro   tidy up around fi...
1749

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1750
1751
1752
1753
  /*
   * create a new mount for userspace and request it to be added into the
   * namespace's tree
   */
0a0d8a467   Al Viro   [PATCH] no need f...
1754
  static int do_new_mount(struct path *path, char *type, int flags,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1755
1756
1757
  			int mnt_flags, char *name, void *data)
  {
  	struct vfsmount *mnt;
15f9a3f3e   Al Viro   don't drop newmnt...
1758
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1759

eca6f534e   Vegard Nossum   fs: fix overflow ...
1760
  	if (!type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1761
1762
1763
1764
1765
1766
1767
1768
1769
  		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);
95bc5f25c   Al Viro   vfs: spread struc...
1770
  	err = do_add_mount(real_mount(mnt), path, mnt_flags);
15f9a3f3e   Al Viro   don't drop newmnt...
1771
1772
1773
  	if (err)
  		mntput(mnt);
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1774
  }
19a167af7   Al Viro   Take the completi...
1775
1776
  int finish_automount(struct vfsmount *m, struct path *path)
  {
6776db3d3   Al Viro   vfs: take mnt_sha...
1777
  	struct mount *mnt = real_mount(m);
19a167af7   Al Viro   Take the completi...
1778
1779
1780
1781
  	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
  	 */
6776db3d3   Al Viro   vfs: take mnt_sha...
1782
  	BUG_ON(mnt_get_count(mnt) < 2);
19a167af7   Al Viro   Take the completi...
1783
1784
1785
  
  	if (m->mnt_sb == path->mnt->mnt_sb &&
  	    m->mnt_root == path->dentry) {
b1e75df45   Al Viro   tidy up around fi...
1786
1787
  		err = -ELOOP;
  		goto fail;
19a167af7   Al Viro   Take the completi...
1788
  	}
95bc5f25c   Al Viro   vfs: spread struc...
1789
  	err = do_add_mount(mnt, path, path->mnt->mnt_flags | MNT_SHRINKABLE);
b1e75df45   Al Viro   tidy up around fi...
1790
1791
1792
1793
  	if (!err)
  		return 0;
  fail:
  	/* remove m from any expiration list it may be on */
6776db3d3   Al Viro   vfs: take mnt_sha...
1794
  	if (!list_empty(&mnt->mnt_expire)) {
b1e75df45   Al Viro   tidy up around fi...
1795
1796
  		down_write(&namespace_sem);
  		br_write_lock(vfsmount_lock);
6776db3d3   Al Viro   vfs: take mnt_sha...
1797
  		list_del_init(&mnt->mnt_expire);
b1e75df45   Al Viro   tidy up around fi...
1798
1799
  		br_write_unlock(vfsmount_lock);
  		up_write(&namespace_sem);
19a167af7   Al Viro   Take the completi...
1800
  	}
b1e75df45   Al Viro   tidy up around fi...
1801
1802
  	mntput(m);
  	mntput(m);
19a167af7   Al Viro   Take the completi...
1803
1804
  	return err;
  }
ea5b778a8   David Howells   Unexport do_add_m...
1805
1806
1807
1808
1809
1810
1811
1812
1813
  /**
   * 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);
6776db3d3   Al Viro   vfs: take mnt_sha...
1814
  	list_add_tail(&real_mount(mnt)->mnt_expire, expiry_list);
ea5b778a8   David Howells   Unexport do_add_m...
1815
1816
1817
1818
1819
1820
1821
  
  	br_write_unlock(vfsmount_lock);
  	up_write(&namespace_sem);
  }
  EXPORT_SYMBOL(mnt_set_expiry);
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1822
1823
1824
1825
1826
1827
   * 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)
  {
761d5c38e   Al Viro   vfs: spread struc...
1828
  	struct mount *mnt, *next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1829
  	LIST_HEAD(graveyard);
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
1830
  	LIST_HEAD(umounts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1831
1832
1833
  
  	if (list_empty(mounts))
  		return;
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
1834
  	down_write(&namespace_sem);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1835
  	br_write_lock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1836
1837
1838
1839
1840
1841
1842
  
  	/* 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())
  	 */
6776db3d3   Al Viro   vfs: take mnt_sha...
1843
  	list_for_each_entry_safe(mnt, next, mounts, mnt_expire) {
863d684f9   Al Viro   vfs: move the res...
1844
  		if (!xchg(&mnt->mnt_expiry_mark, 1) ||
1ab597386   Al Viro   vfs: spread struc...
1845
  			propagate_mount_busy(mnt, 1))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1846
  			continue;
6776db3d3   Al Viro   vfs: take mnt_sha...
1847
  		list_move(&mnt->mnt_expire, &graveyard);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1848
  	}
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
1849
  	while (!list_empty(&graveyard)) {
6776db3d3   Al Viro   vfs: take mnt_sha...
1850
  		mnt = list_first_entry(&graveyard, struct mount, mnt_expire);
143c8c91c   Al Viro   vfs: mnt_ns moved...
1851
  		touch_mnt_namespace(mnt->mnt_ns);
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
1852
1853
  		umount_tree(mnt, 1, &umounts);
  	}
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
1854
  	br_write_unlock(vfsmount_lock);
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
1855
1856
1857
  	up_write(&namespace_sem);
  
  	release_mounts(&umounts);
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
  }
  
  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.
   */
692afc312   Al Viro   vfs: spread struc...
1868
  static int select_submounts(struct mount *parent, struct list_head *graveyard)
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1869
  {
692afc312   Al Viro   vfs: spread struc...
1870
  	struct mount *this_parent = parent;
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1871
1872
1873
1874
  	struct list_head *next;
  	int found = 0;
  
  repeat:
6b41d536f   Al Viro   vfs: take mnt_chi...
1875
  	next = this_parent->mnt_mounts.next;
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1876
  resume:
6b41d536f   Al Viro   vfs: take mnt_chi...
1877
  	while (next != &this_parent->mnt_mounts) {
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1878
  		struct list_head *tmp = next;
6b41d536f   Al Viro   vfs: take mnt_chi...
1879
  		struct mount *mnt = list_entry(tmp, struct mount, mnt_child);
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1880
1881
  
  		next = tmp->next;
692afc312   Al Viro   vfs: spread struc...
1882
  		if (!(mnt->mnt.mnt_flags & MNT_SHRINKABLE))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1883
  			continue;
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1884
1885
1886
  		/*
  		 * Descend a level if the d_mounts list is non-empty.
  		 */
6b41d536f   Al Viro   vfs: take mnt_chi...
1887
  		if (!list_empty(&mnt->mnt_mounts)) {
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1888
1889
1890
  			this_parent = mnt;
  			goto repeat;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1891

1ab597386   Al Viro   vfs: spread struc...
1892
  		if (!propagate_mount_busy(mnt, 1)) {
6776db3d3   Al Viro   vfs: take mnt_sha...
1893
  			list_move_tail(&mnt->mnt_expire, graveyard);
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1894
1895
  			found++;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1896
  	}
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1897
1898
1899
1900
  	/*
  	 * All done at this level ... ascend and resume the search
  	 */
  	if (this_parent != parent) {
6b41d536f   Al Viro   vfs: take mnt_chi...
1901
  		next = this_parent->mnt_child.next;
0714a5338   Al Viro   vfs: now it can b...
1902
  		this_parent = this_parent->mnt_parent;
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1903
1904
1905
1906
1907
1908
1909
1910
  		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...
1911
1912
   *
   * vfsmount_lock must be held for write
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1913
   */
692afc312   Al Viro   vfs: spread struc...
1914
  static void shrink_submounts(struct mount *mnt, struct list_head *umounts)
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1915
1916
  {
  	LIST_HEAD(graveyard);
761d5c38e   Al Viro   vfs: spread struc...
1917
  	struct mount *m;
5528f911b   Trond Myklebust   VFS: Add shrink_s...
1918

5528f911b   Trond Myklebust   VFS: Add shrink_s...
1919
  	/* extract submounts of 'mountpoint' from the expiration list */
c35038bec   Al Viro   [PATCH] do shrink...
1920
  	while (select_submounts(mnt, &graveyard)) {
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
1921
  		while (!list_empty(&graveyard)) {
761d5c38e   Al Viro   vfs: spread struc...
1922
  			m = list_first_entry(&graveyard, struct mount,
6776db3d3   Al Viro   vfs: take mnt_sha...
1923
  						mnt_expire);
143c8c91c   Al Viro   vfs: mnt_ns moved...
1924
  			touch_mnt_namespace(m->mnt_ns);
afef80b3d   Eric W. Biederman   vfs: fix shrink_s...
1925
  			umount_tree(m, 1, umounts);
bcc5c7d2b   Al Viro   [PATCH] sanitize ...
1926
1927
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1928
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1929
1930
1931
1932
1933
1934
  /*
   * 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...
1935
1936
  static long exact_copy_from_user(void *to, const void __user * from,
  				 unsigned long n)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
  {
  	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...
1956
  int copy_mount_options(const void __user * data, unsigned long *where)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1957
1958
1959
1960
  {
  	int i;
  	unsigned long page;
  	unsigned long size;
b58fed8b1   Ram Pai   [PATCH] lindent f...
1961

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
  	*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...
1980
  		free_page(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1981
1982
1983
1984
1985
1986
1987
  		return -EFAULT;
  	}
  	if (i != PAGE_SIZE)
  		memset((char *)page + i, 0, PAGE_SIZE - i);
  	*where = page;
  	return 0;
  }
eca6f534e   Vegard Nossum   fs: fix overflow ...
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
  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
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
  /*
   * 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...
2018
  long do_mount(char *dev_name, char *dir_name, char *type_page,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2019
2020
  		  unsigned long flags, void *data_page)
  {
2d92ab3c6   Al Viro   [PATCH] finally g...
2021
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
  	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
2033
2034
2035
  
  	if (data_page)
  		((char *)data_page)[PAGE_SIZE - 1] = 0;
a27ab9f26   Tetsuo Handa   LSM: Pass origina...
2036
2037
2038
2039
2040
2041
2042
2043
2044
  	/* ... 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...
2045
2046
2047
  	/* Default to relatime unless overriden */
  	if (!(flags & MS_NOATIME))
  		mnt_flags |= MNT_RELATIME;
0a1c01c94   Matthew Garrett   Make relatime def...
2048

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2049
2050
2051
2052
2053
2054
2055
  	/* 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...
2056
2057
2058
2059
  	if (flags & MS_NOATIME)
  		mnt_flags |= MNT_NOATIME;
  	if (flags & MS_NODIRATIME)
  		mnt_flags |= MNT_NODIRATIME;
d0adde574   Matthew Garrett   Add a strictatime...
2060
2061
  	if (flags & MS_STRICTATIME)
  		mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME);
2e4b7fcd9   Dave Hansen   [PATCH] r/o bind ...
2062
2063
  	if (flags & MS_RDONLY)
  		mnt_flags |= MNT_READONLY;
fc33a7bb9   Christoph Hellwig   [PATCH] per-mount...
2064

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2069
  	if (flags & MS_REMOUNT)
2d92ab3c6   Al Viro   [PATCH] finally g...
2070
  		retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2071
2072
  				    data_page);
  	else if (flags & MS_BIND)
2d92ab3c6   Al Viro   [PATCH] finally g...
2073
  		retval = do_loopback(&path, dev_name, flags & MS_REC);
9676f0c63   Ram Pai   [PATCH] unbindabl...
2074
  	else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
2d92ab3c6   Al Viro   [PATCH] finally g...
2075
  		retval = do_change_type(&path, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2076
  	else if (flags & MS_MOVE)
2d92ab3c6   Al Viro   [PATCH] finally g...
2077
  		retval = do_move_mount(&path, dev_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2078
  	else
2d92ab3c6   Al Viro   [PATCH] finally g...
2079
  		retval = do_new_mount(&path, type_page, flags, mnt_flags,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2080
2081
  				      dev_name, data_page);
  dput_out:
2d92ab3c6   Al Viro   [PATCH] finally g...
2082
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2083
2084
  	return retval;
  }
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
  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...
2099
2100
  void mnt_make_longterm(struct vfsmount *mnt)
  {
83adc7532   Al Viro   vfs: spread struc...
2101
  	__mnt_make_longterm(real_mount(mnt));
f03c65993   Al Viro   sanitize vfsmount...
2102
  }
83adc7532   Al Viro   vfs: spread struc...
2103
  void mnt_make_shortterm(struct vfsmount *m)
f03c65993   Al Viro   sanitize vfsmount...
2104
  {
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
2105
  #ifdef CONFIG_SMP
83adc7532   Al Viro   vfs: spread struc...
2106
  	struct mount *mnt = real_mount(m);
68e8a9fea   Al Viro   vfs: all counters...
2107
  	if (atomic_add_unless(&mnt->mnt_longterm, -1, 1))
f03c65993   Al Viro   sanitize vfsmount...
2108
2109
  		return;
  	br_write_lock(vfsmount_lock);
68e8a9fea   Al Viro   vfs: all counters...
2110
  	atomic_dec(&mnt->mnt_longterm);
f03c65993   Al Viro   sanitize vfsmount...
2111
  	br_write_unlock(vfsmount_lock);
7e3d0eb0b   Al Viro   VFS: Fix UP compi...
2112
  #endif
f03c65993   Al Viro   sanitize vfsmount...
2113
  }
741a29513   JANAK DESAI   [PATCH] unshare s...
2114
2115
2116
2117
  /*
   * 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()...
2118
  static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2119
  		struct fs_struct *fs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2120
  {
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2121
  	struct mnt_namespace *new_ns;
7f2da1e7d   Al Viro   [PATCH] kill altroot
2122
  	struct vfsmount *rootmnt = NULL, *pwdmnt = NULL;
315fc83e5   Al Viro   vfs: spread struc...
2123
  	struct mount *p, *q;
be08d6d26   Al Viro   switch mnt_namesp...
2124
  	struct mount *old = mnt_ns->root;
cb338d06e   Al Viro   vfs: spread struc...
2125
  	struct mount *new;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2126

cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2127
2128
2129
  	new_ns = alloc_mnt_ns();
  	if (IS_ERR(new_ns))
  		return new_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2130

390c68436   Ram Pai   [PATCH] making na...
2131
  	down_write(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2132
  	/* First pass: copy the tree topology */
909b0a88e   Al Viro   vfs: spread struc...
2133
  	new = copy_tree(old, old->mnt.mnt_root, CL_COPY_ALL | CL_EXPIRE);
cb338d06e   Al Viro   vfs: spread struc...
2134
  	if (!new) {
390c68436   Ram Pai   [PATCH] making na...
2135
  		up_write(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2136
  		kfree(new_ns);
5cc4a0341   Julia Lawall   fs/namespace.c: d...
2137
  		return ERR_PTR(-ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2138
  	}
be08d6d26   Al Viro   switch mnt_namesp...
2139
  	new_ns->root = new;
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2140
  	br_write_lock(vfsmount_lock);
1a4eeaf2a   Al Viro   vfs: move mnt_lis...
2141
  	list_add_tail(&new_ns->list, &new->mnt_list);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2142
  	br_write_unlock(vfsmount_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2143
2144
2145
2146
2147
2148
  
  	/*
  	 * 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.
  	 */
909b0a88e   Al Viro   vfs: spread struc...
2149
  	p = old;
cb338d06e   Al Viro   vfs: spread struc...
2150
  	q = new;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2151
  	while (p) {
143c8c91c   Al Viro   vfs: mnt_ns moved...
2152
  		q->mnt_ns = new_ns;
83adc7532   Al Viro   vfs: spread struc...
2153
  		__mnt_make_longterm(q);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2154
  		if (fs) {
315fc83e5   Al Viro   vfs: spread struc...
2155
2156
  			if (&p->mnt == fs->root.mnt) {
  				fs->root.mnt = mntget(&q->mnt);
83adc7532   Al Viro   vfs: spread struc...
2157
  				__mnt_make_longterm(q);
315fc83e5   Al Viro   vfs: spread struc...
2158
2159
  				mnt_make_shortterm(&p->mnt);
  				rootmnt = &p->mnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2160
  			}
315fc83e5   Al Viro   vfs: spread struc...
2161
2162
  			if (&p->mnt == fs->pwd.mnt) {
  				fs->pwd.mnt = mntget(&q->mnt);
83adc7532   Al Viro   vfs: spread struc...
2163
  				__mnt_make_longterm(q);
315fc83e5   Al Viro   vfs: spread struc...
2164
2165
  				mnt_make_shortterm(&p->mnt);
  				pwdmnt = &p->mnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2166
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2167
  		}
909b0a88e   Al Viro   vfs: spread struc...
2168
2169
  		p = next_mnt(p, old);
  		q = next_mnt(q, new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2170
  	}
390c68436   Ram Pai   [PATCH] making na...
2171
  	up_write(&namespace_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2172

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2173
  	if (rootmnt)
f03c65993   Al Viro   sanitize vfsmount...
2174
  		mntput(rootmnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2175
  	if (pwdmnt)
f03c65993   Al Viro   sanitize vfsmount...
2176
  		mntput(pwdmnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2177

741a29513   JANAK DESAI   [PATCH] unshare s...
2178
2179
  	return new_ns;
  }
213dd266d   Eric W. Biederman   namespace: ensure...
2180
  struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
2181
  		struct fs_struct *new_fs)
741a29513   JANAK DESAI   [PATCH] unshare s...
2182
  {
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2183
  	struct mnt_namespace *new_ns;
741a29513   JANAK DESAI   [PATCH] unshare s...
2184

e3222c4ec   Badari Pulavarty   Merge sys_clone()...
2185
  	BUG_ON(!ns);
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2186
  	get_mnt_ns(ns);
741a29513   JANAK DESAI   [PATCH] unshare s...
2187
2188
  
  	if (!(flags & CLONE_NEWNS))
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
2189
  		return ns;
741a29513   JANAK DESAI   [PATCH] unshare s...
2190

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

6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2193
  	put_mnt_ns(ns);
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
2194
  	return new_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2195
  }
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2196
2197
2198
2199
  /**
   * create_mnt_ns - creates a private namespace and adds a root filesystem
   * @mnt: pointer to the new root filesystem mountpoint
   */
1a4eeaf2a   Al Viro   vfs: move mnt_lis...
2200
  static struct mnt_namespace *create_mnt_ns(struct vfsmount *m)
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2201
  {
1a4eeaf2a   Al Viro   vfs: move mnt_lis...
2202
  	struct mnt_namespace *new_ns = alloc_mnt_ns();
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2203
  	if (!IS_ERR(new_ns)) {
1a4eeaf2a   Al Viro   vfs: move mnt_lis...
2204
2205
2206
  		struct mount *mnt = real_mount(m);
  		mnt->mnt_ns = new_ns;
  		__mnt_make_longterm(mnt);
be08d6d26   Al Viro   switch mnt_namesp...
2207
  		new_ns->root = mnt;
1a4eeaf2a   Al Viro   vfs: move mnt_lis...
2208
  		list_add(&new_ns->list, &mnt->mnt_list);
c13344958   Al Viro   switch create_mnt...
2209
  	} else {
1a4eeaf2a   Al Viro   vfs: move mnt_lis...
2210
  		mntput(m);
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2211
2212
2213
  	}
  	return new_ns;
  }
cf8d2c11c   Trond Myklebust   VFS: Add VFS help...
2214

ea441d110   Al Viro   new helper: mount...
2215
2216
2217
  struct dentry *mount_subtree(struct vfsmount *mnt, const char *name)
  {
  	struct mnt_namespace *ns;
d31da0f0b   Al Viro   mount_subtree() p...
2218
  	struct super_block *s;
ea441d110   Al Viro   new helper: mount...
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
  	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...
2235
2236
  	s = path.mnt->mnt_sb;
  	atomic_inc(&s->s_active);
ea441d110   Al Viro   new helper: mount...
2237
2238
  	mntput(path.mnt);
  	/* lock the sucker */
d31da0f0b   Al Viro   mount_subtree() p...
2239
  	down_write(&s->s_umount);
ea441d110   Al Viro   new helper: mount...
2240
2241
2242
2243
  	/* ... and return the root of (sub)tree on it */
  	return path.dentry;
  }
  EXPORT_SYMBOL(mount_subtree);
bdc480e3b   Heiko Carstens   [CVE-2009-0029] S...
2244
2245
  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
2246
  {
eca6f534e   Vegard Nossum   fs: fix overflow ...
2247
2248
2249
2250
  	int ret;
  	char *kernel_type;
  	char *kernel_dir;
  	char *kernel_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2251
  	unsigned long data_page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2252

eca6f534e   Vegard Nossum   fs: fix overflow ...
2253
2254
2255
  	ret = copy_mount_string(type, &kernel_type);
  	if (ret < 0)
  		goto out_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2256

eca6f534e   Vegard Nossum   fs: fix overflow ...
2257
2258
2259
2260
2261
  	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
2262

eca6f534e   Vegard Nossum   fs: fix overflow ...
2263
2264
2265
  	ret = copy_mount_string(dev_name, &kernel_dev);
  	if (ret < 0)
  		goto out_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2266

eca6f534e   Vegard Nossum   fs: fix overflow ...
2267
2268
2269
  	ret = copy_mount_options(data, &data_page);
  	if (ret < 0)
  		goto out_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2270

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

eca6f534e   Vegard Nossum   fs: fix overflow ...
2274
2275
2276
2277
2278
2279
2280
2281
2282
  	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
2283
2284
2285
  }
  
  /*
afac7cba7   Al Viro   vfs: more mnt_par...
2286
2287
2288
2289
   * Return true if path is reachable from root
   *
   * namespace_sem or vfsmount_lock is held
   */
643822b41   Al Viro   vfs: spread struc...
2290
  bool is_path_reachable(struct mount *mnt, struct dentry *dentry,
afac7cba7   Al Viro   vfs: more mnt_par...
2291
2292
  			 const struct path *root)
  {
643822b41   Al Viro   vfs: spread struc...
2293
  	while (&mnt->mnt != root->mnt && mnt_has_parent(mnt)) {
a73324da7   Al Viro   vfs: move mnt_mou...
2294
  		dentry = mnt->mnt_mountpoint;
0714a5338   Al Viro   vfs: now it can b...
2295
  		mnt = mnt->mnt_parent;
afac7cba7   Al Viro   vfs: more mnt_par...
2296
  	}
643822b41   Al Viro   vfs: spread struc...
2297
  	return &mnt->mnt == root->mnt && is_subdir(dentry, root->dentry);
afac7cba7   Al Viro   vfs: more mnt_par...
2298
2299
2300
2301
2302
2303
  }
  
  int path_is_under(struct path *path1, struct path *path2)
  {
  	int res;
  	br_read_lock(vfsmount_lock);
643822b41   Al Viro   vfs: spread struc...
2304
  	res = is_path_reachable(real_mount(path1->mnt), path1->dentry, path2);
afac7cba7   Al Viro   vfs: more mnt_par...
2305
2306
2307
2308
2309
2310
  	br_read_unlock(vfsmount_lock);
  	return res;
  }
  EXPORT_SYMBOL(path_is_under);
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
   * 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...
2323
2324
2325
2326
   * 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
2327
2328
2329
2330
2331
2332
2333
2334
   * 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...
2335
2336
  SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
  		const char __user *, put_old)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2337
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
2338
  	struct path new, old, parent_path, root_parent, root;
419148da6   Al Viro   vfs: spread struc...
2339
  	struct mount *new_mnt, *root_mnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2340
2341
2342
2343
  	int error;
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
2d8f30380   Al Viro   [PATCH] sanitize ...
2344
  	error = user_path_dir(new_root, &new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2345
2346
  	if (error)
  		goto out0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2347

2d8f30380   Al Viro   [PATCH] sanitize ...
2348
  	error = user_path_dir(put_old, &old);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2349
2350
  	if (error)
  		goto out1;
2d8f30380   Al Viro   [PATCH] sanitize ...
2351
  	error = security_sb_pivotroot(&old, &new);
b12cea919   Al Viro   change the lockin...
2352
2353
  	if (error)
  		goto out2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2354

f7ad3c6be   Miklos Szeredi   vfs: add helpers ...
2355
  	get_fs_root(current->fs, &root);
b12cea919   Al Viro   change the lockin...
2356
2357
2358
  	error = lock_mount(&old);
  	if (error)
  		goto out3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2359
  	error = -EINVAL;
419148da6   Al Viro   vfs: spread struc...
2360
2361
  	new_mnt = real_mount(new.mnt);
  	root_mnt = real_mount(root.mnt);
fc7be130c   Al Viro   vfs: switch pnode...
2362
2363
2364
  	if (IS_MNT_SHARED(real_mount(old.mnt)) ||
  		IS_MNT_SHARED(new_mnt->mnt_parent) ||
  		IS_MNT_SHARED(root_mnt->mnt_parent))
b12cea919   Al Viro   change the lockin...
2365
  		goto out4;
143c8c91c   Al Viro   vfs: mnt_ns moved...
2366
  	if (!check_mnt(root_mnt) || !check_mnt(new_mnt))
b12cea919   Al Viro   change the lockin...
2367
  		goto out4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2368
  	error = -ENOENT;
f3da392e9   Alexey Dobriyan   dcache: extrace a...
2369
  	if (d_unlinked(new.dentry))
b12cea919   Al Viro   change the lockin...
2370
  		goto out4;
f3da392e9   Alexey Dobriyan   dcache: extrace a...
2371
  	if (d_unlinked(old.dentry))
b12cea919   Al Viro   change the lockin...
2372
  		goto out4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2373
  	error = -EBUSY;
2d8f30380   Al Viro   [PATCH] sanitize ...
2374
2375
  	if (new.mnt == root.mnt ||
  	    old.mnt == root.mnt)
b12cea919   Al Viro   change the lockin...
2376
  		goto out4; /* loop, on the same file system  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2377
  	error = -EINVAL;
8c3ee42e8   Al Viro   [PATCH] get rid o...
2378
  	if (root.mnt->mnt_root != root.dentry)
b12cea919   Al Viro   change the lockin...
2379
  		goto out4; /* not a mountpoint */
676da58df   Al Viro   vfs: spread struc...
2380
  	if (!mnt_has_parent(root_mnt))
b12cea919   Al Viro   change the lockin...
2381
  		goto out4; /* not attached */
2d8f30380   Al Viro   [PATCH] sanitize ...
2382
  	if (new.mnt->mnt_root != new.dentry)
b12cea919   Al Viro   change the lockin...
2383
  		goto out4; /* not a mountpoint */
676da58df   Al Viro   vfs: spread struc...
2384
  	if (!mnt_has_parent(new_mnt))
b12cea919   Al Viro   change the lockin...
2385
  		goto out4; /* not attached */
4ac913785   Jan Blunck   Embed a struct pa...
2386
  	/* make sure we can reach put_old from new_root */
643822b41   Al Viro   vfs: spread struc...
2387
  	if (!is_path_reachable(real_mount(old.mnt), old.dentry, &new))
b12cea919   Al Viro   change the lockin...
2388
  		goto out4;
27cb1572e   Al Viro   fix deadlock in p...
2389
  	br_write_lock(vfsmount_lock);
419148da6   Al Viro   vfs: spread struc...
2390
2391
  	detach_mnt(new_mnt, &parent_path);
  	detach_mnt(root_mnt, &root_parent);
4ac913785   Jan Blunck   Embed a struct pa...
2392
  	/* mount old root on put_old */
419148da6   Al Viro   vfs: spread struc...
2393
  	attach_mnt(root_mnt, &old);
4ac913785   Jan Blunck   Embed a struct pa...
2394
  	/* mount new_root on / */
419148da6   Al Viro   vfs: spread struc...
2395
  	attach_mnt(new_mnt, &root_parent);
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2396
  	touch_mnt_namespace(current->nsproxy->mnt_ns);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2397
  	br_write_unlock(vfsmount_lock);
2d8f30380   Al Viro   [PATCH] sanitize ...
2398
  	chroot_fs_refs(&root, &new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2399
  	error = 0;
b12cea919   Al Viro   change the lockin...
2400
2401
2402
2403
2404
2405
2406
  out4:
  	unlock_mount(&old);
  	if (!error) {
  		path_put(&root_parent);
  		path_put(&parent_path);
  	}
  out3:
8c3ee42e8   Al Viro   [PATCH] get rid o...
2407
  	path_put(&root);
b12cea919   Al Viro   change the lockin...
2408
  out2:
2d8f30380   Al Viro   [PATCH] sanitize ...
2409
  	path_put(&old);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2410
  out1:
2d8f30380   Al Viro   [PATCH] sanitize ...
2411
  	path_put(&new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2412
  out0:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2413
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2414
2415
2416
2417
2418
  }
  
  static void __init init_mount_tree(void)
  {
  	struct vfsmount *mnt;
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2419
  	struct mnt_namespace *ns;
ac748a09f   Jan Blunck   Make set_fs_{root...
2420
  	struct path root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2421
2422
2423
2424
  
  	mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
  	if (IS_ERR(mnt))
  		panic("Can't create rootfs");
b3e19d924   Nick Piggin   fs: scale mntget/...
2425

3b22edc57   Trond Myklebust   VFS: Switch init_...
2426
2427
  	ns = create_mnt_ns(mnt);
  	if (IS_ERR(ns))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2428
  		panic("Can't allocate initial namespace");
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2429
2430
2431
  
  	init_task.nsproxy->mnt_ns = ns;
  	get_mnt_ns(ns);
be08d6d26   Al Viro   switch mnt_namesp...
2432
2433
  	root.mnt = mnt;
  	root.dentry = mnt->mnt_root;
ac748a09f   Jan Blunck   Make set_fs_{root...
2434
2435
2436
  
  	set_fs_pwd(current->fs, &root);
  	set_fs_root(current->fs, &root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2437
  }
74bf17cff   Denis Cheng   fs: remove the un...
2438
  void __init mnt_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2439
  {
13f14b4d8   Eric Dumazet   Use ilog2() in fs...
2440
  	unsigned u;
15a67dd8c   Randy Dunlap   [PATCH] fs/namesp...
2441
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2442

390c68436   Ram Pai   [PATCH] making na...
2443
  	init_rwsem(&namespace_sem);
7d6fec45a   Al Viro   vfs: start hiding...
2444
  	mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct mount),
20c2df83d   Paul Mundt   mm: Remove slab d...
2445
  			0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2446

b58fed8b1   Ram Pai   [PATCH] lindent f...
2447
  	mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2448
2449
2450
2451
  
  	if (!mount_hashtable)
  		panic("Failed to allocate mount hash table
  ");
80cdc6dae   Mandeep Singh Baines   fs: use appropria...
2452
2453
  	printk(KERN_INFO "Mount-cache hash table entries: %lu
  ", HASH_SIZE);
13f14b4d8   Eric Dumazet   Use ilog2() in fs...
2454
2455
2456
  
  	for (u = 0; u < HASH_SIZE; u++)
  		INIT_LIST_HEAD(&mount_hashtable[u]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2457

99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2458
  	br_lock_init(vfsmount_lock);
15a67dd8c   Randy Dunlap   [PATCH] fs/namesp...
2459
2460
2461
2462
  	err = sysfs_init();
  	if (err)
  		printk(KERN_WARNING "%s: sysfs_init error: %d
  ",
8e24eea72   Harvey Harrison   fs: replace remai...
2463
  			__func__, err);
00d266662   Greg Kroah-Hartman   kobject: convert ...
2464
2465
  	fs_kobj = kobject_create_and_add("fs", NULL);
  	if (!fs_kobj)
8e24eea72   Harvey Harrison   fs: replace remai...
2466
2467
  		printk(KERN_WARNING "%s: kobj create error
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2468
2469
2470
  	init_rootfs();
  	init_mount_tree();
  }
616511d03   Trond Myklebust   VFS: Uninline the...
2471
  void put_mnt_ns(struct mnt_namespace *ns)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2472
  {
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
2473
  	LIST_HEAD(umount_list);
616511d03   Trond Myklebust   VFS: Uninline the...
2474

d498b25a4   Al Viro   get rid of useles...
2475
  	if (!atomic_dec_and_test(&ns->count))
616511d03   Trond Myklebust   VFS: Uninline the...
2476
  		return;
390c68436   Ram Pai   [PATCH] making na...
2477
  	down_write(&namespace_sem);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2478
  	br_write_lock(vfsmount_lock);
be08d6d26   Al Viro   switch mnt_namesp...
2479
  	umount_tree(ns->root, 0, &umount_list);
99b7db7b8   Nick Piggin   fs: brlock vfsmou...
2480
  	br_write_unlock(vfsmount_lock);
390c68436   Ram Pai   [PATCH] making na...
2481
  	up_write(&namespace_sem);
70fbcdf4d   Ram Pai   [PATCH] umount_tr...
2482
  	release_mounts(&umount_list);
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
2483
  	kfree(ns);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2484
  }
9d412a43c   Al Viro   vfs: split off vf...
2485
2486
2487
  
  struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
  {
423e0ab08   Tim Chen   VFS : mount lock ...
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
  	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...
2498
2499
  }
  EXPORT_SYMBOL_GPL(kern_mount_data);
423e0ab08   Tim Chen   VFS : mount lock ...
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
  
  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...
2510
2511
2512
  
  bool our_mnt(struct vfsmount *mnt)
  {
143c8c91c   Al Viro   vfs: mnt_ns moved...
2513
  	return check_mnt(real_mount(mnt));
02125a826   Al Viro   fix apparmor dere...
2514
  }