linux/drivers/staging/lustre/lnet/selftest/console.c
<<
>>
Prefs
   1/*
   2 * GPL HEADER START
   3 *
   4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 only,
   8 * as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful, but
  11 * WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13 * General Public License version 2 for more details (a copy is included
  14 * in the LICENSE file that accompanied this code).
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * version 2 along with this program; If not, see
  18 * http://www.gnu.org/licenses/gpl-2.0.html
  19 *
  20 * GPL HEADER END
  21 */
  22/*
  23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  24 * Use is subject to license terms.
  25 *
  26 * Copyright (c) 2012, Intel Corporation.
  27 */
  28/*
  29 * This file is part of Lustre, http://www.lustre.org/
  30 * Lustre is a trademark of Sun Microsystems, Inc.
  31 *
  32 * lnet/selftest/conctl.c
  33 *
  34 * Infrastructure of LST console
  35 *
  36 * Author: Liang Zhen <liangzhen@clusterfs.com>
  37 */
  38
  39#include <linux/libcfs/libcfs.h>
  40#include <linux/lnet/lib-lnet.h>
  41#include "console.h"
  42#include "conrpc.h"
  43
  44#define LST_NODE_STATE_COUNTER(nd, p)                   \
  45do {                                                    \
  46        if ((nd)->nd_state == LST_NODE_ACTIVE)          \
  47                (p)->nle_nactive++;                     \
  48        else if ((nd)->nd_state == LST_NODE_BUSY)       \
  49                (p)->nle_nbusy++;                       \
  50        else if ((nd)->nd_state == LST_NODE_DOWN)       \
  51                (p)->nle_ndown++;                       \
  52        else                                            \
  53                (p)->nle_nunknown++;                    \
  54        (p)->nle_nnode++;                               \
  55} while (0)
  56
  57struct lstcon_session console_session;
  58
  59static void
  60lstcon_node_get(struct lstcon_node *nd)
  61{
  62        LASSERT(nd->nd_ref >= 1);
  63
  64        nd->nd_ref++;
  65}
  66
  67static int
  68lstcon_node_find(struct lnet_process_id id, struct lstcon_node **ndpp,
  69                 int create)
  70{
  71        struct lstcon_ndlink    *ndl;
  72        unsigned int idx = LNET_NIDADDR(id.nid) % LST_GLOBAL_HASHSIZE;
  73
  74        LASSERT(id.nid != LNET_NID_ANY);
  75
  76        list_for_each_entry(ndl, &console_session.ses_ndl_hash[idx],
  77                            ndl_hlink) {
  78                if (ndl->ndl_node->nd_id.nid != id.nid ||
  79                    ndl->ndl_node->nd_id.pid != id.pid)
  80                        continue;
  81
  82                lstcon_node_get(ndl->ndl_node);
  83                *ndpp = ndl->ndl_node;
  84                return 0;
  85        }
  86
  87        if (!create)
  88                return -ENOENT;
  89
  90        LIBCFS_ALLOC(*ndpp, sizeof(**ndpp) + sizeof(*ndl));
  91        if (!*ndpp)
  92                return -ENOMEM;
  93
  94        ndl = (struct lstcon_ndlink *)(*ndpp + 1);
  95
  96        ndl->ndl_node = *ndpp;
  97
  98        ndl->ndl_node->nd_ref = 1;
  99        ndl->ndl_node->nd_id = id;
 100        ndl->ndl_node->nd_stamp = cfs_time_current();
 101        ndl->ndl_node->nd_state = LST_NODE_UNKNOWN;
 102        ndl->ndl_node->nd_timeout = 0;
 103        memset(&ndl->ndl_node->nd_ping, 0, sizeof(struct lstcon_rpc));
 104
 105        /*
 106         * queued in global hash & list, no refcount is taken by
 107         * global hash & list, if caller release his refcount,
 108         * node will be released
 109         */
 110        list_add_tail(&ndl->ndl_hlink, &console_session.ses_ndl_hash[idx]);
 111        list_add_tail(&ndl->ndl_link, &console_session.ses_ndl_list);
 112
 113        return 0;
 114}
 115
 116static void
 117lstcon_node_put(struct lstcon_node *nd)
 118{
 119        struct lstcon_ndlink *ndl;
 120
 121        LASSERT(nd->nd_ref > 0);
 122
 123        if (--nd->nd_ref > 0)
 124                return;
 125
 126        ndl = (struct lstcon_ndlink *)(nd + 1);
 127
 128        LASSERT(!list_empty(&ndl->ndl_link));
 129        LASSERT(!list_empty(&ndl->ndl_hlink));
 130
 131        /* remove from session */
 132        list_del(&ndl->ndl_link);
 133        list_del(&ndl->ndl_hlink);
 134
 135        LIBCFS_FREE(nd, sizeof(*nd) + sizeof(*ndl));
 136}
 137
 138static int
 139lstcon_ndlink_find(struct list_head *hash, struct lnet_process_id id,
 140                   struct lstcon_ndlink **ndlpp, int create)
 141{
 142        unsigned int idx = LNET_NIDADDR(id.nid) % LST_NODE_HASHSIZE;
 143        struct lstcon_ndlink *ndl;
 144        struct lstcon_node *nd;
 145        int rc;
 146
 147        if (id.nid == LNET_NID_ANY)
 148                return -EINVAL;
 149
 150        /* search in hash */
 151        list_for_each_entry(ndl, &hash[idx], ndl_hlink) {
 152                if (ndl->ndl_node->nd_id.nid != id.nid ||
 153                    ndl->ndl_node->nd_id.pid != id.pid)
 154                        continue;
 155
 156                *ndlpp = ndl;
 157                return 0;
 158        }
 159
 160        if (!create)
 161                return -ENOENT;
 162
 163        /* find or create in session hash */
 164        rc = lstcon_node_find(id, &nd, (create == 1) ? 1 : 0);
 165        if (rc)
 166                return rc;
 167
 168        LIBCFS_ALLOC(ndl, sizeof(struct lstcon_ndlink));
 169        if (!ndl) {
 170                lstcon_node_put(nd);
 171                return -ENOMEM;
 172        }
 173
 174        *ndlpp = ndl;
 175
 176        ndl->ndl_node = nd;
 177        INIT_LIST_HEAD(&ndl->ndl_link);
 178        list_add_tail(&ndl->ndl_hlink, &hash[idx]);
 179
 180        return 0;
 181}
 182
 183static void
 184lstcon_ndlink_release(struct lstcon_ndlink *ndl)
 185{
 186        LASSERT(list_empty(&ndl->ndl_link));
 187        LASSERT(!list_empty(&ndl->ndl_hlink));
 188
 189        list_del(&ndl->ndl_hlink); /* delete from hash */
 190        lstcon_node_put(ndl->ndl_node);
 191
 192        LIBCFS_FREE(ndl, sizeof(*ndl));
 193}
 194
 195static int
 196lstcon_group_alloc(char *name, struct lstcon_group **grpp)
 197{
 198        struct lstcon_group *grp;
 199        int i;
 200
 201        LIBCFS_ALLOC(grp, offsetof(struct lstcon_group,
 202                                   grp_ndl_hash[LST_NODE_HASHSIZE]));
 203        if (!grp)
 204                return -ENOMEM;
 205
 206        grp->grp_ref = 1;
 207        if (name) {
 208                if (strlen(name) > sizeof(grp->grp_name) - 1) {
 209                        LIBCFS_FREE(grp, offsetof(struct lstcon_group,
 210                                    grp_ndl_hash[LST_NODE_HASHSIZE]));
 211                        return -E2BIG;
 212                }
 213                strncpy(grp->grp_name, name, sizeof(grp->grp_name));
 214        }
 215
 216        INIT_LIST_HEAD(&grp->grp_link);
 217        INIT_LIST_HEAD(&grp->grp_ndl_list);
 218        INIT_LIST_HEAD(&grp->grp_trans_list);
 219
 220        for (i = 0; i < LST_NODE_HASHSIZE; i++)
 221                INIT_LIST_HEAD(&grp->grp_ndl_hash[i]);
 222
 223        *grpp = grp;
 224
 225        return 0;
 226}
 227
 228static void
 229lstcon_group_addref(struct lstcon_group *grp)
 230{
 231        grp->grp_ref++;
 232}
 233
 234static void lstcon_group_ndlink_release(struct lstcon_group *,
 235                                        struct lstcon_ndlink *);
 236
 237static void
 238lstcon_group_drain(struct lstcon_group *grp, int keep)
 239{
 240        struct lstcon_ndlink *ndl;
 241        struct lstcon_ndlink *tmp;
 242
 243        list_for_each_entry_safe(ndl, tmp, &grp->grp_ndl_list, ndl_link) {
 244                if (!(ndl->ndl_node->nd_state & keep))
 245                        lstcon_group_ndlink_release(grp, ndl);
 246        }
 247}
 248
 249static void
 250lstcon_group_decref(struct lstcon_group *grp)
 251{
 252        int i;
 253
 254        if (--grp->grp_ref > 0)
 255                return;
 256
 257        if (!list_empty(&grp->grp_link))
 258                list_del(&grp->grp_link);
 259
 260        lstcon_group_drain(grp, 0);
 261
 262        for (i = 0; i < LST_NODE_HASHSIZE; i++)
 263                LASSERT(list_empty(&grp->grp_ndl_hash[i]));
 264
 265        LIBCFS_FREE(grp, offsetof(struct lstcon_group,
 266                                  grp_ndl_hash[LST_NODE_HASHSIZE]));
 267}
 268
 269static int
 270lstcon_group_find(const char *name, struct lstcon_group **grpp)
 271{
 272        struct lstcon_group *grp;
 273
 274        list_for_each_entry(grp, &console_session.ses_grp_list, grp_link) {
 275                if (strncmp(grp->grp_name, name, LST_NAME_SIZE))
 276                        continue;
 277
 278                lstcon_group_addref(grp); /* +1 ref for caller */
 279                *grpp = grp;
 280                return 0;
 281        }
 282
 283        return -ENOENT;
 284}
 285
 286static int
 287lstcon_group_ndlink_find(struct lstcon_group *grp, struct lnet_process_id id,
 288                         struct lstcon_ndlink **ndlpp, int create)
 289{
 290        int rc;
 291
 292        rc = lstcon_ndlink_find(&grp->grp_ndl_hash[0], id, ndlpp, create);
 293        if (rc)
 294                return rc;
 295
 296        if (!list_empty(&(*ndlpp)->ndl_link))
 297                return 0;
 298
 299        list_add_tail(&(*ndlpp)->ndl_link, &grp->grp_ndl_list);
 300        grp->grp_nnode++;
 301
 302        return 0;
 303}
 304
 305static void
 306lstcon_group_ndlink_release(struct lstcon_group *grp, struct lstcon_ndlink *ndl)
 307{
 308        list_del_init(&ndl->ndl_link);
 309        lstcon_ndlink_release(ndl);
 310        grp->grp_nnode--;
 311}
 312
 313static void
 314lstcon_group_ndlink_move(struct lstcon_group *old,
 315                         struct lstcon_group *new, struct lstcon_ndlink *ndl)
 316{
 317        unsigned int idx = LNET_NIDADDR(ndl->ndl_node->nd_id.nid) %
 318                                        LST_NODE_HASHSIZE;
 319
 320        list_del(&ndl->ndl_hlink);
 321        list_del(&ndl->ndl_link);
 322        old->grp_nnode--;
 323
 324        list_add_tail(&ndl->ndl_hlink, &new->grp_ndl_hash[idx]);
 325        list_add_tail(&ndl->ndl_link, &new->grp_ndl_list);
 326        new->grp_nnode++;
 327}
 328
 329static void
 330lstcon_group_move(struct lstcon_group *old, struct lstcon_group *new)
 331{
 332        struct lstcon_ndlink *ndl;
 333
 334        while (!list_empty(&old->grp_ndl_list)) {
 335                ndl = list_entry(old->grp_ndl_list.next,
 336                                 struct lstcon_ndlink, ndl_link);
 337                lstcon_group_ndlink_move(old, new, ndl);
 338        }
 339}
 340
 341static int
 342lstcon_sesrpc_condition(int transop, struct lstcon_node *nd, void *arg)
 343{
 344        struct lstcon_group *grp = (struct lstcon_group *)arg;
 345
 346        switch (transop) {
 347        case LST_TRANS_SESNEW:
 348                if (nd->nd_state == LST_NODE_ACTIVE)
 349                        return 0;
 350                break;
 351
 352        case LST_TRANS_SESEND:
 353                if (nd->nd_state != LST_NODE_ACTIVE)
 354                        return 0;
 355
 356                if (grp && nd->nd_ref > 1)
 357                        return 0;
 358                break;
 359
 360        case LST_TRANS_SESQRY:
 361                break;
 362
 363        default:
 364                LBUG();
 365        }
 366
 367        return 1;
 368}
 369
 370static int
 371lstcon_sesrpc_readent(int transop, struct srpc_msg *msg,
 372                      struct lstcon_rpc_ent __user *ent_up)
 373{
 374        struct srpc_debug_reply *rep;
 375
 376        switch (transop) {
 377        case LST_TRANS_SESNEW:
 378        case LST_TRANS_SESEND:
 379                return 0;
 380
 381        case LST_TRANS_SESQRY:
 382                rep = &msg->msg_body.dbg_reply;
 383
 384                if (copy_to_user(&ent_up->rpe_priv[0],
 385                                 &rep->dbg_timeout, sizeof(int)) ||
 386                    copy_to_user(&ent_up->rpe_payload[0],
 387                                 &rep->dbg_name, LST_NAME_SIZE))
 388                        return -EFAULT;
 389
 390                return 0;
 391
 392        default:
 393                LBUG();
 394        }
 395
 396        return 0;
 397}
 398
 399static int
 400lstcon_group_nodes_add(struct lstcon_group *grp,
 401                       int count, struct lnet_process_id __user *ids_up,
 402                       unsigned int *featp,
 403                       struct list_head __user *result_up)
 404{
 405        struct lstcon_rpc_trans *trans;
 406        struct lstcon_ndlink    *ndl;
 407        struct lstcon_group *tmp;
 408        struct lnet_process_id id;
 409        int i;
 410        int rc;
 411
 412        rc = lstcon_group_alloc(NULL, &tmp);
 413        if (rc) {
 414                CERROR("Out of memory\n");
 415                return -ENOMEM;
 416        }
 417
 418        for (i = 0 ; i < count; i++) {
 419                if (copy_from_user(&id, &ids_up[i], sizeof(id))) {
 420                        rc = -EFAULT;
 421                        break;
 422                }
 423
 424                /* skip if it's in this group already */
 425                rc = lstcon_group_ndlink_find(grp, id, &ndl, 0);
 426                if (!rc)
 427                        continue;
 428
 429                /* add to tmp group */
 430                rc = lstcon_group_ndlink_find(tmp, id, &ndl, 1);
 431                if (rc) {
 432                        CERROR("Can't create ndlink, out of memory\n");
 433                        break;
 434                }
 435        }
 436
 437        if (rc) {
 438                lstcon_group_decref(tmp);
 439                return rc;
 440        }
 441
 442        rc = lstcon_rpc_trans_ndlist(&tmp->grp_ndl_list,
 443                                     &tmp->grp_trans_list, LST_TRANS_SESNEW,
 444                                     tmp, lstcon_sesrpc_condition, &trans);
 445        if (rc) {
 446                CERROR("Can't create transaction: %d\n", rc);
 447                lstcon_group_decref(tmp);
 448                return rc;
 449        }
 450
 451        /* post all RPCs */
 452        lstcon_rpc_trans_postwait(trans, LST_TRANS_TIMEOUT);
 453
 454        rc = lstcon_rpc_trans_interpreter(trans, result_up,
 455                                          lstcon_sesrpc_readent);
 456        *featp = trans->tas_features;
 457
 458        /* destroy all RPGs */
 459        lstcon_rpc_trans_destroy(trans);
 460
 461        lstcon_group_move(tmp, grp);
 462        lstcon_group_decref(tmp);
 463
 464        return rc;
 465}
 466
 467static int
 468lstcon_group_nodes_remove(struct lstcon_group *grp,
 469                          int count, struct lnet_process_id __user *ids_up,
 470                          struct list_head __user *result_up)
 471{
 472        struct lstcon_rpc_trans *trans;
 473        struct lstcon_ndlink *ndl;
 474        struct lstcon_group *tmp;
 475        struct lnet_process_id id;
 476        int rc;
 477        int i;
 478
 479        /* End session and remove node from the group */
 480
 481        rc = lstcon_group_alloc(NULL, &tmp);
 482        if (rc) {
 483                CERROR("Out of memory\n");
 484                return -ENOMEM;
 485        }
 486
 487        for (i = 0; i < count; i++) {
 488                if (copy_from_user(&id, &ids_up[i], sizeof(id))) {
 489                        rc = -EFAULT;
 490                        goto error;
 491                }
 492
 493                /* move node to tmp group */
 494                if (!lstcon_group_ndlink_find(grp, id, &ndl, 0))
 495                        lstcon_group_ndlink_move(grp, tmp, ndl);
 496        }
 497
 498        rc = lstcon_rpc_trans_ndlist(&tmp->grp_ndl_list,
 499                                     &tmp->grp_trans_list, LST_TRANS_SESEND,
 500                                     tmp, lstcon_sesrpc_condition, &trans);
 501        if (rc) {
 502                CERROR("Can't create transaction: %d\n", rc);
 503                goto error;
 504        }
 505
 506        lstcon_rpc_trans_postwait(trans, LST_TRANS_TIMEOUT);
 507
 508        rc = lstcon_rpc_trans_interpreter(trans, result_up, NULL);
 509
 510        lstcon_rpc_trans_destroy(trans);
 511        /* release nodes anyway, because we can't rollback status */
 512        lstcon_group_decref(tmp);
 513
 514        return rc;
 515error:
 516        lstcon_group_move(tmp, grp);
 517        lstcon_group_decref(tmp);
 518
 519        return rc;
 520}
 521
 522int
 523lstcon_group_add(char *name)
 524{
 525        struct lstcon_group *grp;
 526        int rc;
 527
 528        rc = lstcon_group_find(name, &grp) ? 0 : -EEXIST;
 529        if (rc) {
 530                /* find a group with same name */
 531                lstcon_group_decref(grp);
 532                return rc;
 533        }
 534
 535        rc = lstcon_group_alloc(name, &grp);
 536        if (rc) {
 537                CERROR("Can't allocate descriptor for group %s\n", name);
 538                return -ENOMEM;
 539        }
 540
 541        list_add_tail(&grp->grp_link, &console_session.ses_grp_list);
 542
 543        return rc;
 544}
 545
 546int
 547lstcon_nodes_add(char *name, int count, struct lnet_process_id __user *ids_up,
 548                 unsigned int *featp, struct list_head __user *result_up)
 549{
 550        struct lstcon_group *grp;
 551        int rc;
 552
 553        LASSERT(count > 0);
 554        LASSERT(ids_up);
 555
 556        rc = lstcon_group_find(name, &grp);
 557        if (rc) {
 558                CDEBUG(D_NET, "Can't find group %s\n", name);
 559                return rc;
 560        }
 561
 562        if (grp->grp_ref > 2) {
 563                /* referred by other threads or test */
 564                CDEBUG(D_NET, "Group %s is busy\n", name);
 565                lstcon_group_decref(grp);
 566
 567                return -EBUSY;
 568        }
 569
 570        rc = lstcon_group_nodes_add(grp, count, ids_up, featp, result_up);
 571
 572        lstcon_group_decref(grp);
 573
 574        return rc;
 575}
 576
 577int
 578lstcon_group_del(char *name)
 579{
 580        struct lstcon_rpc_trans *trans;
 581        struct lstcon_group *grp;
 582        int rc;
 583
 584        rc = lstcon_group_find(name, &grp);
 585        if (rc) {
 586                CDEBUG(D_NET, "Can't find group: %s\n", name);
 587                return rc;
 588        }
 589
 590        if (grp->grp_ref > 2) {
 591                /* referred by others threads or test */
 592                CDEBUG(D_NET, "Group %s is busy\n", name);
 593                lstcon_group_decref(grp);
 594                return -EBUSY;
 595        }
 596
 597        rc = lstcon_rpc_trans_ndlist(&grp->grp_ndl_list,
 598                                     &grp->grp_trans_list, LST_TRANS_SESEND,
 599                                     grp, lstcon_sesrpc_condition, &trans);
 600        if (rc) {
 601                CERROR("Can't create transaction: %d\n", rc);
 602                lstcon_group_decref(grp);
 603                return rc;
 604        }
 605
 606        lstcon_rpc_trans_postwait(trans, LST_TRANS_TIMEOUT);
 607
 608        lstcon_rpc_trans_destroy(trans);
 609
 610        lstcon_group_decref(grp);
 611        /*
 612         * -ref for session, it's destroyed,
 613         * status can't be rolled back, destroy group anyway
 614         */
 615        lstcon_group_decref(grp);
 616
 617        return rc;
 618}
 619
 620int
 621lstcon_group_clean(char *name, int args)
 622{
 623        struct lstcon_group *grp = NULL;
 624        int rc;
 625
 626        rc = lstcon_group_find(name, &grp);
 627        if (rc) {
 628                CDEBUG(D_NET, "Can't find group %s\n", name);
 629                return rc;
 630        }
 631
 632        if (grp->grp_ref > 2) {
 633                /* referred by test */
 634                CDEBUG(D_NET, "Group %s is busy\n", name);
 635                lstcon_group_decref(grp);
 636                return -EBUSY;
 637        }
 638
 639        args = (LST_NODE_ACTIVE | LST_NODE_BUSY |
 640                LST_NODE_DOWN | LST_NODE_UNKNOWN) & ~args;
 641
 642        lstcon_group_drain(grp, args);
 643
 644        lstcon_group_decref(grp);
 645        /* release empty group */
 646        if (list_empty(&grp->grp_ndl_list))
 647                lstcon_group_decref(grp);
 648
 649        return 0;
 650}
 651
 652int
 653lstcon_nodes_remove(char *name, int count,
 654                    struct lnet_process_id __user *ids_up,
 655                    struct list_head __user *result_up)
 656{
 657        struct lstcon_group *grp = NULL;
 658        int rc;
 659
 660        rc = lstcon_group_find(name, &grp);
 661        if (rc) {
 662                CDEBUG(D_NET, "Can't find group: %s\n", name);
 663                return rc;
 664        }
 665
 666        if (grp->grp_ref > 2) {
 667                /* referred by test */
 668                CDEBUG(D_NET, "Group %s is busy\n", name);
 669                lstcon_group_decref(grp);
 670                return -EBUSY;
 671        }
 672
 673        rc = lstcon_group_nodes_remove(grp, count, ids_up, result_up);
 674
 675        lstcon_group_decref(grp);
 676        /* release empty group */
 677        if (list_empty(&grp->grp_ndl_list))
 678                lstcon_group_decref(grp);
 679
 680        return rc;
 681}
 682
 683int
 684lstcon_group_refresh(char *name, struct list_head __user *result_up)
 685{
 686        struct lstcon_rpc_trans *trans;
 687        struct lstcon_group *grp;
 688        int rc;
 689
 690        rc = lstcon_group_find(name, &grp);
 691        if (rc) {
 692                CDEBUG(D_NET, "Can't find group: %s\n", name);
 693                return rc;
 694        }
 695
 696        if (grp->grp_ref > 2) {
 697                /* referred by test */
 698                CDEBUG(D_NET, "Group %s is busy\n", name);
 699                lstcon_group_decref(grp);
 700                return -EBUSY;
 701        }
 702
 703        /* re-invite all inactive nodes int the group */
 704        rc = lstcon_rpc_trans_ndlist(&grp->grp_ndl_list,
 705                                     &grp->grp_trans_list, LST_TRANS_SESNEW,
 706                                     grp, lstcon_sesrpc_condition, &trans);
 707        if (rc) {
 708                /* local error, return */
 709                CDEBUG(D_NET, "Can't create transaction: %d\n", rc);
 710                lstcon_group_decref(grp);
 711                return rc;
 712        }
 713
 714        lstcon_rpc_trans_postwait(trans, LST_TRANS_TIMEOUT);
 715
 716        rc = lstcon_rpc_trans_interpreter(trans, result_up, NULL);
 717
 718        lstcon_rpc_trans_destroy(trans);
 719        /* -ref for me */
 720        lstcon_group_decref(grp);
 721
 722        return rc;
 723}
 724
 725int
 726lstcon_group_list(int index, int len, char __user *name_up)
 727{
 728        struct lstcon_group *grp;
 729
 730        LASSERT(index >= 0);
 731        LASSERT(name_up);
 732
 733        list_for_each_entry(grp, &console_session.ses_grp_list, grp_link) {
 734                if (!index--) {
 735                        return copy_to_user(name_up, grp->grp_name, len) ?
 736                                            -EFAULT : 0;
 737                }
 738        }
 739
 740        return -ENOENT;
 741}
 742
 743static int
 744lstcon_nodes_getent(struct list_head *head, int *index_p,
 745                    int *count_p, struct lstcon_node_ent __user *dents_up)
 746{
 747        struct lstcon_ndlink *ndl;
 748        struct lstcon_node *nd;
 749        int count = 0;
 750        int index = 0;
 751
 752        LASSERT(index_p && count_p);
 753        LASSERT(dents_up);
 754        LASSERT(*index_p >= 0);
 755        LASSERT(*count_p > 0);
 756
 757        list_for_each_entry(ndl, head, ndl_link) {
 758                if (index++ < *index_p)
 759                        continue;
 760
 761                if (count >= *count_p)
 762                        break;
 763
 764                nd = ndl->ndl_node;
 765                if (copy_to_user(&dents_up[count].nde_id,
 766                                 &nd->nd_id, sizeof(nd->nd_id)) ||
 767                    copy_to_user(&dents_up[count].nde_state,
 768                                 &nd->nd_state, sizeof(nd->nd_state)))
 769                        return -EFAULT;
 770
 771                count++;
 772        }
 773
 774        if (index <= *index_p)
 775                return -ENOENT;
 776
 777        *count_p = count;
 778        *index_p = index;
 779
 780        return 0;
 781}
 782
 783int
 784lstcon_group_info(char *name, struct lstcon_ndlist_ent __user *gents_p,
 785                  int *index_p, int *count_p,
 786                  struct lstcon_node_ent __user *dents_up)
 787{
 788        struct lstcon_ndlist_ent *gentp;
 789        struct lstcon_group *grp;
 790        struct lstcon_ndlink *ndl;
 791        int rc;
 792
 793        rc = lstcon_group_find(name, &grp);
 794        if (rc) {
 795                CDEBUG(D_NET, "Can't find group %s\n", name);
 796                return rc;
 797        }
 798
 799        if (dents_up) {
 800                /* verbose query */
 801                rc = lstcon_nodes_getent(&grp->grp_ndl_list,
 802                                         index_p, count_p, dents_up);
 803                lstcon_group_decref(grp);
 804
 805                return rc;
 806        }
 807
 808        /* non-verbose query */
 809        LIBCFS_ALLOC(gentp, sizeof(struct lstcon_ndlist_ent));
 810        if (!gentp) {
 811                CERROR("Can't allocate ndlist_ent\n");
 812                lstcon_group_decref(grp);
 813
 814                return -ENOMEM;
 815        }
 816
 817        list_for_each_entry(ndl, &grp->grp_ndl_list, ndl_link)
 818                LST_NODE_STATE_COUNTER(ndl->ndl_node, gentp);
 819
 820        rc = copy_to_user(gents_p, gentp,
 821                          sizeof(struct lstcon_ndlist_ent)) ? -EFAULT : 0;
 822
 823        LIBCFS_FREE(gentp, sizeof(struct lstcon_ndlist_ent));
 824
 825        lstcon_group_decref(grp);
 826
 827        return rc;
 828}
 829
 830static int
 831lstcon_batch_find(const char *name, struct lstcon_batch **batpp)
 832{
 833        struct lstcon_batch *bat;
 834
 835        list_for_each_entry(bat, &console_session.ses_bat_list, bat_link) {
 836                if (!strncmp(bat->bat_name, name, LST_NAME_SIZE)) {
 837                        *batpp = bat;
 838                        return 0;
 839                }
 840        }
 841
 842        return -ENOENT;
 843}
 844
 845int
 846lstcon_batch_add(char *name)
 847{
 848        struct lstcon_batch *bat;
 849        int i;
 850        int rc;
 851
 852        rc = !lstcon_batch_find(name, &bat) ? -EEXIST : 0;
 853        if (rc) {
 854                CDEBUG(D_NET, "Batch %s already exists\n", name);
 855                return rc;
 856        }
 857
 858        LIBCFS_ALLOC(bat, sizeof(struct lstcon_batch));
 859        if (!bat) {
 860                CERROR("Can't allocate descriptor for batch %s\n", name);
 861                return -ENOMEM;
 862        }
 863
 864        LIBCFS_ALLOC(bat->bat_cli_hash,
 865                     sizeof(struct list_head) * LST_NODE_HASHSIZE);
 866        if (!bat->bat_cli_hash) {
 867                CERROR("Can't allocate hash for batch %s\n", name);
 868                LIBCFS_FREE(bat, sizeof(struct lstcon_batch));
 869
 870                return -ENOMEM;
 871        }
 872
 873        LIBCFS_ALLOC(bat->bat_srv_hash,
 874                     sizeof(struct list_head) * LST_NODE_HASHSIZE);
 875        if (!bat->bat_srv_hash) {
 876                CERROR("Can't allocate hash for batch %s\n", name);
 877                LIBCFS_FREE(bat->bat_cli_hash, LST_NODE_HASHSIZE);
 878                LIBCFS_FREE(bat, sizeof(struct lstcon_batch));
 879
 880                return -ENOMEM;
 881        }
 882
 883        if (strlen(name) > sizeof(bat->bat_name) - 1) {
 884                LIBCFS_FREE(bat->bat_srv_hash, LST_NODE_HASHSIZE);
 885                LIBCFS_FREE(bat->bat_cli_hash, LST_NODE_HASHSIZE);
 886                LIBCFS_FREE(bat, sizeof(struct lstcon_batch));
 887                return -E2BIG;
 888        }
 889        strncpy(bat->bat_name, name, sizeof(bat->bat_name));
 890        bat->bat_hdr.tsb_index = 0;
 891        bat->bat_hdr.tsb_id.bat_id = ++console_session.ses_id_cookie;
 892
 893        bat->bat_ntest = 0;
 894        bat->bat_state = LST_BATCH_IDLE;
 895
 896        INIT_LIST_HEAD(&bat->bat_cli_list);
 897        INIT_LIST_HEAD(&bat->bat_srv_list);
 898        INIT_LIST_HEAD(&bat->bat_test_list);
 899        INIT_LIST_HEAD(&bat->bat_trans_list);
 900
 901        for (i = 0; i < LST_NODE_HASHSIZE; i++) {
 902                INIT_LIST_HEAD(&bat->bat_cli_hash[i]);
 903                INIT_LIST_HEAD(&bat->bat_srv_hash[i]);
 904        }
 905
 906        list_add_tail(&bat->bat_link, &console_session.ses_bat_list);
 907
 908        return rc;
 909}
 910
 911int
 912lstcon_batch_list(int index, int len, char __user *name_up)
 913{
 914        struct lstcon_batch *bat;
 915
 916        LASSERT(name_up);
 917        LASSERT(index >= 0);
 918
 919        list_for_each_entry(bat, &console_session.ses_bat_list, bat_link) {
 920                if (!index--) {
 921                        return copy_to_user(name_up, bat->bat_name, len) ?
 922                                            -EFAULT : 0;
 923                }
 924        }
 925
 926        return -ENOENT;
 927}
 928
 929int
 930lstcon_batch_info(char *name, struct lstcon_test_batch_ent __user *ent_up,
 931                  int server, int testidx, int *index_p, int *ndent_p,
 932                  struct lstcon_node_ent __user *dents_up)
 933{
 934        struct lstcon_test_batch_ent *entp;
 935        struct list_head *clilst;
 936        struct list_head *srvlst;
 937        struct lstcon_test *test = NULL;
 938        struct lstcon_batch *bat;
 939        struct lstcon_ndlink    *ndl;
 940        int rc;
 941
 942        rc = lstcon_batch_find(name, &bat);
 943        if (rc) {
 944                CDEBUG(D_NET, "Can't find batch %s\n", name);
 945                return -ENOENT;
 946        }
 947
 948        if (testidx > 0) {
 949                /* query test, test index start from 1 */
 950                list_for_each_entry(test, &bat->bat_test_list, tes_link) {
 951                        if (testidx-- == 1)
 952                                break;
 953                }
 954
 955                if (testidx > 0) {
 956                        CDEBUG(D_NET, "Can't find specified test in batch\n");
 957                        return -ENOENT;
 958                }
 959        }
 960
 961        clilst = !test ? &bat->bat_cli_list :
 962                         &test->tes_src_grp->grp_ndl_list;
 963        srvlst = !test ? &bat->bat_srv_list :
 964                         &test->tes_dst_grp->grp_ndl_list;
 965
 966        if (dents_up) {
 967                rc = lstcon_nodes_getent((server ? srvlst : clilst),
 968                                         index_p, ndent_p, dents_up);
 969                return rc;
 970        }
 971
 972        /* non-verbose query */
 973        LIBCFS_ALLOC(entp, sizeof(struct lstcon_test_batch_ent));
 974        if (!entp)
 975                return -ENOMEM;
 976
 977        if (!test) {
 978                entp->u.tbe_batch.bae_ntest = bat->bat_ntest;
 979                entp->u.tbe_batch.bae_state = bat->bat_state;
 980        } else {
 981                entp->u.tbe_test.tse_type = test->tes_type;
 982                entp->u.tbe_test.tse_loop = test->tes_loop;
 983                entp->u.tbe_test.tse_concur = test->tes_concur;
 984        }
 985
 986        list_for_each_entry(ndl, clilst, ndl_link)
 987                LST_NODE_STATE_COUNTER(ndl->ndl_node, &entp->tbe_cli_nle);
 988
 989        list_for_each_entry(ndl, srvlst, ndl_link)
 990                LST_NODE_STATE_COUNTER(ndl->ndl_node, &entp->tbe_srv_nle);
 991
 992        rc = copy_to_user(ent_up, entp,
 993                          sizeof(struct lstcon_test_batch_ent)) ? -EFAULT : 0;
 994
 995        LIBCFS_FREE(entp, sizeof(struct lstcon_test_batch_ent));
 996
 997        return rc;
 998}
 999
1000static int
1001lstcon_batrpc_condition(int transop, struct lstcon_node *nd, void *arg)
1002{
1003        switch (transop) {
1004        case LST_TRANS_TSBRUN:
1005                if (nd->nd_state != LST_NODE_ACTIVE)
1006                        return -ENETDOWN;
1007                break;
1008
1009        case LST_TRANS_TSBSTOP:
1010                if (nd->nd_state != LST_NODE_ACTIVE)
1011                        return 0;
1012                break;
1013
1014        case LST_TRANS_TSBCLIQRY:
1015        case LST_TRANS_TSBSRVQRY:
1016                break;
1017        }
1018
1019        return 1;
1020}
1021
1022static int
1023lstcon_batch_op(struct lstcon_batch *bat, int transop,
1024                struct list_head __user *result_up)
1025{
1026        struct lstcon_rpc_trans *trans;
1027        int rc;
1028
1029        rc = lstcon_rpc_trans_ndlist(&bat->bat_cli_list,
1030                                     &bat->bat_trans_list, transop,
1031                                     bat, lstcon_batrpc_condition, &trans);
1032        if (rc) {
1033                CERROR("Can't create transaction: %d\n", rc);
1034                return rc;
1035        }
1036
1037        lstcon_rpc_trans_postwait(trans, LST_TRANS_TIMEOUT);
1038
1039        rc = lstcon_rpc_trans_interpreter(trans, result_up, NULL);
1040
1041        lstcon_rpc_trans_destroy(trans);
1042
1043        return rc;
1044}
1045
1046int
1047lstcon_batch_run(char *name, int timeout, struct list_head __user *result_up)
1048{
1049        struct lstcon_batch *bat;
1050        int rc;
1051
1052        if (lstcon_batch_find(name, &bat)) {
1053                CDEBUG(D_NET, "Can't find batch %s\n", name);
1054                return -ENOENT;
1055        }
1056
1057        bat->bat_arg = timeout;
1058
1059        rc = lstcon_batch_op(bat, LST_TRANS_TSBRUN, result_up);
1060
1061        /* mark batch as running if it's started in any node */
1062        if (lstcon_tsbop_stat_success(lstcon_trans_stat(), 0))
1063                bat->bat_state = LST_BATCH_RUNNING;
1064
1065        return rc;
1066}
1067
1068int
1069lstcon_batch_stop(char *name, int force, struct list_head __user *result_up)
1070{
1071        struct lstcon_batch *bat;
1072        int rc;
1073
1074        if (lstcon_batch_find(name, &bat)) {
1075                CDEBUG(D_NET, "Can't find batch %s\n", name);
1076                return -ENOENT;
1077        }
1078
1079        bat->bat_arg = force;
1080
1081        rc = lstcon_batch_op(bat, LST_TRANS_TSBSTOP, result_up);
1082
1083        /* mark batch as stopped if all RPCs finished */
1084        if (!lstcon_tsbop_stat_failure(lstcon_trans_stat(), 0))
1085                bat->bat_state = LST_BATCH_IDLE;
1086
1087        return rc;
1088}
1089
1090static void
1091lstcon_batch_destroy(struct lstcon_batch *bat)
1092{
1093        struct lstcon_ndlink *ndl;
1094        struct lstcon_test *test;
1095        int i;
1096
1097        list_del(&bat->bat_link);
1098
1099        while (!list_empty(&bat->bat_test_list)) {
1100                test = list_entry(bat->bat_test_list.next,
1101                                  struct lstcon_test, tes_link);
1102                LASSERT(list_empty(&test->tes_trans_list));
1103
1104                list_del(&test->tes_link);
1105
1106                lstcon_group_decref(test->tes_src_grp);
1107                lstcon_group_decref(test->tes_dst_grp);
1108
1109                LIBCFS_FREE(test, offsetof(struct lstcon_test,
1110                                           tes_param[test->tes_paramlen]));
1111        }
1112
1113        LASSERT(list_empty(&bat->bat_trans_list));
1114
1115        while (!list_empty(&bat->bat_cli_list)) {
1116                ndl = list_entry(bat->bat_cli_list.next,
1117                                 struct lstcon_ndlink, ndl_link);
1118                list_del_init(&ndl->ndl_link);
1119
1120                lstcon_ndlink_release(ndl);
1121        }
1122
1123        while (!list_empty(&bat->bat_srv_list)) {
1124                ndl = list_entry(bat->bat_srv_list.next,
1125                                 struct lstcon_ndlink, ndl_link);
1126                list_del_init(&ndl->ndl_link);
1127
1128                lstcon_ndlink_release(ndl);
1129        }
1130
1131        for (i = 0; i < LST_NODE_HASHSIZE; i++) {
1132                LASSERT(list_empty(&bat->bat_cli_hash[i]));
1133                LASSERT(list_empty(&bat->bat_srv_hash[i]));
1134        }
1135
1136        LIBCFS_FREE(bat->bat_cli_hash,
1137                    sizeof(struct list_head) * LST_NODE_HASHSIZE);
1138        LIBCFS_FREE(bat->bat_srv_hash,
1139                    sizeof(struct list_head) * LST_NODE_HASHSIZE);
1140        LIBCFS_FREE(bat, sizeof(struct lstcon_batch));
1141}
1142
1143static int
1144lstcon_testrpc_condition(int transop, struct lstcon_node *nd, void *arg)
1145{
1146        struct lstcon_test *test;
1147        struct lstcon_batch *batch;
1148        struct lstcon_ndlink *ndl;
1149        struct list_head *hash;
1150        struct list_head *head;
1151
1152        test = (struct lstcon_test *)arg;
1153        LASSERT(test);
1154
1155        batch = test->tes_batch;
1156        LASSERT(batch);
1157
1158        if (test->tes_oneside &&
1159            transop == LST_TRANS_TSBSRVADD)
1160                return 0;
1161
1162        if (nd->nd_state != LST_NODE_ACTIVE)
1163                return -ENETDOWN;
1164
1165        if (transop == LST_TRANS_TSBCLIADD) {
1166                hash = batch->bat_cli_hash;
1167                head = &batch->bat_cli_list;
1168
1169        } else {
1170                LASSERT(transop == LST_TRANS_TSBSRVADD);
1171
1172                hash = batch->bat_srv_hash;
1173                head = &batch->bat_srv_list;
1174        }
1175
1176        LASSERT(nd->nd_id.nid != LNET_NID_ANY);
1177
1178        if (lstcon_ndlink_find(hash, nd->nd_id, &ndl, 1))
1179                return -ENOMEM;
1180
1181        if (list_empty(&ndl->ndl_link))
1182                list_add_tail(&ndl->ndl_link, head);
1183
1184        return 1;
1185}
1186
1187static int
1188lstcon_test_nodes_add(struct lstcon_test *test,
1189                      struct list_head __user *result_up)
1190{
1191        struct lstcon_rpc_trans *trans;
1192        struct lstcon_group *grp;
1193        int transop;
1194        int rc;
1195
1196        LASSERT(test->tes_src_grp);
1197        LASSERT(test->tes_dst_grp);
1198
1199        transop = LST_TRANS_TSBSRVADD;
1200        grp = test->tes_dst_grp;
1201again:
1202        rc = lstcon_rpc_trans_ndlist(&grp->grp_ndl_list,
1203                                     &test->tes_trans_list, transop,
1204                                     test, lstcon_testrpc_condition, &trans);
1205        if (rc) {
1206                CERROR("Can't create transaction: %d\n", rc);
1207                return rc;
1208        }
1209
1210        lstcon_rpc_trans_postwait(trans, LST_TRANS_TIMEOUT);
1211
1212        if (lstcon_trans_stat()->trs_rpc_errno ||
1213            lstcon_trans_stat()->trs_fwk_errno) {
1214                lstcon_rpc_trans_interpreter(trans, result_up, NULL);
1215
1216                lstcon_rpc_trans_destroy(trans);
1217                /* return if any error */
1218                CDEBUG(D_NET, "Failed to add test %s, RPC error %d, framework error %d\n",
1219                       transop == LST_TRANS_TSBCLIADD ? "client" : "server",
1220                       lstcon_trans_stat()->trs_rpc_errno,
1221                       lstcon_trans_stat()->trs_fwk_errno);
1222
1223                return rc;
1224        }
1225
1226        lstcon_rpc_trans_destroy(trans);
1227
1228        if (transop == LST_TRANS_TSBCLIADD)
1229                return rc;
1230
1231        transop = LST_TRANS_TSBCLIADD;
1232        grp = test->tes_src_grp;
1233        test->tes_cliidx = 0;
1234
1235        /* requests to test clients */
1236        goto again;
1237}
1238
1239static int
1240lstcon_verify_batch(const char *name, struct lstcon_batch **batch)
1241{
1242        int rc;
1243
1244        rc = lstcon_batch_find(name, batch);
1245        if (rc) {
1246                CDEBUG(D_NET, "Can't find batch %s\n", name);
1247                return rc;
1248        }
1249
1250        if ((*batch)->bat_state != LST_BATCH_IDLE) {
1251                CDEBUG(D_NET, "Can't change running batch %s\n", name);
1252                return -EINVAL;
1253        }
1254
1255        return 0;
1256}
1257
1258static int
1259lstcon_verify_group(const char *name, struct lstcon_group **grp)
1260{
1261        int rc;
1262        struct lstcon_ndlink    *ndl;
1263
1264        rc = lstcon_group_find(name, grp);
1265        if (rc) {
1266                CDEBUG(D_NET, "can't find group %s\n", name);
1267                return rc;
1268        }
1269
1270        list_for_each_entry(ndl, &(*grp)->grp_ndl_list, ndl_link) {
1271                if (ndl->ndl_node->nd_state == LST_NODE_ACTIVE)
1272                        return 0;
1273        }
1274
1275        CDEBUG(D_NET, "Group %s has no ACTIVE nodes\n", name);
1276
1277        return -EINVAL;
1278}
1279
1280int
1281lstcon_test_add(char *batch_name, int type, int loop,
1282                int concur, int dist, int span,
1283                char *src_name, char *dst_name,
1284                void *param, int paramlen, int *retp,
1285                struct list_head __user *result_up)
1286{
1287        struct lstcon_test *test = NULL;
1288        int rc;
1289        struct lstcon_group *src_grp = NULL;
1290        struct lstcon_group *dst_grp = NULL;
1291        struct lstcon_batch *batch = NULL;
1292
1293        /*
1294         * verify that a batch of the given name exists, and the groups
1295         * that will be part of the batch exist and have at least one
1296         * active node
1297         */
1298        rc = lstcon_verify_batch(batch_name, &batch);
1299        if (rc)
1300                goto out;
1301
1302        rc = lstcon_verify_group(src_name, &src_grp);
1303        if (rc)
1304                goto out;
1305
1306        rc = lstcon_verify_group(dst_name, &dst_grp);
1307        if (rc)
1308                goto out;
1309
1310        if (dst_grp->grp_userland)
1311                *retp = 1;
1312
1313        LIBCFS_ALLOC(test, offsetof(struct lstcon_test, tes_param[paramlen]));
1314        if (!test) {
1315                CERROR("Can't allocate test descriptor\n");
1316                rc = -ENOMEM;
1317
1318                goto out;
1319        }
1320
1321        test->tes_hdr.tsb_id = batch->bat_hdr.tsb_id;
1322        test->tes_batch = batch;
1323        test->tes_type = type;
1324        test->tes_oneside = 0; /* TODO */
1325        test->tes_loop = loop;
1326        test->tes_concur = concur;
1327        test->tes_stop_onerr = 1; /* TODO */
1328        test->tes_span = span;
1329        test->tes_dist = dist;
1330        test->tes_cliidx = 0; /* just used for creating RPC */
1331        test->tes_src_grp = src_grp;
1332        test->tes_dst_grp = dst_grp;
1333        INIT_LIST_HEAD(&test->tes_trans_list);
1334
1335        if (param) {
1336                test->tes_paramlen = paramlen;
1337                memcpy(&test->tes_param[0], param, paramlen);
1338        }
1339
1340        rc = lstcon_test_nodes_add(test, result_up);
1341
1342        if (rc)
1343                goto out;
1344
1345        if (lstcon_trans_stat()->trs_rpc_errno ||
1346            lstcon_trans_stat()->trs_fwk_errno)
1347                CDEBUG(D_NET, "Failed to add test %d to batch %s\n", type,
1348                       batch_name);
1349
1350        /* add to test list anyway, so user can check what's going on */
1351        list_add_tail(&test->tes_link, &batch->bat_test_list);
1352
1353        batch->bat_ntest++;
1354        test->tes_hdr.tsb_index = batch->bat_ntest;
1355
1356        /*  hold groups so nobody can change them */
1357        return rc;
1358out:
1359        if (test)
1360                LIBCFS_FREE(test, offsetof(struct lstcon_test, tes_param[paramlen]));
1361
1362        if (dst_grp)
1363                lstcon_group_decref(dst_grp);
1364
1365        if (src_grp)
1366                lstcon_group_decref(src_grp);
1367
1368        return rc;
1369}
1370
1371static int
1372lstcon_test_find(struct lstcon_batch *batch, int idx,
1373                 struct lstcon_test **testpp)
1374{
1375        struct lstcon_test *test;
1376
1377        list_for_each_entry(test, &batch->bat_test_list, tes_link) {
1378                if (idx == test->tes_hdr.tsb_index) {
1379                        *testpp = test;
1380                        return 0;
1381                }
1382        }
1383
1384        return -ENOENT;
1385}
1386
1387static int
1388lstcon_tsbrpc_readent(int transop, struct srpc_msg *msg,
1389                      struct lstcon_rpc_ent __user *ent_up)
1390{
1391        struct srpc_batch_reply *rep = &msg->msg_body.bat_reply;
1392
1393        LASSERT(transop == LST_TRANS_TSBCLIQRY ||
1394                transop == LST_TRANS_TSBSRVQRY);
1395
1396        /* positive errno, framework error code */
1397        if (copy_to_user(&ent_up->rpe_priv[0], &rep->bar_active,
1398                         sizeof(rep->bar_active)))
1399                return -EFAULT;
1400
1401        return 0;
1402}
1403
1404int
1405lstcon_test_batch_query(char *name, int testidx, int client,
1406                        int timeout, struct list_head __user *result_up)
1407{
1408        struct lstcon_rpc_trans *trans;
1409        struct list_head *translist;
1410        struct list_head *ndlist;
1411        struct lstcon_tsb_hdr *hdr;
1412        struct lstcon_batch *batch;
1413        struct lstcon_test *test = NULL;
1414        int transop;
1415        int rc;
1416
1417        rc = lstcon_batch_find(name, &batch);
1418        if (rc) {
1419                CDEBUG(D_NET, "Can't find batch: %s\n", name);
1420                return rc;
1421        }
1422
1423        if (!testidx) {
1424                translist = &batch->bat_trans_list;
1425                ndlist = &batch->bat_cli_list;
1426                hdr = &batch->bat_hdr;
1427        } else {
1428                /* query specified test only */
1429                rc = lstcon_test_find(batch, testidx, &test);
1430                if (rc) {
1431                        CDEBUG(D_NET, "Can't find test: %d\n", testidx);
1432                        return rc;
1433                }
1434
1435                translist = &test->tes_trans_list;
1436                ndlist = &test->tes_src_grp->grp_ndl_list;
1437                hdr = &test->tes_hdr;
1438        }
1439
1440        transop = client ? LST_TRANS_TSBCLIQRY : LST_TRANS_TSBSRVQRY;
1441
1442        rc = lstcon_rpc_trans_ndlist(ndlist, translist, transop, hdr,
1443                                     lstcon_batrpc_condition, &trans);
1444        if (rc) {
1445                CERROR("Can't create transaction: %d\n", rc);
1446                return rc;
1447        }
1448
1449        lstcon_rpc_trans_postwait(trans, timeout);
1450
1451        /* query a batch, not a test */
1452        if (!testidx &&
1453            !lstcon_rpc_stat_failure(lstcon_trans_stat(), 0) &&
1454            !lstcon_tsbqry_stat_run(lstcon_trans_stat(), 0)) {
1455                /* all RPCs finished, and no active test */
1456                batch->bat_state = LST_BATCH_IDLE;
1457        }
1458
1459        rc = lstcon_rpc_trans_interpreter(trans, result_up,
1460                                          lstcon_tsbrpc_readent);
1461        lstcon_rpc_trans_destroy(trans);
1462
1463        return rc;
1464}
1465
1466static int
1467lstcon_statrpc_readent(int transop, struct srpc_msg *msg,
1468                       struct lstcon_rpc_ent __user *ent_up)
1469{
1470        struct srpc_stat_reply *rep = &msg->msg_body.stat_reply;
1471        struct sfw_counters __user *sfwk_stat;
1472        struct srpc_counters __user *srpc_stat;
1473        struct lnet_counters __user *lnet_stat;
1474
1475        if (rep->str_status)
1476                return 0;
1477
1478        sfwk_stat = (struct sfw_counters __user *)&ent_up->rpe_payload[0];
1479        srpc_stat = (struct srpc_counters __user *)(sfwk_stat + 1);
1480        lnet_stat = (struct lnet_counters __user *)(srpc_stat + 1);
1481
1482        if (copy_to_user(sfwk_stat, &rep->str_fw, sizeof(*sfwk_stat)) ||
1483            copy_to_user(srpc_stat, &rep->str_rpc, sizeof(*srpc_stat)) ||
1484            copy_to_user(lnet_stat, &rep->str_lnet, sizeof(*lnet_stat)))
1485                return -EFAULT;
1486
1487        return 0;
1488}
1489
1490static int
1491lstcon_ndlist_stat(struct list_head *ndlist,
1492                   int timeout, struct list_head __user *result_up)
1493{
1494        struct list_head head;
1495        struct lstcon_rpc_trans *trans;
1496        int rc;
1497
1498        INIT_LIST_HEAD(&head);
1499
1500        rc = lstcon_rpc_trans_ndlist(ndlist, &head,
1501                                     LST_TRANS_STATQRY, NULL, NULL, &trans);
1502        if (rc) {
1503                CERROR("Can't create transaction: %d\n", rc);
1504                return rc;
1505        }
1506
1507        lstcon_rpc_trans_postwait(trans, LST_VALIDATE_TIMEOUT(timeout));
1508
1509        rc = lstcon_rpc_trans_interpreter(trans, result_up,
1510                                          lstcon_statrpc_readent);
1511        lstcon_rpc_trans_destroy(trans);
1512
1513        return rc;
1514}
1515
1516int
1517lstcon_group_stat(char *grp_name, int timeout,
1518                  struct list_head __user *result_up)
1519{
1520        struct lstcon_group *grp;
1521        int rc;
1522
1523        rc = lstcon_group_find(grp_name, &grp);
1524        if (rc) {
1525                CDEBUG(D_NET, "Can't find group %s\n", grp_name);
1526                return rc;
1527        }
1528
1529        rc = lstcon_ndlist_stat(&grp->grp_ndl_list, timeout, result_up);
1530
1531        lstcon_group_decref(grp);
1532
1533        return rc;
1534}
1535
1536int
1537lstcon_nodes_stat(int count, struct lnet_process_id __user *ids_up,
1538                  int timeout, struct list_head __user *result_up)
1539{
1540        struct lstcon_ndlink    *ndl;
1541        struct lstcon_group *tmp;
1542        struct lnet_process_id id;
1543        int i;
1544        int rc;
1545
1546        rc = lstcon_group_alloc(NULL, &tmp);
1547        if (rc) {
1548                CERROR("Out of memory\n");
1549                return -ENOMEM;
1550        }
1551
1552        for (i = 0 ; i < count; i++) {
1553                if (copy_from_user(&id, &ids_up[i], sizeof(id))) {
1554                        rc = -EFAULT;
1555                        break;
1556                }
1557
1558                /* add to tmp group */
1559                rc = lstcon_group_ndlink_find(tmp, id, &ndl, 2);
1560                if (rc) {
1561                        CDEBUG((rc == -ENOMEM) ? D_ERROR : D_NET,
1562                               "Failed to find or create %s: %d\n",
1563                               libcfs_id2str(id), rc);
1564                        break;
1565                }
1566        }
1567
1568        if (rc) {
1569                lstcon_group_decref(tmp);
1570                return rc;
1571        }
1572
1573        rc = lstcon_ndlist_stat(&tmp->grp_ndl_list, timeout, result_up);
1574
1575        lstcon_group_decref(tmp);
1576
1577        return rc;
1578}
1579
1580static int
1581lstcon_debug_ndlist(struct list_head *ndlist,
1582                    struct list_head *translist,
1583                    int timeout, struct list_head __user *result_up)
1584{
1585        struct lstcon_rpc_trans *trans;
1586        int rc;
1587
1588        rc = lstcon_rpc_trans_ndlist(ndlist, translist, LST_TRANS_SESQRY,
1589                                     NULL, lstcon_sesrpc_condition, &trans);
1590        if (rc) {
1591                CERROR("Can't create transaction: %d\n", rc);
1592                return rc;
1593        }
1594
1595        lstcon_rpc_trans_postwait(trans, LST_VALIDATE_TIMEOUT(timeout));
1596
1597        rc = lstcon_rpc_trans_interpreter(trans, result_up,
1598                                          lstcon_sesrpc_readent);
1599        lstcon_rpc_trans_destroy(trans);
1600
1601        return rc;
1602}
1603
1604int
1605lstcon_session_debug(int timeout, struct list_head __user *result_up)
1606{
1607        return lstcon_debug_ndlist(&console_session.ses_ndl_list,
1608                                   NULL, timeout, result_up);
1609}
1610
1611int
1612lstcon_batch_debug(int timeout, char *name,
1613                   int client, struct list_head __user *result_up)
1614{
1615        struct lstcon_batch *bat;
1616        int rc;
1617
1618        rc = lstcon_batch_find(name, &bat);
1619        if (rc)
1620                return -ENOENT;
1621
1622        rc = lstcon_debug_ndlist(client ? &bat->bat_cli_list :
1623                                          &bat->bat_srv_list,
1624                                 NULL, timeout, result_up);
1625
1626        return rc;
1627}
1628
1629int
1630lstcon_group_debug(int timeout, char *name,
1631                   struct list_head __user *result_up)
1632{
1633        struct lstcon_group *grp;
1634        int rc;
1635
1636        rc = lstcon_group_find(name, &grp);
1637        if (rc)
1638                return -ENOENT;
1639
1640        rc = lstcon_debug_ndlist(&grp->grp_ndl_list, NULL,
1641                                 timeout, result_up);
1642        lstcon_group_decref(grp);
1643
1644        return rc;
1645}
1646
1647int
1648lstcon_nodes_debug(int timeout, int count,
1649                   struct lnet_process_id __user *ids_up,
1650                   struct list_head __user *result_up)
1651{
1652        struct lnet_process_id id;
1653        struct lstcon_ndlink *ndl;
1654        struct lstcon_group *grp;
1655        int i;
1656        int rc;
1657
1658        rc = lstcon_group_alloc(NULL, &grp);
1659        if (rc) {
1660                CDEBUG(D_NET, "Out of memory\n");
1661                return rc;
1662        }
1663
1664        for (i = 0; i < count; i++) {
1665                if (copy_from_user(&id, &ids_up[i], sizeof(id))) {
1666                        rc = -EFAULT;
1667                        break;
1668                }
1669
1670                /* node is added to tmp group */
1671                rc = lstcon_group_ndlink_find(grp, id, &ndl, 1);
1672                if (rc) {
1673                        CERROR("Can't create node link\n");
1674                        break;
1675                }
1676        }
1677
1678        if (rc) {
1679                lstcon_group_decref(grp);
1680                return rc;
1681        }
1682
1683        rc = lstcon_debug_ndlist(&grp->grp_ndl_list, NULL,
1684                                 timeout, result_up);
1685
1686        lstcon_group_decref(grp);
1687
1688        return rc;
1689}
1690
1691int
1692lstcon_session_match(struct lst_sid sid)
1693{
1694        return (console_session.ses_id.ses_nid == sid.ses_nid &&
1695                console_session.ses_id.ses_stamp == sid.ses_stamp) ? 1 : 0;
1696}
1697
1698static void
1699lstcon_new_session_id(struct lst_sid *sid)
1700{
1701        struct lnet_process_id id;
1702
1703        LASSERT(console_session.ses_state == LST_SESSION_NONE);
1704
1705        LNetGetId(1, &id);
1706        sid->ses_nid = id.nid;
1707        sid->ses_stamp = cfs_time_current();
1708}
1709
1710int
1711lstcon_session_new(char *name, int key, unsigned int feats,
1712                   int timeout, int force, struct lst_sid __user *sid_up)
1713{
1714        int rc = 0;
1715        int i;
1716
1717        if (console_session.ses_state != LST_SESSION_NONE) {
1718                /* session exists */
1719                if (!force) {
1720                        CNETERR("Session %s already exists\n",
1721                                console_session.ses_name);
1722                        return -EEXIST;
1723                }
1724
1725                rc = lstcon_session_end();
1726
1727                /* lstcon_session_end() only return local error */
1728                if (rc)
1729                        return rc;
1730        }
1731
1732        if (feats & ~LST_FEATS_MASK) {
1733                CNETERR("Unknown session features %x\n",
1734                        (feats & ~LST_FEATS_MASK));
1735                return -EINVAL;
1736        }
1737
1738        for (i = 0; i < LST_GLOBAL_HASHSIZE; i++)
1739                LASSERT(list_empty(&console_session.ses_ndl_hash[i]));
1740
1741        lstcon_new_session_id(&console_session.ses_id);
1742
1743        console_session.ses_key = key;
1744        console_session.ses_state = LST_SESSION_ACTIVE;
1745        console_session.ses_force = !!force;
1746        console_session.ses_features = feats;
1747        console_session.ses_feats_updated = 0;
1748        console_session.ses_timeout = (timeout <= 0) ?
1749                                      LST_CONSOLE_TIMEOUT : timeout;
1750
1751        if (strlen(name) > sizeof(console_session.ses_name) - 1)
1752                return -E2BIG;
1753        strlcpy(console_session.ses_name, name,
1754                sizeof(console_session.ses_name));
1755
1756        rc = lstcon_batch_add(LST_DEFAULT_BATCH);
1757        if (rc)
1758                return rc;
1759
1760        rc = lstcon_rpc_pinger_start();
1761        if (rc) {
1762                struct lstcon_batch *bat = NULL;
1763
1764                lstcon_batch_find(LST_DEFAULT_BATCH, &bat);
1765                lstcon_batch_destroy(bat);
1766
1767                return rc;
1768        }
1769
1770        if (!copy_to_user(sid_up, &console_session.ses_id,
1771                          sizeof(struct lst_sid)))
1772                return rc;
1773
1774        lstcon_session_end();
1775
1776        return -EFAULT;
1777}
1778
1779int
1780lstcon_session_info(struct lst_sid __user *sid_up, int __user *key_up,
1781                    unsigned __user *featp,
1782                    struct lstcon_ndlist_ent __user *ndinfo_up,
1783                    char __user *name_up, int len)
1784{
1785        struct lstcon_ndlist_ent *entp;
1786        struct lstcon_ndlink *ndl;
1787        int rc = 0;
1788
1789        if (console_session.ses_state != LST_SESSION_ACTIVE)
1790                return -ESRCH;
1791
1792        LIBCFS_ALLOC(entp, sizeof(*entp));
1793        if (!entp)
1794                return -ENOMEM;
1795
1796        list_for_each_entry(ndl, &console_session.ses_ndl_list, ndl_link)
1797                LST_NODE_STATE_COUNTER(ndl->ndl_node, entp);
1798
1799        if (copy_to_user(sid_up, &console_session.ses_id,
1800                         sizeof(*sid_up)) ||
1801            copy_to_user(key_up, &console_session.ses_key,
1802                         sizeof(*key_up)) ||
1803            copy_to_user(featp, &console_session.ses_features,
1804                         sizeof(*featp)) ||
1805            copy_to_user(ndinfo_up, entp, sizeof(*entp)) ||
1806            copy_to_user(name_up, console_session.ses_name, len))
1807                rc = -EFAULT;
1808
1809        LIBCFS_FREE(entp, sizeof(*entp));
1810
1811        return rc;
1812}
1813
1814int
1815lstcon_session_end(void)
1816{
1817        struct lstcon_rpc_trans *trans;
1818        struct lstcon_group *grp;
1819        struct lstcon_batch *bat;
1820        int rc = 0;
1821
1822        LASSERT(console_session.ses_state == LST_SESSION_ACTIVE);
1823
1824        rc = lstcon_rpc_trans_ndlist(&console_session.ses_ndl_list,
1825                                     NULL, LST_TRANS_SESEND, NULL,
1826                                     lstcon_sesrpc_condition, &trans);
1827        if (rc) {
1828                CERROR("Can't create transaction: %d\n", rc);
1829                return rc;
1830        }
1831
1832        console_session.ses_shutdown = 1;
1833
1834        lstcon_rpc_pinger_stop();
1835
1836        lstcon_rpc_trans_postwait(trans, LST_TRANS_TIMEOUT);
1837
1838        lstcon_rpc_trans_destroy(trans);
1839        /* User can do nothing even rpc failed, so go on */
1840
1841        /* waiting for orphan rpcs to die */
1842        lstcon_rpc_cleanup_wait();
1843
1844        console_session.ses_id = LST_INVALID_SID;
1845        console_session.ses_state = LST_SESSION_NONE;
1846        console_session.ses_key = 0;
1847        console_session.ses_force = 0;
1848        console_session.ses_feats_updated = 0;
1849
1850        /* destroy all batches */
1851        while (!list_empty(&console_session.ses_bat_list)) {
1852                bat = list_entry(console_session.ses_bat_list.next,
1853                                 struct lstcon_batch, bat_link);
1854
1855                lstcon_batch_destroy(bat);
1856        }
1857
1858        /* destroy all groups */
1859        while (!list_empty(&console_session.ses_grp_list)) {
1860                grp = list_entry(console_session.ses_grp_list.next,
1861                                 struct lstcon_group, grp_link);
1862                LASSERT(grp->grp_ref == 1);
1863
1864                lstcon_group_decref(grp);
1865        }
1866
1867        /* all nodes should be released */
1868        LASSERT(list_empty(&console_session.ses_ndl_list));
1869
1870        console_session.ses_shutdown = 0;
1871        console_session.ses_expired = 0;
1872
1873        return rc;
1874}
1875
1876int
1877lstcon_session_feats_check(unsigned int feats)
1878{
1879        int rc = 0;
1880
1881        if (feats & ~LST_FEATS_MASK) {
1882                CERROR("Can't support these features: %x\n",
1883                       (feats & ~LST_FEATS_MASK));
1884                return -EPROTO;
1885        }
1886
1887        spin_lock(&console_session.ses_rpc_lock);
1888
1889        if (!console_session.ses_feats_updated) {
1890                console_session.ses_feats_updated = 1;
1891                console_session.ses_features = feats;
1892        }
1893
1894        if (console_session.ses_features != feats)
1895                rc = -EPROTO;
1896
1897        spin_unlock(&console_session.ses_rpc_lock);
1898
1899        if (rc) {
1900                CERROR("remote features %x do not match with session features %x of console\n",
1901                       feats, console_session.ses_features);
1902        }
1903
1904        return rc;
1905}
1906
1907static int
1908lstcon_acceptor_handle(struct srpc_server_rpc *rpc)
1909{
1910        struct srpc_msg *rep    = &rpc->srpc_replymsg;
1911        struct srpc_msg *req    = &rpc->srpc_reqstbuf->buf_msg;
1912        struct srpc_join_reqst *jreq = &req->msg_body.join_reqst;
1913        struct srpc_join_reply *jrep = &rep->msg_body.join_reply;
1914        struct lstcon_group *grp = NULL;
1915        struct lstcon_ndlink *ndl;
1916        int rc = 0;
1917
1918        sfw_unpack_message(req);
1919
1920        mutex_lock(&console_session.ses_mutex);
1921
1922        jrep->join_sid = console_session.ses_id;
1923
1924        if (console_session.ses_id.ses_nid == LNET_NID_ANY) {
1925                jrep->join_status = ESRCH;
1926                goto out;
1927        }
1928
1929        if (lstcon_session_feats_check(req->msg_ses_feats)) {
1930                jrep->join_status = EPROTO;
1931                goto out;
1932        }
1933
1934        if (jreq->join_sid.ses_nid != LNET_NID_ANY &&
1935            !lstcon_session_match(jreq->join_sid)) {
1936                jrep->join_status = EBUSY;
1937                goto out;
1938        }
1939
1940        if (lstcon_group_find(jreq->join_group, &grp)) {
1941                rc = lstcon_group_alloc(jreq->join_group, &grp);
1942                if (rc) {
1943                        CERROR("Out of memory\n");
1944                        goto out;
1945                }
1946
1947                list_add_tail(&grp->grp_link,
1948                              &console_session.ses_grp_list);
1949                lstcon_group_addref(grp);
1950        }
1951
1952        if (grp->grp_ref > 2) {
1953                /* Group in using */
1954                jrep->join_status = EBUSY;
1955                goto out;
1956        }
1957
1958        rc = lstcon_group_ndlink_find(grp, rpc->srpc_peer, &ndl, 0);
1959        if (!rc) {
1960                jrep->join_status = EEXIST;
1961                goto out;
1962        }
1963
1964        rc = lstcon_group_ndlink_find(grp, rpc->srpc_peer, &ndl, 1);
1965        if (rc) {
1966                CERROR("Out of memory\n");
1967                goto out;
1968        }
1969
1970        ndl->ndl_node->nd_state = LST_NODE_ACTIVE;
1971        ndl->ndl_node->nd_timeout = console_session.ses_timeout;
1972
1973        if (!grp->grp_userland)
1974                grp->grp_userland = 1;
1975
1976        strlcpy(jrep->join_session, console_session.ses_name,
1977                sizeof(jrep->join_session));
1978        jrep->join_timeout = console_session.ses_timeout;
1979        jrep->join_status = 0;
1980
1981out:
1982        rep->msg_ses_feats = console_session.ses_features;
1983        if (grp)
1984                lstcon_group_decref(grp);
1985
1986        mutex_unlock(&console_session.ses_mutex);
1987
1988        return rc;
1989}
1990
1991static struct srpc_service lstcon_acceptor_service;
1992
1993static void lstcon_init_acceptor_service(void)
1994{
1995        /* initialize selftest console acceptor service table */
1996        lstcon_acceptor_service.sv_name = "join session";
1997        lstcon_acceptor_service.sv_handler = lstcon_acceptor_handle;
1998        lstcon_acceptor_service.sv_id = SRPC_SERVICE_JOIN;
1999        lstcon_acceptor_service.sv_wi_total = SFW_FRWK_WI_MAX;
2000}
2001
2002static DECLARE_IOCTL_HANDLER(lstcon_ioctl_handler, lstcon_ioctl_entry);
2003
2004/* initialize console */
2005int
2006lstcon_console_init(void)
2007{
2008        int i;
2009        int rc;
2010
2011        memset(&console_session, 0, sizeof(struct lstcon_session));
2012
2013        console_session.ses_id = LST_INVALID_SID;
2014        console_session.ses_state = LST_SESSION_NONE;
2015        console_session.ses_timeout = 0;
2016        console_session.ses_force = 0;
2017        console_session.ses_expired = 0;
2018        console_session.ses_feats_updated = 0;
2019        console_session.ses_features = LST_FEATS_MASK;
2020        console_session.ses_laststamp = ktime_get_real_seconds();
2021
2022        mutex_init(&console_session.ses_mutex);
2023
2024        INIT_LIST_HEAD(&console_session.ses_ndl_list);
2025        INIT_LIST_HEAD(&console_session.ses_grp_list);
2026        INIT_LIST_HEAD(&console_session.ses_bat_list);
2027        INIT_LIST_HEAD(&console_session.ses_trans_list);
2028
2029        LIBCFS_ALLOC(console_session.ses_ndl_hash,
2030                     sizeof(struct list_head) * LST_GLOBAL_HASHSIZE);
2031        if (!console_session.ses_ndl_hash)
2032                return -ENOMEM;
2033
2034        for (i = 0; i < LST_GLOBAL_HASHSIZE; i++)
2035                INIT_LIST_HEAD(&console_session.ses_ndl_hash[i]);
2036
2037        /* initialize acceptor service table */
2038        lstcon_init_acceptor_service();
2039
2040        rc = srpc_add_service(&lstcon_acceptor_service);
2041        LASSERT(rc != -EBUSY);
2042        if (rc) {
2043                LIBCFS_FREE(console_session.ses_ndl_hash,
2044                            sizeof(struct list_head) * LST_GLOBAL_HASHSIZE);
2045                return rc;
2046        }
2047
2048        rc = srpc_service_add_buffers(&lstcon_acceptor_service,
2049                                      lstcon_acceptor_service.sv_wi_total);
2050        if (rc) {
2051                rc = -ENOMEM;
2052                goto out;
2053        }
2054
2055        rc = libcfs_register_ioctl(&lstcon_ioctl_handler);
2056
2057        if (!rc) {
2058                lstcon_rpc_module_init();
2059                return 0;
2060        }
2061
2062out:
2063        srpc_shutdown_service(&lstcon_acceptor_service);
2064        srpc_remove_service(&lstcon_acceptor_service);
2065
2066        LIBCFS_FREE(console_session.ses_ndl_hash,
2067                    sizeof(struct list_head) * LST_GLOBAL_HASHSIZE);
2068
2069        srpc_wait_service_shutdown(&lstcon_acceptor_service);
2070
2071        return rc;
2072}
2073
2074int
2075lstcon_console_fini(void)
2076{
2077        int i;
2078
2079        libcfs_deregister_ioctl(&lstcon_ioctl_handler);
2080
2081        mutex_lock(&console_session.ses_mutex);
2082
2083        srpc_shutdown_service(&lstcon_acceptor_service);
2084        srpc_remove_service(&lstcon_acceptor_service);
2085
2086        if (console_session.ses_state != LST_SESSION_NONE)
2087                lstcon_session_end();
2088
2089        lstcon_rpc_module_fini();
2090
2091        mutex_unlock(&console_session.ses_mutex);
2092
2093        LASSERT(list_empty(&console_session.ses_ndl_list));
2094        LASSERT(list_empty(&console_session.ses_grp_list));
2095        LASSERT(list_empty(&console_session.ses_bat_list));
2096        LASSERT(list_empty(&console_session.ses_trans_list));
2097
2098        for (i = 0; i < LST_NODE_HASHSIZE; i++)
2099                LASSERT(list_empty(&console_session.ses_ndl_hash[i]));
2100
2101        LIBCFS_FREE(console_session.ses_ndl_hash,
2102                    sizeof(struct list_head) * LST_GLOBAL_HASHSIZE);
2103
2104        srpc_wait_service_shutdown(&lstcon_acceptor_service);
2105
2106        return 0;
2107}
2108