From: Andreas Gruenbacher <agruen@suse.de>

Allow a clone of an RPC client (created with rpc_clone_client()) to change to
another program.  This allows the NFS and NFSACL programs to share the same
transport.

Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Acked-by: Olaf Kirch <okir@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/include/linux/sunrpc/clnt.h |    3 +++
 25-akpm/net/sunrpc/clnt.c           |   23 +++++++++++++++++++++++
 25-akpm/net/sunrpc/pmap_clnt.c      |    4 ++--
 25-akpm/net/sunrpc/sunrpc_syms.c    |    1 +
 4 files changed, 29 insertions(+), 2 deletions(-)

diff -puN include/linux/sunrpc/clnt.h~nfsacl-allow-multiple-programs-to-share-the-same-transport include/linux/sunrpc/clnt.h
--- 25/include/linux/sunrpc/clnt.h~nfsacl-allow-multiple-programs-to-share-the-same-transport	2005-01-23 01:27:52.312353640 -0800
+++ 25-akpm/include/linux/sunrpc/clnt.h	2005-01-23 01:27:52.320352424 -0800
@@ -22,6 +22,7 @@
  * This defines an RPC port mapping
  */
 struct rpc_portmap {
+	struct rpc_portmap	*pm_parent;
 	__u32			pm_prog;
 	__u32			pm_vers;
 	__u32			pm_prot;
@@ -116,6 +117,8 @@ struct rpc_clnt *rpc_clone_client(struct
 int		rpc_shutdown_client(struct rpc_clnt *);
 int		rpc_destroy_client(struct rpc_clnt *);
 void		rpc_release_client(struct rpc_clnt *);
+void		rpc_change_program(struct rpc_clnt *, struct rpc_program *,
+				   int);
 void		rpc_getport(struct rpc_task *, struct rpc_clnt *);
 int		rpc_register(u32, u32, int, unsigned short, int *);
 
diff -puN net/sunrpc/clnt.c~nfsacl-allow-multiple-programs-to-share-the-same-transport net/sunrpc/clnt.c
--- 25/net/sunrpc/clnt.c~nfsacl-allow-multiple-programs-to-share-the-same-transport	2005-01-23 01:27:52.314353336 -0800
+++ 25-akpm/net/sunrpc/clnt.c	2005-01-23 01:27:52.321352272 -0800
@@ -139,6 +139,7 @@ rpc_create_client(struct rpc_xprt *xprt,
 	clnt->cl_maxproc  = version->nrprocs;
 	clnt->cl_protname = program->name;
 	clnt->cl_pmap	  = &clnt->cl_pmap_default;
+	clnt->cl_pmap->pm_parent = clnt->cl_pmap;
 	clnt->cl_port     = xprt->addr.sin_port;
 	clnt->cl_prog     = program->number;
 	clnt->cl_vers     = version->number;
@@ -207,6 +208,9 @@ rpc_clone_client(struct rpc_clnt *clnt)
 	rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval);
 	if (new->cl_auth)
 		atomic_inc(&new->cl_auth->au_count);
+	new->cl_pmap		= &new->cl_pmap_default;
+	new->cl_pmap->pm_parent = clnt->cl_pmap->pm_parent;
+	rpc_init_wait_queue(&new->cl_pmap_default.pm_bindwait, "bindwait");
 	return new;
 out_no_clnt:
 	printk(KERN_INFO "RPC: out of memory in %s\n", __FUNCTION__);
@@ -296,6 +300,25 @@ rpc_release_client(struct rpc_clnt *clnt
 }
 
 /*
+ * Change the program of a (usually cloned) client
+ */
+void
+rpc_change_program(struct rpc_clnt *clnt, struct rpc_program *program,
+		   int vers)
+{
+	struct rpc_version *version;
+
+	BUG_ON(vers >= program->nrvers || !program->version[vers]);
+	version = program->version[vers];
+	clnt->cl_procinfo = version->procs;
+	clnt->cl_maxproc  = version->nrprocs;
+	clnt->cl_protname = program->name;
+	clnt->cl_prog     = program->number;
+	clnt->cl_vers     = version->number;
+	clnt->cl_stats    = program->stats;
+}
+
+/*
  * Default callback for async RPC calls
  */
 static void
diff -puN net/sunrpc/pmap_clnt.c~nfsacl-allow-multiple-programs-to-share-the-same-transport net/sunrpc/pmap_clnt.c
--- 25/net/sunrpc/pmap_clnt.c~nfsacl-allow-multiple-programs-to-share-the-same-transport	2005-01-23 01:27:52.315353184 -0800
+++ 25-akpm/net/sunrpc/pmap_clnt.c	2005-01-23 01:27:52.322352120 -0800
@@ -41,7 +41,7 @@ static DEFINE_SPINLOCK(pmap_lock);
 void
 rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt)
 {
-	struct rpc_portmap *map = clnt->cl_pmap;
+	struct rpc_portmap *map = clnt->cl_pmap->pm_parent;
 	struct sockaddr_in *sap = &clnt->cl_xprt->addr;
 	struct rpc_message msg = {
 		.rpc_proc	= &pmap_procedures[PMAP_GETPORT],
@@ -132,7 +132,7 @@ static void
 pmap_getport_done(struct rpc_task *task)
 {
 	struct rpc_clnt	*clnt = task->tk_client;
-	struct rpc_portmap *map = clnt->cl_pmap;
+	struct rpc_portmap *map = clnt->cl_pmap->pm_parent;
 
 	dprintk("RPC: %4d pmap_getport_done(status %d, port %d)\n",
 			task->tk_pid, task->tk_status, clnt->cl_port);
diff -puN net/sunrpc/sunrpc_syms.c~nfsacl-allow-multiple-programs-to-share-the-same-transport net/sunrpc/sunrpc_syms.c
--- 25/net/sunrpc/sunrpc_syms.c~nfsacl-allow-multiple-programs-to-share-the-same-transport	2005-01-23 01:27:52.317352880 -0800
+++ 25-akpm/net/sunrpc/sunrpc_syms.c	2005-01-23 01:27:52.322352120 -0800
@@ -42,6 +42,7 @@ EXPORT_SYMBOL(rpc_release_task);
 /* RPC client functions */
 EXPORT_SYMBOL(rpc_create_client);
 EXPORT_SYMBOL(rpc_clone_client);
+EXPORT_SYMBOL(rpc_change_program);
 EXPORT_SYMBOL(rpc_destroy_client);
 EXPORT_SYMBOL(rpc_shutdown_client);
 EXPORT_SYMBOL(rpc_release_client);
_