diff options
author | Bryan Schumaker <bjschuma@netapp.com> | 2012-07-30 16:05:16 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-07-30 19:04:17 -0400 |
commit | ab7017a3a0a64b953e091619c30413b3721d925d (patch) | |
tree | 1ec947c2794b217d7ead01ee29d8cc5aae4c51f8 /fs | |
parent | a427b9ec4eda8cd6e641ea24541d30b641fc3140 (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/Makefile | 4 | ||||
-rw-r--r-- | fs/nfs/client.c | 147 | ||||
-rw-r--r-- | fs/nfs/inode.c | 9 | ||||
-rw-r--r-- | fs/nfs/internal.h | 10 | ||||
-rw-r--r-- | fs/nfs/nfs.h | 72 | ||||
-rw-r--r-- | fs/nfs/nfs2super.c | 25 | ||||
-rw-r--r-- | fs/nfs/nfs3super.c | 25 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 1 | ||||
-rw-r--r-- | fs/nfs/nfs4client.c | 4 | ||||
-rw-r--r-- | fs/nfs/nfs4super.c | 14 | ||||
-rw-r--r-- | fs/nfs/super.c | 32 |
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 |
11 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o | 11 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o |
12 | nfs-$(CONFIG_NFS_V2) += proc.o nfs2xdr.o | 12 | nfs-$(CONFIG_NFS_V2) += nfs2super.o proc.o nfs2xdr.o |
13 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o | 13 | nfs-$(CONFIG_NFS_V3) += nfs3super.o nfs3proc.o nfs3xdr.o |
14 | nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o | 14 | nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o |
15 | nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ | 15 | nfs-$(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 | ||
58 | static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); | 59 | static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); |
60 | static DEFINE_SPINLOCK(nfs_version_lock); | ||
61 | static DEFINE_MUTEX(nfs_version_mutex); | ||
62 | static LIST_HEAD(nfs_versions); | ||
59 | 63 | ||
60 | /* | 64 | /* |
61 | * RPC cruft for NFS | 65 | * RPC cruft for NFS |
62 | */ | 66 | */ |
63 | static const struct rpc_version *nfs_version[5] = { | 67 | static 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 | ||
75 | const struct rpc_program nfs_program = { | 73 | const 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 | ||
102 | static 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 | |||
118 | struct 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 | |||
134 | void put_nfs_version(struct nfs_subversion *nfs) | ||
135 | { | ||
136 | module_put(nfs->owner); | ||
137 | } | ||
138 | |||
139 | void 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 | } | ||
148 | EXPORT_SYMBOL_GPL(register_nfs_version); | ||
149 | |||
150 | void 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 | } | ||
159 | EXPORT_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 | */ | ||
166 | int __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 | */ | ||
182 | void 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 | ||
147 | error_cleanup: | 235 | error_cleanup: |
236 | put_nfs_version(clp->cl_nfs_mod); | ||
148 | kfree(clp); | 237 | kfree(clp); |
149 | error_0: | 238 | error_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 | */ |
716 | static int nfs_init_server(struct nfs_server *server, | 806 | static 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 | */ |
1035 | struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, | 1111 | struct 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; |
1684 | out0: | 1683 | out0: |
1685 | #ifdef CONFIG_NFS_V4 | 1684 | nfs_unregister_versions(); |
1686 | exit_nfs_v4(); | ||
1687 | out1: | 1685 | out1: |
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 *); |
190 | extern struct nfs_server *nfs_create_server( | 190 | extern 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 *); | ||
193 | extern struct nfs_server *nfs4_create_server( | 194 | extern 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); | |||
321 | extern int nfs_wait_bit_killable(void *word); | 322 | extern int nfs_wait_bit_killable(void *word); |
322 | 323 | ||
323 | /* super.c */ | 324 | /* super.c */ |
325 | extern struct file_system_type nfs_fs_type; | ||
324 | extern struct file_system_type nfs_xdev_fs_type; | 326 | extern struct file_system_type nfs_xdev_fs_type; |
325 | #ifdef CONFIG_NFS_V4 | 327 | #ifdef CONFIG_NFS_V4 |
326 | extern struct file_system_type nfs4_xdev_fs_type; | 328 | extern struct file_system_type nfs4_xdev_fs_type; |
@@ -329,8 +331,8 @@ extern struct file_system_type nfs4_referral_fs_type; | |||
329 | void nfs_initialise_sb(struct super_block *); | 331 | void nfs_initialise_sb(struct super_block *); |
330 | int nfs_set_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *); | 332 | int nfs_set_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *); |
331 | int nfs_clone_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *); | 333 | int nfs_clone_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *); |
332 | struct dentry *nfs_fs_mount_common(struct file_system_type *, struct nfs_server *, | 334 | struct 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 *); |
334 | struct dentry *nfs_fs_mount(struct file_system_type *, int, const char *, void *); | 336 | struct dentry *nfs_fs_mount(struct file_system_type *, int, const char *, void *); |
335 | struct dentry * nfs_xdev_mount_common(struct file_system_type *, int, | 337 | struct 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 | |||
14 | struct 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 | |||
22 | int nfs_register_versions(void); | ||
23 | void nfs_unregister_versions(void); | ||
24 | |||
25 | #ifdef CONFIG_NFS_V2 | ||
26 | int init_nfs_v2(void); | ||
27 | void exit_nfs_v2(void); | ||
28 | #else /* CONFIG_NFS_V2 */ | ||
29 | static inline int __init init_nfs_v2(void) | ||
30 | { | ||
31 | return 0; | ||
32 | } | ||
33 | |||
34 | static inline void exit_nfs_v2(void) | ||
35 | { | ||
36 | } | ||
37 | #endif /* CONFIG_NFS_V2 */ | ||
38 | |||
39 | #ifdef CONFIG_NFS_V3 | ||
40 | int init_nfs_v3(void); | ||
41 | void exit_nfs_v3(void); | ||
42 | #else /* CONFIG_NFS_V3 */ | ||
43 | static inline int __init init_nfs_v3(void) | ||
44 | { | ||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | static inline void exit_nfs_v3(void) | ||
49 | { | ||
50 | } | ||
51 | #endif /* CONFIG_NFS_V3 */ | ||
52 | |||
53 | #ifdef CONFIG_NFS_V4 | ||
54 | int init_nfs_v4(void); | ||
55 | void exit_nfs_v4(void); | ||
56 | #else /* CONFIG_NFS_V4 */ | ||
57 | static inline int __init init_nfs_v4(void) | ||
58 | { | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static inline void exit_nfs_v4(void) | ||
63 | { | ||
64 | } | ||
65 | #endif /* CONFIG_NFS_V4 */ | ||
66 | |||
67 | struct nfs_subversion *get_nfs_version(unsigned int); | ||
68 | void put_nfs_version(struct nfs_subversion *); | ||
69 | void register_nfs_version(struct nfs_subversion *); | ||
70 | void 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 | |||
9 | static 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 | |||
16 | int __init init_nfs_v2(void) | ||
17 | { | ||
18 | register_nfs_version(&nfs_v2); | ||
19 | return 0; | ||
20 | } | ||
21 | |||
22 | void 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 | |||
9 | static 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 | |||
16 | int __init init_nfs_v3(void) | ||
17 | { | ||
18 | register_nfs_version(&nfs_v3); | ||
19 | return 0; | ||
20 | } | ||
21 | |||
22 | void 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 */ |
368 | struct nfs_mount_info; | 368 | struct nfs_mount_info; |
369 | extern struct nfs_subversion nfs_v4; | ||
369 | struct dentry *nfs4_try_mount(int, const char *, struct nfs_mount_info *); | 370 | struct dentry *nfs4_try_mount(int, const char *, struct nfs_mount_info *); |
370 | int init_nfs_v4(void); | 371 | int init_nfs_v4(void); |
371 | void exit_nfs_v4(void); | 372 | void 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 | ||
79 | struct 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 | ||
118 | out: | 126 | out: |
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); |
297 | out: | 305 | out: |
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; |
347 | out2: | 356 | out2: |
348 | nfs4_unregister_sysctl(); | 357 | nfs4_unregister_sysctl(); |
@@ -354,6 +363,7 @@ out: | |||
354 | 363 | ||
355 | void exit_nfs_v4(void) | 364 | void 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 = { | |||
281 | static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type, | 282 | static 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 | ||
284 | static struct file_system_type nfs_fs_type = { | 285 | struct 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 | ||
1652 | static struct dentry *nfs_try_mount(int flags, const char *dev_name, | 1653 | static 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 | ||
2300 | struct dentry *nfs_fs_mount_common(struct file_system_type *fs_type, | 2302 | struct 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 | ||
2404 | out: | 2415 | out: |
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"); |
2458 | out: | 2470 | out: |
2459 | return mntroot; | 2471 | return mntroot; |