Whamcloud - gitweb
b=18102
[fs/lustre-release.git] / lnet / lnet / router_proc.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
5  *
6  *   This file is part of Portals
7  *   http://sourceforge.net/projects/sandiaportals/
8  *
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.
12  *
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.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with Portals; if not, write to the Free Software
20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  */
23
24 #define DEBUG_SUBSYSTEM S_LNET
25 #include <libcfs/libcfs.h>
26 #include <lnet/lib-lnet.h>
27
28 #if defined(__KERNEL__) && defined(LNET_ROUTER)
29
30 /* this is really lnet_proc.c */
31
32 static cfs_sysctl_table_header_t *lnet_table_header = NULL;
33
34 #ifndef HAVE_SYSCTL_UNNUMBERED
35 #define CTL_LNET         (0x100)
36 enum {
37         PSDEV_LNET_STATS = 100,
38         PSDEV_LNET_ROUTES,
39         PSDEV_LNET_ROUTERS,
40         PSDEV_LNET_PEERS,
41         PSDEV_LNET_BUFFERS,
42         PSDEV_LNET_NIS,
43 };
44 #else
45 #define CTL_LNET           CTL_UNNUMBERED
46 #define PSDEV_LNET_STATS   CTL_UNNUMBERED
47 #define PSDEV_LNET_ROUTES  CTL_UNNUMBERED
48 #define PSDEV_LNET_ROUTERS CTL_UNNUMBERED
49 #define PSDEV_LNET_PEERS   CTL_UNNUMBERED
50 #define PSDEV_LNET_BUFFERS CTL_UNNUMBERED
51 #define PSDEV_LNET_NIS     CTL_UNNUMBERED
52 #endif
53
54 static int __proc_lnet_stats(void *data, int write,
55                              loff_t pos, void *buffer, int nob)
56 {
57         int              rc;
58         lnet_counters_t *ctrs;
59         int              len;
60         char            *tmpstr;
61         const int        tmpsiz = 256; /* 7 %u and 4 LPU64 */
62
63         if (write) {
64                 LNET_LOCK();
65                 memset(&the_lnet.ln_counters, 0, sizeof(the_lnet.ln_counters));
66                 LNET_UNLOCK();
67                 return 0;
68         }
69
70         /* read */
71
72         LIBCFS_ALLOC(ctrs, sizeof(*ctrs));
73         if (ctrs == NULL)
74                 return -ENOMEM;
75
76         LIBCFS_ALLOC(tmpstr, tmpsiz);
77         if (tmpstr == NULL) {
78                 LIBCFS_FREE(ctrs, sizeof(*ctrs));
79                 return -ENOMEM;
80         }
81
82         LNET_LOCK();
83         *ctrs = the_lnet.ln_counters;
84         LNET_UNLOCK();
85
86         len = snprintf(tmpstr, tmpsiz,
87                        "%u %u %u %u %u %u %u "LPU64" "LPU64" "
88                        LPU64" "LPU64,
89                        ctrs->msgs_alloc, ctrs->msgs_max,
90                        ctrs->errors,
91                        ctrs->send_count, ctrs->recv_count,
92                        ctrs->route_count, ctrs->drop_count,
93                        ctrs->send_length, ctrs->recv_length,
94                        ctrs->route_length, ctrs->drop_length);
95
96         if (pos >= min_t(int, len, strlen(tmpstr)))
97                 rc = 0;
98         else
99                 rc = trace_copyout_string(buffer, nob,
100                                           tmpstr + pos, "\n");
101
102         LIBCFS_FREE(tmpstr, tmpsiz);
103         LIBCFS_FREE(ctrs, sizeof(*ctrs));
104         return rc;
105 }
106
107 DECLARE_PROC_HANDLER(proc_lnet_stats);
108
109 int LL_PROC_PROTO(proc_lnet_routes)
110 {
111         int        rc     = 0;
112         char      *tmpstr;
113         char      *s;
114         const int  tmpsiz = 256;
115         int        len;
116         int       *ver_p  = (unsigned int *)(&filp->private_data);
117
118         DECLARE_LL_PROC_PPOS_DECL;
119
120         LASSERT (!write);
121
122         if (*lenp == 0)
123                 return 0;
124
125         LIBCFS_ALLOC(tmpstr, tmpsiz);
126         if (tmpstr == NULL)
127                 return -ENOMEM;
128
129         s = tmpstr; /* points to current position in tmpstr[] */
130
131         if (*ppos == 0) {
132                 s += snprintf(s, tmpstr + tmpsiz - s, "Routing %s\n",
133                               the_lnet.ln_routing ? "enabled" : "disabled");
134                 LASSERT (tmpstr + tmpsiz - s > 0);
135
136                 s += snprintf(s, tmpstr + tmpsiz - s, "%-8s %4s %7s %s\n",
137                               "net", "hops", "state", "router");
138                 LASSERT (tmpstr + tmpsiz - s > 0);
139
140                 LNET_LOCK();
141                 *ver_p = (unsigned int)the_lnet.ln_remote_nets_version;
142                 LNET_UNLOCK();
143         } else {
144                 struct list_head  *n;
145                 struct list_head  *r;
146                 lnet_route_t      *route = NULL;
147                 lnet_remotenet_t  *rnet  = NULL;
148                 int                skip  = *ppos - 1;
149
150                 LNET_LOCK();
151
152                 if (*ver_p != (unsigned int)the_lnet.ln_remote_nets_version) {
153                         LNET_UNLOCK();
154                         LIBCFS_FREE(tmpstr, tmpsiz);
155                         return -ESTALE;
156                 }
157
158                 n = the_lnet.ln_remote_nets.next;
159
160                 while (n != &the_lnet.ln_remote_nets && route == NULL) {
161                         rnet = list_entry(n, lnet_remotenet_t, lrn_list);
162
163                         r = rnet->lrn_routes.next;
164
165                         while (r != &rnet->lrn_routes) {
166                                 lnet_route_t *re = list_entry(r, lnet_route_t,
167                                                               lr_list);
168                                 if (skip == 0) {
169                                         route = re;
170                                         break;
171                                 } else
172                                         skip--;
173
174                                 r = r->next;
175                         }
176
177                         n = n->next;
178                 }
179
180                 if (route != NULL) {
181                         __u32        net   = rnet->lrn_net;
182                         unsigned int hops  = rnet->lrn_hops;
183                         lnet_nid_t   nid   = route->lr_gateway->lp_nid;
184                         int          alive = route->lr_gateway->lp_alive;
185
186                         s += snprintf(s, tmpstr + tmpsiz - s, "%-8s %4u %7s %s\n",
187                                       libcfs_net2str(net), hops,
188                                       alive ? "up" : "down", libcfs_nid2str(nid));
189                         LASSERT (tmpstr + tmpsiz - s > 0);
190                 }
191
192                 LNET_UNLOCK();
193         }
194
195         len = s - tmpstr;     /* how many bytes was written */
196
197         if (len > *lenp) {    /* linux-supplied buffer is too small */
198                 rc = -EINVAL;
199         } else if (len > 0) { /* wrote something */
200                 if (copy_to_user(buffer, tmpstr, len))
201                         rc = -EFAULT;
202                 else
203                         *ppos += 1;
204         }
205
206         LIBCFS_FREE(tmpstr, tmpsiz);
207
208         if (rc == 0)
209                 *lenp = len;
210
211         return rc;
212 }
213
214 int LL_PROC_PROTO(proc_lnet_routers)
215 {
216         int        rc = 0;
217         char      *tmpstr;
218         char      *s;
219         const int  tmpsiz = 256;
220         int        len;
221         int       *ver_p = (unsigned int *)(&filp->private_data);
222
223         DECLARE_LL_PROC_PPOS_DECL;
224
225         LASSERT (!write);
226
227         if (*lenp == 0)
228                 return 0;
229
230         LIBCFS_ALLOC(tmpstr, tmpsiz);
231         if (tmpstr == NULL)
232                 return -ENOMEM;
233
234         s = tmpstr; /* points to current position in tmpstr[] */
235
236         if (*ppos == 0) {
237                 s += snprintf(s, tmpstr + tmpsiz - s,
238                               "%-4s %7s %9s %6s %12s %s\n",
239                               "ref", "rtr_ref", "alive_cnt", "state",
240                               "last_ping", "router");
241                 LASSERT (tmpstr + tmpsiz - s > 0);
242
243                 LNET_LOCK();
244                 *ver_p = (unsigned int)the_lnet.ln_routers_version;
245                 LNET_UNLOCK();
246         } else {
247                 struct list_head  *r;
248                 lnet_peer_t       *peer = NULL;
249                 int                skip = *ppos - 1;
250
251                 LNET_LOCK();
252
253                 if (*ver_p != (unsigned int)the_lnet.ln_routers_version) {
254                         LNET_UNLOCK();
255                         LIBCFS_FREE(tmpstr, tmpsiz);
256                         return -ESTALE;
257                 }
258
259                 r = the_lnet.ln_routers.next;
260
261                 while (r != &the_lnet.ln_routers) {
262                         lnet_peer_t *lp = list_entry(r, lnet_peer_t,
263                                                      lp_rtr_list);
264
265                         if (skip == 0) {
266                                 peer = lp;
267                                         break;
268                                 } else
269                                         skip--;
270
271                         r = r->next;
272                 }
273
274                 if (peer != NULL) {
275                         int        nrefs     = peer->lp_refcount;
276                         int        nrtrrefs  = peer->lp_rtr_refcount;
277                         int        alive_cnt = peer->lp_alive_count;
278                         int        alive     = peer->lp_alive;
279                         time_t     last_ping = peer->lp_ping_timestamp;
280                         lnet_nid_t nid       = peer->lp_nid;
281
282                         s += snprintf(s, tmpstr + tmpsiz - s,
283                                       "%-4d %7d %9d %6s %12lu %s\n",
284                                       nrefs, nrtrrefs,
285                                       alive_cnt, alive ? "up" : "down",
286                                       last_ping, libcfs_nid2str(nid));
287                         LASSERT (tmpstr + tmpsiz - s > 0);
288                 }
289
290                 LNET_UNLOCK();
291         }
292
293         len = s - tmpstr;     /* how many bytes was written */
294
295         if (len > *lenp) {    /* linux-supplied buffer is too small */
296                 rc = -EINVAL;
297         } else if (len > 0) { /* wrote something */
298                 if (copy_to_user(buffer, tmpstr, len))
299                         rc = -EFAULT;
300                 else
301                         *ppos += 1;
302         }
303
304         LIBCFS_FREE(tmpstr, tmpsiz);
305
306         if (rc == 0)
307                 *lenp = len;
308
309         return rc;
310 }
311
312 /*
313  * NB: we don't use the highest bit of *ppos because it's signed;
314  *     next 9 bits is used to stash idx (assuming that
315  *     LNET_PEER_HASHSIZE < 512)
316  */
317 #define LNET_LOFFT_BITS (sizeof(loff_t) * 8)
318 #define LNET_PHASH_BITS 9
319 #define LNET_PHASH_IDX_MASK (((1ULL << LNET_PHASH_BITS) - 1) <<               \
320                              (LNET_LOFFT_BITS - LNET_PHASH_BITS - 1))
321 #define LNET_PHASH_NUM_MASK ((1ULL <<                                         \
322                               (LNET_LOFFT_BITS - LNET_PHASH_BITS -1)) - 1)
323 #define LNET_PHASH_IDX_GET(pos) (int)(((pos) & LNET_PHASH_IDX_MASK) >>  \
324                                       (LNET_LOFFT_BITS - LNET_PHASH_BITS -1))
325 #define LNET_PHASH_NUM_GET(pos) (int)((pos) & LNET_PHASH_NUM_MASK)
326 #define LNET_PHASH_POS_MAKE(idx, num) ((((loff_t)idx) << (LNET_LOFFT_BITS -   \
327                                                   LNET_PHASH_BITS -1)) | (num))
328
329 int LL_PROC_PROTO(proc_lnet_peers)
330 {
331         int        rc = 0;
332         char      *tmpstr;
333         char      *s;
334         const int  tmpsiz      = 256;
335         int        len;
336         int       *ver_p       = (unsigned int *)(&filp->private_data);
337         int        idx;
338         int        num;
339
340         DECLARE_LL_PROC_PPOS_DECL;
341
342         idx = LNET_PHASH_IDX_GET(*ppos);
343         num = LNET_PHASH_NUM_GET(*ppos);
344
345         CLASSERT ((1 << LNET_PHASH_BITS) > LNET_PEER_HASHSIZE);
346
347         LASSERT (!write);
348
349         if (*lenp == 0)
350                 return 0;
351
352         LIBCFS_ALLOC(tmpstr, tmpsiz);
353         if (tmpstr == NULL)
354                 return -ENOMEM;
355
356         s = tmpstr; /* points to current position in tmpstr[] */
357
358         if (*ppos == 0) {
359                 s += snprintf(s, tmpstr + tmpsiz - s,
360                               "%-24s %4s %5s %5s %5s %5s %5s %5s %s\n",
361                               "nid", "refs", "state", "max",
362                               "rtr", "min", "tx", "min", "queue");
363                 LASSERT (tmpstr + tmpsiz - s > 0);
364
365                 LNET_LOCK();
366                 *ver_p  = (unsigned int)the_lnet.ln_peertable_version;
367                 LNET_UNLOCK();
368
369                 num++;
370         } else {
371                 struct list_head  *p    = NULL;
372                 lnet_peer_t       *peer = NULL;
373                 int                skip = num - 1;
374
375                 LNET_LOCK();
376
377                 if (*ver_p != (unsigned int)the_lnet.ln_peertable_version) {
378                         LNET_UNLOCK();
379                         LIBCFS_FREE(tmpstr, tmpsiz);
380                         return -ESTALE;
381                 }
382
383                 while (idx < LNET_PEER_HASHSIZE) {
384                         if (p == NULL)
385                                 p = the_lnet.ln_peer_hash[idx].next;
386
387                         while (p != &the_lnet.ln_peer_hash[idx]) {
388                                 lnet_peer_t *lp = list_entry(p, lnet_peer_t,
389                                                              lp_hashlist);
390                                 if (skip == 0) {
391                                         peer = lp;
392
393                                         /* minor optimiztion: start from idx+1
394                                          * on next iteration if we've just
395                                          * drained lp_hashlist */
396                                         if (lp->lp_hashlist.next ==
397                                             &the_lnet.ln_peer_hash[idx]) {
398                                                 num = 1;
399                                                 idx++;
400                                         } else
401                                                 num++;
402
403                                         break;
404                                 } else
405                                         skip--;
406
407                                 p = lp->lp_hashlist.next;
408                         }
409
410                         if (peer != NULL)
411                                 break;
412
413                         p = NULL;
414                         num = 1;
415                         idx++;
416                 }
417
418                 if (peer != NULL) {
419                         lnet_nid_t nid       = peer->lp_nid;
420                         int        nrefs     = peer->lp_refcount;
421                         char      *aliveness = "NA";
422                         int        maxcr     = peer->lp_ni->ni_peertxcredits;
423                         int        txcr      = peer->lp_txcredits;
424                         int        mintxcr   = peer->lp_mintxcredits;
425                         int        rtrcr     = peer->lp_rtrcredits;
426                         int        minrtrcr  = peer->lp_minrtrcredits;
427                         int        txqnob    = peer->lp_txqnob;
428
429                         if (lnet_isrouter(peer) ||
430                             peer->lp_ni->ni_peertimeout > 0)
431                                 aliveness = peer->lp_alive ? "up" : "down";
432
433                         s += snprintf(s, tmpstr + tmpsiz - s,
434                                       "%-24s %4d %5s %5d %5d %5d %5d %5d %d\n",
435                                       libcfs_nid2str(nid), nrefs, aliveness,
436                                       maxcr, rtrcr, minrtrcr, txcr,
437                                       mintxcr, txqnob);
438                         LASSERT (tmpstr + tmpsiz - s > 0);
439                 }
440
441                 LNET_UNLOCK();
442         }
443
444         len = s - tmpstr;     /* how many bytes was written */
445
446         if (len > *lenp) {    /* linux-supplied buffer is too small */
447                 rc = -EINVAL;
448         } else if (len > 0) { /* wrote something */
449                 if (copy_to_user(buffer, tmpstr, len))
450                         rc = -EFAULT;
451                 else
452                         *ppos = LNET_PHASH_POS_MAKE(idx, num);
453         }
454
455         LIBCFS_FREE(tmpstr, tmpsiz);
456
457         if (rc == 0)
458                 *lenp = len;
459
460         return rc;
461 }
462
463 static int __proc_lnet_buffers(void *data, int write,
464                                loff_t pos, void *buffer, int nob)
465 {
466
467         int              rc;
468         int              len;
469         char            *s;
470         char            *tmpstr;
471         const int        tmpsiz = 64 * (LNET_NRBPOOLS + 1); /* (4 %d) * 4 */
472         int              idx;
473
474         LASSERT (!write);
475
476         LIBCFS_ALLOC(tmpstr, tmpsiz);
477         if (tmpstr == NULL)
478                 return -ENOMEM;
479
480         s = tmpstr; /* points to current position in tmpstr[] */
481
482         s += snprintf(s, tmpstr + tmpsiz - s,
483                       "%5s %5s %7s %7s\n",
484                       "pages", "count", "credits", "min");
485         LASSERT (tmpstr + tmpsiz - s > 0);
486
487         LNET_LOCK();
488
489         for (idx = 0; idx < LNET_NRBPOOLS; idx++) {
490                 lnet_rtrbufpool_t *rbp = &the_lnet.ln_rtrpools[idx];
491
492                 int npages = rbp->rbp_npages;
493                 int nbuf   = rbp->rbp_nbuffers;
494                 int cr     = rbp->rbp_credits;
495                 int mincr  = rbp->rbp_mincredits;
496
497                 s += snprintf(s, tmpstr + tmpsiz - s,
498                               "%5d %5d %7d %7d\n",
499                               npages, nbuf, cr, mincr);
500                 LASSERT (tmpstr + tmpsiz - s > 0);
501         }
502
503         LNET_UNLOCK();
504
505         len = s - tmpstr;
506
507         if (pos >= min_t(int, len, strlen(tmpstr)))
508                 rc = 0;
509         else
510                 rc = trace_copyout_string(buffer, nob,
511                                           tmpstr + pos, NULL);
512
513         LIBCFS_FREE(tmpstr, tmpsiz);
514         return rc;
515 }
516
517 DECLARE_PROC_HANDLER(proc_lnet_buffers);
518
519 int LL_PROC_PROTO(proc_lnet_nis)
520 {
521         int        rc = 0;
522         char      *tmpstr;
523         char      *s;
524         const int  tmpsiz = 256;
525         int        len;
526
527         DECLARE_LL_PROC_PPOS_DECL;
528
529         LASSERT (!write);
530
531         if (*lenp == 0)
532                 return 0;
533
534         LIBCFS_ALLOC(tmpstr, tmpsiz);
535         if (tmpstr == NULL)
536                 return -ENOMEM;
537
538         s = tmpstr; /* points to current position in tmpstr[] */
539
540         if (*ppos == 0) {
541                 s += snprintf(s, tmpstr + tmpsiz - s,
542                               "%-24s %4s %4s %4s %5s %5s %5s\n",
543                               "nid", "refs", "peer", "rtr", "max",
544                               "tx", "min");
545                 LASSERT (tmpstr + tmpsiz - s > 0);
546         } else {
547                 struct list_head  *n;
548                 lnet_ni_t         *ni   = NULL;
549                 int                skip = *ppos - 1;
550
551                 LNET_LOCK();
552
553                 n = the_lnet.ln_nis.next;
554
555                 while (n != &the_lnet.ln_nis) {
556                         lnet_ni_t *a_ni = list_entry(n, lnet_ni_t, ni_list);
557
558                         if (skip == 0) {
559                                 ni = a_ni;
560                                 break;
561                         } else
562                                 skip--;
563
564                         n = n->next;
565                 }
566
567                 if (ni != NULL) {
568                         int        maxtxcr = ni->ni_maxtxcredits;
569                         int        txcr = ni->ni_txcredits;
570                         int        mintxcr = ni->ni_mintxcredits;
571                         int        npeertxcr = ni->ni_peertxcredits;
572                         int        npeerrtrcr = ni->ni_peerrtrcredits;
573                         lnet_nid_t nid = ni->ni_nid;
574                         int        nref = ni->ni_refcount;
575
576                         s += snprintf(s, tmpstr + tmpsiz - s,
577                                       "%-24s %4d %4d %4d %5d %5d %5d\n",
578                                       libcfs_nid2str(nid), nref,
579                                       npeertxcr, npeerrtrcr, maxtxcr,
580                                       txcr, mintxcr);
581                         LASSERT (tmpstr + tmpsiz - s > 0);
582                 }
583
584                 LNET_UNLOCK();
585         }
586
587         len = s - tmpstr;     /* how many bytes was written */
588
589         if (len > *lenp) {    /* linux-supplied buffer is too small */
590                 rc = -EINVAL;
591         } else if (len > 0) { /* wrote something */
592                 if (copy_to_user(buffer, tmpstr, len))
593                         rc = -EFAULT;
594                 else
595                         *ppos += 1;
596         }
597
598         LIBCFS_FREE(tmpstr, tmpsiz);
599
600         if (rc == 0)
601                 *lenp = len;
602
603         return rc;
604 }
605
606 static cfs_sysctl_table_t lnet_table[] = {
607         /*
608          * NB No .strategy entries have been provided since sysctl(8) prefers
609          * to go via /proc for portability.
610          */
611         {
612                 .ctl_name = PSDEV_LNET_STATS,
613                 .procname = "stats",
614                 .mode     = 0644,
615                 .proc_handler = &proc_lnet_stats,
616         },
617         {
618                 .ctl_name = PSDEV_LNET_ROUTES,
619                 .procname = "routes",
620                 .mode     = 0444,
621                 .proc_handler = &proc_lnet_routes,
622         },
623         {
624                 .ctl_name = PSDEV_LNET_ROUTERS,
625                 .procname = "routers",
626                 .mode     = 0444,
627                 .proc_handler = &proc_lnet_routers,
628         },
629         {
630                 .ctl_name = PSDEV_LNET_PEERS,
631                 .procname = "peers",
632                 .mode     = 0444,
633                 .proc_handler = &proc_lnet_peers,
634         },
635         {
636                 .ctl_name = PSDEV_LNET_PEERS,
637                 .procname = "buffers",
638                 .mode     = 0444,
639                 .proc_handler = &proc_lnet_buffers,
640         },
641         {
642                 .ctl_name = PSDEV_LNET_NIS,
643                 .procname = "nis",
644                 .mode     = 0444,
645                 .proc_handler = &proc_lnet_nis,
646         },
647         {0}
648 };
649
650 static cfs_sysctl_table_t top_table[] = {
651         {
652                 .ctl_name = CTL_LNET,
653                 .procname = "lnet",
654                 .mode     = 0555,
655                 .data     = NULL,
656                 .maxlen   = 0,
657                 .child    = lnet_table,
658         },
659         {
660                 .ctl_name = 0
661         }
662 };
663
664 void
665 lnet_proc_init(void)
666 {
667 #ifdef CONFIG_SYSCTL
668         if (lnet_table_header == NULL)
669                 lnet_table_header = cfs_register_sysctl_table(top_table, 0);
670 #endif
671 }
672
673 void
674 lnet_proc_fini(void)
675 {
676 #ifdef CONFIG_SYSCTL
677         if (lnet_table_header != NULL)
678                 cfs_unregister_sysctl_table(lnet_table_header);
679
680         lnet_table_header = NULL;
681 #endif
682 }
683
684 #else
685
686 void
687 lnet_proc_init(void)
688 {
689 }
690
691 void
692 lnet_proc_fini(void)
693 {
694 }
695
696 #endif