aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/super.c
diff options
context:
space:
mode:
authorJens Axboe <jens.axboe@oracle.com>2010-05-21 15:27:26 -0400
committerJens Axboe <jens.axboe@oracle.com>2010-05-21 15:27:26 -0400
commitee9a3607fb03e804ddf624544105f4e34260c380 (patch)
treece41b6e0fa10982a306f6c142a92dbf3c9961284 /fs/nfs/super.c
parentb492e95be0ae672922f4734acf3f5d35c30be948 (diff)
parentd515e86e639890b33a09390d062b0831664f04a2 (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.c150
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);
2248out_free_fh: 2253out_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,
2613out: 2618out:
2614 security_free_mnt_opts(&data->lsm_opts); 2619 security_free_mnt_opts(&data->lsm_opts);
2615out_free_fh: 2620out_free_fh:
2616 kfree(mntfh); 2621 nfs_free_fhandle(mntfh);
2617 return error; 2622 return error;
2618 2623
2619out_free: 2624out_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
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
2671static int nfs_follow_remote_path(struct vfsmount *root_mnt, 2742static 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;
2784out_put_mnt_ns:
2785 put_mnt_ns(ns_private);
2703out_mntput: 2786out_mntput:
2704 mntput(root_mnt); 2787 mntput(root_mnt);
2705out_err: 2788out_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
2938out_err_nosb: 3027out_err_nosb:
2939 nfs_free_server(server); 3028 nfs_free_server(server);
2940out_err_noserver: 3029out_err_noserver:
3030 nfs_free_fhandle(mntfh);
3031out_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);
2947error_splat_bdi: 3038error_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}