rxrpc: Add /proc/net/rxrpc/peers to display peer list
Add /proc/net/rxrpc/peers to display the list of peers currently active. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
d275444cc3
Коммит
bc0e7cf433
|
@ -1062,6 +1062,7 @@ void rxrpc_put_peer(struct rxrpc_peer *);
|
||||||
*/
|
*/
|
||||||
extern const struct seq_operations rxrpc_call_seq_ops;
|
extern const struct seq_operations rxrpc_call_seq_ops;
|
||||||
extern const struct seq_operations rxrpc_connection_seq_ops;
|
extern const struct seq_operations rxrpc_connection_seq_ops;
|
||||||
|
extern const struct seq_operations rxrpc_peer_seq_ops;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* recvmsg.c
|
* recvmsg.c
|
||||||
|
|
|
@ -102,6 +102,9 @@ static __net_init int rxrpc_init_net(struct net *net)
|
||||||
proc_create_net("conns", 0444, rxnet->proc_net,
|
proc_create_net("conns", 0444, rxnet->proc_net,
|
||||||
&rxrpc_connection_seq_ops,
|
&rxrpc_connection_seq_ops,
|
||||||
sizeof(struct seq_net_private));
|
sizeof(struct seq_net_private));
|
||||||
|
proc_create_net("peers", 0444, rxnet->proc_net,
|
||||||
|
&rxrpc_peer_seq_ops,
|
||||||
|
sizeof(struct seq_net_private));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_proc:
|
err_proc:
|
||||||
|
|
126
net/rxrpc/proc.c
126
net/rxrpc/proc.c
|
@ -212,3 +212,129 @@ const struct seq_operations rxrpc_connection_seq_ops = {
|
||||||
.stop = rxrpc_connection_seq_stop,
|
.stop = rxrpc_connection_seq_stop,
|
||||||
.show = rxrpc_connection_seq_show,
|
.show = rxrpc_connection_seq_show,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* generate a list of extant virtual peers in /proc/net/rxrpc/peers
|
||||||
|
*/
|
||||||
|
static int rxrpc_peer_seq_show(struct seq_file *seq, void *v)
|
||||||
|
{
|
||||||
|
struct rxrpc_peer *peer;
|
||||||
|
time64_t now;
|
||||||
|
char lbuff[50], rbuff[50];
|
||||||
|
|
||||||
|
if (v == SEQ_START_TOKEN) {
|
||||||
|
seq_puts(seq,
|
||||||
|
"Proto Local "
|
||||||
|
" Remote "
|
||||||
|
" Use CW MTU LastUse RTT Rc\n"
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
peer = list_entry(v, struct rxrpc_peer, hash_link);
|
||||||
|
|
||||||
|
sprintf(lbuff, "%pISpc", &peer->local->srx.transport);
|
||||||
|
|
||||||
|
sprintf(rbuff, "%pISpc", &peer->srx.transport);
|
||||||
|
|
||||||
|
now = ktime_get_seconds();
|
||||||
|
seq_printf(seq,
|
||||||
|
"UDP %-47.47s %-47.47s %3u"
|
||||||
|
" %3u %5u %6llus %12llu %2u\n",
|
||||||
|
lbuff,
|
||||||
|
rbuff,
|
||||||
|
atomic_read(&peer->usage),
|
||||||
|
peer->cong_cwnd,
|
||||||
|
peer->mtu,
|
||||||
|
now - peer->last_tx_at,
|
||||||
|
peer->rtt,
|
||||||
|
peer->rtt_cursor);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *rxrpc_peer_seq_start(struct seq_file *seq, loff_t *_pos)
|
||||||
|
__acquires(rcu)
|
||||||
|
{
|
||||||
|
struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
|
||||||
|
unsigned int bucket, n;
|
||||||
|
unsigned int shift = 32 - HASH_BITS(rxnet->peer_hash);
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
|
||||||
|
if (*_pos >= UINT_MAX)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
n = *_pos & ((1U << shift) - 1);
|
||||||
|
bucket = *_pos >> shift;
|
||||||
|
for (;;) {
|
||||||
|
if (bucket >= HASH_SIZE(rxnet->peer_hash)) {
|
||||||
|
*_pos = UINT_MAX;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (n == 0) {
|
||||||
|
if (bucket == 0)
|
||||||
|
return SEQ_START_TOKEN;
|
||||||
|
*_pos += 1;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = seq_hlist_start_rcu(&rxnet->peer_hash[bucket], n - 1);
|
||||||
|
if (p)
|
||||||
|
return p;
|
||||||
|
bucket++;
|
||||||
|
n = 1;
|
||||||
|
*_pos = (bucket << shift) | n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *rxrpc_peer_seq_next(struct seq_file *seq, void *v, loff_t *_pos)
|
||||||
|
{
|
||||||
|
struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
|
||||||
|
unsigned int bucket, n;
|
||||||
|
unsigned int shift = 32 - HASH_BITS(rxnet->peer_hash);
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
if (*_pos >= UINT_MAX)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
bucket = *_pos >> shift;
|
||||||
|
|
||||||
|
p = seq_hlist_next_rcu(v, &rxnet->peer_hash[bucket], _pos);
|
||||||
|
if (p)
|
||||||
|
return p;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
bucket++;
|
||||||
|
n = 1;
|
||||||
|
*_pos = (bucket << shift) | n;
|
||||||
|
|
||||||
|
if (bucket >= HASH_SIZE(rxnet->peer_hash)) {
|
||||||
|
*_pos = UINT_MAX;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (n == 0) {
|
||||||
|
*_pos += 1;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = seq_hlist_start_rcu(&rxnet->peer_hash[bucket], n - 1);
|
||||||
|
if (p)
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rxrpc_peer_seq_stop(struct seq_file *seq, void *v)
|
||||||
|
__releases(rcu)
|
||||||
|
{
|
||||||
|
rcu_read_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const struct seq_operations rxrpc_peer_seq_ops = {
|
||||||
|
.start = rxrpc_peer_seq_start,
|
||||||
|
.next = rxrpc_peer_seq_next,
|
||||||
|
.stop = rxrpc_peer_seq_stop,
|
||||||
|
.show = rxrpc_peer_seq_show,
|
||||||
|
};
|
||||||
|
|
Загрузка…
Ссылка в новой задаче