diff -Nur linux-2.4.22.orig/fs/lockd/host.c linux-2.4.22/fs/lockd/host.c
--- linux-2.4.22.orig/fs/lockd/host.c	2003-08-25 19:44:43.000000000 +0800
+++ linux-2.4.22/fs/lockd/host.c	2003-12-21 15:25:45.000000000 +0800
@@ -26,7 +26,6 @@
 #define NLM_HOST_REBIND		(60 * HZ)
 #define NLM_HOST_EXPIRE		((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ)
 #define NLM_HOST_COLLECT	((nrhosts > NLM_HOST_MAX)? 120 * HZ :  60 * HZ)
-#define NLM_HOST_ADDR(sv)	(&(sv)->s_nlmclnt->cl_xprt->addr)
 
 static struct nlm_host *	nlm_hosts[NLM_HOST_NRHASH];
 static unsigned long		next_gc;
@@ -166,7 +165,6 @@
 nlm_bind_host(struct nlm_host *host)
 {
 	struct rpc_clnt	*clnt;
-	struct rpc_xprt	*xprt;
 
 	dprintk("lockd: nlm_bind_host(%08x)\n",
 			(unsigned)ntohl(host->h_addr.sin_addr.s_addr));
@@ -179,29 +177,23 @@
 	 * Note: why keep rebinding if we're on a tcp connection?
 	 */
 	if ((clnt = host->h_rpcclnt) != NULL) {
-		xprt = clnt->cl_xprt;
-		if (!xprt->stream && time_after_eq(jiffies, host->h_nextrebind)) {
-			clnt->cl_port = 0;
+		if (clnt->cl_prot == IPPROTO_UDP
+				&& time_after_eq(jiffies, host->h_nextrebind)) {
+			rpc_do_rebind(clnt);
 			host->h_nextrebind = jiffies + NLM_HOST_REBIND;
 			dprintk("lockd: next rebind in %ld jiffies\n",
 					host->h_nextrebind - jiffies);
 		}
 	} else {
-		xprt = xprt_create_proto(host->h_proto, &host->h_addr, NULL);
-		if (xprt == NULL)
+		clnt = rpc_create_client(host->h_name, host->h_proto,
+				&host->h_addr, &nlm_program,
+				host->h_version, host->h_authflavor);
+		if (clnt == NULL)
 			goto forgetit;
 
-		xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout);
-
-		clnt = rpc_create_client(xprt, host->h_name, &nlm_program,
-					host->h_version, host->h_authflavor);
-		if (clnt == NULL) {
-			xprt_destroy(xprt);
-			goto forgetit;
-		}
+		// xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout);
 		clnt->cl_autobind = 1;	/* turn on pmap queries */
-		xprt->nocong = 1;	/* No congestion control for NLM */
-		xprt->resvport = 1;	/* NLM requires a reserved port */
+		clnt->cl_resvport = 1;	/* NLM requires a reserved port */
 
 		host->h_rpcclnt = clnt;
 	}
@@ -223,7 +215,7 @@
 {
 	dprintk("lockd: rebind host %s\n", host->h_name);
 	if (host->h_rpcclnt && time_after_eq(jiffies, host->h_nextrebind)) {
-		host->h_rpcclnt->cl_port = 0;
+		rpc_do_rebind(host->h_rpcclnt);
 		host->h_nextrebind = jiffies + NLM_HOST_REBIND;
 	}
 }
diff -Nur linux-2.4.22.orig/fs/lockd/mon.c linux-2.4.22/fs/lockd/mon.c
--- linux-2.4.22.orig/fs/lockd/mon.c	2003-08-25 19:44:43.000000000 +0800
+++ linux-2.4.22/fs/lockd/mon.c	2003-12-21 15:25:45.000000000 +0800
@@ -102,7 +102,6 @@
 static struct rpc_clnt *
 nsm_create(void)
 {
-	struct rpc_xprt		*xprt;
 	struct rpc_clnt		*clnt = NULL;
 	struct sockaddr_in	sin;
 
@@ -110,25 +109,17 @@
 	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 	sin.sin_port = 0;
 
-	xprt = xprt_create_proto(IPPROTO_UDP, &sin, NULL);
-	if (!xprt)
-		goto out;
-
-	clnt = rpc_create_client(xprt, "localhost",
+	clnt = rpc_create_client("localhost", IPPROTO_UDP, &sin,
 				&nsm_program, SM_VERSION,
 				RPC_AUTH_NULL);
 	if (!clnt)
-		goto out_destroy;
+		goto out;
 	clnt->cl_softrtry = 1;
 	clnt->cl_chatty   = 1;
 	clnt->cl_oneshot  = 1;
-	xprt->resvport = 1;	/* NSM requires a reserved port */
+	clnt->cl_resvport = 1;	/* NSM requires a reserved port */
 out:
 	return clnt;
-
-out_destroy:
-	xprt_destroy(xprt);
-	goto out;
 }
 
 /*
diff -Nur linux-2.4.22.orig/fs/nfs/inode.c linux-2.4.22/fs/nfs/inode.c
--- linux-2.4.22.orig/fs/nfs/inode.c	2002-11-29 07:53:15.000000000 +0800
+++ linux-2.4.22/fs/nfs/inode.c	2003-12-21 15:47:43.000000000 +0800
@@ -261,7 +261,6 @@
 {
 	struct nfs_mount_data	*data = (struct nfs_mount_data *) raw_data;
 	struct nfs_server	*server;
-	struct rpc_xprt		*xprt = NULL;
 	struct rpc_clnt		*clnt = NULL;
 	struct nfs_fh		*root = &data->root, fh;
 	struct inode		*root_inode = NULL;
@@ -270,6 +269,7 @@
 	struct rpc_timeout	timeparms;
 	struct nfs_fsinfo	fsinfo;
 	int			tcp, version, maxlen;
+	int			proto;
 
 	memset(&sb->u.nfs_sb, 0, sizeof(sb->u.nfs_sb));
 	if (!data)
@@ -359,12 +359,6 @@
 	if (!timeparms.to_retries)
 		timeparms.to_retries = 5;
 
-	/* Now create transport and client */
-	xprt = xprt_create_proto(tcp? IPPROTO_TCP : IPPROTO_UDP,
-						&srvaddr, &timeparms);
-	if (xprt == NULL)
-		goto out_no_xprt;
-
 	/* Choose authentication flavor */
 	authflavor = RPC_AUTH_UNIX;
 	if (data->flags & NFS_MOUNT_SECURE)
@@ -372,11 +366,18 @@
 	else if (data->flags & NFS_MOUNT_KERBEROS)
 		authflavor = RPC_AUTH_KRB;
 
-	clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
-				 version, authflavor);
-	if (clnt == NULL)
+	proto = tcp? IPPROTO_TCP : IPPROTO_UDP;
+	/* Now create transport and client */
+	clnt = rpc_create_client(server->hostname, proto,
+			&server->addr, &nfs_program,
+			server->rpc_ops->version, authflavor);
+
+	if (clnt == NULL) {
+		printk(KERN_WARNING "NFS: cannot create RPC client.\n");
 		goto out_no_client;
+	}
 
+	rpc_set_timeout(clnt, &timeparms);
 	clnt->cl_intr     = (data->flags & NFS_MOUNT_INTR)? 1 : 0;
 	clnt->cl_softrtry = (data->flags & NFS_MOUNT_SOFT)? 1 : 0;
 	clnt->cl_droppriv = (data->flags & NFS_MOUNT_BROKEN_SUID) ? 1 : 0;
@@ -497,12 +498,8 @@
 
 out_no_client:
 	printk(KERN_WARNING "NFS: cannot create RPC client.\n");
-	xprt_destroy(xprt);
 	goto out_free_host;
 
-out_no_xprt:
-	printk(KERN_WARNING "NFS: cannot create RPC transport.\n");
-
 out_free_host:
 	nfs_reqlist_free(server);
 	kfree(server->hostname);
diff -Nur linux-2.4.22.orig/include/linux/sunrpc/clnt.h linux-2.4.22/include/linux/sunrpc/clnt.h
--- linux-2.4.22.orig/include/linux/sunrpc/clnt.h	2002-11-29 07:53:15.000000000 +0800
+++ linux-2.4.22/include/linux/sunrpc/clnt.h	2003-12-21 15:53:51.000000000 +0800
@@ -38,6 +38,7 @@
 
 	char *			cl_server;	/* server machine name */
 	char *			cl_protname;	/* protocol name */
+	struct sockaddr_in	cl_addr;	/* server address */
 	struct rpc_auth *	cl_auth;	/* authenticator */
 	struct rpc_stat *	cl_stats;	/* statistics */
 
@@ -48,19 +49,22 @@
 				cl_binding  : 1,/* doing a getport() */
 				cl_droppriv : 1,/* enable NFS suid hack */
 				cl_oneshot  : 1,/* dispose after use */
+				cl_resvport : 1,/* use a reserved port */
 				cl_dead     : 1;/* abandoned */
 	unsigned int		cl_flags;	/* misc client flags */
 	unsigned long		cl_hardmax;	/* max hard timeout */
 
 	struct rpc_rtt		cl_rtt;		/* RTO estimator data */
+	struct rpc_timeout      cl_timeout;     /* timeout parms */
 
 	struct rpc_portmap	cl_pmap;	/* port mapping */
 	struct rpc_wait_queue	cl_bindwait;	/* waiting on getport() */
 
 	int			cl_nodelen;	/* nodename length */
 	char 			cl_nodename[UNX_MAXNODENAME];
+
+	rwlock_t                cl_rwlock;
 };
-#define cl_timeout		cl_xprt->timeout
 #define cl_prog			cl_pmap.pm_prog
 #define cl_vers			cl_pmap.pm_vers
 #define cl_port			cl_pmap.pm_port
@@ -108,7 +112,8 @@
 
 #ifdef __KERNEL__
 
-struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname,
+struct rpc_clnt *rpc_create_client(char *servname, int proto,
+				struct sockaddr_in *addr,
 				struct rpc_program *info,
 				u32 version, int authflavor);
 int		rpc_shutdown_client(struct rpc_clnt *);
@@ -127,8 +132,25 @@
 void		rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset);
 void		rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset);
 void		rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);
+void		rpc_set_timeout(struct rpc_clnt *, struct rpc_timeout *);
+
+static inline int rpc_need_rebind(struct rpc_clnt *clnt)
+{
+	if (!clnt->cl_autobind)
+		return 0;
+	smp_rmb();
+	return clnt->cl_addr.sin_port == 0;
+}
+
+static inline void rpc_do_rebind(struct rpc_clnt *clnt)
+{
+	if (clnt->cl_autobind) {
+		clnt->cl_addr.sin_port = 0;
+		smp_wmb();
+	}
+}
 
-static __inline__
+static inline
 int rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags)
 {
 	struct rpc_message msg = { proc, argp, resp, NULL };
diff -Nur linux-2.4.22.orig/include/linux/sunrpc/sched.h linux-2.4.22/include/linux/sunrpc/sched.h
--- linux-2.4.22.orig/include/linux/sunrpc/sched.h	2002-11-29 07:53:15.000000000 +0800
+++ linux-2.4.22/include/linux/sunrpc/sched.h	2003-12-21 15:25:46.000000000 +0800
@@ -40,6 +40,7 @@
 #endif
 	struct list_head	tk_task;	/* global list of tasks */
 	struct rpc_clnt *	tk_client;	/* RPC client */
+	struct rpc_xprt *	tk_xprt;	/* RPC transport */
 	struct rpc_rqst *	tk_rqstp;	/* RPC request */
 	int			tk_status;	/* result of last operation */
 	struct rpc_wait_queue *	tk_rpcwait;	/* RPC wait queue we're on */
@@ -82,7 +83,6 @@
 #endif
 };
 #define tk_auth			tk_client->cl_auth
-#define tk_xprt			tk_client->cl_xprt
 
 /* support walking a list of tasks on a wait queue */
 #define	task_for_each(task, pos, head) \
@@ -121,6 +121,7 @@
 #define RPC_ASSASSINATED(t)	((t)->tk_flags & RPC_TASK_KILLED)
 #define RPC_IS_ACTIVATED(t)	((t)->tk_active)
 #define RPC_DO_CALLBACK(t)	((t)->tk_callback != NULL)
+#define RPC_IS_SOFT(t)		((t)->tk_client->cl_softrtry)
 
 #define RPC_TASK_SLEEPING	0
 #define RPC_TASK_RUNNING	1
diff -Nur linux-2.4.22.orig/include/linux/sunrpc/xprt.h linux-2.4.22/include/linux/sunrpc/xprt.h
--- linux-2.4.22.orig/include/linux/sunrpc/xprt.h	2003-08-25 19:44:44.000000000 +0800
+++ linux-2.4.22/include/linux/sunrpc/xprt.h	2003-12-21 15:25:46.000000000 +0800
@@ -128,10 +128,10 @@
 #define XPRT_COPY_DATA		(1 << 3)
 
 struct rpc_xprt {
+	struct list_head	list;		/* Global list */
 	struct socket *		sock;		/* BSD socket layer */
 	struct sock *		inet;		/* INET layer */
 
-	struct rpc_timeout	timeout;	/* timeout parms */
 	struct sockaddr_in	addr;		/* server address */
 	int			prot;		/* IP protocol */
 
@@ -153,6 +153,8 @@
 				resvport   : 1, /* use a reserved port */
 				stream     : 1;	/* TCP */
 
+	atomic_t		count;
+
 	/*
 	 * State of TCP reply receive stuff
 	 */
@@ -183,8 +185,8 @@
 #ifdef __KERNEL__
 
 struct rpc_xprt *	xprt_create_proto(int proto, struct sockaddr_in *addr,
-					struct rpc_timeout *toparms);
-int			xprt_destroy(struct rpc_xprt *);
+					int resvport);
+void			put_xprt(struct rpc_xprt *);
 void			xprt_shutdown(struct rpc_xprt *);
 void			xprt_default_timeout(struct rpc_timeout *, int);
 void			xprt_set_timeout(struct rpc_timeout *, unsigned int,
@@ -199,12 +201,23 @@
 int			xprt_clear_backlog(struct rpc_xprt *);
 void			xprt_sock_setbufsize(struct rpc_xprt *);
 
+static inline struct rpc_xprt *
+get_xprt(struct rpc_xprt *xprt)
+{
+	if (xprt)
+		atomic_inc(&xprt->count);
+	return xprt;
+}
+
+
 #define XPRT_CONNECT	0
+#define XPRT_DISCONNECT	1
 
 #define xprt_connected(xp)		(test_bit(XPRT_CONNECT, &(xp)->sockstate))
 #define xprt_set_connected(xp)		(set_bit(XPRT_CONNECT, &(xp)->sockstate))
 #define xprt_test_and_set_connected(xp)	(test_and_set_bit(XPRT_CONNECT, &(xp)->sockstate))
-#define xprt_clear_connected(xp)	(clear_bit(XPRT_CONNECT, &(xp)->sockstate))
+#define xprt_set_disconnected(xp)	(set_bit(XPRT_DISCONNECT, &(xp)->sockstate))
+#define xprt_disconnected(xp)		(test_bit(XPRT_DISCONNECT, &(xp)->sockstate))
 
 #endif /* __KERNEL__*/
 
diff -Nur linux-2.4.22.orig/net/sunrpc/clnt.c linux-2.4.22/net/sunrpc/clnt.c
--- linux-2.4.22.orig/net/sunrpc/clnt.c	2003-08-25 19:44:44.000000000 +0800
+++ linux-2.4.22/net/sunrpc/clnt.c	2003-12-23 21:53:27.000000000 +0800
@@ -50,6 +50,7 @@
 static void	call_encode(struct rpc_task *task);
 static void	call_decode(struct rpc_task *task);
 static void	call_bind(struct rpc_task *task);
+static void	call_xprt(struct rpc_task *task);
 static void	call_transmit(struct rpc_task *task);
 static void	call_status(struct rpc_task *task);
 static void	call_refresh(struct rpc_task *task);
@@ -69,21 +70,18 @@
  * made to sleep too long.
  */
 struct rpc_clnt *
-rpc_create_client(struct rpc_xprt *xprt, char *servname,
+rpc_create_client(char *servname, int proto, struct sockaddr_in *addr,
 		  struct rpc_program *program, u32 vers, int flavor)
 {
 	struct rpc_version	*version;
-	struct rpc_clnt		*clnt = NULL;
+	struct rpc_clnt		*clnt;
 
-	dprintk("RPC: creating %s client for %s (xprt %p)\n",
-		program->name, servname, xprt);
+	dprintk("RPC: creating %s client for %s\n", program->name, servname);
 
-	if (!xprt)
-		goto out;
 	if (vers >= program->nrvers || !(version = program->version[vers]))
-		goto out;
+		return NULL;
 
-	clnt = (struct rpc_clnt *) rpc_allocate(0, sizeof(*clnt));
+	clnt = (struct rpc_clnt *)kmalloc(sizeof(*clnt), GFP_KERNEL);
 	if (!clnt)
 		goto out_no_clnt;
 	memset(clnt, 0, sizeof(*clnt));
@@ -94,17 +92,22 @@
 	clnt->cl_maxproc  = version->nrprocs;
 	clnt->cl_server   = servname;
 	clnt->cl_protname = program->name;
-	clnt->cl_port     = xprt->addr.sin_port;
-	clnt->cl_prog     = program->number;
-	clnt->cl_vers     = version->number;
-	clnt->cl_prot     = xprt->prot;
+	memcpy(&clnt->cl_addr, addr, sizeof(clnt->cl_addr));
+	clnt->cl_pmap.pm_port = addr->sin_port;
+	clnt->cl_pmap.pm_prog = program->number;
+	clnt->cl_pmap.pm_vers = version->number;
+	clnt->cl_pmap.pm_prot = proto;
 	clnt->cl_stats    = program->stats;
 	INIT_RPC_WAITQ(&clnt->cl_bindwait, "bindwait");
+	rwlock_init(&clnt->cl_rwlock);
 
-	if (!clnt->cl_port)
+	if (!clnt->cl_addr.sin_port)
 		clnt->cl_autobind = 1;
 
-	rpc_init_rtt(&clnt->cl_rtt, xprt->timeout.to_initval);
+	if (capable(CAP_NET_BIND_SERVICE))
+		clnt->cl_resvport = 1;
+
+	rpc_init_rtt(&clnt->cl_rtt, clnt->cl_timeout.to_initval);
 
 	if (!rpcauth_create(flavor, clnt))
 		goto out_no_auth;
@@ -128,6 +131,13 @@
 	goto out;
 }
 
+void
+rpc_set_timeout(struct rpc_clnt *clnt, struct rpc_timeout *timeout)
+{
+	memcpy(&clnt->cl_timeout, timeout, sizeof(clnt->cl_timeout));
+	rpc_init_rtt(&clnt->cl_rtt, clnt->cl_timeout.to_initval);
+}
+
 /*
  * Properly shut down an RPC client, terminating all outstanding
  * requests. Note that we must be certain that cl_oneshot and
@@ -166,10 +176,6 @@
 		rpcauth_destroy(clnt->cl_auth);
 		clnt->cl_auth = NULL;
 	}
-	if (clnt->cl_xprt) {
-		xprt_destroy(clnt->cl_xprt);
-		clnt->cl_xprt = NULL;
-	}
 	rpc_free(clnt);
 	return 0;
 }
@@ -334,6 +340,7 @@
 void
 rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize)
 {
+#if 0
 	struct rpc_xprt *xprt = clnt->cl_xprt;
 
 	xprt->sndsize = 0;
@@ -343,6 +350,7 @@
 	if (rcvsize)
 		xprt->rcvsize = rcvsize + RPC_SLACK_SPACE;
 	xprt_sock_setbufsize(xprt);
+#endif
 }
 
 /*
@@ -384,11 +392,11 @@
 	/* Increment call count */
 	rpcproc_count(clnt, task->tk_msg.rpc_proc)++;
 	clnt->cl_stats->rpccnt++;
-	task->tk_action = call_reserve;
+	task->tk_action = call_bind;
 }
 
 /*
- * 1.	Reserve an RPC call slot
+ * 2.	Reserve an RPC call slot
  */
 static void
 call_reserve(struct rpc_task *task)
@@ -400,13 +408,18 @@
 		return;
 	}
 
+	if (task->tk_rqstp) {
+		task->tk_action = call_allocate;
+		return;
+	}
+
 	task->tk_status  = 0;
 	task->tk_action  = call_reserveresult;
 	xprt_reserve(task);
 }
 
 /*
- * 1b.	Grok the result of xprt_reserve()
+ * 2b.	Grok the result of xprt_reserve()
  */
 static void
 call_reserveresult(struct rpc_task *task)
@@ -444,6 +457,9 @@
 	}
 
 	switch (status) {
+	case -ENOTCONN:
+		task->tk_action = call_bind;
+		return;
 	case -EAGAIN:	/* woken up; retry */
 		task->tk_action = call_reserve;
 		return;
@@ -458,7 +474,7 @@
 }
 
 /*
- * 2.	Allocate the buffer. For details, see sched.c:rpc_malloc.
+ * 3.	Allocate the buffer. For details, see sched.c:rpc_malloc.
  *	(Note: buffer memory is freed in rpc_task_release).
  */
 static void
@@ -469,7 +485,7 @@
 
 	dprintk("RPC: %4d call_allocate (status %d)\n", 
 				task->tk_pid, task->tk_status);
-	task->tk_action = call_encode;
+	task->tk_action = call_transmit;
 	if (task->tk_buffer)
 		return;
 
@@ -492,7 +508,7 @@
 }
 
 /*
- * 3.	Encode arguments of an RPC call
+ * 4.	Encode arguments of an RPC call
  */
 static void
 call_encode(struct rpc_task *task)
@@ -541,40 +557,94 @@
 }
 
 /*
- * 4.	Get the server port number if not yet set
+ * 1.	Get the server port number if not yet set
  */
 static void
 call_bind(struct rpc_task *task)
 {
 	struct rpc_clnt	*clnt = task->tk_client;
-	struct rpc_xprt *xprt = clnt->cl_xprt;
+	int status = task->tk_status;
 
-	dprintk("RPC: %4d call_bind xprt %p %s connected\n", task->tk_pid,
-			xprt, (xprt_connected(xprt) ? "is" : "is not"));
+	dprintk("RPC: %4d call_bind\n", task->tk_pid);
 
 	task->tk_action = (xprt_connected(xprt)) ? call_transmit : call_connect;
 
-	if (!clnt->cl_port) {
-		task->tk_action = call_connect;
-		task->tk_timeout = clnt->cl_timeout.to_maxval;
-		rpc_getport(task, clnt);
+	task->tk_status = 0;
+	if (rpc_need_rebind(clnt)) {
+		if (status >= 0 || !RPC_IS_SOFT(task)) {
+			task->tk_timeout = RPC_CONNECT_TIMEOUT;
+			rpc_getport(task, clnt);
+		} else
+			rpc_exit(task, -EIO);
+		}
+	} else
+		task->tk_action = call_xprt;
+}
+
+/*
+ * 1a.  Bind the task to the current RPC transport
+ */
+static void call_xprt(struct rpc_task *task)
+{
+	struct rpc_clnt *clnt = task->tk_client;
+	struct rpc_xprt *new, *xprt;
+	struct sockaddr_in addr;
+
+	/* Check the common case: the client has a valid RPC transport */
+	read_lock(&clnt->cl_rwlock);
+	xprt = get_xprt(clnt->cl_xprt);
+	read_unlock(&clnt->cl_rwlock);
+	if (likely(xprt != NULL)) {
+		if (!xprt_disconnected(xprt))
+			goto out;
+		put_xprt(xprt);
+	}
+
+	/* Sigh... We need to create and install a new RPC transport */
+	memcpy(&addr, &clnt->cl_addr, sizeof(addr));
+	/* Hey, has someone asked us to bind to a new port too? */
+	if (addr.sin_port == 0) {
+		task->tk_action = call_bind;
+		return;
+	}
+	new = xprt_create_proto(clnt->cl_prot, &addr, clnt->cl_resvport);
+	if (new == NULL) {
+		rpc_exit(task, -EIO);
+		return;
 	}
+	write_lock(&clnt->cl_rwlock);
+	xprt = clnt->cl_xprt;
+	if (xprt == NULL || xprt_disconnected(xprt)) {
+		clnt->cl_xprt = new;
+		new = xprt;
+	}
+	xprt = get_xprt(clnt->cl_xprt);
+	write_unlock(&clnt->cl_rwlock);
+	if (new != NULL)
+		put_xprt(new);
+out:
+	if (task->tk_xprt) {
+		/* Release the old slot if the transports differ */
+		if (unlikely(xprt != task->tk_xprt))
+			xprt_release(task);
+		else
+			put_xprt(xprt);
+	}
+	task->tk_xprt = xprt;
+	task->tk_action = call_connect;
 }
 
 /*
- * 4a.	Establish socket
- *	Connect to the RPC server (TCP case)
+ * 1b.	Connect to the RPC server (TCP case)
  */
 static void
 call_connect(struct rpc_task *task)
 {
-	struct rpc_clnt *clnt = task->tk_client;
-
 	dprintk("RPC: %4d call_connect status %d\n",
 				task->tk_pid, task->tk_status);
 
-	if (xprt_connected(clnt->cl_xprt)) {
-		task->tk_action = call_transmit;
+	if (xprt_connected(task->tk_xprt)) {
+		task->tk_action = call_reserve;
 		return;
 	}
 	task->tk_action = call_connect_status;
@@ -584,9 +654,10 @@
 }
 
 /*
- * 4b.	Sort out reconnection result
+ * 1c.	Sort out reconnection result
  */
-static void call_connect_status(struct rpc_task *task)
+static void
+call_connect_status(struct rpc_task *task)
 {
 	struct rpc_clnt *clnt = task->tk_client;
 	int status = task->tk_status;
@@ -594,21 +665,25 @@
 	task->tk_status = 0;
 	if (status >= 0) {
 		clnt->cl_stats->netreconn++;
-		task->tk_action = call_transmit;
+		task->tk_action = call_reserve;
 		return;
 	}
 
 	/* Something failed: we may have to rebind */
-	if (clnt->cl_autobind)
-		clnt->cl_port = 0;
+	rpc_do_rebind(clnt);
 	switch (status) {
 	case -ECONNREFUSED:
 	case -ECONNRESET:
 	case -ENOTCONN:
 	case -ETIMEDOUT:
 	case -EAGAIN:
-		task->tk_action = (clnt->cl_port == 0) ? call_bind : call_connect;
-		break;
+		if (!RPC_IS_SOFT(task)) {
+			if (rpc_need_rebind(clnt))
+				task->tk_action = call_bind;
+			else
+				task->tk_action = call_xprt;
+			break;
+		}
 	default:
 		rpc_exit(task, status);
 	}
@@ -666,19 +741,9 @@
 		break;
 	case -ECONNREFUSED:
 	case -ENOTCONN:
-		req->rq_bytes_sent = 0;
-		if (clnt->cl_autobind || !clnt->cl_port) {
-			clnt->cl_port = 0;
-			task->tk_action = call_bind;
-			break;
-		}
-		task->tk_action = call_connect;
+		rpc_do_rebind(clnt);
+		task->tk_action = call_bind;
 		break;
-		/*
-		 * Sleep and dream of an open connection
-		 */
-		task->tk_timeout = 5 * HZ;
-		rpc_sleep_on(&xprt->sending, task, NULL, NULL);
 	case -ENOMEM:
 	case -EAGAIN:
 		task->tk_action = call_transmit;
@@ -709,8 +774,8 @@
 	to->to_retries = clnt->cl_timeout.to_retries;
 
 	dprintk("RPC: %4d call_timeout (major)\n", task->tk_pid);
-	if (clnt->cl_softrtry) {
-		if (clnt->cl_chatty)
+	if (RPC_IS_SOFT(task)) {
+		if (clnt->cl_chatty && !task->tk_exit)
 			printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
 				clnt->cl_protname, clnt->cl_server);
 		rpc_exit(task, -EIO);
@@ -722,8 +787,7 @@
 		printk(KERN_NOTICE "%s: server %s not responding, still trying\n",
 			clnt->cl_protname, clnt->cl_server);
 	}
-	if (clnt->cl_autobind)
-		clnt->cl_port = 0;
+	rpc_do_rebind(clnt);
 
 retry:
 	clnt->cl_stats->rpcretrans++;
@@ -752,7 +816,7 @@
 	}
 
 	if (task->tk_status < 12) {
-		if (!clnt->cl_softrtry) {
+		if (!RPC_IS_SOFT(task)) {
 			task->tk_action = call_transmit;
 			clnt->cl_stats->rpcretrans++;
 			goto out_retry;
@@ -834,7 +898,7 @@
 	if (task->tk_status < 0)
 		rpc_exit(task, -EACCES);
 	else
-		task->tk_action = call_reserve;
+		task->tk_action = call_bind;
 }
 
 /*
@@ -844,7 +908,7 @@
 call_header(struct rpc_task *task)
 {
 	struct rpc_clnt *clnt = task->tk_client;
-	struct rpc_xprt *xprt = clnt->cl_xprt;
+	struct rpc_xprt *xprt = task->tk_xprt;
 	struct rpc_rqst	*req = task->tk_rqstp;
 	u32		*p = req->rq_svec[0].iov_base;
 
diff -Nur linux-2.4.22.orig/net/sunrpc/pmap_clnt.c linux-2.4.22/net/sunrpc/pmap_clnt.c
--- linux-2.4.22.orig/net/sunrpc/pmap_clnt.c	2002-08-03 08:39:46.000000000 +0800
+++ linux-2.4.22/net/sunrpc/pmap_clnt.c	2003-12-21 17:29:54.000000000 +0800
@@ -31,7 +31,6 @@
 static struct rpc_clnt *	pmap_create(char *, struct sockaddr_in *, int);
 static void			pmap_getport_done(struct rpc_task *);
 extern struct rpc_program	pmap_program;
-static spinlock_t		pmap_lock = SPIN_LOCK_UNLOCKED;
 
 /*
  * Obtain the port for a given RPC service on a given host. This one can
@@ -41,8 +40,7 @@
 rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt)
 {
 	struct rpc_portmap *map = &clnt->cl_pmap;
-	struct sockaddr_in *sap = &clnt->cl_xprt->addr;
-	struct rpc_message msg = { PMAP_GETPORT, map, &clnt->cl_port, NULL };
+	struct rpc_message msg = { PMAP_GETPORT, map, &clnt->pm_port, NULL };
 	struct rpc_clnt	*pmap_clnt;
 	struct rpc_task	*child;
 
@@ -50,18 +48,19 @@
 			task->tk_pid, clnt->cl_server,
 			map->pm_prog, map->pm_vers, map->pm_prot);
 
-	spin_lock(&pmap_lock);
+	write_lock(&clnt->cl_rwlock);
 	if (clnt->cl_binding) {
 		rpc_sleep_on(&clnt->cl_bindwait, task, NULL, 0);
-		spin_unlock(&pmap_lock);
+		write_unlock(&clnt->cl_rwlock);
 		return;
 	}
 	clnt->cl_binding = 1;
-	spin_unlock(&pmap_lock);
+	write_unlock(&clnt->cl_rwlock);
 
 	task->tk_status = -EACCES; /* why set this? returns -EIO below */
 	if (!(pmap_clnt = pmap_create(clnt->cl_server, sap, map->pm_prot)))
 		goto bailout;
+	pmap_clnt->cl_resvport = 0;
 	task->tk_status = 0;
 
 	/*
@@ -78,10 +77,10 @@
 	return;
 
 bailout:
-	spin_lock(&pmap_lock);
+	write_lock(&clnt->cl_rwlock);
 	clnt->cl_binding = 0;
+	write_unlock(&clnt->cl_rwlock);
 	rpc_wake_up(&clnt->cl_bindwait);
-	spin_unlock(&pmap_lock);
 	task->tk_status = -EIO;
 	task->tk_action = NULL;
 }
@@ -101,6 +100,7 @@
 	sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(sin->sin_addr.s_addr));
 	if (!(pmap_clnt = pmap_create(hostname, sin, prot)))
 		return -EACCES;
+	pmap_clnt->cl_resvport = 0;
 
 	/* Setup the call info struct */
 	status = rpc_call(pmap_clnt, PMAP_GETPORT, &map, &map.pm_port, 0);
@@ -118,25 +118,34 @@
 pmap_getport_done(struct rpc_task *task)
 {
 	struct rpc_clnt	*clnt = task->tk_client;
+	struct rpc_portmap *map = &clnt->cl_pmap;
+	struct rpc_xprt *xprt;
 
 	dprintk("RPC: %4d pmap_getport_done(status %d, port %d)\n",
-			task->tk_pid, task->tk_status, clnt->cl_port);
+			task->tk_pid, task->tk_status, map->pm_port);
+	write_lock(&clnt->cl_rwlock);
 	if (task->tk_status < 0) {
 		/* Make the calling task exit with an error */
 		task->tk_action = NULL;
-	} else if (clnt->cl_port == 0) {
+	} else if (map->pm_port == 0) {
 		/* Program not registered */
 		task->tk_status = -EACCES;
 		task->tk_action = NULL;
 	} else {
 		/* byte-swap port number first */
-		clnt->cl_port = htons(clnt->cl_port);
-		clnt->cl_xprt->addr.sin_port = clnt->cl_port;
+		clnt->cl_addr.sin_port = htons(map->pm_port);
+		wmb();
 	}
-	spin_lock(&pmap_lock);
+	xprt = clnt->cl_xprt;
+	if (xprt && xprt->addr.sin_port != clnt->cl_addr.sin_port)
+		clnt->cl_xprt = NULL;
+	else
+		xprt = NULL;
 	clnt->cl_binding = 0;
+	write_unlock(&clnt->cl_rwlock);
 	rpc_wake_up(&clnt->cl_bindwait);
-	spin_unlock(&pmap_lock);
+	if (xprt)
+		put_xprt(xprt);
 }
 
 /*
@@ -183,21 +192,13 @@
 static struct rpc_clnt *
 pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto)
 {
-	struct rpc_xprt	*xprt;
 	struct rpc_clnt	*clnt;
 
-	/* printk("pmap: create xprt\n"); */
-	if (!(xprt = xprt_create_proto(proto, srvaddr, NULL)))
-		return NULL;
-	xprt->addr.sin_port = htons(RPC_PMAP_PORT);
-
-	/* printk("pmap: create clnt\n"); */
-	clnt = rpc_create_client(xprt, hostname,
+	clnt = rpc_create_client(hostname, proto, srvaddr,
 				&pmap_program, RPC_PMAP_VERSION,
 				RPC_AUTH_NULL);
-	if (!clnt) {
-		xprt_destroy(xprt);
-	} else {
+	if (clnt) {
+		clnt->cl_addr.sin_port = htons(RPC_PMAP_PORT);
 		clnt->cl_softrtry = 1;
 		clnt->cl_chatty   = 1;
 		clnt->cl_oneshot  = 1;
diff -Nur linux-2.4.22.orig/net/sunrpc/sunrpc_syms.c linux-2.4.22/net/sunrpc/sunrpc_syms.c
--- linux-2.4.22.orig/net/sunrpc/sunrpc_syms.c	2003-06-13 22:51:39.000000000 +0800
+++ linux-2.4.22/net/sunrpc/sunrpc_syms.c	2003-12-21 17:32:12.000000000 +0800
@@ -50,11 +50,11 @@
 EXPORT_SYMBOL(rpc_delay);
 EXPORT_SYMBOL(rpc_restart_call);
 EXPORT_SYMBOL(rpc_setbufsize);
+EXPORT_SYMBOL(rpc_set_timeout);
 
 /* Client transport */
 EXPORT_SYMBOL(xprt_create_proto);
-EXPORT_SYMBOL(xprt_destroy);
-EXPORT_SYMBOL(xprt_set_timeout);
+EXPORT_SYMBOL(put_xprt);
 
 /* Client credential cache */
 EXPORT_SYMBOL(rpcauth_register);
diff -Nur linux-2.4.22.orig/net/sunrpc/xprt.c linux-2.4.22/net/sunrpc/xprt.c
--- linux-2.4.22.orig/net/sunrpc/xprt.c	2003-08-25 19:44:44.000000000 +0800
+++ linux-2.4.22/net/sunrpc/xprt.c	2003-12-21 22:27:53.000000000 +0800
@@ -86,10 +86,16 @@
 static inline void	do_xprt_reserve(struct rpc_task *);
 static void	xprt_disconnect(struct rpc_xprt *);
 static void	xprt_connect_status(struct rpc_task *task);
-static struct socket *xprt_create_socket(int, struct rpc_timeout *, int);
+static struct rpc_xprt * xprt_setup(int proto, struct sockaddr_in *ap,
+						int resvport);
+static struct socket *xprt_create_socket(int, int);
 static int	xprt_bind_socket(struct rpc_xprt *, struct socket *);
 static int      __xprt_get_cong(struct rpc_xprt *, struct rpc_task *);
 
+/* Global list of xprt structs */
+static LIST_HEAD(all_xprts);
+static spinlock_t xprt_global_lock = SPIN_LOCK_UNLOCKED;
+
 #ifdef RPC_DEBUG_DATA
 /*
  * Print the buffer contents (first 128 bytes only--just enough for
@@ -138,11 +144,16 @@
 static int
 __xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task)
 {
+	if (xprt_disconnected(xprt)) {
+		task->tk_status = -ENOTCONN;
+		return 0;
+	}
 	if (!xprt->snd_task) {
 		if (xprt->nocong || __xprt_get_cong(xprt, task)) {
+			struct rpc_rqst *req = task->tk_rqstp;
+			if (req)
+				req->rq_bytes_sent = 0;
 			xprt->snd_task = task;
-			if (task->tk_rqstp)
-				task->tk_rqstp->rq_bytes_sent = 0;
 		}
 	}
 	if (xprt->snd_task != task) {
@@ -183,9 +194,10 @@
 			return;
 	}
 	if (xprt->nocong || __xprt_get_cong(xprt, task)) {
+		struct rpc_rqst *req = task->tk_rqstp;
+		if (req)
+			req->rq_bytes_sent = 0;
 		xprt->snd_task = task;
-		if (task->tk_rqstp)
-			task->tk_rqstp->rq_bytes_sent = 0;
 	}
 }
 
@@ -404,7 +416,6 @@
 	sk->write_space  = xprt->old_write_space;
 	write_unlock_bh(&sk->callback_lock);
 
-	xprt_disconnect(xprt);
 	sk->no_check	 = 0;
 
 	sock_release(sock);
@@ -418,8 +429,10 @@
 {
 	dprintk("RPC:      disconnected transport %p\n", xprt);
 	spin_lock_bh(&xprt->sock_lock);
-	xprt_clear_connected(xprt);
+	xprt_set_disconnected(xprt);
 	rpc_wake_up_status(&xprt->pending, -ENOTCONN);
+	rpc_wake_up_status(&xprt->sending, -ENOTCONN);
+	rpc_wake_up_status(&xprt->resend, -ENOTCONN);
 	spin_unlock_bh(&xprt->sock_lock);
 }
 
@@ -449,21 +462,6 @@
 		return;
 	if (xprt_connected(xprt))
 		goto out_write;
-
-	if (task->tk_rqstp)
-		task->tk_rqstp->rq_bytes_sent = 0;
-
-	xprt_close(xprt);
-	/* Create an unconnected socket */
-	sock = xprt_create_socket(xprt->prot, &xprt->timeout, xprt->resvport);
-	if (!sock) {
-		/* couldn't create socket or bind to reserved port;
-		 * this is likely a permanent error, so cause an abort */
-		task->tk_status = -EIO;
-		goto out_write;
-	}
-	xprt_bind_socket(xprt, sock);
-
 	if (!xprt->stream)
 		goto out_write;
 
@@ -489,7 +487,7 @@
 					task->tk_pid);
 			task->tk_timeout = RPC_CONNECT_TIMEOUT;
 			/* if the socket is already closing, delay briefly */
-			if ((1<<inet->state) & ~(TCPF_SYN_SENT|TCPF_SYN_RECV))
+			if (xprt_disconnected(xprt))
 				task->tk_timeout = RPC_REESTABLISH_TIMEOUT;
 			rpc_sleep_on(&xprt->pending, task, xprt_connect_status,
 					NULL);
@@ -499,7 +497,7 @@
 	case -ECONNREFUSED:
 	case -ECONNRESET:
 	case -ENOTCONN:
-		if (!task->tk_client->cl_softrtry) {
+		if (!RPC_IS_SOFT(task)) {
 			rpc_delay(task, RPC_REESTABLISH_TIMEOUT);
 			task->tk_status = -ENOTCONN;
 			break;
@@ -507,7 +505,7 @@
 	default:
 		/* Report myriad other possible returns.  If this file
 		 * system is soft mounted, just error out, like Solaris.  */
-		if (task->tk_client->cl_softrtry) {
+		if (RPC_IS_SOFT(task)) {
 			printk(KERN_WARNING
 					"RPC: error %d connecting to server %s, exiting\n",
 					-status, task->tk_client->cl_server);
@@ -541,7 +539,7 @@
 	}
 
 	/* if soft mounted, cause this RPC to fail */
-	if (task->tk_client->cl_softrtry)
+	if (RPC_IS_SOFT(task))
 		task->tk_status = -EIO;
 
 	switch (task->tk_status) {
@@ -994,12 +992,10 @@
 			rpc_wake_up_task(xprt->snd_task);
 		spin_unlock_bh(&xprt->sock_lock);
 		break;
-	case TCP_SYN_SENT:
-	case TCP_SYN_RECV:
-		break;
-	default:
+	case TCP_CLOSING:
+	case TCP_CLOSE_WAIT:
+	case TCP_CLOSE:
 		xprt_disconnect(xprt);
-		break;
 	}
  out:
 	if (sk->sleep && waitqueue_active(sk->sleep))
@@ -1181,6 +1177,9 @@
 	 * Note, though, that we can't do this if we've already started
 	 * resending down a TCP stream.
 	 */
+	if (req->rq_received && !req->rq_bytes_sent)
+		goto out_release;
+
 	task->tk_status = status;
 
 	switch (status) {
@@ -1189,7 +1188,7 @@
 			/* Protect against races with xprt_write_space */
 			spin_lock_bh(&xprt->sock_lock);
 			/* Don't race with disconnect */
-			if (!xprt_connected(xprt))
+			if (xprt_disconnected(xprt))
 				task->tk_status = -ENOTCONN;
 			else if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) {
 				task->tk_timeout = req->rq_timeout.to_current;
@@ -1210,6 +1209,7 @@
 		if (xprt->stream)
 			xprt_disconnect(xprt);
 	}
+out_release:
 	xprt_release_write(xprt, task);
 	return;
  out_receive:
@@ -1226,7 +1226,7 @@
 	} else
 		task->tk_timeout = req->rq_timeout.to_current;
 	/* Don't race with disconnect */
-	if (!xprt_connected(xprt))
+	if (xprt_disconnected(xprt))
 		task->tk_status = -ENOTCONN;
 	else if (!req->rq_received)
 		rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer);
@@ -1301,7 +1301,7 @@
 {
 	struct rpc_rqst	*req = task->tk_rqstp;
 
-	req->rq_timeout = xprt->timeout;
+	memcpy(&req->rq_timeout, &task->tk_client->cl_timeout, sizeof(req->rq_timeout));
 	req->rq_task	= task;
 	req->rq_xprt    = xprt;
 	req->rq_xid     = xprt_alloc_xid();
@@ -1319,8 +1319,10 @@
 	struct rpc_xprt	*xprt = task->tk_xprt;
 	struct rpc_rqst	*req;
 
-	if (!(req = task->tk_rqstp))
+	if (!xprt)
 		return;
+	if (!(req = task->tk_rqstp))
+		goto out;
 	spin_lock_bh(&xprt->sock_lock);
 	__xprt_release_write(xprt, task);
 	__xprt_put_cong(xprt, req);
@@ -1338,6 +1340,9 @@
 
 	xprt_clear_backlog(xprt);
 	spin_unlock(&xprt->xprt_lock);
+out:
+	put_xprt(xprt);
+	task->tk_xprt = NULL;
 }
 
 /*
@@ -1366,14 +1371,35 @@
 	to->to_exponential = 0;
 }
 
+struct rpc_xprt *
+__xprt_find(int proto, struct sockaddr_in *ap, int resvport)
+{
+	struct rpc_xprt *xprt;
+
+	list_for_each_entry(xprt, &all_xprts, list) {
+		if (xprt_disconnected(xprt))
+			continue;
+		if (proto != xprt->prot)
+			continue;
+		if (memcmp(&xprt->addr, ap, sizeof(xprt->addr)))
+			continue;
+		if (resvport != xprt->resvport)
+			continue;
+		atomic_inc(&xprt->count);
+		return xprt;
+	}
+	return NULL;
+}
+
 /*
  * Initialize an RPC client
  */
 static struct rpc_xprt *
-xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to)
+xprt_setup(int proto, struct sockaddr_in *ap, int resvport)
 {
 	struct rpc_xprt	*xprt;
 	struct rpc_rqst	*req;
+	struct socket *sock;
 	int		i;
 
 	dprintk("RPC:      setting up %s transport...\n",
@@ -1383,7 +1409,7 @@
 		return NULL;
 	memset(xprt, 0, sizeof(*xprt)); /* Nnnngh! */
 
-	xprt->addr = *ap;
+	memcpy(&xprt->addr, ap, sizeof(xprt->addr));
 	xprt->prot = proto;
 	xprt->stream = (proto == IPPROTO_TCP)? 1 : 0;
 	if (xprt->stream) {
@@ -1395,14 +1421,10 @@
 	spin_lock_init(&xprt->xprt_lock);
 	init_waitqueue_head(&xprt->cong_wait);
 
-	INIT_LIST_HEAD(&xprt->recv);
+	atomic_set(&xprt->count, 1);
 
-	/* Set timeout parameters */
-	if (to) {
-		xprt->timeout = *to;
-		xprt->timeout.to_current = to->to_initval;
-	} else
-		xprt_default_timeout(&xprt->timeout, xprt->prot);
+	INIT_LIST_HEAD(&xprt->list);
+	INIT_LIST_HEAD(&xprt->recv);
 
 	INIT_RPC_WAITQ(&xprt->pending, "xprt_pending");
 	INIT_RPC_WAITQ(&xprt->sending, "xprt_sending");
@@ -1415,12 +1437,20 @@
 	req->rq_next = NULL;
 	xprt->free = xprt->slot;
 
-	/* Check whether we want to use a reserved port */
-	xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
+	xprt->resvport = resvport;
+
+	/* Create the socket */
+	sock = xprt_create_socket(xprt->prot, resvport);
+	if (!sock)
+		goto out_nosock;
+	xprt_bind_socket(xprt, sock);
 
 	dprintk("RPC:      created transport %p\n", xprt);
 	
 	return xprt;
+out_nosock:
+	kfree(xprt);
+	return NULL;
 }
 
 /*
@@ -1476,7 +1506,6 @@
 		tp->nonagle = 1;	/* disable Nagle's algorithm */
 		sk->data_ready = tcp_data_ready;
 		sk->state_change = tcp_state_change;
-		xprt_clear_connected(xprt);
 	}
 	sk->write_space = xprt_write_space;
 
@@ -1513,7 +1542,7 @@
  * Create a client socket given the protocol and peer address.
  */
 static struct socket *
-xprt_create_socket(int proto, struct rpc_timeout *to, int resvport)
+xprt_create_socket(int proto, int resvport)
 {
 	struct socket	*sock;
 	int		type, err;
@@ -1543,14 +1572,31 @@
  * Create an RPC client transport given the protocol and peer address.
  */
 struct rpc_xprt *
-xprt_create_proto(int proto, struct sockaddr_in *sap, struct rpc_timeout *to)
+xprt_create_proto(int proto, struct sockaddr_in *sap, int resvport)
 {
-	struct rpc_xprt	*xprt;
+	struct rpc_xprt	*xprt, *new_xprt = NULL;
 
-	xprt = xprt_setup(proto, sap, to);
-	if (!xprt)
-		goto out_bad;
+	spin_lock(&xprt_global_lock);
+	do {
+		xprt = __xprt_find(proto, sap, resvport);
+		if (xprt)
+			break;
 
+		if (!new_xprt) {
+			spin_unlock(&xprt_global_lock);
+			new_xprt = xprt_setup(proto, sap, resvport);
+			if (!new_xprt)
+				goto out_bad;
+			spin_lock(&xprt_global_lock);
+			continue;
+		}
+		list_add(&new_xprt->list, &all_xprts);
+		xprt = new_xprt;
+		new_xprt = NULL;
+	} while (xprt == NULL);
+	spin_unlock(&xprt_global_lock);
+	if (new_xprt)
+		put_xprt(new_xprt);
 	dprintk("RPC:      xprt_create_proto created xprt %p\n", xprt);
 	return xprt;
 out_bad:
@@ -1587,15 +1633,18 @@
 }
 
 /*
- * Destroy an RPC transport, killing off all requests.
+ * Release an RPC transport.
  */
-int
-xprt_destroy(struct rpc_xprt *xprt)
+void
+put_xprt(struct rpc_xprt *xprt)
 {
+	if (!atomic_dec_and_lock(&xprt->count, &xprt_global_lock))
+		return;
+	if (!list_empty(&xprt->list))
+		list_del(&xprt->list);
+	spin_unlock(&xprt_global_lock);
 	dprintk("RPC:      destroying transport %p\n", xprt);
 	xprt_shutdown(xprt);
 	xprt_close(xprt);
 	kfree(xprt);
-
-	return 0;
 }
