patch-2.1.117 linux/net/sunrpc/xprt.c

Next file: linux/CREDITS
Previous file: linux/net/sunrpc/sunrpc_syms.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.116/linux/net/sunrpc/xprt.c linux/net/sunrpc/xprt.c
@@ -34,6 +34,7 @@
  *  Copyright (C) 1995, 1996, Olaf Kirch <okir@monad.swb.de>
  *
  *  TCP callback races fixes (C) 1998 Red Hat Software <alan@redhat.com>
+ *  TCP send fixes (C) 1998 Red Hat Software <alan@redhat.com>
  */
 
 #define __KERNEL_SYSCALLS__
@@ -136,8 +137,49 @@
 }
 
 /*
+ *	Adjust the iovec to move on 'n' bytes
+ */
+ 
+extern inline void xprt_move_iov(struct msghdr *msg, int amount)
+{
+	struct iovec niv[MAX_IOVEC];
+	struct iovec *iv=msg->msg_iov;
+	
+	/*
+	 *	Eat any sent iovecs
+	 */
+
+	while(iv->iov_len < amount)
+	{
+		amount-=iv->iov_len;
+		iv++;
+		msg->msg_iovlen--;
+	}
+	
+	msg->msg_iov=niv;
+	
+	/*
+	 *	And chew down the partial one
+	 */
+
+	niv[0].iov_len = iv->iov_len-amount;
+	niv[0].iov_base =((unsigned char *)iv->iov_base)+amount;
+	iv++;
+	
+	/*
+	 *	And copy any others
+	 */
+	 
+	for(amount=1;amount<msg->msg_iovlen; amount++)
+	{
+		niv[amount]=*iv++;
+	}
+}
+ 
+/*
  * Write data to socket.
  */
+
 static inline int
 xprt_sendmsg(struct rpc_xprt *xprt)
 {
@@ -150,7 +192,6 @@
 				xprt->snd_buf.io_vec->iov_base,
 				xprt->snd_buf.io_vec->iov_len);
 
-#if LINUX_VERSION_CODE >= 0x020100
 	msg.msg_flags   = MSG_DONTWAIT;
 	msg.msg_iov	= xprt->snd_buf.io_vec;
 	msg.msg_iovlen	= xprt->snd_buf.io_nr;
@@ -158,27 +199,21 @@
 	msg.msg_namelen = sizeof(xprt->addr);
 	msg.msg_control = NULL;
 
+	/* Dont repeat bytes */
+	
+	if(xprt->snd_sent)
+		xprt_move_iov(&msg, xprt->snd_sent);
+		
 	oldfs = get_fs(); set_fs(get_ds());
 	result = sock_sendmsg(sock, &msg, xprt->snd_buf.io_len);
 	set_fs(oldfs);
-#else
-	msg.msg_flags   = 0;
-	msg.msg_iov	= xprt->snd_buf.io_vec;
-	msg.msg_iovlen	= xprt->snd_buf.io_nr;
-	msg.msg_name	= (struct sockaddr *) &xprt->addr;
-	msg.msg_namelen = sizeof(xprt->addr);
-	msg.msg_control = NULL;
-
-	oldfs = get_fs(); set_fs(get_ds());
-	result = sock->ops->sendmsg(sock, &msg, xprt->snd_buf.io_len, 1, 0);
-	set_fs(oldfs);
-#endif
 
 	dprintk("RPC:      xprt_sendmsg(%d) = %d\n",
 				xprt->snd_buf.io_len, result);
 
 	if (result >= 0) {
 		xprt->snd_buf.io_len -= result;
+		xprt->snd_sent += result;
 		return result;
 	}
 
@@ -188,6 +223,8 @@
 		 * prompts ECONNREFUSED.
 		 */
 		break;
+	case -EAGAIN:
+		return 0;
 	case -ENOTCONN: case -EPIPE:
 		/* connection broken */
 		break;
@@ -828,9 +865,19 @@
 
 	if (!(xprt = xprt_from_sock(sk)))
 		return;
-	xprt->write_space = 1;
-	if (xprt->snd_task && !RPC_IS_RUNNING(xprt->snd_task))
-		rpc_wake_up_task(xprt->snd_task);
+	if(xprt->snd_sent && xprt->snd_task)
+		printk("write space\n");
+	if(xprt->write_space == 0)
+	{
+		xprt->write_space = 1;
+		if (xprt->snd_task && !RPC_IS_RUNNING(xprt->snd_task))
+		{
+			if(xprt->snd_sent)
+				printk("Write wakeup snd_sent =%d\n",
+					xprt->snd_sent);
+			rpc_wake_up_task(xprt->snd_task);			
+		}
+	}
 }
 
 /*
@@ -889,6 +936,8 @@
 	struct rpc_rqst	*req = task->tk_rqstp;
 	struct rpc_xprt	*xprt = req->rq_xprt;
 
+	/*DEBUG*/int ac_debug=xprt->snd_sent;
+	
 	dprintk("RPC: %4d xprt_transmit(%x)\n", task->tk_pid, 
 				*(u32 *)(req->rq_svec[0].iov_base));
 
@@ -935,6 +984,8 @@
 		}
 		xprt->snd_buf  = req->rq_snd_buf;
 		xprt->snd_task = task;
+		xprt->snd_sent = 0;
+		/*DEBUG*/ac_debug = 0;
 	}
 
 	/* For fast networks/servers we have to put the request on
@@ -954,10 +1005,12 @@
 		if (xprt_transmit_some(xprt, task) != -EAGAIN) {
 			dprintk("RPC: %4d xmit complete\n", task->tk_pid);
 			xprt->snd_task = NULL;
+			if(ac_debug)
+				printk("Partial xmit finished\n");
 			return;
 		}
 
-		dprintk("RPC: %4d xmit incomplete (%d left of %d)\n",
+		/*d*/printk("RPC: %4d xmit incomplete (%d left of %d)\n",
 				task->tk_pid, xprt->snd_buf.io_len,
 				req->rq_slen);
 		task->tk_status = 0;
@@ -984,10 +1037,15 @@
 	struct rpc_xprt	*xprt = task->tk_client->cl_xprt;
 
 	dprintk("RPC: %4d transmit_status %d\n", task->tk_pid, task->tk_status);
-	if (xprt->snd_task == task) {
+	if (xprt->snd_task == task) 
+	{
 		if (task->tk_status < 0)
+		{
 			xprt->snd_task = NULL;
-		xprt_disconnect(xprt);
+			xprt_disconnect(xprt);
+		}
+		else
+			xprt_transmit(task);
 	}
 }
 


FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov