2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
4 * Copyright (c) 2011, 2012, Intel Corporation.
6 * This file is part of Portals
7 * http://sourceforge.net/projects/sandiaportals/
9 * Portals is free software; you can redistribute it and/or
10 * modify it under the terms of version 2 of the GNU General Public
11 * License as published by the Free Software Foundation.
13 * Portals is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
20 #define DEBUG_SUBSYSTEM S_LNET
21 #include "../../include/linux/libcfs/libcfs.h"
22 #include "../../include/linux/lnet/lib-lnet.h"
25 * This is really lnet_proc.c. You might need to update sanity test 215
26 * if any file format is changed.
29 #define LNET_LOFFT_BITS (sizeof(loff_t) * 8)
31 * NB: max allowed LNET_CPT_BITS is 8 on 64-bit system and 2 on 32-bit system
33 #define LNET_PROC_CPT_BITS (LNET_CPT_BITS + 1)
34 /* change version, 16 bits or 8 bits */
35 #define LNET_PROC_VER_BITS max_t(size_t, min_t(size_t, LNET_LOFFT_BITS, 64) / 4, 8)
37 #define LNET_PROC_HASH_BITS LNET_PEER_HASH_BITS
39 * bits for peer hash offset
40 * NB: we don't use the highest bit of *ppos because it's signed
42 #define LNET_PROC_HOFF_BITS (LNET_LOFFT_BITS - \
43 LNET_PROC_CPT_BITS - \
44 LNET_PROC_VER_BITS - \
45 LNET_PROC_HASH_BITS - 1)
46 /* bits for hash index + position */
47 #define LNET_PROC_HPOS_BITS (LNET_PROC_HASH_BITS + LNET_PROC_HOFF_BITS)
48 /* bits for peer hash table + hash version */
49 #define LNET_PROC_VPOS_BITS (LNET_PROC_HPOS_BITS + LNET_PROC_VER_BITS)
51 #define LNET_PROC_CPT_MASK ((1ULL << LNET_PROC_CPT_BITS) - 1)
52 #define LNET_PROC_VER_MASK ((1ULL << LNET_PROC_VER_BITS) - 1)
53 #define LNET_PROC_HASH_MASK ((1ULL << LNET_PROC_HASH_BITS) - 1)
54 #define LNET_PROC_HOFF_MASK ((1ULL << LNET_PROC_HOFF_BITS) - 1)
56 #define LNET_PROC_CPT_GET(pos) \
57 (int)(((pos) >> LNET_PROC_VPOS_BITS) & LNET_PROC_CPT_MASK)
59 #define LNET_PROC_VER_GET(pos) \
60 (int)(((pos) >> LNET_PROC_HPOS_BITS) & LNET_PROC_VER_MASK)
62 #define LNET_PROC_HASH_GET(pos) \
63 (int)(((pos) >> LNET_PROC_HOFF_BITS) & LNET_PROC_HASH_MASK)
65 #define LNET_PROC_HOFF_GET(pos) \
66 (int)((pos) & LNET_PROC_HOFF_MASK)
68 #define LNET_PROC_POS_MAKE(cpt, ver, hash, off) \
69 (((((loff_t)(cpt)) & LNET_PROC_CPT_MASK) << LNET_PROC_VPOS_BITS) | \
70 ((((loff_t)(ver)) & LNET_PROC_VER_MASK) << LNET_PROC_HPOS_BITS) | \
71 ((((loff_t)(hash)) & LNET_PROC_HASH_MASK) << LNET_PROC_HOFF_BITS) | \
72 ((off) & LNET_PROC_HOFF_MASK))
74 #define LNET_PROC_VERSION(v) ((unsigned int)((v) & LNET_PROC_VER_MASK))
76 static int proc_call_handler(void *data
, int write
, loff_t
*ppos
,
77 void __user
*buffer
, size_t *lenp
,
78 int (*handler
)(void *data
, int write
,
79 loff_t pos
, void __user
*buffer
,
82 int rc
= handler(data
, write
, *ppos
, buffer
, *lenp
);
96 static int __proc_lnet_stats(void *data
, int write
,
97 loff_t pos
, void __user
*buffer
, int nob
)
100 lnet_counters_t
*ctrs
;
103 const int tmpsiz
= 256; /* 7 %u and 4 %llu */
106 lnet_counters_reset();
112 LIBCFS_ALLOC(ctrs
, sizeof(*ctrs
));
116 LIBCFS_ALLOC(tmpstr
, tmpsiz
);
118 LIBCFS_FREE(ctrs
, sizeof(*ctrs
));
122 lnet_counters_get(ctrs
);
124 len
= snprintf(tmpstr
, tmpsiz
,
125 "%u %u %u %u %u %u %u %llu %llu %llu %llu",
126 ctrs
->msgs_alloc
, ctrs
->msgs_max
,
128 ctrs
->send_count
, ctrs
->recv_count
,
129 ctrs
->route_count
, ctrs
->drop_count
,
130 ctrs
->send_length
, ctrs
->recv_length
,
131 ctrs
->route_length
, ctrs
->drop_length
);
133 if (pos
>= min_t(int, len
, strlen(tmpstr
)))
136 rc
= cfs_trace_copyout_string(buffer
, nob
,
139 LIBCFS_FREE(tmpstr
, tmpsiz
);
140 LIBCFS_FREE(ctrs
, sizeof(*ctrs
));
144 static int proc_lnet_stats(struct ctl_table
*table
, int write
,
145 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
147 return proc_call_handler(table
->data
, write
, ppos
, buffer
, lenp
,
151 static int proc_lnet_routes(struct ctl_table
*table
, int write
,
152 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
154 const int tmpsiz
= 256;
162 CLASSERT(sizeof(loff_t
) >= 4);
164 off
= LNET_PROC_HOFF_GET(*ppos
);
165 ver
= LNET_PROC_VER_GET(*ppos
);
172 LIBCFS_ALLOC(tmpstr
, tmpsiz
);
176 s
= tmpstr
; /* points to current position in tmpstr[] */
179 s
+= snprintf(s
, tmpstr
+ tmpsiz
- s
, "Routing %s\n",
180 the_lnet
.ln_routing
? "enabled" : "disabled");
181 LASSERT(tmpstr
+ tmpsiz
- s
> 0);
183 s
+= snprintf(s
, tmpstr
+ tmpsiz
- s
, "%-8s %4s %8s %7s %s\n",
184 "net", "hops", "priority", "state", "router");
185 LASSERT(tmpstr
+ tmpsiz
- s
> 0);
188 ver
= (unsigned int)the_lnet
.ln_remote_nets_version
;
190 *ppos
= LNET_PROC_POS_MAKE(0, ver
, 0, off
);
194 lnet_route_t
*route
= NULL
;
195 lnet_remotenet_t
*rnet
= NULL
;
197 struct list_head
*rn_list
;
202 if (ver
!= LNET_PROC_VERSION(the_lnet
.ln_remote_nets_version
)) {
204 LIBCFS_FREE(tmpstr
, tmpsiz
);
208 for (i
= 0; i
< LNET_REMOTE_NETS_HASH_SIZE
&& !route
; i
++) {
209 rn_list
= &the_lnet
.ln_remote_nets_hash
[i
];
213 while (n
!= rn_list
&& !route
) {
214 rnet
= list_entry(n
, lnet_remotenet_t
,
217 r
= rnet
->lrn_routes
.next
;
219 while (r
!= &rnet
->lrn_routes
) {
221 list_entry(r
, lnet_route_t
,
237 __u32 net
= rnet
->lrn_net
;
238 __u32 hops
= route
->lr_hops
;
239 unsigned int priority
= route
->lr_priority
;
240 lnet_nid_t nid
= route
->lr_gateway
->lp_nid
;
241 int alive
= lnet_is_route_alive(route
);
243 s
+= snprintf(s
, tmpstr
+ tmpsiz
- s
,
244 "%-8s %4u %8u %7s %s\n",
245 libcfs_net2str(net
), hops
,
247 alive
? "up" : "down",
248 libcfs_nid2str(nid
));
249 LASSERT(tmpstr
+ tmpsiz
- s
> 0);
255 len
= s
- tmpstr
; /* how many bytes was written */
257 if (len
> *lenp
) { /* linux-supplied buffer is too small */
259 } else if (len
> 0) { /* wrote something */
260 if (copy_to_user(buffer
, tmpstr
, len
)) {
264 *ppos
= LNET_PROC_POS_MAKE(0, ver
, 0, off
);
268 LIBCFS_FREE(tmpstr
, tmpsiz
);
276 static int proc_lnet_routers(struct ctl_table
*table
, int write
,
277 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
282 const int tmpsiz
= 256;
287 off
= LNET_PROC_HOFF_GET(*ppos
);
288 ver
= LNET_PROC_VER_GET(*ppos
);
295 LIBCFS_ALLOC(tmpstr
, tmpsiz
);
299 s
= tmpstr
; /* points to current position in tmpstr[] */
302 s
+= snprintf(s
, tmpstr
+ tmpsiz
- s
,
303 "%-4s %7s %9s %6s %12s %9s %8s %7s %s\n",
304 "ref", "rtr_ref", "alive_cnt", "state",
305 "last_ping", "ping_sent", "deadline",
306 "down_ni", "router");
307 LASSERT(tmpstr
+ tmpsiz
- s
> 0);
310 ver
= (unsigned int)the_lnet
.ln_routers_version
;
312 *ppos
= LNET_PROC_POS_MAKE(0, ver
, 0, off
);
315 struct lnet_peer
*peer
= NULL
;
320 if (ver
!= LNET_PROC_VERSION(the_lnet
.ln_routers_version
)) {
323 LIBCFS_FREE(tmpstr
, tmpsiz
);
327 r
= the_lnet
.ln_routers
.next
;
329 while (r
!= &the_lnet
.ln_routers
) {
330 lnet_peer_t
*lp
= list_entry(r
, lnet_peer_t
,
343 lnet_nid_t nid
= peer
->lp_nid
;
344 unsigned long now
= cfs_time_current();
345 unsigned long deadline
= peer
->lp_ping_deadline
;
346 int nrefs
= peer
->lp_refcount
;
347 int nrtrrefs
= peer
->lp_rtr_refcount
;
348 int alive_cnt
= peer
->lp_alive_count
;
349 int alive
= peer
->lp_alive
;
350 int pingsent
= !peer
->lp_ping_notsent
;
351 int last_ping
= cfs_duration_sec(cfs_time_sub(now
,
352 peer
->lp_ping_timestamp
));
356 if ((peer
->lp_ping_feats
&
357 LNET_PING_FEAT_NI_STATUS
)) {
358 list_for_each_entry(rtr
, &peer
->lp_routes
,
361 * downis on any route should be the
362 * number of downis on the gateway
364 if (rtr
->lr_downis
) {
365 down_ni
= rtr
->lr_downis
;
372 s
+= snprintf(s
, tmpstr
+ tmpsiz
- s
,
373 "%-4d %7d %9d %6s %12d %9d %8s %7d %s\n",
374 nrefs
, nrtrrefs
, alive_cnt
,
375 alive
? "up" : "down", last_ping
,
376 pingsent
, "NA", down_ni
,
377 libcfs_nid2str(nid
));
379 s
+= snprintf(s
, tmpstr
+ tmpsiz
- s
,
380 "%-4d %7d %9d %6s %12d %9d %8lu %7d %s\n",
381 nrefs
, nrtrrefs
, alive_cnt
,
382 alive
? "up" : "down", last_ping
,
384 cfs_duration_sec(cfs_time_sub(deadline
, now
)),
385 down_ni
, libcfs_nid2str(nid
));
386 LASSERT(tmpstr
+ tmpsiz
- s
> 0);
392 len
= s
- tmpstr
; /* how many bytes was written */
394 if (len
> *lenp
) { /* linux-supplied buffer is too small */
396 } else if (len
> 0) { /* wrote something */
397 if (copy_to_user(buffer
, tmpstr
, len
)) {
401 *ppos
= LNET_PROC_POS_MAKE(0, ver
, 0, off
);
405 LIBCFS_FREE(tmpstr
, tmpsiz
);
413 static int proc_lnet_peers(struct ctl_table
*table
, int write
,
414 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
416 const int tmpsiz
= 256;
417 struct lnet_peer_table
*ptable
;
420 int cpt
= LNET_PROC_CPT_GET(*ppos
);
421 int ver
= LNET_PROC_VER_GET(*ppos
);
422 int hash
= LNET_PROC_HASH_GET(*ppos
);
423 int hoff
= LNET_PROC_HOFF_GET(*ppos
);
427 CLASSERT(LNET_PROC_HASH_BITS
>= LNET_PEER_HASH_BITS
);
433 if (cpt
>= LNET_CPT_NUMBER
) {
438 LIBCFS_ALLOC(tmpstr
, tmpsiz
);
442 s
= tmpstr
; /* points to current position in tmpstr[] */
445 s
+= snprintf(s
, tmpstr
+ tmpsiz
- s
,
446 "%-24s %4s %5s %5s %5s %5s %5s %5s %5s %s\n",
447 "nid", "refs", "state", "last", "max",
448 "rtr", "min", "tx", "min", "queue");
449 LASSERT(tmpstr
+ tmpsiz
- s
> 0);
453 struct lnet_peer
*peer
;
462 ptable
= the_lnet
.ln_peer_tables
[cpt
];
464 ver
= LNET_PROC_VERSION(ptable
->pt_version
);
466 if (ver
!= LNET_PROC_VERSION(ptable
->pt_version
)) {
467 lnet_net_unlock(cpt
);
468 LIBCFS_FREE(tmpstr
, tmpsiz
);
472 while (hash
< LNET_PEER_HASH_SIZE
) {
474 p
= ptable
->pt_hash
[hash
].next
;
476 while (p
!= &ptable
->pt_hash
[hash
]) {
477 lnet_peer_t
*lp
= list_entry(p
, lnet_peer_t
,
483 * minor optimization: start from idx+1
484 * on next iteration if we've just
485 * drained lp_hashlist
487 if (lp
->lp_hashlist
.next
==
488 &ptable
->pt_hash
[hash
]) {
499 p
= lp
->lp_hashlist
.next
;
511 lnet_nid_t nid
= peer
->lp_nid
;
512 int nrefs
= peer
->lp_refcount
;
514 char *aliveness
= "NA";
515 int maxcr
= peer
->lp_ni
->ni_peertxcredits
;
516 int txcr
= peer
->lp_txcredits
;
517 int mintxcr
= peer
->lp_mintxcredits
;
518 int rtrcr
= peer
->lp_rtrcredits
;
519 int minrtrcr
= peer
->lp_minrtrcredits
;
520 int txqnob
= peer
->lp_txqnob
;
522 if (lnet_isrouter(peer
) ||
523 lnet_peer_aliveness_enabled(peer
))
524 aliveness
= peer
->lp_alive
? "up" : "down";
526 if (lnet_peer_aliveness_enabled(peer
)) {
527 unsigned long now
= cfs_time_current();
530 delta
= cfs_time_sub(now
, peer
->lp_last_alive
);
531 lastalive
= cfs_duration_sec(delta
);
533 /* No need to mess up peers contents with
534 * arbitrarily long integers - it suffices to
535 * know that lastalive is more than 10000s old
537 if (lastalive
>= 10000)
541 lnet_net_unlock(cpt
);
543 s
+= snprintf(s
, tmpstr
+ tmpsiz
- s
,
544 "%-24s %4d %5s %5d %5d %5d %5d %5d %5d %d\n",
545 libcfs_nid2str(nid
), nrefs
, aliveness
,
546 lastalive
, maxcr
, rtrcr
, minrtrcr
, txcr
,
548 LASSERT(tmpstr
+ tmpsiz
- s
> 0);
550 } else { /* peer is NULL */
551 lnet_net_unlock(cpt
);
554 if (hash
== LNET_PEER_HASH_SIZE
) {
558 if (!peer
&& cpt
< LNET_CPT_NUMBER
)
563 len
= s
- tmpstr
; /* how many bytes was written */
565 if (len
> *lenp
) { /* linux-supplied buffer is too small */
567 } else if (len
> 0) { /* wrote something */
568 if (copy_to_user(buffer
, tmpstr
, len
))
571 *ppos
= LNET_PROC_POS_MAKE(cpt
, ver
, hash
, hoff
);
574 LIBCFS_FREE(tmpstr
, tmpsiz
);
582 static int __proc_lnet_buffers(void *data
, int write
,
583 loff_t pos
, void __user
*buffer
, int nob
)
595 /* (4 %d) * 4 * LNET_CPT_NUMBER */
596 tmpsiz
= 64 * (LNET_NRBPOOLS
+ 1) * LNET_CPT_NUMBER
;
597 LIBCFS_ALLOC(tmpstr
, tmpsiz
);
601 s
= tmpstr
; /* points to current position in tmpstr[] */
603 s
+= snprintf(s
, tmpstr
+ tmpsiz
- s
,
605 "pages", "count", "credits", "min");
606 LASSERT(tmpstr
+ tmpsiz
- s
> 0);
608 if (!the_lnet
.ln_rtrpools
)
609 goto out
; /* I'm not a router */
611 for (idx
= 0; idx
< LNET_NRBPOOLS
; idx
++) {
612 lnet_rtrbufpool_t
*rbp
;
614 lnet_net_lock(LNET_LOCK_EX
);
615 cfs_percpt_for_each(rbp
, i
, the_lnet
.ln_rtrpools
) {
616 s
+= snprintf(s
, tmpstr
+ tmpsiz
- s
,
619 rbp
[idx
].rbp_nbuffers
,
620 rbp
[idx
].rbp_credits
,
621 rbp
[idx
].rbp_mincredits
);
622 LASSERT(tmpstr
+ tmpsiz
- s
> 0);
624 lnet_net_unlock(LNET_LOCK_EX
);
630 if (pos
>= min_t(int, len
, strlen(tmpstr
)))
633 rc
= cfs_trace_copyout_string(buffer
, nob
,
636 LIBCFS_FREE(tmpstr
, tmpsiz
);
640 static int proc_lnet_buffers(struct ctl_table
*table
, int write
,
641 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
643 return proc_call_handler(table
->data
, write
, ppos
, buffer
, lenp
,
644 __proc_lnet_buffers
);
647 static int proc_lnet_nis(struct ctl_table
*table
, int write
,
648 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
650 int tmpsiz
= 128 * LNET_CPT_NUMBER
;
661 LIBCFS_ALLOC(tmpstr
, tmpsiz
);
665 s
= tmpstr
; /* points to current position in tmpstr[] */
668 s
+= snprintf(s
, tmpstr
+ tmpsiz
- s
,
669 "%-24s %6s %5s %4s %4s %4s %5s %5s %5s\n",
670 "nid", "status", "alive", "refs", "peer",
671 "rtr", "max", "tx", "min");
672 LASSERT(tmpstr
+ tmpsiz
- s
> 0);
675 lnet_ni_t
*ni
= NULL
;
676 int skip
= *ppos
- 1;
680 n
= the_lnet
.ln_nis
.next
;
682 while (n
!= &the_lnet
.ln_nis
) {
683 lnet_ni_t
*a_ni
= list_entry(n
, lnet_ni_t
, ni_list
);
695 struct lnet_tx_queue
*tq
;
697 time64_t now
= ktime_get_real_seconds();
702 if (the_lnet
.ln_routing
)
703 last_alive
= now
- ni
->ni_last_alive
;
705 /* @lo forever alive */
706 if (ni
->ni_lnd
->lnd_type
== LOLND
)
710 LASSERT(ni
->ni_status
);
711 stat
= (ni
->ni_status
->ns_status
==
712 LNET_NI_STATUS_UP
) ? "up" : "down";
716 * we actually output credits information for
717 * TX queue of each partition
719 cfs_percpt_for_each(tq
, i
, ni
->ni_tx_queues
) {
720 for (j
= 0; ni
->ni_cpts
&&
721 j
< ni
->ni_ncpts
; j
++) {
722 if (i
== ni
->ni_cpts
[j
])
726 if (j
== ni
->ni_ncpts
)
732 s
+= snprintf(s
, tmpstr
+ tmpsiz
- s
,
733 "%-24s %6s %5d %4d %4d %4d %5d %5d %5d\n",
734 libcfs_nid2str(ni
->ni_nid
), stat
,
735 last_alive
, *ni
->ni_refs
[i
],
736 ni
->ni_peertxcredits
,
737 ni
->ni_peerrtrcredits
,
744 LASSERT(tmpstr
+ tmpsiz
- s
> 0);
750 len
= s
- tmpstr
; /* how many bytes was written */
752 if (len
> *lenp
) { /* linux-supplied buffer is too small */
754 } else if (len
> 0) { /* wrote something */
755 if (copy_to_user(buffer
, tmpstr
, len
))
761 LIBCFS_FREE(tmpstr
, tmpsiz
);
769 struct lnet_portal_rotors
{
775 static struct lnet_portal_rotors portal_rotors
[] = {
777 .pr_value
= LNET_PTL_ROTOR_OFF
,
779 .pr_desc
= "Turn off message rotor for wildcard portals"
782 .pr_value
= LNET_PTL_ROTOR_ON
,
784 .pr_desc
= "round-robin dispatch all PUT messages for wildcard portals"
787 .pr_value
= LNET_PTL_ROTOR_RR_RT
,
789 .pr_desc
= "round-robin dispatch routed PUT message for wildcard portals"
792 .pr_value
= LNET_PTL_ROTOR_HASH_RT
,
793 .pr_name
= "HASH_RT",
794 .pr_desc
= "dispatch routed PUT message by hashing source NID for wildcard portals"
803 static int __proc_lnet_portal_rotor(void *data
, int write
,
804 loff_t pos
, void __user
*buffer
, int nob
)
806 const int buf_len
= 128;
812 LIBCFS_ALLOC(buf
, buf_len
);
819 for (i
= 0; portal_rotors
[i
].pr_value
>= 0; i
++) {
820 if (portal_rotors
[i
].pr_value
== portal_rotor
)
824 LASSERT(portal_rotors
[i
].pr_value
== portal_rotor
);
827 rc
= snprintf(buf
, buf_len
,
828 "{\n\tportals: all\n"
829 "\trotor: %s\n\tdescription: %s\n}",
830 portal_rotors
[i
].pr_name
,
831 portal_rotors
[i
].pr_desc
);
833 if (pos
>= min_t(int, rc
, buf_len
)) {
836 rc
= cfs_trace_copyout_string(buffer
, nob
,
842 rc
= cfs_trace_copyin_string(buf
, buf_len
, buffer
, nob
);
846 tmp
= cfs_trimwhite(buf
);
850 for (i
= 0; portal_rotors
[i
].pr_name
; i
++) {
851 if (!strncasecmp(portal_rotors
[i
].pr_name
, tmp
,
852 strlen(portal_rotors
[i
].pr_name
))) {
853 portal_rotor
= portal_rotors
[i
].pr_value
;
860 LIBCFS_FREE(buf
, buf_len
);
864 static int proc_lnet_portal_rotor(struct ctl_table
*table
, int write
,
865 void __user
*buffer
, size_t *lenp
,
868 return proc_call_handler(table
->data
, write
, ppos
, buffer
, lenp
,
869 __proc_lnet_portal_rotor
);
872 static struct ctl_table lnet_table
[] = {
874 * NB No .strategy entries have been provided since sysctl(8) prefers
875 * to go via /proc for portability.
880 .proc_handler
= &proc_lnet_stats
,
883 .procname
= "routes",
885 .proc_handler
= &proc_lnet_routes
,
888 .procname
= "routers",
890 .proc_handler
= &proc_lnet_routers
,
895 .proc_handler
= &proc_lnet_peers
,
898 .procname
= "buffers",
900 .proc_handler
= &proc_lnet_buffers
,
905 .proc_handler
= &proc_lnet_nis
,
908 .procname
= "portal_rotor",
910 .proc_handler
= &proc_lnet_portal_rotor
,
916 void lnet_router_debugfs_init(void)
918 lustre_insert_debugfs(lnet_table
, NULL
);
921 void lnet_router_debugfs_fini(void)