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