diff options
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 64 |
1 files changed, 22 insertions, 42 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index c2ffa0f349fd..65f9c0ecc21c 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -27,6 +27,8 @@ | |||
27 | 27 | ||
28 | extern int __init init_rootfs(void); | 28 | extern int __init init_rootfs(void); |
29 | 29 | ||
30 | #define CL_EXPIRE 0x01 | ||
31 | |||
30 | #ifdef CONFIG_SYSFS | 32 | #ifdef CONFIG_SYSFS |
31 | extern int __init sysfs_init(void); | 33 | extern int __init sysfs_init(void); |
32 | #else | 34 | #else |
@@ -165,7 +167,8 @@ static struct vfsmount *next_mnt(struct vfsmount *p, struct vfsmount *root) | |||
165 | return list_entry(next, struct vfsmount, mnt_child); | 167 | return list_entry(next, struct vfsmount, mnt_child); |
166 | } | 168 | } |
167 | 169 | ||
168 | static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root) | 170 | static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root, |
171 | int flag) | ||
169 | { | 172 | { |
170 | struct super_block *sb = old->mnt_sb; | 173 | struct super_block *sb = old->mnt_sb; |
171 | struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname); | 174 | struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname); |
@@ -181,10 +184,12 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root) | |||
181 | 184 | ||
182 | /* stick the duplicate mount on the same expiry list | 185 | /* stick the duplicate mount on the same expiry list |
183 | * as the original if that was on one */ | 186 | * as the original if that was on one */ |
184 | spin_lock(&vfsmount_lock); | 187 | if (flag & CL_EXPIRE) { |
185 | if (!list_empty(&old->mnt_expire)) | 188 | spin_lock(&vfsmount_lock); |
186 | list_add(&mnt->mnt_expire, &old->mnt_expire); | 189 | if (!list_empty(&old->mnt_expire)) |
187 | spin_unlock(&vfsmount_lock); | 190 | list_add(&mnt->mnt_expire, &old->mnt_expire); |
191 | spin_unlock(&vfsmount_lock); | ||
192 | } | ||
188 | } | 193 | } |
189 | return mnt; | 194 | return mnt; |
190 | } | 195 | } |
@@ -331,36 +336,14 @@ struct seq_operations mounts_op = { | |||
331 | */ | 336 | */ |
332 | int may_umount_tree(struct vfsmount *mnt) | 337 | int may_umount_tree(struct vfsmount *mnt) |
333 | { | 338 | { |
334 | struct list_head *next; | 339 | int actual_refs = 0; |
335 | struct vfsmount *this_parent = mnt; | 340 | int minimum_refs = 0; |
336 | int actual_refs; | 341 | struct vfsmount *p; |
337 | int minimum_refs; | ||
338 | 342 | ||
339 | spin_lock(&vfsmount_lock); | 343 | spin_lock(&vfsmount_lock); |
340 | actual_refs = atomic_read(&mnt->mnt_count); | 344 | for (p = mnt; p; p = next_mnt(p, mnt)) { |
341 | minimum_refs = 2; | ||
342 | repeat: | ||
343 | next = this_parent->mnt_mounts.next; | ||
344 | resume: | ||
345 | while (next != &this_parent->mnt_mounts) { | ||
346 | struct vfsmount *p = | ||
347 | list_entry(next, struct vfsmount, mnt_child); | ||
348 | |||
349 | next = next->next; | ||
350 | |||
351 | actual_refs += atomic_read(&p->mnt_count); | 345 | actual_refs += atomic_read(&p->mnt_count); |
352 | minimum_refs += 2; | 346 | minimum_refs += 2; |
353 | |||
354 | if (!list_empty(&p->mnt_mounts)) { | ||
355 | this_parent = p; | ||
356 | goto repeat; | ||
357 | } | ||
358 | } | ||
359 | |||
360 | if (this_parent != mnt) { | ||
361 | next = this_parent->mnt_child.next; | ||
362 | this_parent = this_parent->mnt_parent; | ||
363 | goto resume; | ||
364 | } | 347 | } |
365 | spin_unlock(&vfsmount_lock); | 348 | spin_unlock(&vfsmount_lock); |
366 | 349 | ||
@@ -596,12 +579,13 @@ static int lives_below_in_same_fs(struct dentry *d, struct dentry *dentry) | |||
596 | } | 579 | } |
597 | } | 580 | } |
598 | 581 | ||
599 | static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry) | 582 | static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry, |
583 | int flag) | ||
600 | { | 584 | { |
601 | struct vfsmount *res, *p, *q, *r, *s; | 585 | struct vfsmount *res, *p, *q, *r, *s; |
602 | struct nameidata nd; | 586 | struct nameidata nd; |
603 | 587 | ||
604 | res = q = clone_mnt(mnt, dentry); | 588 | res = q = clone_mnt(mnt, dentry, flag); |
605 | if (!q) | 589 | if (!q) |
606 | goto Enomem; | 590 | goto Enomem; |
607 | q->mnt_mountpoint = mnt->mnt_mountpoint; | 591 | q->mnt_mountpoint = mnt->mnt_mountpoint; |
@@ -619,7 +603,7 @@ static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry) | |||
619 | p = s; | 603 | p = s; |
620 | nd.mnt = q; | 604 | nd.mnt = q; |
621 | nd.dentry = p->mnt_mountpoint; | 605 | nd.dentry = p->mnt_mountpoint; |
622 | q = clone_mnt(p, p->mnt_root); | 606 | q = clone_mnt(p, p->mnt_root, flag); |
623 | if (!q) | 607 | if (!q) |
624 | goto Enomem; | 608 | goto Enomem; |
625 | spin_lock(&vfsmount_lock); | 609 | spin_lock(&vfsmount_lock); |
@@ -701,18 +685,13 @@ static int do_loopback(struct nameidata *nd, char *old_name, int recurse) | |||
701 | 685 | ||
702 | err = -ENOMEM; | 686 | err = -ENOMEM; |
703 | if (recurse) | 687 | if (recurse) |
704 | mnt = copy_tree(old_nd.mnt, old_nd.dentry); | 688 | mnt = copy_tree(old_nd.mnt, old_nd.dentry, 0); |
705 | else | 689 | else |
706 | mnt = clone_mnt(old_nd.mnt, old_nd.dentry); | 690 | mnt = clone_mnt(old_nd.mnt, old_nd.dentry, 0); |
707 | 691 | ||
708 | if (!mnt) | 692 | if (!mnt) |
709 | goto out; | 693 | goto out; |
710 | 694 | ||
711 | /* stop bind mounts from expiring */ | ||
712 | spin_lock(&vfsmount_lock); | ||
713 | list_del_init(&mnt->mnt_expire); | ||
714 | spin_unlock(&vfsmount_lock); | ||
715 | |||
716 | err = graft_tree(mnt, nd); | 695 | err = graft_tree(mnt, nd); |
717 | if (err) { | 696 | if (err) { |
718 | LIST_HEAD(umount_list); | 697 | LIST_HEAD(umount_list); |
@@ -1155,7 +1134,8 @@ int copy_namespace(int flags, struct task_struct *tsk) | |||
1155 | 1134 | ||
1156 | down_write(&tsk->namespace->sem); | 1135 | down_write(&tsk->namespace->sem); |
1157 | /* First pass: copy the tree topology */ | 1136 | /* First pass: copy the tree topology */ |
1158 | new_ns->root = copy_tree(namespace->root, namespace->root->mnt_root); | 1137 | new_ns->root = copy_tree(namespace->root, namespace->root->mnt_root, |
1138 | CL_EXPIRE); | ||
1159 | if (!new_ns->root) { | 1139 | if (!new_ns->root) { |
1160 | up_write(&tsk->namespace->sem); | 1140 | up_write(&tsk->namespace->sem); |
1161 | kfree(new_ns); | 1141 | kfree(new_ns); |