[RFC v2 3/4] NFS: Add functions for adding new NFS versions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Bryan Schumaker <bjschuma@xxxxxxxxxx>

These functions and structures allow us to add modular NFS versions at
runtime, rather than requiring them to be compiled directly into the NFS
kernel module.

Signed-off-by: Bryan Schumaker <bjschuma@xxxxxxxxxx>
---
 fs/nfs/client.c         |   65 +++++++++++++++++++++++++++++++++++++++++++---
 fs/nfs/file.c           |    2 +
 fs/nfs/internal.h       |   15 +++++++++++
 fs/nfs/mount_clnt.c     |    1 +
 fs/nfs/nfs3/nfs3proc.c  |    2 +-
 fs/nfs/nfs4proc.c       |    2 +-
 fs/nfs/proc.c           |    2 +-
 fs/nfs/super.c          |    1 +
 include/linux/nfs_xdr.h |    6 ++--
 9 files changed, 85 insertions(+), 11 deletions(-)

diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index c32a21f..9e77056 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -87,6 +87,21 @@ retry:
 static int nfs4_disable_idmapping = 0;
 
 /*
+ * NFS versions
+ */
+static struct nfs_version_ops *nfs_version_ops[5] = {
+	[2] = NULL,
+	[3] = NULL,
+	[4] = NULL,
+};
+
+static struct nfs_rpc_ops *nfs_ops[5] = {
+	[2]	= &nfs_v2_clientops,
+	[3]	= &nfs_v3_clientops,
+	[4]	= &nfs_v4_clientops,
+};
+
+/*
  * RPC cruft for NFS
  */
 static struct rpc_version *nfs_version[5] = {
@@ -137,6 +152,45 @@ struct nfs_client_initdata {
 	u32 minorversion;
 };
 
+void nfs_register_version(unsigned int version, struct nfs_version_ops *ops)
+{
+	nfs_version_ops[version] = ops;
+	nfs_version[version] = ops->nfs_rpc;
+	nfs_ops[version] = ops->nfs_ops;
+#ifdef CONFIG_NFS_V3_ACL
+	nfsacl_version[version] = ops->nfs_acl;
+#endif
+}
+EXPORT_SYMBOL_GPL(nfs_register_version);
+
+void nfs_unregister_version(unsigned int version)
+{
+	struct nfs_version_ops *ops = nfs_version_ops[version];
+	if (ops != NULL) {
+		nfs_version_ops[version] = NULL;
+		nfs_version[version] = NULL;
+		nfs_ops[version] = NULL;
+#ifdef CONFIG_NFS_V3_ACL
+		nfsacl_version[version] = NULL;
+#endif
+	}
+}
+EXPORT_SYMBOL_GPL(nfs_unregister_version);
+
+void nfs_version_ref(unsigned int version)
+{
+	struct nfs_version_ops *nfs = nfs_version_ops[version];
+	if (nfs != NULL)
+		nfs->version_ref();
+}
+
+void nfs_version_unref(unsigned int version)
+{
+	struct nfs_version_ops *nfs = nfs_version_ops[version];
+	if (nfs != NULL)
+		nfs->version_unref();
+}
+
 /*
  * Allocate a shared client record
  *
@@ -825,7 +879,7 @@ static int nfs_init_server(struct nfs_server *server,
 		.hostname = data->nfs_server.hostname,
 		.addr = (const struct sockaddr *)&data->nfs_server.address,
 		.addrlen = data->nfs_server.addrlen,
-		.rpc_ops = &nfs_v2_clientops,
+		.rpc_ops = nfs_ops[data->version],
 		.proto = data->nfs_server.protocol,
 	};
 	struct rpc_timeout timeparms;
@@ -834,10 +888,10 @@ static int nfs_init_server(struct nfs_server *server,
 
 	dprintk("--> nfs_init_server()\n");
 
-#ifdef CONFIG_NFS_V3
-	if (data->version == 3)
-		cl_init.rpc_ops = &nfs_v3_clientops;
-#endif
+	if (cl_init.rpc_ops == NULL) {
+		error = -EPROTONOSUPPORT;
+		goto out;
+	}
 
 	nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
 			data->timeo, data->retrans);
@@ -899,6 +953,7 @@ static int nfs_init_server(struct nfs_server *server,
 error:
 	server->nfs_client = NULL;
 	nfs_put_client(clp);
+out:
 	dprintk("<-- nfs_init_server() = xerror %d\n", error);
 	return error;
 }
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index eca56d4..90389ca 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -19,6 +19,7 @@
 #include <linux/time.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
+#include <linux/export.h>
 #include <linux/fcntl.h>
 #include <linux/stat.h>
 #include <linux/nfs_fs.h>
@@ -865,6 +866,7 @@ const struct file_operations nfs_file_operations = {
 	.check_flags	= nfs_check_flags,
 	.setlease	= nfs_setlease,
 };
+EXPORT_SYMBOL_GPL(nfs_file_operations);
 
 #ifdef CONFIG_NFS_V4
 static int
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 3f4d957..93a0ba2 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -68,6 +68,21 @@ struct nfs_clone_mount {
 	rpc_authflavor_t authflavor;
 };
 
+struct nfs_version_ops {
+	struct rpc_version *nfs_rpc;
+	struct nfs_rpc_ops *nfs_ops;
+#ifdef CONFIG_NFS_V3_ACL
+	struct rpc_version *nfs_acl;
+#endif
+	void (*version_ref)(void);
+	void (*version_unref)(void);
+};
+
+void nfs_register_version(unsigned int, struct nfs_version_ops *);
+void nfs_unregister_version(unsigned int);
+void nfs_version_ref(unsigned int);
+void nfs_version_unref(unsigned int);
+
 /*
  * Note: RFC 1813 doesn't limit the number of auth flavors that
  * a server can return, so make something up.
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
index d4c2d6b..323a105 100644
--- a/fs/nfs/mount_clnt.c
+++ b/fs/nfs/mount_clnt.c
@@ -190,6 +190,7 @@ int nfs_mount(struct nfs_mount_request *info)
 		goto out_mnt_err;
 
 	dprintk("NFS: MNT request succeeded\n");
+	nfs_version_ref(info->version);
 	status = 0;
 
 out:
diff --git a/fs/nfs/nfs3/nfs3proc.c b/fs/nfs/nfs3/nfs3proc.c
index f37ddb9..593a44c 100644
--- a/fs/nfs/nfs3/nfs3proc.c
+++ b/fs/nfs/nfs3/nfs3proc.c
@@ -848,7 +848,7 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
 	return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl);
 }
 
-const struct nfs_rpc_ops nfs_v3_clientops = {
+struct nfs_rpc_ops nfs_v3_clientops = {
 	.version	= 3,			/* protocol version */
 	.dentry_ops	= &nfs_dentry_operations,
 	.dir_inode_ops	= &nfs3_dir_inode_operations,
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index be2bbac..58bb8d2 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -6247,7 +6247,7 @@ static const struct inode_operations nfs4_file_inode_operations = {
 	.removexattr	= generic_removexattr,
 };
 
-const struct nfs_rpc_ops nfs_v4_clientops = {
+struct nfs_rpc_ops nfs_v4_clientops = {
 	.version	= 4,			/* protocol version */
 	.dentry_ops	= &nfs4_dentry_operations,
 	.dir_inode_ops	= &nfs4_dir_inode_operations,
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index f48125d..d3eb291 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -705,7 +705,7 @@ out_einval:
 	return -EINVAL;
 }
 
-const struct nfs_rpc_ops nfs_v2_clientops = {
+struct nfs_rpc_ops nfs_v2_clientops = {
 	.version	= 2,		       /* protocol version */
 	.dentry_ops	= &nfs_dentry_operations,
 	.dir_inode_ops	= &nfs_dir_inode_operations,
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 1347774..96967ff 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2334,6 +2334,7 @@ static void nfs_kill_super(struct super_block *s)
 
 	kill_anon_super(s);
 	nfs_fscache_release_super_cookie(s);
+	nfs_version_unref(server->nfs_client->rpc_ops->version);
 	nfs_free_server(server);
 }
 
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 2a7c533..6004f5c 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1260,9 +1260,9 @@ struct nfs_rpc_ops {
 /*
  * Function vectors etc. for the NFS client
  */
-extern const struct nfs_rpc_ops	nfs_v2_clientops;
-extern const struct nfs_rpc_ops	nfs_v3_clientops;
-extern const struct nfs_rpc_ops	nfs_v4_clientops;
+extern struct nfs_rpc_ops	nfs_v2_clientops;
+extern struct nfs_rpc_ops	nfs_v3_clientops;
+extern struct nfs_rpc_ops	nfs_v4_clientops;
 extern struct rpc_version	nfs_version2;
 extern struct rpc_version	nfs_version3;
 extern struct rpc_version	nfs_version4;
-- 
1.7.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux