diff options
Diffstat (limited to 'net/sunrpc/xprt.c')
-rw-r--r-- | net/sunrpc/xprt.c | 96 |
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); } } |