Whamcloud - gitweb
fde0e0ad3fa97c604d0d7108cc586db160b26175
[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. 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         int        rc = 0;
382         char      *tmpstr;
383         char      *s;
384         const int  tmpsiz      = 256;
385         int        len;
386         int        ver;
387         int        idx;
388         int        num;
389
390         DECLARE_LL_PROC_PPOS_DECL;
391
392         idx = LNET_PHASH_IDX_GET(*ppos);
393         num = LNET_PHASH_NUM_GET(*ppos);
394         ver = LNET_VERSION_GET(*ppos);
395
396         CLASSERT ((1ULL << LNET_PHASH_BITS) > LNET_PEER_HASHSIZE);
397
398         LASSERT (!write);
399
400         if (*lenp == 0)
401                 return 0;
402
403         LIBCFS_ALLOC(tmpstr, tmpsiz);
404         if (tmpstr == NULL)
405                 return -ENOMEM;
406
407         s = tmpstr; /* points to current position in tmpstr[] */
408
409         if (*ppos == 0) {
410                 s += snprintf(s, tmpstr + tmpsiz - s,
411                               "%-24s %4s %5s %5s %5s %5s %5s %5s %5s %s\n",
412                               "nid", "refs", "state", "last", "max",
413                               "rtr", "min", "tx", "min", "queue");
414                 LASSERT (tmpstr + tmpsiz - s > 0);
415
416                 LNET_LOCK();
417                 ver = (unsigned int)the_lnet.ln_peertable_version;
418                 LNET_UNLOCK();
419                 *ppos = LNET_PHASH_POS_MAKE(ver, idx, num);
420
421                 num++;
422         } else {
423                 cfs_list_t        *p    = NULL;
424                 lnet_peer_t       *peer = NULL;
425                 int                skip = num - 1;
426
427                 LNET_LOCK();
428
429                 if (ver != LNET_VERSION_VALID_MASK(the_lnet.ln_peertable_version)) {
430                         LNET_UNLOCK();
431                         LIBCFS_FREE(tmpstr, tmpsiz);
432                         return -ESTALE;
433                 }
434
435                 while (idx < LNET_PEER_HASHSIZE) {
436                         if (p == NULL)
437                                 p = the_lnet.ln_peer_hash[idx].next;
438
439                         while (p != &the_lnet.ln_peer_hash[idx]) {
440                                 lnet_peer_t *lp = cfs_list_entry(p, lnet_peer_t,
441                                                                  lp_hashlist);
442                                 if (skip == 0) {
443                                         peer = lp;
444
445                                         /* minor optimization: start from idx+1
446                                          * on next iteration if we've just
447                                          * drained lp_hashlist */
448                                         if (lp->lp_hashlist.next ==
449                                             &the_lnet.ln_peer_hash[idx]) {
450                                                 num = 1;
451                                                 idx++;
452                                         } else {
453                                                 num++;
454                                         }
455
456                                         break;
457                                 }
458
459                                 skip--;
460                                 p = lp->lp_hashlist.next;
461                         }
462
463                         if (peer != NULL)
464                                 break;
465
466                         p = NULL;
467                         num = 1;
468                         idx++;
469                 }
470
471                 if (peer != NULL) {
472                         lnet_nid_t nid       = peer->lp_nid;
473                         int        nrefs     = peer->lp_refcount;
474                         int        lastalive = -1;
475                         char      *aliveness = "NA";
476                         int        maxcr     = peer->lp_ni->ni_peertxcredits;
477                         int        txcr      = peer->lp_txcredits;
478                         int        mintxcr   = peer->lp_mintxcredits;
479                         int        rtrcr     = peer->lp_rtrcredits;
480                         int        minrtrcr  = peer->lp_minrtrcredits;
481                         int        txqnob    = peer->lp_txqnob;
482
483                         if (lnet_isrouter(peer) ||
484                             lnet_peer_aliveness_enabled(peer))
485                                 aliveness = peer->lp_alive ? "up" : "down";
486
487                         if (lnet_peer_aliveness_enabled(peer)) {
488                                 cfs_time_t     now = cfs_time_current();
489                                 cfs_duration_t delta;
490
491                                 delta = cfs_time_sub(now, peer->lp_last_alive);
492                                 lastalive = cfs_duration_sec(delta);
493
494                                 /* No need to mess up peers contents with
495                                  * arbitrarily long integers - it suffices to
496                                  * know that lastalive is more than 10000s old
497                                  */
498                                 if (lastalive >= 10000)
499                                         lastalive = 9999;
500                         }
501
502                         s += snprintf(s, tmpstr + tmpsiz - s,
503                                       "%-24s %4d %5s %5d %5d %5d %5d %5d %5d %d\n",
504                                       libcfs_nid2str(nid), nrefs, aliveness,
505                                       lastalive, maxcr, rtrcr, minrtrcr, txcr,
506                                       mintxcr, txqnob);
507                         LASSERT (tmpstr + tmpsiz - s > 0);
508                 }
509
510                 LNET_UNLOCK();
511         }
512
513         len = s - tmpstr;     /* how many bytes was written */
514
515         if (len > *lenp) {    /* linux-supplied buffer is too small */
516                 rc = -EINVAL;
517         } else if (len > 0) { /* wrote something */
518                 if (cfs_copy_to_user(buffer, tmpstr, len))
519                         rc = -EFAULT;
520                 else
521                         *ppos = LNET_PHASH_POS_MAKE(ver, idx, num);
522         }
523
524         LIBCFS_FREE(tmpstr, tmpsiz);
525
526         if (rc == 0)
527                 *lenp = len;
528
529         return rc;
530 }
531
532 static int __proc_lnet_buffers(void *data, int write,
533                                loff_t pos, void *buffer, int nob)
534 {
535
536         int              rc;
537         int              len;
538         char            *s;
539         char            *tmpstr;
540         const int        tmpsiz = 64 * (LNET_NRBPOOLS + 1); /* (4 %d) * 4 */
541         int              idx;
542
543         LASSERT (!write);
544
545         LIBCFS_ALLOC(tmpstr, tmpsiz);
546         if (tmpstr == NULL)
547                 return -ENOMEM;
548
549         s = tmpstr; /* points to current position in tmpstr[] */
550
551         s += snprintf(s, tmpstr + tmpsiz - s,
552                       "%5s %5s %7s %7s\n",
553                       "pages", "count", "credits", "min");
554         LASSERT (tmpstr + tmpsiz - s > 0);
555
556         LNET_LOCK();
557
558         for (idx = 0; idx < LNET_NRBPOOLS; idx++) {
559                 lnet_rtrbufpool_t *rbp = &the_lnet.ln_rtrpools[idx];
560
561                 int npages = rbp->rbp_npages;
562                 int nbuf   = rbp->rbp_nbuffers;
563                 int cr     = rbp->rbp_credits;
564                 int mincr  = rbp->rbp_mincredits;
565
566                 s += snprintf(s, tmpstr + tmpsiz - s,
567                               "%5d %5d %7d %7d\n",
568                               npages, nbuf, cr, mincr);
569                 LASSERT (tmpstr + tmpsiz - s > 0);
570         }
571
572         LNET_UNLOCK();
573
574         len = s - tmpstr;
575
576         if (pos >= min_t(int, len, strlen(tmpstr)))
577                 rc = 0;
578         else
579                 rc = cfs_trace_copyout_string(buffer, nob,
580                                               tmpstr + pos, NULL);
581
582         LIBCFS_FREE(tmpstr, tmpsiz);
583         return rc;
584 }
585
586 DECLARE_PROC_HANDLER(proc_lnet_buffers);
587
588 int LL_PROC_PROTO(proc_lnet_nis)
589 {
590         int        rc = 0;
591         char      *tmpstr;
592         char      *s;
593         const int  tmpsiz = 256;
594         int        len;
595
596         DECLARE_LL_PROC_PPOS_DECL;
597
598         LASSERT (!write);
599
600         if (*lenp == 0)
601                 return 0;
602
603         LIBCFS_ALLOC(tmpstr, tmpsiz);
604         if (tmpstr == NULL)
605                 return -ENOMEM;
606
607         s = tmpstr; /* points to current position in tmpstr[] */
608
609         if (*ppos == 0) {
610                 s += snprintf(s, tmpstr + tmpsiz - s,
611                               "%-24s %6s %5s %4s %4s %4s %5s %5s %5s\n",
612                               "nid", "status", "alive", "refs", "peer",
613                               "rtr", "max", "tx", "min");
614                 LASSERT (tmpstr + tmpsiz - s > 0);
615         } else {
616                 cfs_list_t        *n;
617                 lnet_ni_t         *ni   = NULL;
618                 int                skip = *ppos - 1;
619
620                 LNET_LOCK();
621
622                 n = the_lnet.ln_nis.next;
623
624                 while (n != &the_lnet.ln_nis) {
625                         lnet_ni_t *a_ni = cfs_list_entry(n, lnet_ni_t, ni_list);
626
627                         if (skip == 0) {
628                                 ni = a_ni;
629                                 break;
630                         }
631
632                         skip--;
633                         n = n->next;
634                 }
635
636                 if (ni != NULL) {
637                         cfs_time_t now = cfs_time_current();
638                         int        last_alive = -1;
639                         int        maxtxcr = ni->ni_maxtxcredits;
640                         int        txcr = ni->ni_txcredits;
641                         int        mintxcr = ni->ni_mintxcredits;
642                         int        npeertxcr = ni->ni_peertxcredits;
643                         int        npeerrtrcr = ni->ni_peerrtrcredits;
644                         lnet_nid_t nid = ni->ni_nid;
645                         int        nref = ni->ni_refcount;
646                         char      *stat;
647
648                         if (the_lnet.ln_routing)
649                                 last_alive = cfs_duration_sec(cfs_time_sub(now,
650                                                             ni->ni_last_alive));
651                         if (ni->ni_lnd->lnd_type == LOLND)  /* @lo forever alive */
652                                 last_alive = 0;
653
654                         LASSERT (ni->ni_status != NULL);
655                         stat = (ni->ni_status->ns_status == LNET_NI_STATUS_UP) ?
656                                                                   "up" : "down";
657
658                         s += snprintf(s, tmpstr + tmpsiz - s,
659                                       "%-24s %6s %5d %4d %4d %4d %5d %5d %5d\n",
660                                       libcfs_nid2str(nid), stat, last_alive, nref,
661                                       npeertxcr, npeerrtrcr, maxtxcr,
662                                       txcr, mintxcr);
663                         LASSERT (tmpstr + tmpsiz - s > 0);
664                 }
665
666                 LNET_UNLOCK();
667         }
668
669         len = s - tmpstr;     /* how many bytes was written */
670
671         if (len > *lenp) {    /* linux-supplied buffer is too small */
672                 rc = -EINVAL;
673         } else if (len > 0) { /* wrote something */
674                 if (cfs_copy_to_user(buffer, tmpstr, len))
675                         rc = -EFAULT;
676                 else
677                         *ppos += 1;
678         }
679
680         LIBCFS_FREE(tmpstr, tmpsiz);
681
682         if (rc == 0)
683                 *lenp = len;
684
685         return rc;
686 }
687
688 static cfs_sysctl_table_t lnet_table[] = {
689         /*
690          * NB No .strategy entries have been provided since sysctl(8) prefers
691          * to go via /proc for portability.
692          */
693         {
694                 .ctl_name = PSDEV_LNET_STATS,
695                 .procname = "stats",
696                 .mode     = 0644,
697                 .proc_handler = &proc_lnet_stats,
698         },
699         {
700                 .ctl_name = PSDEV_LNET_ROUTES,
701                 .procname = "routes",
702                 .mode     = 0444,
703                 .proc_handler = &proc_lnet_routes,
704         },
705         {
706                 .ctl_name = PSDEV_LNET_ROUTERS,
707                 .procname = "routers",
708                 .mode     = 0444,
709                 .proc_handler = &proc_lnet_routers,
710         },
711         {
712                 .ctl_name = PSDEV_LNET_PEERS,
713                 .procname = "peers",
714                 .mode     = 0444,
715                 .proc_handler = &proc_lnet_peers,
716         },
717         {
718                 .ctl_name = PSDEV_LNET_PEERS,
719                 .procname = "buffers",
720                 .mode     = 0444,
721                 .proc_handler = &proc_lnet_buffers,
722         },
723         {
724                 .ctl_name = PSDEV_LNET_NIS,
725                 .procname = "nis",
726                 .mode     = 0444,
727                 .proc_handler = &proc_lnet_nis,
728         },
729         {0}
730 };
731
732 static cfs_sysctl_table_t top_table[] = {
733         {
734                 .ctl_name = CTL_LNET,
735                 .procname = "lnet",
736                 .mode     = 0555,
737                 .data     = NULL,
738                 .maxlen   = 0,
739                 .child    = lnet_table,
740         },
741         {
742                 .ctl_name = 0
743         }
744 };
745
746 void
747 lnet_proc_init(void)
748 {
749 #ifdef CONFIG_SYSCTL
750         if (lnet_table_header == NULL)
751                 lnet_table_header = cfs_register_sysctl_table(top_table, 0);
752 #endif
753 }
754
755 void
756 lnet_proc_fini(void)
757 {
758 #ifdef CONFIG_SYSCTL
759         if (lnet_table_header != NULL)
760                 cfs_unregister_sysctl_table(lnet_table_header);
761
762         lnet_table_header = NULL;
763 #endif
764 }
765
766 #else
767
768 void
769 lnet_proc_init(void)
770 {
771 }
772
773 void
774 lnet_proc_fini(void)
775 {
776 }
777
778 #endif