summaryrefslogtreecommitdiffstats
path: root/net/sunrpc/xprt.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sunrpc/xprt.c')
-rw-r--r--net/sunrpc/xprt.c96
1 files changed, 77 insertions, 19 deletions
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index e2af81be4..4566ce5d2 100644
--- a/net/sunrpc/xprt.c
+++ b/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,48 @@ xprt_from_sock(struct sock *sk)
}
/*
+ * Adjust the iovec to move on 'n' bytes
+ */
+
+extern inline void xprt_move_iov(struct msghdr *msg, struct iovec *niv, int amount)
+{
+ 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)
{
@@ -145,12 +186,12 @@ xprt_sendmsg(struct rpc_xprt *xprt)
struct msghdr msg;
mm_segment_t oldfs;
int result;
+ struct iovec niv[MAX_IOVEC];
xprt_pktdump("packet data:",
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 @@ xprt_sendmsg(struct rpc_xprt *xprt)
msg.msg_namelen = sizeof(xprt->addr);
msg.msg_control = NULL;
+ /* Dont repeat bytes */
+
+ if(xprt->snd_sent)
+ xprt_move_iov(&msg, niv, 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 @@ xprt_sendmsg(struct rpc_xprt *xprt)
* prompts ECONNREFUSED.
*/
break;
+ case -EAGAIN:
+ return 0;
case -ENOTCONN: case -EPIPE:
/* connection broken */
break;
@@ -828,9 +865,19 @@ tcp_write_space(struct sock *sk)
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 @@ xprt_transmit(struct rpc_task *task)
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_transmit(struct rpc_task *task)
}
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 @@ xprt_transmit(struct rpc_task *task)
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 @@ xprt_transmit_status(struct rpc_task *task)
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);
}
}