diff options
Diffstat (limited to 'fs/namespace.c')
| -rw-r--r-- | fs/namespace.c | 142 |
1 files changed, 74 insertions, 68 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 208c079e9fdb..2fa9fdf7d6f5 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -40,7 +40,7 @@ static inline int sysfs_init(void) | |||
| 40 | __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); | 40 | __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); |
| 41 | 41 | ||
| 42 | static struct list_head *mount_hashtable; | 42 | static struct list_head *mount_hashtable; |
| 43 | static int hash_mask, hash_bits; | 43 | static int hash_mask __read_mostly, hash_bits __read_mostly; |
| 44 | static kmem_cache_t *mnt_cache; | 44 | static kmem_cache_t *mnt_cache; |
| 45 | 45 | ||
| 46 | static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) | 46 | static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) |
| @@ -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); |
| @@ -160,13 +160,13 @@ clone_mnt(struct vfsmount *old, struct dentry *root) | |||
| 160 | mnt->mnt_root = dget(root); | 160 | mnt->mnt_root = dget(root); |
| 161 | mnt->mnt_mountpoint = mnt->mnt_root; | 161 | mnt->mnt_mountpoint = mnt->mnt_root; |
| 162 | mnt->mnt_parent = mnt; | 162 | mnt->mnt_parent = mnt; |
| 163 | mnt->mnt_namespace = old->mnt_namespace; | 163 | mnt->mnt_namespace = current->namespace; |
| 164 | 164 | ||
| 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 { |
| @@ -536,7 +537,6 @@ lives_below_in_same_fs(struct dentry *d, struct dentry *dentry) | |||
| 536 | static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry) | 537 | static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry) |
| 537 | { | 538 | { |
| 538 | struct vfsmount *res, *p, *q, *r, *s; | 539 | struct vfsmount *res, *p, *q, *r, *s; |
| 539 | struct list_head *h; | ||
| 540 | struct nameidata nd; | 540 | struct nameidata nd; |
| 541 | 541 | ||
| 542 | res = q = clone_mnt(mnt, dentry); | 542 | res = q = clone_mnt(mnt, dentry); |
| @@ -545,8 +545,7 @@ static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry) | |||
| 545 | q->mnt_mountpoint = mnt->mnt_mountpoint; | 545 | q->mnt_mountpoint = mnt->mnt_mountpoint; |
| 546 | 546 | ||
| 547 | p = mnt; | 547 | p = mnt; |
| 548 | for (h = mnt->mnt_mounts.next; h != &mnt->mnt_mounts; h = h->next) { | 548 | list_for_each_entry(r, &mnt->mnt_mounts, mnt_child) { |
| 549 | r = list_entry(h, struct vfsmount, mnt_child); | ||
| 550 | if (!lives_below_in_same_fs(r->mnt_mountpoint, dentry)) | 549 | if (!lives_below_in_same_fs(r->mnt_mountpoint, dentry)) |
| 551 | continue; | 550 | continue; |
| 552 | 551 | ||
| @@ -644,7 +643,7 @@ static int do_loopback(struct nameidata *nd, char *old_name, int recurse) | |||
| 644 | if (mnt) { | 643 | if (mnt) { |
| 645 | /* stop bind mounts from expiring */ | 644 | /* stop bind mounts from expiring */ |
| 646 | spin_lock(&vfsmount_lock); | 645 | spin_lock(&vfsmount_lock); |
| 647 | list_del_init(&mnt->mnt_fslink); | 646 | list_del_init(&mnt->mnt_expire); |
| 648 | spin_unlock(&vfsmount_lock); | 647 | spin_unlock(&vfsmount_lock); |
| 649 | 648 | ||
| 650 | err = graft_tree(mnt, nd); | 649 | err = graft_tree(mnt, nd); |
| @@ -743,7 +742,7 @@ static int do_move_mount(struct nameidata *nd, char *old_name) | |||
| 743 | 742 | ||
| 744 | /* if the mount is moved, it should no longer be expire | 743 | /* if the mount is moved, it should no longer be expire |
| 745 | * automatically */ | 744 | * automatically */ |
| 746 | list_del_init(&old_nd.mnt->mnt_fslink); | 745 | list_del_init(&old_nd.mnt->mnt_expire); |
| 747 | out2: | 746 | out2: |
| 748 | spin_unlock(&vfsmount_lock); | 747 | spin_unlock(&vfsmount_lock); |
| 749 | out1: | 748 | out1: |
| @@ -807,12 +806,13 @@ int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd, | |||
| 807 | goto unlock; | 806 | goto unlock; |
| 808 | 807 | ||
| 809 | newmnt->mnt_flags = mnt_flags; | 808 | newmnt->mnt_flags = mnt_flags; |
| 809 | newmnt->mnt_namespace = current->namespace; | ||
| 810 | err = graft_tree(newmnt, nd); | 810 | err = graft_tree(newmnt, nd); |
| 811 | 811 | ||
| 812 | if (err == 0 && fslist) { | 812 | if (err == 0 && fslist) { |
| 813 | /* add to the specified expiration list */ | 813 | /* add to the specified expiration list */ |
| 814 | spin_lock(&vfsmount_lock); | 814 | spin_lock(&vfsmount_lock); |
| 815 | list_add_tail(&newmnt->mnt_fslink, fslist); | 815 | list_add_tail(&newmnt->mnt_expire, fslist); |
| 816 | spin_unlock(&vfsmount_lock); | 816 | spin_unlock(&vfsmount_lock); |
| 817 | } | 817 | } |
| 818 | 818 | ||
| @@ -824,6 +824,54 @@ unlock: | |||
| 824 | 824 | ||
| 825 | EXPORT_SYMBOL_GPL(do_add_mount); | 825 | EXPORT_SYMBOL_GPL(do_add_mount); |
| 826 | 826 | ||
| 827 | static void expire_mount(struct vfsmount *mnt, struct list_head *mounts) | ||
| 828 | { | ||
| 829 | spin_lock(&vfsmount_lock); | ||
| 830 | |||
| 831 | /* | ||
| 832 | * Check if mount is still attached, if not, let whoever holds it deal | ||
| 833 | * with the sucker | ||
| 834 | */ | ||
| 835 | if (mnt->mnt_parent == mnt) { | ||
| 836 | spin_unlock(&vfsmount_lock); | ||
| 837 | return; | ||
| 838 | } | ||
| 839 | |||
| 840 | /* | ||
| 841 | * Check that it is still dead: the count should now be 2 - as | ||
| 842 | * contributed by the vfsmount parent and the mntget above | ||
| 843 | */ | ||
| 844 | if (atomic_read(&mnt->mnt_count) == 2) { | ||
| 845 | struct nameidata old_nd; | ||
| 846 | |||
| 847 | /* delete from the namespace */ | ||
| 848 | list_del_init(&mnt->mnt_list); | ||
| 849 | mnt->mnt_namespace = NULL; | ||
| 850 | detach_mnt(mnt, &old_nd); | ||
| 851 | spin_unlock(&vfsmount_lock); | ||
| 852 | path_release(&old_nd); | ||
| 853 | |||
| 854 | /* | ||
| 855 | * Now lay it to rest if this was the last ref on the superblock | ||
| 856 | */ | ||
| 857 | if (atomic_read(&mnt->mnt_sb->s_active) == 1) { | ||
| 858 | /* last instance - try to be smart */ | ||
| 859 | lock_kernel(); | ||
| 860 | DQUOT_OFF(mnt->mnt_sb); | ||
| 861 | acct_auto_close(mnt->mnt_sb); | ||
| 862 | unlock_kernel(); | ||
| 863 | } | ||
| 864 | mntput(mnt); | ||
| 865 | } else { | ||
| 866 | /* | ||
| 867 | * Someone brought it back to life whilst we didn't have any | ||
| 868 | * locks held so return it to the expiration list | ||
| 869 | */ | ||
| 870 | list_add_tail(&mnt->mnt_expire, mounts); | ||
| 871 | spin_unlock(&vfsmount_lock); | ||
| 872 | } | ||
| 873 | } | ||
| 874 | |||
| 827 | /* | 875 | /* |
| 828 | * process a list of expirable mountpoints with the intent of discarding any | 876 | * 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 | 877 | * mountpoints that aren't in use and haven't been touched since last we came |
| @@ -846,13 +894,13 @@ void mark_mounts_for_expiry(struct list_head *mounts) | |||
| 846 | * - still marked for expiry (marked on the last call here; marks are | 894 | * - still marked for expiry (marked on the last call here; marks are |
| 847 | * cleared by mntput()) | 895 | * cleared by mntput()) |
| 848 | */ | 896 | */ |
| 849 | list_for_each_entry_safe(mnt, next, mounts, mnt_fslink) { | 897 | list_for_each_entry_safe(mnt, next, mounts, mnt_expire) { |
| 850 | if (!xchg(&mnt->mnt_expiry_mark, 1) || | 898 | if (!xchg(&mnt->mnt_expiry_mark, 1) || |
| 851 | atomic_read(&mnt->mnt_count) != 1) | 899 | atomic_read(&mnt->mnt_count) != 1) |
| 852 | continue; | 900 | continue; |
| 853 | 901 | ||
| 854 | mntget(mnt); | 902 | mntget(mnt); |
| 855 | list_move(&mnt->mnt_fslink, &graveyard); | 903 | list_move(&mnt->mnt_expire, &graveyard); |
| 856 | } | 904 | } |
| 857 | 905 | ||
| 858 | /* | 906 | /* |
| @@ -862,61 +910,19 @@ void mark_mounts_for_expiry(struct list_head *mounts) | |||
| 862 | * - dispose of the corpse | 910 | * - dispose of the corpse |
| 863 | */ | 911 | */ |
| 864 | while (!list_empty(&graveyard)) { | 912 | while (!list_empty(&graveyard)) { |
| 865 | mnt = list_entry(graveyard.next, struct vfsmount, mnt_fslink); | 913 | mnt = list_entry(graveyard.next, struct vfsmount, mnt_expire); |
| 866 | list_del_init(&mnt->mnt_fslink); | 914 | list_del_init(&mnt->mnt_expire); |
| 867 | 915 | ||
| 868 | /* don't do anything if the namespace is dead - all the | 916 | /* don't do anything if the namespace is dead - all the |
| 869 | * vfsmounts from it are going away anyway */ | 917 | * vfsmounts from it are going away anyway */ |
| 870 | namespace = mnt->mnt_namespace; | 918 | namespace = mnt->mnt_namespace; |
| 871 | if (!namespace || atomic_read(&namespace->count) <= 0) | 919 | if (!namespace || !namespace->root) |
| 872 | continue; | 920 | continue; |
| 873 | get_namespace(namespace); | 921 | get_namespace(namespace); |
| 874 | 922 | ||
| 875 | spin_unlock(&vfsmount_lock); | 923 | spin_unlock(&vfsmount_lock); |
| 876 | down_write(&namespace->sem); | 924 | down_write(&namespace->sem); |
| 877 | spin_lock(&vfsmount_lock); | 925 | 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); | 926 | up_write(&namespace->sem); |
| 921 | 927 | ||
| 922 | mntput(mnt); | 928 | mntput(mnt); |
| @@ -1326,8 +1332,12 @@ asmlinkage long sys_pivot_root(const char __user *new_root, const char __user *p | |||
| 1326 | error = -EINVAL; | 1332 | error = -EINVAL; |
| 1327 | if (user_nd.mnt->mnt_root != user_nd.dentry) | 1333 | if (user_nd.mnt->mnt_root != user_nd.dentry) |
| 1328 | goto out2; /* not a mountpoint */ | 1334 | goto out2; /* not a mountpoint */ |
| 1335 | if (user_nd.mnt->mnt_parent == user_nd.mnt) | ||
| 1336 | goto out2; /* not attached */ | ||
| 1329 | if (new_nd.mnt->mnt_root != new_nd.dentry) | 1337 | if (new_nd.mnt->mnt_root != new_nd.dentry) |
| 1330 | goto out2; /* not a mountpoint */ | 1338 | goto out2; /* not a mountpoint */ |
| 1339 | if (new_nd.mnt->mnt_parent == new_nd.mnt) | ||
| 1340 | goto out2; /* not attached */ | ||
| 1331 | tmp = old_nd.mnt; /* make sure we can reach put_old from new_root */ | 1341 | tmp = old_nd.mnt; /* make sure we can reach put_old from new_root */ |
| 1332 | spin_lock(&vfsmount_lock); | 1342 | spin_lock(&vfsmount_lock); |
| 1333 | if (tmp != new_nd.mnt) { | 1343 | if (tmp != new_nd.mnt) { |
| @@ -1449,16 +1459,12 @@ void __init mnt_init(unsigned long mempages) | |||
| 1449 | 1459 | ||
| 1450 | void __put_namespace(struct namespace *namespace) | 1460 | void __put_namespace(struct namespace *namespace) |
| 1451 | { | 1461 | { |
| 1452 | struct vfsmount *mnt; | 1462 | struct vfsmount *root = namespace->root; |
| 1453 | 1463 | namespace->root = NULL; | |
| 1464 | spin_unlock(&vfsmount_lock); | ||
| 1454 | down_write(&namespace->sem); | 1465 | down_write(&namespace->sem); |
| 1455 | spin_lock(&vfsmount_lock); | 1466 | spin_lock(&vfsmount_lock); |
| 1456 | 1467 | 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); | 1468 | spin_unlock(&vfsmount_lock); |
| 1463 | up_write(&namespace->sem); | 1469 | up_write(&namespace->sem); |
| 1464 | kfree(namespace); | 1470 | kfree(namespace); |
