In the IPv4 socket transport implementation, RPC buffers are allocated as needed for each RPC message that is sent. Some transport implementations may choose to use pre-allocated buffers for encoding, sending, receiving, and unmarshalling RPC messages. This patch adds RPC client transport switch support for replacing buffer management on a per-transport basis. Patch against 2.6.7. include/linux/sunrpc/sched.h | 6 ++---- include/linux/sunrpc/xprt.h | 16 ++++++++-------- net/sunrpc/clnt.c | 14 ++++++++------ net/sunrpc/sched.c | 35 ++++++++++++++++++----------------- net/sunrpc/sock.c | 5 +++++ net/sunrpc/xprt.c | 3 +++ 6 files changed, 44 insertions(+), 35 deletions(-) Signed-off-by: Chuck Lever Generated-at: Wed, 16 Jun 2004 19:50:57 -0400 diff -X /home/cel/src/linux/dont-diff -Naurp 17-xprt-stream/include/linux/sunrpc/sched.h 18-xprt-buffer/include/linux/sunrpc/sched.h --- 17-xprt-stream/include/linux/sunrpc/sched.h 2004-06-16 01:19:42.000000000 -0400 +++ 18-xprt-buffer/include/linux/sunrpc/sched.h 2004-06-16 13:36:32.063617000 -0400 @@ -43,8 +43,6 @@ struct rpc_task { * RPC call state */ struct rpc_message tk_msg; /* RPC call info */ - __u32 * tk_buffer; /* XDR buffer */ - size_t tk_bufsize; __u8 tk_garb_retry, tk_cred_retry, tk_suid_retry; @@ -219,8 +217,8 @@ void rpc_wake_up(struct rpc_wait_queue struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *); void rpc_wake_up_status(struct rpc_wait_queue *, int); void rpc_delay(struct rpc_task *, unsigned long); -void * rpc_malloc(struct rpc_task *, size_t); -void rpc_free(struct rpc_task *); +fastcall void * rpc_malloc(struct rpc_task *, size_t); +fastcall void rpc_free(struct rpc_task *); int rpciod_up(void); void rpciod_down(void); void rpciod_wake_up(void); diff -X /home/cel/src/linux/dont-diff -Naurp 17-xprt-stream/include/linux/sunrpc/xprt.h 18-xprt-buffer/include/linux/sunrpc/xprt.h --- 17-xprt-stream/include/linux/sunrpc/xprt.h 2004-06-16 13:34:59.075525000 -0400 +++ 18-xprt-buffer/include/linux/sunrpc/xprt.h 2004-06-16 13:36:32.080616000 -0400 @@ -104,17 +104,15 @@ struct rpc_rqst { struct list_head rq_list; - struct xdr_buf rq_private_buf; /* The receive buffer - * used in the softirq. - */ + __u32 * rq_buffer; /* XDR encode buffer */ + size_t rq_bufsize; + struct xdr_buf rq_private_buf; /* The receive buffer + * used in the softirq. */ + unsigned long rq_majortimeo; /* major timeout alarm */ unsigned long rq_timeout; /* Current timeout value */ unsigned int rq_retries; /* # of retries */ - /* - * For authentication (e.g. auth_des) - */ - u32 rq_creddata[2]; - + /* * Partial send handling */ @@ -135,6 +133,8 @@ struct rpc_rqst { struct xprt_procs { void (*setbufsize)(struct rpc_xprt *); void (*connect)(void *); + fastcall void * (*buf_alloc)(struct rpc_task *, size_t); + fastcall void (*buf_free)(struct rpc_task *); fastcall int (*send_request)(struct rpc_task *); void (*close)(struct rpc_xprt *); void (*destroy)(struct rpc_xprt *); diff -X /home/cel/src/linux/dont-diff -Naurp 17-xprt-stream/net/sunrpc/clnt.c 18-xprt-buffer/net/sunrpc/clnt.c --- 17-xprt-stream/net/sunrpc/clnt.c 2004-06-16 13:33:04.699407000 -0400 +++ 18-xprt-buffer/net/sunrpc/clnt.c 2004-06-16 13:36:32.085617000 -0400 @@ -549,24 +549,26 @@ call_reserveresult(struct rpc_task *task /* * 2. Allocate the buffer. For details, see sched.c:rpc_malloc. - * (Note: buffer memory is freed in rpc_task_release). + * (Note: buffer memory is freed in xprt_release). */ static void call_allocate(struct rpc_task *task) { + struct rpc_rqst *req = task->tk_rqstp; + struct rpc_xprt *xprt = task->tk_xprt; unsigned int bufsiz; dprintk("RPC: %4d call_allocate (status %d)\n", task->tk_pid, task->tk_status); task->tk_action = call_bind; - if (task->tk_buffer) + if (req->rq_buffer) return; /* FIXME: compute buffer requirements more exactly using * auth->au_wslack */ bufsiz = task->tk_msg.rpc_proc->p_bufsiz + RPC_SLACK_SPACE; - if (rpc_malloc(task, bufsiz << 1) != NULL) + if (xprt->procs->buf_alloc(task, bufsiz << 1) != NULL) return; printk(KERN_INFO "RPC: buffer allocation failed for task %p\n", task); @@ -599,14 +601,14 @@ call_encode(struct rpc_task *task) task->tk_pid, task->tk_status); /* Default buffer setup */ - bufsiz = task->tk_bufsize >> 1; - sndbuf->head[0].iov_base = (void *)task->tk_buffer; + bufsiz = req->rq_bufsize >> 1; + sndbuf->head[0].iov_base = (void *)req->rq_buffer; sndbuf->head[0].iov_len = bufsiz; sndbuf->tail[0].iov_len = 0; sndbuf->page_len = 0; sndbuf->len = 0; sndbuf->buflen = bufsiz; - rcvbuf->head[0].iov_base = (void *)((char *)task->tk_buffer + bufsiz); + rcvbuf->head[0].iov_base = (void *)((char *)req->rq_buffer + bufsiz); rcvbuf->head[0].iov_len = bufsiz; rcvbuf->tail[0].iov_len = 0; rcvbuf->page_len = 0; diff -X /home/cel/src/linux/dont-diff -Naurp 17-xprt-stream/net/sunrpc/sched.c 18-xprt-buffer/net/sunrpc/sched.c --- 17-xprt-stream/net/sunrpc/sched.c 2004-06-16 01:19:35.000000000 -0400 +++ 18-xprt-buffer/net/sunrpc/sched.c 2004-06-16 13:36:32.091614000 -0400 @@ -726,7 +726,6 @@ __rpc_execute(struct rpc_task *task) /* Release RPC slot and buffer memory */ if (task->tk_rqstp) xprt_release(task); - rpc_free(task); goto restarted; } printk(KERN_ERR "RPC: dead task tries to walk away.\n"); @@ -815,9 +814,10 @@ __rpc_schedule(void) * In order to avoid memory starvation triggering more writebacks of * NFS requests, we use GFP_NOFS rather than GFP_KERNEL. */ -void * +fastcall void * rpc_malloc(struct rpc_task *task, size_t size) { + struct rpc_rqst *req = task->tk_rqstp; int gfp; if (task->tk_flags & RPC_TASK_SWAPPER) @@ -826,27 +826,29 @@ rpc_malloc(struct rpc_task *task, size_t gfp = GFP_NOFS; if (size > RPC_BUFFER_MAXSIZE) { - task->tk_buffer = kmalloc(size, gfp); - if (task->tk_buffer) - task->tk_bufsize = size; + req->rq_buffer = kmalloc(size, gfp); + if (req->rq_buffer) + req->rq_bufsize = size; } else { - task->tk_buffer = mempool_alloc(rpc_buffer_mempool, gfp); - if (task->tk_buffer) - task->tk_bufsize = RPC_BUFFER_MAXSIZE; + req->rq_buffer = mempool_alloc(rpc_buffer_mempool, gfp); + if (req->rq_buffer) + req->rq_bufsize = RPC_BUFFER_MAXSIZE; } - return task->tk_buffer; + return req->rq_buffer; } -void +fastcall void rpc_free(struct rpc_task *task) { - if (task->tk_buffer) { - if (task->tk_bufsize == RPC_BUFFER_MAXSIZE) - mempool_free(task->tk_buffer, rpc_buffer_mempool); + struct rpc_rqst *req = task->tk_rqstp; + + if (req->rq_buffer) { + if (req->rq_bufsize == RPC_BUFFER_MAXSIZE) + mempool_free(req->rq_buffer, rpc_buffer_mempool); else - kfree(task->tk_buffer); - task->tk_buffer = NULL; - task->tk_bufsize = 0; + kfree(req->rq_buffer); + req->rq_buffer = NULL; + req->rq_bufsize = 0; } } @@ -982,7 +984,6 @@ rpc_release_task(struct rpc_task *task) xprt_release(task); if (task->tk_msg.rpc_cred) rpcauth_unbindcred(task); - rpc_free(task); if (task->tk_client) { rpc_release_client(task->tk_client); task->tk_client = NULL; diff -X /home/cel/src/linux/dont-diff -Naurp 17-xprt-stream/net/sunrpc/sock.c 18-xprt-buffer/net/sunrpc/sock.c --- 17-xprt-stream/net/sunrpc/sock.c 2004-06-16 13:34:59.080522000 -0400 +++ 18-xprt-buffer/net/sunrpc/sock.c 2004-06-16 13:36:32.095615000 -0400 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -1212,6 +1213,8 @@ out_clear: static struct xprt_procs xprt_sock_udp_procs = { .setbufsize = xprt_sock_udp_setbufsize, .connect = xprt_sock_udp_connect, + .buf_alloc = rpc_malloc, + .buf_free = rpc_free, .send_request = xprt_sock_udp_send_request, .close = xprt_sock_close, .destroy = xprt_sock_destroy, @@ -1220,6 +1223,8 @@ static struct xprt_procs xprt_sock_udp_p static struct xprt_procs xprt_sock_tcp_procs = { .setbufsize = xprt_sock_tcp_setbufsize, .connect = xprt_sock_tcp_connect, + .buf_alloc = rpc_malloc, + .buf_free = rpc_free, .send_request = xprt_sock_tcp_send_request, .close = xprt_sock_close, .destroy = xprt_sock_destroy, diff -X /home/cel/src/linux/dont-diff -Naurp 17-xprt-stream/net/sunrpc/xprt.c 18-xprt-buffer/net/sunrpc/xprt.c --- 17-xprt-stream/net/sunrpc/xprt.c 2004-06-16 13:34:59.086521000 -0400 +++ 18-xprt-buffer/net/sunrpc/xprt.c 2004-06-16 13:36:32.100614000 -0400 @@ -669,6 +669,8 @@ xprt_request_init(struct rpc_task *task, req->rq_timeout = xprt->timeout.to_initval; req->rq_task = task; req->rq_xprt = xprt; + req->rq_buffer = NULL; + req->rq_bufsize = 0; req->rq_xid = xprt_alloc_xid(xprt); dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid, req, req->rq_xid); @@ -694,6 +696,7 @@ xprt_release(struct rpc_task *task) if (list_empty(&xprt->recv) && !xprt->shutdown) mod_timer(&xprt->timer, xprt->last_used + RPC_IDLE_TIMEOUT); spin_unlock_bh(&xprt->xprt_lock); + xprt->procs->buf_free(task); task->tk_rqstp = NULL; memset(req, 0, sizeof(*req)); /* mark unused */