aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorBryan Schumaker <bjschuma@netapp.com>2012-07-30 16:05:16 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-07-30 19:04:17 -0400
commitab7017a3a0a64b953e091619c30413b3721d925d (patch)
tree1ec947c2794b217d7ead01ee29d8cc5aae4c51f8 /fs
parenta427b9ec4eda8cd6e641ea24541d30b641fc3140 (diff)
NFS: Add version registering framework
This patch adds in the code to track multiple versions of the NFS protocol. I created default structures for v2, v3 and v4 so that each version can continue to work while I convert them into kernel modules. I also removed the const parameter from the rpc_version array so that I can change it at runtime. Signed-off-by: Bryan Schumaker <bjschuma@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/Makefile4
-rw-r--r--fs/nfs/client.c147
-rw-r--r--fs/nfs/inode.c9
-rw-r--r--fs/nfs/internal.h10
-rw-r--r--fs/nfs/nfs.h72
-rw-r--r--fs/nfs/nfs2super.c25
-rw-r--r--fs/nfs/nfs3super.c25
-rw-r--r--fs/nfs/nfs4_fs.h1
-rw-r--r--fs/nfs/nfs4client.c4
-rw-r--r--fs/nfs/nfs4super.c14
-rw-r--r--fs/nfs/super.c32
11 files changed, 282 insertions, 61 deletions
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index 0b96c203834..66dd3075e5d 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -9,8 +9,8 @@ nfs-y := client.o dir.o file.o getroot.o inode.o super.o \
9 write.o namespace.o mount_clnt.o \ 9 write.o namespace.o mount_clnt.o \
10 dns_resolve.o cache_lib.o 10 dns_resolve.o cache_lib.o
11nfs-$(CONFIG_ROOT_NFS) += nfsroot.o 11nfs-$(CONFIG_ROOT_NFS) += nfsroot.o
12nfs-$(CONFIG_NFS_V2) += proc.o nfs2xdr.o 12nfs-$(CONFIG_NFS_V2) += nfs2super.o proc.o nfs2xdr.o
13nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o 13nfs-$(CONFIG_NFS_V3) += nfs3super.o nfs3proc.o nfs3xdr.o
14nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o 14nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
15nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ 15nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
16 nfs4super.o nfs4file.o delegation.o idmap.o \ 16 nfs4super.o nfs4file.o delegation.o idmap.o \
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 65afa382c5e..462de24482b 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -51,25 +51,23 @@
51#include "internal.h" 51#include "internal.h"
52#include "fscache.h" 52#include "fscache.h"
53#include "pnfs.h" 53#include "pnfs.h"
54#include "nfs.h"
54#include "netns.h" 55#include "netns.h"
55 56
56#define NFSDBG_FACILITY NFSDBG_CLIENT 57#define NFSDBG_FACILITY NFSDBG_CLIENT
57 58
58static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); 59static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
60static DEFINE_SPINLOCK(nfs_version_lock);
61static DEFINE_MUTEX(nfs_version_mutex);
62static LIST_HEAD(nfs_versions);
59 63
60/* 64/*
61 * RPC cruft for NFS 65 * RPC cruft for NFS
62 */ 66 */
63static const struct rpc_version *nfs_version[5] = { 67static const struct rpc_version *nfs_version[5] = {
64#ifdef CONFIG_NFS_V2 68 [2] = NULL,
65 [2] = &nfs_version2, 69 [3] = NULL,
66#endif 70 [4] = NULL,
67#ifdef CONFIG_NFS_V3
68 [3] = &nfs_version3,
69#endif
70#ifdef CONFIG_NFS_V4
71 [4] = &nfs_version4,
72#endif
73}; 71};
74 72
75const struct rpc_program nfs_program = { 73const struct rpc_program nfs_program = {
@@ -101,6 +99,93 @@ const struct rpc_program nfsacl_program = {
101}; 99};
102#endif /* CONFIG_NFS_V3_ACL */ 100#endif /* CONFIG_NFS_V3_ACL */
103 101
102static struct nfs_subversion *find_nfs_version(unsigned int version)
103{
104 struct nfs_subversion *nfs;
105 spin_lock(&nfs_version_lock);
106
107 list_for_each_entry(nfs, &nfs_versions, list) {
108 if (nfs->rpc_ops->version == version) {
109 spin_unlock(&nfs_version_lock);
110 return nfs;
111 }
112 };
113
114 spin_unlock(&nfs_version_lock);
115 return ERR_PTR(-EPROTONOSUPPORT);;
116}
117
118struct nfs_subversion *get_nfs_version(unsigned int version)
119{
120 struct nfs_subversion *nfs = find_nfs_version(version);
121
122 if (IS_ERR(nfs)) {
123 mutex_lock(&nfs_version_mutex);
124 request_module("nfs%d", version);
125 nfs = find_nfs_version(version);
126 mutex_unlock(&nfs_version_mutex);
127 }
128
129 if (!IS_ERR(nfs))
130 try_module_get(nfs->owner);
131 return nfs;
132}
133
134void put_nfs_version(struct nfs_subversion *nfs)
135{
136 module_put(nfs->owner);
137}
138
139void register_nfs_version(struct nfs_subversion *nfs)
140{
141 spin_lock(&nfs_version_lock);
142
143 list_add(&nfs->list, &nfs_versions);
144 nfs_version[nfs->rpc_ops->version] = nfs->rpc_vers;
145
146 spin_unlock(&nfs_version_lock);
147}
148EXPORT_SYMBOL_GPL(register_nfs_version);
149
150void unregister_nfs_version(struct nfs_subversion *nfs)
151{
152 spin_lock(&nfs_version_lock);
153
154 nfs_version[nfs->rpc_ops->version] = NULL;
155 list_del(&nfs->list);
156
157 spin_unlock(&nfs_version_lock);
158}
159EXPORT_SYMBOL_GPL(unregister_nfs_version);
160
161/*
162 * Preload all configured NFS versions during module init.
163 * This function should be edited after each protocol is converted,
164 * and eventually removed.
165 */
166int __init nfs_register_versions(void)
167{
168 int err = init_nfs_v2();
169 if (err)
170 return err;
171
172 err = init_nfs_v3();
173 if (err)
174 return err;
175
176 return init_nfs_v4();
177}
178
179/*
180 * Remove each pre-loaded NFS version
181 */
182void nfs_unregister_versions(void)
183{
184 exit_nfs_v2();
185 exit_nfs_v3();
186 exit_nfs_v4();
187}
188
104/* 189/*
105 * Allocate a shared client record 190 * Allocate a shared client record
106 * 191 *
@@ -116,7 +201,10 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
116 if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) 201 if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL)
117 goto error_0; 202 goto error_0;
118 203
119 clp->rpc_ops = cl_init->rpc_ops; 204 clp->cl_nfs_mod = cl_init->nfs_mod;
205 try_module_get(clp->cl_nfs_mod->owner);
206
207 clp->rpc_ops = clp->cl_nfs_mod->rpc_ops;
120 208
121 atomic_set(&clp->cl_count, 1); 209 atomic_set(&clp->cl_count, 1);
122 clp->cl_cons_state = NFS_CS_INITING; 210 clp->cl_cons_state = NFS_CS_INITING;
@@ -145,6 +233,7 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
145 return clp; 233 return clp;
146 234
147error_cleanup: 235error_cleanup:
236 put_nfs_version(clp->cl_nfs_mod);
148 kfree(clp); 237 kfree(clp);
149error_0: 238error_0:
150 return ERR_PTR(err); 239 return ERR_PTR(err);
@@ -205,6 +294,7 @@ void nfs_free_client(struct nfs_client *clp)
205 put_rpccred(clp->cl_machine_cred); 294 put_rpccred(clp->cl_machine_cred);
206 295
207 put_net(clp->cl_net); 296 put_net(clp->cl_net);
297 put_nfs_version(clp->cl_nfs_mod);
208 kfree(clp->cl_hostname); 298 kfree(clp->cl_hostname);
209 kfree(clp); 299 kfree(clp);
210 300
@@ -362,7 +452,7 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
362 continue; 452 continue;
363 453
364 /* Different NFS versions cannot share the same nfs_client */ 454 /* Different NFS versions cannot share the same nfs_client */
365 if (clp->rpc_ops != data->rpc_ops) 455 if (clp->rpc_ops != data->nfs_mod->rpc_ops)
366 continue; 456 continue;
367 457
368 if (clp->cl_proto != data->proto) 458 if (clp->cl_proto != data->proto)
@@ -431,9 +521,10 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
431{ 521{
432 struct nfs_client *clp, *new = NULL; 522 struct nfs_client *clp, *new = NULL;
433 struct nfs_net *nn = net_generic(cl_init->net, nfs_net_id); 523 struct nfs_net *nn = net_generic(cl_init->net, nfs_net_id);
524 const struct nfs_rpc_ops *rpc_ops = cl_init->nfs_mod->rpc_ops;
434 525
435 dprintk("--> nfs_get_client(%s,v%u)\n", 526 dprintk("--> nfs_get_client(%s,v%u)\n",
436 cl_init->hostname ?: "", cl_init->rpc_ops->version); 527 cl_init->hostname ?: "", rpc_ops->version);
437 528
438 /* see if the client already exists */ 529 /* see if the client already exists */
439 do { 530 do {
@@ -450,14 +541,13 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
450 list_add(&new->cl_share_link, &nn->nfs_client_list); 541 list_add(&new->cl_share_link, &nn->nfs_client_list);
451 spin_unlock(&nn->nfs_client_lock); 542 spin_unlock(&nn->nfs_client_lock);
452 new->cl_flags = cl_init->init_flags; 543 new->cl_flags = cl_init->init_flags;
453 return cl_init->rpc_ops->init_client(new, 544 return rpc_ops->init_client(new, timeparms, ip_addr,
454 timeparms, ip_addr, 545 authflavour);
455 authflavour);
456 } 546 }
457 547
458 spin_unlock(&nn->nfs_client_lock); 548 spin_unlock(&nn->nfs_client_lock);
459 549
460 new = cl_init->rpc_ops->alloc_client(cl_init); 550 new = rpc_ops->alloc_client(cl_init);
461 } while (!IS_ERR(new)); 551 } while (!IS_ERR(new));
462 552
463 dprintk("<-- nfs_get_client() Failed to find %s (%ld)\n", 553 dprintk("<-- nfs_get_client() Failed to find %s (%ld)\n",
@@ -714,13 +804,14 @@ error:
714 * Create a version 2 or 3 client 804 * Create a version 2 or 3 client
715 */ 805 */
716static int nfs_init_server(struct nfs_server *server, 806static int nfs_init_server(struct nfs_server *server,
717 const struct nfs_parsed_mount_data *data) 807 const struct nfs_parsed_mount_data *data,
808 struct nfs_subversion *nfs_mod)
718{ 809{
719 struct nfs_client_initdata cl_init = { 810 struct nfs_client_initdata cl_init = {
720 .hostname = data->nfs_server.hostname, 811 .hostname = data->nfs_server.hostname,
721 .addr = (const struct sockaddr *)&data->nfs_server.address, 812 .addr = (const struct sockaddr *)&data->nfs_server.address,
722 .addrlen = data->nfs_server.addrlen, 813 .addrlen = data->nfs_server.addrlen,
723 .rpc_ops = NULL, 814 .nfs_mod = nfs_mod,
724 .proto = data->nfs_server.protocol, 815 .proto = data->nfs_server.protocol,
725 .net = data->net, 816 .net = data->net,
726 }; 817 };
@@ -730,21 +821,6 @@ static int nfs_init_server(struct nfs_server *server,
730 821
731 dprintk("--> nfs_init_server()\n"); 822 dprintk("--> nfs_init_server()\n");
732 823
733 switch (data->version) {
734#ifdef CONFIG_NFS_V2
735 case 2:
736 cl_init.rpc_ops = &nfs_v2_clientops;
737 break;
738#endif
739#ifdef CONFIG_NFS_V3
740 case 3:
741 cl_init.rpc_ops = &nfs_v3_clientops;
742 break;
743#endif
744 default:
745 return -EPROTONOSUPPORT;
746 }
747
748 nfs_init_timeout_values(&timeparms, data->nfs_server.protocol, 824 nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
749 data->timeo, data->retrans); 825 data->timeo, data->retrans);
750 if (data->flags & NFS_MOUNT_NORESVPORT) 826 if (data->flags & NFS_MOUNT_NORESVPORT)
@@ -1033,7 +1109,8 @@ void nfs_free_server(struct nfs_server *server)
1033 * - keyed on server and FSID 1109 * - keyed on server and FSID
1034 */ 1110 */
1035struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, 1111struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data,
1036 struct nfs_fh *mntfh) 1112 struct nfs_fh *mntfh,
1113 struct nfs_subversion *nfs_mod)
1037{ 1114{
1038 struct nfs_server *server; 1115 struct nfs_server *server;
1039 struct nfs_fattr *fattr; 1116 struct nfs_fattr *fattr;
@@ -1049,7 +1126,7 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data,
1049 goto error; 1126 goto error;
1050 1127
1051 /* Get a client representation */ 1128 /* Get a client representation */
1052 error = nfs_init_server(server, data); 1129 error = nfs_init_server(server, data, nfs_mod);
1053 if (error < 0) 1130 if (error < 0)
1054 goto error; 1131 goto error;
1055 1132
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 35f7e4bc680..e8877c82582 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -50,6 +50,7 @@
50#include "fscache.h" 50#include "fscache.h"
51#include "dns_resolve.h" 51#include "dns_resolve.h"
52#include "pnfs.h" 52#include "pnfs.h"
53#include "nfs.h"
53#include "netns.h" 54#include "netns.h"
54 55
55#define NFSDBG_FACILITY NFSDBG_VFS 56#define NFSDBG_FACILITY NFSDBG_VFS
@@ -1671,21 +1672,17 @@ static int __init init_nfs_fs(void)
1671 rpc_proc_register(&init_net, &nfs_rpcstat); 1672 rpc_proc_register(&init_net, &nfs_rpcstat);
1672#endif 1673#endif
1673 1674
1674#ifdef CONFIG_NFS_V4 1675 err = nfs_register_versions();
1675 err = init_nfs_v4();
1676 if (err) 1676 if (err)
1677 goto out1; 1677 goto out1;
1678#endif
1679 1678
1680 if ((err = register_nfs_fs()) != 0) 1679 if ((err = register_nfs_fs()) != 0)
1681 goto out0; 1680 goto out0;
1682 1681
1683 return 0; 1682 return 0;
1684out0: 1683out0:
1685#ifdef CONFIG_NFS_V4 1684 nfs_unregister_versions();
1686 exit_nfs_v4();
1687out1: 1685out1:
1688#endif
1689#ifdef CONFIG_PROC_FS 1686#ifdef CONFIG_PROC_FS
1690 rpc_proc_unregister(&init_net, "nfs"); 1687 rpc_proc_unregister(&init_net, "nfs");
1691#endif 1688#endif
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index cfafd13b6fe..ac936476b3b 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -90,7 +90,7 @@ struct nfs_client_initdata {
90 const char *hostname; 90 const char *hostname;
91 const struct sockaddr *addr; 91 const struct sockaddr *addr;
92 size_t addrlen; 92 size_t addrlen;
93 const struct nfs_rpc_ops *rpc_ops; 93 struct nfs_subversion *nfs_mod;
94 int proto; 94 int proto;
95 u32 minorversion; 95 u32 minorversion;
96 struct net *net; 96 struct net *net;
@@ -189,7 +189,8 @@ nfs4_find_client_sessionid(struct net *, const struct sockaddr *,
189 struct nfs4_sessionid *); 189 struct nfs4_sessionid *);
190extern struct nfs_server *nfs_create_server( 190extern struct nfs_server *nfs_create_server(
191 const struct nfs_parsed_mount_data *, 191 const struct nfs_parsed_mount_data *,
192 struct nfs_fh *); 192 struct nfs_fh *,
193 struct nfs_subversion *);
193extern struct nfs_server *nfs4_create_server( 194extern struct nfs_server *nfs4_create_server(
194 const struct nfs_parsed_mount_data *, 195 const struct nfs_parsed_mount_data *,
195 struct nfs_fh *); 196 struct nfs_fh *);
@@ -321,6 +322,7 @@ void nfs_zap_acl_cache(struct inode *inode);
321extern int nfs_wait_bit_killable(void *word); 322extern int nfs_wait_bit_killable(void *word);
322 323
323/* super.c */ 324/* super.c */
325extern struct file_system_type nfs_fs_type;
324extern struct file_system_type nfs_xdev_fs_type; 326extern struct file_system_type nfs_xdev_fs_type;
325#ifdef CONFIG_NFS_V4 327#ifdef CONFIG_NFS_V4
326extern struct file_system_type nfs4_xdev_fs_type; 328extern struct file_system_type nfs4_xdev_fs_type;
@@ -329,8 +331,8 @@ extern struct file_system_type nfs4_referral_fs_type;
329void nfs_initialise_sb(struct super_block *); 331void nfs_initialise_sb(struct super_block *);
330int nfs_set_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *); 332int nfs_set_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *);
331int nfs_clone_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *); 333int nfs_clone_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *);
332struct dentry *nfs_fs_mount_common(struct file_system_type *, struct nfs_server *, 334struct dentry *nfs_fs_mount_common(struct nfs_server *, int, const char *,
333 int, const char *, struct nfs_mount_info *); 335 struct nfs_mount_info *, struct nfs_subversion *);
334struct dentry *nfs_fs_mount(struct file_system_type *, int, const char *, void *); 336struct dentry *nfs_fs_mount(struct file_system_type *, int, const char *, void *);
335struct dentry * nfs_xdev_mount_common(struct file_system_type *, int, 337struct dentry * nfs_xdev_mount_common(struct file_system_type *, int,
336 const char *, struct nfs_mount_info *); 338 const char *, struct nfs_mount_info *);
diff --git a/fs/nfs/nfs.h b/fs/nfs/nfs.h
new file mode 100644
index 00000000000..ac10b9e6c92
--- /dev/null
+++ b/fs/nfs/nfs.h
@@ -0,0 +1,72 @@
1/*
2 * Copyright (c) 2012 Netapp, Inc. All rights reserved.
3 *
4 * Function and structures exported by the NFS module
5 * for use by NFS version-specific modules.
6 */
7#ifndef __LINUX_INTERNAL_NFS_H
8#define __LINUX_INTERNAL_NFS_H
9
10#include <linux/fs.h>
11#include <linux/sunrpc/sched.h>
12#include <linux/nfs_xdr.h>
13
14struct nfs_subversion {
15 struct module *owner; /* THIS_MODULE pointer */
16 struct file_system_type *nfs_fs; /* NFS filesystem type */
17 const struct rpc_version *rpc_vers; /* NFS version information */
18 const struct nfs_rpc_ops *rpc_ops; /* NFS operations */
19 struct list_head list; /* List of NFS versions */
20};
21
22int nfs_register_versions(void);
23void nfs_unregister_versions(void);
24
25#ifdef CONFIG_NFS_V2
26int init_nfs_v2(void);
27void exit_nfs_v2(void);
28#else /* CONFIG_NFS_V2 */
29static inline int __init init_nfs_v2(void)
30{
31 return 0;
32}
33
34static inline void exit_nfs_v2(void)
35{
36}
37#endif /* CONFIG_NFS_V2 */
38
39#ifdef CONFIG_NFS_V3
40int init_nfs_v3(void);
41void exit_nfs_v3(void);
42#else /* CONFIG_NFS_V3 */
43static inline int __init init_nfs_v3(void)
44{
45 return 0;
46}
47
48static inline void exit_nfs_v3(void)
49{
50}
51#endif /* CONFIG_NFS_V3 */
52
53#ifdef CONFIG_NFS_V4
54int init_nfs_v4(void);
55void exit_nfs_v4(void);
56#else /* CONFIG_NFS_V4 */
57static inline int __init init_nfs_v4(void)
58{
59 return 0;
60}
61
62static inline void exit_nfs_v4(void)
63{
64}
65#endif /* CONFIG_NFS_V4 */
66
67struct nfs_subversion *get_nfs_version(unsigned int);
68void put_nfs_version(struct nfs_subversion *);
69void register_nfs_version(struct nfs_subversion *);
70void unregister_nfs_version(struct nfs_subversion *);
71
72#endif /* __LINUX_INTERNAL_NFS_H */
diff --git a/fs/nfs/nfs2super.c b/fs/nfs/nfs2super.c
new file mode 100644
index 00000000000..cef06d42334
--- /dev/null
+++ b/fs/nfs/nfs2super.c
@@ -0,0 +1,25 @@
1/*
2 * Copyright (c) 2012 Netapp, Inc. All rights reserved.
3 */
4#include <linux/module.h>
5#include <linux/nfs_fs.h>
6#include "internal.h"
7#include "nfs.h"
8
9static struct nfs_subversion nfs_v2 = {
10 .owner = THIS_MODULE,
11 .nfs_fs = &nfs_fs_type,
12 .rpc_vers = &nfs_version2,
13 .rpc_ops = &nfs_v2_clientops,
14};
15
16int __init init_nfs_v2(void)
17{
18 register_nfs_version(&nfs_v2);
19 return 0;
20}
21
22void exit_nfs_v2(void)
23{
24 unregister_nfs_version(&nfs_v2);
25}
diff --git a/fs/nfs/nfs3super.c b/fs/nfs/nfs3super.c
new file mode 100644
index 00000000000..f815cf359d9
--- /dev/null
+++ b/fs/nfs/nfs3super.c
@@ -0,0 +1,25 @@
1/*
2 * Copyright (c) 2012 Netapp, Inc. All rights reserved.
3 */
4#include <linux/module.h>
5#include <linux/nfs_fs.h>
6#include "internal.h"
7#include "nfs.h"
8
9static struct nfs_subversion nfs_v3 = {
10 .owner = THIS_MODULE,
11 .nfs_fs = &nfs_fs_type,
12 .rpc_vers = &nfs_version3,
13 .rpc_ops = &nfs_v3_clientops,
14};
15
16int __init init_nfs_v3(void)
17{
18 register_nfs_version(&nfs_v3);
19 return 0;
20}
21
22void exit_nfs_v3(void)
23{
24 unregister_nfs_version(&nfs_v3);
25}
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 5511690de8a..99c2e7e4d3e 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -366,6 +366,7 @@ extern const nfs4_stateid zero_stateid;
366 366
367/* nfs4super.c */ 367/* nfs4super.c */
368struct nfs_mount_info; 368struct nfs_mount_info;
369extern struct nfs_subversion nfs_v4;
369struct dentry *nfs4_try_mount(int, const char *, struct nfs_mount_info *); 370struct dentry *nfs4_try_mount(int, const char *, struct nfs_mount_info *);
370int init_nfs_v4(void); 371int init_nfs_v4(void);
371void exit_nfs_v4(void); 372void exit_nfs_v4(void);
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 1c3f13c8e47..769e798b395 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -357,7 +357,7 @@ static int nfs4_set_client(struct nfs_server *server,
357 .hostname = hostname, 357 .hostname = hostname,
358 .addr = addr, 358 .addr = addr,
359 .addrlen = addrlen, 359 .addrlen = addrlen,
360 .rpc_ops = &nfs_v4_clientops, 360 .nfs_mod = &nfs_v4,
361 .proto = proto, 361 .proto = proto,
362 .minorversion = minorversion, 362 .minorversion = minorversion,
363 .net = net, 363 .net = net,
@@ -411,7 +411,7 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
411 struct nfs_client_initdata cl_init = { 411 struct nfs_client_initdata cl_init = {
412 .addr = ds_addr, 412 .addr = ds_addr,
413 .addrlen = ds_addrlen, 413 .addrlen = ds_addrlen,
414 .rpc_ops = &nfs_v4_clientops, 414 .nfs_mod = &nfs_v4,
415 .proto = ds_proto, 415 .proto = ds_proto,
416 .minorversion = mds_clp->cl_minorversion, 416 .minorversion = mds_clp->cl_minorversion,
417 .net = mds_clp->cl_net, 417 .net = mds_clp->cl_net,
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index 59264fb335c..1f3401902c2 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -8,6 +8,7 @@
8#include <linux/nfs_fs.h> 8#include <linux/nfs_fs.h>
9#include "internal.h" 9#include "internal.h"
10#include "nfs4_fs.h" 10#include "nfs4_fs.h"
11#include "nfs.h"
11 12
12#define NFSDBG_FACILITY NFSDBG_VFS 13#define NFSDBG_FACILITY NFSDBG_VFS
13 14
@@ -75,6 +76,13 @@ static const struct super_operations nfs4_sops = {
75 .remount_fs = nfs_remount, 76 .remount_fs = nfs_remount,
76}; 77};
77 78
79struct nfs_subversion nfs_v4 = {
80 .owner = THIS_MODULE,
81 .nfs_fs = &nfs4_fs_type,
82 .rpc_vers = &nfs_version4,
83 .rpc_ops = &nfs_v4_clientops,
84};
85
78/* 86/*
79 * Set up an NFS4 superblock 87 * Set up an NFS4 superblock
80 */ 88 */
@@ -113,7 +121,7 @@ nfs4_remote_mount(struct file_system_type *fs_type, int flags,
113 goto out; 121 goto out;
114 } 122 }
115 123
116 mntroot = nfs_fs_mount_common(fs_type, server, flags, dev_name, mount_info); 124 mntroot = nfs_fs_mount_common(server, flags, dev_name, mount_info, &nfs_v4);
117 125
118out: 126out:
119 return mntroot; 127 return mntroot;
@@ -293,7 +301,7 @@ nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags,
293 goto out; 301 goto out;
294 } 302 }
295 303
296 mntroot = nfs_fs_mount_common(&nfs4_fs_type, server, flags, dev_name, &mount_info); 304 mntroot = nfs_fs_mount_common(server, flags, dev_name, &mount_info, &nfs_v4);
297out: 305out:
298 nfs_free_fhandle(mount_info.mntfh); 306 nfs_free_fhandle(mount_info.mntfh);
299 return mntroot; 307 return mntroot;
@@ -343,6 +351,7 @@ int __init init_nfs_v4(void)
343 if (err < 0) 351 if (err < 0)
344 goto out2; 352 goto out2;
345 353
354 register_nfs_version(&nfs_v4);
346 return 0; 355 return 0;
347out2: 356out2:
348 nfs4_unregister_sysctl(); 357 nfs4_unregister_sysctl();
@@ -354,6 +363,7 @@ out:
354 363
355void exit_nfs_v4(void) 364void exit_nfs_v4(void)
356{ 365{
366 unregister_nfs_version(&nfs_v4);
357 unregister_filesystem(&nfs4_fs_type); 367 unregister_filesystem(&nfs4_fs_type);
358 nfs4_unregister_sysctl(); 368 nfs4_unregister_sysctl();
359 nfs_idmap_quit(); 369 nfs_idmap_quit();
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 95866a8c21b..61405a7a6b3 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -64,6 +64,7 @@
64#include "internal.h" 64#include "internal.h"
65#include "fscache.h" 65#include "fscache.h"
66#include "pnfs.h" 66#include "pnfs.h"
67#include "nfs.h"
67 68
68#define NFSDBG_FACILITY NFSDBG_VFS 69#define NFSDBG_FACILITY NFSDBG_VFS
69#define NFS_TEXT_DATA 1 70#define NFS_TEXT_DATA 1
@@ -281,7 +282,7 @@ static match_table_t nfs_vers_tokens = {
281static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type, 282static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type,
282 int flags, const char *dev_name, void *raw_data); 283 int flags, const char *dev_name, void *raw_data);
283 284
284static struct file_system_type nfs_fs_type = { 285struct file_system_type nfs_fs_type = {
285 .owner = THIS_MODULE, 286 .owner = THIS_MODULE,
286 .name = "nfs", 287 .name = "nfs",
287 .mount = nfs_fs_mount, 288 .mount = nfs_fs_mount,
@@ -1650,7 +1651,8 @@ static int nfs_request_mount(struct nfs_parsed_mount_data *args,
1650} 1651}
1651 1652
1652static struct dentry *nfs_try_mount(int flags, const char *dev_name, 1653static struct dentry *nfs_try_mount(int flags, const char *dev_name,
1653 struct nfs_mount_info *mount_info) 1654 struct nfs_mount_info *mount_info,
1655 struct nfs_subversion *nfs_mod)
1654{ 1656{
1655 int status; 1657 int status;
1656 struct nfs_server *server; 1658 struct nfs_server *server;
@@ -1662,11 +1664,11 @@ static struct dentry *nfs_try_mount(int flags, const char *dev_name,
1662 } 1664 }
1663 1665
1664 /* Get a volume representation */ 1666 /* Get a volume representation */
1665 server = nfs_create_server(mount_info->parsed, mount_info->mntfh); 1667 server = nfs_create_server(mount_info->parsed, mount_info->mntfh, nfs_mod);
1666 if (IS_ERR(server)) 1668 if (IS_ERR(server))
1667 return ERR_CAST(server); 1669 return ERR_CAST(server);
1668 1670
1669 return nfs_fs_mount_common(&nfs_fs_type, server, flags, dev_name, mount_info); 1671 return nfs_fs_mount_common(server, flags, dev_name, mount_info, nfs_mod);
1670} 1672}
1671 1673
1672/* 1674/*
@@ -2297,10 +2299,10 @@ int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot,
2297 return 0; 2299 return 0;
2298} 2300}
2299 2301
2300struct dentry *nfs_fs_mount_common(struct file_system_type *fs_type, 2302struct dentry *nfs_fs_mount_common(struct nfs_server *server,
2301 struct nfs_server *server,
2302 int flags, const char *dev_name, 2303 int flags, const char *dev_name,
2303 struct nfs_mount_info *mount_info) 2304 struct nfs_mount_info *mount_info,
2305 struct nfs_subversion *nfs_mod)
2304{ 2306{
2305 struct super_block *s; 2307 struct super_block *s;
2306 struct dentry *mntroot = ERR_PTR(-ENOMEM); 2308 struct dentry *mntroot = ERR_PTR(-ENOMEM);
@@ -2319,7 +2321,7 @@ struct dentry *nfs_fs_mount_common(struct file_system_type *fs_type,
2319 sb_mntdata.mntflags |= MS_SYNCHRONOUS; 2321 sb_mntdata.mntflags |= MS_SYNCHRONOUS;
2320 2322
2321 /* Get a superblock - note that we may end up sharing one that already exists */ 2323 /* Get a superblock - note that we may end up sharing one that already exists */
2322 s = sget(fs_type, compare_super, nfs_set_super, flags, &sb_mntdata); 2324 s = sget(nfs_mod->nfs_fs, compare_super, nfs_set_super, flags, &sb_mntdata);
2323 if (IS_ERR(s)) { 2325 if (IS_ERR(s)) {
2324 mntroot = ERR_CAST(s); 2326 mntroot = ERR_CAST(s);
2325 goto out_err_nosb; 2327 goto out_err_nosb;
@@ -2378,6 +2380,7 @@ struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
2378 .set_security = nfs_set_sb_security, 2380 .set_security = nfs_set_sb_security,
2379 }; 2381 };
2380 struct dentry *mntroot = ERR_PTR(-ENOMEM); 2382 struct dentry *mntroot = ERR_PTR(-ENOMEM);
2383 struct nfs_subversion *nfs_mod;
2381 int error; 2384 int error;
2382 2385
2383 mount_info.parsed = nfs_alloc_parsed_mount_data(); 2386 mount_info.parsed = nfs_alloc_parsed_mount_data();
@@ -2394,12 +2397,20 @@ struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
2394 goto out; 2397 goto out;
2395 } 2398 }
2396 2399
2400 nfs_mod = get_nfs_version(mount_info.parsed->version);
2401 if (IS_ERR(nfs_mod)) {
2402 mntroot = ERR_CAST(nfs_mod);
2403 goto out;
2404 }
2405
2397#ifdef CONFIG_NFS_V4 2406#ifdef CONFIG_NFS_V4
2398 if (mount_info.parsed->version == 4) 2407 if (mount_info.parsed->version == 4)
2399 mntroot = nfs4_try_mount(flags, dev_name, &mount_info); 2408 mntroot = nfs4_try_mount(flags, dev_name, &mount_info);
2400 else 2409 else
2401#endif /* CONFIG_NFS_V4 */ 2410#endif /* CONFIG_NFS_V4 */
2402 mntroot = nfs_try_mount(flags, dev_name, &mount_info); 2411 mntroot = nfs_try_mount(flags, dev_name, &mount_info, nfs_mod);
2412
2413 put_nfs_version(nfs_mod);
2403 2414
2404out: 2415out:
2405 nfs_free_parsed_mount_data(mount_info.parsed); 2416 nfs_free_parsed_mount_data(mount_info.parsed);
@@ -2440,6 +2451,7 @@ nfs_xdev_mount_common(struct file_system_type *fs_type, int flags,
2440 struct nfs_clone_mount *data = mount_info->cloned; 2451 struct nfs_clone_mount *data = mount_info->cloned;
2441 struct nfs_server *server; 2452 struct nfs_server *server;
2442 struct dentry *mntroot = ERR_PTR(-ENOMEM); 2453 struct dentry *mntroot = ERR_PTR(-ENOMEM);
2454 struct nfs_subversion *nfs_mod = NFS_SB(data->sb)->nfs_client->cl_nfs_mod;
2443 int error; 2455 int error;
2444 2456
2445 dprintk("--> nfs_xdev_mount_common()\n"); 2457 dprintk("--> nfs_xdev_mount_common()\n");
@@ -2453,7 +2465,7 @@ nfs_xdev_mount_common(struct file_system_type *fs_type, int flags,
2453 goto out_err; 2465 goto out_err;
2454 } 2466 }
2455 2467
2456 mntroot = nfs_fs_mount_common(fs_type, server, flags, dev_name, mount_info); 2468 mntroot = nfs_fs_mount_common(server, flags, dev_name, mount_info, nfs_mod);
2457 dprintk("<-- nfs_xdev_mount_common() = 0\n"); 2469 dprintk("<-- nfs_xdev_mount_common() = 0\n");
2458out: 2470out:
2459 return mntroot; 2471 return mntroot;