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