|
@@ -212,3 +212,129 @@ const struct seq_operations rxrpc_connection_seq_ops = {
|
|
|
.stop = rxrpc_connection_seq_stop,
|
|
|
.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,
|
|
|
+};
|