linux/drivers/staging/lustre/lnet/lnet/router_proc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
   4 *
   5 * Copyright (c) 2011, 2012, Intel Corporation.
   6 *
   7 *   This file is part of Portals
   8 *   http://sourceforge.net/projects/sandiaportals/
   9 *
  10 *   Portals is free software; you can redistribute it and/or
  11 *   modify it under the terms of version 2 of the GNU General Public
  12 *   License as published by the Free Software Foundation.
  13 *
  14 *   Portals is distributed in the hope that it will be useful,
  15 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 *   GNU General Public License for more details.
  18 *
  19 */
  20
  21#define DEBUG_SUBSYSTEM S_LNET
  22
  23#include <linux/libcfs/libcfs.h>
  24#include <linux/lnet/lib-lnet.h>
  25
  26/*
  27 * This is really lnet_proc.c. You might need to update sanity test 215
  28 * if any file format is changed.
  29 */
  30
  31#define LNET_LOFFT_BITS         (sizeof(loff_t) * 8)
  32/*
  33 * NB: max allowed LNET_CPT_BITS is 8 on 64-bit system and 2 on 32-bit system
  34 */
  35#define LNET_PROC_CPT_BITS      (LNET_CPT_BITS + 1)
  36/* change version, 16 bits or 8 bits */
  37#define LNET_PROC_VER_BITS      max_t(size_t, min_t(size_t, LNET_LOFFT_BITS, 64) / 4, 8)
  38
  39#define LNET_PROC_HASH_BITS     LNET_PEER_HASH_BITS
  40/*
  41 * bits for peer hash offset
  42 * NB: we don't use the highest bit of *ppos because it's signed
  43 */
  44#define LNET_PROC_HOFF_BITS     (LNET_LOFFT_BITS -       \
  45                                 LNET_PROC_CPT_BITS -    \
  46                                 LNET_PROC_VER_BITS -    \
  47                                 LNET_PROC_HASH_BITS - 1)
  48/* bits for hash index + position */
  49#define LNET_PROC_HPOS_BITS     (LNET_PROC_HASH_BITS + LNET_PROC_HOFF_BITS)
  50/* bits for peer hash table + hash version */
  51#define LNET_PROC_VPOS_BITS     (LNET_PROC_HPOS_BITS + LNET_PROC_VER_BITS)
  52
  53#define LNET_PROC_CPT_MASK      ((1ULL << LNET_PROC_CPT_BITS) - 1)
  54#define LNET_PROC_VER_MASK      ((1ULL << LNET_PROC_VER_BITS) - 1)
  55#define LNET_PROC_HASH_MASK     ((1ULL << LNET_PROC_HASH_BITS) - 1)
  56#define LNET_PROC_HOFF_MASK     ((1ULL << LNET_PROC_HOFF_BITS) - 1)
  57
  58#define LNET_PROC_CPT_GET(pos)                          \
  59        (int)(((pos) >> LNET_PROC_VPOS_BITS) & LNET_PROC_CPT_MASK)
  60
  61#define LNET_PROC_VER_GET(pos)                          \
  62        (int)(((pos) >> LNET_PROC_HPOS_BITS) & LNET_PROC_VER_MASK)
  63
  64#define LNET_PROC_HASH_GET(pos)                         \
  65        (int)(((pos) >> LNET_PROC_HOFF_BITS) & LNET_PROC_HASH_MASK)
  66
  67#define LNET_PROC_HOFF_GET(pos)                         \
  68        (int)((pos) & LNET_PROC_HOFF_MASK)
  69
  70#define LNET_PROC_POS_MAKE(cpt, ver, hash, off)         \
  71        (((((loff_t)(cpt)) & LNET_PROC_CPT_MASK) << LNET_PROC_VPOS_BITS) |   \
  72        ((((loff_t)(ver)) & LNET_PROC_VER_MASK) << LNET_PROC_HPOS_BITS) |   \
  73        ((((loff_t)(hash)) & LNET_PROC_HASH_MASK) << LNET_PROC_HOFF_BITS) | \
  74        ((off) & LNET_PROC_HOFF_MASK))
  75
  76#define LNET_PROC_VERSION(v)    ((unsigned int)((v) & LNET_PROC_VER_MASK))
  77
  78static int __proc_lnet_stats(void *data, int write,
  79                             loff_t pos, void __user *buffer, int nob)
  80{
  81        int rc;
  82        struct lnet_counters *ctrs;
  83        int len;
  84        char *tmpstr;
  85        const int tmpsiz = 256; /* 7 %u and 4 %llu */
  86
  87        if (write) {
  88                lnet_counters_reset();
  89                return 0;
  90        }
  91
  92        /* read */
  93
  94        ctrs = kzalloc(sizeof(*ctrs), GFP_NOFS);
  95        if (!ctrs)
  96                return -ENOMEM;
  97
  98        tmpstr = kmalloc(tmpsiz, GFP_KERNEL);
  99        if (!tmpstr) {
 100                kfree(ctrs);
 101                return -ENOMEM;
 102        }
 103
 104        lnet_counters_get(ctrs);
 105
 106        len = snprintf(tmpstr, tmpsiz,
 107                       "%u %u %u %u %u %u %u %llu %llu %llu %llu",
 108                       ctrs->msgs_alloc, ctrs->msgs_max,
 109                       ctrs->errors,
 110                       ctrs->send_count, ctrs->recv_count,
 111                       ctrs->route_count, ctrs->drop_count,
 112                       ctrs->send_length, ctrs->recv_length,
 113                       ctrs->route_length, ctrs->drop_length);
 114
 115        if (pos >= min_t(int, len, strlen(tmpstr)))
 116                rc = 0;
 117        else
 118                rc = cfs_trace_copyout_string(buffer, nob,
 119                                              tmpstr + pos, "\n");
 120
 121        kfree(tmpstr);
 122        kfree(ctrs);
 123        return rc;
 124}
 125
 126static int proc_lnet_stats(struct ctl_table *table, int write,
 127                           void __user *buffer, size_t *lenp, loff_t *ppos)
 128{
 129        return lprocfs_call_handler(table->data, write, ppos, buffer, lenp,
 130                                    __proc_lnet_stats);
 131}
 132
 133static int proc_lnet_routes(struct ctl_table *table, int write,
 134                            void __user *buffer, size_t *lenp, loff_t *ppos)
 135{
 136        const int tmpsiz = 256;
 137        char *tmpstr;
 138        char *s;
 139        int rc = 0;
 140        int len;
 141        int ver;
 142        int off;
 143
 144        BUILD_BUG_ON(sizeof(loff_t) < 4);
 145
 146        off = LNET_PROC_HOFF_GET(*ppos);
 147        ver = LNET_PROC_VER_GET(*ppos);
 148
 149        LASSERT(!write);
 150
 151        if (!*lenp)
 152                return 0;
 153
 154        tmpstr = kmalloc(tmpsiz, GFP_KERNEL);
 155        if (!tmpstr)
 156                return -ENOMEM;
 157
 158        s = tmpstr; /* points to current position in tmpstr[] */
 159
 160        if (!*ppos) {
 161                s += snprintf(s, tmpstr + tmpsiz - s, "Routing %s\n",
 162                              the_lnet.ln_routing ? "enabled" : "disabled");
 163                LASSERT(tmpstr + tmpsiz - s > 0);
 164
 165                s += snprintf(s, tmpstr + tmpsiz - s, "%-8s %4s %8s %7s %s\n",
 166                              "net", "hops", "priority", "state", "router");
 167                LASSERT(tmpstr + tmpsiz - s > 0);
 168
 169                lnet_net_lock(0);
 170                ver = (unsigned int)the_lnet.ln_remote_nets_version;
 171                lnet_net_unlock(0);
 172                *ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
 173        } else {
 174                struct list_head *n;
 175                struct list_head *r;
 176                struct lnet_route *route = NULL;
 177                struct lnet_remotenet *rnet  = NULL;
 178                int skip  = off - 1;
 179                struct list_head *rn_list;
 180                int i;
 181
 182                lnet_net_lock(0);
 183
 184                if (ver != LNET_PROC_VERSION(the_lnet.ln_remote_nets_version)) {
 185                        lnet_net_unlock(0);
 186                        kfree(tmpstr);
 187                        return -ESTALE;
 188                }
 189
 190                for (i = 0; i < LNET_REMOTE_NETS_HASH_SIZE && !route; i++) {
 191                        rn_list = &the_lnet.ln_remote_nets_hash[i];
 192
 193                        n = rn_list->next;
 194
 195                        while (n != rn_list && !route) {
 196                                rnet = list_entry(n, struct lnet_remotenet,
 197                                                  lrn_list);
 198
 199                                r = rnet->lrn_routes.next;
 200
 201                                while (r != &rnet->lrn_routes) {
 202                                        struct lnet_route *re;
 203
 204                                        re = list_entry(r, struct lnet_route,
 205                                                        lr_list);
 206                                        if (!skip) {
 207                                                route = re;
 208                                                break;
 209                                        }
 210
 211                                        skip--;
 212                                        r = r->next;
 213                                }
 214
 215                                n = n->next;
 216                        }
 217                }
 218
 219                if (route) {
 220                        __u32 net = rnet->lrn_net;
 221                        __u32 hops = route->lr_hops;
 222                        unsigned int priority = route->lr_priority;
 223                        lnet_nid_t nid = route->lr_gateway->lp_nid;
 224                        int alive = lnet_is_route_alive(route);
 225
 226                        s += snprintf(s, tmpstr + tmpsiz - s,
 227                                      "%-8s %4u %8u %7s %s\n",
 228                                      libcfs_net2str(net), hops,
 229                                      priority,
 230                                      alive ? "up" : "down",
 231                                      libcfs_nid2str(nid));
 232                        LASSERT(tmpstr + tmpsiz - s > 0);
 233                }
 234
 235                lnet_net_unlock(0);
 236        }
 237
 238        len = s - tmpstr;     /* how many bytes was written */
 239
 240        if (len > *lenp) {    /* linux-supplied buffer is too small */
 241                rc = -EINVAL;
 242        } else if (len > 0) { /* wrote something */
 243                if (copy_to_user(buffer, tmpstr, len)) {
 244                        rc = -EFAULT;
 245                } else {
 246                        off += 1;
 247                        *ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
 248                }
 249        }
 250
 251        kfree(tmpstr);
 252
 253        if (!rc)
 254                *lenp = len;
 255
 256        return rc;
 257}
 258
 259static int proc_lnet_routers(struct ctl_table *table, int write,
 260                             void __user *buffer, size_t *lenp, loff_t *ppos)
 261{
 262        int rc = 0;
 263        char *tmpstr;
 264        char *s;
 265        const int tmpsiz = 256;
 266        int len;
 267        int ver;
 268        int off;
 269
 270        off = LNET_PROC_HOFF_GET(*ppos);
 271        ver = LNET_PROC_VER_GET(*ppos);
 272
 273        LASSERT(!write);
 274
 275        if (!*lenp)
 276                return 0;
 277
 278        tmpstr = kmalloc(tmpsiz, GFP_KERNEL);
 279        if (!tmpstr)
 280                return -ENOMEM;
 281
 282        s = tmpstr; /* points to current position in tmpstr[] */
 283
 284        if (!*ppos) {
 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",
 288                              "last_ping", "ping_sent", "deadline",
 289                              "down_ni", "router");
 290                LASSERT(tmpstr + tmpsiz - s > 0);
 291
 292                lnet_net_lock(0);
 293                ver = (unsigned int)the_lnet.ln_routers_version;
 294                lnet_net_unlock(0);
 295                *ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
 296        } else {
 297                struct list_head *r;
 298                struct lnet_peer *peer = NULL;
 299                int skip = off - 1;
 300
 301                lnet_net_lock(0);
 302
 303                if (ver != LNET_PROC_VERSION(the_lnet.ln_routers_version)) {
 304                        lnet_net_unlock(0);
 305
 306                        kfree(tmpstr);
 307                        return -ESTALE;
 308                }
 309
 310                r = the_lnet.ln_routers.next;
 311
 312                while (r != &the_lnet.ln_routers) {
 313                        struct lnet_peer *lp;
 314
 315                        lp = list_entry(r, struct lnet_peer, lp_rtr_list);
 316                        if (!skip) {
 317                                peer = lp;
 318                                break;
 319                        }
 320
 321                        skip--;
 322                        r = r->next;
 323                }
 324
 325                if (peer) {
 326                        lnet_nid_t nid = peer->lp_nid;
 327                        unsigned long now = cfs_time_current();
 328                        unsigned long 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 = 0;
 337                        struct lnet_route *rtr;
 338
 339                        if ((peer->lp_ping_feats &
 340                             LNET_PING_FEAT_NI_STATUS)) {
 341                                list_for_each_entry(rtr, &peer->lp_routes,
 342                                                    lr_gwlist) {
 343                                        /*
 344                                         * downis on any route should be the
 345                                         * number of downis on the gateway
 346                                         */
 347                                        if (rtr->lr_downis) {
 348                                                down_ni = rtr->lr_downis;
 349                                                break;
 350                                        }
 351                                }
 352                        }
 353
 354                        if (!deadline)
 355                                s += snprintf(s, tmpstr + tmpsiz - s,
 356                                              "%-4d %7d %9d %6s %12d %9d %8s %7d %s\n",
 357                                              nrefs, nrtrrefs, alive_cnt,
 358                                              alive ? "up" : "down", last_ping,
 359                                              pingsent, "NA", down_ni,
 360                                              libcfs_nid2str(nid));
 361                        else
 362                                s += snprintf(s, tmpstr + tmpsiz - s,
 363                                              "%-4d %7d %9d %6s %12d %9d %8lu %7d %s\n",
 364                                              nrefs, nrtrrefs, alive_cnt,
 365                                              alive ? "up" : "down", last_ping,
 366                                              pingsent,
 367                                              cfs_duration_sec(cfs_time_sub(deadline, now)),
 368                                              down_ni, libcfs_nid2str(nid));
 369                        LASSERT(tmpstr + tmpsiz - s > 0);
 370                }
 371
 372                lnet_net_unlock(0);
 373        }
 374
 375        len = s - tmpstr;     /* how many bytes was written */
 376
 377        if (len > *lenp) {    /* linux-supplied buffer is too small */
 378                rc = -EINVAL;
 379        } else if (len > 0) { /* wrote something */
 380                if (copy_to_user(buffer, tmpstr, len)) {
 381                        rc = -EFAULT;
 382                } else {
 383                        off += 1;
 384                        *ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
 385                }
 386        }
 387
 388        kfree(tmpstr);
 389
 390        if (!rc)
 391                *lenp = len;
 392
 393        return rc;
 394}
 395
 396static int proc_lnet_peers(struct ctl_table *table, int write,
 397                           void __user *buffer, size_t *lenp, loff_t *ppos)
 398{
 399        const int tmpsiz  = 256;
 400        struct lnet_peer_table *ptable;
 401        char *tmpstr;
 402        char *s;
 403        int cpt  = LNET_PROC_CPT_GET(*ppos);
 404        int ver  = LNET_PROC_VER_GET(*ppos);
 405        int hash = LNET_PROC_HASH_GET(*ppos);
 406        int hoff = LNET_PROC_HOFF_GET(*ppos);
 407        int rc = 0;
 408        int len;
 409
 410        BUILD_BUG_ON(LNET_PROC_HASH_BITS < LNET_PEER_HASH_BITS);
 411        LASSERT(!write);
 412
 413        if (!*lenp)
 414                return 0;
 415
 416        if (cpt >= LNET_CPT_NUMBER) {
 417                *lenp = 0;
 418                return 0;
 419        }
 420
 421        tmpstr = kmalloc(tmpsiz, GFP_KERNEL);
 422        if (!tmpstr)
 423                return -ENOMEM;
 424
 425        s = tmpstr; /* points to current position in tmpstr[] */
 426
 427        if (!*ppos) {
 428                s += snprintf(s, tmpstr + tmpsiz - s,
 429                              "%-24s %4s %5s %5s %5s %5s %5s %5s %5s %s\n",
 430                              "nid", "refs", "state", "last", "max",
 431                              "rtr", "min", "tx", "min", "queue");
 432                LASSERT(tmpstr + tmpsiz - s > 0);
 433
 434                hoff++;
 435        } else {
 436                struct lnet_peer *peer;
 437                struct list_head *p;
 438                int skip;
 439 again:
 440                p = NULL;
 441                peer = NULL;
 442                skip = hoff - 1;
 443
 444                lnet_net_lock(cpt);
 445                ptable = the_lnet.ln_peer_tables[cpt];
 446                if (hoff == 1)
 447                        ver = LNET_PROC_VERSION(ptable->pt_version);
 448
 449                if (ver != LNET_PROC_VERSION(ptable->pt_version)) {
 450                        lnet_net_unlock(cpt);
 451                        kfree(tmpstr);
 452                        return -ESTALE;
 453                }
 454
 455                while (hash < LNET_PEER_HASH_SIZE) {
 456                        if (!p)
 457                                p = ptable->pt_hash[hash].next;
 458
 459                        while (p != &ptable->pt_hash[hash]) {
 460                                struct lnet_peer *lp;
 461
 462                                lp = list_entry(p, struct lnet_peer,
 463                                                lp_hashlist);
 464                                if (!skip) {
 465                                        peer = lp;
 466
 467                                        /*
 468                                         * minor optimization: start from idx+1
 469                                         * on next iteration if we've just
 470                                         * drained lp_hashlist
 471                                         */
 472                                        if (lp->lp_hashlist.next ==
 473                                            &ptable->pt_hash[hash]) {
 474                                                hoff = 1;
 475                                                hash++;
 476                                        } else {
 477                                                hoff++;
 478                                        }
 479
 480                                        break;
 481                                }
 482
 483                                skip--;
 484                                p = lp->lp_hashlist.next;
 485                        }
 486
 487                        if (peer)
 488                                break;
 489
 490                        p = NULL;
 491                        hoff = 1;
 492                        hash++;
 493                }
 494
 495                if (peer) {
 496                        lnet_nid_t nid = peer->lp_nid;
 497                        int nrefs = peer->lp_refcount;
 498                        int lastalive = -1;
 499                        char *aliveness = "NA";
 500                        int maxcr = peer->lp_ni->ni_peertxcredits;
 501                        int txcr = peer->lp_txcredits;
 502                        int mintxcr = peer->lp_mintxcredits;
 503                        int rtrcr = peer->lp_rtrcredits;
 504                        int minrtrcr = peer->lp_minrtrcredits;
 505                        int txqnob = peer->lp_txqnob;
 506
 507                        if (lnet_isrouter(peer) ||
 508                            lnet_peer_aliveness_enabled(peer))
 509                                aliveness = peer->lp_alive ? "up" : "down";
 510
 511                        if (lnet_peer_aliveness_enabled(peer)) {
 512                                unsigned long now = cfs_time_current();
 513                                long delta;
 514
 515                                delta = cfs_time_sub(now, peer->lp_last_alive);
 516                                lastalive = cfs_duration_sec(delta);
 517
 518                                /* No need to mess up peers contents with
 519                                 * arbitrarily long integers - it suffices to
 520                                 * know that lastalive is more than 10000s old
 521                                 */
 522                                if (lastalive >= 10000)
 523                                        lastalive = 9999;
 524                        }
 525
 526                        lnet_net_unlock(cpt);
 527
 528                        s += snprintf(s, tmpstr + tmpsiz - s,
 529                                      "%-24s %4d %5s %5d %5d %5d %5d %5d %5d %d\n",
 530                                      libcfs_nid2str(nid), nrefs, aliveness,
 531                                      lastalive, maxcr, rtrcr, minrtrcr, txcr,
 532                                      mintxcr, txqnob);
 533                        LASSERT(tmpstr + tmpsiz - s > 0);
 534
 535                } else { /* peer is NULL */
 536                        lnet_net_unlock(cpt);
 537                }
 538
 539                if (hash == LNET_PEER_HASH_SIZE) {
 540                        cpt++;
 541                        hash = 0;
 542                        hoff = 1;
 543                        if (!peer && cpt < LNET_CPT_NUMBER)
 544                                goto again;
 545                }
 546        }
 547
 548        len = s - tmpstr;     /* how many bytes was written */
 549
 550        if (len > *lenp) {    /* linux-supplied buffer is too small */
 551                rc = -EINVAL;
 552        } else if (len > 0) { /* wrote something */
 553                if (copy_to_user(buffer, tmpstr, len))
 554                        rc = -EFAULT;
 555                else
 556                        *ppos = LNET_PROC_POS_MAKE(cpt, ver, hash, hoff);
 557        }
 558
 559        kfree(tmpstr);
 560
 561        if (!rc)
 562                *lenp = len;
 563
 564        return rc;
 565}
 566
 567static int __proc_lnet_buffers(void *data, int write,
 568                               loff_t pos, void __user *buffer, int nob)
 569{
 570        char *s;
 571        char *tmpstr;
 572        int tmpsiz;
 573        int idx;
 574        int len;
 575        int rc;
 576        int i;
 577
 578        LASSERT(!write);
 579
 580        /* (4 %d) * 4 * LNET_CPT_NUMBER */
 581        tmpsiz = 64 * (LNET_NRBPOOLS + 1) * LNET_CPT_NUMBER;
 582        tmpstr = kvmalloc(tmpsiz, GFP_KERNEL);
 583        if (!tmpstr)
 584                return -ENOMEM;
 585
 586        s = tmpstr; /* points to current position in tmpstr[] */
 587
 588        s += snprintf(s, tmpstr + tmpsiz - s,
 589                      "%5s %5s %7s %7s\n",
 590                      "pages", "count", "credits", "min");
 591        LASSERT(tmpstr + tmpsiz - s > 0);
 592
 593        if (!the_lnet.ln_rtrpools)
 594                goto out; /* I'm not a router */
 595
 596        for (idx = 0; idx < LNET_NRBPOOLS; idx++) {
 597                struct lnet_rtrbufpool *rbp;
 598
 599                lnet_net_lock(LNET_LOCK_EX);
 600                cfs_percpt_for_each(rbp, i, the_lnet.ln_rtrpools) {
 601                        s += snprintf(s, tmpstr + tmpsiz - s,
 602                                      "%5d %5d %7d %7d\n",
 603                                      rbp[idx].rbp_npages,
 604                                      rbp[idx].rbp_nbuffers,
 605                                      rbp[idx].rbp_credits,
 606                                      rbp[idx].rbp_mincredits);
 607                        LASSERT(tmpstr + tmpsiz - s > 0);
 608                }
 609                lnet_net_unlock(LNET_LOCK_EX);
 610        }
 611
 612 out:
 613        len = s - tmpstr;
 614
 615        if (pos >= min_t(int, len, strlen(tmpstr)))
 616                rc = 0;
 617        else
 618                rc = cfs_trace_copyout_string(buffer, nob,
 619                                              tmpstr + pos, NULL);
 620
 621        kvfree(tmpstr);
 622        return rc;
 623}
 624
 625static int proc_lnet_buffers(struct ctl_table *table, int write,
 626                             void __user *buffer, size_t *lenp, loff_t *ppos)
 627{
 628        return lprocfs_call_handler(table->data, write, ppos, buffer, lenp,
 629                                    __proc_lnet_buffers);
 630}
 631
 632static int proc_lnet_nis(struct ctl_table *table, int write,
 633                         void __user *buffer, size_t *lenp, loff_t *ppos)
 634{
 635        int tmpsiz = 128 * LNET_CPT_NUMBER;
 636        int rc = 0;
 637        char *tmpstr;
 638        char *s;
 639        int len;
 640
 641        LASSERT(!write);
 642
 643        if (!*lenp)
 644                return 0;
 645
 646        tmpstr = kvmalloc(tmpsiz, GFP_KERNEL);
 647        if (!tmpstr)
 648                return -ENOMEM;
 649
 650        s = tmpstr; /* points to current position in tmpstr[] */
 651
 652        if (!*ppos) {
 653                s += snprintf(s, tmpstr + tmpsiz - s,
 654                              "%-24s %6s %5s %4s %4s %4s %5s %5s %5s\n",
 655                              "nid", "status", "alive", "refs", "peer",
 656                              "rtr", "max", "tx", "min");
 657                LASSERT(tmpstr + tmpsiz - s > 0);
 658        } else {
 659                struct list_head *n;
 660                struct lnet_ni *ni = NULL;
 661                int skip = *ppos - 1;
 662
 663                lnet_net_lock(0);
 664
 665                n = the_lnet.ln_nis.next;
 666
 667                while (n != &the_lnet.ln_nis) {
 668                        struct lnet_ni *a_ni;
 669
 670                        a_ni = list_entry(n, struct lnet_ni, ni_list);
 671                        if (!skip) {
 672                                ni = a_ni;
 673                                break;
 674                        }
 675
 676                        skip--;
 677                        n = n->next;
 678                }
 679
 680                if (ni) {
 681                        struct lnet_tx_queue *tq;
 682                        char *stat;
 683                        time64_t now = ktime_get_real_seconds();
 684                        int last_alive = -1;
 685                        int i;
 686                        int j;
 687
 688                        if (the_lnet.ln_routing)
 689                                last_alive = now - ni->ni_last_alive;
 690
 691                        /* @lo forever alive */
 692                        if (ni->ni_lnd->lnd_type == LOLND)
 693                                last_alive = 0;
 694
 695                        lnet_ni_lock(ni);
 696                        LASSERT(ni->ni_status);
 697                        stat = (ni->ni_status->ns_status ==
 698                                LNET_NI_STATUS_UP) ? "up" : "down";
 699                        lnet_ni_unlock(ni);
 700
 701                        /*
 702                         * we actually output credits information for
 703                         * TX queue of each partition
 704                         */
 705                        cfs_percpt_for_each(tq, i, ni->ni_tx_queues) {
 706                                for (j = 0; ni->ni_cpts &&
 707                                     j < ni->ni_ncpts; j++) {
 708                                        if (i == ni->ni_cpts[j])
 709                                                break;
 710                                }
 711
 712                                if (j == ni->ni_ncpts)
 713                                        continue;
 714
 715                                if (i)
 716                                        lnet_net_lock(i);
 717
 718                                s += snprintf(s, tmpstr + tmpsiz - s,
 719                                              "%-24s %6s %5d %4d %4d %4d %5d %5d %5d\n",
 720                                              libcfs_nid2str(ni->ni_nid), stat,
 721                                              last_alive, *ni->ni_refs[i],
 722                                              ni->ni_peertxcredits,
 723                                              ni->ni_peerrtrcredits,
 724                                              tq->tq_credits_max,
 725                                              tq->tq_credits,
 726                                              tq->tq_credits_min);
 727                                if (i)
 728                                        lnet_net_unlock(i);
 729                        }
 730                        LASSERT(tmpstr + tmpsiz - s > 0);
 731                }
 732
 733                lnet_net_unlock(0);
 734        }
 735
 736        len = s - tmpstr;     /* how many bytes was written */
 737
 738        if (len > *lenp) {    /* linux-supplied buffer is too small */
 739                rc = -EINVAL;
 740        } else if (len > 0) { /* wrote something */
 741                if (copy_to_user(buffer, tmpstr, len))
 742                        rc = -EFAULT;
 743                else
 744                        *ppos += 1;
 745        }
 746
 747        kvfree(tmpstr);
 748
 749        if (!rc)
 750                *lenp = len;
 751
 752        return rc;
 753}
 754
 755struct lnet_portal_rotors {
 756        int pr_value;
 757        const char *pr_name;
 758        const char *pr_desc;
 759};
 760
 761static struct lnet_portal_rotors        portal_rotors[] = {
 762        {
 763                .pr_value = LNET_PTL_ROTOR_OFF,
 764                .pr_name  = "OFF",
 765                .pr_desc  = "Turn off message rotor for wildcard portals"
 766        },
 767        {
 768                .pr_value = LNET_PTL_ROTOR_ON,
 769                .pr_name  = "ON",
 770                .pr_desc  = "round-robin dispatch all PUT messages for wildcard portals"
 771        },
 772        {
 773                .pr_value = LNET_PTL_ROTOR_RR_RT,
 774                .pr_name  = "RR_RT",
 775                .pr_desc  = "round-robin dispatch routed PUT message for wildcard portals"
 776        },
 777        {
 778                .pr_value = LNET_PTL_ROTOR_HASH_RT,
 779                .pr_name  = "HASH_RT",
 780                .pr_desc  = "dispatch routed PUT message by hashing source NID for wildcard portals"
 781        },
 782        {
 783                .pr_value = -1,
 784                .pr_name  = NULL,
 785                .pr_desc  = NULL
 786        },
 787};
 788
 789static int __proc_lnet_portal_rotor(void *data, int write,
 790                                    loff_t pos, void __user *buffer, int nob)
 791{
 792        const int buf_len = 128;
 793        char *buf;
 794        char *tmp;
 795        int rc;
 796        int i;
 797
 798        buf = kmalloc(buf_len, GFP_KERNEL);
 799        if (!buf)
 800                return -ENOMEM;
 801
 802        if (!write) {
 803                lnet_res_lock(0);
 804
 805                for (i = 0; portal_rotors[i].pr_value >= 0; i++) {
 806                        if (portal_rotors[i].pr_value == portal_rotor)
 807                                break;
 808                }
 809
 810                LASSERT(portal_rotors[i].pr_value == portal_rotor);
 811                lnet_res_unlock(0);
 812
 813                rc = snprintf(buf, buf_len,
 814                              "{\n\tportals: all\n"
 815                              "\trotor: %s\n\tdescription: %s\n}",
 816                              portal_rotors[i].pr_name,
 817                              portal_rotors[i].pr_desc);
 818
 819                if (pos >= min_t(int, rc, buf_len)) {
 820                        rc = 0;
 821                } else {
 822                        rc = cfs_trace_copyout_string(buffer, nob,
 823                                                      buf + pos, "\n");
 824                }
 825                goto out;
 826        }
 827
 828        rc = cfs_trace_copyin_string(buf, buf_len, buffer, nob);
 829        if (rc < 0)
 830                goto out;
 831
 832        tmp = strim(buf);
 833
 834        rc = -EINVAL;
 835        lnet_res_lock(0);
 836        for (i = 0; portal_rotors[i].pr_name; i++) {
 837                if (!strncasecmp(portal_rotors[i].pr_name, tmp,
 838                                 strlen(portal_rotors[i].pr_name))) {
 839                        portal_rotor = portal_rotors[i].pr_value;
 840                        rc = 0;
 841                        break;
 842                }
 843        }
 844        lnet_res_unlock(0);
 845out:
 846        kfree(buf);
 847        return rc;
 848}
 849
 850static int proc_lnet_portal_rotor(struct ctl_table *table, int write,
 851                                  void __user *buffer, size_t *lenp,
 852                                  loff_t *ppos)
 853{
 854        return lprocfs_call_handler(table->data, write, ppos, buffer, lenp,
 855                                    __proc_lnet_portal_rotor);
 856}
 857
 858static struct ctl_table lnet_table[] = {
 859        /*
 860         * NB No .strategy entries have been provided since sysctl(8) prefers
 861         * to go via /proc for portability.
 862         */
 863        {
 864                .procname     = "stats",
 865                .mode         = 0644,
 866                .proc_handler = &proc_lnet_stats,
 867        },
 868        {
 869                .procname     = "routes",
 870                .mode         = 0444,
 871                .proc_handler = &proc_lnet_routes,
 872        },
 873        {
 874                .procname     = "routers",
 875                .mode         = 0444,
 876                .proc_handler = &proc_lnet_routers,
 877        },
 878        {
 879                .procname     = "peers",
 880                .mode         = 0444,
 881                .proc_handler = &proc_lnet_peers,
 882        },
 883        {
 884                .procname     = "buffers",
 885                .mode         = 0444,
 886                .proc_handler = &proc_lnet_buffers,
 887        },
 888        {
 889                .procname     = "nis",
 890                .mode         = 0444,
 891                .proc_handler = &proc_lnet_nis,
 892        },
 893        {
 894                .procname     = "portal_rotor",
 895                .mode         = 0644,
 896                .proc_handler = &proc_lnet_portal_rotor,
 897        },
 898        {
 899        }
 900};
 901
 902void lnet_router_debugfs_init(void)
 903{
 904        lustre_insert_debugfs(lnet_table, NULL);
 905}
 906
 907void lnet_router_debugfs_fini(void)
 908{
 909}
 910