Whamcloud - gitweb
Update copyrights on source files changed since 2010-02-15.
[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 (c) 2007, 2010, Oracle and/or its affiliates. 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 /*
55  * NB: we don't use the highest bit of *ppos because it's signed;
56  *     next 9 bits is used to stash idx (assuming that
57  *     LNET_PEER_HASHSIZE < 512)
58  */
59 #define LNET_LOFFT_BITS        (sizeof(loff_t) * 8)
60 #define LNET_VERSION_BITS      MAX(((MIN(LNET_LOFFT_BITS, 64)) / 4), 8)
61 #define LNET_PHASH_IDX_BITS    9
62 #define LNET_PHASH_NUM_BITS    (LNET_LOFFT_BITS - 1 -\
63                                 LNET_VERSION_BITS - LNET_PHASH_IDX_BITS)
64 #define LNET_PHASH_BITS        (LNET_PHASH_IDX_BITS + LNET_PHASH_NUM_BITS)
65
66 #define LNET_VERSION_BITMASK   ((1ULL << LNET_VERSION_BITS) - 1)
67 #define LNET_PHASH_IDX_BITMASK ((1ULL << LNET_PHASH_IDX_BITS) - 1)
68 #define LNET_PHASH_NUM_BITMASK ((1ULL << LNET_PHASH_NUM_BITS) - 1)
69
70 #define LNET_VERSION_MASK      (LNET_VERSION_BITMASK << LNET_PHASH_BITS)
71 #define LNET_PHASH_IDX_MASK    (LNET_PHASH_IDX_BITMASK << LNET_PHASH_NUM_BITS)
72 #define LNET_PHASH_NUM_MASK    (LNET_PHASH_NUM_BITMASK)
73
74 #define LNET_VERSION_GET(pos)   (int)(((pos) & LNET_VERSION_MASK) >> \
75                                      LNET_PHASH_BITS)
76 #define LNET_PHASH_IDX_GET(pos) (int)(((pos) & LNET_PHASH_IDX_MASK) >> \
77                                       LNET_PHASH_NUM_BITS)
78 #define LNET_PHASH_NUM_GET(pos) (int)((pos) & LNET_PHASH_NUM_MASK)
79 #define LNET_VERSION_VALID_MASK(ver) \
80                                 (unsigned int)((ver) & \
81                                  LNET_VERSION_BITMASK)
82 #define LNET_PHASH_POS_MAKE(ver, idx, num)                                     \
83                                 (((((loff_t)(ver)) & LNET_VERSION_BITMASK) <<  \
84                                    LNET_PHASH_BITS) |                          \
85                                  ((((loff_t)(idx)) & LNET_PHASH_IDX_BITMASK) <<\
86                                    LNET_PHASH_NUM_BITS) |                      \
87                                  ((num) & LNET_PHASH_NUM_BITMASK))
88
89 static int __proc_lnet_stats(void *data, int write,
90                              loff_t pos, void *buffer, int nob)
91 {
92         int              rc;
93         lnet_counters_t *ctrs;
94         int              len;
95         char            *tmpstr;
96         const int        tmpsiz = 256; /* 7 %u and 4 LPU64 */
97
98         if (write) {
99                 LNET_LOCK();
100                 memset(&the_lnet.ln_counters, 0, sizeof(the_lnet.ln_counters));
101                 LNET_UNLOCK();
102                 return 0;
103         }
104
105         /* read */
106
107         LIBCFS_ALLOC(ctrs, sizeof(*ctrs));
108         if (ctrs == NULL)
109                 return -ENOMEM;
110
111         LIBCFS_ALLOC(tmpstr, tmpsiz);
112         if (tmpstr == NULL) {
113                 LIBCFS_FREE(ctrs, sizeof(*ctrs));
114                 return -ENOMEM;
115         }
116
117         LNET_LOCK();
118         *ctrs = the_lnet.ln_counters;
119         LNET_UNLOCK();
120
121         len = snprintf(tmpstr, tmpsiz,
122                        "%u %u %u %u %u %u %u "LPU64" "LPU64" "
123                        LPU64" "LPU64,
124                        ctrs->msgs_alloc, ctrs->msgs_max,
125                        ctrs->errors,
126                        ctrs->send_count, ctrs->recv_count,
127                        ctrs->route_count, ctrs->drop_count,
128                        ctrs->send_length, ctrs->recv_length,
129                        ctrs->route_length, ctrs->drop_length);
130
131         if (pos >= min_t(int, len, strlen(tmpstr)))
132                 rc = 0;
133         else
134                 rc = cfs_trace_copyout_string(buffer, nob,
135                                               tmpstr + pos, "\n");
136
137         LIBCFS_FREE(tmpstr, tmpsiz);
138         LIBCFS_FREE(ctrs, sizeof(*ctrs));
139         return rc;
140 }
141
142 DECLARE_PROC_HANDLER(proc_lnet_stats);
143
144 int LL_PROC_PROTO(proc_lnet_routes)
145 {
146         int        rc     = 0;
147         char      *tmpstr;
148         char      *s;
149         const int  tmpsiz = 256;
150         int        len;
151         int        ver;
152         int        num;
153
154         DECLARE_LL_PROC_PPOS_DECL;
155
156         num = LNET_PHASH_NUM_GET(*ppos);
157         ver = LNET_VERSION_GET(*ppos);
158
159         LASSERT (!write);
160
161         if (*lenp == 0)
162                 return 0;
163
164         LIBCFS_ALLOC(tmpstr, tmpsiz);
165         if (tmpstr == NULL)
166                 return -ENOMEM;
167
168         s = tmpstr; /* points to current position in tmpstr[] */
169
170         if (*ppos == 0) {
171                 s += snprintf(s, tmpstr + tmpsiz - s, "Routing %s\n",
172                               the_lnet.ln_routing ? "enabled" : "disabled");
173                 LASSERT (tmpstr + tmpsiz - s > 0);
174
175                 s += snprintf(s, tmpstr + tmpsiz - s, "%-8s %4s %7s %s\n",
176                               "net", "hops", "state", "router");
177                 LASSERT (tmpstr + tmpsiz - s > 0);
178
179                 LNET_LOCK();
180                 ver = (unsigned int)the_lnet.ln_remote_nets_version;
181                 LNET_UNLOCK();
182                 *ppos = LNET_PHASH_POS_MAKE(ver, 0, num);
183         } else {
184                 cfs_list_t        *n;
185                 cfs_list_t        *r;
186                 lnet_route_t      *route = NULL;
187                 lnet_remotenet_t  *rnet  = NULL;
188                 int                skip  = num - 1;
189
190                 LNET_LOCK();
191
192                 if (ver != LNET_VERSION_VALID_MASK(the_lnet.ln_remote_nets_version)) {
193                         LNET_UNLOCK();
194                         LIBCFS_FREE(tmpstr, tmpsiz);
195                         return -ESTALE;
196                 }
197
198                 n = the_lnet.ln_remote_nets.next;
199
200                 while (n != &the_lnet.ln_remote_nets && route == NULL) {
201                         rnet = cfs_list_entry(n, lnet_remotenet_t, lrn_list);
202
203                         r = rnet->lrn_routes.next;
204
205                         while (r != &rnet->lrn_routes) {
206                                 lnet_route_t *re =
207                                         cfs_list_entry(r, lnet_route_t,
208                                                        lr_list);
209                                 if (skip == 0) {
210                                         route = re;
211                                         break;
212                                 }
213
214                                 skip--;
215                                 r = r->next;
216                         }
217
218                         n = n->next;
219                 }
220
221                 if (route != NULL) {
222                         __u32        net   = rnet->lrn_net;
223                         unsigned int hops  = route->lr_hops;
224                         lnet_nid_t   nid   = route->lr_gateway->lp_nid;
225                         int          alive = route->lr_gateway->lp_alive;
226
227                         s += snprintf(s, tmpstr + tmpsiz - s, "%-8s %4u %7s %s\n",
228                                       libcfs_net2str(net), hops,
229                                       alive ? "up" : "down", libcfs_nid2str(nid));
230                         LASSERT (tmpstr + tmpsiz - s > 0);
231                 }
232
233                 LNET_UNLOCK();
234         }
235
236         len = s - tmpstr;     /* how many bytes was written */
237
238         if (len > *lenp) {    /* linux-supplied buffer is too small */
239                 rc = -EINVAL;
240         } else if (len > 0) { /* wrote something */
241                 if (cfs_copy_to_user(buffer, tmpstr, len))
242                         rc = -EFAULT;
243                 else {
244                         num += 1;
245                         *ppos = LNET_PHASH_POS_MAKE(ver, 0, num);
246                 }
247         }
248
249         LIBCFS_FREE(tmpstr, tmpsiz);
250
251         if (rc == 0)
252                 *lenp = len;
253
254         return rc;
255 }
256
257 int LL_PROC_PROTO(proc_lnet_routers)
258 {
259         int        rc = 0;
260         char      *tmpstr;
261         char      *s;
262         const int  tmpsiz = 256;
263         int        len;
264         int        ver;
265         int        num;
266
267         DECLARE_LL_PROC_PPOS_DECL;
268
269         num = LNET_PHASH_NUM_GET(*ppos);
270         ver = LNET_VERSION_GET(*ppos);
271
272         LASSERT (!write);
273
274         if (*lenp == 0)
275                 return 0;
276
277         LIBCFS_ALLOC(tmpstr, tmpsiz);
278         if (tmpstr == NULL)
279                 return -ENOMEM;
280
281         s = tmpstr; /* points to current position in tmpstr[] */
282
283         if (*ppos == 0) {
284                 s += snprintf(s, tmpstr + tmpsiz - s,
285                               "%-4s %7s %9s %6s %12s %9s %8s %7s %s\n",
286                               "ref", "rtr_ref", "alive_cnt", "state", "last_ping",
287                               "ping_sent", "deadline", "down_ni", "router");
288                 LASSERT (tmpstr + tmpsiz - s > 0);
289
290                 LNET_LOCK();
291                 ver = (unsigned int)the_lnet.ln_routers_version;
292                 LNET_UNLOCK();
293                 *ppos = LNET_PHASH_POS_MAKE(ver, 0, num);
294         } else {
295                 cfs_list_t        *r;
296                 lnet_peer_t       *peer = NULL;
297                 int                skip = num - 1;
298
299                 LNET_LOCK();
300
301                 if (ver != LNET_VERSION_VALID_MASK(the_lnet.ln_routers_version)) {
302                         LNET_UNLOCK();
303                         LIBCFS_FREE(tmpstr, tmpsiz);
304                         return -ESTALE;
305                 }
306
307                 r = the_lnet.ln_routers.next;
308
309                 while (r != &the_lnet.ln_routers) {
310                         lnet_peer_t *lp = cfs_list_entry(r, lnet_peer_t,
311                                                          lp_rtr_list);
312
313                         if (skip == 0) {
314                                 peer = lp;
315                                 break;
316                         }
317
318                         skip--;
319                         r = r->next;
320                 }
321
322                 if (peer != NULL) {
323                         lnet_nid_t nid = peer->lp_nid;
324                         cfs_time_t now = cfs_time_current();
325                         cfs_time_t deadline = peer->lp_ping_deadline;
326                         int nrefs     = peer->lp_refcount;
327                         int nrtrrefs  = peer->lp_rtr_refcount;
328                         int alive_cnt = peer->lp_alive_count;
329                         int alive     = peer->lp_alive;
330                         int pingsent  = !peer->lp_ping_notsent;
331                         int last_ping = cfs_duration_sec(cfs_time_sub(now,
332                                                      peer->lp_ping_timestamp));
333                         int down_ni   = lnet_router_down_ni(peer,
334                                                     LNET_NIDNET(LNET_NID_ANY));
335
336                         if (deadline == 0)
337                                 s += snprintf(s, tmpstr + tmpsiz - s,
338                                               "%-4d %7d %9d %6s %12d %9d %8s %7d %s\n",
339                                               nrefs, nrtrrefs, alive_cnt,
340                                               alive ? "up" : "down", last_ping,
341                                               pingsent, "NA", down_ni,
342                                               libcfs_nid2str(nid));
343                         else
344                                 s += snprintf(s, tmpstr + tmpsiz - s,
345                                               "%-4d %7d %9d %6s %12d %9d %8lu %7d %s\n",
346                                               nrefs, nrtrrefs, alive_cnt,
347                                               alive ? "up" : "down", last_ping,
348                                               pingsent,
349                                               cfs_duration_sec(cfs_time_sub(deadline, now)),
350                                               down_ni, libcfs_nid2str(nid));
351                         LASSERT (tmpstr + tmpsiz - s > 0);
352                 }
353
354                 LNET_UNLOCK();
355         }
356
357         len = s - tmpstr;     /* how many bytes was written */
358
359         if (len > *lenp) {    /* linux-supplied buffer is too small */
360                 rc = -EINVAL;
361         } else if (len > 0) { /* wrote something */
362                 if (cfs_copy_to_user(buffer, tmpstr, len))
363                         rc = -EFAULT;
364                 else {
365                         num += 1;
366                         *ppos = LNET_PHASH_POS_MAKE(ver, 0, num);
367                 }
368         }
369
370         LIBCFS_FREE(tmpstr, tmpsiz);
371
372         if (rc == 0)
373                 *lenp = len;
374
375         return rc;
376 }
377
378 int LL_PROC_PROTO(proc_lnet_peers)
379 {
380         int        rc = 0;
381         char      *tmpstr;
382         char      *s;
383         const int  tmpsiz      = 256;
384         int        len;
385         int        ver;
386         int        idx;
387         int        num;
388
389         DECLARE_LL_PROC_PPOS_DECL;
390
391         idx = LNET_PHASH_IDX_GET(*ppos);
392         num = LNET_PHASH_NUM_GET(*ppos);
393         ver = LNET_VERSION_GET(*ppos);
394
395         CLASSERT ((1ULL << LNET_PHASH_BITS) > LNET_PEER_HASHSIZE);
396
397         LASSERT (!write);
398
399         if (*lenp == 0)
400                 return 0;
401
402         LIBCFS_ALLOC(tmpstr, tmpsiz);
403         if (tmpstr == NULL)
404                 return -ENOMEM;
405
406         s = tmpstr; /* points to current position in tmpstr[] */
407
408         if (*ppos == 0) {
409                 s += snprintf(s, tmpstr + tmpsiz - s,
410                               "%-24s %4s %5s %5s %5s %5s %5s %5s %s\n",
411                               "nid", "refs", "state", "max",
412                               "rtr", "min", "tx", "min", "queue");
413                 LASSERT (tmpstr + tmpsiz - s > 0);
414
415                 LNET_LOCK();
416                 ver = (unsigned int)the_lnet.ln_peertable_version;
417                 LNET_UNLOCK();
418                 *ppos = LNET_PHASH_POS_MAKE(ver, idx, num);
419
420                 num++;
421         } else {
422                 cfs_list_t        *p    = NULL;
423                 lnet_peer_t       *peer = NULL;
424                 int                skip = num - 1;
425
426                 LNET_LOCK();
427
428                 if (ver != LNET_VERSION_VALID_MASK(the_lnet.ln_peertable_version)) {
429                         LNET_UNLOCK();
430                         LIBCFS_FREE(tmpstr, tmpsiz);
431                         return -ESTALE;
432                 }
433
434                 while (idx < LNET_PEER_HASHSIZE) {
435                         if (p == NULL)
436                                 p = the_lnet.ln_peer_hash[idx].next;
437
438                         while (p != &the_lnet.ln_peer_hash[idx]) {
439                                 lnet_peer_t *lp = cfs_list_entry(p, lnet_peer_t,
440                                                                  lp_hashlist);
441                                 if (skip == 0) {
442                                         peer = lp;
443
444                                         /* minor optimiztion: start from idx+1
445                                          * on next iteration if we've just
446                                          * drained lp_hashlist */
447                                         if (lp->lp_hashlist.next ==
448                                             &the_lnet.ln_peer_hash[idx]) {
449                                                 num = 1;
450                                                 idx++;
451                                         } else {
452                                                 num++;
453                                         }
454
455                                         break;
456                                 }
457
458                                 skip--;
459                                 p = lp->lp_hashlist.next;
460                         }
461
462                         if (peer != NULL)
463                                 break;
464
465                         p = NULL;
466                         num = 1;
467                         idx++;
468                 }
469
470                 if (peer != NULL) {
471                         lnet_nid_t nid       = peer->lp_nid;
472                         int        nrefs     = peer->lp_refcount;
473                         char      *aliveness = "NA";
474                         int        maxcr     = peer->lp_ni->ni_peertxcredits;
475                         int        txcr      = peer->lp_txcredits;
476                         int        mintxcr   = peer->lp_mintxcredits;
477                         int        rtrcr     = peer->lp_rtrcredits;
478                         int        minrtrcr  = peer->lp_minrtrcredits;
479                         int        txqnob    = peer->lp_txqnob;
480
481                         if (lnet_isrouter(peer) ||
482                             lnet_peer_aliveness_enabled(peer))
483                                 aliveness = peer->lp_alive ? "up" : "down";
484
485                         s += snprintf(s, tmpstr + tmpsiz - s,
486                                       "%-24s %4d %5s %5d %5d %5d %5d %5d %d\n",
487                                       libcfs_nid2str(nid), nrefs, aliveness,
488                                       maxcr, rtrcr, minrtrcr, txcr,
489                                       mintxcr, txqnob);
490                         LASSERT (tmpstr + tmpsiz - s > 0);
491                 }
492
493                 LNET_UNLOCK();
494         }
495
496         len = s - tmpstr;     /* how many bytes was written */
497
498         if (len > *lenp) {    /* linux-supplied buffer is too small */
499                 rc = -EINVAL;
500         } else if (len > 0) { /* wrote something */
501                 if (cfs_copy_to_user(buffer, tmpstr, len))
502                         rc = -EFAULT;
503                 else
504                         *ppos = LNET_PHASH_POS_MAKE(ver, idx, num);
505         }
506
507         LIBCFS_FREE(tmpstr, tmpsiz);
508
509         if (rc == 0)
510                 *lenp = len;
511
512         return rc;
513 }
514
515 static int __proc_lnet_buffers(void *data, int write,
516                                loff_t pos, void *buffer, int nob)
517 {
518
519         int              rc;
520         int              len;
521         char            *s;
522         char            *tmpstr;
523         const int        tmpsiz = 64 * (LNET_NRBPOOLS + 1); /* (4 %d) * 4 */
524         int              idx;
525
526         LASSERT (!write);
527
528         LIBCFS_ALLOC(tmpstr, tmpsiz);
529         if (tmpstr == NULL)
530                 return -ENOMEM;
531
532         s = tmpstr; /* points to current position in tmpstr[] */
533
534         s += snprintf(s, tmpstr + tmpsiz - s,
535                       "%5s %5s %7s %7s\n",
536                       "pages", "count", "credits", "min");
537         LASSERT (tmpstr + tmpsiz - s > 0);
538
539         LNET_LOCK();
540
541         for (idx = 0; idx < LNET_NRBPOOLS; idx++) {
542                 lnet_rtrbufpool_t *rbp = &the_lnet.ln_rtrpools[idx];
543
544                 int npages = rbp->rbp_npages;
545                 int nbuf   = rbp->rbp_nbuffers;
546                 int cr     = rbp->rbp_credits;
547                 int mincr  = rbp->rbp_mincredits;
548
549                 s += snprintf(s, tmpstr + tmpsiz - s,
550                               "%5d %5d %7d %7d\n",
551                               npages, nbuf, cr, mincr);
552                 LASSERT (tmpstr + tmpsiz - s > 0);
553         }
554
555         LNET_UNLOCK();
556
557         len = s - tmpstr;
558
559         if (pos >= min_t(int, len, strlen(tmpstr)))
560                 rc = 0;
561         else
562                 rc = cfs_trace_copyout_string(buffer, nob,
563                                               tmpstr + pos, NULL);
564
565         LIBCFS_FREE(tmpstr, tmpsiz);
566         return rc;
567 }
568
569 DECLARE_PROC_HANDLER(proc_lnet_buffers);
570
571 int LL_PROC_PROTO(proc_lnet_nis)
572 {
573         int        rc = 0;
574         char      *tmpstr;
575         char      *s;
576         const int  tmpsiz = 256;
577         int        len;
578
579         DECLARE_LL_PROC_PPOS_DECL;
580
581         LASSERT (!write);
582
583         if (*lenp == 0)
584                 return 0;
585
586         LIBCFS_ALLOC(tmpstr, tmpsiz);
587         if (tmpstr == NULL)
588                 return -ENOMEM;
589
590         s = tmpstr; /* points to current position in tmpstr[] */
591
592         if (*ppos == 0) {
593                 s += snprintf(s, tmpstr + tmpsiz - s,
594                               "%-24s %6s %5s %4s %4s %4s %5s %5s %5s\n",
595                               "nid", "status", "alive", "refs", "peer",
596                               "rtr", "max", "tx", "min");
597                 LASSERT (tmpstr + tmpsiz - s > 0);
598         } else {
599                 cfs_list_t        *n;
600                 lnet_ni_t         *ni   = NULL;
601                 int                skip = *ppos - 1;
602
603                 LNET_LOCK();
604
605                 n = the_lnet.ln_nis.next;
606
607                 while (n != &the_lnet.ln_nis) {
608                         lnet_ni_t *a_ni = cfs_list_entry(n, lnet_ni_t, ni_list);
609
610                         if (skip == 0) {
611                                 ni = a_ni;
612                                 break;
613                         }
614
615                         skip--;
616                         n = n->next;
617                 }
618
619                 if (ni != NULL) {
620                         cfs_time_t now = cfs_time_current();
621                         int        last_alive = -1;
622                         int        maxtxcr = ni->ni_maxtxcredits;
623                         int        txcr = ni->ni_txcredits;
624                         int        mintxcr = ni->ni_mintxcredits;
625                         int        npeertxcr = ni->ni_peertxcredits;
626                         int        npeerrtrcr = ni->ni_peerrtrcredits;
627                         lnet_nid_t nid = ni->ni_nid;
628                         int        nref = ni->ni_refcount;
629                         char      *stat;
630
631                         if (the_lnet.ln_routing)
632                                 last_alive = cfs_duration_sec(cfs_time_sub(now,
633                                                             ni->ni_last_alive));
634                         if (ni->ni_lnd->lnd_type == LOLND)  /* @lo forever alive */
635                                 last_alive = 0;
636
637                         LASSERT (ni->ni_status != NULL);
638                         stat = (ni->ni_status->ns_status == LNET_NI_STATUS_UP) ?
639                                                                   "up" : "down";
640
641                         s += snprintf(s, tmpstr + tmpsiz - s,
642                                       "%-24s %6s %5d %4d %4d %4d %5d %5d %5d\n",
643                                       libcfs_nid2str(nid), stat, last_alive, nref,
644                                       npeertxcr, npeerrtrcr, maxtxcr,
645                                       txcr, mintxcr);
646                         LASSERT (tmpstr + tmpsiz - s > 0);
647                 }
648
649                 LNET_UNLOCK();
650         }
651
652         len = s - tmpstr;     /* how many bytes was written */
653
654         if (len > *lenp) {    /* linux-supplied buffer is too small */
655                 rc = -EINVAL;
656         } else if (len > 0) { /* wrote something */
657                 if (cfs_copy_to_user(buffer, tmpstr, len))
658                         rc = -EFAULT;
659                 else
660                         *ppos += 1;
661         }
662
663         LIBCFS_FREE(tmpstr, tmpsiz);
664
665         if (rc == 0)
666                 *lenp = len;
667
668         return rc;
669 }
670
671 static cfs_sysctl_table_t lnet_table[] = {
672         /*
673          * NB No .strategy entries have been provided since sysctl(8) prefers
674          * to go via /proc for portability.
675          */
676         {
677                 .ctl_name = PSDEV_LNET_STATS,
678                 .procname = "stats",
679                 .mode     = 0644,
680                 .proc_handler = &proc_lnet_stats,
681         },
682         {
683                 .ctl_name = PSDEV_LNET_ROUTES,
684                 .procname = "routes",
685                 .mode     = 0444,
686                 .proc_handler = &proc_lnet_routes,
687         },
688         {
689                 .ctl_name = PSDEV_LNET_ROUTERS,
690                 .procname = "routers",
691                 .mode     = 0444,
692                 .proc_handler = &proc_lnet_routers,
693         },
694         {
695                 .ctl_name = PSDEV_LNET_PEERS,
696                 .procname = "peers",
697                 .mode     = 0444,
698                 .proc_handler = &proc_lnet_peers,
699         },
700         {
701                 .ctl_name = PSDEV_LNET_PEERS,
702                 .procname = "buffers",
703                 .mode     = 0444,
704                 .proc_handler = &proc_lnet_buffers,
705         },
706         {
707                 .ctl_name = PSDEV_LNET_NIS,
708                 .procname = "nis",
709                 .mode     = 0444,
710                 .proc_handler = &proc_lnet_nis,
711         },
712         {0}
713 };
714
715 static cfs_sysctl_table_t top_table[] = {
716         {
717                 .ctl_name = CTL_LNET,
718                 .procname = "lnet",
719                 .mode     = 0555,
720                 .data     = NULL,
721                 .maxlen   = 0,
722                 .child    = lnet_table,
723         },
724         {
725                 .ctl_name = 0
726         }
727 };
728
729 void
730 lnet_proc_init(void)
731 {
732 #ifdef CONFIG_SYSCTL
733         if (lnet_table_header == NULL)
734                 lnet_table_header = cfs_register_sysctl_table(top_table, 0);
735 #endif
736 }
737
738 void
739 lnet_proc_fini(void)
740 {
741 #ifdef CONFIG_SYSCTL
742         if (lnet_table_header != NULL)
743                 cfs_unregister_sysctl_table(lnet_table_header);
744
745         lnet_table_header = NULL;
746 #endif
747 }
748
749 #else
750
751 void
752 lnet_proc_init(void)
753 {
754 }
755
756 void
757 lnet_proc_fini(void)
758 {
759 }
760
761 #endif