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