1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#define DEBUG_SUBSYSTEM S_LNET
22
23#include <linux/libcfs/libcfs.h>
24#include <linux/lnet/lib-lnet.h>
25
26
27
28
29
30
31#define LNET_LOFFT_BITS (sizeof(loff_t) * 8)
32
33
34
35#define LNET_PROC_CPT_BITS (LNET_CPT_BITS + 1)
36
37#define LNET_PROC_VER_BITS max_t(size_t, min_t(size_t, LNET_LOFFT_BITS, 64) / 4, 8)
38
39#define LNET_PROC_HASH_BITS LNET_PEER_HASH_BITS
40
41
42
43
44#define LNET_PROC_HOFF_BITS (LNET_LOFFT_BITS - \
45 LNET_PROC_CPT_BITS - \
46 LNET_PROC_VER_BITS - \
47 LNET_PROC_HASH_BITS - 1)
48
49#define LNET_PROC_HPOS_BITS (LNET_PROC_HASH_BITS + LNET_PROC_HOFF_BITS)
50
51#define LNET_PROC_VPOS_BITS (LNET_PROC_HPOS_BITS + LNET_PROC_VER_BITS)
52
53#define LNET_PROC_CPT_MASK ((1ULL << LNET_PROC_CPT_BITS) - 1)
54#define LNET_PROC_VER_MASK ((1ULL << LNET_PROC_VER_BITS) - 1)
55#define LNET_PROC_HASH_MASK ((1ULL << LNET_PROC_HASH_BITS) - 1)
56#define LNET_PROC_HOFF_MASK ((1ULL << LNET_PROC_HOFF_BITS) - 1)
57
58#define LNET_PROC_CPT_GET(pos) \
59 (int)(((pos) >> LNET_PROC_VPOS_BITS) & LNET_PROC_CPT_MASK)
60
61#define LNET_PROC_VER_GET(pos) \
62 (int)(((pos) >> LNET_PROC_HPOS_BITS) & LNET_PROC_VER_MASK)
63
64#define LNET_PROC_HASH_GET(pos) \
65 (int)(((pos) >> LNET_PROC_HOFF_BITS) & LNET_PROC_HASH_MASK)
66
67#define LNET_PROC_HOFF_GET(pos) \
68 (int)((pos) & LNET_PROC_HOFF_MASK)
69
70#define LNET_PROC_POS_MAKE(cpt, ver, hash, off) \
71 (((((loff_t)(cpt)) & LNET_PROC_CPT_MASK) << LNET_PROC_VPOS_BITS) | \
72 ((((loff_t)(ver)) & LNET_PROC_VER_MASK) << LNET_PROC_HPOS_BITS) | \
73 ((((loff_t)(hash)) & LNET_PROC_HASH_MASK) << LNET_PROC_HOFF_BITS) | \
74 ((off) & LNET_PROC_HOFF_MASK))
75
76#define LNET_PROC_VERSION(v) ((unsigned int)((v) & LNET_PROC_VER_MASK))
77
78static int __proc_lnet_stats(void *data, int write,
79 loff_t pos, void __user *buffer, int nob)
80{
81 int rc;
82 struct lnet_counters *ctrs;
83 int len;
84 char *tmpstr;
85 const int tmpsiz = 256;
86
87 if (write) {
88 lnet_counters_reset();
89 return 0;
90 }
91
92
93
94 ctrs = kzalloc(sizeof(*ctrs), GFP_NOFS);
95 if (!ctrs)
96 return -ENOMEM;
97
98 tmpstr = kmalloc(tmpsiz, GFP_KERNEL);
99 if (!tmpstr) {
100 kfree(ctrs);
101 return -ENOMEM;
102 }
103
104 lnet_counters_get(ctrs);
105
106 len = snprintf(tmpstr, tmpsiz,
107 "%u %u %u %u %u %u %u %llu %llu %llu %llu",
108 ctrs->msgs_alloc, ctrs->msgs_max,
109 ctrs->errors,
110 ctrs->send_count, ctrs->recv_count,
111 ctrs->route_count, ctrs->drop_count,
112 ctrs->send_length, ctrs->recv_length,
113 ctrs->route_length, ctrs->drop_length);
114
115 if (pos >= min_t(int, len, strlen(tmpstr)))
116 rc = 0;
117 else
118 rc = cfs_trace_copyout_string(buffer, nob,
119 tmpstr + pos, "\n");
120
121 kfree(tmpstr);
122 kfree(ctrs);
123 return rc;
124}
125
126static int proc_lnet_stats(struct ctl_table *table, int write,
127 void __user *buffer, size_t *lenp, loff_t *ppos)
128{
129 return lprocfs_call_handler(table->data, write, ppos, buffer, lenp,
130 __proc_lnet_stats);
131}
132
133static int proc_lnet_routes(struct ctl_table *table, int write,
134 void __user *buffer, size_t *lenp, loff_t *ppos)
135{
136 const int tmpsiz = 256;
137 char *tmpstr;
138 char *s;
139 int rc = 0;
140 int len;
141 int ver;
142 int off;
143
144 BUILD_BUG_ON(sizeof(loff_t) < 4);
145
146 off = LNET_PROC_HOFF_GET(*ppos);
147 ver = LNET_PROC_VER_GET(*ppos);
148
149 LASSERT(!write);
150
151 if (!*lenp)
152 return 0;
153
154 tmpstr = kmalloc(tmpsiz, GFP_KERNEL);
155 if (!tmpstr)
156 return -ENOMEM;
157
158 s = tmpstr;
159
160 if (!*ppos) {
161 s += snprintf(s, tmpstr + tmpsiz - s, "Routing %s\n",
162 the_lnet.ln_routing ? "enabled" : "disabled");
163 LASSERT(tmpstr + tmpsiz - s > 0);
164
165 s += snprintf(s, tmpstr + tmpsiz - s, "%-8s %4s %8s %7s %s\n",
166 "net", "hops", "priority", "state", "router");
167 LASSERT(tmpstr + tmpsiz - s > 0);
168
169 lnet_net_lock(0);
170 ver = (unsigned int)the_lnet.ln_remote_nets_version;
171 lnet_net_unlock(0);
172 *ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
173 } else {
174 struct list_head *n;
175 struct list_head *r;
176 struct lnet_route *route = NULL;
177 struct lnet_remotenet *rnet = NULL;
178 int skip = off - 1;
179 struct list_head *rn_list;
180 int i;
181
182 lnet_net_lock(0);
183
184 if (ver != LNET_PROC_VERSION(the_lnet.ln_remote_nets_version)) {
185 lnet_net_unlock(0);
186 kfree(tmpstr);
187 return -ESTALE;
188 }
189
190 for (i = 0; i < LNET_REMOTE_NETS_HASH_SIZE && !route; i++) {
191 rn_list = &the_lnet.ln_remote_nets_hash[i];
192
193 n = rn_list->next;
194
195 while (n != rn_list && !route) {
196 rnet = list_entry(n, struct lnet_remotenet,
197 lrn_list);
198
199 r = rnet->lrn_routes.next;
200
201 while (r != &rnet->lrn_routes) {
202 struct lnet_route *re;
203
204 re = list_entry(r, struct lnet_route,
205 lr_list);
206 if (!skip) {
207 route = re;
208 break;
209 }
210
211 skip--;
212 r = r->next;
213 }
214
215 n = n->next;
216 }
217 }
218
219 if (route) {
220 __u32 net = rnet->lrn_net;
221 __u32 hops = route->lr_hops;
222 unsigned int priority = route->lr_priority;
223 lnet_nid_t nid = route->lr_gateway->lp_nid;
224 int alive = lnet_is_route_alive(route);
225
226 s += snprintf(s, tmpstr + tmpsiz - s,
227 "%-8s %4u %8u %7s %s\n",
228 libcfs_net2str(net), hops,
229 priority,
230 alive ? "up" : "down",
231 libcfs_nid2str(nid));
232 LASSERT(tmpstr + tmpsiz - s > 0);
233 }
234
235 lnet_net_unlock(0);
236 }
237
238 len = s - tmpstr;
239
240 if (len > *lenp) {
241 rc = -EINVAL;
242 } else if (len > 0) {
243 if (copy_to_user(buffer, tmpstr, len)) {
244 rc = -EFAULT;
245 } else {
246 off += 1;
247 *ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
248 }
249 }
250
251 kfree(tmpstr);
252
253 if (!rc)
254 *lenp = len;
255
256 return rc;
257}
258
259static int proc_lnet_routers(struct ctl_table *table, int write,
260 void __user *buffer, size_t *lenp, loff_t *ppos)
261{
262 int rc = 0;
263 char *tmpstr;
264 char *s;
265 const int tmpsiz = 256;
266 int len;
267 int ver;
268 int off;
269
270 off = LNET_PROC_HOFF_GET(*ppos);
271 ver = LNET_PROC_VER_GET(*ppos);
272
273 LASSERT(!write);
274
275 if (!*lenp)
276 return 0;
277
278 tmpstr = kmalloc(tmpsiz, GFP_KERNEL);
279 if (!tmpstr)
280 return -ENOMEM;
281
282 s = tmpstr;
283
284 if (!*ppos) {
285 s += snprintf(s, tmpstr + tmpsiz - s,
286 "%-4s %7s %9s %6s %12s %9s %8s %7s %s\n",
287 "ref", "rtr_ref", "alive_cnt", "state",
288 "last_ping", "ping_sent", "deadline",
289 "down_ni", "router");
290 LASSERT(tmpstr + tmpsiz - s > 0);
291
292 lnet_net_lock(0);
293 ver = (unsigned int)the_lnet.ln_routers_version;
294 lnet_net_unlock(0);
295 *ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
296 } else {
297 struct list_head *r;
298 struct lnet_peer *peer = NULL;
299 int skip = off - 1;
300
301 lnet_net_lock(0);
302
303 if (ver != LNET_PROC_VERSION(the_lnet.ln_routers_version)) {
304 lnet_net_unlock(0);
305
306 kfree(tmpstr);
307 return -ESTALE;
308 }
309
310 r = the_lnet.ln_routers.next;
311
312 while (r != &the_lnet.ln_routers) {
313 struct lnet_peer *lp;
314
315 lp = list_entry(r, struct lnet_peer, lp_rtr_list);
316 if (!skip) {
317 peer = lp;
318 break;
319 }
320
321 skip--;
322 r = r->next;
323 }
324
325 if (peer) {
326 lnet_nid_t nid = peer->lp_nid;
327 unsigned long now = cfs_time_current();
328 unsigned long deadline = peer->lp_ping_deadline;
329 int nrefs = peer->lp_refcount;
330 int nrtrrefs = peer->lp_rtr_refcount;
331 int alive_cnt = peer->lp_alive_count;
332 int alive = peer->lp_alive;
333 int pingsent = !peer->lp_ping_notsent;
334 int last_ping = cfs_duration_sec(cfs_time_sub(now,
335 peer->lp_ping_timestamp));
336 int down_ni = 0;
337 struct lnet_route *rtr;
338
339 if ((peer->lp_ping_feats &
340 LNET_PING_FEAT_NI_STATUS)) {
341 list_for_each_entry(rtr, &peer->lp_routes,
342 lr_gwlist) {
343
344
345
346
347 if (rtr->lr_downis) {
348 down_ni = rtr->lr_downis;
349 break;
350 }
351 }
352 }
353
354 if (!deadline)
355 s += snprintf(s, tmpstr + tmpsiz - s,
356 "%-4d %7d %9d %6s %12d %9d %8s %7d %s\n",
357 nrefs, nrtrrefs, alive_cnt,
358 alive ? "up" : "down", last_ping,
359 pingsent, "NA", down_ni,
360 libcfs_nid2str(nid));
361 else
362 s += snprintf(s, tmpstr + tmpsiz - s,
363 "%-4d %7d %9d %6s %12d %9d %8lu %7d %s\n",
364 nrefs, nrtrrefs, alive_cnt,
365 alive ? "up" : "down", last_ping,
366 pingsent,
367 cfs_duration_sec(cfs_time_sub(deadline, now)),
368 down_ni, libcfs_nid2str(nid));
369 LASSERT(tmpstr + tmpsiz - s > 0);
370 }
371
372 lnet_net_unlock(0);
373 }
374
375 len = s - tmpstr;
376
377 if (len > *lenp) {
378 rc = -EINVAL;
379 } else if (len > 0) {
380 if (copy_to_user(buffer, tmpstr, len)) {
381 rc = -EFAULT;
382 } else {
383 off += 1;
384 *ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
385 }
386 }
387
388 kfree(tmpstr);
389
390 if (!rc)
391 *lenp = len;
392
393 return rc;
394}
395
396static int proc_lnet_peers(struct ctl_table *table, int write,
397 void __user *buffer, size_t *lenp, loff_t *ppos)
398{
399 const int tmpsiz = 256;
400 struct lnet_peer_table *ptable;
401 char *tmpstr;
402 char *s;
403 int cpt = LNET_PROC_CPT_GET(*ppos);
404 int ver = LNET_PROC_VER_GET(*ppos);
405 int hash = LNET_PROC_HASH_GET(*ppos);
406 int hoff = LNET_PROC_HOFF_GET(*ppos);
407 int rc = 0;
408 int len;
409
410 BUILD_BUG_ON(LNET_PROC_HASH_BITS < LNET_PEER_HASH_BITS);
411 LASSERT(!write);
412
413 if (!*lenp)
414 return 0;
415
416 if (cpt >= LNET_CPT_NUMBER) {
417 *lenp = 0;
418 return 0;
419 }
420
421 tmpstr = kmalloc(tmpsiz, GFP_KERNEL);
422 if (!tmpstr)
423 return -ENOMEM;
424
425 s = tmpstr;
426
427 if (!*ppos) {
428 s += snprintf(s, tmpstr + tmpsiz - s,
429 "%-24s %4s %5s %5s %5s %5s %5s %5s %5s %s\n",
430 "nid", "refs", "state", "last", "max",
431 "rtr", "min", "tx", "min", "queue");
432 LASSERT(tmpstr + tmpsiz - s > 0);
433
434 hoff++;
435 } else {
436 struct lnet_peer *peer;
437 struct list_head *p;
438 int skip;
439 again:
440 p = NULL;
441 peer = NULL;
442 skip = hoff - 1;
443
444 lnet_net_lock(cpt);
445 ptable = the_lnet.ln_peer_tables[cpt];
446 if (hoff == 1)
447 ver = LNET_PROC_VERSION(ptable->pt_version);
448
449 if (ver != LNET_PROC_VERSION(ptable->pt_version)) {
450 lnet_net_unlock(cpt);
451 kfree(tmpstr);
452 return -ESTALE;
453 }
454
455 while (hash < LNET_PEER_HASH_SIZE) {
456 if (!p)
457 p = ptable->pt_hash[hash].next;
458
459 while (p != &ptable->pt_hash[hash]) {
460 struct lnet_peer *lp;
461
462 lp = list_entry(p, struct lnet_peer,
463 lp_hashlist);
464 if (!skip) {
465 peer = lp;
466
467
468
469
470
471
472 if (lp->lp_hashlist.next ==
473 &ptable->pt_hash[hash]) {
474 hoff = 1;
475 hash++;
476 } else {
477 hoff++;
478 }
479
480 break;
481 }
482
483 skip--;
484 p = lp->lp_hashlist.next;
485 }
486
487 if (peer)
488 break;
489
490 p = NULL;
491 hoff = 1;
492 hash++;
493 }
494
495 if (peer) {
496 lnet_nid_t nid = peer->lp_nid;
497 int nrefs = peer->lp_refcount;
498 int lastalive = -1;
499 char *aliveness = "NA";
500 int maxcr = peer->lp_ni->ni_peertxcredits;
501 int txcr = peer->lp_txcredits;
502 int mintxcr = peer->lp_mintxcredits;
503 int rtrcr = peer->lp_rtrcredits;
504 int minrtrcr = peer->lp_minrtrcredits;
505 int txqnob = peer->lp_txqnob;
506
507 if (lnet_isrouter(peer) ||
508 lnet_peer_aliveness_enabled(peer))
509 aliveness = peer->lp_alive ? "up" : "down";
510
511 if (lnet_peer_aliveness_enabled(peer)) {
512 unsigned long now = cfs_time_current();
513 long delta;
514
515 delta = cfs_time_sub(now, peer->lp_last_alive);
516 lastalive = cfs_duration_sec(delta);
517
518
519
520
521
522 if (lastalive >= 10000)
523 lastalive = 9999;
524 }
525
526 lnet_net_unlock(cpt);
527
528 s += snprintf(s, tmpstr + tmpsiz - s,
529 "%-24s %4d %5s %5d %5d %5d %5d %5d %5d %d\n",
530 libcfs_nid2str(nid), nrefs, aliveness,
531 lastalive, maxcr, rtrcr, minrtrcr, txcr,
532 mintxcr, txqnob);
533 LASSERT(tmpstr + tmpsiz - s > 0);
534
535 } else {
536 lnet_net_unlock(cpt);
537 }
538
539 if (hash == LNET_PEER_HASH_SIZE) {
540 cpt++;
541 hash = 0;
542 hoff = 1;
543 if (!peer && cpt < LNET_CPT_NUMBER)
544 goto again;
545 }
546 }
547
548 len = s - tmpstr;
549
550 if (len > *lenp) {
551 rc = -EINVAL;
552 } else if (len > 0) {
553 if (copy_to_user(buffer, tmpstr, len))
554 rc = -EFAULT;
555 else
556 *ppos = LNET_PROC_POS_MAKE(cpt, ver, hash, hoff);
557 }
558
559 kfree(tmpstr);
560
561 if (!rc)
562 *lenp = len;
563
564 return rc;
565}
566
567static int __proc_lnet_buffers(void *data, int write,
568 loff_t pos, void __user *buffer, int nob)
569{
570 char *s;
571 char *tmpstr;
572 int tmpsiz;
573 int idx;
574 int len;
575 int rc;
576 int i;
577
578 LASSERT(!write);
579
580
581 tmpsiz = 64 * (LNET_NRBPOOLS + 1) * LNET_CPT_NUMBER;
582 tmpstr = kvmalloc(tmpsiz, GFP_KERNEL);
583 if (!tmpstr)
584 return -ENOMEM;
585
586 s = tmpstr;
587
588 s += snprintf(s, tmpstr + tmpsiz - s,
589 "%5s %5s %7s %7s\n",
590 "pages", "count", "credits", "min");
591 LASSERT(tmpstr + tmpsiz - s > 0);
592
593 if (!the_lnet.ln_rtrpools)
594 goto out;
595
596 for (idx = 0; idx < LNET_NRBPOOLS; idx++) {
597 struct lnet_rtrbufpool *rbp;
598
599 lnet_net_lock(LNET_LOCK_EX);
600 cfs_percpt_for_each(rbp, i, the_lnet.ln_rtrpools) {
601 s += snprintf(s, tmpstr + tmpsiz - s,
602 "%5d %5d %7d %7d\n",
603 rbp[idx].rbp_npages,
604 rbp[idx].rbp_nbuffers,
605 rbp[idx].rbp_credits,
606 rbp[idx].rbp_mincredits);
607 LASSERT(tmpstr + tmpsiz - s > 0);
608 }
609 lnet_net_unlock(LNET_LOCK_EX);
610 }
611
612 out:
613 len = s - tmpstr;
614
615 if (pos >= min_t(int, len, strlen(tmpstr)))
616 rc = 0;
617 else
618 rc = cfs_trace_copyout_string(buffer, nob,
619 tmpstr + pos, NULL);
620
621 kvfree(tmpstr);
622 return rc;
623}
624
625static int proc_lnet_buffers(struct ctl_table *table, int write,
626 void __user *buffer, size_t *lenp, loff_t *ppos)
627{
628 return lprocfs_call_handler(table->data, write, ppos, buffer, lenp,
629 __proc_lnet_buffers);
630}
631
632static int proc_lnet_nis(struct ctl_table *table, int write,
633 void __user *buffer, size_t *lenp, loff_t *ppos)
634{
635 int tmpsiz = 128 * LNET_CPT_NUMBER;
636 int rc = 0;
637 char *tmpstr;
638 char *s;
639 int len;
640
641 LASSERT(!write);
642
643 if (!*lenp)
644 return 0;
645
646 tmpstr = kvmalloc(tmpsiz, GFP_KERNEL);
647 if (!tmpstr)
648 return -ENOMEM;
649
650 s = tmpstr;
651
652 if (!*ppos) {
653 s += snprintf(s, tmpstr + tmpsiz - s,
654 "%-24s %6s %5s %4s %4s %4s %5s %5s %5s\n",
655 "nid", "status", "alive", "refs", "peer",
656 "rtr", "max", "tx", "min");
657 LASSERT(tmpstr + tmpsiz - s > 0);
658 } else {
659 struct list_head *n;
660 struct lnet_ni *ni = NULL;
661 int skip = *ppos - 1;
662
663 lnet_net_lock(0);
664
665 n = the_lnet.ln_nis.next;
666
667 while (n != &the_lnet.ln_nis) {
668 struct lnet_ni *a_ni;
669
670 a_ni = list_entry(n, struct lnet_ni, ni_list);
671 if (!skip) {
672 ni = a_ni;
673 break;
674 }
675
676 skip--;
677 n = n->next;
678 }
679
680 if (ni) {
681 struct lnet_tx_queue *tq;
682 char *stat;
683 time64_t now = ktime_get_real_seconds();
684 int last_alive = -1;
685 int i;
686 int j;
687
688 if (the_lnet.ln_routing)
689 last_alive = now - ni->ni_last_alive;
690
691
692 if (ni->ni_lnd->lnd_type == LOLND)
693 last_alive = 0;
694
695 lnet_ni_lock(ni);
696 LASSERT(ni->ni_status);
697 stat = (ni->ni_status->ns_status ==
698 LNET_NI_STATUS_UP) ? "up" : "down";
699 lnet_ni_unlock(ni);
700
701
702
703
704
705 cfs_percpt_for_each(tq, i, ni->ni_tx_queues) {
706 for (j = 0; ni->ni_cpts &&
707 j < ni->ni_ncpts; j++) {
708 if (i == ni->ni_cpts[j])
709 break;
710 }
711
712 if (j == ni->ni_ncpts)
713 continue;
714
715 if (i)
716 lnet_net_lock(i);
717
718 s += snprintf(s, tmpstr + tmpsiz - s,
719 "%-24s %6s %5d %4d %4d %4d %5d %5d %5d\n",
720 libcfs_nid2str(ni->ni_nid), stat,
721 last_alive, *ni->ni_refs[i],
722 ni->ni_peertxcredits,
723 ni->ni_peerrtrcredits,
724 tq->tq_credits_max,
725 tq->tq_credits,
726 tq->tq_credits_min);
727 if (i)
728 lnet_net_unlock(i);
729 }
730 LASSERT(tmpstr + tmpsiz - s > 0);
731 }
732
733 lnet_net_unlock(0);
734 }
735
736 len = s - tmpstr;
737
738 if (len > *lenp) {
739 rc = -EINVAL;
740 } else if (len > 0) {
741 if (copy_to_user(buffer, tmpstr, len))
742 rc = -EFAULT;
743 else
744 *ppos += 1;
745 }
746
747 kvfree(tmpstr);
748
749 if (!rc)
750 *lenp = len;
751
752 return rc;
753}
754
755struct lnet_portal_rotors {
756 int pr_value;
757 const char *pr_name;
758 const char *pr_desc;
759};
760
761static struct lnet_portal_rotors portal_rotors[] = {
762 {
763 .pr_value = LNET_PTL_ROTOR_OFF,
764 .pr_name = "OFF",
765 .pr_desc = "Turn off message rotor for wildcard portals"
766 },
767 {
768 .pr_value = LNET_PTL_ROTOR_ON,
769 .pr_name = "ON",
770 .pr_desc = "round-robin dispatch all PUT messages for wildcard portals"
771 },
772 {
773 .pr_value = LNET_PTL_ROTOR_RR_RT,
774 .pr_name = "RR_RT",
775 .pr_desc = "round-robin dispatch routed PUT message for wildcard portals"
776 },
777 {
778 .pr_value = LNET_PTL_ROTOR_HASH_RT,
779 .pr_name = "HASH_RT",
780 .pr_desc = "dispatch routed PUT message by hashing source NID for wildcard portals"
781 },
782 {
783 .pr_value = -1,
784 .pr_name = NULL,
785 .pr_desc = NULL
786 },
787};
788
789static int __proc_lnet_portal_rotor(void *data, int write,
790 loff_t pos, void __user *buffer, int nob)
791{
792 const int buf_len = 128;
793 char *buf;
794 char *tmp;
795 int rc;
796 int i;
797
798 buf = kmalloc(buf_len, GFP_KERNEL);
799 if (!buf)
800 return -ENOMEM;
801
802 if (!write) {
803 lnet_res_lock(0);
804
805 for (i = 0; portal_rotors[i].pr_value >= 0; i++) {
806 if (portal_rotors[i].pr_value == portal_rotor)
807 break;
808 }
809
810 LASSERT(portal_rotors[i].pr_value == portal_rotor);
811 lnet_res_unlock(0);
812
813 rc = snprintf(buf, buf_len,
814 "{\n\tportals: all\n"
815 "\trotor: %s\n\tdescription: %s\n}",
816 portal_rotors[i].pr_name,
817 portal_rotors[i].pr_desc);
818
819 if (pos >= min_t(int, rc, buf_len)) {
820 rc = 0;
821 } else {
822 rc = cfs_trace_copyout_string(buffer, nob,
823 buf + pos, "\n");
824 }
825 goto out;
826 }
827
828 rc = cfs_trace_copyin_string(buf, buf_len, buffer, nob);
829 if (rc < 0)
830 goto out;
831
832 tmp = strim(buf);
833
834 rc = -EINVAL;
835 lnet_res_lock(0);
836 for (i = 0; portal_rotors[i].pr_name; i++) {
837 if (!strncasecmp(portal_rotors[i].pr_name, tmp,
838 strlen(portal_rotors[i].pr_name))) {
839 portal_rotor = portal_rotors[i].pr_value;
840 rc = 0;
841 break;
842 }
843 }
844 lnet_res_unlock(0);
845out:
846 kfree(buf);
847 return rc;
848}
849
850static int proc_lnet_portal_rotor(struct ctl_table *table, int write,
851 void __user *buffer, size_t *lenp,
852 loff_t *ppos)
853{
854 return lprocfs_call_handler(table->data, write, ppos, buffer, lenp,
855 __proc_lnet_portal_rotor);
856}
857
858static struct ctl_table lnet_table[] = {
859
860
861
862
863 {
864 .procname = "stats",
865 .mode = 0644,
866 .proc_handler = &proc_lnet_stats,
867 },
868 {
869 .procname = "routes",
870 .mode = 0444,
871 .proc_handler = &proc_lnet_routes,
872 },
873 {
874 .procname = "routers",
875 .mode = 0444,
876 .proc_handler = &proc_lnet_routers,
877 },
878 {
879 .procname = "peers",
880 .mode = 0444,
881 .proc_handler = &proc_lnet_peers,
882 },
883 {
884 .procname = "buffers",
885 .mode = 0444,
886 .proc_handler = &proc_lnet_buffers,
887 },
888 {
889 .procname = "nis",
890 .mode = 0444,
891 .proc_handler = &proc_lnet_nis,
892 },
893 {
894 .procname = "portal_rotor",
895 .mode = 0644,
896 .proc_handler = &proc_lnet_portal_rotor,
897 },
898 {
899 }
900};
901
902void lnet_router_debugfs_init(void)
903{
904 lustre_insert_debugfs(lnet_table, NULL);
905}
906
907void lnet_router_debugfs_fini(void)
908{
909}
910