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