diff options
author | Jens Axboe <jens.axboe@oracle.com> | 2010-05-21 15:27:26 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2010-05-21 15:27:26 -0400 |
commit | ee9a3607fb03e804ddf624544105f4e34260c380 (patch) | |
tree | ce41b6e0fa10982a306f6c142a92dbf3c9961284 /fs/nfs/super.c | |
parent | b492e95be0ae672922f4734acf3f5d35c30be948 (diff) | |
parent | d515e86e639890b33a09390d062b0831664f04a2 (diff) |
Merge branch 'master' into for-2.6.35
Conflicts:
fs/ext3/fsync.c
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'fs/nfs/super.c')
-rw-r--r-- | fs/nfs/super.c | 150 |
1 files changed, 121 insertions, 29 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index e01637240eeb..2f8b1157daa2 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -141,7 +141,6 @@ static const match_table_t nfs_mount_option_tokens = { | |||
141 | { Opt_resvport, "resvport" }, | 141 | { Opt_resvport, "resvport" }, |
142 | { Opt_noresvport, "noresvport" }, | 142 | { Opt_noresvport, "noresvport" }, |
143 | { Opt_fscache, "fsc" }, | 143 | { Opt_fscache, "fsc" }, |
144 | { Opt_fscache_uniq, "fsc=%s" }, | ||
145 | { Opt_nofscache, "nofsc" }, | 144 | { Opt_nofscache, "nofsc" }, |
146 | 145 | ||
147 | { Opt_port, "port=%s" }, | 146 | { Opt_port, "port=%s" }, |
@@ -171,6 +170,7 @@ static const match_table_t nfs_mount_option_tokens = { | |||
171 | { Opt_mountaddr, "mountaddr=%s" }, | 170 | { Opt_mountaddr, "mountaddr=%s" }, |
172 | 171 | ||
173 | { Opt_lookupcache, "lookupcache=%s" }, | 172 | { Opt_lookupcache, "lookupcache=%s" }, |
173 | { Opt_fscache_uniq, "fsc=%s" }, | ||
174 | 174 | ||
175 | { Opt_err, NULL } | 175 | { Opt_err, NULL } |
176 | }; | 176 | }; |
@@ -423,15 +423,19 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
423 | unsigned char blockbits; | 423 | unsigned char blockbits; |
424 | unsigned long blockres; | 424 | unsigned long blockres; |
425 | struct nfs_fh *fh = NFS_FH(dentry->d_inode); | 425 | struct nfs_fh *fh = NFS_FH(dentry->d_inode); |
426 | struct nfs_fattr fattr; | 426 | struct nfs_fsstat res; |
427 | struct nfs_fsstat res = { | 427 | int error = -ENOMEM; |
428 | .fattr = &fattr, | 428 | |
429 | }; | 429 | res.fattr = nfs_alloc_fattr(); |
430 | int error; | 430 | if (res.fattr == NULL) |
431 | goto out_err; | ||
431 | 432 | ||
432 | error = server->nfs_client->rpc_ops->statfs(server, fh, &res); | 433 | error = server->nfs_client->rpc_ops->statfs(server, fh, &res); |
434 | |||
435 | nfs_free_fattr(res.fattr); | ||
433 | if (error < 0) | 436 | if (error < 0) |
434 | goto out_err; | 437 | goto out_err; |
438 | |||
435 | buf->f_type = NFS_SUPER_MAGIC; | 439 | buf->f_type = NFS_SUPER_MAGIC; |
436 | 440 | ||
437 | /* | 441 | /* |
@@ -1046,14 +1050,6 @@ static int nfs_parse_mount_options(char *raw, | |||
1046 | kfree(mnt->fscache_uniq); | 1050 | kfree(mnt->fscache_uniq); |
1047 | mnt->fscache_uniq = NULL; | 1051 | mnt->fscache_uniq = NULL; |
1048 | break; | 1052 | break; |
1049 | case Opt_fscache_uniq: | ||
1050 | string = match_strdup(args); | ||
1051 | if (!string) | ||
1052 | goto out_nomem; | ||
1053 | kfree(mnt->fscache_uniq); | ||
1054 | mnt->fscache_uniq = string; | ||
1055 | mnt->options |= NFS_OPTION_FSCACHE; | ||
1056 | break; | ||
1057 | 1053 | ||
1058 | /* | 1054 | /* |
1059 | * options that take numeric values | 1055 | * options that take numeric values |
@@ -1384,6 +1380,14 @@ static int nfs_parse_mount_options(char *raw, | |||
1384 | return 0; | 1380 | return 0; |
1385 | }; | 1381 | }; |
1386 | break; | 1382 | break; |
1383 | case Opt_fscache_uniq: | ||
1384 | string = match_strdup(args); | ||
1385 | if (string == NULL) | ||
1386 | goto out_nomem; | ||
1387 | kfree(mnt->fscache_uniq); | ||
1388 | mnt->fscache_uniq = string; | ||
1389 | mnt->options |= NFS_OPTION_FSCACHE; | ||
1390 | break; | ||
1387 | 1391 | ||
1388 | /* | 1392 | /* |
1389 | * Special options | 1393 | * Special options |
@@ -2172,7 +2176,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
2172 | int error = -ENOMEM; | 2176 | int error = -ENOMEM; |
2173 | 2177 | ||
2174 | data = nfs_alloc_parsed_mount_data(3); | 2178 | data = nfs_alloc_parsed_mount_data(3); |
2175 | mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL); | 2179 | mntfh = nfs_alloc_fhandle(); |
2176 | if (data == NULL || mntfh == NULL) | 2180 | if (data == NULL || mntfh == NULL) |
2177 | goto out_free_fh; | 2181 | goto out_free_fh; |
2178 | 2182 | ||
@@ -2187,6 +2191,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
2187 | if (data->version == 4) { | 2191 | if (data->version == 4) { |
2188 | error = nfs4_try_mount(flags, dev_name, data, mnt); | 2192 | error = nfs4_try_mount(flags, dev_name, data, mnt); |
2189 | kfree(data->client_address); | 2193 | kfree(data->client_address); |
2194 | kfree(data->nfs_server.export_path); | ||
2190 | goto out; | 2195 | goto out; |
2191 | } | 2196 | } |
2192 | #endif /* CONFIG_NFS_V4 */ | 2197 | #endif /* CONFIG_NFS_V4 */ |
@@ -2246,7 +2251,7 @@ out: | |||
2246 | kfree(data->fscache_uniq); | 2251 | kfree(data->fscache_uniq); |
2247 | security_free_mnt_opts(&data->lsm_opts); | 2252 | security_free_mnt_opts(&data->lsm_opts); |
2248 | out_free_fh: | 2253 | out_free_fh: |
2249 | kfree(mntfh); | 2254 | nfs_free_fhandle(mntfh); |
2250 | kfree(data); | 2255 | kfree(data); |
2251 | return error; | 2256 | return error; |
2252 | 2257 | ||
@@ -2555,7 +2560,7 @@ static int nfs4_remote_get_sb(struct file_system_type *fs_type, | |||
2555 | }; | 2560 | }; |
2556 | int error = -ENOMEM; | 2561 | int error = -ENOMEM; |
2557 | 2562 | ||
2558 | mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL); | 2563 | mntfh = nfs_alloc_fhandle(); |
2559 | if (data == NULL || mntfh == NULL) | 2564 | if (data == NULL || mntfh == NULL) |
2560 | goto out_free_fh; | 2565 | goto out_free_fh; |
2561 | 2566 | ||
@@ -2613,7 +2618,7 @@ static int nfs4_remote_get_sb(struct file_system_type *fs_type, | |||
2613 | out: | 2618 | out: |
2614 | security_free_mnt_opts(&data->lsm_opts); | 2619 | security_free_mnt_opts(&data->lsm_opts); |
2615 | out_free_fh: | 2620 | out_free_fh: |
2616 | kfree(mntfh); | 2621 | nfs_free_fhandle(mntfh); |
2617 | return error; | 2622 | return error; |
2618 | 2623 | ||
2619 | out_free: | 2624 | out_free: |
@@ -2657,7 +2662,7 @@ static void nfs_fix_devname(const struct path *path, struct vfsmount *mnt) | |||
2657 | devname = nfs_path(path->mnt->mnt_devname, | 2662 | devname = nfs_path(path->mnt->mnt_devname, |
2658 | path->mnt->mnt_root, path->dentry, | 2663 | path->mnt->mnt_root, path->dentry, |
2659 | page, PAGE_SIZE); | 2664 | page, PAGE_SIZE); |
2660 | if (devname == NULL) | 2665 | if (IS_ERR(devname)) |
2661 | goto out_freepage; | 2666 | goto out_freepage; |
2662 | tmp = kstrdup(devname, GFP_KERNEL); | 2667 | tmp = kstrdup(devname, GFP_KERNEL); |
2663 | if (tmp == NULL) | 2668 | if (tmp == NULL) |
@@ -2668,41 +2673,120 @@ out_freepage: | |||
2668 | free_page((unsigned long)page); | 2673 | free_page((unsigned long)page); |
2669 | } | 2674 | } |
2670 | 2675 | ||
2676 | struct nfs_referral_count { | ||
2677 | struct list_head list; | ||
2678 | const struct task_struct *task; | ||
2679 | unsigned int referral_count; | ||
2680 | }; | ||
2681 | |||
2682 | static LIST_HEAD(nfs_referral_count_list); | ||
2683 | static DEFINE_SPINLOCK(nfs_referral_count_list_lock); | ||
2684 | |||
2685 | static struct nfs_referral_count *nfs_find_referral_count(void) | ||
2686 | { | ||
2687 | struct nfs_referral_count *p; | ||
2688 | |||
2689 | list_for_each_entry(p, &nfs_referral_count_list, list) { | ||
2690 | if (p->task == current) | ||
2691 | return p; | ||
2692 | } | ||
2693 | return NULL; | ||
2694 | } | ||
2695 | |||
2696 | #define NFS_MAX_NESTED_REFERRALS 2 | ||
2697 | |||
2698 | static int nfs_referral_loop_protect(void) | ||
2699 | { | ||
2700 | struct nfs_referral_count *p, *new; | ||
2701 | int ret = -ENOMEM; | ||
2702 | |||
2703 | new = kmalloc(sizeof(*new), GFP_KERNEL); | ||
2704 | if (!new) | ||
2705 | goto out; | ||
2706 | new->task = current; | ||
2707 | new->referral_count = 1; | ||
2708 | |||
2709 | ret = 0; | ||
2710 | spin_lock(&nfs_referral_count_list_lock); | ||
2711 | p = nfs_find_referral_count(); | ||
2712 | if (p != NULL) { | ||
2713 | if (p->referral_count >= NFS_MAX_NESTED_REFERRALS) | ||
2714 | ret = -ELOOP; | ||
2715 | else | ||
2716 | p->referral_count++; | ||
2717 | } else { | ||
2718 | list_add(&new->list, &nfs_referral_count_list); | ||
2719 | new = NULL; | ||
2720 | } | ||
2721 | spin_unlock(&nfs_referral_count_list_lock); | ||
2722 | kfree(new); | ||
2723 | out: | ||
2724 | return ret; | ||
2725 | } | ||
2726 | |||
2727 | static void nfs_referral_loop_unprotect(void) | ||
2728 | { | ||
2729 | struct nfs_referral_count *p; | ||
2730 | |||
2731 | spin_lock(&nfs_referral_count_list_lock); | ||
2732 | p = nfs_find_referral_count(); | ||
2733 | p->referral_count--; | ||
2734 | if (p->referral_count == 0) | ||
2735 | list_del(&p->list); | ||
2736 | else | ||
2737 | p = NULL; | ||
2738 | spin_unlock(&nfs_referral_count_list_lock); | ||
2739 | kfree(p); | ||
2740 | } | ||
2741 | |||
2671 | static int nfs_follow_remote_path(struct vfsmount *root_mnt, | 2742 | static int nfs_follow_remote_path(struct vfsmount *root_mnt, |
2672 | const char *export_path, struct vfsmount *mnt_target) | 2743 | const char *export_path, struct vfsmount *mnt_target) |
2673 | { | 2744 | { |
2745 | struct nameidata *nd = NULL; | ||
2674 | struct mnt_namespace *ns_private; | 2746 | struct mnt_namespace *ns_private; |
2675 | struct nameidata nd; | ||
2676 | struct super_block *s; | 2747 | struct super_block *s; |
2677 | int ret; | 2748 | int ret; |
2678 | 2749 | ||
2750 | nd = kmalloc(sizeof(*nd), GFP_KERNEL); | ||
2751 | if (nd == NULL) | ||
2752 | return -ENOMEM; | ||
2753 | |||
2679 | ns_private = create_mnt_ns(root_mnt); | 2754 | ns_private = create_mnt_ns(root_mnt); |
2680 | ret = PTR_ERR(ns_private); | 2755 | ret = PTR_ERR(ns_private); |
2681 | if (IS_ERR(ns_private)) | 2756 | if (IS_ERR(ns_private)) |
2682 | goto out_mntput; | 2757 | goto out_mntput; |
2683 | 2758 | ||
2759 | ret = nfs_referral_loop_protect(); | ||
2760 | if (ret != 0) | ||
2761 | goto out_put_mnt_ns; | ||
2762 | |||
2684 | ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt, | 2763 | ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt, |
2685 | export_path, LOOKUP_FOLLOW, &nd); | 2764 | export_path, LOOKUP_FOLLOW, nd); |
2686 | 2765 | ||
2766 | nfs_referral_loop_unprotect(); | ||
2687 | put_mnt_ns(ns_private); | 2767 | put_mnt_ns(ns_private); |
2688 | 2768 | ||
2689 | if (ret != 0) | 2769 | if (ret != 0) |
2690 | goto out_err; | 2770 | goto out_err; |
2691 | 2771 | ||
2692 | s = nd.path.mnt->mnt_sb; | 2772 | s = nd->path.mnt->mnt_sb; |
2693 | atomic_inc(&s->s_active); | 2773 | atomic_inc(&s->s_active); |
2694 | mnt_target->mnt_sb = s; | 2774 | mnt_target->mnt_sb = s; |
2695 | mnt_target->mnt_root = dget(nd.path.dentry); | 2775 | mnt_target->mnt_root = dget(nd->path.dentry); |
2696 | 2776 | ||
2697 | /* Correct the device pathname */ | 2777 | /* Correct the device pathname */ |
2698 | nfs_fix_devname(&nd.path, mnt_target); | 2778 | nfs_fix_devname(&nd->path, mnt_target); |
2699 | 2779 | ||
2700 | path_put(&nd.path); | 2780 | path_put(&nd->path); |
2781 | kfree(nd); | ||
2701 | down_write(&s->s_umount); | 2782 | down_write(&s->s_umount); |
2702 | return 0; | 2783 | return 0; |
2784 | out_put_mnt_ns: | ||
2785 | put_mnt_ns(ns_private); | ||
2703 | out_mntput: | 2786 | out_mntput: |
2704 | mntput(root_mnt); | 2787 | mntput(root_mnt); |
2705 | out_err: | 2788 | out_err: |
2789 | kfree(nd); | ||
2706 | return ret; | 2790 | return ret; |
2707 | } | 2791 | } |
2708 | 2792 | ||
@@ -2873,17 +2957,21 @@ static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, | |||
2873 | struct super_block *s; | 2957 | struct super_block *s; |
2874 | struct nfs_server *server; | 2958 | struct nfs_server *server; |
2875 | struct dentry *mntroot; | 2959 | struct dentry *mntroot; |
2876 | struct nfs_fh mntfh; | 2960 | struct nfs_fh *mntfh; |
2877 | int (*compare_super)(struct super_block *, void *) = nfs_compare_super; | 2961 | int (*compare_super)(struct super_block *, void *) = nfs_compare_super; |
2878 | struct nfs_sb_mountdata sb_mntdata = { | 2962 | struct nfs_sb_mountdata sb_mntdata = { |
2879 | .mntflags = flags, | 2963 | .mntflags = flags, |
2880 | }; | 2964 | }; |
2881 | int error; | 2965 | int error = -ENOMEM; |
2882 | 2966 | ||
2883 | dprintk("--> nfs4_referral_get_sb()\n"); | 2967 | dprintk("--> nfs4_referral_get_sb()\n"); |
2884 | 2968 | ||
2969 | mntfh = nfs_alloc_fhandle(); | ||
2970 | if (mntfh == NULL) | ||
2971 | goto out_err_nofh; | ||
2972 | |||
2885 | /* create a new volume representation */ | 2973 | /* create a new volume representation */ |
2886 | server = nfs4_create_referral_server(data, &mntfh); | 2974 | server = nfs4_create_referral_server(data, mntfh); |
2887 | if (IS_ERR(server)) { | 2975 | if (IS_ERR(server)) { |
2888 | error = PTR_ERR(server); | 2976 | error = PTR_ERR(server); |
2889 | goto out_err_noserver; | 2977 | goto out_err_noserver; |
@@ -2915,7 +3003,7 @@ static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, | |||
2915 | nfs_fscache_get_super_cookie(s, NULL, data); | 3003 | nfs_fscache_get_super_cookie(s, NULL, data); |
2916 | } | 3004 | } |
2917 | 3005 | ||
2918 | mntroot = nfs4_get_root(s, &mntfh); | 3006 | mntroot = nfs4_get_root(s, mntfh); |
2919 | if (IS_ERR(mntroot)) { | 3007 | if (IS_ERR(mntroot)) { |
2920 | error = PTR_ERR(mntroot); | 3008 | error = PTR_ERR(mntroot); |
2921 | goto error_splat_super; | 3009 | goto error_splat_super; |
@@ -2932,12 +3020,15 @@ static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, | |||
2932 | 3020 | ||
2933 | security_sb_clone_mnt_opts(data->sb, s); | 3021 | security_sb_clone_mnt_opts(data->sb, s); |
2934 | 3022 | ||
3023 | nfs_free_fhandle(mntfh); | ||
2935 | dprintk("<-- nfs4_referral_get_sb() = 0\n"); | 3024 | dprintk("<-- nfs4_referral_get_sb() = 0\n"); |
2936 | return 0; | 3025 | return 0; |
2937 | 3026 | ||
2938 | out_err_nosb: | 3027 | out_err_nosb: |
2939 | nfs_free_server(server); | 3028 | nfs_free_server(server); |
2940 | out_err_noserver: | 3029 | out_err_noserver: |
3030 | nfs_free_fhandle(mntfh); | ||
3031 | out_err_nofh: | ||
2941 | dprintk("<-- nfs4_referral_get_sb() = %d [error]\n", error); | 3032 | dprintk("<-- nfs4_referral_get_sb() = %d [error]\n", error); |
2942 | return error; | 3033 | return error; |
2943 | 3034 | ||
@@ -2946,6 +3037,7 @@ error_splat_super: | |||
2946 | bdi_unregister(&server->backing_dev_info); | 3037 | bdi_unregister(&server->backing_dev_info); |
2947 | error_splat_bdi: | 3038 | error_splat_bdi: |
2948 | deactivate_locked_super(s); | 3039 | deactivate_locked_super(s); |
3040 | nfs_free_fhandle(mntfh); | ||
2949 | dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error); | 3041 | dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error); |
2950 | return error; | 3042 | return error; |
2951 | } | 3043 | } |