diff options
Diffstat (limited to 'fs/namespace.c')
| -rw-r--r-- | fs/namespace.c | 130 |
1 files changed, 67 insertions, 63 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 208c079e9fdb..587eb0d707ee 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -61,7 +61,7 @@ struct vfsmount *alloc_vfsmnt(const char *name) | |||
| 61 | INIT_LIST_HEAD(&mnt->mnt_child); | 61 | INIT_LIST_HEAD(&mnt->mnt_child); |
| 62 | INIT_LIST_HEAD(&mnt->mnt_mounts); | 62 | INIT_LIST_HEAD(&mnt->mnt_mounts); |
| 63 | INIT_LIST_HEAD(&mnt->mnt_list); | 63 | INIT_LIST_HEAD(&mnt->mnt_list); |
| 64 | INIT_LIST_HEAD(&mnt->mnt_fslink); | 64 | INIT_LIST_HEAD(&mnt->mnt_expire); |
| 65 | if (name) { | 65 | if (name) { |
| 66 | int size = strlen(name)+1; | 66 | int size = strlen(name)+1; |
| 67 | char *newname = kmalloc(size, GFP_KERNEL); | 67 | char *newname = kmalloc(size, GFP_KERNEL); |
| @@ -165,8 +165,8 @@ clone_mnt(struct vfsmount *old, struct dentry *root) | |||
| 165 | /* stick the duplicate mount on the same expiry list | 165 | /* stick the duplicate mount on the same expiry list |
| 166 | * as the original if that was on one */ | 166 | * as the original if that was on one */ |
| 167 | spin_lock(&vfsmount_lock); | 167 | spin_lock(&vfsmount_lock); |
| 168 | if (!list_empty(&old->mnt_fslink)) | 168 | if (!list_empty(&old->mnt_expire)) |
| 169 | list_add(&mnt->mnt_fslink, &old->mnt_fslink); | 169 | list_add(&mnt->mnt_expire, &old->mnt_expire); |
| 170 | spin_unlock(&vfsmount_lock); | 170 | spin_unlock(&vfsmount_lock); |
| 171 | } | 171 | } |
| 172 | return mnt; | 172 | return mnt; |
| @@ -345,12 +345,13 @@ static void umount_tree(struct vfsmount *mnt) | |||
| 345 | for (p = mnt; p; p = next_mnt(p, mnt)) { | 345 | for (p = mnt; p; p = next_mnt(p, mnt)) { |
| 346 | list_del(&p->mnt_list); | 346 | list_del(&p->mnt_list); |
| 347 | list_add(&p->mnt_list, &kill); | 347 | list_add(&p->mnt_list, &kill); |
| 348 | p->mnt_namespace = NULL; | ||
| 348 | } | 349 | } |
| 349 | 350 | ||
| 350 | while (!list_empty(&kill)) { | 351 | while (!list_empty(&kill)) { |
| 351 | mnt = list_entry(kill.next, struct vfsmount, mnt_list); | 352 | mnt = list_entry(kill.next, struct vfsmount, mnt_list); |
| 352 | list_del_init(&mnt->mnt_list); | 353 | list_del_init(&mnt->mnt_list); |
| 353 | list_del_init(&mnt->mnt_fslink); | 354 | list_del_init(&mnt->mnt_expire); |
| 354 | if (mnt->mnt_parent == mnt) { | 355 | if (mnt->mnt_parent == mnt) { |
| 355 | spin_unlock(&vfsmount_lock); | 356 | spin_unlock(&vfsmount_lock); |
| 356 | } else { | 357 | } else { |
| @@ -644,7 +645,7 @@ static int do_loopback(struct nameidata *nd, char *old_name, int recurse) | |||
| 644 | if (mnt) { | 645 | if (mnt) { |
| 645 | /* stop bind mounts from expiring */ | 646 | /* stop bind mounts from expiring */ |
| 646 | spin_lock(&vfsmount_lock); | 647 | spin_lock(&vfsmount_lock); |
| 647 | list_del_init(&mnt->mnt_fslink); | 648 | list_del_init(&mnt->mnt_expire); |
| 648 | spin_unlock(&vfsmount_lock); | 649 | spin_unlock(&vfsmount_lock); |
| 649 | 650 | ||
| 650 | err = graft_tree(mnt, nd); | 651 | err = graft_tree(mnt, nd); |
| @@ -743,7 +744,7 @@ static int do_move_mount(struct nameidata *nd, char *old_name) | |||
| 743 | 744 | ||
| 744 | /* if the mount is moved, it should no longer be expire | 745 | /* if the mount is moved, it should no longer be expire |
| 745 | * automatically */ | 746 | * automatically */ |
| 746 | list_del_init(&old_nd.mnt->mnt_fslink); | 747 | list_del_init(&old_nd.mnt->mnt_expire); |
| 747 | out2: | 748 | out2: |
| 748 | spin_unlock(&vfsmount_lock); | 749 | spin_unlock(&vfsmount_lock); |
| 749 | out1: | 750 | out1: |
| @@ -807,12 +808,13 @@ int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd, | |||
| 807 | goto unlock; | 808 | goto unlock; |
| 808 | 809 | ||
| 809 | newmnt->mnt_flags = mnt_flags; | 810 | newmnt->mnt_flags = mnt_flags; |
| 811 | newmnt->mnt_namespace = current->namespace; | ||
| 810 | err = graft_tree(newmnt, nd); | 812 | err = graft_tree(newmnt, nd); |
| 811 | 813 | ||
| 812 | if (err == 0 && fslist) { | 814 | if (err == 0 && fslist) { |
| 813 | /* add to the specified expiration list */ | 815 | /* add to the specified expiration list */ |
| 814 | spin_lock(&vfsmount_lock); | 816 | spin_lock(&vfsmount_lock); |
| 815 | list_add_tail(&newmnt->mnt_fslink, fslist); | 817 | list_add_tail(&newmnt->mnt_expire, fslist); |
| 816 | spin_unlock(&vfsmount_lock); | 818 | spin_unlock(&vfsmount_lock); |
| 817 | } | 819 | } |
| 818 | 820 | ||
| @@ -824,6 +826,54 @@ unlock: | |||
| 824 | 826 | ||
| 825 | EXPORT_SYMBOL_GPL(do_add_mount); | 827 | EXPORT_SYMBOL_GPL(do_add_mount); |
| 826 | 828 | ||
| 829 | static void expire_mount(struct vfsmount *mnt, struct list_head *mounts) | ||
| 830 | { | ||
| 831 | spin_lock(&vfsmount_lock); | ||
| 832 | |||
| 833 | /* | ||
| 834 | * Check if mount is still attached, if not, let whoever holds it deal | ||
| 835 | * with the sucker | ||
| 836 | */ | ||
| 837 | if (mnt->mnt_parent == mnt) { | ||
| 838 | spin_unlock(&vfsmount_lock); | ||
| 839 | return; | ||
| 840 | } | ||
| 841 | |||
| 842 | /* | ||
| 843 | * Check that it is still dead: the count should now be 2 - as | ||
| 844 | * contributed by the vfsmount parent and the mntget above | ||
| 845 | */ | ||
| 846 | if (atomic_read(&mnt->mnt_count) == 2) { | ||
| 847 | struct nameidata old_nd; | ||
| 848 | |||
| 849 | /* delete from the namespace */ | ||
| 850 | list_del_init(&mnt->mnt_list); | ||
| 851 | mnt->mnt_namespace = NULL; | ||
| 852 | detach_mnt(mnt, &old_nd); | ||
| 853 | spin_unlock(&vfsmount_lock); | ||
| 854 | path_release(&old_nd); | ||
| 855 | |||
| 856 | /* | ||
| 857 | * Now lay it to rest if this was the last ref on the superblock | ||
| 858 | */ | ||
| 859 | if (atomic_read(&mnt->mnt_sb->s_active) == 1) { | ||
| 860 | /* last instance - try to be smart */ | ||
| 861 | lock_kernel(); | ||
| 862 | DQUOT_OFF(mnt->mnt_sb); | ||
| 863 | acct_auto_close(mnt->mnt_sb); | ||
| 864 | unlock_kernel(); | ||
| 865 | } | ||
| 866 | mntput(mnt); | ||
| 867 | } else { | ||
| 868 | /* | ||
| 869 | * Someone brought it back to life whilst we didn't have any | ||
| 870 | * locks held so return it to the expiration list | ||
| 871 | */ | ||
| 872 | list_add_tail(&mnt->mnt_expire, mounts); | ||
| 873 | spin_unlock(&vfsmount_lock); | ||
| 874 | } | ||
| 875 | } | ||
| 876 | |||
| 827 | /* | 877 | /* |
| 828 | * process a list of expirable mountpoints with the intent of discarding any | 878 | * process a list of expirable mountpoints with the intent of discarding any |
| 829 | * mountpoints that aren't in use and haven't been touched since last we came | 879 | * mountpoints that aren't in use and haven't been touched since last we came |
| @@ -846,13 +896,13 @@ void mark_mounts_for_expiry(struct list_head *mounts) | |||
| 846 | * - still marked for expiry (marked on the last call here; marks are | 896 | * - still marked for expiry (marked on the last call here; marks are |
| 847 | * cleared by mntput()) | 897 | * cleared by mntput()) |
| 848 | */ | 898 | */ |
| 849 | list_for_each_entry_safe(mnt, next, mounts, mnt_fslink) { | 899 | list_for_each_entry_safe(mnt, next, mounts, mnt_expire) { |
| 850 | if (!xchg(&mnt->mnt_expiry_mark, 1) || | 900 | if (!xchg(&mnt->mnt_expiry_mark, 1) || |
| 851 | atomic_read(&mnt->mnt_count) != 1) | 901 | atomic_read(&mnt->mnt_count) != 1) |
| 852 | continue; | 902 | continue; |
| 853 | 903 | ||
| 854 | mntget(mnt); | 904 | mntget(mnt); |
| 855 | list_move(&mnt->mnt_fslink, &graveyard); | 905 | list_move(&mnt->mnt_expire, &graveyard); |
| 856 | } | 906 | } |
| 857 | 907 | ||
| 858 | /* | 908 | /* |
| @@ -862,61 +912,19 @@ void mark_mounts_for_expiry(struct list_head *mounts) | |||
| 862 | * - dispose of the corpse | 912 | * - dispose of the corpse |
| 863 | */ | 913 | */ |
| 864 | while (!list_empty(&graveyard)) { | 914 | while (!list_empty(&graveyard)) { |
| 865 | mnt = list_entry(graveyard.next, struct vfsmount, mnt_fslink); | 915 | mnt = list_entry(graveyard.next, struct vfsmount, mnt_expire); |
| 866 | list_del_init(&mnt->mnt_fslink); | 916 | list_del_init(&mnt->mnt_expire); |
| 867 | 917 | ||
| 868 | /* don't do anything if the namespace is dead - all the | 918 | /* don't do anything if the namespace is dead - all the |
| 869 | * vfsmounts from it are going away anyway */ | 919 | * vfsmounts from it are going away anyway */ |
| 870 | namespace = mnt->mnt_namespace; | 920 | namespace = mnt->mnt_namespace; |
| 871 | if (!namespace || atomic_read(&namespace->count) <= 0) | 921 | if (!namespace || !namespace->root) |
| 872 | continue; | 922 | continue; |
| 873 | get_namespace(namespace); | 923 | get_namespace(namespace); |
| 874 | 924 | ||
| 875 | spin_unlock(&vfsmount_lock); | 925 | spin_unlock(&vfsmount_lock); |
| 876 | down_write(&namespace->sem); | 926 | down_write(&namespace->sem); |
| 877 | spin_lock(&vfsmount_lock); | 927 | expire_mount(mnt, mounts); |
| 878 | |||
| 879 | /* check that it is still dead: the count should now be 2 - as | ||
| 880 | * contributed by the vfsmount parent and the mntget above */ | ||
| 881 | if (atomic_read(&mnt->mnt_count) == 2) { | ||
| 882 | struct vfsmount *xdmnt; | ||
| 883 | struct dentry *xdentry; | ||
| 884 | |||
| 885 | /* delete from the namespace */ | ||
| 886 | list_del_init(&mnt->mnt_list); | ||
| 887 | list_del_init(&mnt->mnt_child); | ||
| 888 | list_del_init(&mnt->mnt_hash); | ||
| 889 | mnt->mnt_mountpoint->d_mounted--; | ||
| 890 | |||
| 891 | xdentry = mnt->mnt_mountpoint; | ||
| 892 | mnt->mnt_mountpoint = mnt->mnt_root; | ||
| 893 | xdmnt = mnt->mnt_parent; | ||
| 894 | mnt->mnt_parent = mnt; | ||
| 895 | |||
| 896 | spin_unlock(&vfsmount_lock); | ||
| 897 | |||
| 898 | mntput(xdmnt); | ||
| 899 | dput(xdentry); | ||
| 900 | |||
| 901 | /* now lay it to rest if this was the last ref on the | ||
| 902 | * superblock */ | ||
| 903 | if (atomic_read(&mnt->mnt_sb->s_active) == 1) { | ||
| 904 | /* last instance - try to be smart */ | ||
| 905 | lock_kernel(); | ||
| 906 | DQUOT_OFF(mnt->mnt_sb); | ||
| 907 | acct_auto_close(mnt->mnt_sb); | ||
| 908 | unlock_kernel(); | ||
| 909 | } | ||
| 910 | |||
| 911 | mntput(mnt); | ||
| 912 | } else { | ||
| 913 | /* someone brought it back to life whilst we didn't | ||
| 914 | * have any locks held so return it to the expiration | ||
| 915 | * list */ | ||
| 916 | list_add_tail(&mnt->mnt_fslink, mounts); | ||
| 917 | spin_unlock(&vfsmount_lock); | ||
| 918 | } | ||
| 919 | |||
| 920 | up_write(&namespace->sem); | 928 | up_write(&namespace->sem); |
| 921 | 929 | ||
| 922 | mntput(mnt); | 930 | mntput(mnt); |
| @@ -1449,16 +1457,12 @@ void __init mnt_init(unsigned long mempages) | |||
| 1449 | 1457 | ||
| 1450 | void __put_namespace(struct namespace *namespace) | 1458 | void __put_namespace(struct namespace *namespace) |
| 1451 | { | 1459 | { |
| 1452 | struct vfsmount *mnt; | 1460 | struct vfsmount *root = namespace->root; |
| 1453 | 1461 | namespace->root = NULL; | |
| 1462 | spin_unlock(&vfsmount_lock); | ||
| 1454 | down_write(&namespace->sem); | 1463 | down_write(&namespace->sem); |
| 1455 | spin_lock(&vfsmount_lock); | 1464 | spin_lock(&vfsmount_lock); |
| 1456 | 1465 | umount_tree(root); | |
| 1457 | list_for_each_entry(mnt, &namespace->list, mnt_list) { | ||
| 1458 | mnt->mnt_namespace = NULL; | ||
| 1459 | } | ||
| 1460 | |||
| 1461 | umount_tree(namespace->root); | ||
| 1462 | spin_unlock(&vfsmount_lock); | 1466 | spin_unlock(&vfsmount_lock); |
| 1463 | up_write(&namespace->sem); | 1467 | up_write(&namespace->sem); |
| 1464 | kfree(namespace); | 1468 | kfree(namespace); |
