aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/super.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/super.c')
-rw-r--r--fs/nfs/super.c147
1 files changed, 119 insertions, 28 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index b4148fc00f9f..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
@@ -2247,7 +2251,7 @@ out:
2247 kfree(data->fscache_uniq); 2251 kfree(data->fscache_uniq);
2248 security_free_mnt_opts(&data->lsm_opts); 2252 security_free_mnt_opts(&data->lsm_opts);
2249out_free_fh: 2253out_free_fh:
2250 kfree(mntfh); 2254 nfs_free_fhandle(mntfh);
2251 kfree(data); 2255 kfree(data);
2252 return error; 2256 return error;
2253 2257
@@ -2556,7 +2560,7 @@ static int nfs4_remote_get_sb(struct file_system_type *fs_type,
2556 }; 2560 };
2557 int error = -ENOMEM; 2561 int error = -ENOMEM;
2558 2562
2559 mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL); 2563 mntfh = nfs_alloc_fhandle();
2560 if (data == NULL || mntfh == NULL) 2564 if (data == NULL || mntfh == NULL)
2561 goto out_free_fh; 2565 goto out_free_fh;
2562 2566
@@ -2614,7 +2618,7 @@ static int nfs4_remote_get_sb(struct file_system_type *fs_type,
2614out: 2618out:
2615 security_free_mnt_opts(&data->lsm_opts); 2619 security_free_mnt_opts(&data->lsm_opts);
2616out_free_fh: 2620out_free_fh:
2617 kfree(mntfh); 2621 nfs_free_fhandle(mntfh);
2618 return error; 2622 return error;
2619 2623
2620out_free: 2624out_free:
@@ -2669,41 +2673,120 @@ out_freepage:
2669 free_page((unsigned long)page); 2673 free_page((unsigned long)page);
2670} 2674}
2671 2675
2676struct nfs_referral_count {
2677 struct list_head list;
2678 const struct task_struct *task;
2679 unsigned int referral_count;
2680};
2681
2682static LIST_HEAD(nfs_referral_count_list);
2683static DEFINE_SPINLOCK(nfs_referral_count_list_lock);
2684
2685static 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
2698static 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);
2723out:
2724 return ret;
2725}
2726
2727static 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
2672static int nfs_follow_remote_path(struct vfsmount *root_mnt, 2742static int nfs_follow_remote_path(struct vfsmount *root_mnt,
2673 const char *export_path, struct vfsmount *mnt_target) 2743 const char *export_path, struct vfsmount *mnt_target)
2674{ 2744{
2745 struct nameidata *nd = NULL;
2675 struct mnt_namespace *ns_private; 2746 struct mnt_namespace *ns_private;
2676 struct nameidata nd;
2677 struct super_block *s; 2747 struct super_block *s;
2678 int ret; 2748 int ret;
2679 2749
2750 nd = kmalloc(sizeof(*nd), GFP_KERNEL);
2751 if (nd == NULL)
2752 return -ENOMEM;
2753
2680 ns_private = create_mnt_ns(root_mnt); 2754 ns_private = create_mnt_ns(root_mnt);
2681 ret = PTR_ERR(ns_private); 2755 ret = PTR_ERR(ns_private);
2682 if (IS_ERR(ns_private)) 2756 if (IS_ERR(ns_private))
2683 goto out_mntput; 2757 goto out_mntput;
2684 2758
2759 ret = nfs_referral_loop_protect();
2760 if (ret != 0)
2761 goto out_put_mnt_ns;
2762
2685 ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt, 2763 ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt,
2686 export_path, LOOKUP_FOLLOW, &nd); 2764 export_path, LOOKUP_FOLLOW, nd);
2687 2765
2766 nfs_referral_loop_unprotect();
2688 put_mnt_ns(ns_private); 2767 put_mnt_ns(ns_private);
2689 2768
2690 if (ret != 0) 2769 if (ret != 0)
2691 goto out_err; 2770 goto out_err;
2692 2771
2693 s = nd.path.mnt->mnt_sb; 2772 s = nd->path.mnt->mnt_sb;
2694 atomic_inc(&s->s_active); 2773 atomic_inc(&s->s_active);
2695 mnt_target->mnt_sb = s; 2774 mnt_target->mnt_sb = s;
2696 mnt_target->mnt_root = dget(nd.path.dentry); 2775 mnt_target->mnt_root = dget(nd->path.dentry);
2697 2776
2698 /* Correct the device pathname */ 2777 /* Correct the device pathname */
2699 nfs_fix_devname(&nd.path, mnt_target); 2778 nfs_fix_devname(&nd->path, mnt_target);
2700 2779
2701 path_put(&nd.path); 2780 path_put(&nd->path);
2781 kfree(nd);
2702 down_write(&s->s_umount); 2782 down_write(&s->s_umount);
2703 return 0; 2783 return 0;
2784out_put_mnt_ns:
2785 put_mnt_ns(ns_private);
2704out_mntput: 2786out_mntput:
2705 mntput(root_mnt); 2787 mntput(root_mnt);
2706out_err: 2788out_err:
2789 kfree(nd);
2707 return ret; 2790 return ret;
2708} 2791}
2709 2792
@@ -2874,17 +2957,21 @@ static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type,
2874 struct super_block *s; 2957 struct super_block *s;
2875 struct nfs_server *server; 2958 struct nfs_server *server;
2876 struct dentry *mntroot; 2959 struct dentry *mntroot;
2877 struct nfs_fh mntfh; 2960 struct nfs_fh *mntfh;
2878 int (*compare_super)(struct super_block *, void *) = nfs_compare_super; 2961 int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
2879 struct nfs_sb_mountdata sb_mntdata = { 2962 struct nfs_sb_mountdata sb_mntdata = {
2880 .mntflags = flags, 2963 .mntflags = flags,
2881 }; 2964 };
2882 int error; 2965 int error = -ENOMEM;
2883 2966
2884 dprintk("--> nfs4_referral_get_sb()\n"); 2967 dprintk("--> nfs4_referral_get_sb()\n");
2885 2968
2969 mntfh = nfs_alloc_fhandle();
2970 if (mntfh == NULL)
2971 goto out_err_nofh;
2972
2886 /* create a new volume representation */ 2973 /* create a new volume representation */
2887 server = nfs4_create_referral_server(data, &mntfh); 2974 server = nfs4_create_referral_server(data, mntfh);
2888 if (IS_ERR(server)) { 2975 if (IS_ERR(server)) {
2889 error = PTR_ERR(server); 2976 error = PTR_ERR(server);
2890 goto out_err_noserver; 2977 goto out_err_noserver;
@@ -2916,7 +3003,7 @@ static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type,
2916 nfs_fscache_get_super_cookie(s, NULL, data); 3003 nfs_fscache_get_super_cookie(s, NULL, data);
2917 } 3004 }
2918 3005
2919 mntroot = nfs4_get_root(s, &mntfh); 3006 mntroot = nfs4_get_root(s, mntfh);
2920 if (IS_ERR(mntroot)) { 3007 if (IS_ERR(mntroot)) {
2921 error = PTR_ERR(mntroot); 3008 error = PTR_ERR(mntroot);
2922 goto error_splat_super; 3009 goto error_splat_super;
@@ -2933,12 +3020,15 @@ static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type,
2933 3020
2934 security_sb_clone_mnt_opts(data->sb, s); 3021 security_sb_clone_mnt_opts(data->sb, s);
2935 3022
3023 nfs_free_fhandle(mntfh);
2936 dprintk("<-- nfs4_referral_get_sb() = 0\n"); 3024 dprintk("<-- nfs4_referral_get_sb() = 0\n");
2937 return 0; 3025 return 0;
2938 3026
2939out_err_nosb: 3027out_err_nosb:
2940 nfs_free_server(server); 3028 nfs_free_server(server);
2941out_err_noserver: 3029out_err_noserver:
3030 nfs_free_fhandle(mntfh);
3031out_err_nofh:
2942 dprintk("<-- nfs4_referral_get_sb() = %d [error]\n", error); 3032 dprintk("<-- nfs4_referral_get_sb() = %d [error]\n", error);
2943 return error; 3033 return error;
2944 3034
@@ -2947,6 +3037,7 @@ error_splat_super:
2947 bdi_unregister(&server->backing_dev_info); 3037 bdi_unregister(&server->backing_dev_info);
2948error_splat_bdi: 3038error_splat_bdi:
2949 deactivate_locked_super(s); 3039 deactivate_locked_super(s);
3040 nfs_free_fhandle(mntfh);
2950 dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error); 3041 dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error);
2951 return error; 3042 return error;
2952} 3043}