Blame view
fs/namespace.c
63.2 KB
1da177e4c 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 Linux-2.6.12-rc2 |
10 |
#include <linux/syscalls.h> |
d10577a8d vfs: trim include... |
11 |
#include <linux/export.h> |
16f7e0fe2 [PATCH] capable/c... |
12 |
#include <linux/capability.h> |
6b3286ed1 [PATCH] rename st... |
13 |
#include <linux/mnt_namespace.h> |
1da177e4c Linux-2.6.12-rc2 |
14 15 |
#include <linux/namei.h> #include <linux/security.h> |
73cd49ecd [patch 3/7] vfs: ... |
16 |
#include <linux/idr.h> |
d10577a8d 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 [PATCH] beginning... |
22 |
#include "pnode.h" |
948730b0e fs/namespace.c sh... |
23 |
#include "internal.h" |
1da177e4c Linux-2.6.12-rc2 |
24 |
|
13f14b4d8 Use ilog2() in fs... |
25 26 |
#define HASH_SHIFT ilog2(PAGE_SIZE / sizeof(struct list_head)) #define HASH_SIZE (1UL << HASH_SHIFT) |
5addc5dd8 [PATCH] make /pro... |
27 |
static int event; |
73cd49ecd [patch 3/7] vfs: ... |
28 |
static DEFINE_IDA(mnt_id_ida); |
719f5d7f0 [patch 4/7] vfs: ... |
29 |
static DEFINE_IDA(mnt_group_ida); |
99b7db7b8 fs: brlock vfsmou... |
30 |
static DEFINE_SPINLOCK(mnt_id_lock); |
f21f62208 ... and the same ... |
31 32 |
static int mnt_id_start = 0; static int mnt_group_start = 1; |
1da177e4c Linux-2.6.12-rc2 |
33 |
|
fa3536cc1 [PATCH] Use __rea... |
34 |
static struct list_head *mount_hashtable __read_mostly; |
e18b890bb [PATCH] slab: rem... |
35 |
static struct kmem_cache *mnt_cache __read_mostly; |
390c68436 [PATCH] making na... |
36 |
static struct rw_semaphore namespace_sem; |
1da177e4c Linux-2.6.12-rc2 |
37 |
|
f87fd4c2a [PATCH] add /sys/fs |
38 |
/* /sys/fs */ |
00d266662 kobject: convert ... |
39 40 |
struct kobject *fs_kobj; EXPORT_SYMBOL_GPL(fs_kobj); |
f87fd4c2a [PATCH] add /sys/fs |
41 |
|
99b7db7b8 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 Linux-2.6.12-rc2 |
51 52 |
static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) { |
b58fed8b1 [PATCH] lindent f... |
53 54 |
unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES); tmp += ((unsigned long)dentry / L1_CACHE_BYTES); |
13f14b4d8 Use ilog2() in fs... |
55 56 |
tmp = tmp + (tmp >> HASH_SHIFT); return tmp & (HASH_SIZE - 1); |
1da177e4c Linux-2.6.12-rc2 |
57 |
} |
3d733633a [PATCH] r/o bind ... |
58 |
#define MNT_WRITER_UNDERFLOW_LIMIT -(1<<16) |
99b7db7b8 fs: brlock vfsmou... |
59 60 61 62 |
/* * allocation is serialized by namespace_sem, but we need the spinlock to * serialize with freeing. */ |
b105e270b vfs: spread struc... |
63 |
static int mnt_alloc_id(struct mount *mnt) |
73cd49ecd [patch 3/7] vfs: ... |
64 65 66 67 68 |
{ int res; retry: ida_pre_get(&mnt_id_ida, GFP_KERNEL); |
99b7db7b8 fs: brlock vfsmou... |
69 |
spin_lock(&mnt_id_lock); |
15169fe78 vfs: mnt_id/mnt_g... |
70 |
res = ida_get_new_above(&mnt_id_ida, mnt_id_start, &mnt->mnt_id); |
f21f62208 ... and the same ... |
71 |
if (!res) |
15169fe78 vfs: mnt_id/mnt_g... |
72 |
mnt_id_start = mnt->mnt_id + 1; |
99b7db7b8 fs: brlock vfsmou... |
73 |
spin_unlock(&mnt_id_lock); |
73cd49ecd [patch 3/7] vfs: ... |
74 75 76 77 78 |
if (res == -EAGAIN) goto retry; return res; } |
b105e270b vfs: spread struc... |
79 |
static void mnt_free_id(struct mount *mnt) |
73cd49ecd [patch 3/7] vfs: ... |
80 |
{ |
15169fe78 vfs: mnt_id/mnt_g... |
81 |
int id = mnt->mnt_id; |
99b7db7b8 fs: brlock vfsmou... |
82 |
spin_lock(&mnt_id_lock); |
f21f62208 ... and the same ... |
83 84 85 |
ida_remove(&mnt_id_ida, id); if (mnt_id_start > id) mnt_id_start = id; |
99b7db7b8 fs: brlock vfsmou... |
86 |
spin_unlock(&mnt_id_lock); |
73cd49ecd [patch 3/7] vfs: ... |
87 |
} |
719f5d7f0 [patch 4/7] vfs: ... |
88 89 90 91 92 |
/* * Allocate a new peer group ID * * mnt_group_ida is protected by namespace_sem */ |
4b8b21f4f vfs: spread struc... |
93 |
static int mnt_alloc_group_id(struct mount *mnt) |
719f5d7f0 [patch 4/7] vfs: ... |
94 |
{ |
f21f62208 ... and the same ... |
95 |
int res; |
719f5d7f0 [patch 4/7] vfs: ... |
96 97 |
if (!ida_pre_get(&mnt_group_ida, GFP_KERNEL)) return -ENOMEM; |
f21f62208 ... and the same ... |
98 99 |
res = ida_get_new_above(&mnt_group_ida, mnt_group_start, |
15169fe78 vfs: mnt_id/mnt_g... |
100 |
&mnt->mnt_group_id); |
f21f62208 ... and the same ... |
101 |
if (!res) |
15169fe78 vfs: mnt_id/mnt_g... |
102 |
mnt_group_start = mnt->mnt_group_id + 1; |
f21f62208 ... and the same ... |
103 104 |
return res; |
719f5d7f0 [patch 4/7] vfs: ... |
105 106 107 108 109 |
} /* * Release a peer group ID */ |
4b8b21f4f vfs: spread struc... |
110 |
void mnt_release_group_id(struct mount *mnt) |
719f5d7f0 [patch 4/7] vfs: ... |
111 |
{ |
15169fe78 vfs: mnt_id/mnt_g... |
112 |
int id = mnt->mnt_group_id; |
f21f62208 ... and the same ... |
113 114 115 |
ida_remove(&mnt_group_ida, id); if (mnt_group_start > id) mnt_group_start = id; |
15169fe78 vfs: mnt_id/mnt_g... |
116 |
mnt->mnt_group_id = 0; |
719f5d7f0 [patch 4/7] vfs: ... |
117 |
} |
b3e19d924 fs: scale mntget/... |
118 119 120 |
/* * vfsmount lock must be held for read */ |
83adc7532 vfs: spread struc... |
121 |
static inline void mnt_add_count(struct mount *mnt, int n) |
b3e19d924 fs: scale mntget/... |
122 123 |
{ #ifdef CONFIG_SMP |
68e8a9fea vfs: all counters... |
124 |
this_cpu_add(mnt->mnt_pcp->mnt_count, n); |
b3e19d924 fs: scale mntget/... |
125 126 |
#else preempt_disable(); |
68e8a9fea vfs: all counters... |
127 |
mnt->mnt_count += n; |
b3e19d924 fs: scale mntget/... |
128 129 130 |
preempt_enable(); #endif } |
b3e19d924 fs: scale mntget/... |
131 132 133 |
/* * vfsmount lock must be held for write */ |
83adc7532 vfs: spread struc... |
134 |
unsigned int mnt_get_count(struct mount *mnt) |
b3e19d924 fs: scale mntget/... |
135 136 |
{ #ifdef CONFIG_SMP |
f03c65993 sanitize vfsmount... |
137 |
unsigned int count = 0; |
b3e19d924 fs: scale mntget/... |
138 139 140 |
int cpu; for_each_possible_cpu(cpu) { |
68e8a9fea vfs: all counters... |
141 |
count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_count; |
b3e19d924 fs: scale mntget/... |
142 143 144 145 |
} return count; #else |
68e8a9fea vfs: all counters... |
146 |
return mnt->mnt_count; |
b3e19d924 fs: scale mntget/... |
147 148 |
#endif } |
b105e270b vfs: spread struc... |
149 |
static struct mount *alloc_vfsmnt(const char *name) |
1da177e4c Linux-2.6.12-rc2 |
150 |
{ |
c63181e6b vfs: move fsnotif... |
151 152 |
struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); if (mnt) { |
73cd49ecd [patch 3/7] vfs: ... |
153 |
int err; |
c63181e6b vfs: move fsnotif... |
154 |
err = mnt_alloc_id(mnt); |
88b387824 [PATCH] vfs: use ... |
155 156 157 158 |
if (err) goto out_free_cache; if (name) { |
c63181e6b vfs: move fsnotif... |
159 160 |
mnt->mnt_devname = kstrdup(name, GFP_KERNEL); if (!mnt->mnt_devname) |
88b387824 [PATCH] vfs: use ... |
161 |
goto out_free_id; |
73cd49ecd [patch 3/7] vfs: ... |
162 |
} |
b3e19d924 fs: scale mntget/... |
163 |
#ifdef CONFIG_SMP |
c63181e6b vfs: move fsnotif... |
164 165 |
mnt->mnt_pcp = alloc_percpu(struct mnt_pcp); if (!mnt->mnt_pcp) |
b3e19d924 fs: scale mntget/... |
166 |
goto out_free_devname; |
c63181e6b vfs: move fsnotif... |
167 |
this_cpu_add(mnt->mnt_pcp->mnt_count, 1); |
b3e19d924 fs: scale mntget/... |
168 |
#else |
c63181e6b vfs: move fsnotif... |
169 170 |
mnt->mnt_count = 1; mnt->mnt_writers = 0; |
b3e19d924 fs: scale mntget/... |
171 |
#endif |
c63181e6b 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 fsnotify/vfsmount... |
180 181 182 |
#ifdef CONFIG_FSNOTIFY INIT_HLIST_HEAD(&mnt->mnt_fsnotify_marks); #endif |
1da177e4c Linux-2.6.12-rc2 |
183 |
} |
c63181e6b vfs: move fsnotif... |
184 |
return mnt; |
88b387824 [PATCH] vfs: use ... |
185 |
|
d3ef3d735 fs: mnt_want_writ... |
186 187 |
#ifdef CONFIG_SMP out_free_devname: |
c63181e6b vfs: move fsnotif... |
188 |
kfree(mnt->mnt_devname); |
d3ef3d735 fs: mnt_want_writ... |
189 |
#endif |
88b387824 [PATCH] vfs: use ... |
190 |
out_free_id: |
c63181e6b vfs: move fsnotif... |
191 |
mnt_free_id(mnt); |
88b387824 [PATCH] vfs: use ... |
192 |
out_free_cache: |
c63181e6b vfs: move fsnotif... |
193 |
kmem_cache_free(mnt_cache, mnt); |
88b387824 [PATCH] vfs: use ... |
194 |
return NULL; |
1da177e4c Linux-2.6.12-rc2 |
195 |
} |
8366025eb [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 [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 [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 [PATCH] r/o bind ... |
222 223 |
} EXPORT_SYMBOL_GPL(__mnt_is_readonly); |
83adc7532 vfs: spread struc... |
224 |
static inline void mnt_inc_writers(struct mount *mnt) |
d3ef3d735 fs: mnt_want_writ... |
225 226 |
{ #ifdef CONFIG_SMP |
68e8a9fea vfs: all counters... |
227 |
this_cpu_inc(mnt->mnt_pcp->mnt_writers); |
d3ef3d735 fs: mnt_want_writ... |
228 |
#else |
68e8a9fea vfs: all counters... |
229 |
mnt->mnt_writers++; |
d3ef3d735 fs: mnt_want_writ... |
230 231 |
#endif } |
3d733633a [PATCH] r/o bind ... |
232 |
|
83adc7532 vfs: spread struc... |
233 |
static inline void mnt_dec_writers(struct mount *mnt) |
3d733633a [PATCH] r/o bind ... |
234 |
{ |
d3ef3d735 fs: mnt_want_writ... |
235 |
#ifdef CONFIG_SMP |
68e8a9fea vfs: all counters... |
236 |
this_cpu_dec(mnt->mnt_pcp->mnt_writers); |
d3ef3d735 fs: mnt_want_writ... |
237 |
#else |
68e8a9fea vfs: all counters... |
238 |
mnt->mnt_writers--; |
d3ef3d735 fs: mnt_want_writ... |
239 |
#endif |
3d733633a [PATCH] r/o bind ... |
240 |
} |
3d733633a [PATCH] r/o bind ... |
241 |
|
83adc7532 vfs: spread struc... |
242 |
static unsigned int mnt_get_writers(struct mount *mnt) |
3d733633a [PATCH] r/o bind ... |
243 |
{ |
d3ef3d735 fs: mnt_want_writ... |
244 245 |
#ifdef CONFIG_SMP unsigned int count = 0; |
3d733633a [PATCH] r/o bind ... |
246 |
int cpu; |
3d733633a [PATCH] r/o bind ... |
247 248 |
for_each_possible_cpu(cpu) { |
68e8a9fea vfs: all counters... |
249 |
count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_writers; |
3d733633a [PATCH] r/o bind ... |
250 |
} |
3d733633a [PATCH] r/o bind ... |
251 |
|
d3ef3d735 fs: mnt_want_writ... |
252 253 254 255 |
return count; #else return mnt->mnt_writers; #endif |
3d733633a [PATCH] r/o bind ... |
256 |
} |
4ed5e82fe 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 [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 [PATCH] r/o bind ... |
273 274 |
/** * mnt_want_write - get write access to a mount |
83adc7532 vfs: spread struc... |
275 |
* @m: the mount on which to take a write |
8366025eb [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 vfs: spread struc... |
283 |
int mnt_want_write(struct vfsmount *m) |
8366025eb [PATCH] r/o bind ... |
284 |
{ |
83adc7532 vfs: spread struc... |
285 |
struct mount *mnt = real_mount(m); |
3d733633a [PATCH] r/o bind ... |
286 |
int ret = 0; |
3d733633a [PATCH] r/o bind ... |
287 |
|
d3ef3d735 fs: mnt_want_writ... |
288 |
preempt_disable(); |
c6653a838 fs: rename vfsmou... |
289 |
mnt_inc_writers(mnt); |
d3ef3d735 fs: mnt_want_writ... |
290 |
/* |
c6653a838 fs: rename vfsmou... |
291 |
* The store to mnt_inc_writers must be visible before we pass |
d3ef3d735 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 vfs: spread struc... |
296 |
while (mnt->mnt.mnt_flags & MNT_WRITE_HOLD) |
d3ef3d735 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 vfs: protect remo... |
304 |
if (mnt_is_readonly(m)) { |
c6653a838 fs: rename vfsmou... |
305 |
mnt_dec_writers(mnt); |
3d733633a [PATCH] r/o bind ... |
306 |
ret = -EROFS; |
3d733633a [PATCH] r/o bind ... |
307 |
} |
d3ef3d735 fs: mnt_want_writ... |
308 |
preempt_enable(); |
3d733633a [PATCH] r/o bind ... |
309 |
return ret; |
8366025eb [PATCH] r/o bind ... |
310 311 312 313 |
} EXPORT_SYMBOL_GPL(mnt_want_write); /** |
96029c4e0 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 vfs: spread struc... |
331 |
mnt_inc_writers(real_mount(mnt)); |
96029c4e0 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 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 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 [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 fs: mnt_want_writ... |
364 |
preempt_disable(); |
83adc7532 vfs: spread struc... |
365 |
mnt_dec_writers(real_mount(mnt)); |
d3ef3d735 fs: mnt_want_writ... |
366 |
preempt_enable(); |
8366025eb [PATCH] r/o bind ... |
367 368 |
} EXPORT_SYMBOL_GPL(mnt_drop_write); |
2a79f17e4 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 vfs: spread struc... |
374 |
static int mnt_make_readonly(struct mount *mnt) |
8366025eb [PATCH] r/o bind ... |
375 |
{ |
3d733633a [PATCH] r/o bind ... |
376 |
int ret = 0; |
99b7db7b8 fs: brlock vfsmou... |
377 |
br_write_lock(vfsmount_lock); |
83adc7532 vfs: spread struc... |
378 |
mnt->mnt.mnt_flags |= MNT_WRITE_HOLD; |
3d733633a [PATCH] r/o bind ... |
379 |
/* |
d3ef3d735 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 [PATCH] r/o bind ... |
382 |
*/ |
d3ef3d735 fs: mnt_want_writ... |
383 |
smp_mb(); |
3d733633a [PATCH] r/o bind ... |
384 |
/* |
d3ef3d735 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 [PATCH] r/o bind ... |
399 |
*/ |
c6653a838 fs: rename vfsmou... |
400 |
if (mnt_get_writers(mnt) > 0) |
d3ef3d735 fs: mnt_want_writ... |
401 402 |
ret = -EBUSY; else |
83adc7532 vfs: spread struc... |
403 |
mnt->mnt.mnt_flags |= MNT_READONLY; |
d3ef3d735 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 vfs: spread struc... |
409 |
mnt->mnt.mnt_flags &= ~MNT_WRITE_HOLD; |
99b7db7b8 fs: brlock vfsmou... |
410 |
br_write_unlock(vfsmount_lock); |
3d733633a [PATCH] r/o bind ... |
411 |
return ret; |
8366025eb [PATCH] r/o bind ... |
412 |
} |
8366025eb [PATCH] r/o bind ... |
413 |
|
83adc7532 vfs: spread struc... |
414 |
static void __mnt_unmake_readonly(struct mount *mnt) |
2e4b7fcd9 [PATCH] r/o bind ... |
415 |
{ |
99b7db7b8 fs: brlock vfsmou... |
416 |
br_write_lock(vfsmount_lock); |
83adc7532 vfs: spread struc... |
417 |
mnt->mnt.mnt_flags &= ~MNT_READONLY; |
99b7db7b8 fs: brlock vfsmou... |
418 |
br_write_unlock(vfsmount_lock); |
2e4b7fcd9 [PATCH] r/o bind ... |
419 |
} |
4ed5e82fe vfs: protect remo... |
420 421 422 423 |
int sb_prepare_remount_readonly(struct super_block *sb) { struct mount *mnt; int err = 0; |
8e8b87964 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 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 vfs: prevent remo... |
438 439 |
if (!err && atomic_long_read(&sb->s_remove_count)) err = -EBUSY; |
4ed5e82fe 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 vfs: spread struc... |
452 |
static void free_vfsmnt(struct mount *mnt) |
1da177e4c Linux-2.6.12-rc2 |
453 |
{ |
52ba1621d vfs: move mnt_dev... |
454 |
kfree(mnt->mnt_devname); |
73cd49ecd [patch 3/7] vfs: ... |
455 |
mnt_free_id(mnt); |
d3ef3d735 fs: mnt_want_writ... |
456 |
#ifdef CONFIG_SMP |
68e8a9fea vfs: all counters... |
457 |
free_percpu(mnt->mnt_pcp); |
d3ef3d735 fs: mnt_want_writ... |
458 |
#endif |
b105e270b vfs: spread struc... |
459 |
kmem_cache_free(mnt_cache, mnt); |
1da177e4c Linux-2.6.12-rc2 |
460 461 462 |
} /* |
a05964f39 [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 fs: brlock vfsmou... |
465 |
* vfsmount_lock must be held for read or write. |
1da177e4c Linux-2.6.12-rc2 |
466 |
*/ |
c71053659 vfs: spread struc... |
467 |
struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry, |
a05964f39 [PATCH] shared mo... |
468 |
int dir) |
1da177e4c Linux-2.6.12-rc2 |
469 |
{ |
b58fed8b1 [PATCH] lindent f... |
470 471 |
struct list_head *head = mount_hashtable + hash(mnt, dentry); struct list_head *tmp = head; |
c71053659 vfs: spread struc... |
472 |
struct mount *p, *found = NULL; |
1da177e4c Linux-2.6.12-rc2 |
473 |
|
1da177e4c Linux-2.6.12-rc2 |
474 |
for (;;) { |
a05964f39 [PATCH] shared mo... |
475 |
tmp = dir ? tmp->next : tmp->prev; |
1da177e4c Linux-2.6.12-rc2 |
476 477 478 |
p = NULL; if (tmp == head) break; |
1b8e5564b vfs: the first sp... |
479 |
p = list_entry(tmp, struct mount, mnt_hash); |
a73324da7 vfs: move mnt_mou... |
480 |
if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry) { |
a05964f39 [PATCH] shared mo... |
481 |
found = p; |
1da177e4c Linux-2.6.12-rc2 |
482 483 484 |
break; } } |
1da177e4c Linux-2.6.12-rc2 |
485 486 |
return found; } |
a05964f39 [PATCH] shared mo... |
487 488 489 490 |
/* * lookup_mnt increments the ref count before returning * the vfsmount struct. */ |
1c755af4d switch lookup_mnt() |
491 |
struct vfsmount *lookup_mnt(struct path *path) |
a05964f39 [PATCH] shared mo... |
492 |
{ |
c71053659 vfs: spread struc... |
493 |
struct mount *child_mnt; |
99b7db7b8 fs: brlock vfsmou... |
494 495 |
br_read_lock(vfsmount_lock); |
c71053659 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 [PATCH] shared mo... |
505 |
} |
143c8c91c vfs: mnt_ns moved... |
506 |
static inline int check_mnt(struct mount *mnt) |
1da177e4c Linux-2.6.12-rc2 |
507 |
{ |
6b3286ed1 [PATCH] rename st... |
508 |
return mnt->mnt_ns == current->nsproxy->mnt_ns; |
1da177e4c Linux-2.6.12-rc2 |
509 |
} |
99b7db7b8 fs: brlock vfsmou... |
510 511 512 |
/* * vfsmount lock must be held for write */ |
6b3286ed1 [PATCH] rename st... |
513 |
static void touch_mnt_namespace(struct mnt_namespace *ns) |
5addc5dd8 [PATCH] make /pro... |
514 515 516 517 518 519 |
{ if (ns) { ns->event = ++event; wake_up_interruptible(&ns->poll); } } |
99b7db7b8 fs: brlock vfsmou... |
520 521 522 |
/* * vfsmount lock must be held for write */ |
6b3286ed1 [PATCH] rename st... |
523 |
static void __touch_mnt_namespace(struct mnt_namespace *ns) |
5addc5dd8 [PATCH] make /pro... |
524 525 526 527 528 529 |
{ if (ns && ns->event != event) { ns->event = event; wake_up_interruptible(&ns->poll); } } |
99b7db7b8 fs: brlock vfsmou... |
530 |
/* |
5f57cbcc0 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 vfs: dentry_reset... |
534 |
static void dentry_reset_mounted(struct dentry *dentry) |
5f57cbcc0 fs: dcache remove... |
535 536 537 538 |
{ unsigned u; for (u = 0; u < HASH_SIZE; u++) { |
d5e50f74d vfs: spread struc... |
539 |
struct mount *p; |
5f57cbcc0 fs: dcache remove... |
540 |
|
1b8e5564b vfs: the first sp... |
541 |
list_for_each_entry(p, &mount_hashtable[u], mnt_hash) { |
a73324da7 vfs: move mnt_mou... |
542 |
if (p->mnt_mountpoint == dentry) |
5f57cbcc0 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 fs: brlock vfsmou... |
552 553 |
* vfsmount lock must be held for write */ |
419148da6 vfs: spread struc... |
554 555 |
static void detach_mnt(struct mount *mnt, struct path *old_path) { |
a73324da7 vfs: move mnt_mou... |
556 |
old_path->dentry = mnt->mnt_mountpoint; |
0714a5338 vfs: now it can b... |
557 558 |
old_path->mnt = &mnt->mnt_parent->mnt; mnt->mnt_parent = mnt; |
a73324da7 vfs: move mnt_mou... |
559 |
mnt->mnt_mountpoint = mnt->mnt.mnt_root; |
6b41d536f vfs: take mnt_chi... |
560 |
list_del_init(&mnt->mnt_child); |
1b8e5564b vfs: the first sp... |
561 |
list_del_init(&mnt->mnt_hash); |
aa0a4cf0a vfs: dentry_reset... |
562 |
dentry_reset_mounted(old_path->dentry); |
1da177e4c Linux-2.6.12-rc2 |
563 |
} |
99b7db7b8 fs: brlock vfsmou... |
564 565 566 |
/* * vfsmount lock must be held for write */ |
14cf1fa8f vfs: spread struc... |
567 |
void mnt_set_mountpoint(struct mount *mnt, struct dentry *dentry, |
44d964d60 vfs: spread struc... |
568 |
struct mount *child_mnt) |
b90fa9ae8 [PATCH] shared mo... |
569 |
{ |
3a2393d71 vfs: opencode mnt... |
570 |
mnt_add_count(mnt, 1); /* essentially, that's mntget */ |
a73324da7 vfs: move mnt_mou... |
571 |
child_mnt->mnt_mountpoint = dget(dentry); |
3a2393d71 vfs: opencode mnt... |
572 |
child_mnt->mnt_parent = mnt; |
5f57cbcc0 fs: dcache remove... |
573 574 575 |
spin_lock(&dentry->d_lock); dentry->d_flags |= DCACHE_MOUNTED; spin_unlock(&dentry->d_lock); |
b90fa9ae8 [PATCH] shared mo... |
576 |
} |
99b7db7b8 fs: brlock vfsmou... |
577 578 579 |
/* * vfsmount lock must be held for write */ |
419148da6 vfs: spread struc... |
580 |
static void attach_mnt(struct mount *mnt, struct path *path) |
1da177e4c Linux-2.6.12-rc2 |
581 |
{ |
14cf1fa8f vfs: spread struc... |
582 |
mnt_set_mountpoint(real_mount(path->mnt), path->dentry, mnt); |
1b8e5564b vfs: the first sp... |
583 |
list_add_tail(&mnt->mnt_hash, mount_hashtable + |
1a3906895 [PATCH] reduce st... |
584 |
hash(path->mnt, path->dentry)); |
6b41d536f vfs: take mnt_chi... |
585 |
list_add_tail(&mnt->mnt_child, &real_mount(path->mnt)->mnt_mounts); |
b90fa9ae8 [PATCH] shared mo... |
586 |
} |
83adc7532 vfs: spread struc... |
587 |
static inline void __mnt_make_longterm(struct mount *mnt) |
7e3d0eb0b VFS: Fix UP compi... |
588 589 |
{ #ifdef CONFIG_SMP |
68e8a9fea vfs: all counters... |
590 |
atomic_inc(&mnt->mnt_longterm); |
7e3d0eb0b VFS: Fix UP compi... |
591 592 593 594 |
#endif } /* needs vfsmount lock for write */ |
83adc7532 vfs: spread struc... |
595 |
static inline void __mnt_make_shortterm(struct mount *mnt) |
7e3d0eb0b VFS: Fix UP compi... |
596 597 |
{ #ifdef CONFIG_SMP |
68e8a9fea vfs: all counters... |
598 |
atomic_dec(&mnt->mnt_longterm); |
7e3d0eb0b VFS: Fix UP compi... |
599 600 |
#endif } |
b90fa9ae8 [PATCH] shared mo... |
601 |
/* |
99b7db7b8 fs: brlock vfsmou... |
602 |
* vfsmount lock must be held for write |
b90fa9ae8 [PATCH] shared mo... |
603 |
*/ |
4b2619a57 vfs: spread struc... |
604 |
static void commit_tree(struct mount *mnt) |
b90fa9ae8 [PATCH] shared mo... |
605 |
{ |
0714a5338 vfs: now it can b... |
606 |
struct mount *parent = mnt->mnt_parent; |
83adc7532 vfs: spread struc... |
607 |
struct mount *m; |
b90fa9ae8 [PATCH] shared mo... |
608 |
LIST_HEAD(head); |
143c8c91c vfs: mnt_ns moved... |
609 |
struct mnt_namespace *n = parent->mnt_ns; |
b90fa9ae8 [PATCH] shared mo... |
610 |
|
0714a5338 vfs: now it can b... |
611 |
BUG_ON(parent == mnt); |
b90fa9ae8 [PATCH] shared mo... |
612 |
|
1a4eeaf2a vfs: move mnt_lis... |
613 614 |
list_add_tail(&head, &mnt->mnt_list); list_for_each_entry(m, &head, mnt_list) { |
143c8c91c vfs: mnt_ns moved... |
615 |
m->mnt_ns = n; |
7e3d0eb0b VFS: Fix UP compi... |
616 |
__mnt_make_longterm(m); |
f03c65993 sanitize vfsmount... |
617 |
} |
b90fa9ae8 [PATCH] shared mo... |
618 |
list_splice(&head, n->list.prev); |
1b8e5564b vfs: the first sp... |
619 |
list_add_tail(&mnt->mnt_hash, mount_hashtable + |
a73324da7 vfs: move mnt_mou... |
620 |
hash(&parent->mnt, mnt->mnt_mountpoint)); |
6b41d536f vfs: take mnt_chi... |
621 |
list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); |
6b3286ed1 [PATCH] rename st... |
622 |
touch_mnt_namespace(n); |
1da177e4c Linux-2.6.12-rc2 |
623 |
} |
909b0a88e vfs: spread struc... |
624 |
static struct mount *next_mnt(struct mount *p, struct mount *root) |
1da177e4c Linux-2.6.12-rc2 |
625 |
{ |
6b41d536f vfs: take mnt_chi... |
626 627 |
struct list_head *next = p->mnt_mounts.next; if (next == &p->mnt_mounts) { |
1da177e4c Linux-2.6.12-rc2 |
628 |
while (1) { |
909b0a88e vfs: spread struc... |
629 |
if (p == root) |
1da177e4c Linux-2.6.12-rc2 |
630 |
return NULL; |
6b41d536f vfs: take mnt_chi... |
631 632 |
next = p->mnt_child.next; if (next != &p->mnt_parent->mnt_mounts) |
1da177e4c Linux-2.6.12-rc2 |
633 |
break; |
0714a5338 vfs: now it can b... |
634 |
p = p->mnt_parent; |
1da177e4c Linux-2.6.12-rc2 |
635 636 |
} } |
6b41d536f vfs: take mnt_chi... |
637 |
return list_entry(next, struct mount, mnt_child); |
1da177e4c Linux-2.6.12-rc2 |
638 |
} |
315fc83e5 vfs: spread struc... |
639 |
static struct mount *skip_mnt_tree(struct mount *p) |
9676f0c63 [PATCH] unbindabl... |
640 |
{ |
6b41d536f 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 [PATCH] unbindabl... |
645 646 647 |
} return p; } |
9d412a43c 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 vfs: spread struc... |
651 |
struct mount *mnt; |
9d412a43c 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 vfs: spread struc... |
662 |
mnt->mnt.mnt_flags = MNT_INTERNAL; |
9d412a43c 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 vfs: spread struc... |
669 670 |
mnt->mnt.mnt_root = root; mnt->mnt.mnt_sb = root->d_sb; |
a73324da7 vfs: move mnt_mou... |
671 |
mnt->mnt_mountpoint = mnt->mnt.mnt_root; |
0714a5338 vfs: now it can b... |
672 |
mnt->mnt_parent = mnt; |
39f7c4db1 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 vfs: spread struc... |
676 |
return &mnt->mnt; |
9d412a43c vfs: split off vf... |
677 678 |
} EXPORT_SYMBOL_GPL(vfs_kern_mount); |
87129cc0e vfs: spread struc... |
679 |
static struct mount *clone_mnt(struct mount *old, struct dentry *root, |
36341f645 [PATCH] mount exp... |
680 |
int flag) |
1da177e4c Linux-2.6.12-rc2 |
681 |
{ |
87129cc0e vfs: spread struc... |
682 |
struct super_block *sb = old->mnt.mnt_sb; |
52ba1621d vfs: move mnt_dev... |
683 |
struct mount *mnt = alloc_vfsmnt(old->mnt_devname); |
1da177e4c Linux-2.6.12-rc2 |
684 685 |
if (mnt) { |
719f5d7f0 [patch 4/7] vfs: ... |
686 |
if (flag & (CL_SLAVE | CL_PRIVATE)) |
15169fe78 vfs: mnt_id/mnt_g... |
687 |
mnt->mnt_group_id = 0; /* not a peer of original */ |
719f5d7f0 [patch 4/7] vfs: ... |
688 |
else |
15169fe78 vfs: mnt_id/mnt_g... |
689 |
mnt->mnt_group_id = old->mnt_group_id; |
719f5d7f0 [patch 4/7] vfs: ... |
690 |
|
15169fe78 vfs: mnt_id/mnt_g... |
691 |
if ((flag & CL_MAKE_SHARED) && !mnt->mnt_group_id) { |
b105e270b vfs: spread struc... |
692 |
int err = mnt_alloc_group_id(mnt); |
719f5d7f0 [patch 4/7] vfs: ... |
693 694 695 |
if (err) goto out_free; } |
87129cc0e vfs: spread struc... |
696 |
mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~MNT_WRITE_HOLD; |
1da177e4c Linux-2.6.12-rc2 |
697 |
atomic_inc(&sb->s_active); |
b105e270b vfs: spread struc... |
698 699 |
mnt->mnt.mnt_sb = sb; mnt->mnt.mnt_root = dget(root); |
a73324da7 vfs: move mnt_mou... |
700 |
mnt->mnt_mountpoint = mnt->mnt.mnt_root; |
0714a5338 vfs: now it can b... |
701 |
mnt->mnt_parent = mnt; |
39f7c4db1 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 [PATCH] shared mo... |
705 |
|
5afe00221 [PATCH] handling ... |
706 |
if (flag & CL_SLAVE) { |
6776db3d3 vfs: take mnt_sha... |
707 |
list_add(&mnt->mnt_slave, &old->mnt_slave_list); |
32301920f vfs: and now we c... |
708 |
mnt->mnt_master = old; |
fc7be130c vfs: switch pnode... |
709 |
CLEAR_MNT_SHARED(mnt); |
8aec08094 [PATCH] new helpe... |
710 |
} else if (!(flag & CL_PRIVATE)) { |
fc7be130c vfs: switch pnode... |
711 |
if ((flag & CL_MAKE_SHARED) || IS_MNT_SHARED(old)) |
6776db3d3 vfs: take mnt_sha... |
712 |
list_add(&mnt->mnt_share, &old->mnt_share); |
d10e8def0 vfs: take mnt_mas... |
713 |
if (IS_MNT_SLAVE(old)) |
6776db3d3 vfs: take mnt_sha... |
714 |
list_add(&mnt->mnt_slave, &old->mnt_slave); |
d10e8def0 vfs: take mnt_mas... |
715 |
mnt->mnt_master = old->mnt_master; |
5afe00221 [PATCH] handling ... |
716 |
} |
b90fa9ae8 [PATCH] shared mo... |
717 |
if (flag & CL_MAKE_SHARED) |
0f0afb1dc vfs: spread struc... |
718 |
set_mnt_shared(mnt); |
1da177e4c 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 [PATCH] mount exp... |
722 |
if (flag & CL_EXPIRE) { |
6776db3d3 vfs: take mnt_sha... |
723 724 |
if (!list_empty(&old->mnt_expire)) list_add(&mnt->mnt_expire, &old->mnt_expire); |
36341f645 [PATCH] mount exp... |
725 |
} |
1da177e4c Linux-2.6.12-rc2 |
726 |
} |
cb338d06e vfs: spread struc... |
727 |
return mnt; |
719f5d7f0 [patch 4/7] vfs: ... |
728 729 730 731 |
out_free: free_vfsmnt(mnt); return NULL; |
1da177e4c Linux-2.6.12-rc2 |
732 |
} |
83adc7532 vfs: spread struc... |
733 |
static inline void mntfree(struct mount *mnt) |
1da177e4c Linux-2.6.12-rc2 |
734 |
{ |
83adc7532 vfs: spread struc... |
735 736 |
struct vfsmount *m = &mnt->mnt; struct super_block *sb = m->mnt_sb; |
b3e19d924 fs: scale mntget/... |
737 |
|
3d733633a [PATCH] r/o bind ... |
738 |
/* |
3d733633a [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 fs: mnt_want_writ... |
744 |
/* |
b3e19d924 fs: scale mntget/... |
745 746 |
* The locking used to deal with mnt_count decrement provides barriers, * so mnt_get_writers() below is safe. |
d3ef3d735 fs: mnt_want_writ... |
747 |
*/ |
c6653a838 fs: rename vfsmou... |
748 |
WARN_ON(mnt_get_writers(mnt)); |
83adc7532 vfs: spread struc... |
749 750 751 |
fsnotify_vfsmount_delete(m); dput(m->mnt_root); free_vfsmnt(mnt); |
1da177e4c Linux-2.6.12-rc2 |
752 753 |
deactivate_super(sb); } |
900148dca vfs: spread struc... |
754 |
static void mntput_no_expire(struct mount *mnt) |
b3e19d924 fs: scale mntget/... |
755 |
{ |
b3e19d924 fs: scale mntget/... |
756 |
put_again: |
f03c65993 sanitize vfsmount... |
757 758 |
#ifdef CONFIG_SMP br_read_lock(vfsmount_lock); |
68e8a9fea vfs: all counters... |
759 |
if (likely(atomic_read(&mnt->mnt_longterm))) { |
aa9c0e07b vfs: kill pointle... |
760 |
mnt_add_count(mnt, -1); |
b3e19d924 fs: scale mntget/... |
761 |
br_read_unlock(vfsmount_lock); |
f03c65993 sanitize vfsmount... |
762 |
return; |
b3e19d924 fs: scale mntget/... |
763 |
} |
f03c65993 sanitize vfsmount... |
764 |
br_read_unlock(vfsmount_lock); |
b3e19d924 fs: scale mntget/... |
765 |
|
99b7db7b8 fs: brlock vfsmou... |
766 |
br_write_lock(vfsmount_lock); |
aa9c0e07b vfs: kill pointle... |
767 |
mnt_add_count(mnt, -1); |
b3e19d924 fs: scale mntget/... |
768 |
if (mnt_get_count(mnt)) { |
99b7db7b8 fs: brlock vfsmou... |
769 770 771 |
br_write_unlock(vfsmount_lock); return; } |
b3e19d924 fs: scale mntget/... |
772 |
#else |
aa9c0e07b vfs: kill pointle... |
773 |
mnt_add_count(mnt, -1); |
b3e19d924 fs: scale mntget/... |
774 |
if (likely(mnt_get_count(mnt))) |
99b7db7b8 fs: brlock vfsmou... |
775 |
return; |
b3e19d924 fs: scale mntget/... |
776 |
br_write_lock(vfsmount_lock); |
f03c65993 sanitize vfsmount... |
777 |
#endif |
863d684f9 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 fs: scale mntget/... |
781 |
br_write_unlock(vfsmount_lock); |
900148dca vfs: spread struc... |
782 |
acct_auto_close_mnt(&mnt->mnt); |
b3e19d924 fs: scale mntget/... |
783 |
goto put_again; |
7b7b1ace2 [PATCH] saner han... |
784 |
} |
39f7c4db1 vfs: keep list of... |
785 |
list_del(&mnt->mnt_instance); |
99b7db7b8 fs: brlock vfsmou... |
786 |
br_write_unlock(vfsmount_lock); |
b3e19d924 fs: scale mntget/... |
787 788 |
mntfree(mnt); } |
b3e19d924 fs: scale mntget/... |
789 790 791 792 |
void mntput(struct vfsmount *mnt) { if (mnt) { |
863d684f9 vfs: move the res... |
793 |
struct mount *m = real_mount(mnt); |
b3e19d924 fs: scale mntget/... |
794 |
/* avoid cacheline pingpong, hope gcc doesn't get "smart" */ |
863d684f9 vfs: move the res... |
795 796 797 |
if (unlikely(m->mnt_expiry_mark)) m->mnt_expiry_mark = 0; mntput_no_expire(m); |
b3e19d924 fs: scale mntget/... |
798 799 800 801 802 803 804 |
} } EXPORT_SYMBOL(mntput); struct vfsmount *mntget(struct vfsmount *mnt) { if (mnt) |
83adc7532 vfs: spread struc... |
805 |
mnt_add_count(real_mount(mnt), 1); |
b3e19d924 fs: scale mntget/... |
806 807 808 |
return mnt; } EXPORT_SYMBOL(mntget); |
7b7b1ace2 [PATCH] saner han... |
809 810 |
void mnt_pin(struct vfsmount *mnt) { |
99b7db7b8 fs: brlock vfsmou... |
811 |
br_write_lock(vfsmount_lock); |
863d684f9 vfs: move the res... |
812 |
real_mount(mnt)->mnt_pinned++; |
99b7db7b8 fs: brlock vfsmou... |
813 |
br_write_unlock(vfsmount_lock); |
7b7b1ace2 [PATCH] saner han... |
814 |
} |
7b7b1ace2 [PATCH] saner han... |
815 |
EXPORT_SYMBOL(mnt_pin); |
863d684f9 vfs: move the res... |
816 |
void mnt_unpin(struct vfsmount *m) |
7b7b1ace2 [PATCH] saner han... |
817 |
{ |
863d684f9 vfs: move the res... |
818 |
struct mount *mnt = real_mount(m); |
99b7db7b8 fs: brlock vfsmou... |
819 |
br_write_lock(vfsmount_lock); |
7b7b1ace2 [PATCH] saner han... |
820 |
if (mnt->mnt_pinned) { |
863d684f9 vfs: move the res... |
821 |
mnt_add_count(mnt, 1); |
7b7b1ace2 [PATCH] saner han... |
822 823 |
mnt->mnt_pinned--; } |
99b7db7b8 fs: brlock vfsmou... |
824 |
br_write_unlock(vfsmount_lock); |
7b7b1ace2 [PATCH] saner han... |
825 |
} |
7b7b1ace2 [PATCH] saner han... |
826 |
EXPORT_SYMBOL(mnt_unpin); |
1da177e4c Linux-2.6.12-rc2 |
827 |
|
b3b304a23 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 vfs: switch ->sho... |
840 |
int generic_show_options(struct seq_file *m, struct dentry *root) |
b3b304a23 mount options: ad... |
841 |
{ |
2a32cebd6 Fix races around ... |
842 843 844 |
const char *options; rcu_read_lock(); |
34c80b1d9 vfs: switch ->sho... |
845 |
options = rcu_dereference(root->d_sb->s_options); |
b3b304a23 mount options: ad... |
846 847 848 849 850 |
if (options != NULL && options[0]) { seq_putc(m, ','); mangle(m, options); } |
2a32cebd6 Fix races around ... |
851 |
rcu_read_unlock(); |
b3b304a23 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 Fix races around ... |
872 873 |
BUG_ON(sb->s_options); rcu_assign_pointer(sb->s_options, kstrdup(options, GFP_KERNEL)); |
b3b304a23 mount options: ad... |
874 875 |
} EXPORT_SYMBOL(save_mount_options); |
2a32cebd6 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 [patch 5/7] vfs: ... |
886 |
#ifdef CONFIG_PROC_FS |
0226f4923 vfs: take /proc/*... |
887 |
/* iterator; we want it to have access to namespace_sem, thus here... */ |
1da177e4c Linux-2.6.12-rc2 |
888 889 |
static void *m_start(struct seq_file *m, loff_t *pos) { |
0226f4923 vfs: take /proc/*... |
890 |
struct proc_mounts *p = container_of(m, struct proc_mounts, m); |
1da177e4c Linux-2.6.12-rc2 |
891 |
|
390c68436 [PATCH] making na... |
892 |
down_read(&namespace_sem); |
a1a2c409b [patch 5/7] vfs: ... |
893 |
return seq_list_start(&p->ns->list, *pos); |
1da177e4c Linux-2.6.12-rc2 |
894 895 896 897 |
} static void *m_next(struct seq_file *m, void *v, loff_t *pos) { |
0226f4923 vfs: take /proc/*... |
898 |
struct proc_mounts *p = container_of(m, struct proc_mounts, m); |
b0765fb85 Make /proc/self/m... |
899 |
|
a1a2c409b [patch 5/7] vfs: ... |
900 |
return seq_list_next(v, &p->ns->list, pos); |
1da177e4c Linux-2.6.12-rc2 |
901 902 903 904 |
} static void m_stop(struct seq_file *m, void *v) { |
390c68436 [PATCH] making na... |
905 |
up_read(&namespace_sem); |
1da177e4c Linux-2.6.12-rc2 |
906 |
} |
0226f4923 vfs: take /proc/*... |
907 |
static int m_show(struct seq_file *m, void *v) |
2d4d4864a [patch 6/7] vfs: ... |
908 |
{ |
0226f4923 vfs: take /proc/*... |
909 |
struct proc_mounts *p = container_of(m, struct proc_mounts, m); |
1a4eeaf2a vfs: move mnt_lis... |
910 |
struct mount *r = list_entry(v, struct mount, mnt_list); |
0226f4923 vfs: take /proc/*... |
911 |
return p->show(m, &r->mnt); |
1da177e4c Linux-2.6.12-rc2 |
912 |
} |
a1a2c409b [patch 5/7] vfs: ... |
913 |
const struct seq_operations mounts_op = { |
1da177e4c Linux-2.6.12-rc2 |
914 915 916 |
.start = m_start, .next = m_next, .stop = m_stop, |
0226f4923 vfs: take /proc/*... |
917 |
.show = m_show, |
b4629fe2f VFS: New /proc fi... |
918 |
}; |
a1a2c409b [patch 5/7] vfs: ... |
919 |
#endif /* CONFIG_PROC_FS */ |
b4629fe2f VFS: New /proc fi... |
920 |
|
1da177e4c 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 vfs: spread struc... |
929 |
int may_umount_tree(struct vfsmount *m) |
1da177e4c Linux-2.6.12-rc2 |
930 |
{ |
909b0a88e vfs: spread struc... |
931 |
struct mount *mnt = real_mount(m); |
36341f645 [PATCH] mount exp... |
932 933 |
int actual_refs = 0; int minimum_refs = 0; |
315fc83e5 vfs: spread struc... |
934 |
struct mount *p; |
909b0a88e vfs: spread struc... |
935 |
BUG_ON(!m); |
1da177e4c Linux-2.6.12-rc2 |
936 |
|
b3e19d924 fs: scale mntget/... |
937 938 |
/* write lock needed for mnt_get_count */ br_write_lock(vfsmount_lock); |
909b0a88e vfs: spread struc... |
939 |
for (p = mnt; p; p = next_mnt(p, mnt)) { |
83adc7532 vfs: spread struc... |
940 |
actual_refs += mnt_get_count(p); |
1da177e4c Linux-2.6.12-rc2 |
941 |
minimum_refs += 2; |
1da177e4c Linux-2.6.12-rc2 |
942 |
} |
b3e19d924 fs: scale mntget/... |
943 |
br_write_unlock(vfsmount_lock); |
1da177e4c Linux-2.6.12-rc2 |
944 945 |
if (actual_refs > minimum_refs) |
e3474a8eb [PATCH] autofs4: ... |
946 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
947 |
|
e3474a8eb [PATCH] autofs4: ... |
948 |
return 1; |
1da177e4c 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 [PATCH] autofs4: ... |
968 |
int ret = 1; |
8ad08d8a0 may_umount() need... |
969 |
down_read(&namespace_sem); |
b3e19d924 fs: scale mntget/... |
970 |
br_write_lock(vfsmount_lock); |
1ab597386 vfs: spread struc... |
971 |
if (propagate_mount_busy(real_mount(mnt), 2)) |
e3474a8eb [PATCH] autofs4: ... |
972 |
ret = 0; |
b3e19d924 fs: scale mntget/... |
973 |
br_write_unlock(vfsmount_lock); |
8ad08d8a0 may_umount() need... |
974 |
up_read(&namespace_sem); |
a05964f39 [PATCH] shared mo... |
975 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
976 977 978 |
} EXPORT_SYMBOL(may_umount); |
b90fa9ae8 [PATCH] shared mo... |
979 |
void release_mounts(struct list_head *head) |
70fbcdf4d [PATCH] umount_tr... |
980 |
{ |
d5e50f74d vfs: spread struc... |
981 |
struct mount *mnt; |
bf066c7db [PATCH] shared mo... |
982 |
while (!list_empty(head)) { |
1b8e5564b vfs: the first sp... |
983 984 |
mnt = list_first_entry(head, struct mount, mnt_hash); list_del_init(&mnt->mnt_hash); |
676da58df vfs: spread struc... |
985 |
if (mnt_has_parent(mnt)) { |
70fbcdf4d [PATCH] umount_tr... |
986 |
struct dentry *dentry; |
863d684f9 vfs: move the res... |
987 |
struct mount *m; |
99b7db7b8 fs: brlock vfsmou... |
988 989 |
br_write_lock(vfsmount_lock); |
a73324da7 vfs: move mnt_mou... |
990 |
dentry = mnt->mnt_mountpoint; |
863d684f9 vfs: move the res... |
991 |
m = mnt->mnt_parent; |
a73324da7 vfs: move mnt_mou... |
992 |
mnt->mnt_mountpoint = mnt->mnt.mnt_root; |
0714a5338 vfs: now it can b... |
993 |
mnt->mnt_parent = mnt; |
7c4b93d82 [PATCH] count gho... |
994 |
m->mnt_ghosts--; |
99b7db7b8 fs: brlock vfsmou... |
995 |
br_write_unlock(vfsmount_lock); |
70fbcdf4d [PATCH] umount_tr... |
996 |
dput(dentry); |
863d684f9 vfs: move the res... |
997 |
mntput(&m->mnt); |
70fbcdf4d [PATCH] umount_tr... |
998 |
} |
d5e50f74d vfs: spread struc... |
999 |
mntput(&mnt->mnt); |
70fbcdf4d [PATCH] umount_tr... |
1000 1001 |
} } |
99b7db7b8 fs: brlock vfsmou... |
1002 1003 1004 1005 |
/* * vfsmount lock must be held for write * namespace_sem must be held for write */ |
761d5c38e vfs: spread struc... |
1006 |
void umount_tree(struct mount *mnt, int propagate, struct list_head *kill) |
1da177e4c Linux-2.6.12-rc2 |
1007 |
{ |
7b8a53fd8 fix old umount_tr... |
1008 |
LIST_HEAD(tmp_list); |
315fc83e5 vfs: spread struc... |
1009 |
struct mount *p; |
1da177e4c Linux-2.6.12-rc2 |
1010 |
|
909b0a88e vfs: spread struc... |
1011 |
for (p = mnt; p; p = next_mnt(p, mnt)) |
1b8e5564b vfs: the first sp... |
1012 |
list_move(&p->mnt_hash, &tmp_list); |
1da177e4c Linux-2.6.12-rc2 |
1013 |
|
a05964f39 [PATCH] shared mo... |
1014 |
if (propagate) |
7b8a53fd8 fix old umount_tr... |
1015 |
propagate_umount(&tmp_list); |
a05964f39 [PATCH] shared mo... |
1016 |
|
1b8e5564b vfs: the first sp... |
1017 |
list_for_each_entry(p, &tmp_list, mnt_hash) { |
6776db3d3 vfs: take mnt_sha... |
1018 |
list_del_init(&p->mnt_expire); |
1a4eeaf2a vfs: move mnt_lis... |
1019 |
list_del_init(&p->mnt_list); |
143c8c91c vfs: mnt_ns moved... |
1020 1021 |
__touch_mnt_namespace(p->mnt_ns); p->mnt_ns = NULL; |
83adc7532 vfs: spread struc... |
1022 |
__mnt_make_shortterm(p); |
6b41d536f vfs: take mnt_chi... |
1023 |
list_del_init(&p->mnt_child); |
676da58df vfs: spread struc... |
1024 |
if (mnt_has_parent(p)) { |
863d684f9 vfs: move the res... |
1025 |
p->mnt_parent->mnt_ghosts++; |
a73324da7 vfs: move mnt_mou... |
1026 |
dentry_reset_mounted(p->mnt_mountpoint); |
7c4b93d82 [PATCH] count gho... |
1027 |
} |
0f0afb1dc vfs: spread struc... |
1028 |
change_mnt_propagation(p, MS_PRIVATE); |
1da177e4c Linux-2.6.12-rc2 |
1029 |
} |
7b8a53fd8 fix old umount_tr... |
1030 |
list_splice(&tmp_list, kill); |
1da177e4c Linux-2.6.12-rc2 |
1031 |
} |
692afc312 vfs: spread struc... |
1032 |
static void shrink_submounts(struct mount *mnt, struct list_head *umounts); |
c35038bec [PATCH] do shrink... |
1033 |
|
1ab597386 vfs: spread struc... |
1034 |
static int do_umount(struct mount *mnt, int flags) |
1da177e4c Linux-2.6.12-rc2 |
1035 |
{ |
1ab597386 vfs: spread struc... |
1036 |
struct super_block *sb = mnt->mnt.mnt_sb; |
1da177e4c Linux-2.6.12-rc2 |
1037 |
int retval; |
70fbcdf4d [PATCH] umount_tr... |
1038 |
LIST_HEAD(umount_list); |
1da177e4c Linux-2.6.12-rc2 |
1039 |
|
1ab597386 vfs: spread struc... |
1040 |
retval = security_sb_umount(&mnt->mnt, flags); |
1da177e4c 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 vfs: spread struc... |
1051 |
if (&mnt->mnt == current->fs->root.mnt || |
1da177e4c Linux-2.6.12-rc2 |
1052 1053 |
flags & (MNT_FORCE | MNT_DETACH)) return -EINVAL; |
b3e19d924 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 vfs: spread struc... |
1059 |
if (mnt_get_count(mnt) != 2) { |
bf9faa2aa Unlock vfsmount_l... |
1060 |
br_write_unlock(vfsmount_lock); |
1da177e4c Linux-2.6.12-rc2 |
1061 |
return -EBUSY; |
b3e19d924 fs: scale mntget/... |
1062 1063 |
} br_write_unlock(vfsmount_lock); |
1da177e4c Linux-2.6.12-rc2 |
1064 |
|
863d684f9 vfs: move the res... |
1065 |
if (!xchg(&mnt->mnt_expiry_mark, 1)) |
1da177e4c 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 [PATCH] restore s... |
1078 |
if (flags & MNT_FORCE && sb->s_op->umount_begin) { |
42faad996 [PATCH] restore s... |
1079 |
sb->s_op->umount_begin(sb); |
42faad996 [PATCH] restore s... |
1080 |
} |
1da177e4c 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 vfs: spread struc... |
1091 |
if (&mnt->mnt == current->fs->root.mnt && !(flags & MNT_DETACH)) { |
1da177e4c 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 Push BKL down int... |
1097 |
if (!(sb->s_flags & MS_RDONLY)) |
1da177e4c Linux-2.6.12-rc2 |
1098 |
retval = do_remount_sb(sb, MS_RDONLY, NULL, 0); |
1da177e4c Linux-2.6.12-rc2 |
1099 1100 1101 |
up_write(&sb->s_umount); return retval; } |
390c68436 [PATCH] making na... |
1102 |
down_write(&namespace_sem); |
99b7db7b8 fs: brlock vfsmou... |
1103 |
br_write_lock(vfsmount_lock); |
5addc5dd8 [PATCH] make /pro... |
1104 |
event++; |
1da177e4c Linux-2.6.12-rc2 |
1105 |
|
c35038bec [PATCH] do shrink... |
1106 |
if (!(flags & MNT_DETACH)) |
1ab597386 vfs: spread struc... |
1107 |
shrink_submounts(mnt, &umount_list); |
c35038bec [PATCH] do shrink... |
1108 |
|
1da177e4c Linux-2.6.12-rc2 |
1109 |
retval = -EBUSY; |
a05964f39 [PATCH] shared mo... |
1110 |
if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) { |
1a4eeaf2a vfs: move mnt_lis... |
1111 |
if (!list_empty(&mnt->mnt_list)) |
1ab597386 vfs: spread struc... |
1112 |
umount_tree(mnt, 1, &umount_list); |
1da177e4c Linux-2.6.12-rc2 |
1113 1114 |
retval = 0; } |
99b7db7b8 fs: brlock vfsmou... |
1115 |
br_write_unlock(vfsmount_lock); |
390c68436 [PATCH] making na... |
1116 |
up_write(&namespace_sem); |
70fbcdf4d [PATCH] umount_tr... |
1117 |
release_mounts(&umount_list); |
1da177e4c 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 [CVE-2009-0029] S... |
1128 |
SYSCALL_DEFINE2(umount, char __user *, name, int, flags) |
1da177e4c Linux-2.6.12-rc2 |
1129 |
{ |
2d8f30380 [PATCH] sanitize ... |
1130 |
struct path path; |
900148dca vfs: spread struc... |
1131 |
struct mount *mnt; |
1da177e4c Linux-2.6.12-rc2 |
1132 |
int retval; |
db1f05bb8 vfs: add NOFOLLOW... |
1133 |
int lookup_flags = 0; |
1da177e4c Linux-2.6.12-rc2 |
1134 |
|
db1f05bb8 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 Linux-2.6.12-rc2 |
1142 1143 |
if (retval) goto out; |
900148dca vfs: spread struc... |
1144 |
mnt = real_mount(path.mnt); |
1da177e4c Linux-2.6.12-rc2 |
1145 |
retval = -EINVAL; |
2d8f30380 [PATCH] sanitize ... |
1146 |
if (path.dentry != path.mnt->mnt_root) |
1da177e4c Linux-2.6.12-rc2 |
1147 |
goto dput_and_out; |
143c8c91c vfs: mnt_ns moved... |
1148 |
if (!check_mnt(mnt)) |
1da177e4c 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 vfs: spread struc... |
1154 |
retval = do_umount(mnt, flags); |
1da177e4c Linux-2.6.12-rc2 |
1155 |
dput_and_out: |
429731b15 Remove path_relea... |
1156 |
/* we mustn't call path_put() as that would clear mnt_expiry_mark */ |
2d8f30380 [PATCH] sanitize ... |
1157 |
dput(path.dentry); |
900148dca vfs: spread struc... |
1158 |
mntput_no_expire(mnt); |
1da177e4c Linux-2.6.12-rc2 |
1159 1160 1161 1162 1163 1164 1165 |
out: return retval; } #ifdef __ARCH_WANT_SYS_OLDUMOUNT /* |
b58fed8b1 [PATCH] lindent f... |
1166 |
* The 2.0 compatible umount. No flags. |
1da177e4c Linux-2.6.12-rc2 |
1167 |
*/ |
bdc480e3b [CVE-2009-0029] S... |
1168 |
SYSCALL_DEFINE1(oldumount, char __user *, name) |
1da177e4c Linux-2.6.12-rc2 |
1169 |
{ |
b58fed8b1 [PATCH] lindent f... |
1170 |
return sys_umount(name, 0); |
1da177e4c Linux-2.6.12-rc2 |
1171 1172 1173 |
} #endif |
2d92ab3c6 [PATCH] finally g... |
1174 |
static int mount_is_safe(struct path *path) |
1da177e4c Linux-2.6.12-rc2 |
1175 1176 1177 1178 1179 |
{ if (capable(CAP_SYS_ADMIN)) return 0; return -EPERM; #ifdef notyet |
2d92ab3c6 [PATCH] finally g... |
1180 |
if (S_ISLNK(path->dentry->d_inode->i_mode)) |
1da177e4c Linux-2.6.12-rc2 |
1181 |
return -EPERM; |
2d92ab3c6 [PATCH] finally g... |
1182 |
if (path->dentry->d_inode->i_mode & S_ISVTX) { |
da9592ede CRED: Wrap task c... |
1183 |
if (current_uid() != path->dentry->d_inode->i_uid) |
1da177e4c Linux-2.6.12-rc2 |
1184 1185 |
return -EPERM; } |
2d92ab3c6 [PATCH] finally g... |
1186 |
if (inode_permission(path->dentry->d_inode, MAY_WRITE)) |
1da177e4c Linux-2.6.12-rc2 |
1187 1188 1189 1190 |
return -EPERM; return 0; #endif } |
87129cc0e vfs: spread struc... |
1191 |
struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, |
36341f645 [PATCH] mount exp... |
1192 |
int flag) |
1da177e4c Linux-2.6.12-rc2 |
1193 |
{ |
a73324da7 vfs: move mnt_mou... |
1194 |
struct mount *res, *p, *q, *r; |
1a3906895 [PATCH] reduce st... |
1195 |
struct path path; |
1da177e4c Linux-2.6.12-rc2 |
1196 |
|
fc7be130c vfs: switch pnode... |
1197 |
if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(mnt)) |
9676f0c63 [PATCH] unbindabl... |
1198 |
return NULL; |
36341f645 [PATCH] mount exp... |
1199 |
res = q = clone_mnt(mnt, dentry, flag); |
1da177e4c Linux-2.6.12-rc2 |
1200 1201 |
if (!q) goto Enomem; |
a73324da7 vfs: move mnt_mou... |
1202 |
q->mnt_mountpoint = mnt->mnt_mountpoint; |
1da177e4c Linux-2.6.12-rc2 |
1203 1204 |
p = mnt; |
6b41d536f vfs: take mnt_chi... |
1205 |
list_for_each_entry(r, &mnt->mnt_mounts, mnt_child) { |
315fc83e5 vfs: spread struc... |
1206 |
struct mount *s; |
7ec02ef15 vfs: remove lives... |
1207 |
if (!is_subdir(r->mnt_mountpoint, dentry)) |
1da177e4c Linux-2.6.12-rc2 |
1208 |
continue; |
909b0a88e vfs: spread struc... |
1209 |
for (s = r; s; s = next_mnt(s, r)) { |
fc7be130c vfs: switch pnode... |
1210 |
if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(s)) { |
9676f0c63 [PATCH] unbindabl... |
1211 1212 1213 |
s = skip_mnt_tree(s); continue; } |
0714a5338 vfs: now it can b... |
1214 1215 1216 |
while (p != s->mnt_parent) { p = p->mnt_parent; q = q->mnt_parent; |
1da177e4c Linux-2.6.12-rc2 |
1217 |
} |
87129cc0e vfs: spread struc... |
1218 |
p = s; |
cb338d06e vfs: spread struc... |
1219 |
path.mnt = &q->mnt; |
a73324da7 vfs: move mnt_mou... |
1220 |
path.dentry = p->mnt_mountpoint; |
87129cc0e vfs: spread struc... |
1221 |
q = clone_mnt(p, p->mnt.mnt_root, flag); |
1da177e4c Linux-2.6.12-rc2 |
1222 1223 |
if (!q) goto Enomem; |
99b7db7b8 fs: brlock vfsmou... |
1224 |
br_write_lock(vfsmount_lock); |
1a4eeaf2a vfs: move mnt_lis... |
1225 |
list_add_tail(&q->mnt_list, &res->mnt_list); |
cb338d06e vfs: spread struc... |
1226 |
attach_mnt(q, &path); |
99b7db7b8 fs: brlock vfsmou... |
1227 |
br_write_unlock(vfsmount_lock); |
1da177e4c Linux-2.6.12-rc2 |
1228 1229 1230 |
} } return res; |
b58fed8b1 [PATCH] lindent f... |
1231 |
Enomem: |
1da177e4c Linux-2.6.12-rc2 |
1232 |
if (res) { |
70fbcdf4d [PATCH] umount_tr... |
1233 |
LIST_HEAD(umount_list); |
99b7db7b8 fs: brlock vfsmou... |
1234 |
br_write_lock(vfsmount_lock); |
761d5c38e vfs: spread struc... |
1235 |
umount_tree(res, 0, &umount_list); |
99b7db7b8 fs: brlock vfsmou... |
1236 |
br_write_unlock(vfsmount_lock); |
70fbcdf4d [PATCH] umount_tr... |
1237 |
release_mounts(&umount_list); |
1da177e4c Linux-2.6.12-rc2 |
1238 1239 1240 |
} return NULL; } |
589ff870e Switch collect_mo... |
1241 |
struct vfsmount *collect_mounts(struct path *path) |
8aec08094 [PATCH] new helpe... |
1242 |
{ |
cb338d06e vfs: spread struc... |
1243 |
struct mount *tree; |
1a60a2807 [PATCH] lock excl... |
1244 |
down_write(&namespace_sem); |
87129cc0e vfs: spread struc... |
1245 1246 |
tree = copy_tree(real_mount(path->mnt), path->dentry, CL_COPY_ALL | CL_PRIVATE); |
1a60a2807 [PATCH] lock excl... |
1247 |
up_write(&namespace_sem); |
cb338d06e vfs: spread struc... |
1248 |
return tree ? &tree->mnt : NULL; |
8aec08094 [PATCH] new helpe... |
1249 1250 1251 1252 1253 |
} void drop_collected_mounts(struct vfsmount *mnt) { LIST_HEAD(umount_list); |
1a60a2807 [PATCH] lock excl... |
1254 |
down_write(&namespace_sem); |
99b7db7b8 fs: brlock vfsmou... |
1255 |
br_write_lock(vfsmount_lock); |
761d5c38e vfs: spread struc... |
1256 |
umount_tree(real_mount(mnt), 0, &umount_list); |
99b7db7b8 fs: brlock vfsmou... |
1257 |
br_write_unlock(vfsmount_lock); |
1a60a2807 [PATCH] lock excl... |
1258 |
up_write(&namespace_sem); |
8aec08094 [PATCH] new helpe... |
1259 1260 |
release_mounts(&umount_list); } |
1f707137b new helper: itera... |
1261 1262 1263 |
int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg, struct vfsmount *root) { |
1a4eeaf2a vfs: move mnt_lis... |
1264 |
struct mount *mnt; |
1f707137b new helper: itera... |
1265 1266 1267 |
int res = f(root, arg); if (res) return res; |
1a4eeaf2a vfs: move mnt_lis... |
1268 1269 |
list_for_each_entry(mnt, &real_mount(root)->mnt_list, mnt_list) { res = f(&mnt->mnt, arg); |
1f707137b new helper: itera... |
1270 1271 1272 1273 1274 |
if (res) return res; } return 0; } |
4b8b21f4f vfs: spread struc... |
1275 |
static void cleanup_group_ids(struct mount *mnt, struct mount *end) |
719f5d7f0 [patch 4/7] vfs: ... |
1276 |
{ |
315fc83e5 vfs: spread struc... |
1277 |
struct mount *p; |
719f5d7f0 [patch 4/7] vfs: ... |
1278 |
|
909b0a88e vfs: spread struc... |
1279 |
for (p = mnt; p != end; p = next_mnt(p, mnt)) { |
fc7be130c vfs: switch pnode... |
1280 |
if (p->mnt_group_id && !IS_MNT_SHARED(p)) |
4b8b21f4f vfs: spread struc... |
1281 |
mnt_release_group_id(p); |
719f5d7f0 [patch 4/7] vfs: ... |
1282 1283 |
} } |
4b8b21f4f vfs: spread struc... |
1284 |
static int invent_group_ids(struct mount *mnt, bool recurse) |
719f5d7f0 [patch 4/7] vfs: ... |
1285 |
{ |
315fc83e5 vfs: spread struc... |
1286 |
struct mount *p; |
719f5d7f0 [patch 4/7] vfs: ... |
1287 |
|
909b0a88e vfs: spread struc... |
1288 |
for (p = mnt; p; p = recurse ? next_mnt(p, mnt) : NULL) { |
fc7be130c vfs: switch pnode... |
1289 |
if (!p->mnt_group_id && !IS_MNT_SHARED(p)) { |
4b8b21f4f vfs: spread struc... |
1290 |
int err = mnt_alloc_group_id(p); |
719f5d7f0 [patch 4/7] vfs: ... |
1291 |
if (err) { |
4b8b21f4f vfs: spread struc... |
1292 |
cleanup_group_ids(mnt, p); |
719f5d7f0 [patch 4/7] vfs: ... |
1293 1294 1295 1296 1297 1298 1299 |
return err; } } } return 0; } |
b90fa9ae8 [PATCH] shared mo... |
1300 1301 |
/* * @source_mnt : mount tree to be attached |
214444032 [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 [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 [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 [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 [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 [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 [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 [PATCH] shared mo... |
1352 |
* (+*) the mount is moved to the destination. |
5afe00221 [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 [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 vfs: spread struc... |
1363 |
static int attach_recursive_mnt(struct mount *source_mnt, |
1a3906895 [PATCH] reduce st... |
1364 |
struct path *path, struct path *parent_path) |
b90fa9ae8 [PATCH] shared mo... |
1365 1366 |
{ LIST_HEAD(tree_list); |
a8d56d8e4 vfs: spread struc... |
1367 |
struct mount *dest_mnt = real_mount(path->mnt); |
1a3906895 [PATCH] reduce st... |
1368 |
struct dentry *dest_dentry = path->dentry; |
315fc83e5 vfs: spread struc... |
1369 |
struct mount *child, *p; |
719f5d7f0 [patch 4/7] vfs: ... |
1370 |
int err; |
b90fa9ae8 [PATCH] shared mo... |
1371 |
|
fc7be130c vfs: switch pnode... |
1372 |
if (IS_MNT_SHARED(dest_mnt)) { |
0fb54e505 vfs: spread struc... |
1373 |
err = invent_group_ids(source_mnt, true); |
719f5d7f0 [patch 4/7] vfs: ... |
1374 1375 1376 |
if (err) goto out; } |
a8d56d8e4 vfs: spread struc... |
1377 |
err = propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list); |
719f5d7f0 [patch 4/7] vfs: ... |
1378 1379 |
if (err) goto out_cleanup_ids; |
b90fa9ae8 [PATCH] shared mo... |
1380 |
|
99b7db7b8 fs: brlock vfsmou... |
1381 |
br_write_lock(vfsmount_lock); |
df1a1ad29 attach_recursive_... |
1382 |
|
fc7be130c vfs: switch pnode... |
1383 |
if (IS_MNT_SHARED(dest_mnt)) { |
909b0a88e vfs: spread struc... |
1384 |
for (p = source_mnt; p; p = next_mnt(p, source_mnt)) |
0f0afb1dc vfs: spread struc... |
1385 |
set_mnt_shared(p); |
b90fa9ae8 [PATCH] shared mo... |
1386 |
} |
1a3906895 [PATCH] reduce st... |
1387 |
if (parent_path) { |
0fb54e505 vfs: spread struc... |
1388 1389 |
detach_mnt(source_mnt, parent_path); attach_mnt(source_mnt, path); |
143c8c91c vfs: mnt_ns moved... |
1390 |
touch_mnt_namespace(source_mnt->mnt_ns); |
214444032 [PATCH] shared mo... |
1391 |
} else { |
14cf1fa8f vfs: spread struc... |
1392 |
mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt); |
0fb54e505 vfs: spread struc... |
1393 |
commit_tree(source_mnt); |
214444032 [PATCH] shared mo... |
1394 |
} |
b90fa9ae8 [PATCH] shared mo... |
1395 |
|
1b8e5564b vfs: the first sp... |
1396 1397 |
list_for_each_entry_safe(child, p, &tree_list, mnt_hash) { list_del_init(&child->mnt_hash); |
4b2619a57 vfs: spread struc... |
1398 |
commit_tree(child); |
b90fa9ae8 [PATCH] shared mo... |
1399 |
} |
99b7db7b8 fs: brlock vfsmou... |
1400 |
br_write_unlock(vfsmount_lock); |
b90fa9ae8 [PATCH] shared mo... |
1401 |
return 0; |
719f5d7f0 [patch 4/7] vfs: ... |
1402 1403 |
out_cleanup_ids: |
fc7be130c vfs: switch pnode... |
1404 |
if (IS_MNT_SHARED(dest_mnt)) |
0fb54e505 vfs: spread struc... |
1405 |
cleanup_group_ids(source_mnt, NULL); |
719f5d7f0 [patch 4/7] vfs: ... |
1406 1407 |
out: return err; |
b90fa9ae8 [PATCH] shared mo... |
1408 |
} |
b12cea919 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 vfs: spread struc... |
1435 |
static int graft_tree(struct mount *mnt, struct path *path) |
1da177e4c Linux-2.6.12-rc2 |
1436 |
{ |
95bc5f25c vfs: spread struc... |
1437 |
if (mnt->mnt.mnt_sb->s_flags & MS_NOUSER) |
1da177e4c Linux-2.6.12-rc2 |
1438 |
return -EINVAL; |
8c3ee42e8 [PATCH] get rid o... |
1439 |
if (S_ISDIR(path->dentry->d_inode->i_mode) != |
95bc5f25c vfs: spread struc... |
1440 |
S_ISDIR(mnt->mnt.mnt_root->d_inode->i_mode)) |
1da177e4c Linux-2.6.12-rc2 |
1441 |
return -ENOTDIR; |
b12cea919 change the lockin... |
1442 1443 |
if (d_unlinked(path->dentry)) return -ENOENT; |
1da177e4c Linux-2.6.12-rc2 |
1444 |
|
95bc5f25c vfs: spread struc... |
1445 |
return attach_recursive_mnt(mnt, path, NULL); |
1da177e4c Linux-2.6.12-rc2 |
1446 1447 1448 |
} /* |
7a2e8a8fa 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 fs/namespace.c: b... |
1454 |
int type = flags & ~(MS_REC | MS_SILENT); |
7a2e8a8fa 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 [PATCH] beginning... |
1466 1467 |
* recursively change the type of the mountpoint. */ |
0a0d8a467 [PATCH] no need f... |
1468 |
static int do_change_type(struct path *path, int flag) |
07b20889e [PATCH] beginning... |
1469 |
{ |
315fc83e5 vfs: spread struc... |
1470 |
struct mount *m; |
4b8b21f4f vfs: spread struc... |
1471 |
struct mount *mnt = real_mount(path->mnt); |
07b20889e [PATCH] beginning... |
1472 |
int recurse = flag & MS_REC; |
7a2e8a8fa VFS: Sanity check... |
1473 |
int type; |
719f5d7f0 [patch 4/7] vfs: ... |
1474 |
int err = 0; |
07b20889e [PATCH] beginning... |
1475 |
|
ee6f95829 check privileges ... |
1476 1477 |
if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
2d92ab3c6 [PATCH] finally g... |
1478 |
if (path->dentry != path->mnt->mnt_root) |
07b20889e [PATCH] beginning... |
1479 |
return -EINVAL; |
7a2e8a8fa VFS: Sanity check... |
1480 1481 1482 |
type = flags_to_propagation_type(flag); if (!type) return -EINVAL; |
07b20889e [PATCH] beginning... |
1483 |
down_write(&namespace_sem); |
719f5d7f0 [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 fs: brlock vfsmou... |
1489 |
br_write_lock(vfsmount_lock); |
909b0a88e vfs: spread struc... |
1490 |
for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL)) |
0f0afb1dc vfs: spread struc... |
1491 |
change_mnt_propagation(m, type); |
99b7db7b8 fs: brlock vfsmou... |
1492 |
br_write_unlock(vfsmount_lock); |
719f5d7f0 [patch 4/7] vfs: ... |
1493 1494 |
out_unlock: |
07b20889e [PATCH] beginning... |
1495 |
up_write(&namespace_sem); |
719f5d7f0 [patch 4/7] vfs: ... |
1496 |
return err; |
07b20889e [PATCH] beginning... |
1497 1498 1499 |
} /* |
1da177e4c Linux-2.6.12-rc2 |
1500 1501 |
* do loopback mount. */ |
0a0d8a467 [PATCH] no need f... |
1502 |
static int do_loopback(struct path *path, char *old_name, |
2dafe1c4d reduce large do_m... |
1503 |
int recurse) |
1da177e4c Linux-2.6.12-rc2 |
1504 |
{ |
b12cea919 change the lockin... |
1505 |
LIST_HEAD(umount_list); |
2d92ab3c6 [PATCH] finally g... |
1506 |
struct path old_path; |
87129cc0e vfs: spread struc... |
1507 |
struct mount *mnt = NULL, *old; |
2d92ab3c6 [PATCH] finally g... |
1508 |
int err = mount_is_safe(path); |
1da177e4c Linux-2.6.12-rc2 |
1509 1510 1511 1512 |
if (err) return err; if (!old_name || !*old_name) return -EINVAL; |
815d405ce VFS: Fix the rema... |
1513 |
err = kern_path(old_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path); |
1da177e4c Linux-2.6.12-rc2 |
1514 1515 |
if (err) return err; |
b12cea919 change the lockin... |
1516 1517 1518 |
err = lock_mount(path); if (err) goto out; |
87129cc0e vfs: spread struc... |
1519 |
old = real_mount(old_path.mnt); |
1da177e4c Linux-2.6.12-rc2 |
1520 |
err = -EINVAL; |
fc7be130c vfs: switch pnode... |
1521 |
if (IS_MNT_UNBINDABLE(old)) |
b12cea919 change the lockin... |
1522 |
goto out2; |
9676f0c63 [PATCH] unbindabl... |
1523 |
|
143c8c91c vfs: mnt_ns moved... |
1524 |
if (!check_mnt(real_mount(path->mnt)) || !check_mnt(old)) |
b12cea919 change the lockin... |
1525 |
goto out2; |
1da177e4c Linux-2.6.12-rc2 |
1526 |
|
ccd48bc7f [PATCH] cleanups ... |
1527 1528 |
err = -ENOMEM; if (recurse) |
87129cc0e vfs: spread struc... |
1529 |
mnt = copy_tree(old, old_path.dentry, 0); |
ccd48bc7f [PATCH] cleanups ... |
1530 |
else |
87129cc0e vfs: spread struc... |
1531 |
mnt = clone_mnt(old, old_path.dentry, 0); |
ccd48bc7f [PATCH] cleanups ... |
1532 1533 |
if (!mnt) |
b12cea919 change the lockin... |
1534 |
goto out2; |
ccd48bc7f [PATCH] cleanups ... |
1535 |
|
95bc5f25c vfs: spread struc... |
1536 |
err = graft_tree(mnt, path); |
ccd48bc7f [PATCH] cleanups ... |
1537 |
if (err) { |
99b7db7b8 fs: brlock vfsmou... |
1538 |
br_write_lock(vfsmount_lock); |
761d5c38e vfs: spread struc... |
1539 |
umount_tree(mnt, 0, &umount_list); |
99b7db7b8 fs: brlock vfsmou... |
1540 |
br_write_unlock(vfsmount_lock); |
5b83d2c5c [PATCH] sanitize ... |
1541 |
} |
b12cea919 change the lockin... |
1542 1543 1544 |
out2: unlock_mount(path); release_mounts(&umount_list); |
ccd48bc7f [PATCH] cleanups ... |
1545 |
out: |
2d92ab3c6 [PATCH] finally g... |
1546 |
path_put(&old_path); |
1da177e4c Linux-2.6.12-rc2 |
1547 1548 |
return err; } |
2e4b7fcd9 [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 vfs: spread struc... |
1560 |
error = mnt_make_readonly(real_mount(mnt)); |
2e4b7fcd9 [PATCH] r/o bind ... |
1561 |
else |
83adc7532 vfs: spread struc... |
1562 |
__mnt_unmake_readonly(real_mount(mnt)); |
2e4b7fcd9 [PATCH] r/o bind ... |
1563 1564 |
return error; } |
1da177e4c 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 [PATCH] no need f... |
1570 |
static int do_remount(struct path *path, int flags, int mnt_flags, |
1da177e4c Linux-2.6.12-rc2 |
1571 1572 1573 |
void *data) { int err; |
2d92ab3c6 [PATCH] finally g... |
1574 |
struct super_block *sb = path->mnt->mnt_sb; |
143c8c91c vfs: mnt_ns moved... |
1575 |
struct mount *mnt = real_mount(path->mnt); |
1da177e4c Linux-2.6.12-rc2 |
1576 1577 1578 |
if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
143c8c91c vfs: mnt_ns moved... |
1579 |
if (!check_mnt(mnt)) |
1da177e4c Linux-2.6.12-rc2 |
1580 |
return -EINVAL; |
2d92ab3c6 [PATCH] finally g... |
1581 |
if (path->dentry != path->mnt->mnt_root) |
1da177e4c Linux-2.6.12-rc2 |
1582 |
return -EINVAL; |
ff36fe2c8 LSM: Pass -o remo... |
1583 1584 1585 |
err = security_sb_remount(sb, data); if (err) return err; |
1da177e4c Linux-2.6.12-rc2 |
1586 |
down_write(&sb->s_umount); |
2e4b7fcd9 [PATCH] r/o bind ... |
1587 |
if (flags & MS_BIND) |
2d92ab3c6 [PATCH] finally g... |
1588 |
err = change_mount_flags(path->mnt, flags); |
4aa98cf76 Push BKL down int... |
1589 |
else |
2e4b7fcd9 [PATCH] r/o bind ... |
1590 |
err = do_remount_sb(sb, flags, data, 0); |
7b43a79f3 mnt_flags fixes i... |
1591 |
if (!err) { |
99b7db7b8 fs: brlock vfsmou... |
1592 |
br_write_lock(vfsmount_lock); |
143c8c91c vfs: mnt_ns moved... |
1593 1594 |
mnt_flags |= mnt->mnt.mnt_flags & MNT_PROPAGATION_MASK; mnt->mnt.mnt_flags = mnt_flags; |
99b7db7b8 fs: brlock vfsmou... |
1595 |
br_write_unlock(vfsmount_lock); |
7b43a79f3 mnt_flags fixes i... |
1596 |
} |
1da177e4c Linux-2.6.12-rc2 |
1597 |
up_write(&sb->s_umount); |
0e55a7cca [RFC PATCH] touch... |
1598 |
if (!err) { |
99b7db7b8 fs: brlock vfsmou... |
1599 |
br_write_lock(vfsmount_lock); |
143c8c91c vfs: mnt_ns moved... |
1600 |
touch_mnt_namespace(mnt->mnt_ns); |
99b7db7b8 fs: brlock vfsmou... |
1601 |
br_write_unlock(vfsmount_lock); |
0e55a7cca [RFC PATCH] touch... |
1602 |
} |
1da177e4c Linux-2.6.12-rc2 |
1603 1604 |
return err; } |
cbbe362cd vfs: spread struc... |
1605 |
static inline int tree_contains_unbindable(struct mount *mnt) |
9676f0c63 [PATCH] unbindabl... |
1606 |
{ |
315fc83e5 vfs: spread struc... |
1607 |
struct mount *p; |
909b0a88e vfs: spread struc... |
1608 |
for (p = mnt; p; p = next_mnt(p, mnt)) { |
fc7be130c vfs: switch pnode... |
1609 |
if (IS_MNT_UNBINDABLE(p)) |
9676f0c63 [PATCH] unbindabl... |
1610 1611 1612 1613 |
return 1; } return 0; } |
0a0d8a467 [PATCH] no need f... |
1614 |
static int do_move_mount(struct path *path, char *old_name) |
1da177e4c Linux-2.6.12-rc2 |
1615 |
{ |
2d92ab3c6 [PATCH] finally g... |
1616 |
struct path old_path, parent_path; |
676da58df vfs: spread struc... |
1617 |
struct mount *p; |
0fb54e505 vfs: spread struc... |
1618 |
struct mount *old; |
1da177e4c 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 [PATCH] finally g... |
1624 |
err = kern_path(old_name, LOOKUP_FOLLOW, &old_path); |
1da177e4c Linux-2.6.12-rc2 |
1625 1626 |
if (err) return err; |
b12cea919 change the lockin... |
1627 |
err = lock_mount(path); |
cc53ce53c Add a dentry op t... |
1628 1629 |
if (err < 0) goto out; |
143c8c91c vfs: mnt_ns moved... |
1630 |
old = real_mount(old_path.mnt); |
fc7be130c vfs: switch pnode... |
1631 |
p = real_mount(path->mnt); |
143c8c91c vfs: mnt_ns moved... |
1632 |
|
1da177e4c Linux-2.6.12-rc2 |
1633 |
err = -EINVAL; |
fc7be130c vfs: switch pnode... |
1634 |
if (!check_mnt(p) || !check_mnt(old)) |
1da177e4c Linux-2.6.12-rc2 |
1635 |
goto out1; |
f3da392e9 dcache: extrace a... |
1636 |
if (d_unlinked(path->dentry)) |
214444032 [PATCH] shared mo... |
1637 |
goto out1; |
1da177e4c Linux-2.6.12-rc2 |
1638 1639 |
err = -EINVAL; |
2d92ab3c6 [PATCH] finally g... |
1640 |
if (old_path.dentry != old_path.mnt->mnt_root) |
214444032 [PATCH] shared mo... |
1641 |
goto out1; |
1da177e4c Linux-2.6.12-rc2 |
1642 |
|
676da58df vfs: spread struc... |
1643 |
if (!mnt_has_parent(old)) |
214444032 [PATCH] shared mo... |
1644 |
goto out1; |
1da177e4c Linux-2.6.12-rc2 |
1645 |
|
2d92ab3c6 [PATCH] finally g... |
1646 1647 |
if (S_ISDIR(path->dentry->d_inode->i_mode) != S_ISDIR(old_path.dentry->d_inode->i_mode)) |
214444032 [PATCH] shared mo... |
1648 1649 1650 1651 |
goto out1; /* * Don't move a mount residing in a shared parent. */ |
fc7be130c vfs: switch pnode... |
1652 |
if (IS_MNT_SHARED(old->mnt_parent)) |
214444032 [PATCH] shared mo... |
1653 |
goto out1; |
9676f0c63 [PATCH] unbindabl... |
1654 1655 1656 1657 |
/* * Don't move a mount tree containing unbindable mounts to a destination * mount which is shared. */ |
fc7be130c vfs: switch pnode... |
1658 |
if (IS_MNT_SHARED(p) && tree_contains_unbindable(old)) |
9676f0c63 [PATCH] unbindabl... |
1659 |
goto out1; |
1da177e4c Linux-2.6.12-rc2 |
1660 |
err = -ELOOP; |
fc7be130c vfs: switch pnode... |
1661 |
for (; mnt_has_parent(p); p = p->mnt_parent) |
676da58df vfs: spread struc... |
1662 |
if (p == old) |
214444032 [PATCH] shared mo... |
1663 |
goto out1; |
1da177e4c Linux-2.6.12-rc2 |
1664 |
|
0fb54e505 vfs: spread struc... |
1665 |
err = attach_recursive_mnt(old, path, &parent_path); |
4ac913785 Embed a struct pa... |
1666 |
if (err) |
214444032 [PATCH] shared mo... |
1667 |
goto out1; |
1da177e4c Linux-2.6.12-rc2 |
1668 1669 1670 |
/* if the mount is moved, it should no longer be expire * automatically */ |
6776db3d3 vfs: take mnt_sha... |
1671 |
list_del_init(&old->mnt_expire); |
1da177e4c Linux-2.6.12-rc2 |
1672 |
out1: |
b12cea919 change the lockin... |
1673 |
unlock_mount(path); |
1da177e4c Linux-2.6.12-rc2 |
1674 |
out: |
1da177e4c Linux-2.6.12-rc2 |
1675 |
if (!err) |
1a3906895 [PATCH] reduce st... |
1676 |
path_put(&parent_path); |
2d92ab3c6 [PATCH] finally g... |
1677 |
path_put(&old_path); |
1da177e4c Linux-2.6.12-rc2 |
1678 1679 |
return err; } |
9d412a43c 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 vfs: make do_kern... |
1702 |
static struct vfsmount * |
9d412a43c 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 vfs: split off vf... |
1716 1717 1718 1719 |
/* * add a mount into a namespace's mount tree */ |
95bc5f25c vfs: spread struc... |
1720 |
static int do_add_mount(struct mount *newmnt, struct path *path, int mnt_flags) |
9d412a43c vfs: split off vf... |
1721 1722 1723 1724 |
{ int err; mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL); |
b12cea919 change the lockin... |
1725 1726 1727 |
err = lock_mount(path); if (err) return err; |
9d412a43c vfs: split off vf... |
1728 1729 |
err = -EINVAL; |
143c8c91c vfs: mnt_ns moved... |
1730 |
if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(real_mount(path->mnt))) |
9d412a43c vfs: split off vf... |
1731 1732 1733 1734 |
goto unlock; /* Refuse the same filesystem on the same mount point */ err = -EBUSY; |
95bc5f25c vfs: spread struc... |
1735 |
if (path->mnt->mnt_sb == newmnt->mnt.mnt_sb && |
9d412a43c vfs: split off vf... |
1736 1737 1738 1739 |
path->mnt->mnt_root == path->dentry) goto unlock; err = -EINVAL; |
95bc5f25c vfs: spread struc... |
1740 |
if (S_ISLNK(newmnt->mnt.mnt_root->d_inode->i_mode)) |
9d412a43c vfs: split off vf... |
1741 |
goto unlock; |
95bc5f25c vfs: spread struc... |
1742 |
newmnt->mnt.mnt_flags = mnt_flags; |
9d412a43c vfs: split off vf... |
1743 1744 1745 |
err = graft_tree(newmnt, path); unlock: |
b12cea919 change the lockin... |
1746 |
unlock_mount(path); |
9d412a43c vfs: split off vf... |
1747 1748 |
return err; } |
b1e75df45 tidy up around fi... |
1749 |
|
1da177e4c 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 [PATCH] no need f... |
1754 |
static int do_new_mount(struct path *path, char *type, int flags, |
1da177e4c Linux-2.6.12-rc2 |
1755 1756 1757 |
int mnt_flags, char *name, void *data) { struct vfsmount *mnt; |
15f9a3f3e don't drop newmnt... |
1758 |
int err; |
1da177e4c Linux-2.6.12-rc2 |
1759 |
|
eca6f534e fs: fix overflow ... |
1760 |
if (!type) |
1da177e4c 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 vfs: spread struc... |
1770 |
err = do_add_mount(real_mount(mnt), path, mnt_flags); |
15f9a3f3e don't drop newmnt... |
1771 1772 1773 |
if (err) mntput(mnt); return err; |
1da177e4c Linux-2.6.12-rc2 |
1774 |
} |
19a167af7 Take the completi... |
1775 1776 |
int finish_automount(struct vfsmount *m, struct path *path) { |
6776db3d3 vfs: take mnt_sha... |
1777 |
struct mount *mnt = real_mount(m); |
19a167af7 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 vfs: take mnt_sha... |
1782 |
BUG_ON(mnt_get_count(mnt) < 2); |
19a167af7 Take the completi... |
1783 1784 1785 |
if (m->mnt_sb == path->mnt->mnt_sb && m->mnt_root == path->dentry) { |
b1e75df45 tidy up around fi... |
1786 1787 |
err = -ELOOP; goto fail; |
19a167af7 Take the completi... |
1788 |
} |
95bc5f25c vfs: spread struc... |
1789 |
err = do_add_mount(mnt, path, path->mnt->mnt_flags | MNT_SHRINKABLE); |
b1e75df45 tidy up around fi... |
1790 1791 1792 1793 |
if (!err) return 0; fail: /* remove m from any expiration list it may be on */ |
6776db3d3 vfs: take mnt_sha... |
1794 |
if (!list_empty(&mnt->mnt_expire)) { |
b1e75df45 tidy up around fi... |
1795 1796 |
down_write(&namespace_sem); br_write_lock(vfsmount_lock); |
6776db3d3 vfs: take mnt_sha... |
1797 |
list_del_init(&mnt->mnt_expire); |
b1e75df45 tidy up around fi... |
1798 1799 |
br_write_unlock(vfsmount_lock); up_write(&namespace_sem); |
19a167af7 Take the completi... |
1800 |
} |
b1e75df45 tidy up around fi... |
1801 1802 |
mntput(m); mntput(m); |
19a167af7 Take the completi... |
1803 1804 |
return err; } |
ea5b778a8 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 vfs: take mnt_sha... |
1814 |
list_add_tail(&real_mount(mnt)->mnt_expire, expiry_list); |
ea5b778a8 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 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 vfs: spread struc... |
1828 |
struct mount *mnt, *next; |
1da177e4c Linux-2.6.12-rc2 |
1829 |
LIST_HEAD(graveyard); |
bcc5c7d2b [PATCH] sanitize ... |
1830 |
LIST_HEAD(umounts); |
1da177e4c Linux-2.6.12-rc2 |
1831 1832 1833 |
if (list_empty(mounts)) return; |
bcc5c7d2b [PATCH] sanitize ... |
1834 |
down_write(&namespace_sem); |
99b7db7b8 fs: brlock vfsmou... |
1835 |
br_write_lock(vfsmount_lock); |
1da177e4c 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 vfs: take mnt_sha... |
1843 |
list_for_each_entry_safe(mnt, next, mounts, mnt_expire) { |
863d684f9 vfs: move the res... |
1844 |
if (!xchg(&mnt->mnt_expiry_mark, 1) || |
1ab597386 vfs: spread struc... |
1845 |
propagate_mount_busy(mnt, 1)) |
1da177e4c Linux-2.6.12-rc2 |
1846 |
continue; |
6776db3d3 vfs: take mnt_sha... |
1847 |
list_move(&mnt->mnt_expire, &graveyard); |
1da177e4c Linux-2.6.12-rc2 |
1848 |
} |
bcc5c7d2b [PATCH] sanitize ... |
1849 |
while (!list_empty(&graveyard)) { |
6776db3d3 vfs: take mnt_sha... |
1850 |
mnt = list_first_entry(&graveyard, struct mount, mnt_expire); |
143c8c91c vfs: mnt_ns moved... |
1851 |
touch_mnt_namespace(mnt->mnt_ns); |
bcc5c7d2b [PATCH] sanitize ... |
1852 1853 |
umount_tree(mnt, 1, &umounts); } |
99b7db7b8 fs: brlock vfsmou... |
1854 |
br_write_unlock(vfsmount_lock); |
bcc5c7d2b [PATCH] sanitize ... |
1855 1856 1857 |
up_write(&namespace_sem); release_mounts(&umounts); |
5528f911b 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 vfs: spread struc... |
1868 |
static int select_submounts(struct mount *parent, struct list_head *graveyard) |
5528f911b VFS: Add shrink_s... |
1869 |
{ |
692afc312 vfs: spread struc... |
1870 |
struct mount *this_parent = parent; |
5528f911b VFS: Add shrink_s... |
1871 1872 1873 1874 |
struct list_head *next; int found = 0; repeat: |
6b41d536f vfs: take mnt_chi... |
1875 |
next = this_parent->mnt_mounts.next; |
5528f911b VFS: Add shrink_s... |
1876 |
resume: |
6b41d536f vfs: take mnt_chi... |
1877 |
while (next != &this_parent->mnt_mounts) { |
5528f911b VFS: Add shrink_s... |
1878 |
struct list_head *tmp = next; |
6b41d536f vfs: take mnt_chi... |
1879 |
struct mount *mnt = list_entry(tmp, struct mount, mnt_child); |
5528f911b VFS: Add shrink_s... |
1880 1881 |
next = tmp->next; |
692afc312 vfs: spread struc... |
1882 |
if (!(mnt->mnt.mnt_flags & MNT_SHRINKABLE)) |
1da177e4c Linux-2.6.12-rc2 |
1883 |
continue; |
5528f911b VFS: Add shrink_s... |
1884 1885 1886 |
/* * Descend a level if the d_mounts list is non-empty. */ |
6b41d536f vfs: take mnt_chi... |
1887 |
if (!list_empty(&mnt->mnt_mounts)) { |
5528f911b VFS: Add shrink_s... |
1888 1889 1890 |
this_parent = mnt; goto repeat; } |
1da177e4c Linux-2.6.12-rc2 |
1891 |
|
1ab597386 vfs: spread struc... |
1892 |
if (!propagate_mount_busy(mnt, 1)) { |
6776db3d3 vfs: take mnt_sha... |
1893 |
list_move_tail(&mnt->mnt_expire, graveyard); |
5528f911b VFS: Add shrink_s... |
1894 1895 |
found++; } |
1da177e4c Linux-2.6.12-rc2 |
1896 |
} |
5528f911b VFS: Add shrink_s... |
1897 1898 1899 1900 |
/* * All done at this level ... ascend and resume the search */ if (this_parent != parent) { |
6b41d536f vfs: take mnt_chi... |
1901 |
next = this_parent->mnt_child.next; |
0714a5338 vfs: now it can b... |
1902 |
this_parent = this_parent->mnt_parent; |
5528f911b 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 fs: brlock vfsmou... |
1911 1912 |
* * vfsmount_lock must be held for write |
5528f911b VFS: Add shrink_s... |
1913 |
*/ |
692afc312 vfs: spread struc... |
1914 |
static void shrink_submounts(struct mount *mnt, struct list_head *umounts) |
5528f911b VFS: Add shrink_s... |
1915 1916 |
{ LIST_HEAD(graveyard); |
761d5c38e vfs: spread struc... |
1917 |
struct mount *m; |
5528f911b VFS: Add shrink_s... |
1918 |
|
5528f911b VFS: Add shrink_s... |
1919 |
/* extract submounts of 'mountpoint' from the expiration list */ |
c35038bec [PATCH] do shrink... |
1920 |
while (select_submounts(mnt, &graveyard)) { |
bcc5c7d2b [PATCH] sanitize ... |
1921 |
while (!list_empty(&graveyard)) { |
761d5c38e vfs: spread struc... |
1922 |
m = list_first_entry(&graveyard, struct mount, |
6776db3d3 vfs: take mnt_sha... |
1923 |
mnt_expire); |
143c8c91c vfs: mnt_ns moved... |
1924 |
touch_mnt_namespace(m->mnt_ns); |
afef80b3d vfs: fix shrink_s... |
1925 |
umount_tree(m, 1, umounts); |
bcc5c7d2b [PATCH] sanitize ... |
1926 1927 |
} } |
1da177e4c Linux-2.6.12-rc2 |
1928 |
} |
1da177e4c 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 [PATCH] lindent f... |
1935 1936 |
static long exact_copy_from_user(void *to, const void __user * from, unsigned long n) |
1da177e4c 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 [PATCH] lindent f... |
1956 |
int copy_mount_options(const void __user * data, unsigned long *where) |
1da177e4c Linux-2.6.12-rc2 |
1957 1958 1959 1960 |
{ int i; unsigned long page; unsigned long size; |
b58fed8b1 [PATCH] lindent f... |
1961 |
|
1da177e4c 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 [PATCH] lindent f... |
1980 |
free_page(page); |
1da177e4c 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 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 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 [PATCH] lindent f... |
2018 |
long do_mount(char *dev_name, char *dir_name, char *type_page, |
1da177e4c Linux-2.6.12-rc2 |
2019 2020 |
unsigned long flags, void *data_page) { |
2d92ab3c6 [PATCH] finally g... |
2021 |
struct path path; |
1da177e4c 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 Linux-2.6.12-rc2 |
2033 2034 2035 |
if (data_page) ((char *)data_page)[PAGE_SIZE - 1] = 0; |
a27ab9f26 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 Don't set relatim... |
2045 2046 2047 |
/* Default to relatime unless overriden */ if (!(flags & MS_NOATIME)) mnt_flags |= MNT_RELATIME; |
0a1c01c94 Make relatime def... |
2048 |
|
1da177e4c 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 [PATCH] per-mount... |
2056 2057 2058 2059 |
if (flags & MS_NOATIME) mnt_flags |= MNT_NOATIME; if (flags & MS_NODIRATIME) mnt_flags |= MNT_NODIRATIME; |
d0adde574 Add a strictatime... |
2060 2061 |
if (flags & MS_STRICTATIME) mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME); |
2e4b7fcd9 [PATCH] r/o bind ... |
2062 2063 |
if (flags & MS_RDONLY) mnt_flags |= MNT_READONLY; |
fc33a7bb9 [PATCH] per-mount... |
2064 |
|
7a4dec538 Fix sget() race w... |
2065 |
flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN | |
d0adde574 Add a strictatime... |
2066 2067 |
MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT | MS_STRICTATIME); |
1da177e4c Linux-2.6.12-rc2 |
2068 |
|
1da177e4c Linux-2.6.12-rc2 |
2069 |
if (flags & MS_REMOUNT) |
2d92ab3c6 [PATCH] finally g... |
2070 |
retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags, |
1da177e4c Linux-2.6.12-rc2 |
2071 2072 |
data_page); else if (flags & MS_BIND) |
2d92ab3c6 [PATCH] finally g... |
2073 |
retval = do_loopback(&path, dev_name, flags & MS_REC); |
9676f0c63 [PATCH] unbindabl... |
2074 |
else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) |
2d92ab3c6 [PATCH] finally g... |
2075 |
retval = do_change_type(&path, flags); |
1da177e4c Linux-2.6.12-rc2 |
2076 |
else if (flags & MS_MOVE) |
2d92ab3c6 [PATCH] finally g... |
2077 |
retval = do_move_mount(&path, dev_name); |
1da177e4c Linux-2.6.12-rc2 |
2078 |
else |
2d92ab3c6 [PATCH] finally g... |
2079 |
retval = do_new_mount(&path, type_page, flags, mnt_flags, |
1da177e4c Linux-2.6.12-rc2 |
2080 2081 |
dev_name, data_page); dput_out: |
2d92ab3c6 [PATCH] finally g... |
2082 |
path_put(&path); |
1da177e4c Linux-2.6.12-rc2 |
2083 2084 |
return retval; } |
cf8d2c11c 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 sanitize vfsmount... |
2099 2100 |
void mnt_make_longterm(struct vfsmount *mnt) { |
83adc7532 vfs: spread struc... |
2101 |
__mnt_make_longterm(real_mount(mnt)); |
f03c65993 sanitize vfsmount... |
2102 |
} |
83adc7532 vfs: spread struc... |
2103 |
void mnt_make_shortterm(struct vfsmount *m) |
f03c65993 sanitize vfsmount... |
2104 |
{ |
7e3d0eb0b VFS: Fix UP compi... |
2105 |
#ifdef CONFIG_SMP |
83adc7532 vfs: spread struc... |
2106 |
struct mount *mnt = real_mount(m); |
68e8a9fea vfs: all counters... |
2107 |
if (atomic_add_unless(&mnt->mnt_longterm, -1, 1)) |
f03c65993 sanitize vfsmount... |
2108 2109 |
return; br_write_lock(vfsmount_lock); |
68e8a9fea vfs: all counters... |
2110 |
atomic_dec(&mnt->mnt_longterm); |
f03c65993 sanitize vfsmount... |
2111 |
br_write_unlock(vfsmount_lock); |
7e3d0eb0b VFS: Fix UP compi... |
2112 |
#endif |
f03c65993 sanitize vfsmount... |
2113 |
} |
741a29513 [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 Merge sys_clone()... |
2118 |
static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, |
6b3286ed1 [PATCH] rename st... |
2119 |
struct fs_struct *fs) |
1da177e4c Linux-2.6.12-rc2 |
2120 |
{ |
6b3286ed1 [PATCH] rename st... |
2121 |
struct mnt_namespace *new_ns; |
7f2da1e7d [PATCH] kill altroot |
2122 |
struct vfsmount *rootmnt = NULL, *pwdmnt = NULL; |
315fc83e5 vfs: spread struc... |
2123 |
struct mount *p, *q; |
be08d6d26 switch mnt_namesp... |
2124 |
struct mount *old = mnt_ns->root; |
cb338d06e vfs: spread struc... |
2125 |
struct mount *new; |
1da177e4c Linux-2.6.12-rc2 |
2126 |
|
cf8d2c11c VFS: Add VFS help... |
2127 2128 2129 |
new_ns = alloc_mnt_ns(); if (IS_ERR(new_ns)) return new_ns; |
1da177e4c Linux-2.6.12-rc2 |
2130 |
|
390c68436 [PATCH] making na... |
2131 |
down_write(&namespace_sem); |
1da177e4c Linux-2.6.12-rc2 |
2132 |
/* First pass: copy the tree topology */ |
909b0a88e vfs: spread struc... |
2133 |
new = copy_tree(old, old->mnt.mnt_root, CL_COPY_ALL | CL_EXPIRE); |
cb338d06e vfs: spread struc... |
2134 |
if (!new) { |
390c68436 [PATCH] making na... |
2135 |
up_write(&namespace_sem); |
1da177e4c Linux-2.6.12-rc2 |
2136 |
kfree(new_ns); |
5cc4a0341 fs/namespace.c: d... |
2137 |
return ERR_PTR(-ENOMEM); |
1da177e4c Linux-2.6.12-rc2 |
2138 |
} |
be08d6d26 switch mnt_namesp... |
2139 |
new_ns->root = new; |
99b7db7b8 fs: brlock vfsmou... |
2140 |
br_write_lock(vfsmount_lock); |
1a4eeaf2a vfs: move mnt_lis... |
2141 |
list_add_tail(&new_ns->list, &new->mnt_list); |
99b7db7b8 fs: brlock vfsmou... |
2142 |
br_write_unlock(vfsmount_lock); |
1da177e4c 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 vfs: spread struc... |
2149 |
p = old; |
cb338d06e vfs: spread struc... |
2150 |
q = new; |
1da177e4c Linux-2.6.12-rc2 |
2151 |
while (p) { |
143c8c91c vfs: mnt_ns moved... |
2152 |
q->mnt_ns = new_ns; |
83adc7532 vfs: spread struc... |
2153 |
__mnt_make_longterm(q); |
1da177e4c Linux-2.6.12-rc2 |
2154 |
if (fs) { |
315fc83e5 vfs: spread struc... |
2155 2156 |
if (&p->mnt == fs->root.mnt) { fs->root.mnt = mntget(&q->mnt); |
83adc7532 vfs: spread struc... |
2157 |
__mnt_make_longterm(q); |
315fc83e5 vfs: spread struc... |
2158 2159 |
mnt_make_shortterm(&p->mnt); rootmnt = &p->mnt; |
1da177e4c Linux-2.6.12-rc2 |
2160 |
} |
315fc83e5 vfs: spread struc... |
2161 2162 |
if (&p->mnt == fs->pwd.mnt) { fs->pwd.mnt = mntget(&q->mnt); |
83adc7532 vfs: spread struc... |
2163 |
__mnt_make_longterm(q); |
315fc83e5 vfs: spread struc... |
2164 2165 |
mnt_make_shortterm(&p->mnt); pwdmnt = &p->mnt; |
1da177e4c Linux-2.6.12-rc2 |
2166 |
} |
1da177e4c Linux-2.6.12-rc2 |
2167 |
} |
909b0a88e vfs: spread struc... |
2168 2169 |
p = next_mnt(p, old); q = next_mnt(q, new); |
1da177e4c Linux-2.6.12-rc2 |
2170 |
} |
390c68436 [PATCH] making na... |
2171 |
up_write(&namespace_sem); |
1da177e4c Linux-2.6.12-rc2 |
2172 |
|
1da177e4c Linux-2.6.12-rc2 |
2173 |
if (rootmnt) |
f03c65993 sanitize vfsmount... |
2174 |
mntput(rootmnt); |
1da177e4c Linux-2.6.12-rc2 |
2175 |
if (pwdmnt) |
f03c65993 sanitize vfsmount... |
2176 |
mntput(pwdmnt); |
1da177e4c Linux-2.6.12-rc2 |
2177 |
|
741a29513 [PATCH] unshare s... |
2178 2179 |
return new_ns; } |
213dd266d namespace: ensure... |
2180 |
struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, |
e3222c4ec Merge sys_clone()... |
2181 |
struct fs_struct *new_fs) |
741a29513 [PATCH] unshare s... |
2182 |
{ |
6b3286ed1 [PATCH] rename st... |
2183 |
struct mnt_namespace *new_ns; |
741a29513 [PATCH] unshare s... |
2184 |
|
e3222c4ec Merge sys_clone()... |
2185 |
BUG_ON(!ns); |
6b3286ed1 [PATCH] rename st... |
2186 |
get_mnt_ns(ns); |
741a29513 [PATCH] unshare s... |
2187 2188 |
if (!(flags & CLONE_NEWNS)) |
e3222c4ec Merge sys_clone()... |
2189 |
return ns; |
741a29513 [PATCH] unshare s... |
2190 |
|
e3222c4ec Merge sys_clone()... |
2191 |
new_ns = dup_mnt_ns(ns, new_fs); |
741a29513 [PATCH] unshare s... |
2192 |
|
6b3286ed1 [PATCH] rename st... |
2193 |
put_mnt_ns(ns); |
e3222c4ec Merge sys_clone()... |
2194 |
return new_ns; |
1da177e4c Linux-2.6.12-rc2 |
2195 |
} |
cf8d2c11c 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 vfs: move mnt_lis... |
2200 |
static struct mnt_namespace *create_mnt_ns(struct vfsmount *m) |
cf8d2c11c VFS: Add VFS help... |
2201 |
{ |
1a4eeaf2a vfs: move mnt_lis... |
2202 |
struct mnt_namespace *new_ns = alloc_mnt_ns(); |
cf8d2c11c VFS: Add VFS help... |
2203 |
if (!IS_ERR(new_ns)) { |
1a4eeaf2a vfs: move mnt_lis... |
2204 2205 2206 |
struct mount *mnt = real_mount(m); mnt->mnt_ns = new_ns; __mnt_make_longterm(mnt); |
be08d6d26 switch mnt_namesp... |
2207 |
new_ns->root = mnt; |
1a4eeaf2a vfs: move mnt_lis... |
2208 |
list_add(&new_ns->list, &mnt->mnt_list); |
c13344958 switch create_mnt... |
2209 |
} else { |
1a4eeaf2a vfs: move mnt_lis... |
2210 |
mntput(m); |
cf8d2c11c VFS: Add VFS help... |
2211 2212 2213 |
} return new_ns; } |
cf8d2c11c VFS: Add VFS help... |
2214 |
|
ea441d110 new helper: mount... |
2215 2216 2217 |
struct dentry *mount_subtree(struct vfsmount *mnt, const char *name) { struct mnt_namespace *ns; |
d31da0f0b mount_subtree() p... |
2218 |
struct super_block *s; |
ea441d110 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 mount_subtree() p... |
2235 2236 |
s = path.mnt->mnt_sb; atomic_inc(&s->s_active); |
ea441d110 new helper: mount... |
2237 2238 |
mntput(path.mnt); /* lock the sucker */ |
d31da0f0b mount_subtree() p... |
2239 |
down_write(&s->s_umount); |
ea441d110 new helper: mount... |
2240 2241 2242 2243 |
/* ... and return the root of (sub)tree on it */ return path.dentry; } EXPORT_SYMBOL(mount_subtree); |
bdc480e3b [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 Linux-2.6.12-rc2 |
2246 |
{ |
eca6f534e fs: fix overflow ... |
2247 2248 2249 2250 |
int ret; char *kernel_type; char *kernel_dir; char *kernel_dev; |
1da177e4c Linux-2.6.12-rc2 |
2251 |
unsigned long data_page; |
1da177e4c Linux-2.6.12-rc2 |
2252 |
|
eca6f534e fs: fix overflow ... |
2253 2254 2255 |
ret = copy_mount_string(type, &kernel_type); if (ret < 0) goto out_type; |
1da177e4c Linux-2.6.12-rc2 |
2256 |
|
eca6f534e 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 Linux-2.6.12-rc2 |
2262 |
|
eca6f534e fs: fix overflow ... |
2263 2264 2265 |
ret = copy_mount_string(dev_name, &kernel_dev); if (ret < 0) goto out_dev; |
1da177e4c Linux-2.6.12-rc2 |
2266 |
|
eca6f534e fs: fix overflow ... |
2267 2268 2269 |
ret = copy_mount_options(data, &data_page); if (ret < 0) goto out_data; |
1da177e4c Linux-2.6.12-rc2 |
2270 |
|
eca6f534e fs: fix overflow ... |
2271 2272 |
ret = do_mount(kernel_dev, kernel_dir, kernel_type, flags, (void *) data_page); |
1da177e4c Linux-2.6.12-rc2 |
2273 |
|
eca6f534e 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 Linux-2.6.12-rc2 |
2283 2284 2285 |
} /* |
afac7cba7 vfs: more mnt_par... |
2286 2287 2288 2289 |
* Return true if path is reachable from root * * namespace_sem or vfsmount_lock is held */ |
643822b41 vfs: spread struc... |
2290 |
bool is_path_reachable(struct mount *mnt, struct dentry *dentry, |
afac7cba7 vfs: more mnt_par... |
2291 2292 |
const struct path *root) { |
643822b41 vfs: spread struc... |
2293 |
while (&mnt->mnt != root->mnt && mnt_has_parent(mnt)) { |
a73324da7 vfs: move mnt_mou... |
2294 |
dentry = mnt->mnt_mountpoint; |
0714a5338 vfs: now it can b... |
2295 |
mnt = mnt->mnt_parent; |
afac7cba7 vfs: more mnt_par... |
2296 |
} |
643822b41 vfs: spread struc... |
2297 |
return &mnt->mnt == root->mnt && is_subdir(dentry, root->dentry); |
afac7cba7 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 vfs: spread struc... |
2304 |
res = is_path_reachable(real_mount(path1->mnt), path1->dentry, path2); |
afac7cba7 vfs: more mnt_par... |
2305 2306 2307 2308 2309 2310 |
br_read_unlock(vfsmount_lock); return res; } EXPORT_SYMBOL(path_is_under); /* |
1da177e4c 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 [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 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 [CVE-2009-0029] S... |
2335 2336 |
SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, const char __user *, put_old) |
1da177e4c Linux-2.6.12-rc2 |
2337 |
{ |
2d8f30380 [PATCH] sanitize ... |
2338 |
struct path new, old, parent_path, root_parent, root; |
419148da6 vfs: spread struc... |
2339 |
struct mount *new_mnt, *root_mnt; |
1da177e4c Linux-2.6.12-rc2 |
2340 2341 2342 2343 |
int error; if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
2d8f30380 [PATCH] sanitize ... |
2344 |
error = user_path_dir(new_root, &new); |
1da177e4c Linux-2.6.12-rc2 |
2345 2346 |
if (error) goto out0; |
1da177e4c Linux-2.6.12-rc2 |
2347 |
|
2d8f30380 [PATCH] sanitize ... |
2348 |
error = user_path_dir(put_old, &old); |
1da177e4c Linux-2.6.12-rc2 |
2349 2350 |
if (error) goto out1; |
2d8f30380 [PATCH] sanitize ... |
2351 |
error = security_sb_pivotroot(&old, &new); |
b12cea919 change the lockin... |
2352 2353 |
if (error) goto out2; |
1da177e4c Linux-2.6.12-rc2 |
2354 |
|
f7ad3c6be vfs: add helpers ... |
2355 |
get_fs_root(current->fs, &root); |
b12cea919 change the lockin... |
2356 2357 2358 |
error = lock_mount(&old); if (error) goto out3; |
1da177e4c Linux-2.6.12-rc2 |
2359 |
error = -EINVAL; |
419148da6 vfs: spread struc... |
2360 2361 |
new_mnt = real_mount(new.mnt); root_mnt = real_mount(root.mnt); |
fc7be130c 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 change the lockin... |
2365 |
goto out4; |
143c8c91c vfs: mnt_ns moved... |
2366 |
if (!check_mnt(root_mnt) || !check_mnt(new_mnt)) |
b12cea919 change the lockin... |
2367 |
goto out4; |
1da177e4c Linux-2.6.12-rc2 |
2368 |
error = -ENOENT; |
f3da392e9 dcache: extrace a... |
2369 |
if (d_unlinked(new.dentry)) |
b12cea919 change the lockin... |
2370 |
goto out4; |
f3da392e9 dcache: extrace a... |
2371 |
if (d_unlinked(old.dentry)) |
b12cea919 change the lockin... |
2372 |
goto out4; |
1da177e4c Linux-2.6.12-rc2 |
2373 |
error = -EBUSY; |
2d8f30380 [PATCH] sanitize ... |
2374 2375 |
if (new.mnt == root.mnt || old.mnt == root.mnt) |
b12cea919 change the lockin... |
2376 |
goto out4; /* loop, on the same file system */ |
1da177e4c Linux-2.6.12-rc2 |
2377 |
error = -EINVAL; |
8c3ee42e8 [PATCH] get rid o... |
2378 |
if (root.mnt->mnt_root != root.dentry) |
b12cea919 change the lockin... |
2379 |
goto out4; /* not a mountpoint */ |
676da58df vfs: spread struc... |
2380 |
if (!mnt_has_parent(root_mnt)) |
b12cea919 change the lockin... |
2381 |
goto out4; /* not attached */ |
2d8f30380 [PATCH] sanitize ... |
2382 |
if (new.mnt->mnt_root != new.dentry) |
b12cea919 change the lockin... |
2383 |
goto out4; /* not a mountpoint */ |
676da58df vfs: spread struc... |
2384 |
if (!mnt_has_parent(new_mnt)) |
b12cea919 change the lockin... |
2385 |
goto out4; /* not attached */ |
4ac913785 Embed a struct pa... |
2386 |
/* make sure we can reach put_old from new_root */ |
643822b41 vfs: spread struc... |
2387 |
if (!is_path_reachable(real_mount(old.mnt), old.dentry, &new)) |
b12cea919 change the lockin... |
2388 |
goto out4; |
27cb1572e fix deadlock in p... |
2389 |
br_write_lock(vfsmount_lock); |
419148da6 vfs: spread struc... |
2390 2391 |
detach_mnt(new_mnt, &parent_path); detach_mnt(root_mnt, &root_parent); |
4ac913785 Embed a struct pa... |
2392 |
/* mount old root on put_old */ |
419148da6 vfs: spread struc... |
2393 |
attach_mnt(root_mnt, &old); |
4ac913785 Embed a struct pa... |
2394 |
/* mount new_root on / */ |
419148da6 vfs: spread struc... |
2395 |
attach_mnt(new_mnt, &root_parent); |
6b3286ed1 [PATCH] rename st... |
2396 |
touch_mnt_namespace(current->nsproxy->mnt_ns); |
99b7db7b8 fs: brlock vfsmou... |
2397 |
br_write_unlock(vfsmount_lock); |
2d8f30380 [PATCH] sanitize ... |
2398 |
chroot_fs_refs(&root, &new); |
1da177e4c Linux-2.6.12-rc2 |
2399 |
error = 0; |
b12cea919 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 [PATCH] get rid o... |
2407 |
path_put(&root); |
b12cea919 change the lockin... |
2408 |
out2: |
2d8f30380 [PATCH] sanitize ... |
2409 |
path_put(&old); |
1da177e4c Linux-2.6.12-rc2 |
2410 |
out1: |
2d8f30380 [PATCH] sanitize ... |
2411 |
path_put(&new); |
1da177e4c Linux-2.6.12-rc2 |
2412 |
out0: |
1da177e4c Linux-2.6.12-rc2 |
2413 |
return error; |
1da177e4c Linux-2.6.12-rc2 |
2414 2415 2416 2417 2418 |
} static void __init init_mount_tree(void) { struct vfsmount *mnt; |
6b3286ed1 [PATCH] rename st... |
2419 |
struct mnt_namespace *ns; |
ac748a09f Make set_fs_{root... |
2420 |
struct path root; |
1da177e4c 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 fs: scale mntget/... |
2425 |
|
3b22edc57 VFS: Switch init_... |
2426 2427 |
ns = create_mnt_ns(mnt); if (IS_ERR(ns)) |
1da177e4c Linux-2.6.12-rc2 |
2428 |
panic("Can't allocate initial namespace"); |
6b3286ed1 [PATCH] rename st... |
2429 2430 2431 |
init_task.nsproxy->mnt_ns = ns; get_mnt_ns(ns); |
be08d6d26 switch mnt_namesp... |
2432 2433 |
root.mnt = mnt; root.dentry = mnt->mnt_root; |
ac748a09f Make set_fs_{root... |
2434 2435 2436 |
set_fs_pwd(current->fs, &root); set_fs_root(current->fs, &root); |
1da177e4c Linux-2.6.12-rc2 |
2437 |
} |
74bf17cff fs: remove the un... |
2438 |
void __init mnt_init(void) |
1da177e4c Linux-2.6.12-rc2 |
2439 |
{ |
13f14b4d8 Use ilog2() in fs... |
2440 |
unsigned u; |
15a67dd8c [PATCH] fs/namesp... |
2441 |
int err; |
1da177e4c Linux-2.6.12-rc2 |
2442 |
|
390c68436 [PATCH] making na... |
2443 |
init_rwsem(&namespace_sem); |
7d6fec45a vfs: start hiding... |
2444 |
mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct mount), |
20c2df83d mm: Remove slab d... |
2445 |
0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); |
1da177e4c Linux-2.6.12-rc2 |
2446 |
|
b58fed8b1 [PATCH] lindent f... |
2447 |
mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC); |
1da177e4c Linux-2.6.12-rc2 |
2448 2449 2450 2451 |
if (!mount_hashtable) panic("Failed to allocate mount hash table "); |
80cdc6dae fs: use appropria... |
2452 2453 |
printk(KERN_INFO "Mount-cache hash table entries: %lu ", HASH_SIZE); |
13f14b4d8 Use ilog2() in fs... |
2454 2455 2456 |
for (u = 0; u < HASH_SIZE; u++) INIT_LIST_HEAD(&mount_hashtable[u]); |
1da177e4c Linux-2.6.12-rc2 |
2457 |
|
99b7db7b8 fs: brlock vfsmou... |
2458 |
br_lock_init(vfsmount_lock); |
15a67dd8c [PATCH] fs/namesp... |
2459 2460 2461 2462 |
err = sysfs_init(); if (err) printk(KERN_WARNING "%s: sysfs_init error: %d ", |
8e24eea72 fs: replace remai... |
2463 |
__func__, err); |
00d266662 kobject: convert ... |
2464 2465 |
fs_kobj = kobject_create_and_add("fs", NULL); if (!fs_kobj) |
8e24eea72 fs: replace remai... |
2466 2467 |
printk(KERN_WARNING "%s: kobj create error ", __func__); |
1da177e4c Linux-2.6.12-rc2 |
2468 2469 2470 |
init_rootfs(); init_mount_tree(); } |
616511d03 VFS: Uninline the... |
2471 |
void put_mnt_ns(struct mnt_namespace *ns) |
1da177e4c Linux-2.6.12-rc2 |
2472 |
{ |
70fbcdf4d [PATCH] umount_tr... |
2473 |
LIST_HEAD(umount_list); |
616511d03 VFS: Uninline the... |
2474 |
|
d498b25a4 get rid of useles... |
2475 |
if (!atomic_dec_and_test(&ns->count)) |
616511d03 VFS: Uninline the... |
2476 |
return; |
390c68436 [PATCH] making na... |
2477 |
down_write(&namespace_sem); |
99b7db7b8 fs: brlock vfsmou... |
2478 |
br_write_lock(vfsmount_lock); |
be08d6d26 switch mnt_namesp... |
2479 |
umount_tree(ns->root, 0, &umount_list); |
99b7db7b8 fs: brlock vfsmou... |
2480 |
br_write_unlock(vfsmount_lock); |
390c68436 [PATCH] making na... |
2481 |
up_write(&namespace_sem); |
70fbcdf4d [PATCH] umount_tr... |
2482 |
release_mounts(&umount_list); |
6b3286ed1 [PATCH] rename st... |
2483 |
kfree(ns); |
1da177e4c Linux-2.6.12-rc2 |
2484 |
} |
9d412a43c vfs: split off vf... |
2485 2486 2487 |
struct vfsmount *kern_mount_data(struct file_system_type *type, void *data) { |
423e0ab08 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 vfs: split off vf... |
2498 2499 |
} EXPORT_SYMBOL_GPL(kern_mount_data); |
423e0ab08 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 fix apparmor dere... |
2510 2511 2512 |
bool our_mnt(struct vfsmount *mnt) { |
143c8c91c vfs: mnt_ns moved... |
2513 |
return check_mnt(real_mount(mnt)); |
02125a826 fix apparmor dere... |
2514 |
} |