diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/namespace.c | 84 |
1 files changed, 51 insertions, 33 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index dfeeab964e84..c2ffa0f349fd 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -394,32 +394,45 @@ int may_umount(struct vfsmount *mnt) | |||
394 | 394 | ||
395 | EXPORT_SYMBOL(may_umount); | 395 | EXPORT_SYMBOL(may_umount); |
396 | 396 | ||
397 | static void umount_tree(struct vfsmount *mnt) | 397 | static void release_mounts(struct list_head *head) |
398 | { | ||
399 | struct vfsmount *mnt; | ||
400 | while(!list_empty(head)) { | ||
401 | mnt = list_entry(head->next, struct vfsmount, mnt_hash); | ||
402 | list_del_init(&mnt->mnt_hash); | ||
403 | if (mnt->mnt_parent != mnt) { | ||
404 | struct dentry *dentry; | ||
405 | struct vfsmount *m; | ||
406 | spin_lock(&vfsmount_lock); | ||
407 | dentry = mnt->mnt_mountpoint; | ||
408 | m = mnt->mnt_parent; | ||
409 | mnt->mnt_mountpoint = mnt->mnt_root; | ||
410 | mnt->mnt_parent = mnt; | ||
411 | spin_unlock(&vfsmount_lock); | ||
412 | dput(dentry); | ||
413 | mntput(m); | ||
414 | } | ||
415 | mntput(mnt); | ||
416 | } | ||
417 | } | ||
418 | |||
419 | static void umount_tree(struct vfsmount *mnt, struct list_head *kill) | ||
398 | { | 420 | { |
399 | struct vfsmount *p; | 421 | struct vfsmount *p; |
400 | LIST_HEAD(kill); | ||
401 | 422 | ||
402 | for (p = mnt; p; p = next_mnt(p, mnt)) { | 423 | for (p = mnt; p; p = next_mnt(p, mnt)) { |
403 | list_del(&p->mnt_list); | 424 | list_del(&p->mnt_hash); |
404 | list_add(&p->mnt_list, &kill); | 425 | list_add(&p->mnt_hash, kill); |
405 | __touch_namespace(p->mnt_namespace); | ||
406 | p->mnt_namespace = NULL; | ||
407 | } | 426 | } |
408 | 427 | ||
409 | while (!list_empty(&kill)) { | 428 | list_for_each_entry(p, kill, mnt_hash) { |
410 | mnt = list_entry(kill.next, struct vfsmount, mnt_list); | 429 | list_del_init(&p->mnt_expire); |
411 | list_del_init(&mnt->mnt_list); | 430 | list_del_init(&p->mnt_list); |
412 | list_del_init(&mnt->mnt_expire); | 431 | __touch_namespace(p->mnt_namespace); |
413 | if (mnt->mnt_parent == mnt) { | 432 | p->mnt_namespace = NULL; |
414 | spin_unlock(&vfsmount_lock); | 433 | list_del_init(&p->mnt_child); |
415 | } else { | 434 | if (p->mnt_parent != p) |
416 | struct nameidata old_nd; | 435 | mnt->mnt_mountpoint->d_mounted--; |
417 | detach_mnt(mnt, &old_nd); | ||
418 | spin_unlock(&vfsmount_lock); | ||
419 | path_release(&old_nd); | ||
420 | } | ||
421 | mntput(mnt); | ||
422 | spin_lock(&vfsmount_lock); | ||
423 | } | 436 | } |
424 | } | 437 | } |
425 | 438 | ||
@@ -427,6 +440,7 @@ static int do_umount(struct vfsmount *mnt, int flags) | |||
427 | { | 440 | { |
428 | struct super_block *sb = mnt->mnt_sb; | 441 | struct super_block *sb = mnt->mnt_sb; |
429 | int retval; | 442 | int retval; |
443 | LIST_HEAD(umount_list); | ||
430 | 444 | ||
431 | retval = security_sb_umount(mnt, flags); | 445 | retval = security_sb_umount(mnt, flags); |
432 | if (retval) | 446 | if (retval) |
@@ -497,13 +511,14 @@ static int do_umount(struct vfsmount *mnt, int flags) | |||
497 | retval = -EBUSY; | 511 | retval = -EBUSY; |
498 | if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) { | 512 | if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) { |
499 | if (!list_empty(&mnt->mnt_list)) | 513 | if (!list_empty(&mnt->mnt_list)) |
500 | umount_tree(mnt); | 514 | umount_tree(mnt, &umount_list); |
501 | retval = 0; | 515 | retval = 0; |
502 | } | 516 | } |
503 | spin_unlock(&vfsmount_lock); | 517 | spin_unlock(&vfsmount_lock); |
504 | if (retval) | 518 | if (retval) |
505 | security_sb_umount_busy(mnt); | 519 | security_sb_umount_busy(mnt); |
506 | up_write(¤t->namespace->sem); | 520 | up_write(¤t->namespace->sem); |
521 | release_mounts(&umount_list); | ||
507 | return retval; | 522 | return retval; |
508 | } | 523 | } |
509 | 524 | ||
@@ -616,9 +631,11 @@ static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry) | |||
616 | return res; | 631 | return res; |
617 | Enomem: | 632 | Enomem: |
618 | if (res) { | 633 | if (res) { |
634 | LIST_HEAD(umount_list); | ||
619 | spin_lock(&vfsmount_lock); | 635 | spin_lock(&vfsmount_lock); |
620 | umount_tree(res); | 636 | umount_tree(res, &umount_list); |
621 | spin_unlock(&vfsmount_lock); | 637 | spin_unlock(&vfsmount_lock); |
638 | release_mounts(&umount_list); | ||
622 | } | 639 | } |
623 | return NULL; | 640 | return NULL; |
624 | } | 641 | } |
@@ -698,9 +715,11 @@ static int do_loopback(struct nameidata *nd, char *old_name, int recurse) | |||
698 | 715 | ||
699 | err = graft_tree(mnt, nd); | 716 | err = graft_tree(mnt, nd); |
700 | if (err) { | 717 | if (err) { |
718 | LIST_HEAD(umount_list); | ||
701 | spin_lock(&vfsmount_lock); | 719 | spin_lock(&vfsmount_lock); |
702 | umount_tree(mnt); | 720 | umount_tree(mnt, &umount_list); |
703 | spin_unlock(&vfsmount_lock); | 721 | spin_unlock(&vfsmount_lock); |
722 | release_mounts(&umount_list); | ||
704 | } | 723 | } |
705 | 724 | ||
706 | out: | 725 | out: |
@@ -875,7 +894,8 @@ unlock: | |||
875 | 894 | ||
876 | EXPORT_SYMBOL_GPL(do_add_mount); | 895 | EXPORT_SYMBOL_GPL(do_add_mount); |
877 | 896 | ||
878 | static void expire_mount(struct vfsmount *mnt, struct list_head *mounts) | 897 | static void expire_mount(struct vfsmount *mnt, struct list_head *mounts, |
898 | struct list_head *umounts) | ||
879 | { | 899 | { |
880 | spin_lock(&vfsmount_lock); | 900 | spin_lock(&vfsmount_lock); |
881 | 901 | ||
@@ -893,16 +913,12 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts) | |||
893 | * contributed by the vfsmount parent and the mntget above | 913 | * contributed by the vfsmount parent and the mntget above |
894 | */ | 914 | */ |
895 | if (atomic_read(&mnt->mnt_count) == 2) { | 915 | if (atomic_read(&mnt->mnt_count) == 2) { |
896 | struct nameidata old_nd; | ||
897 | |||
898 | /* delete from the namespace */ | 916 | /* delete from the namespace */ |
899 | touch_namespace(mnt->mnt_namespace); | 917 | touch_namespace(mnt->mnt_namespace); |
900 | list_del_init(&mnt->mnt_list); | 918 | list_del_init(&mnt->mnt_list); |
901 | mnt->mnt_namespace = NULL; | 919 | mnt->mnt_namespace = NULL; |
902 | detach_mnt(mnt, &old_nd); | 920 | umount_tree(mnt, umounts); |
903 | spin_unlock(&vfsmount_lock); | 921 | spin_unlock(&vfsmount_lock); |
904 | path_release(&old_nd); | ||
905 | mntput(mnt); | ||
906 | } else { | 922 | } else { |
907 | /* | 923 | /* |
908 | * Someone brought it back to life whilst we didn't have any | 924 | * Someone brought it back to life whilst we didn't have any |
@@ -951,6 +967,7 @@ void mark_mounts_for_expiry(struct list_head *mounts) | |||
951 | * - dispose of the corpse | 967 | * - dispose of the corpse |
952 | */ | 968 | */ |
953 | while (!list_empty(&graveyard)) { | 969 | while (!list_empty(&graveyard)) { |
970 | LIST_HEAD(umounts); | ||
954 | mnt = list_entry(graveyard.next, struct vfsmount, mnt_expire); | 971 | mnt = list_entry(graveyard.next, struct vfsmount, mnt_expire); |
955 | list_del_init(&mnt->mnt_expire); | 972 | list_del_init(&mnt->mnt_expire); |
956 | 973 | ||
@@ -963,12 +980,11 @@ void mark_mounts_for_expiry(struct list_head *mounts) | |||
963 | 980 | ||
964 | spin_unlock(&vfsmount_lock); | 981 | spin_unlock(&vfsmount_lock); |
965 | down_write(&namespace->sem); | 982 | down_write(&namespace->sem); |
966 | expire_mount(mnt, mounts); | 983 | expire_mount(mnt, mounts, &umounts); |
967 | up_write(&namespace->sem); | 984 | up_write(&namespace->sem); |
968 | 985 | release_mounts(&umounts); | |
969 | mntput(mnt); | 986 | mntput(mnt); |
970 | put_namespace(namespace); | 987 | put_namespace(namespace); |
971 | |||
972 | spin_lock(&vfsmount_lock); | 988 | spin_lock(&vfsmount_lock); |
973 | } | 989 | } |
974 | 990 | ||
@@ -1508,12 +1524,14 @@ void __init mnt_init(unsigned long mempages) | |||
1508 | void __put_namespace(struct namespace *namespace) | 1524 | void __put_namespace(struct namespace *namespace) |
1509 | { | 1525 | { |
1510 | struct vfsmount *root = namespace->root; | 1526 | struct vfsmount *root = namespace->root; |
1527 | LIST_HEAD(umount_list); | ||
1511 | namespace->root = NULL; | 1528 | namespace->root = NULL; |
1512 | spin_unlock(&vfsmount_lock); | 1529 | spin_unlock(&vfsmount_lock); |
1513 | down_write(&namespace->sem); | 1530 | down_write(&namespace->sem); |
1514 | spin_lock(&vfsmount_lock); | 1531 | spin_lock(&vfsmount_lock); |
1515 | umount_tree(root); | 1532 | umount_tree(root, &umount_list); |
1516 | spin_unlock(&vfsmount_lock); | 1533 | spin_unlock(&vfsmount_lock); |
1517 | up_write(&namespace->sem); | 1534 | up_write(&namespace->sem); |
1535 | release_mounts(&umount_list); | ||
1518 | kfree(namespace); | 1536 | kfree(namespace); |
1519 | } | 1537 | } |