1 // SPDX-License-Identifier: GPL-2.0
4 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
5 * Use is subject to license terms.
7 * Copyright (c) 2012, 2017, Intel Corporation.
11 * This file is part of Lustre, http://www.lustre.org/
13 * Author: Liang Zhen <liangzhen@clusterfs.com>
25 #include <sys/ioctl.h>
27 #include <linux/types.h>
29 #include <libcfs/util/list.h>
30 #include <libcfs/util/ioctl.h>
31 #include <libcfs/util/parser.h>
32 #include <linux/lnet/lnetctl.h>
33 #include <linux/lnet/lnetst.h>
34 #include <linux/lnet/nidstr.h>
35 #include "lnetconfig/liblnetconfig.h"
37 static void lst_print_usage(char *cmd);
39 static int lst_info_batch_ioctl(char *batch, int test, int server,
40 struct lstcon_test_batch_ent *entp, int *idxp,
41 int *ndentp, struct lstcon_node_ent *dentsp);
42 static int lst_info_group_ioctl(char *name, struct lstcon_ndlist_ent *gent,
43 int *idx, int *count, struct lstcon_node_ent *dents);
44 static int lst_query_batch_ioctl(char *batch, int test, int server,
45 int timeout, struct list_head *head);
47 struct lst_sid LST_INVALID_SID = { .ses_nid = LNET_NID_ANY, .ses_stamp = -1 };
48 static unsigned int session_key;
50 /* All nodes running 2.6.50 or later understand feature LST_FEAT_BULK_LEN */
51 static unsigned int session_features = LST_FEATS_MASK;
52 static struct lstcon_trans_stat trans_stat;
54 typedef struct list_string {
55 struct list_string *lstr_next;
61 # define offsetof(typ, memb) ((unsigned long)((char *)&(((typ *)0)->memb)))
64 static int alloc_count;
70 lstr_t *lstr = malloc(offsetof(lstr_t, lstr_str[sz]));
73 fprintf(stderr, "Can't allocate lstr\n");
80 lstr->lstr_str[0] = 0;
86 free_lstr(lstr_t *lstr)
89 alloc_nob -= lstr->lstr_sz;
94 new_lstrs(lstr_t **list, char *prefix, char *postfix,
95 int lo, int hi, int stride)
97 int n1 = strlen(prefix);
98 int n2 = strlen(postfix);
99 int sz = n1 + 20 + n2 + 1;
102 lstr_t *n = alloc_lstr(sz);
104 snprintf(n->lstr_str, sz - 1, "%s%u%s", prefix, lo, postfix);
106 n->lstr_next = *list;
114 expand_lstr(lstr_t **list, lstr_t *l)
116 int nob = strlen(l->lstr_str);
117 char *b1, *b2, *expr, *sep;
120 b1 = strchr(l->lstr_str, '[');
122 l->lstr_next = *list;
127 b2 = strchr(b1, ']');
128 if (b2 == NULL || b2 == b1 + 1)
135 sep = strchr(expr, ',');
141 if (sscanf(expr, "%u%n", &x, &n) >= 1 && n == nob) {
143 new_lstrs(list, l->lstr_str, b2, x, x, 1);
148 if (sscanf(expr, "%u-%u%n", &x, &y, &n) >= 2 && n == nob &&
151 new_lstrs(list, l->lstr_str, b2, x, y, 1);
156 if (sscanf(expr, "%u-%u/%u%n", &x, &y, &z, &n) >= 3 &&
159 new_lstrs(list, l->lstr_str, b2, x, y, z);
165 } while ((expr = sep) != NULL);
173 expand_strs(char *str, lstr_t **head)
181 l = alloc_lstr(strlen(str) + 1);
182 memcpy(l->lstr_str, str, strlen(str) + 1);
190 while ((l = list) != NULL) {
193 rc = expand_lstr(&nlist, l);
195 fprintf(stderr, "Syntax error in \"%s\"\n",
204 /* re-order onto 'list' */
205 while ((l = nlist) != NULL) {
206 nlist = l->lstr_next;
211 } while (expanded && rc > 0);
218 while ((l = list) != NULL) {
227 lst_parse_nids(char *str, int *countp, struct lnet_process_id **idspp)
235 rc = expand_strs(str, &head);
245 *idspp = malloc(c * sizeof(struct lnet_process_id));
246 if (*idspp == NULL) {
247 fprintf(stderr, "Out of memory\n");
254 while ((l = head) != NULL) {
258 (*idspp)[i].nid = libcfs_str2nid(l->lstr_str);
259 if ((*idspp)[i].nid == LNET_NID_ANY) {
260 fprintf(stderr, "Invalid nid: %s\n",
265 (*idspp)[i].pid = LNET_PID_LUSTRE;
282 lst_node_state2str(int state)
284 if (state == LST_NODE_ACTIVE)
286 if (state == LST_NODE_BUSY)
288 if (state == LST_NODE_DOWN)
295 lst_node_str2state(char *str)
297 if (strcasecmp(str, "active") == 0)
298 return LST_NODE_ACTIVE;
299 if (strcasecmp(str, "busy") == 0)
300 return LST_NODE_BUSY;
301 if (strcasecmp(str, "down") == 0)
302 return LST_NODE_DOWN;
303 if (strcasecmp(str, "unknown") == 0)
304 return LST_NODE_UNKNOWN;
305 if (strcasecmp(str, "invalid") == 0)
306 return (LST_NODE_UNKNOWN | LST_NODE_DOWN | LST_NODE_BUSY);
312 lst_test_type2name(int type)
314 if (type == LST_TEST_PING)
316 if (type == LST_TEST_BULK)
323 lst_test_name2type(char *name)
325 if (strcasecmp(name, "ping") == 0)
326 return LST_TEST_PING;
327 if (strcasecmp(name, "brw") == 0)
328 return LST_TEST_BULK;
334 lst_print_error(char *sub, const char *def_format, ...)
338 /* local error returned from kernel */
341 fprintf(stderr, "No session exists\n");
344 fprintf(stderr, "Session is shutting down\n");
347 fprintf(stderr, "Unmatched session key or not root\n");
350 fprintf(stderr, "Can't find %s in current session\n", sub);
353 fprintf(stderr, "Invalid parameters list in command line\n");
356 fprintf(stderr, "Bad parameter address\n");
359 fprintf(stderr, "%s already exists\n", sub);
362 va_start(ap, def_format);
363 vfprintf(stderr, def_format, ap);
371 lst_free_rpcent(struct list_head *head)
373 struct lstcon_rpc_ent *ent;
375 while (!list_empty(head)) {
376 ent = list_first_entry(head, struct lstcon_rpc_ent, rpe_link);
378 list_del(&ent->rpe_link);
384 lst_reset_rpcent(struct list_head *head)
386 struct lstcon_rpc_ent *ent;
388 list_for_each_entry(ent, head, rpe_link) {
389 ent->rpe_sid = LST_INVALID_SID;
390 ent->rpe_peer.nid = LNET_NID_ANY;
391 ent->rpe_peer.pid = LNET_PID_ANY;
392 ent->rpe_rpc_errno = ent->rpe_fwk_errno = 0;
397 lst_alloc_rpcent(struct list_head *head, int count, int offset)
399 struct lstcon_rpc_ent *ent;
402 for (i = 0; i < count; i++) {
403 ent = malloc(offsetof(struct lstcon_rpc_ent,
404 rpe_payload[offset]));
406 lst_free_rpcent(head);
410 memset(ent, 0, offsetof(struct lstcon_rpc_ent,
411 rpe_payload[offset]));
413 ent->rpe_sid = LST_INVALID_SID;
414 ent->rpe_peer.nid = LNET_NID_ANY;
415 ent->rpe_peer.pid = LNET_PID_ANY;
416 list_add(&ent->rpe_link, head);
423 lst_print_transerr(struct list_head *head, char *optstr)
425 struct lstcon_rpc_ent *ent;
427 list_for_each_entry(ent, head, rpe_link) {
428 if (ent->rpe_rpc_errno == 0 && ent->rpe_fwk_errno == 0)
431 if (ent->rpe_rpc_errno != 0) {
432 fprintf(stderr, "%s RPC failed on %s: %s\n",
433 optstr, libcfs_id2str(ent->rpe_peer),
434 strerror(ent->rpe_rpc_errno));
438 fprintf(stderr, "operation %s failed on %s: %s\n",
439 optstr, libcfs_id2str(ent->rpe_peer),
440 strerror(ent->rpe_fwk_errno));
445 lst_ioctl(unsigned int opc, void *buf, int len)
447 struct libcfs_ioctl_data data;
450 LIBCFS_IOC_INIT(data);
451 data.ioc_u32[0] = opc;
452 data.ioc_plen1 = len;
453 data.ioc_pbuf1 = (char *)buf;
454 data.ioc_plen2 = sizeof(trans_stat);
455 data.ioc_pbuf2 = (char *)&trans_stat;
457 memset(&trans_stat, 0, sizeof(trans_stat));
459 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_LNETST, &data);
461 /* local error, no valid RPC result */
466 if (trans_stat.trs_rpc_errno != 0)
469 /* Framework error */
470 if (trans_stat.trs_fwk_errno != 0)
476 static int lst_yaml_session(const char *label, const char *timeout, int nlflags,
479 struct lstcon_ndlist_ent ndinfo = { };
480 struct lst_sid sid = LST_INVALID_SID;
481 /* nlflags being zero means we are destroying the session.
482 * No parsing of reply needed.
484 bool done = nlflags ? false : true;
485 char nid[LNET_NIDSTR_SIZE];
486 char name[LST_NAME_SIZE];
487 unsigned int key = 0;
488 yaml_emitter_t request;
494 sk = nl_socket_alloc();
498 /* Note: NL_AUTO_PID == zero which we use by default for the
499 * session_key when creating a new session. This is considered
500 * an invalid key so we need to get the real session key from
501 * the yaml parser yet to be created. If the user did request
502 * a specific session key then set the socket's port id to this
506 nl_socket_set_local_port(sk, session_key);
508 /* Setup reply parser to recieve Netlink packets */
509 rc = yaml_parser_initialize(&reply);
515 rc = yaml_parser_set_input_netlink(&reply, sk, false);
519 /* Create Netlink emitter to send request to kernel */
520 yaml_emitter_initialize(&request);
521 rc = yaml_emitter_set_output_netlink(&request, sk,
522 LNET_SELFTEST_GENL_NAME,
523 LNET_SELFTEST_GENL_VERSION,
524 LNET_SELFTEST_CMD_SESSIONS,
529 yaml_emitter_open(&request);
530 yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
531 rc = yaml_emitter_emit(&request, &event);
535 yaml_mapping_start_event_initialize(&event, NULL,
536 (yaml_char_t *)YAML_MAP_TAG,
537 1, YAML_BLOCK_MAPPING_STYLE);
538 rc = yaml_emitter_emit(&request, &event);
542 yaml_scalar_event_initialize(&event, NULL,
543 (yaml_char_t *)YAML_STR_TAG,
544 (yaml_char_t *)"sessions",
545 strlen("sessions"), 1, 0,
546 YAML_PLAIN_SCALAR_STYLE);
547 rc = yaml_emitter_emit(&request, &event);
552 yaml_scalar_event_initialize(&event, NULL,
553 (yaml_char_t *)YAML_STR_TAG,
556 YAML_PLAIN_SCALAR_STYLE);
557 rc = yaml_emitter_emit(&request, &event);
563 /* sessions: { name: 'name', timeout: 300 }
569 yaml_mapping_start_event_initialize(&event, NULL,
570 (yaml_char_t *)YAML_MAP_TAG,
571 1, YAML_FLOW_MAPPING_STYLE);
572 rc = yaml_emitter_emit(&request, &event);
576 yaml_scalar_event_initialize(&event, NULL,
577 (yaml_char_t *)YAML_STR_TAG,
578 (yaml_char_t *)"name",
579 strlen("name"), 1, 0,
580 YAML_PLAIN_SCALAR_STYLE);
581 rc = yaml_emitter_emit(&request, &event);
585 yaml_scalar_event_initialize(&event, NULL,
586 (yaml_char_t *)YAML_STR_TAG,
587 (yaml_char_t *)label,
589 YAML_PLAIN_SCALAR_STYLE);
590 rc = yaml_emitter_emit(&request, &event);
595 yaml_scalar_event_initialize(&event, NULL,
596 (yaml_char_t *)YAML_STR_TAG,
597 (yaml_char_t *)"timeout",
598 strlen("timeout"), 1, 0,
599 YAML_PLAIN_SCALAR_STYLE);
600 rc = yaml_emitter_emit(&request, &event);
604 yaml_scalar_event_initialize(&event, NULL,
605 (yaml_char_t *)YAML_STR_TAG,
606 (yaml_char_t *)timeout,
607 strlen(timeout), 1, 0,
608 YAML_PLAIN_SCALAR_STYLE);
609 rc = yaml_emitter_emit(&request, &event);
614 yaml_mapping_end_event_initialize(&event);
615 rc = yaml_emitter_emit(&request, &event);
620 yaml_mapping_end_event_initialize(&event);
621 rc = yaml_emitter_emit(&request, &event);
625 yaml_document_end_event_initialize(&event, 0);
626 rc = yaml_emitter_emit(&request, &event);
630 rc = yaml_emitter_close(&request);
633 yaml_emitter_log_error(&request, stderr);
634 yaml_emitter_delete(&request);
638 yaml_emitter_delete(&request);
641 rc = yaml_parser_parse(&reply, &event);
645 if (event.type == YAML_SCALAR_EVENT) {
646 char *tmp, *endp = NULL;
648 if (strcmp((char *)event.data.scalar.value,
650 yaml_event_delete(&event);
651 rc = yaml_parser_parse(&reply, &event);
655 strncpy(name, (char *)event.data.scalar.value,
659 if (strcmp((char *)event.data.scalar.value,
661 yaml_event_delete(&event);
662 rc = yaml_parser_parse(&reply, &event);
666 tmp = (char *)event.data.scalar.value;
667 key = strtoul(tmp, &endp, 10);
672 if (strcmp((char *)event.data.scalar.value,
674 yaml_event_delete(&event);
675 rc = yaml_parser_parse(&reply, &event);
679 tmp = (char *)event.data.scalar.value;
680 sid.ses_stamp = strtoll(tmp, &endp, 10);
685 if (strcmp((char *)event.data.scalar.value,
687 yaml_event_delete(&event);
688 rc = yaml_parser_parse(&reply, &event);
692 strncpy(nid, (char *)event.data.scalar.value,
696 if (strcmp((char *)event.data.scalar.value,
698 yaml_event_delete(&event);
699 rc = yaml_parser_parse(&reply, &event);
703 tmp = (char *)event.data.scalar.value;
704 ndinfo.nle_nnode = strtoul(tmp, &endp, 10);
710 done = (event.type == YAML_STREAM_END_EVENT);
712 yaml_event_delete(&event);
715 if (nlflags & NLM_F_CREATE) {
716 session_features = yaml_parser_get_reader_proto_version(&reply);
720 if (rc == 0 && errmsg)
721 yaml_parser_log_error(&reply, stderr, errmsg);
722 yaml_parser_delete(&reply);
725 if (((nlflags & NLM_F_DUMP) == NLM_F_DUMP) && rc != 0) {
727 "%s ID: %ju@%s, KEY: %u FEATURES: %x NODES: %d\n",
728 name, (uintmax_t)sid.ses_stamp, nid,
729 key, session_features, ndinfo.nle_nnode);
732 return rc == 0 ? -1 : 0;
736 lst_new_session_ioctl(char *name, int timeout, int force, struct lst_sid *sid)
738 struct lstio_session_new_args args = { 0 };
740 args.lstio_ses_key = session_key;
741 args.lstio_ses_timeout = timeout;
742 args.lstio_ses_force = force;
743 args.lstio_ses_idp = sid;
744 args.lstio_ses_feats = session_features;
745 args.lstio_ses_nmlen = strlen(name);
746 args.lstio_ses_namep = name;
748 return lst_ioctl(LSTIO_SESSION_NEW, &args, sizeof(args));
752 jt_lst_new_session(int argc, char **argv)
754 char buf[LST_NAME_SIZE * 2 + 1];
755 char *name, *timeout_s = NULL;
756 int nlflags = NLM_F_CREATE;
757 struct lst_sid session_id;
764 static const struct option session_opts[] = {
765 { .name = "timeout", .has_arg = required_argument, .val = 't' },
766 { .name = "force", .has_arg = no_argument, .val = 'f' },
770 c = getopt_long(argc, argv, "ft:",
771 session_opts, &optidx);
777 nlflags |= NLM_F_REPLACE;
784 lst_print_usage(argv[0]);
790 timeout = atoi(timeout_s);
792 fprintf(stderr, "Invalid timeout value\n");
797 if (optind == argc - 1) {
798 name = argv[optind++];
799 if (strlen(name) >= LST_NAME_SIZE) {
800 fprintf(stderr, "Name size is limited to %d\n",
804 } else if (optind == argc) {
805 char user[LST_NAME_SIZE];
806 char host[LST_NAME_SIZE];
807 struct passwd *pw = getpwuid(getuid());
810 snprintf(user, sizeof(user), "%d", (int)getuid());
812 snprintf(user, sizeof(user), "%s", pw->pw_name);
814 rc = gethostname(host, sizeof(host));
816 snprintf(host, sizeof(host), "unknown_host");
818 snprintf(buf, sizeof(buf), "%s@%s", user, host);
821 lst_print_usage(argv[0]);
825 rc = lst_yaml_session(name, timeout_s, nlflags, "new session");
829 if (session_key == 0) {
831 "Can't find env LST_SESSION or value is not valid\n");
835 rc = lst_new_session_ioctl(name, timeout, force, &session_id);
837 lst_print_error("session", "Failed to create session: %s\n",
842 fprintf(stdout, "SESSION: %s FEATURES: %x TIMEOUT: %d FORCE: %s\n",
843 name, session_features, timeout, force ? "Yes" : "No");
848 lst_session_info_ioctl(char *name, int len, int *key, unsigned int *featp,
849 struct lst_sid *sid, struct lstcon_ndlist_ent *ndinfo)
851 struct lstio_session_info_args args = { 0 };
853 args.lstio_ses_idp = sid;
854 args.lstio_ses_keyp = key;
855 args.lstio_ses_featp = featp;
856 args.lstio_ses_ndinfo = ndinfo;
857 args.lstio_ses_nmlen = len;
858 args.lstio_ses_namep = name;
860 return lst_ioctl(LSTIO_SESSION_INFO, &args, sizeof(args));
864 jt_lst_show_session(int argc, char **argv)
866 struct lstcon_ndlist_ent ndinfo;
868 char name[LST_NAME_SIZE];
873 rc = lst_yaml_session(NULL, NULL, NLM_F_DUMP, "show session");
877 rc = lst_session_info_ioctl(name, sizeof(name), &key,
878 &feats, &sid, &ndinfo);
881 lst_print_error("session", "Failed to show session: %s\n",
886 fprintf(stdout, "%s ID: %ju@%s, KEY: %d FEATURES: %x NODES: %d\n",
887 name, (uintmax_t)sid.ses_stamp, libcfs_nid2str(sid.ses_nid),
888 key, feats, ndinfo.nle_nnode);
894 lst_end_session_ioctl(void)
896 struct lstio_session_end_args args = { 0 };
898 args.lstio_ses_key = session_key;
899 return lst_ioctl(LSTIO_SESSION_END, &args, sizeof(args));
903 jt_lst_end_session(int argc, char **argv)
907 if (session_key == 0) {
909 "Can't find env LST_SESSION or value is not valid\n");
913 rc = lst_yaml_session(NULL, NULL, 0, "end session");
917 rc = lst_end_session_ioctl();
920 fprintf(stdout, "session is ended\n");
925 lst_print_error("session", "Failed to end session: %s\n",
930 if (trans_stat.trs_rpc_errno != 0) {
932 "[RPC] Failed to send %d session RPCs: %s\n",
933 lstcon_rpc_stat_failure(&trans_stat, 0),
934 strerror(trans_stat.trs_rpc_errno));
937 if (trans_stat.trs_fwk_errno != 0) {
939 "[FWK] Failed to end session on %d nodes: %s\n",
940 lstcon_sesop_stat_failure(&trans_stat, 0),
941 strerror(trans_stat.trs_fwk_errno));
947 #define LST_NODES_TITLE "\tACTIVE\tBUSY\tDOWN\tUNKNOWN\tTOTAL\n"
949 static int lst_yaml_display_groups(yaml_parser_t *reply, char *group,
950 int states, bool print)
956 char name[LST_NAME_SIZE] = {};
961 fprintf(stdout, LST_NODES_TITLE);
964 rc = yaml_parser_parse(reply, &event);
968 if (event.type == YAML_MAPPING_START_EVENT) {
972 rc = yaml_parser_parse(reply, &next);
976 if (next.type != YAML_SCALAR_EVENT) {
977 yaml_event_delete(&next);
981 value = (char *)next.data.scalar.value;
982 if (strcmp(value, "groups") == 0) {
983 yaml_event_delete(&next);
984 } else if (strcmp(value, "nid") == 0) {
988 rc = yaml_parser_parse(reply, &next);
992 fprintf(stdout, "\t%s: ",
993 (char *)next.data.scalar.value);
995 rc = yaml_parser_parse(reply, &next);
999 tmp = (char *)next.data.scalar.value;
1000 if (strcmp(tmp, "status") == 0) {
1003 rc = yaml_parser_parse(reply,
1008 fprintf(stdout, "%s\n",
1009 (char *)state.data.scalar.value);
1015 rc = yaml_parser_parse(reply, &next);
1019 strncpy(name, value, sizeof(name) - 1);
1020 fprintf(stdout, "Group [ %s ]\n", name);
1024 YAML_SEQUENCE_START_EVENT) {
1026 "No nodes found [ %s ]\n",
1030 } else if (event.type == YAML_SEQUENCE_END_EVENT &&
1032 fprintf(stdout, "Total %d nodes [ %s ]\n",
1037 done = (event.type == YAML_STREAM_END_EVENT);
1038 yaml_event_delete(&event);
1041 int active = 0, busy = 0, down = 0, unknown = 0;
1042 char group[LST_NAME_SIZE];
1046 rc = yaml_parser_parse(reply, &event);
1050 if (event.type == YAML_SCALAR_EVENT) {
1051 char *value = (char *)event.data.scalar.value;
1054 value = (char *)event.data.scalar.value;
1055 if (strcmp(value, "groups") == 0) {
1056 yaml_event_delete(&event);
1060 rc = yaml_parser_parse(reply, &next);
1064 if (next.type == YAML_SCALAR_EVENT) {
1067 status = lst_node_str2state((char *)next.data.scalar.value);
1069 case LST_NODE_ACTIVE:
1078 case LST_NODE_UNKNOWN:
1083 } else if (next.type == YAML_SEQUENCE_START_EVENT) {
1084 strncpy(group, value,
1091 yaml_event_delete(&next);
1092 } else if (event.type == YAML_SEQUENCE_END_EVENT) {
1093 if (strlen(group)) {
1094 fprintf(stdout, "\t%d\t%d\t%d\t%d\t%d\t%s\n",
1095 active, busy, down, unknown,
1096 active + busy + down + unknown,
1099 memset(group, 0, sizeof(group));
1101 done = (event.type == YAML_STREAM_END_EVENT);
1102 yaml_event_delete(&event);
1109 rc = yaml_parser_parse(reply, &event);
1113 if (event.type == YAML_SCALAR_EVENT) {
1116 value = (char *)event.data.scalar.value;
1117 if (strlen(value) &&
1118 strcmp(value, "groups") != 0) {
1120 fprintf(stdout, "%d) %s\n",
1125 done = (event.type == YAML_STREAM_END_EVENT);
1127 yaml_event_delete(&event);
1130 fprintf(stdout, "Total %d groups\n", i - 1);
1138 #define LST_NODES_TITLE "\tACTIVE\tBUSY\tDOWN\tUNKNOWN\tTOTAL\n"
1140 static int lst_yaml_groups(int nlflags, char *name, int states, bool print)
1142 yaml_emitter_t request;
1143 yaml_parser_t reply;
1148 sk = nl_socket_alloc();
1152 /* Setup reply parser to recieve Netlink packets */
1153 rc = yaml_parser_initialize(&reply);
1159 rc = yaml_parser_set_input_netlink(&reply, sk, false);
1163 /* Create Netlink emitter to send request to kernel */
1164 yaml_emitter_initialize(&request);
1165 rc = yaml_emitter_set_output_netlink(&request, sk,
1166 LNET_SELFTEST_GENL_NAME,
1167 LNET_SELFTEST_GENL_VERSION,
1168 LNET_SELFTEST_CMD_GROUPS,
1173 yaml_emitter_open(&request);
1174 yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
1175 rc = yaml_emitter_emit(&request, &event);
1179 yaml_mapping_start_event_initialize(&event, NULL,
1180 (yaml_char_t *)YAML_MAP_TAG,
1181 1, YAML_BLOCK_MAPPING_STYLE);
1182 rc = yaml_emitter_emit(&request, &event);
1186 yaml_scalar_event_initialize(&event, NULL,
1187 (yaml_char_t *)YAML_STR_TAG,
1188 (yaml_char_t *)"groups",
1189 strlen("groups"), 1, 0,
1190 YAML_PLAIN_SCALAR_STYLE);
1191 rc = yaml_emitter_emit(&request, &event);
1196 yaml_sequence_start_event_initialize(&event, NULL,
1197 (yaml_char_t *)YAML_SEQ_TAG,
1198 1, YAML_BLOCK_SEQUENCE_STYLE);
1199 rc = yaml_emitter_emit(&request, &event);
1203 yaml_mapping_start_event_initialize(&event, NULL,
1204 (yaml_char_t *)YAML_MAP_TAG,
1205 1, YAML_BLOCK_MAPPING_STYLE);
1206 rc = yaml_emitter_emit(&request, &event);
1210 yaml_scalar_event_initialize(&event, NULL,
1211 (yaml_char_t *)YAML_STR_TAG,
1212 (yaml_char_t *)name,
1214 YAML_PLAIN_SCALAR_STYLE);
1215 rc = yaml_emitter_emit(&request, &event);
1220 int max = ffs(LST_NODE_UNKNOWN) + 1, i;
1223 yaml_sequence_start_event_initialize(&event, NULL,
1224 (yaml_char_t *)YAML_SEQ_TAG,
1225 1, YAML_BLOCK_SEQUENCE_STYLE);
1226 rc = yaml_emitter_emit(&request, &event);
1231 for (i = 0; i < max; i++) {
1232 int mask = states & (1 << i);
1234 state = lst_node_state2str(mask);
1235 if (mask != LST_NODE_UNKNOWN && strcmp(state, "Unknown") == 0)
1238 yaml_mapping_start_event_initialize(&event, NULL,
1239 (yaml_char_t *)YAML_MAP_TAG,
1240 1, YAML_BLOCK_MAPPING_STYLE);
1241 rc = yaml_emitter_emit(&request, &event);
1245 yaml_scalar_event_initialize(&event, NULL,
1246 (yaml_char_t *)YAML_STR_TAG,
1247 (yaml_char_t *)"status",
1248 strlen("status"), 1, 0,
1249 YAML_PLAIN_SCALAR_STYLE);
1250 rc = yaml_emitter_emit(&request, &event);
1254 yaml_scalar_event_initialize(&event, NULL,
1255 (yaml_char_t *)YAML_STR_TAG,
1256 (yaml_char_t *)state,
1257 strlen(state), 1, 0,
1258 YAML_PLAIN_SCALAR_STYLE);
1259 rc = yaml_emitter_emit(&request, &event);
1263 yaml_mapping_end_event_initialize(&event);
1264 rc = yaml_emitter_emit(&request, &event);
1269 yaml_sequence_end_event_initialize(&event);
1270 rc = yaml_emitter_emit(&request, &event);
1274 yaml_scalar_event_initialize(&event, NULL,
1275 (yaml_char_t *)YAML_STR_TAG,
1278 YAML_PLAIN_SCALAR_STYLE);
1279 rc = yaml_emitter_emit(&request, &event);
1284 yaml_mapping_end_event_initialize(&event);
1285 rc = yaml_emitter_emit(&request, &event);
1289 yaml_sequence_end_event_initialize(&event);
1290 rc = yaml_emitter_emit(&request, &event);
1294 yaml_scalar_event_initialize(&event, NULL,
1295 (yaml_char_t *)YAML_STR_TAG,
1298 YAML_PLAIN_SCALAR_STYLE);
1299 rc = yaml_emitter_emit(&request, &event);
1303 yaml_mapping_end_event_initialize(&event);
1304 rc = yaml_emitter_emit(&request, &event);
1308 yaml_document_end_event_initialize(&event, 0);
1309 rc = yaml_emitter_emit(&request, &event);
1313 rc = yaml_emitter_close(&request);
1316 yaml_emitter_log_error(&request, stderr);
1317 yaml_emitter_delete(&request);
1321 yaml_emitter_delete(&request);
1323 /* display output */
1324 if (nlflags == NLM_F_DUMP)
1325 rc = lst_yaml_display_groups(&reply, name, states, print);
1328 yaml_parser_log_error(&reply, stderr, NULL);
1329 yaml_parser_delete(&reply);
1333 rc = rc == 1 ? 0 : -EINVAL;
1339 lst_ping_ioctl(char *str, int type, int timeout,
1340 int count, struct lnet_process_id *ids, struct list_head *head)
1342 struct lstio_debug_args args = { 0 };
1344 args.lstio_dbg_key = session_key;
1345 args.lstio_dbg_type = type;
1346 args.lstio_dbg_flags = 0;
1347 args.lstio_dbg_timeout = timeout;
1348 args.lstio_dbg_nmlen = (str == NULL) ? 0 : strlen(str);
1349 args.lstio_dbg_namep = str;
1350 args.lstio_dbg_count = count;
1351 args.lstio_dbg_idsp = ids;
1352 args.lstio_dbg_resultp = head;
1354 return lst_ioctl(LSTIO_DEBUG, &args, sizeof(args));
1358 lst_get_node_count(int type, char *str, int *countp,
1359 struct lnet_process_id **idspp)
1361 char buf[LST_NAME_SIZE];
1362 struct lstcon_test_batch_ent ent;
1363 struct lstcon_ndlist_ent *entp = &ent.tbe_cli_nle;
1369 case LST_OPC_SESSION:
1370 rc = lst_session_info_ioctl(buf, LST_NAME_SIZE,
1371 &key, &feats, &sid, entp);
1374 case LST_OPC_BATCHSRV:
1375 entp = &ent.tbe_srv_nle;
1376 case LST_OPC_BATCHCLI:
1377 rc = lst_info_batch_ioctl(str, 0, 0, &ent, NULL, NULL, NULL);
1381 rc = lst_yaml_groups(NLM_F_DUMP, NULL, 0, false);
1382 if (rc == -EOPNOTSUPP) {
1383 rc = lst_info_group_ioctl(str, entp, NULL, NULL, NULL);
1384 } else if (rc > 0) {
1385 entp->nle_nnode = rc;
1391 rc = lst_parse_nids(str, &entp->nle_nnode, idspp) < 0 ? -1 : 0;
1400 *countp = entp->nle_nnode;
1406 jt_lst_ping(int argc, char **argv)
1408 struct list_head head;
1409 struct lnet_process_id *ids = NULL;
1410 struct lstcon_rpc_ent *ent = NULL;
1420 static const struct option ping_opts[] = {
1421 { .name = "session", .has_arg = no_argument, .val = 's' },
1422 { .name = "server", .has_arg = no_argument, .val = 'v' },
1423 { .name = "batch", .has_arg = required_argument, .val = 'b' },
1424 { .name = "group", .has_arg = required_argument, .val = 'g' },
1425 { .name = "nodes", .has_arg = required_argument, .val = 'n' },
1426 { .name = "timeout", .has_arg = required_argument, .val = 't' },
1427 { .name = NULL, } };
1429 if (session_key == 0) {
1431 "Can't find env LST_SESSION or value is not valid\n");
1437 c = getopt_long(argc, argv, "g:b:n:t:sv", ping_opts, &optidx);
1443 type = LST_OPC_SESSION;
1447 type = LST_OPC_GROUP;
1452 type = LST_OPC_BATCHCLI;
1457 type = LST_OPC_NODES;
1462 timeout = atoi(optarg);
1470 lst_print_usage(argv[0]);
1475 if (type == 0 || timeout <= 0 || optind != argc) {
1476 lst_print_usage(argv[0]);
1480 if (type == LST_OPC_BATCHCLI && server)
1481 type = LST_OPC_BATCHSRV;
1483 rc = lst_get_node_count(type, str, &count, &ids);
1485 fprintf(stderr, "Failed to get count of nodes from %s: %s\n",
1486 (str == NULL) ? "session" : str, strerror(errno));
1490 INIT_LIST_HEAD(&head);
1492 rc = lst_alloc_rpcent(&head, count, LST_NAME_SIZE);
1494 fprintf(stderr, "Out of memory\n");
1499 fprintf(stdout, "Target %s is empty\n",
1500 (str == NULL) ? "session" : str);
1504 rc = lst_ping_ioctl(str, type, timeout, count, ids, &head);
1505 if (rc == -1) { /* local failure */
1506 lst_print_error("debug", "Failed to ping %s: %s\n",
1507 (str == NULL) ? "session" : str,
1513 /* ignore RPC errors and framwork errors */
1514 list_for_each_entry(ent, &head, rpe_link) {
1515 fprintf(stdout, "\t%s: %s [session: %s id: %s]\n",
1516 libcfs_id2str(ent->rpe_peer),
1517 lst_node_state2str(ent->rpe_state),
1518 (ent->rpe_state == LST_NODE_ACTIVE ||
1519 ent->rpe_state == LST_NODE_BUSY) ?
1520 (ent->rpe_rpc_errno == 0 ?
1521 &ent->rpe_payload[0] : "Unknown") :
1522 "<NULL>", libcfs_nid2str(ent->rpe_sid.ses_nid));
1526 lst_free_rpcent(&head);
1535 lst_add_nodes_ioctl(char *name, int count, struct lnet_process_id *ids,
1536 unsigned int *featp, struct list_head *resultp)
1538 struct lstio_group_nodes_args args = { 0 };
1540 args.lstio_grp_key = session_key;
1541 args.lstio_grp_nmlen = strlen(name);
1542 args.lstio_grp_namep = name;
1543 args.lstio_grp_count = count;
1544 args.lstio_grp_featp = featp;
1545 args.lstio_grp_idsp = ids;
1546 args.lstio_grp_resultp = resultp;
1548 return lst_ioctl(LSTIO_NODES_ADD, &args, sizeof(args));
1552 lst_del_group_ioctl(char *name)
1554 struct lstio_group_del_args args = { 0 };
1556 args.lstio_grp_key = session_key;
1557 args.lstio_grp_nmlen = strlen(name);
1558 args.lstio_grp_namep = name;
1560 return lst_ioctl(LSTIO_GROUP_DEL, &args, sizeof(args));
1564 lst_del_group(char *grp_name)
1568 rc = lst_del_group_ioctl(grp_name);
1570 fprintf(stdout, "Group is deleted\n");
1575 lst_print_error("group", "Failed to delete group: %s\n",
1580 fprintf(stderr, "Group is deleted with some errors\n");
1582 if (trans_stat.trs_rpc_errno != 0) {
1584 "[RPC] Failed to send %d end session RPCs: %s\n",
1585 lstcon_rpc_stat_failure(&trans_stat, 0),
1586 strerror(trans_stat.trs_rpc_errno));
1589 if (trans_stat.trs_fwk_errno != 0) {
1591 "[FWK] Failed to end session on %d nodes: %s\n",
1592 lstcon_sesop_stat_failure(&trans_stat, 0),
1593 strerror(trans_stat.trs_fwk_errno));
1600 lst_add_group_ioctl(char *name)
1602 struct lstio_group_add_args args = { 0 };
1604 args.lstio_grp_key = session_key;
1605 args.lstio_grp_nmlen = strlen(name);
1606 args.lstio_grp_namep = name;
1608 return lst_ioctl(LSTIO_GROUP_ADD, &args, sizeof(args));
1612 jt_lst_add_group(int argc, char **argv)
1614 struct list_head head;
1615 struct lnet_process_id *ids;
1617 unsigned int feats = session_features;
1621 bool nodes_added = false;
1623 if (session_key == 0) {
1625 "Can't find env LST_SESSION or value is not valid\n");
1630 lst_print_usage(argv[0]);
1635 if (strlen(name) >= LST_NAME_SIZE) {
1636 fprintf(stderr, "Name length is limited to %d\n",
1641 rc = lst_add_group_ioctl(name);
1643 lst_print_error("group", "Failed to add group %s: %s\n",
1644 name, strerror(errno));
1648 INIT_LIST_HEAD(&head);
1650 for (i = 2; i < argc; i++) {
1651 /* parse address list */
1652 rc = lst_parse_nids(argv[i], &count, &ids);
1654 fprintf(stderr, "Ignore invalid id list %s\n",
1662 rc = lst_alloc_rpcent(&head, count, 0);
1664 fprintf(stderr, "Out of memory\n");
1670 rc = lst_add_nodes_ioctl(name, count, ids, &feats, &head);
1677 fprintf(stdout, "%s are added to session\n", argv[i]);
1681 if ((feats & session_features) != session_features) {
1683 "Warning, this session will run with compatible mode because some test nodes might not understand these features: %x\n",
1684 (~feats & session_features));
1687 lst_free_rpcent(&head);
1691 /* The selftest kernel module expects that a group should
1692 * have at least one node, since it doesn't make sense for
1693 * an empty group to be added to a test.
1696 "No nodes added successfully, deleting group %s\n",
1698 rc = lst_del_group(name);
1701 "Failed to delete group %s. Group is empty.\n",
1710 lst_print_error("group", "Failed to add nodes %s: %s\n",
1711 argv[i], strerror(errno));
1714 if (trans_stat.trs_fwk_errno == EPROTO) {
1716 "test nodes might have different LST features, please disable some features by setting LST_FEATURES\n");
1719 lst_print_transerr(&head, "create session");
1722 lst_free_rpcent(&head);
1726 "No nodes added successfully, deleting group %s\n",
1728 if (lst_del_group(name) != 0) {
1730 "Failed to delete group %s. Group is empty.\n",
1739 jt_lst_del_group(int argc, char **argv)
1743 if (session_key == 0) {
1745 "Can't find env LST_SESSION or value is not valid\n");
1750 lst_print_usage(argv[0]);
1754 rc = lst_del_group(argv[1]);
1760 lst_update_group_ioctl(int opc, char *name, int clean, int count,
1761 struct lnet_process_id *ids, struct list_head *resultp)
1763 struct lstio_group_update_args args = { 0 };
1765 args.lstio_grp_key = session_key;
1766 args.lstio_grp_opc = opc;
1767 args.lstio_grp_args = clean;
1768 args.lstio_grp_nmlen = strlen(name);
1769 args.lstio_grp_namep = name;
1770 args.lstio_grp_count = count;
1771 args.lstio_grp_idsp = ids;
1772 args.lstio_grp_resultp = resultp;
1774 return lst_ioctl(LSTIO_GROUP_UPDATE, &args, sizeof(args));
1778 jt_lst_update_group(int argc, char **argv)
1780 struct list_head head;
1781 struct lnet_process_id *ids = NULL;
1791 static const struct option update_group_opts[] = {
1792 { .name = "refresh", .has_arg = no_argument, .val = 'f' },
1793 { .name = "clean", .has_arg = required_argument, .val = 'c' },
1794 { .name = "remove", .has_arg = required_argument, .val = 'r' },
1797 if (session_key == 0) {
1799 "Can't find env LST_SESSION or value is not valid\n");
1804 c = getopt_long(argc, argv, "fc:r:", update_group_opts,
1807 /* Detect the end of the options. */
1814 lst_print_usage(argv[0]);
1817 opc = LST_GROUP_REFRESH;
1822 lst_print_usage(argv[0]);
1825 opc = LST_GROUP_RMND;
1830 clean = lst_node_str2state(optarg);
1831 if (opc != 0 || clean <= 0) {
1832 lst_print_usage(argv[0]);
1835 opc = LST_GROUP_CLEAN;
1839 lst_print_usage(argv[0]);
1844 /* no OPC or group is specified */
1845 if (opc == 0 || optind != argc - 1) {
1846 lst_print_usage(argv[0]);
1852 INIT_LIST_HEAD(&head);
1854 if (opc == LST_GROUP_RMND || opc == LST_GROUP_REFRESH) {
1855 rc = lst_get_node_count(opc == LST_GROUP_RMND ? LST_OPC_NODES :
1857 opc == LST_GROUP_RMND ? str : grp,
1861 fprintf(stderr, "Can't get count of nodes from %s: %s\n",
1862 opc == LST_GROUP_RMND ? str : grp,
1867 rc = lst_alloc_rpcent(&head, count, 0);
1869 fprintf(stderr, "Out of memory\n");
1875 rc = lst_update_group_ioctl(opc, grp, clean, count, ids, &head);
1881 lst_free_rpcent(&head);
1886 lst_free_rpcent(&head);
1887 lst_print_error("group", "Failed to update group: %s\n",
1892 lst_print_transerr(&head, "Updating group");
1894 lst_free_rpcent(&head);
1900 lst_list_group_ioctl(int len, char *name, int idx)
1902 struct lstio_group_list_args args = { 0 };
1904 args.lstio_grp_key = session_key;
1905 args.lstio_grp_idx = idx;
1906 args.lstio_grp_nmlen = len;
1907 args.lstio_grp_namep = name;
1909 return lst_ioctl(LSTIO_GROUP_LIST, &args, sizeof(args));
1913 lst_info_group_ioctl(char *name, struct lstcon_ndlist_ent *gent,
1914 int *idx, int *count, struct lstcon_node_ent *dents)
1916 struct lstio_group_info_args args = { 0 };
1918 args.lstio_grp_key = session_key;
1919 args.lstio_grp_nmlen = strlen(name);
1920 args.lstio_grp_namep = name;
1921 args.lstio_grp_entp = gent;
1922 args.lstio_grp_idxp = idx;
1923 args.lstio_grp_ndentp = count;
1924 args.lstio_grp_dentsp = dents;
1926 return lst_ioctl(LSTIO_GROUP_INFO, &args, sizeof(args));
1930 lst_list_group_all(void)
1932 char name[LST_NAME_SIZE];
1935 /* no group is specified, list name of all groups */
1936 for (i = 0; ; i++) {
1937 rc = lst_list_group_ioctl(LST_NAME_SIZE, name, i);
1939 fprintf(stdout, "%d) %s\n", i + 1, name);
1943 if (errno == ENOENT)
1946 lst_print_error("group", "Failed to list group: %s\n",
1951 fprintf(stdout, "Total %d groups\n", i);
1957 jt_lst_list_group(int argc, char **argv)
1959 struct lstcon_ndlist_ent gent;
1960 struct lstcon_node_ent *dents;
1975 static const struct option list_group_opts[] = {
1976 { .name = "active", .has_arg = no_argument, .val = 'a' },
1977 { .name = "busy", .has_arg = no_argument, .val = 'b' },
1978 { .name = "down", .has_arg = no_argument, .val = 'd' },
1979 { .name = "unknown", .has_arg = no_argument, .val = 'u' },
1980 { .name = "all", .has_arg = no_argument, .val = 'l' },
1981 { .name = NULL, } };
1983 if (session_key == 0) {
1985 "Can't find env LST_SESSION or value is not valid\n");
1990 c = getopt_long(argc, argv, "abdul", list_group_opts, &optidx);
1996 verbose = active = 1;
1997 states |= LST_NODE_ACTIVE;
2002 states |= LST_NODE_BUSY;
2007 states |= LST_NODE_DOWN;
2011 verbose = unknown = 1;
2012 states |= LST_NODE_UNKNOWN;
2016 states |= LST_NODE_ACTIVE | LST_NODE_BUSY |
2017 LST_NODE_DOWN | LST_NODE_UNKNOWN;
2021 lst_print_usage(argv[0]);
2026 if (optind == argc) {
2027 rc = lst_yaml_groups(NLM_F_DUMP, NULL, 0, true);
2029 if (rc == -EOPNOTSUPP)
2034 for (i = optind; i < argc; i++) {
2035 rc = lst_yaml_groups(NLM_F_DUMP, argv[i], states,
2036 i == optind ? true : false);
2038 if (rc == -EOPNOTSUPP)
2046 if (optind == argc) {
2047 /* no group is specified, list name of all groups */
2048 rc = lst_list_group_all();
2054 fprintf(stdout, LST_NODES_TITLE);
2056 /* list nodes in specified groups */
2057 for (i = optind; i < argc; i++) {
2058 rc = lst_info_group_ioctl(argv[i], &gent, NULL, NULL, NULL);
2060 if (errno == ENOENT) {
2065 lst_print_error("group", "Failed to list group: %s\n",
2071 fprintf(stdout, "\t%d\t%d\t%d\t%d\t%d\t%s\n",
2072 gent.nle_nactive, gent.nle_nbusy,
2073 gent.nle_ndown, gent.nle_nunknown,
2074 gent.nle_nnode, argv[i]);
2078 fprintf(stdout, "Group [ %s ]\n", argv[i]);
2080 if (gent.nle_nnode == 0) {
2081 fprintf(stdout, "No nodes found [ %s ]\n", argv[i]);
2085 count = gent.nle_nnode;
2087 dents = malloc(count * sizeof(struct lstcon_node_ent));
2088 if (dents == NULL) {
2089 fprintf(stderr, "Failed to malloc: %s\n",
2095 rc = lst_info_group_ioctl(argv[i], &gent, &index, &count,
2098 lst_print_error("group", "Failed to list group: %s\n",
2104 for (j = 0, c = 0; j < count; j++) {
2106 ((active && dents[j].nde_state == LST_NODE_ACTIVE) ||
2107 (busy && dents[j].nde_state == LST_NODE_BUSY) ||
2108 (down && dents[j].nde_state == LST_NODE_DOWN) ||
2109 (unknown && dents[j].nde_state == LST_NODE_UNKNOWN))) {
2111 fprintf(stdout, "\t%s: %s\n",
2112 libcfs_id2str(dents[j].nde_id),
2113 lst_node_state2str(dents[j].nde_state));
2118 fprintf(stdout, "Total %d nodes [ %s ]\n", c, argv[i]);
2127 lst_stat_ioctl(char *name, int count, struct lnet_process_id *idsp,
2128 int timeout, struct list_head *resultp)
2130 struct lstio_stat_args args = { 0 };
2132 args.lstio_sta_key = session_key;
2133 args.lstio_sta_timeout = timeout;
2134 args.lstio_sta_nmlen = strlen(name);
2135 args.lstio_sta_namep = name;
2136 args.lstio_sta_count = count;
2137 args.lstio_sta_idsp = idsp;
2138 args.lstio_sta_resultp = resultp;
2140 return lst_ioctl(LSTIO_STAT_QUERY, &args, sizeof(args));
2144 struct list_head srp_link;
2147 struct lnet_process_id *srp_ids;
2148 struct list_head srp_result[2];
2149 } lst_stat_req_param_t;
2152 lst_stat_req_param_free(lst_stat_req_param_t *srp)
2156 for (i = 0; i < 2; i++)
2157 lst_free_rpcent(&srp->srp_result[i]);
2159 if (srp->srp_ids != NULL)
2166 lst_stat_req_param_alloc(char *name, lst_stat_req_param_t **srpp, int save_old)
2168 lst_stat_req_param_t *srp = NULL;
2169 int count = save_old ? 2 : 1;
2172 srp = malloc(sizeof(*srp));
2176 memset(srp, 0, sizeof(*srp));
2177 INIT_LIST_HEAD(&srp->srp_result[0]);
2178 INIT_LIST_HEAD(&srp->srp_result[1]);
2180 rc = lst_get_node_count(LST_OPC_GROUP, name, &srp->srp_count, NULL);
2181 if (rc != 0 && errno == ENOENT) {
2182 rc = lst_get_node_count(LST_OPC_NODES, name,
2183 &srp->srp_count, &srp->srp_ids);
2188 "Failed to get count of nodes from %s: %s\n",
2189 name, strerror(errno));
2190 lst_stat_req_param_free(srp);
2195 srp->srp_name = name;
2197 for (i = 0; i < count; i++) {
2198 rc = lst_alloc_rpcent(&srp->srp_result[i], srp->srp_count,
2199 sizeof(struct sfw_counters) +
2200 sizeof(struct srpc_counters) +
2201 sizeof(struct lnet_counters_common));
2203 fprintf(stderr, "Out of memory\n");
2213 lst_stat_req_param_free(srp);
2221 } lst_srpc_stat_result;
2223 #define LST_LNET_AVG 0
2224 #define LST_LNET_MIN 1
2225 #define LST_LNET_MAX 2
2228 float lnet_avg_sndrate;
2229 float lnet_min_sndrate;
2230 float lnet_max_sndrate;
2231 float lnet_total_sndrate;
2233 float lnet_avg_rcvrate;
2234 float lnet_min_rcvrate;
2235 float lnet_max_rcvrate;
2236 float lnet_total_rcvrate;
2238 float lnet_avg_sndperf;
2239 float lnet_min_sndperf;
2240 float lnet_max_sndperf;
2241 float lnet_total_sndperf;
2243 float lnet_avg_rcvperf;
2244 float lnet_min_rcvperf;
2245 float lnet_max_rcvperf;
2246 float lnet_total_rcvperf;
2248 int lnet_stat_count;
2249 } lst_lnet_stat_result_t;
2251 lst_lnet_stat_result_t lnet_stat_result;
2254 lst_lnet_stat_value(int bw, int send, int off)
2258 p = bw ? &lnet_stat_result.lnet_avg_sndperf :
2259 &lnet_stat_result.lnet_avg_sndrate;
2270 lst_cal_lnet_stat(float delta, struct lnet_counters_common *lnet_new,
2271 struct lnet_counters_common *lnet_old, int mbs)
2275 unsigned int unit_divisor;
2277 unit_divisor = (mbs) ? (1000 * 1000) : (1024 * 1024);
2278 perf = (float)(lnet_new->lcc_send_length -
2279 lnet_old->lcc_send_length) / unit_divisor / delta;
2280 lnet_stat_result.lnet_total_sndperf += perf;
2282 if (lnet_stat_result.lnet_min_sndperf > perf ||
2283 lnet_stat_result.lnet_min_sndperf == 0)
2284 lnet_stat_result.lnet_min_sndperf = perf;
2286 if (lnet_stat_result.lnet_max_sndperf < perf)
2287 lnet_stat_result.lnet_max_sndperf = perf;
2289 perf = (float)(lnet_new->lcc_recv_length -
2290 lnet_old->lcc_recv_length) / unit_divisor / delta;
2291 lnet_stat_result.lnet_total_rcvperf += perf;
2293 if (lnet_stat_result.lnet_min_rcvperf > perf ||
2294 lnet_stat_result.lnet_min_rcvperf == 0)
2295 lnet_stat_result.lnet_min_rcvperf = perf;
2297 if (lnet_stat_result.lnet_max_rcvperf < perf)
2298 lnet_stat_result.lnet_max_rcvperf = perf;
2300 rate = (lnet_new->lcc_send_count - lnet_old->lcc_send_count) / delta;
2301 lnet_stat_result.lnet_total_sndrate += rate;
2303 if (lnet_stat_result.lnet_min_sndrate > rate ||
2304 lnet_stat_result.lnet_min_sndrate == 0)
2305 lnet_stat_result.lnet_min_sndrate = rate;
2307 if (lnet_stat_result.lnet_max_sndrate < rate)
2308 lnet_stat_result.lnet_max_sndrate = rate;
2310 rate = (lnet_new->lcc_recv_count - lnet_old->lcc_recv_count) / delta;
2311 lnet_stat_result.lnet_total_rcvrate += rate;
2313 if (lnet_stat_result.lnet_min_rcvrate > rate ||
2314 lnet_stat_result.lnet_min_rcvrate == 0)
2315 lnet_stat_result.lnet_min_rcvrate = rate;
2317 if (lnet_stat_result.lnet_max_rcvrate < rate)
2318 lnet_stat_result.lnet_max_rcvrate = rate;
2320 lnet_stat_result.lnet_stat_count++;
2322 lnet_stat_result.lnet_avg_sndrate = lnet_stat_result.lnet_total_sndrate /
2323 lnet_stat_result.lnet_stat_count;
2324 lnet_stat_result.lnet_avg_rcvrate = lnet_stat_result.lnet_total_rcvrate /
2325 lnet_stat_result.lnet_stat_count;
2327 lnet_stat_result.lnet_avg_sndperf = lnet_stat_result.lnet_total_sndperf /
2328 lnet_stat_result.lnet_stat_count;
2329 lnet_stat_result.lnet_avg_rcvperf = lnet_stat_result.lnet_total_rcvperf /
2330 lnet_stat_result.lnet_stat_count;
2334 lst_print_lnet_stat(char *name, int bwrt, int rdwr, int type, int mbs)
2344 if (lnet_stat_result.lnet_stat_count == 0)
2347 units = (mbs) ? "MB/s " : "MiB/s ";
2349 if (bwrt == 1) /* bw only */
2352 if (bwrt == 2) /* rates only */
2355 if (rdwr == 1) /* recv only */
2358 if (rdwr == 2) /* send only */
2361 for (i = start1; i <= end1; i++) {
2362 fprintf(stdout, "[LNet %s of %s]\n",
2363 i == 0 ? "Rates" : "Bandwidth", name);
2365 for (j = start2; j <= end2; j++) {
2366 fprintf(stdout, "[%c] ", j == 0 ? 'R' : 'W');
2368 if ((type & 1) != 0) {
2369 fprintf(stdout, i == 0 ? "Avg: %-8.0f RPC/s " :
2371 lst_lnet_stat_value(i, j, 0), units);
2374 if ((type & 2) != 0) {
2375 fprintf(stdout, i == 0 ? "Min: %-8.0f RPC/s " :
2377 lst_lnet_stat_value(i, j, 1), units);
2380 if ((type & 4) != 0) {
2381 fprintf(stdout, i == 0 ? "Max: %-8.0f RPC/s" :
2383 lst_lnet_stat_value(i, j, 2), units);
2386 fprintf(stdout, "\n");
2392 lst_print_stat(char *name, struct list_head *resultp,
2393 int idx, int lnet, int bwrt, int rdwr, int type,
2396 struct list_head tmp[2];
2397 struct lstcon_rpc_ent *new;
2398 struct lstcon_rpc_ent *old;
2399 struct sfw_counters *sfwk_new;
2400 struct sfw_counters *sfwk_old;
2401 struct srpc_counters *srpc_new;
2402 struct srpc_counters *srpc_old;
2403 struct lnet_counters_common *lnet_new;
2404 struct lnet_counters_common *lnet_old;
2408 INIT_LIST_HEAD(&tmp[0]);
2409 INIT_LIST_HEAD(&tmp[1]);
2411 memset(&lnet_stat_result, 0, sizeof(lnet_stat_result));
2413 while (!list_empty(&resultp[idx])) {
2414 if (list_empty(&resultp[1 - idx])) {
2415 fprintf(stderr, "Group is changed, re-run stat\n");
2419 new = list_first_entry(&resultp[idx], struct lstcon_rpc_ent,
2421 old = list_first_entry(&resultp[1 - idx], struct lstcon_rpc_ent,
2424 /* first time get stats result, can't calculate diff */
2425 if (new->rpe_peer.nid == LNET_NID_ANY)
2428 if (new->rpe_peer.nid != old->rpe_peer.nid ||
2429 new->rpe_peer.pid != old->rpe_peer.pid) {
2430 /* Something wrong. i.e, somebody change the group */
2434 list_move_tail(&new->rpe_link, &tmp[idx]);
2436 list_move_tail(&old->rpe_link, &tmp[1 - idx]);
2438 if (new->rpe_rpc_errno != 0 || new->rpe_fwk_errno != 0 ||
2439 old->rpe_rpc_errno != 0 || old->rpe_fwk_errno != 0) {
2444 sfwk_new = (struct sfw_counters *)&new->rpe_payload[0];
2445 sfwk_old = (struct sfw_counters *)&old->rpe_payload[0];
2447 srpc_new = (struct srpc_counters *)((char *)sfwk_new +
2449 srpc_old = (struct srpc_counters *)((char *)sfwk_old +
2452 lnet_new = (struct lnet_counters_common *)((char *)srpc_new +
2454 lnet_old = (struct lnet_counters_common *)((char *)srpc_old +
2457 /* Prior to version 2.3, the running_ms was a counter for
2458 * the number of running tests. Since 2.3, running_ms is
2459 * changed to hold the millisecond since the start of
2460 * the work item. The rpe_stamp field was formerly used,
2461 * but is no longer. In 2.12 rpe_stamp was changed to
2462 * struct timespec64 and has nanosecond resolution, in
2463 * case it is needed in the future.
2465 delta = (float)(sfwk_new->running_ms -
2466 sfwk_old->running_ms) / 1000;
2468 if (!lnet) /* TODO */
2471 lst_cal_lnet_stat(delta, lnet_new, lnet_old, mbs);
2474 list_splice(&tmp[idx], &resultp[idx]);
2475 list_splice(&tmp[1 - idx], &resultp[1 - idx]);
2478 fprintf(stdout, "Failed to stat on %d nodes\n", errcount);
2480 if (!lnet) /* TODO */
2483 lst_print_lnet_stat(name, bwrt, rdwr, type, mbs);
2487 jt_lst_stat(int argc, char **argv)
2489 struct list_head head;
2490 lst_stat_req_param_t *srp;
2493 int timeout = 5; /* default timeout, 5 sec */
2494 int delay = 5; /* default delay, 5 sec */
2495 int count = -1; /* run forever */
2496 int lnet = 1; /* lnet stat by default */
2501 int mbs = 0; /* report as MB/s */
2504 static const struct option stat_opts[] = {
2505 { .name = "timeout", .has_arg = required_argument, .val = 't' },
2506 { .name = "delay", .has_arg = required_argument, .val = 'd' },
2507 { .name = "count", .has_arg = required_argument, .val = 'o' },
2508 { .name = "lnet", .has_arg = no_argument, .val = 'l' },
2509 { .name = "rpc", .has_arg = no_argument, .val = 'c' },
2510 { .name = "bw", .has_arg = no_argument, .val = 'b' },
2511 { .name = "rate", .has_arg = no_argument, .val = 'a' },
2512 { .name = "read", .has_arg = no_argument, .val = 'r' },
2513 { .name = "write", .has_arg = no_argument, .val = 'w' },
2514 { .name = "avg", .has_arg = no_argument, .val = 'g' },
2515 { .name = "min", .has_arg = no_argument, .val = 'n' },
2516 { .name = "max", .has_arg = no_argument, .val = 'x' },
2517 { .name = "mbs", .has_arg = no_argument, .val = 'm' },
2520 if (session_key == 0) {
2522 "Can't find env LST_SESSION or value is not valid\n");
2527 c = getopt_long(argc, argv, "t:d:lcbarwgnxm", stat_opts,
2535 timeout = atoi(optarg);
2538 delay = atoi(optarg);
2541 count = atoi(optarg);
2587 lst_print_usage(argv[0]);
2592 if (optind == argc) {
2593 lst_print_usage(argv[0]);
2597 if (timeout <= 0 || delay <= 0) {
2598 fprintf(stderr, "Invalid timeout or delay value\n");
2603 fprintf(stderr, "Invalid count value\n");
2607 /* extra count to get first data point */
2611 INIT_LIST_HEAD(&head);
2613 while (optind < argc) {
2614 rc = lst_stat_req_param_alloc(argv[optind++], &srp, 1);
2618 list_add_tail(&srp->srp_link, &head);
2622 time_t now = time(NULL);
2624 if (now - last < delay) {
2625 sleep(delay - now + last);
2630 list_for_each_entry(srp, &head, srp_link) {
2631 rc = lst_stat_ioctl(srp->srp_name, srp->srp_count,
2632 srp->srp_ids, timeout,
2633 &srp->srp_result[idx]);
2635 lst_print_error("stat",
2636 "Failed to stat %s: %s\n",
2637 srp->srp_name, strerror(errno));
2641 lst_print_stat(srp->srp_name, srp->srp_result,
2642 idx, lnet, bwrt, rdwr, type, mbs);
2644 lst_reset_rpcent(&srp->srp_result[1 - idx]);
2651 } while (count == -1 || count > 0);
2654 while (!list_empty(&head)) {
2655 srp = list_first_entry(&head, lst_stat_req_param_t, srp_link);
2657 list_del(&srp->srp_link);
2658 lst_stat_req_param_free(srp);
2665 jt_lst_show_error(int argc, char **argv)
2667 struct list_head head;
2668 lst_stat_req_param_t *srp;
2669 struct lstcon_rpc_ent *ent;
2670 struct sfw_counters *sfwk;
2671 struct srpc_counters *srpc;
2677 static const struct option show_error_opts[] = {
2678 { .name = "session", .has_arg = no_argument, .val = 's' },
2679 { .name = NULL, } };
2681 if (session_key == 0) {
2683 "Can't find env LST_SESSION or value is not valid\n");
2688 c = getopt_long(argc, argv, "s", show_error_opts, &optidx);
2699 lst_print_usage(argv[0]);
2704 if (optind == argc) {
2705 lst_print_usage(argv[0]);
2709 INIT_LIST_HEAD(&head);
2711 while (optind < argc) {
2712 rc = lst_stat_req_param_alloc(argv[optind++], &srp, 0);
2716 list_add_tail(&srp->srp_link, &head);
2719 list_for_each_entry(srp, &head, srp_link) {
2720 rc = lst_stat_ioctl(srp->srp_name, srp->srp_count,
2721 srp->srp_ids, 10, &srp->srp_result[0]);
2724 lst_print_error(srp->srp_name,
2725 "Failed to show errors of %s: %s\n",
2726 srp->srp_name, strerror(errno));
2730 fprintf(stdout, "%s:\n", srp->srp_name);
2734 list_for_each_entry(ent, &srp->srp_result[0], rpe_link) {
2735 if (ent->rpe_rpc_errno != 0) {
2738 "RPC failure, can't show error on %s\n",
2739 libcfs_id2str(ent->rpe_peer));
2743 if (ent->rpe_fwk_errno != 0) {
2746 "Framework failure, can't show error on %s\n",
2747 libcfs_id2str(ent->rpe_peer));
2751 sfwk = (struct sfw_counters *)&ent->rpe_payload[0];
2752 srpc = (struct srpc_counters *)((char *)sfwk +
2755 if (srpc->errors == 0 &&
2756 sfwk->brw_errors == 0 && sfwk->ping_errors == 0)
2760 sfwk->brw_errors == 0 && sfwk->ping_errors == 0)
2766 "%s: [Session %d brw errors, %d ping errors]%c",
2767 libcfs_id2str(ent->rpe_peer),
2768 sfwk->brw_errors, sfwk->ping_errors,
2769 show_rpc ? ' ' : '\n');
2775 "[RPC: %d errors, %d dropped, %d expired]\n",
2776 srpc->errors, srpc->rpcs_dropped,
2777 srpc->rpcs_expired);
2780 fprintf(stdout, "Total %d error nodes in %s\n", ecount,
2784 while (!list_empty(&head)) {
2785 srp = list_first_entry(&head, lst_stat_req_param_t, srp_link);
2787 list_del(&srp->srp_link);
2788 lst_stat_req_param_free(srp);
2795 lst_add_batch_ioctl(char *name)
2797 struct lstio_batch_add_args args = { 0 };
2799 args.lstio_bat_key = session_key;
2800 args.lstio_bat_nmlen = strlen(name);
2801 args.lstio_bat_namep = name;
2803 return lst_ioctl(LSTIO_BATCH_ADD, &args, sizeof(args));
2807 jt_lst_add_batch(int argc, char **argv)
2812 if (session_key == 0) {
2814 "Can't find env LST_SESSION or value is not valid\n");
2819 lst_print_usage(argv[0]);
2824 if (strlen(name) >= LST_NAME_SIZE) {
2825 fprintf(stderr, "Name length is limited to %d\n",
2830 rc = lst_add_batch_ioctl(name);
2834 lst_print_error("batch", "Failed to create batch: %s\n",
2841 lst_start_batch_ioctl(char *name, int timeout, struct list_head *resultp)
2843 struct lstio_batch_run_args args = { 0 };
2845 args.lstio_bat_key = session_key;
2846 args.lstio_bat_timeout = timeout;
2847 args.lstio_bat_nmlen = strlen(name);
2848 args.lstio_bat_namep = name;
2849 args.lstio_bat_resultp = resultp;
2851 return lst_ioctl(LSTIO_BATCH_START, &args, sizeof(args));
2855 jt_lst_start_batch(int argc, char **argv)
2857 struct list_head head;
2865 static const struct option start_batch_opts[] = {
2866 { .name = "timeout", .has_arg = required_argument, .val = 't' },
2869 if (session_key == 0) {
2871 "Can't find env LST_SESSION or value is not valid\n");
2876 c = getopt_long(argc, argv, "t:",
2877 start_batch_opts, &optidx);
2879 /* Detect the end of the options. */
2885 timeout = atoi(optarg);
2888 lst_print_usage(argv[0]);
2893 if (optind == argc) {
2894 batch = LST_DEFAULT_BATCH;
2896 } else if (optind == argc - 1) {
2897 batch = argv[optind];
2900 lst_print_usage(argv[0]);
2904 rc = lst_get_node_count(LST_OPC_BATCHCLI, batch, &count, NULL);
2906 fprintf(stderr, "Failed to get count of nodes from %s: %s\n",
2907 batch, strerror(errno));
2911 INIT_LIST_HEAD(&head);
2913 rc = lst_alloc_rpcent(&head, count, 0);
2915 fprintf(stderr, "Out of memory\n");
2919 rc = lst_start_batch_ioctl(batch, timeout, &head);
2922 fprintf(stdout, "%s is running now\n", batch);
2923 lst_free_rpcent(&head);
2928 lst_print_error("batch", "Failed to start batch: %s\n",
2930 lst_free_rpcent(&head);
2934 lst_print_transerr(&head, "Run batch");
2936 lst_free_rpcent(&head);
2942 lst_stop_batch_ioctl(char *name, int force, struct list_head *resultp)
2944 struct lstio_batch_stop_args args = { 0 };
2946 args.lstio_bat_key = session_key;
2947 args.lstio_bat_force = force;
2948 args.lstio_bat_nmlen = strlen(name);
2949 args.lstio_bat_namep = name;
2950 args.lstio_bat_resultp = resultp;
2952 return lst_ioctl(LSTIO_BATCH_STOP, &args, sizeof(args));
2956 jt_lst_stop_batch(int argc, char **argv)
2958 struct list_head head;
2965 static const struct option stop_batch_opts[] = {
2966 { .name = "force", .has_arg = no_argument, .val = 'f' },
2969 if (session_key == 0) {
2971 "Can't find env LST_SESSION or value is not valid\n");
2976 c = getopt_long(argc, argv, "f", stop_batch_opts, &optidx);
2977 /* Detect the end of the options. */
2986 lst_print_usage(argv[0]);
2991 if (optind == argc) {
2992 batch = LST_DEFAULT_BATCH;
2994 } else if (optind == argc - 1) {
2995 batch = argv[optind];
2998 lst_print_usage(argv[0]);
3002 rc = lst_get_node_count(LST_OPC_BATCHCLI, batch, &count, NULL);
3004 fprintf(stderr, "Failed to get count of nodes from %s: %s\n",
3005 batch, strerror(errno));
3009 INIT_LIST_HEAD(&head);
3011 rc = lst_alloc_rpcent(&head, count, 0);
3013 fprintf(stderr, "Out of memory\n");
3017 rc = lst_stop_batch_ioctl(batch, force, &head);
3022 lst_reset_rpcent(&head);
3024 rc = lst_query_batch_ioctl(batch, 0, 0, 30, &head);
3028 if (lstcon_tsbqry_stat_run(&trans_stat, 0) == 0 &&
3029 lstcon_tsbqry_stat_failure(&trans_stat, 0) == 0)
3032 fprintf(stdout, "%d batch in stopping\n",
3033 lstcon_tsbqry_stat_run(&trans_stat, 0));
3037 fprintf(stdout, "Batch is stopped\n");
3038 lst_free_rpcent(&head);
3043 lst_print_error("batch", "Failed to stop batch: %s\n",
3045 lst_free_rpcent(&head);
3049 lst_print_transerr(&head, "stop batch");
3051 lst_free_rpcent(&head);
3057 lst_list_batch_ioctl(int len, char *name, int index)
3059 struct lstio_batch_list_args args = { 0 };
3061 args.lstio_bat_key = session_key;
3062 args.lstio_bat_idx = index;
3063 args.lstio_bat_nmlen = len;
3064 args.lstio_bat_namep = name;
3066 return lst_ioctl(LSTIO_BATCH_LIST, &args, sizeof(args));
3070 lst_info_batch_ioctl(char *batch, int test, int server,
3071 struct lstcon_test_batch_ent *entp, int *idxp,
3072 int *ndentp, struct lstcon_node_ent *dentsp)
3074 struct lstio_batch_info_args args = { 0 };
3076 args.lstio_bat_key = session_key;
3077 args.lstio_bat_nmlen = strlen(batch);
3078 args.lstio_bat_namep = batch;
3079 args.lstio_bat_server = server;
3080 args.lstio_bat_testidx = test;
3081 args.lstio_bat_entp = entp;
3082 args.lstio_bat_idxp = idxp;
3083 args.lstio_bat_ndentp = ndentp;
3084 args.lstio_bat_dentsp = dentsp;
3086 return lst_ioctl(LSTIO_BATCH_INFO, &args, sizeof(args));
3090 lst_list_batch_all(void)
3092 char name[LST_NAME_SIZE];
3095 for (i = 0; ; i++) {
3096 rc = lst_list_batch_ioctl(LST_NAME_SIZE, name, i);
3098 fprintf(stdout, "%d) %s\n", i + 1, name);
3102 if (errno == ENOENT)
3105 lst_print_error("batch", "Failed to list batch: %s\n",
3110 fprintf(stdout, "Total %d batches\n", i);
3116 lst_list_tsb_nodes(char *batch, int test, int server,
3117 int count, int active, int invalid)
3119 struct lstcon_node_ent *dents;
3126 /* verbose list, show nodes in batch or test */
3127 dents = malloc(count * sizeof(struct lstcon_node_ent));
3128 if (dents == NULL) {
3129 fprintf(stdout, "Can't allocate memory\n");
3133 rc = lst_info_batch_ioctl(batch, test, server,
3134 NULL, &index, &count, dents);
3137 lst_print_error((test > 0) ? "test" : "batch",
3138 (test > 0) ? "Failed to query test: %s\n" :
3139 "Failed to query batch: %s\n",
3144 for (i = 0, c = 0; i < count; i++) {
3145 if ((!active && dents[i].nde_state == LST_NODE_ACTIVE) ||
3146 (!invalid && (dents[i].nde_state == LST_NODE_BUSY ||
3147 dents[i].nde_state == LST_NODE_DOWN ||
3148 dents[i].nde_state == LST_NODE_UNKNOWN)))
3151 fprintf(stdout, "\t%s: %s\n",
3152 libcfs_id2str(dents[i].nde_id),
3153 lst_node_state2str(dents[i].nde_state));
3157 fprintf(stdout, "Total %d nodes\n", c);
3164 jt_lst_list_batch(int argc, char **argv)
3166 struct lstcon_test_batch_ent ent;
3169 int verbose = 0; /* list nodes in batch or test */
3178 static const struct option list_batch_opts[] = {
3179 { .name = "test", .has_arg = required_argument, .val = 't' },
3180 { .name = "invalid", .has_arg = no_argument, .val = 'i' },
3181 { .name = "active", .has_arg = no_argument, .val = 'a' },
3182 { .name = "all", .has_arg = no_argument, .val = 'l' },
3183 { .name = "server", .has_arg = no_argument, .val = 's' },
3184 { .name = NULL, } };
3186 if (session_key == 0) {
3188 "Can't find env LST_SESSION or value is not valid\n");
3193 c = getopt_long(argc, argv, "ailst:", list_batch_opts, &optidx);
3199 verbose = active = 1;
3202 verbose = invalid = 1;
3205 verbose = active = invalid = 1;
3211 test = atoi(optarg);
3215 lst_print_usage(argv[0]);
3220 if (optind == argc) {
3221 /* list all batches */
3222 rc = lst_list_batch_all();
3226 if (ntest == 1 && test <= 0) {
3227 fprintf(stderr, "Invalid test id, test id starts from 1\n");
3231 if (optind != argc - 1) {
3232 lst_print_usage(argv[0]);
3236 batch = argv[optind];
3239 /* show detail of specified batch or test */
3240 rc = lst_info_batch_ioctl(batch, test, server, &ent, NULL, NULL, NULL);
3242 lst_print_error((test > 0) ? "test" : "batch",
3243 (test > 0) ? "Failed to query test: %s\n" :
3244 "Failed to query batch: %s\n",
3250 /* list nodes in test or batch */
3251 rc = lst_list_tsb_nodes(batch, test, server,
3252 server ? ent.tbe_srv_nle.nle_nnode :
3253 ent.tbe_cli_nle.nle_nnode,
3258 /* only show number of hosts in batch or test */
3260 fprintf(stdout, "Batch: %s Tests: %d State: %d\n",
3261 batch, ent.u.tbe_batch.bae_ntest,
3262 ent.u.tbe_batch.bae_state);
3263 ntest = ent.u.tbe_batch.bae_ntest;
3264 test = 1; /* starting from test 1 */
3267 "\tTest %d(%s) (loop: %d, concurrency: %d)\n",
3268 test, lst_test_type2name(ent.u.tbe_test.tse_type),
3269 ent.u.tbe_test.tse_loop,
3270 ent.u.tbe_test.tse_concur);
3275 fprintf(stdout, LST_NODES_TITLE);
3276 fprintf(stdout, "client\t%d\t%d\t%d\t%d\t%d\n"
3277 "server\t%d\t%d\t%d\t%d\t%d\n",
3278 ent.tbe_cli_nle.nle_nactive,
3279 ent.tbe_cli_nle.nle_nbusy,
3280 ent.tbe_cli_nle.nle_ndown,
3281 ent.tbe_cli_nle.nle_nunknown,
3282 ent.tbe_cli_nle.nle_nnode,
3283 ent.tbe_srv_nle.nle_nactive,
3284 ent.tbe_srv_nle.nle_nbusy,
3285 ent.tbe_srv_nle.nle_ndown,
3286 ent.tbe_srv_nle.nle_nunknown,
3287 ent.tbe_srv_nle.nle_nnode);
3296 lst_query_batch_ioctl(char *batch, int test, int server,
3297 int timeout, struct list_head *head)
3299 struct lstio_batch_query_args args = { 0 };
3301 args.lstio_bat_key = session_key;
3302 args.lstio_bat_testidx = test;
3303 args.lstio_bat_client = !(server);
3304 args.lstio_bat_timeout = timeout;
3305 args.lstio_bat_nmlen = strlen(batch);
3306 args.lstio_bat_namep = batch;
3307 args.lstio_bat_resultp = head;
3309 return lst_ioctl(LSTIO_BATCH_QUERY, &args, sizeof(args));
3313 lst_print_tsb_verbose(struct list_head *head, int active, int idle, int error)
3315 struct lstcon_rpc_ent *ent;
3317 list_for_each_entry(ent, head, rpe_link) {
3318 if (ent->rpe_priv[0] == 0 && active)
3321 if (ent->rpe_priv[0] != 0 && idle)
3324 if (ent->rpe_fwk_errno == 0 && error)
3327 fprintf(stdout, "%s [%s]: %s\n",
3328 libcfs_id2str(ent->rpe_peer),
3329 lst_node_state2str(ent->rpe_state),
3330 ent->rpe_rpc_errno != 0 ?
3331 strerror(ent->rpe_rpc_errno) :
3332 (ent->rpe_priv[0] > 0 ? "Running" : "Idle"));
3337 jt_lst_query_batch(int argc, char **argv)
3339 struct lstcon_test_batch_ent ent;
3340 struct list_head head;
3346 int timeout = 5; /* default 5 seconds */
3347 int delay = 5; /* default 5 seconds */
3348 int loop = 1; /* default 1 loop */
3358 static const struct option query_batch_opts[] = {
3359 { .name = "timeout", .has_arg = required_argument, .val = 'o' },
3360 { .name = "delay", .has_arg = required_argument, .val = 'd' },
3361 { .name = "loop", .has_arg = required_argument, .val = 'c' },
3362 { .name = "test", .has_arg = required_argument, .val = 't' },
3363 { .name = "server", .has_arg = no_argument, .val = 's' },
3364 { .name = "active", .has_arg = no_argument, .val = 'a' },
3365 { .name = "idle", .has_arg = no_argument, .val = 'i' },
3366 { .name = "error", .has_arg = no_argument, .val = 'e' },
3367 { .name = "all", .has_arg = no_argument, .val = 'l' },
3368 { .name = NULL, } };
3370 if (session_key == 0) {
3372 "Can't find env LST_SESSION or value is not valid\n");
3377 c = getopt_long(argc, argv, "o:d:c:t:saiel",
3378 query_batch_opts, &optidx);
3380 /* Detect the end of the options. */
3386 timeout = atoi(optarg);
3389 delay = atoi(optarg);
3392 loop = atoi(optarg);
3395 test = atoi(optarg);
3401 active = verbose = 1;
3407 error = verbose = 1;
3413 lst_print_usage(argv[0]);
3418 if (test < 0 || timeout <= 0 || delay <= 0 || loop <= 0) {
3419 lst_print_usage(argv[0]);
3423 if (optind == argc) {
3424 batch = LST_DEFAULT_BATCH;
3425 } else if (optind == argc - 1) {
3426 batch = argv[optind];
3428 lst_print_usage(argv[0]);
3433 INIT_LIST_HEAD(&head);
3436 rc = lst_info_batch_ioctl(batch, test, server,
3437 &ent, NULL, NULL, NULL);
3439 fprintf(stderr, "Failed to query %s [%d]: %s\n",
3440 batch, test, strerror(errno));
3444 count = server ? ent.tbe_srv_nle.nle_nnode :
3445 ent.tbe_cli_nle.nle_nnode;
3447 fprintf(stdout, "Batch or test is empty\n");
3452 rc = lst_alloc_rpcent(&head, count, 0);
3454 fprintf(stderr, "Out of memory\n");
3458 for (i = 0; i < loop; i++) {
3459 time_t now = time(NULL);
3461 if (now - last < delay) {
3462 sleep(delay - now + last);
3468 rc = lst_query_batch_ioctl(batch, test, server, timeout, &head);
3470 fprintf(stderr, "Failed to query batch: %s\n",
3477 lst_print_tsb_verbose(&head, active, idle, error);
3481 fprintf(stdout, "%s [%d] ", batch, test);
3483 if (lstcon_rpc_stat_failure(&trans_stat, 0) != 0) {
3484 fprintf(stdout, "%d of %d nodes are unknown, ",
3485 lstcon_rpc_stat_failure(&trans_stat, 0),
3486 lstcon_rpc_stat_total(&trans_stat, 0));
3489 if (lstcon_rpc_stat_failure(&trans_stat, 0) == 0 &&
3490 lstcon_tsbqry_stat_run(&trans_stat, 0) == 0 &&
3491 lstcon_tsbqry_stat_failure(&trans_stat, 0) == 0) {
3492 fprintf(stdout, "is stopped\n");
3496 if (lstcon_rpc_stat_failure(&trans_stat, 0) == 0 &&
3497 lstcon_tsbqry_stat_idle(&trans_stat, 0) == 0 &&
3498 lstcon_tsbqry_stat_failure(&trans_stat, 0) == 0) {
3499 fprintf(stdout, "is running\n");
3503 fprintf(stdout, "stopped: %d , running: %d, failed: %d\n",
3504 lstcon_tsbqry_stat_idle(&trans_stat, 0),
3505 lstcon_tsbqry_stat_run(&trans_stat, 0),
3506 lstcon_tsbqry_stat_failure(&trans_stat, 0));
3509 lst_free_rpcent(&head);
3515 lst_parse_distribute(char *dstr, int *dist, int *span)
3521 dstr = strchr(dstr, ':');
3525 *span = atoi(dstr + 1);
3533 lst_get_bulk_param(int argc, char **argv, struct lst_test_bulk_param *bulk)
3540 bulk->blk_size = 4096;
3541 bulk->blk_opc = LST_BRW_READ;
3542 bulk->blk_flags = LST_BRW_CHECK_NONE;
3543 bulk->blk_srv_off = bulk->blk_cli_off = 0;
3546 if (strcasestr(argv[i], "check=") == argv[i] ||
3547 strcasestr(argv[i], "c=") == argv[i]) {
3548 tok = strchr(argv[i], '=') + 1;
3550 if (strcasecmp(tok, "full") == 0) {
3551 bulk->blk_flags = LST_BRW_CHECK_FULL;
3552 } else if (strcasecmp(tok, "simple") == 0) {
3553 bulk->blk_flags = LST_BRW_CHECK_SIMPLE;
3555 fprintf(stderr, "Unknow flag %s\n", tok);
3559 } else if (strcasestr(argv[i], "size=") == argv[i] ||
3560 strcasestr(argv[i], "s=") == argv[i]) {
3561 tok = strchr(argv[i], '=') + 1;
3563 bulk->blk_size = strtol(tok, &end, 0);
3564 if (bulk->blk_size <= 0) {
3565 fprintf(stderr, "Invalid size %s\n", tok);
3572 if (*end == 'k' || *end == 'K')
3573 bulk->blk_size *= 1024;
3574 else if (*end == 'm' || *end == 'M')
3575 bulk->blk_size *= 1024 * 1024;
3577 if (bulk->blk_size > LNET_MTU) {
3578 fprintf(stderr, "Size exceed limitation: %d bytes\n",
3583 } else if (strcasestr(argv[i], "off=") == argv[i]) {
3586 tok = strchr(argv[i], '=') + 1;
3588 off = strtol(tok, &end, 0);
3589 /* NB: align with sizeof(__u64) to simplify page
3590 * checking implementation
3592 if (off < 0 || off % sizeof(__u64) != 0) {
3594 "Invalid offset %s/%d, it should be postive value and multiple of %d\n",
3595 tok, off, (int)sizeof(__u64));
3599 /* NB: blk_srv_off is reserved so far */
3600 bulk->blk_cli_off = bulk->blk_srv_off = off;
3604 } else if (strcasecmp(argv[i], "read") == 0 ||
3605 strcasecmp(argv[i], "r") == 0) {
3606 bulk->blk_opc = LST_BRW_READ;
3608 } else if (strcasecmp(argv[i], "write") == 0 ||
3609 strcasecmp(argv[i], "w") == 0) {
3610 bulk->blk_opc = LST_BRW_WRITE;
3613 fprintf(stderr, "Unknow parameter: %s\n", argv[i]);
3624 lst_get_test_param(char *test, int argc, char **argv, void **param, int *plen)
3626 struct lst_test_bulk_param *bulk = NULL;
3627 struct lst_test_ping_param *ping = NULL;
3630 type = lst_test_name2type(test);
3632 fprintf(stderr, "Unknow test name %s\n", test);
3638 /* unused but needs for kernel part */
3639 ping = malloc(sizeof(*ping));
3641 fprintf(stderr, "Out of memory\n");
3644 memset(ping, 0, sizeof(*ping));
3647 *plen = sizeof(*ping);
3652 bulk = malloc(sizeof(*bulk));
3654 fprintf(stderr, "Out of memory\n");
3658 memset(bulk, 0, sizeof(*bulk));
3660 if (lst_get_bulk_param(argc, argv, bulk) != 0) {
3665 *plen = sizeof(*bulk);
3671 /* TODO: parse more parameter */
3676 lst_add_test_ioctl(char *batch, int type, int loop, int concur,
3677 int dist, int span, char *sgrp, char *dgrp,
3678 void *param, int plen, int *retp, struct list_head *resultp)
3680 struct lstio_test_args args = { 0 };
3682 args.lstio_tes_key = session_key;
3683 args.lstio_tes_bat_nmlen = strlen(batch);
3684 args.lstio_tes_bat_name = batch;
3685 args.lstio_tes_type = type;
3686 args.lstio_tes_oneside = 0;
3687 args.lstio_tes_loop = loop;
3688 args.lstio_tes_concur = concur;
3689 args.lstio_tes_dist = dist;
3690 args.lstio_tes_span = span;
3691 args.lstio_tes_sgrp_nmlen = strlen(sgrp);
3692 args.lstio_tes_sgrp_name = sgrp;
3693 args.lstio_tes_dgrp_nmlen = strlen(dgrp);
3694 args.lstio_tes_dgrp_name = dgrp;
3695 args.lstio_tes_param_len = plen;
3696 args.lstio_tes_param = param;
3697 args.lstio_tes_retp = retp;
3698 args.lstio_tes_resultp = resultp;
3700 return lst_ioctl(LSTIO_TEST_ADD, &args, sizeof(args));
3704 jt_lst_add_test(int argc, char **argv)
3706 struct list_head head;
3726 static const struct option add_test_opts[] = {
3727 { .name = "batch", .has_arg = required_argument, .val = 'b' },
3728 { .name = "concurrency", .has_arg = required_argument, .val = 'c' },
3729 { .name = "distribute", .has_arg = required_argument, .val = 'd' },
3730 { .name = "from", .has_arg = required_argument, .val = 'f' },
3731 { .name = "to", .has_arg = required_argument, .val = 't' },
3732 { .name = "loop", .has_arg = required_argument, .val = 'l' },
3735 if (session_key == 0) {
3737 "Can't find env LST_SESSION or value is not valid\n");
3742 c = getopt_long(argc, argv, "b:c:d:f:l:t:",
3743 add_test_opts, &optidx);
3745 /* Detect the end of the options. */
3754 concur = atoi(optarg);
3763 loop = atoi(optarg);
3769 lst_print_usage(argv[0]);
3774 if (optind == argc || from == NULL || to == NULL) {
3775 lst_print_usage(argv[0]);
3779 if (concur <= 0 || concur > LST_MAX_CONCUR) {
3780 fprintf(stderr, "Invalid concurrency of test: %d\n", concur);
3785 batch = LST_DEFAULT_BATCH;
3788 rc = lst_parse_distribute(dstr, &dist, &span);
3790 fprintf(stderr, "Invalid distribution: %s\n", dstr);
3795 test = argv[optind++];
3800 type = lst_get_test_param(test, argc, argv, ¶m, &plen);
3802 fprintf(stderr, "Failed to add test (%s)\n", test);
3806 INIT_LIST_HEAD(&head);
3808 rc = lst_get_node_count(LST_OPC_GROUP, from, &fcount, NULL);
3810 fprintf(stderr, "Can't get count of nodes from %s: %s\n",
3811 from, strerror(errno));
3815 rc = lst_get_node_count(LST_OPC_GROUP, to, &tcount, NULL);
3817 fprintf(stderr, "Can't get count of nodes from %s: %s\n",
3818 to, strerror(errno));
3822 rc = lst_alloc_rpcent(&head, fcount > tcount ? fcount : tcount, 0);
3824 fprintf(stderr, "Out of memory\n");
3828 rc = lst_add_test_ioctl(batch, type, loop, concur,
3829 dist, span, from, to, param, plen, &ret, &head);
3832 fprintf(stdout, "Test was added successfully\n");
3835 "Server group contains userland test nodes, old version of tcplnd can't accept connection request\n");
3842 lst_print_error("test", "Failed to add test: %s\n",
3847 lst_print_transerr(&head, "add test");
3849 lst_free_rpcent(&head);
3857 static command_t lst_cmdlist[] = {
3858 {"new_session", jt_lst_new_session, NULL,
3859 "Usage: lst new_session [--timeout TIME] [--force] [NAME]"},
3860 {"end_session", jt_lst_end_session, NULL,
3861 "Usage: lst end_session" },
3862 {"show_session", jt_lst_show_session, NULL,
3863 "Usage: lst show_session" },
3864 {"ping", jt_lst_ping, NULL,
3865 "Usage: lst ping [--group NAME] [--batch NAME] [--session] "
3867 {"add_group", jt_lst_add_group, NULL,
3868 "Usage: lst group NAME IDs [IDs]..." },
3869 {"del_group", jt_lst_del_group, NULL,
3870 "Usage: lst del_group NAME" },
3871 {"update_group", jt_lst_update_group, NULL,
3872 "Usage: lst update_group NAME [--clean] [--refresh] [--remove IDs]" },
3873 {"list_group", jt_lst_list_group, NULL,
3874 "Usage: lst list_group [--active] [--busy] [--down] [--unknown] "
3876 {"stat", jt_lst_stat, NULL,
3877 "Usage: lst stat [--bw] [--rate] [--read] [--write] [--max] [--min] "
3878 " [--avg] [--mbs] [--timeout #] [--delay #] [--count #] GROUP [GROUP]"
3880 {"show_error", jt_lst_show_error, NULL,
3881 "Usage: lst show_error NAME | IDS ..." },
3882 {"add_batch", jt_lst_add_batch, NULL,
3883 "Usage: lst add_batch NAME" },
3884 {"run", jt_lst_start_batch, NULL,
3885 "Usage: lst run [--timeout TIME] [NAME]" },
3886 {"stop", jt_lst_stop_batch, NULL,
3887 "Usage: lst stop [--force] BATCH_NAME" },
3888 {"list_batch", jt_lst_list_batch, NULL,
3889 "Usage: lst list_batch NAME [--test ID] [--server]" },
3890 {"query", jt_lst_query_batch, NULL,
3891 "Usage: lst query [--test ID] [--server] [--timeout TIME] NAME" },
3892 {"add_test", jt_lst_add_test, NULL,
3893 "Usage: lst add_test [--batch BATCH] [--loop #] [--concurrency #] "
3894 " [--distribute #:#] [--from GROUP] [--to GROUP] TEST..." },
3899 lst_initialize(void)
3904 feats = getenv("LST_FEATURES");
3906 session_features = strtol(feats, NULL, 16);
3908 if ((session_features & ~LST_FEATS_MASK) != 0) {
3910 "Unsupported session features %x, only support these features so far: %x\n",
3911 (session_features & ~LST_FEATS_MASK), LST_FEATS_MASK);
3915 key = getenv("LST_SESSION");
3922 session_key = atoi(key);
3928 lst_print_usage(char *cmd)
3930 char *argv[] = { "help", cmd };
3932 cfs_parser(2, argv, lst_cmdlist);
3935 int main(int argc, char **argv)
3941 rc = lst_initialize();
3945 rc = lustre_lnet_config_lib_init();
3949 rc = cfs_parser(argc, argv, lst_cmdlist);