diff options
Diffstat (limited to 'net/rxrpc/proc.c')
-rw-r--r-- | net/rxrpc/proc.c | 617 |
1 files changed, 617 insertions, 0 deletions
diff --git a/net/rxrpc/proc.c b/net/rxrpc/proc.c new file mode 100644 index 000000000000..3b5ecd8e2401 --- /dev/null +++ b/net/rxrpc/proc.c @@ -0,0 +1,617 @@ +/* proc.c: /proc interface for RxRPC + * + * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include <rxrpc/rxrpc.h> +#include <rxrpc/transport.h> +#include <rxrpc/peer.h> +#include <rxrpc/connection.h> +#include <rxrpc/call.h> +#include <rxrpc/message.h> +#include "internal.h" + +static struct proc_dir_entry *proc_rxrpc; + +static int rxrpc_proc_transports_open(struct inode *inode, struct file *file); +static void *rxrpc_proc_transports_start(struct seq_file *p, loff_t *pos); +static void *rxrpc_proc_transports_next(struct seq_file *p, void *v, loff_t *pos); +static void rxrpc_proc_transports_stop(struct seq_file *p, void *v); +static int rxrpc_proc_transports_show(struct seq_file *m, void *v); + +static struct seq_operations rxrpc_proc_transports_ops = { + .start = rxrpc_proc_transports_start, + .next = rxrpc_proc_transports_next, + .stop = rxrpc_proc_transports_stop, + .show = rxrpc_proc_transports_show, +}; + +static struct file_operations rxrpc_proc_transports_fops = { + .open = rxrpc_proc_transports_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rxrpc_proc_peers_open(struct inode *inode, struct file *file); +static void *rxrpc_proc_peers_start(struct seq_file *p, loff_t *pos); +static void *rxrpc_proc_peers_next(struct seq_file *p, void *v, loff_t *pos); +static void rxrpc_proc_peers_stop(struct seq_file *p, void *v); +static int rxrpc_proc_peers_show(struct seq_file *m, void *v); + +static struct seq_operations rxrpc_proc_peers_ops = { + .start = rxrpc_proc_peers_start, + .next = rxrpc_proc_peers_next, + .stop = rxrpc_proc_peers_stop, + .show = rxrpc_proc_peers_show, +}; + +static struct file_operations rxrpc_proc_peers_fops = { + .open = rxrpc_proc_peers_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rxrpc_proc_conns_open(struct inode *inode, struct file *file); +static void *rxrpc_proc_conns_start(struct seq_file *p, loff_t *pos); +static void *rxrpc_proc_conns_next(struct seq_file *p, void *v, loff_t *pos); +static void rxrpc_proc_conns_stop(struct seq_file *p, void *v); +static int rxrpc_proc_conns_show(struct seq_file *m, void *v); + +static struct seq_operations rxrpc_proc_conns_ops = { + .start = rxrpc_proc_conns_start, + .next = rxrpc_proc_conns_next, + .stop = rxrpc_proc_conns_stop, + .show = rxrpc_proc_conns_show, +}; + +static struct file_operations rxrpc_proc_conns_fops = { + .open = rxrpc_proc_conns_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rxrpc_proc_calls_open(struct inode *inode, struct file *file); +static void *rxrpc_proc_calls_start(struct seq_file *p, loff_t *pos); +static void *rxrpc_proc_calls_next(struct seq_file *p, void *v, loff_t *pos); +static void rxrpc_proc_calls_stop(struct seq_file *p, void *v); +static int rxrpc_proc_calls_show(struct seq_file *m, void *v); + +static struct seq_operations rxrpc_proc_calls_ops = { + .start = rxrpc_proc_calls_start, + .next = rxrpc_proc_calls_next, + .stop = rxrpc_proc_calls_stop, + .show = rxrpc_proc_calls_show, +}; + +static struct file_operations rxrpc_proc_calls_fops = { + .open = rxrpc_proc_calls_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static const char *rxrpc_call_states7[] = { + "complet", + "error ", + "rcv_op ", + "rcv_arg", + "got_arg", + "snd_rpl", + "fin_ack", + "snd_arg", + "rcv_rpl", + "got_rpl" +}; + +static const char *rxrpc_call_error_states7[] = { + "no_err ", + "loc_abt", + "rmt_abt", + "loc_err", + "rmt_err" +}; + +/*****************************************************************************/ +/* + * initialise the /proc/net/rxrpc/ directory + */ +int rxrpc_proc_init(void) +{ + struct proc_dir_entry *p; + + proc_rxrpc = proc_mkdir("rxrpc", proc_net); + if (!proc_rxrpc) + goto error; + proc_rxrpc->owner = THIS_MODULE; + + p = create_proc_entry("calls", 0, proc_rxrpc); + if (!p) + goto error_proc; + p->proc_fops = &rxrpc_proc_calls_fops; + p->owner = THIS_MODULE; + + p = create_proc_entry("connections", 0, proc_rxrpc); + if (!p) + goto error_calls; + p->proc_fops = &rxrpc_proc_conns_fops; + p->owner = THIS_MODULE; + + p = create_proc_entry("peers", 0, proc_rxrpc); + if (!p) + goto error_calls; + p->proc_fops = &rxrpc_proc_peers_fops; + p->owner = THIS_MODULE; + + p = create_proc_entry("transports", 0, proc_rxrpc); + if (!p) + goto error_conns; + p->proc_fops = &rxrpc_proc_transports_fops; + p->owner = THIS_MODULE; + + return 0; + + error_conns: + remove_proc_entry("connections", proc_rxrpc); + error_calls: + remove_proc_entry("calls", proc_rxrpc); + error_proc: + remove_proc_entry("rxrpc", proc_net); + error: + return -ENOMEM; +} /* end rxrpc_proc_init() */ + +/*****************************************************************************/ +/* + * clean up the /proc/net/rxrpc/ directory + */ +void rxrpc_proc_cleanup(void) +{ + remove_proc_entry("transports", proc_rxrpc); + remove_proc_entry("peers", proc_rxrpc); + remove_proc_entry("connections", proc_rxrpc); + remove_proc_entry("calls", proc_rxrpc); + + remove_proc_entry("rxrpc", proc_net); + +} /* end rxrpc_proc_cleanup() */ + +/*****************************************************************************/ +/* + * open "/proc/net/rxrpc/transports" which provides a summary of extant transports + */ +static int rxrpc_proc_transports_open(struct inode *inode, struct file *file) +{ + struct seq_file *m; + int ret; + + ret = seq_open(file, &rxrpc_proc_transports_ops); + if (ret < 0) + return ret; + + m = file->private_data; + m->private = PDE(inode)->data; + + return 0; +} /* end rxrpc_proc_transports_open() */ + +/*****************************************************************************/ +/* + * set up the iterator to start reading from the transports list and return the first item + */ +static void *rxrpc_proc_transports_start(struct seq_file *m, loff_t *_pos) +{ + struct list_head *_p; + loff_t pos = *_pos; + + /* lock the list against modification */ + down_read(&rxrpc_proc_transports_sem); + + /* allow for the header line */ + if (!pos) + return SEQ_START_TOKEN; + pos--; + + /* find the n'th element in the list */ + list_for_each(_p, &rxrpc_proc_transports) + if (!pos--) + break; + + return _p != &rxrpc_proc_transports ? _p : NULL; +} /* end rxrpc_proc_transports_start() */ + +/*****************************************************************************/ +/* + * move to next call in transports list + */ +static void *rxrpc_proc_transports_next(struct seq_file *p, void *v, loff_t *pos) +{ + struct list_head *_p; + + (*pos)++; + + _p = v; + _p = (v == SEQ_START_TOKEN) ? rxrpc_proc_transports.next : _p->next; + + return _p != &rxrpc_proc_transports ? _p : NULL; +} /* end rxrpc_proc_transports_next() */ + +/*****************************************************************************/ +/* + * clean up after reading from the transports list + */ +static void rxrpc_proc_transports_stop(struct seq_file *p, void *v) +{ + up_read(&rxrpc_proc_transports_sem); + +} /* end rxrpc_proc_transports_stop() */ + +/*****************************************************************************/ +/* + * display a header line followed by a load of call lines + */ +static int rxrpc_proc_transports_show(struct seq_file *m, void *v) +{ + struct rxrpc_transport *trans = + list_entry(v, struct rxrpc_transport, proc_link); + + /* display header on line 1 */ + if (v == SEQ_START_TOKEN) { + seq_puts(m, "LOCAL USE\n"); + return 0; + } + + /* display one transport per line on subsequent lines */ + seq_printf(m, "%5hu %3d\n", + trans->port, + atomic_read(&trans->usage) + ); + + return 0; +} /* end rxrpc_proc_transports_show() */ + +/*****************************************************************************/ +/* + * open "/proc/net/rxrpc/peers" which provides a summary of extant peers + */ +static int rxrpc_proc_peers_open(struct inode *inode, struct file *file) +{ + struct seq_file *m; + int ret; + + ret = seq_open(file, &rxrpc_proc_peers_ops); + if (ret < 0) + return ret; + + m = file->private_data; + m->private = PDE(inode)->data; + + return 0; +} /* end rxrpc_proc_peers_open() */ + +/*****************************************************************************/ +/* + * set up the iterator to start reading from the peers list and return the + * first item + */ +static void *rxrpc_proc_peers_start(struct seq_file *m, loff_t *_pos) +{ + struct list_head *_p; + loff_t pos = *_pos; + + /* lock the list against modification */ + down_read(&rxrpc_peers_sem); + + /* allow for the header line */ + if (!pos) + return SEQ_START_TOKEN; + pos--; + + /* find the n'th element in the list */ + list_for_each(_p, &rxrpc_peers) + if (!pos--) + break; + + return _p != &rxrpc_peers ? _p : NULL; +} /* end rxrpc_proc_peers_start() */ + +/*****************************************************************************/ +/* + * move to next conn in peers list + */ +static void *rxrpc_proc_peers_next(struct seq_file *p, void *v, loff_t *pos) +{ + struct list_head *_p; + + (*pos)++; + + _p = v; + _p = (v == SEQ_START_TOKEN) ? rxrpc_peers.next : _p->next; + + return _p != &rxrpc_peers ? _p : NULL; +} /* end rxrpc_proc_peers_next() */ + +/*****************************************************************************/ +/* + * clean up after reading from the peers list + */ +static void rxrpc_proc_peers_stop(struct seq_file *p, void *v) +{ + up_read(&rxrpc_peers_sem); + +} /* end rxrpc_proc_peers_stop() */ + +/*****************************************************************************/ +/* + * display a header line followed by a load of conn lines + */ +static int rxrpc_proc_peers_show(struct seq_file *m, void *v) +{ + struct rxrpc_peer *peer = list_entry(v, struct rxrpc_peer, proc_link); + signed long timeout; + + /* display header on line 1 */ + if (v == SEQ_START_TOKEN) { + seq_puts(m, "LOCAL REMOTE USAGE CONNS TIMEOUT" + " MTU RTT(uS)\n"); + return 0; + } + + /* display one peer per line on subsequent lines */ + timeout = 0; + if (!list_empty(&peer->timeout.link)) + timeout = (signed long) peer->timeout.timo_jif - + (signed long) jiffies; + + seq_printf(m, "%5hu %08x %5d %5d %8ld %5Zu %7lu\n", + peer->trans->port, + ntohl(peer->addr.s_addr), + atomic_read(&peer->usage), + atomic_read(&peer->conn_count), + timeout, + peer->if_mtu, + (long) peer->rtt + ); + + return 0; +} /* end rxrpc_proc_peers_show() */ + +/*****************************************************************************/ +/* + * open "/proc/net/rxrpc/connections" which provides a summary of extant + * connections + */ +static int rxrpc_proc_conns_open(struct inode *inode, struct file *file) +{ + struct seq_file *m; + int ret; + + ret = seq_open(file, &rxrpc_proc_conns_ops); + if (ret < 0) + return ret; + + m = file->private_data; + m->private = PDE(inode)->data; + + return 0; +} /* end rxrpc_proc_conns_open() */ + +/*****************************************************************************/ +/* + * set up the iterator to start reading from the conns list and return the + * first item + */ +static void *rxrpc_proc_conns_start(struct seq_file *m, loff_t *_pos) +{ + struct list_head *_p; + loff_t pos = *_pos; + + /* lock the list against modification */ + down_read(&rxrpc_conns_sem); + + /* allow for the header line */ + if (!pos) + return SEQ_START_TOKEN; + pos--; + + /* find the n'th element in the list */ + list_for_each(_p, &rxrpc_conns) + if (!pos--) + break; + + return _p != &rxrpc_conns ? _p : NULL; +} /* end rxrpc_proc_conns_start() */ + +/*****************************************************************************/ +/* + * move to next conn in conns list + */ +static void *rxrpc_proc_conns_next(struct seq_file *p, void *v, loff_t *pos) +{ + struct list_head *_p; + + (*pos)++; + + _p = v; + _p = (v == SEQ_START_TOKEN) ? rxrpc_conns.next : _p->next; + + return _p != &rxrpc_conns ? _p : NULL; +} /* end rxrpc_proc_conns_next() */ + +/*****************************************************************************/ +/* + * clean up after reading from the conns list + */ +static void rxrpc_proc_conns_stop(struct seq_file *p, void *v) +{ + up_read(&rxrpc_conns_sem); + +} /* end rxrpc_proc_conns_stop() */ + +/*****************************************************************************/ +/* + * display a header line followed by a load of conn lines + */ +static int rxrpc_proc_conns_show(struct seq_file *m, void *v) +{ + struct rxrpc_connection *conn; + signed long timeout; + + conn = list_entry(v, struct rxrpc_connection, proc_link); + + /* display header on line 1 */ + if (v == SEQ_START_TOKEN) { + seq_puts(m, + "LOCAL REMOTE RPORT SRVC CONN END SERIALNO " + "CALLNO MTU TIMEOUT" + "\n"); + return 0; + } + + /* display one conn per line on subsequent lines */ + timeout = 0; + if (!list_empty(&conn->timeout.link)) + timeout = (signed long) conn->timeout.timo_jif - + (signed long) jiffies; + + seq_printf(m, + "%5hu %08x %5hu %04hx %08x %-3.3s %08x %08x %5Zu %8ld\n", + conn->trans->port, + ntohl(conn->addr.sin_addr.s_addr), + ntohs(conn->addr.sin_port), + ntohs(conn->service_id), + ntohl(conn->conn_id), + conn->out_clientflag ? "CLT" : "SRV", + conn->serial_counter, + conn->call_counter, + conn->mtu_size, + timeout + ); + + return 0; +} /* end rxrpc_proc_conns_show() */ + +/*****************************************************************************/ +/* + * open "/proc/net/rxrpc/calls" which provides a summary of extant calls + */ +static int rxrpc_proc_calls_open(struct inode *inode, struct file *file) +{ + struct seq_file *m; + int ret; + + ret = seq_open(file, &rxrpc_proc_calls_ops); + if (ret < 0) + return ret; + + m = file->private_data; + m->private = PDE(inode)->data; + + return 0; +} /* end rxrpc_proc_calls_open() */ + +/*****************************************************************************/ +/* + * set up the iterator to start reading from the calls list and return the + * first item + */ +static void *rxrpc_proc_calls_start(struct seq_file *m, loff_t *_pos) +{ + struct list_head *_p; + loff_t pos = *_pos; + + /* lock the list against modification */ + down_read(&rxrpc_calls_sem); + + /* allow for the header line */ + if (!pos) + return SEQ_START_TOKEN; + pos--; + + /* find the n'th element in the list */ + list_for_each(_p, &rxrpc_calls) + if (!pos--) + break; + + return _p != &rxrpc_calls ? _p : NULL; +} /* end rxrpc_proc_calls_start() */ + +/*****************************************************************************/ +/* + * move to next call in calls list + */ +static void *rxrpc_proc_calls_next(struct seq_file *p, void *v, loff_t *pos) +{ + struct list_head *_p; + + (*pos)++; + + _p = v; + _p = (v == SEQ_START_TOKEN) ? rxrpc_calls.next : _p->next; + + return _p != &rxrpc_calls ? _p : NULL; +} /* end rxrpc_proc_calls_next() */ + +/*****************************************************************************/ +/* + * clean up after reading from the calls list + */ +static void rxrpc_proc_calls_stop(struct seq_file *p, void *v) +{ + up_read(&rxrpc_calls_sem); + +} /* end rxrpc_proc_calls_stop() */ + +/*****************************************************************************/ +/* + * display a header line followed by a load of call lines + */ +static int rxrpc_proc_calls_show(struct seq_file *m, void *v) +{ + struct rxrpc_call *call = list_entry(v, struct rxrpc_call, call_link); + + /* display header on line 1 */ + if (v == SEQ_START_TOKEN) { + seq_puts(m, + "LOCAL REMOT SRVC CONN CALL DIR USE " + " L STATE OPCODE ABORT ERRNO\n" + ); + return 0; + } + + /* display one call per line on subsequent lines */ + seq_printf(m, + "%5hu %5hu %04hx %08x %08x %s %3u%c" + " %c %-7.7s %6d %08x %5d\n", + call->conn->trans->port, + ntohs(call->conn->addr.sin_port), + ntohs(call->conn->service_id), + ntohl(call->conn->conn_id), + ntohl(call->call_id), + call->conn->service ? "SVC" : "CLT", + atomic_read(&call->usage), + waitqueue_active(&call->waitq) ? 'w' : ' ', + call->app_last_rcv ? 'Y' : '-', + (call->app_call_state!=RXRPC_CSTATE_ERROR ? + rxrpc_call_states7[call->app_call_state] : + rxrpc_call_error_states7[call->app_err_state]), + call->app_opcode, + call->app_abort_code, + call->app_errno + ); + + return 0; +} /* end rxrpc_proc_calls_show() */ |