diff options
| -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); |
