X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fsunrpc%2Fxprt.c;h=7a3999f0a4a2aabc7e156bdb459a68a5cab7d6a7;hb=refs%2Fremotes%2Fvserver;hp=8ff2c8acb22316b00f3bedfb6fc0671276fbdcec;hpb=76828883507a47dae78837ab5dec5a5b4513c667;p=linux-2.6.git diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 8ff2c8acb..7a3999f0a 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -41,16 +41,16 @@ #include #include #include -#include +#include #include +#include /* * Local variables */ #ifdef RPC_DEBUG -# undef RPC_DEBUG_DATA # define RPCDBG_FACILITY RPCDBG_XPRT #endif @@ -459,7 +459,6 @@ int xprt_adjust_timeout(struct rpc_rqst *req) if (to->to_maxval && req->rq_timeout >= to->to_maxval) req->rq_timeout = to->to_maxval; req->rq_retries++; - pprintk("RPC: %lu retrans\n", jiffies); } else { req->rq_timeout = to->to_initval; req->rq_retries = 0; @@ -468,7 +467,6 @@ int xprt_adjust_timeout(struct rpc_rqst *req) spin_lock_bh(&xprt->transport_lock); rpc_init_rtt(req->rq_task->tk_client->cl_rtt, to->to_initval); spin_unlock_bh(&xprt->transport_lock); - pprintk("RPC: %lu timeout\n", jiffies); status = -ETIMEDOUT; } @@ -479,9 +477,10 @@ int xprt_adjust_timeout(struct rpc_rqst *req) return status; } -static void xprt_autoclose(void *args) +static void xprt_autoclose(struct work_struct *work) { - struct rpc_xprt *xprt = (struct rpc_xprt *)args; + struct rpc_xprt *xprt = + container_of(work, struct rpc_xprt, task_cleanup); xprt_disconnect(xprt); xprt->ops->close(xprt); @@ -534,7 +533,7 @@ void xprt_connect(struct rpc_task *task) dprintk("RPC: %4d xprt_connect xprt %p %s connected\n", task->tk_pid, xprt, (xprt_connected(xprt) ? "is" : "is not")); - if (!xprt->addr.sin_port) { + if (!xprt_bound(xprt)) { task->tk_status = -EIO; return; } @@ -548,6 +547,7 @@ void xprt_connect(struct rpc_task *task) task->tk_timeout = xprt->connect_timeout; rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL); + xprt->stat.connect_start = jiffies; xprt->ops->connect(task); } return; @@ -558,6 +558,8 @@ static void xprt_connect_status(struct rpc_task *task) struct rpc_xprt *xprt = task->tk_xprt; if (task->tk_status >= 0) { + xprt->stat.connect_count++; + xprt->stat.connect_time += (long)jiffies - xprt->stat.connect_start; dprintk("RPC: %4d xprt_connect_status: connection established\n", task->tk_pid); return; @@ -582,13 +584,6 @@ static void xprt_connect_status(struct rpc_task *task) task->tk_pid, -task->tk_status, task->tk_client->cl_server); xprt_release_write(xprt, task); task->tk_status = -EIO; - return; - } - - /* if soft mounted, just cause this RPC to fail */ - if (RPC_IS_SOFT(task)) { - xprt_release_write(xprt, task); - task->tk_status = -EIO; } } @@ -598,19 +593,17 @@ static void xprt_connect_status(struct rpc_task *task) * @xid: RPC XID of incoming reply * */ -struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid) +struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid) { struct list_head *pos; - struct rpc_rqst *req = NULL; list_for_each(pos, &xprt->recv) { struct rpc_rqst *entry = list_entry(pos, struct rpc_rqst, rq_list); - if (entry->rq_xid == xid) { - req = entry; - break; - } + if (entry->rq_xid == xid) + return entry; } - return req; + xprt->stat.bad_xids++; + return NULL; } /** @@ -646,7 +639,12 @@ void xprt_complete_rqst(struct rpc_task *task, int copied) dprintk("RPC: %5u xid %08x complete (%d bytes received)\n", task->tk_pid, ntohl(req->rq_xid), copied); + task->tk_xprt->stat.recvs++; + task->tk_rtt = (long)jiffies - req->rq_xtime; + list_del_init(&req->rq_list); + /* Ensure all writes are done before we update req->rq_received */ + smp_wmb(); req->rq_received = req->rq_private_buf.len = copied; rpc_wake_up_task(task); } @@ -701,12 +699,9 @@ out_unlock: return err; } -void -xprt_abort_transmit(struct rpc_task *task) +void xprt_end_transmit(struct rpc_task *task) { - struct rpc_xprt *xprt = task->tk_xprt; - - xprt_release_write(xprt, task); + xprt_release_write(task->tk_xprt, task); } /** @@ -723,7 +718,6 @@ void xprt_transmit(struct rpc_task *task) dprintk("RPC: %4d xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); - smp_rmb(); if (!req->rq_received) { if (list_empty(&req->rq_list)) { spin_lock_bh(&xprt->transport_lock); @@ -744,13 +738,18 @@ void xprt_transmit(struct rpc_task *task) if (status == 0) { dprintk("RPC: %4d xmit complete\n", task->tk_pid); spin_lock_bh(&xprt->transport_lock); + xprt->ops->set_retrans_timeout(task); + + xprt->stat.sends++; + xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs; + xprt->stat.bklog_u += xprt->backlog.qlen; + /* Don't race with disconnect */ if (!xprt_connected(xprt)) task->tk_status = -ENOTCONN; else if (!req->rq_received) rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer); - xprt->ops->release_xprt(xprt, task); spin_unlock_bh(&xprt->transport_lock); return; } @@ -760,18 +759,8 @@ void xprt_transmit(struct rpc_task *task) * schedq, and being picked up by a parallel run of rpciod(). */ task->tk_status = status; - - switch (status) { - case -ECONNREFUSED: + if (status == -ECONNREFUSED) rpc_sleep_on(&xprt->sending, task, NULL, NULL); - case -EAGAIN: - case -ENOTCONN: - return; - default: - break; - } - xprt_release_write(xprt, task); - return; } static inline void do_xprt_reserve(struct rpc_task *task) @@ -811,14 +800,14 @@ void xprt_reserve(struct rpc_task *task) spin_unlock(&xprt->reserve_lock); } -static inline u32 xprt_alloc_xid(struct rpc_xprt *xprt) +static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt) { return xprt->xid++; } static inline void xprt_init_xid(struct rpc_xprt *xprt) { - get_random_bytes(&xprt->xid, sizeof(xprt->xid)); + xprt->xid = net_random(); } static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) @@ -832,6 +821,7 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) req->rq_bufsize = 0; req->rq_xid = xprt_alloc_xid(xprt); req->rq_release_snd_buf = NULL; + xprt_reset_majortimeo(req); dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid, req, ntohl(req->rq_xid)); } @@ -848,6 +838,7 @@ void xprt_release(struct rpc_task *task) if (!(req = task->tk_rqstp)) return; + rpc_count_iostats(task); spin_lock_bh(&xprt->transport_lock); xprt->ops->release_xprt(xprt, task); if (xprt->ops->release_request) @@ -889,48 +880,51 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long i to->to_exponential = 0; } -static struct rpc_xprt *xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to) +/** + * xprt_create_transport - create an RPC transport + * @proto: requested transport protocol + * @ap: remote peer address + * @size: length of address + * @to: timeout parameters + * + */ +struct rpc_xprt *xprt_create_transport(int proto, struct sockaddr *ap, size_t size, struct rpc_timeout *to) { - int result; struct rpc_xprt *xprt; struct rpc_rqst *req; - if ((xprt = kmalloc(sizeof(struct rpc_xprt), GFP_KERNEL)) == NULL) - return ERR_PTR(-ENOMEM); - memset(xprt, 0, sizeof(*xprt)); /* Nnnngh! */ - - xprt->addr = *ap; - switch (proto) { case IPPROTO_UDP: - result = xs_setup_udp(xprt, to); + xprt = xs_setup_udp(ap, size, to); break; case IPPROTO_TCP: - result = xs_setup_tcp(xprt, to); + xprt = xs_setup_tcp(ap, size, to); break; default: printk(KERN_ERR "RPC: unrecognized transport protocol: %d\n", proto); - result = -EIO; - break; + return ERR_PTR(-EIO); } - if (result) { - kfree(xprt); - return ERR_PTR(result); + if (IS_ERR(xprt)) { + dprintk("RPC: xprt_create_transport: failed, %ld\n", + -PTR_ERR(xprt)); + return xprt; } + kref_init(&xprt->kref); spin_lock_init(&xprt->transport_lock); spin_lock_init(&xprt->reserve_lock); INIT_LIST_HEAD(&xprt->free); INIT_LIST_HEAD(&xprt->recv); - INIT_WORK(&xprt->task_cleanup, xprt_autoclose, xprt); + INIT_WORK(&xprt->task_cleanup, xprt_autoclose); init_timer(&xprt->timer); xprt->timer.function = xprt_init_autodisconnect; xprt->timer.data = (unsigned long) xprt; xprt->last_used = jiffies; xprt->cwnd = RPC_INITCWND; + rpc_init_wait_queue(&xprt->binding, "xprt_binding"); rpc_init_wait_queue(&xprt->pending, "xprt_pending"); rpc_init_wait_queue(&xprt->sending, "xprt_sending"); rpc_init_wait_queue(&xprt->resend, "xprt_resend"); @@ -944,41 +938,46 @@ static struct rpc_xprt *xprt_setup(int proto, struct sockaddr_in *ap, struct rpc dprintk("RPC: created transport %p with %u slots\n", xprt, xprt->max_reqs); - + return xprt; } /** - * xprt_create_proto - create an RPC client transport - * @proto: requested transport protocol - * @sap: remote peer's address - * @to: timeout parameters for new transport + * xprt_destroy - destroy an RPC transport, killing off all requests. + * @kref: kref for the transport to destroy * */ -struct rpc_xprt *xprt_create_proto(int proto, struct sockaddr_in *sap, struct rpc_timeout *to) +static void xprt_destroy(struct kref *kref) { - struct rpc_xprt *xprt; + struct rpc_xprt *xprt = container_of(kref, struct rpc_xprt, kref); - xprt = xprt_setup(proto, sap, to); - if (IS_ERR(xprt)) - dprintk("RPC: xprt_create_proto failed\n"); - else - dprintk("RPC: xprt_create_proto created xprt %p\n", xprt); - return xprt; + dprintk("RPC: destroying transport %p\n", xprt); + xprt->shutdown = 1; + del_timer_sync(&xprt->timer); + + /* + * Tear down transport state and free the rpc_xprt + */ + xprt->ops->destroy(xprt); } /** - * xprt_destroy - destroy an RPC transport, killing off all requests. - * @xprt: transport to destroy + * xprt_put - release a reference to an RPC transport. + * @xprt: pointer to the transport * */ -int xprt_destroy(struct rpc_xprt *xprt) +void xprt_put(struct rpc_xprt *xprt) { - dprintk("RPC: destroying transport %p\n", xprt); - xprt->shutdown = 1; - del_timer_sync(&xprt->timer); - xprt->ops->destroy(xprt); - kfree(xprt); + kref_put(&xprt->kref, xprt_destroy); +} - return 0; +/** + * xprt_get - return a reference to an RPC transport. + * @xprt: pointer to the transport + * + */ +struct rpc_xprt *xprt_get(struct rpc_xprt *xprt) +{ + kref_get(&xprt->kref); + return xprt; }