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