SUNRPC: add a handful of per-xprt counters

Monitor generic transport events.  Add a transport switch callout to
format transport counters for export to user-land.

Test plan:
Compile kernel with CONFIG_NFS enabled.

Signed-off-by: Chuck Lever <cel@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
Chuck Lever 2006-03-20 13:44:16 -05:00 committed by Trond Myklebust
parent e19b63dafd
commit 262ca07de4
4 changed files with 77 additions and 6 deletions

View File

@ -114,6 +114,7 @@ struct rpc_xprt_ops {
void (*release_request)(struct rpc_task *task); void (*release_request)(struct rpc_task *task);
void (*close)(struct rpc_xprt *xprt); void (*close)(struct rpc_xprt *xprt);
void (*destroy)(struct rpc_xprt *xprt); void (*destroy)(struct rpc_xprt *xprt);
void (*print_stats)(struct rpc_xprt *xprt, struct seq_file *seq);
}; };
struct rpc_xprt { struct rpc_xprt {
@ -187,6 +188,18 @@ struct rpc_xprt {
struct list_head recv; struct list_head recv;
struct {
unsigned long bind_count, /* total number of binds */
connect_count, /* total number of connects */
connect_start, /* connect start timestamp */
connect_time, /* jiffies waiting for connect */
sends, /* how many complete requests */
recvs, /* how many complete requests */
bad_xids; /* lookup_rqst didn't find XID */
unsigned long long req_u, /* average requests on the wire */
bklog_u; /* backlog queue utilization */
} stat;
void (*old_data_ready)(struct sock *, int); void (*old_data_ready)(struct sock *, int);
void (*old_state_change)(struct sock *); void (*old_state_change)(struct sock *);

View File

@ -82,6 +82,7 @@ rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt)
rpc_call_setup(child, &msg, 0); rpc_call_setup(child, &msg, 0);
/* ... and run the child task */ /* ... and run the child task */
task->tk_xprt->stat.bind_count++;
rpc_run_child(task, child, pmap_getport_done); rpc_run_child(task, child, pmap_getport_done);
return; return;

View File

@ -548,6 +548,7 @@ void xprt_connect(struct rpc_task *task)
task->tk_timeout = xprt->connect_timeout; task->tk_timeout = xprt->connect_timeout;
rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL); rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL);
xprt->stat.connect_start = jiffies;
xprt->ops->connect(task); xprt->ops->connect(task);
} }
return; return;
@ -558,6 +559,8 @@ static void xprt_connect_status(struct rpc_task *task)
struct rpc_xprt *xprt = task->tk_xprt; struct rpc_xprt *xprt = task->tk_xprt;
if (task->tk_status >= 0) { 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", dprintk("RPC: %4d xprt_connect_status: connection established\n",
task->tk_pid); task->tk_pid);
return; return;
@ -601,16 +604,14 @@ static void xprt_connect_status(struct rpc_task *task)
struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid) struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid)
{ {
struct list_head *pos; struct list_head *pos;
struct rpc_rqst *req = NULL;
list_for_each(pos, &xprt->recv) { list_for_each(pos, &xprt->recv) {
struct rpc_rqst *entry = list_entry(pos, struct rpc_rqst, rq_list); struct rpc_rqst *entry = list_entry(pos, struct rpc_rqst, rq_list);
if (entry->rq_xid == xid) { if (entry->rq_xid == xid)
req = entry; return entry;
break;
}
} }
return req; xprt->stat.bad_xids++;
return NULL;
} }
/** /**
@ -646,6 +647,7 @@ void xprt_complete_rqst(struct rpc_task *task, int copied)
dprintk("RPC: %5u xid %08x complete (%d bytes received)\n", dprintk("RPC: %5u xid %08x complete (%d bytes received)\n",
task->tk_pid, ntohl(req->rq_xid), copied); task->tk_pid, ntohl(req->rq_xid), copied);
task->tk_xprt->stat.recvs++;
list_del_init(&req->rq_list); list_del_init(&req->rq_list);
req->rq_received = req->rq_private_buf.len = copied; req->rq_received = req->rq_private_buf.len = copied;
rpc_wake_up_task(task); rpc_wake_up_task(task);
@ -744,12 +746,19 @@ void xprt_transmit(struct rpc_task *task)
if (status == 0) { if (status == 0) {
dprintk("RPC: %4d xmit complete\n", task->tk_pid); dprintk("RPC: %4d xmit complete\n", task->tk_pid);
spin_lock_bh(&xprt->transport_lock); spin_lock_bh(&xprt->transport_lock);
xprt->ops->set_retrans_timeout(task); 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 */ /* Don't race with disconnect */
if (!xprt_connected(xprt)) if (!xprt_connected(xprt))
task->tk_status = -ENOTCONN; task->tk_status = -ENOTCONN;
else if (!req->rq_received) else if (!req->rq_received)
rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer); rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer);
xprt->ops->release_xprt(xprt, task); xprt->ops->release_xprt(xprt, task);
spin_unlock_bh(&xprt->transport_lock); spin_unlock_bh(&xprt->transport_lock);
return; return;

View File

@ -1114,6 +1114,8 @@ static void xs_tcp_connect_worker(void *args)
} }
/* Tell the socket layer to start connecting... */ /* Tell the socket layer to start connecting... */
xprt->stat.connect_count++;
xprt->stat.connect_start = jiffies;
status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr, status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr,
sizeof(xprt->addr), O_NONBLOCK); sizeof(xprt->addr), O_NONBLOCK);
dprintk("RPC: %p connect status %d connected %d sock state %d\n", dprintk("RPC: %p connect status %d connected %d sock state %d\n",
@ -1177,6 +1179,50 @@ static void xs_connect(struct rpc_task *task)
} }
} }
/**
* xs_udp_print_stats - display UDP socket-specifc stats
* @xprt: rpc_xprt struct containing statistics
* @seq: output file
*
*/
static void xs_udp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
{
seq_printf(seq, "\txprt:\tudp %u %lu %lu %lu %lu %Lu %Lu\n",
xprt->port,
xprt->stat.bind_count,
xprt->stat.sends,
xprt->stat.recvs,
xprt->stat.bad_xids,
xprt->stat.req_u,
xprt->stat.bklog_u);
}
/**
* xs_tcp_print_stats - display TCP socket-specifc stats
* @xprt: rpc_xprt struct containing statistics
* @seq: output file
*
*/
static void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
{
long idle_time = 0;
if (xprt_connected(xprt))
idle_time = (long)(jiffies - xprt->last_used) / HZ;
seq_printf(seq, "\txprt:\ttcp %u %lu %lu %lu %ld %lu %lu %lu %Lu %Lu\n",
xprt->port,
xprt->stat.bind_count,
xprt->stat.connect_count,
xprt->stat.connect_time,
idle_time,
xprt->stat.sends,
xprt->stat.recvs,
xprt->stat.bad_xids,
xprt->stat.req_u,
xprt->stat.bklog_u);
}
static struct rpc_xprt_ops xs_udp_ops = { static struct rpc_xprt_ops xs_udp_ops = {
.set_buffer_size = xs_udp_set_buffer_size, .set_buffer_size = xs_udp_set_buffer_size,
.reserve_xprt = xprt_reserve_xprt_cong, .reserve_xprt = xprt_reserve_xprt_cong,
@ -1191,6 +1237,7 @@ static struct rpc_xprt_ops xs_udp_ops = {
.release_request = xprt_release_rqst_cong, .release_request = xprt_release_rqst_cong,
.close = xs_close, .close = xs_close,
.destroy = xs_destroy, .destroy = xs_destroy,
.print_stats = xs_udp_print_stats,
}; };
static struct rpc_xprt_ops xs_tcp_ops = { static struct rpc_xprt_ops xs_tcp_ops = {
@ -1204,6 +1251,7 @@ static struct rpc_xprt_ops xs_tcp_ops = {
.set_retrans_timeout = xprt_set_retrans_timeout_def, .set_retrans_timeout = xprt_set_retrans_timeout_def,
.close = xs_close, .close = xs_close,
.destroy = xs_destroy, .destroy = xs_destroy,
.print_stats = xs_tcp_print_stats,
}; };
/** /**