1 // SPDX-License-Identifier: GPL-2.0
3 /* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
5 * Copyright (c) 2011, 2017, Intel Corporation.
8 /* This file is part of Lustre, http://www.lustre.org/ */
10 #define DEBUG_SUBSYSTEM S_LNET
12 #include <linux/uaccess.h>
14 #include <libcfs/libcfs.h>
15 #include <lnet/lib-lnet.h>
17 #define LNET_LOFFT_BITS (sizeof(loff_t) * 8)
18 /* NB: max allowed LNET_CPT_BITS is 8 on 64-bit system and 2 on 32-bit system
20 #define LNET_PROC_CPT_BITS (LNET_CPT_BITS + 1)
21 /* change version, 16 bits or 8 bits */
22 #define LNET_PROC_VER_BITS \
23 clamp_t(int, LNET_LOFFT_BITS / 4, 8, 16)
25 #define LNET_PROC_HASH_BITS LNET_PEER_HASH_BITS
26 /* bits for peer hash offset
27 * NB: we don't use the highest bit of *ppos because it's signed
29 #define LNET_PROC_HOFF_BITS (LNET_LOFFT_BITS - \
30 LNET_PROC_CPT_BITS - \
31 LNET_PROC_VER_BITS - \
32 LNET_PROC_HASH_BITS - 1)
33 /* bits for hash index + position */
34 #define LNET_PROC_HPOS_BITS (LNET_PROC_HASH_BITS + LNET_PROC_HOFF_BITS)
35 /* bits for peer hash table + hash version */
36 #define LNET_PROC_VPOS_BITS (LNET_PROC_HPOS_BITS + LNET_PROC_VER_BITS)
38 #define LNET_PROC_CPT_MASK ((1ULL << LNET_PROC_CPT_BITS) - 1)
39 #define LNET_PROC_VER_MASK ((1ULL << LNET_PROC_VER_BITS) - 1)
40 #define LNET_PROC_HASH_MASK ((1ULL << LNET_PROC_HASH_BITS) - 1)
41 #define LNET_PROC_HOFF_MASK ((1ULL << LNET_PROC_HOFF_BITS) - 1)
43 #define LNET_PROC_CPT_GET(pos) \
44 (int)(((pos) >> LNET_PROC_VPOS_BITS) & LNET_PROC_CPT_MASK)
46 #define LNET_PROC_VER_GET(pos) \
47 (int)(((pos) >> LNET_PROC_HPOS_BITS) & LNET_PROC_VER_MASK)
49 #define LNET_PROC_HASH_GET(pos) \
50 (int)(((pos) >> LNET_PROC_HOFF_BITS) & LNET_PROC_HASH_MASK)
52 #define LNET_PROC_HOFF_GET(pos) \
53 (int)((pos) & LNET_PROC_HOFF_MASK)
55 #define LNET_PROC_POS_MAKE(cpt, ver, hash, off) \
56 (((((loff_t)(cpt)) & LNET_PROC_CPT_MASK) << LNET_PROC_VPOS_BITS) | \
57 ((((loff_t)(ver)) & LNET_PROC_VER_MASK) << LNET_PROC_HPOS_BITS) | \
58 ((((loff_t)(hash)) & LNET_PROC_HASH_MASK) << LNET_PROC_HOFF_BITS) | \
59 ((off) & LNET_PROC_HOFF_MASK))
61 #define LNET_PROC_VERSION(v) ((unsigned int)((v) & LNET_PROC_VER_MASK))
63 static int proc_cpt_table(struct ctl_table *table, int write,
64 void __user *buffer, size_t *lenp, loff_t *ppos)
76 LIBCFS_ALLOC(buf, len);
80 rc = cfs_cpt_table_print(cfs_cpt_tab, buf, len);
85 LIBCFS_FREE(buf, len);
97 rc = cfs_trace_copyout_string(buffer, nob, buf + pos, NULL);
100 LIBCFS_FREE(buf, len);
104 static int proc_cpt_distance(struct ctl_table *table, int write,
105 void __user *buffer, size_t *lenp, loff_t *ppos)
117 LIBCFS_ALLOC(buf, len);
121 rc = cfs_cpt_distance_print(cfs_cpt_tab, buf, len);
126 LIBCFS_FREE(buf, len);
138 rc = cfs_trace_copyout_string(buffer, nob, buf + pos, NULL);
141 LIBCFS_FREE(buf, len);
145 static int proc_lnet_stats(struct ctl_table *table, int write,
146 void __user *buffer, size_t *lenp, loff_t *ppos)
149 struct lnet_counters *ctrs;
150 struct lnet_counters_common common;
154 char tmpstr[256]; /* 7 %u and 4 u64 */
157 lnet_counters_reset();
163 LIBCFS_ALLOC(ctrs, sizeof(*ctrs));
167 rc = lnet_counters_get(ctrs);
171 common = ctrs->lct_common;
173 len = scnprintf(tmpstr, sizeof(tmpstr),
174 "%u %u %u %u %u %u %u %llu %llu "
176 common.lcc_msgs_alloc, common.lcc_msgs_max,
178 common.lcc_send_count, common.lcc_recv_count,
179 common.lcc_route_count, common.lcc_drop_count,
180 common.lcc_send_length, common.lcc_recv_length,
181 common.lcc_route_length, common.lcc_drop_length);
186 rc = cfs_trace_copyout_string(buffer, nob,
189 LIBCFS_FREE(ctrs, sizeof(*ctrs));
194 proc_lnet_routes(struct ctl_table *table, int write, void __user *buffer,
195 size_t *lenp, loff_t *ppos)
197 const int tmpsiz = 256;
205 BUILD_BUG_ON(sizeof(loff_t) < 4);
207 off = LNET_PROC_HOFF_GET(*ppos);
208 ver = LNET_PROC_VER_GET(*ppos);
215 LIBCFS_ALLOC(tmpstr, tmpsiz);
219 s = tmpstr; /* points to current position in tmpstr[] */
222 s += scnprintf(s, tmpstr + tmpsiz - s, "Routing %s\n",
223 the_lnet.ln_routing ? "enabled" : "disabled");
224 LASSERT(tmpstr + tmpsiz - s > 0);
226 s += scnprintf(s, tmpstr + tmpsiz - s, "%-8s %4s %8s %7s %s\n",
227 "net", "hops", "priority", "state", "router");
228 LASSERT(tmpstr + tmpsiz - s > 0);
231 ver = (unsigned int)the_lnet.ln_remote_nets_version;
233 *ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
237 struct lnet_route *route = NULL;
238 struct lnet_remotenet *rnet = NULL;
240 struct list_head *rn_list;
245 if (ver != LNET_PROC_VERSION(the_lnet.ln_remote_nets_version)) {
247 LIBCFS_FREE(tmpstr, tmpsiz);
251 for (i = 0; i < LNET_REMOTE_NETS_HASH_SIZE && route == NULL;
253 rn_list = &the_lnet.ln_remote_nets_hash[i];
257 while (n != rn_list && route == NULL) {
258 rnet = list_entry(n, struct lnet_remotenet,
261 r = rnet->lrn_routes.next;
263 while (r != &rnet->lrn_routes) {
264 struct lnet_route *re =
265 list_entry(r, struct lnet_route,
281 __u32 net = rnet->lrn_net;
282 __u32 hops = route->lr_hops;
283 unsigned int priority = route->lr_priority;
284 int alive = lnet_is_route_alive(route);
286 s += scnprintf(s, tmpstr + tmpsiz - s,
287 "%-8s %4d %8u %7s %s\n",
288 libcfs_net2str(net), hops,
290 alive ? "up" : "down",
291 libcfs_nidstr(&route->lr_nid));
292 LASSERT(tmpstr + tmpsiz - s > 0);
298 len = s - tmpstr; /* how many bytes was written */
300 if (len > *lenp) { /* linux-supplied buffer is too small */
302 } else if (len > 0) { /* wrote something */
303 if (copy_to_user(buffer, tmpstr, len))
307 *ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
311 LIBCFS_FREE(tmpstr, tmpsiz);
320 proc_lnet_routers(struct ctl_table *table, int write, void __user *buffer,
321 size_t *lenp, loff_t *ppos)
326 const int tmpsiz = 256;
331 off = LNET_PROC_HOFF_GET(*ppos);
332 ver = LNET_PROC_VER_GET(*ppos);
339 LIBCFS_ALLOC(tmpstr, tmpsiz);
343 s = tmpstr; /* points to current position in tmpstr[] */
346 s += scnprintf(s, tmpstr + tmpsiz - s,
348 "ref", "rtr_ref", "alive", "router");
349 LASSERT(tmpstr + tmpsiz - s > 0);
352 ver = (unsigned int)the_lnet.ln_routers_version;
354 *ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
357 struct lnet_peer *peer = NULL;
362 if (ver != LNET_PROC_VERSION(the_lnet.ln_routers_version)) {
365 LIBCFS_FREE(tmpstr, tmpsiz);
369 r = the_lnet.ln_routers.next;
371 while (r != &the_lnet.ln_routers) {
372 struct lnet_peer *lp =
373 list_entry(r, struct lnet_peer,
386 struct lnet_nid *nid = &peer->lp_primary_nid;
387 int nrefs = atomic_read(&peer->lp_refcount);
388 int nrtrrefs = peer->lp_rtr_refcount;
389 int alive = lnet_is_gateway_alive(peer);
391 s += scnprintf(s, tmpstr + tmpsiz - s,
394 alive ? "up" : "down",
401 len = s - tmpstr; /* how many bytes was written */
403 if (len > *lenp) { /* linux-supplied buffer is too small */
405 } else if (len > 0) { /* wrote something */
406 if (copy_to_user(buffer, tmpstr, len))
410 *ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
414 LIBCFS_FREE(tmpstr, tmpsiz);
422 /* TODO: there should be no direct access to ptable. We should add a set
423 * of APIs that give access to the ptable and its members */
425 proc_lnet_peers(struct ctl_table *table, int write, void __user *buffer,
426 size_t *lenp, loff_t *ppos)
428 const int tmpsiz = 256;
429 struct lnet_peer_table *ptable;
432 int cpt = LNET_PROC_CPT_GET(*ppos);
433 int ver = LNET_PROC_VER_GET(*ppos);
434 int hash = LNET_PROC_HASH_GET(*ppos);
435 int hoff = LNET_PROC_HOFF_GET(*ppos);
441 struct lnet_peer_ni *peer;
443 cfs_percpt_for_each(ptable, i, the_lnet.ln_peer_tables) {
445 for (hash = 0; hash < LNET_PEER_HASH_SIZE; hash++) {
446 list_for_each_entry(peer,
447 &ptable->pt_hash[hash],
449 peer->lpni_mintxcredits =
450 peer->lpni_txcredits;
451 peer->lpni_minrtrcredits =
452 peer->lpni_rtrcredits;
464 BUILD_BUG_ON(LNET_PROC_HASH_BITS < LNET_PEER_HASH_BITS);
466 if (cpt >= LNET_CPT_NUMBER) {
471 LIBCFS_ALLOC(tmpstr, tmpsiz);
475 s = tmpstr; /* points to current position in tmpstr[] */
478 s += scnprintf(s, tmpstr + tmpsiz - s,
479 "%-24s %4s %5s %5s %5s %5s %5s %5s %5s %s\n",
480 "nid", "refs", "state", "last", "max",
481 "rtr", "min", "tx", "min", "queue");
482 LASSERT(tmpstr + tmpsiz - s > 0);
486 struct lnet_peer_ni *peer;
496 ptable = the_lnet.ln_peer_tables[cpt];
498 ver = LNET_PROC_VERSION(ptable->pt_version);
500 if (ver != LNET_PROC_VERSION(ptable->pt_version)) {
501 lnet_net_unlock(cpt);
502 LIBCFS_FREE(tmpstr, tmpsiz);
506 while (hash < LNET_PEER_HASH_SIZE) {
508 p = ptable->pt_hash[hash].next;
510 while (p != &ptable->pt_hash[hash]) {
511 struct lnet_peer_ni *lp =
512 list_entry(p, struct lnet_peer_ni,
517 /* minor optimization: start from idx+1
518 * on next iteration if we've just
519 * drained lpni_hashlist */
520 if (lp->lpni_hashlist.next ==
521 &ptable->pt_hash[hash]) {
532 p = lp->lpni_hashlist.next;
544 struct lnet_nid nid = peer->lpni_nid;
545 int nrefs = kref_read(&peer->lpni_kref);
546 time64_t lastalive = -1;
547 char *aliveness = "NA";
548 int maxcr = (peer->lpni_net) ?
549 peer->lpni_net->net_tunables.lct_peer_tx_credits : 0;
550 int txcr = peer->lpni_txcredits;
551 int mintxcr = peer->lpni_mintxcredits;
552 int rtrcr = peer->lpni_rtrcredits;
553 int minrtrcr = peer->lpni_minrtrcredits;
554 int txqnob = peer->lpni_txqnob;
556 if (lnet_isrouter(peer) ||
557 lnet_peer_aliveness_enabled(peer))
558 aliveness = lnet_is_peer_ni_alive(peer) ?
561 lnet_net_unlock(cpt);
563 s += scnprintf(s, tmpstr + tmpsiz - s,
564 "%-24s %4d %5s %5lld %5d %5d %5d %5d %5d %d\n",
565 libcfs_nidstr(&nid), nrefs, aliveness,
566 lastalive, maxcr, rtrcr, minrtrcr, txcr,
568 LASSERT(tmpstr + tmpsiz - s > 0);
570 } else { /* peer is NULL */
571 lnet_net_unlock(cpt);
574 if (hash == LNET_PEER_HASH_SIZE) {
578 if (peer == NULL && cpt < LNET_CPT_NUMBER)
583 len = s - tmpstr; /* how many bytes was written */
585 if (len > *lenp) { /* linux-supplied buffer is too small */
587 } else if (len > 0) { /* wrote something */
588 if (copy_to_user(buffer, tmpstr, len))
591 *ppos = LNET_PROC_POS_MAKE(cpt, ver, hash, hoff);
594 LIBCFS_FREE(tmpstr, tmpsiz);
602 static int proc_lnet_buffers(struct ctl_table *table, int write,
603 void __user *buffer, size_t *lenp, loff_t *ppos)
617 /* (4 %d) * 4 * LNET_CPT_NUMBER */
618 tmpsiz = 64 * (LNET_NRBPOOLS + 1) * LNET_CPT_NUMBER;
619 LIBCFS_ALLOC(tmpstr, tmpsiz);
623 s = tmpstr; /* points to current position in tmpstr[] */
625 s += scnprintf(s, tmpstr + tmpsiz - s,
627 "pages", "count", "credits", "min");
628 LASSERT(tmpstr + tmpsiz - s > 0);
630 if (the_lnet.ln_rtrpools == NULL)
631 goto out; /* I'm not a router */
633 for (idx = 0; idx < LNET_NRBPOOLS; idx++) {
634 struct lnet_rtrbufpool *rbp;
636 lnet_net_lock(LNET_LOCK_EX);
637 cfs_percpt_for_each(rbp, i, the_lnet.ln_rtrpools) {
638 s += scnprintf(s, tmpstr + tmpsiz - s,
641 rbp[idx].rbp_nbuffers,
642 rbp[idx].rbp_credits,
643 rbp[idx].rbp_mincredits);
644 LASSERT(tmpstr + tmpsiz - s > 0);
646 lnet_net_unlock(LNET_LOCK_EX);
652 if (pos >= min_t(int, len, strlen(tmpstr)))
655 rc = cfs_trace_copyout_string(buffer, nob,
658 LIBCFS_FREE(tmpstr, tmpsiz);
663 proc_lnet_nis(struct ctl_table *table, int write, void __user *buffer,
664 size_t *lenp, loff_t *ppos)
666 int tmpsiz = 128 * LNET_CPT_NUMBER;
676 /* Just reset the min stat. */
678 struct lnet_net *net;
682 list_for_each_entry(net, &the_lnet.ln_nets, net_list) {
683 list_for_each_entry(ni, &net->net_ni_list, ni_netlist) {
684 struct lnet_tx_queue *tq;
688 cfs_percpt_for_each(tq, i, ni->ni_tx_queues) {
689 for (j = 0; ni->ni_cpts != NULL &&
690 j < ni->ni_ncpts; j++) {
691 if (i == ni->ni_cpts[j])
695 if (j == ni->ni_ncpts)
700 tq->tq_credits_min = tq->tq_credits;
711 LIBCFS_ALLOC(tmpstr, tmpsiz);
715 s = tmpstr; /* points to current position in tmpstr[] */
718 s += scnprintf(s, tmpstr + tmpsiz - s,
719 "%-24s %6s %5s %4s %4s %4s %5s %5s %5s\n",
720 "nid", "status", "alive", "refs", "peer",
721 "rtr", "max", "tx", "min");
722 LASSERT (tmpstr + tmpsiz - s > 0);
724 struct lnet_ni *ni = NULL;
725 int skip = *ppos - 1;
729 ni = lnet_get_ni_idx_locked(skip);
732 struct lnet_tx_queue *tq;
734 time64_t now = ktime_get_seconds();
735 time64_t last_alive = -1;
739 if (the_lnet.ln_routing)
740 last_alive = now - ni->ni_net->net_last_alive;
743 LASSERT(ni->ni_status != NULL);
744 stat = (lnet_ni_get_status_locked(ni) ==
745 LNET_NI_STATUS_UP) ? "up" : "down";
748 /* @lo forever alive */
749 if (ni->ni_net->net_lnd->lnd_type == LOLND) {
754 /* we actually output credits information for
755 * TX queue of each partition */
756 cfs_percpt_for_each(tq, i, ni->ni_tx_queues) {
757 for (j = 0; ni->ni_cpts != NULL &&
758 j < ni->ni_ncpts; j++) {
759 if (i == ni->ni_cpts[j])
763 if (j == ni->ni_ncpts)
769 s += scnprintf(s, tmpstr + tmpsiz - s,
770 "%-24s %6s %5lld %4d %4d %4d %5d %5d %5d\n",
771 libcfs_nidstr(&ni->ni_nid), stat,
772 last_alive, *ni->ni_refs[i],
773 ni->ni_net->net_tunables.lct_peer_tx_credits,
774 ni->ni_net->net_tunables.lct_peer_rtr_credits,
776 tq->tq_credits, tq->tq_credits_min);
780 LASSERT(tmpstr + tmpsiz - s > 0);
786 len = s - tmpstr; /* how many bytes was written */
788 if (len > *lenp) { /* linux-supplied buffer is too small */
790 } else if (len > 0) { /* wrote something */
791 if (copy_to_user(buffer, tmpstr, len))
797 LIBCFS_FREE(tmpstr, tmpsiz);
805 struct lnet_portal_rotors {
811 static struct lnet_portal_rotors portal_rotors[] = {
813 .pr_value = LNET_PTL_ROTOR_OFF,
815 .pr_desc = "Turn off message rotor for wildcard portals"
818 .pr_value = LNET_PTL_ROTOR_ON,
820 .pr_desc = "round-robin dispatch all PUT messages for "
824 .pr_value = LNET_PTL_ROTOR_RR_RT,
826 .pr_desc = "round-robin dispatch routed PUT message for "
830 .pr_value = LNET_PTL_ROTOR_HASH_RT,
831 .pr_name = "HASH_RT",
832 .pr_desc = "dispatch routed PUT message by hashing source "
833 "NID for wildcard portals"
842 static int proc_lnet_portal_rotor(struct ctl_table *table, int write,
843 void __user *buffer, size_t *lenp,
846 const int buf_len = 128;
855 LIBCFS_ALLOC(buf, buf_len);
861 for (i = 0; portal_rotors[i].pr_value >= 0; i++) {
862 if (portal_rotors[i].pr_value == portal_rotor)
866 LASSERT(portal_rotors[i].pr_value == portal_rotor);
869 rc = scnprintf(buf, buf_len,
870 "{\n\tportals: all\n"
871 "\trotor: %s\n\tdescription: %s\n}",
872 portal_rotors[i].pr_name,
873 portal_rotors[i].pr_desc);
875 if (pos >= min_t(int, rc, buf_len)) {
878 rc = cfs_trace_copyout_string(buffer, nob,
881 LIBCFS_FREE(buf, buf_len);
886 buf = memdup_user_nul(buffer, nob);
894 for (i = 0; portal_rotors[i].pr_name != NULL; i++) {
895 if (strncasecmp(portal_rotors[i].pr_name, tmp,
896 strlen(portal_rotors[i].pr_name)) == 0) {
897 portal_rotor = portal_rotors[i].pr_value;
908 static struct ctl_table lnet_table[] = {
910 * NB No .strategy entries have been provided since sysctl(8) prefers
911 * to go via /proc for portability.
914 .procname = "cpu_partition_table",
917 .proc_handler = &proc_cpt_table,
920 .procname = "cpu_partition_distance",
923 .proc_handler = &proc_cpt_distance,
928 .proc_handler = &proc_lnet_stats,
931 .procname = "routes",
933 .proc_handler = &proc_lnet_routes,
936 .procname = "routers",
938 .proc_handler = &proc_lnet_routers,
943 .proc_handler = &proc_lnet_peers,
946 .procname = "buffers",
948 .proc_handler = &proc_lnet_buffers,
953 .proc_handler = &proc_lnet_nis,
956 .procname = "portal_rotor",
958 .proc_handler = &proc_lnet_portal_rotor,
961 .procname = "lnet_lnd_timeout",
962 .data = &lnet_lnd_timeout,
963 .maxlen = sizeof(lnet_lnd_timeout),
965 .proc_handler = &debugfs_doint,
970 static void *debugfs_state;
972 void lnet_router_debugfs_init(void)
974 lnet_insert_debugfs(lnet_table, THIS_MODULE,
978 void lnet_router_debugfs_fini(void)
980 lnet_remove_debugfs(lnet_table);
982 void lnet_router_exit(void)
984 lnet_debugfs_fini(&debugfs_state);