Whamcloud - gitweb
LU-6142 utils: use list_first/list_entry() on list heads
[fs/lustre-release.git] / lnet / utils / lst.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2012, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  *
31  * lnet/selftest/conctl.c
32  *
33  * Author: Liang Zhen <liangzhen@clusterfs.com>
34  */
35 #include <errno.h>
36 #include <getopt.h>
37 #include <inttypes.h>
38 #include <pwd.h>
39 #include <unistd.h>
40 #include <stdarg.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <sys/ioctl.h>
45 #include <time.h>
46 #include <linux/types.h>
47
48 #include <libcfs/util/list.h>
49 #include <libcfs/util/ioctl.h>
50 #include <libcfs/util/parser.h>
51 #include <linux/lnet/lnetctl.h>
52 #include <linux/lnet/lnetst.h>
53 #include <linux/lnet/nidstr.h>
54 #include "lnetconfig/liblnetconfig.h"
55
56 struct lst_sid LST_INVALID_SID = { .ses_nid = LNET_NID_ANY, .ses_stamp = -1 };
57 static unsigned int session_key;
58
59 /* All nodes running 2.6.50 or later understand feature LST_FEAT_BULK_LEN */
60 static unsigned int session_features = LST_FEATS_MASK;
61 static struct lstcon_trans_stat trans_stat;
62
63 typedef struct list_string {
64         struct list_string *lstr_next;
65         int                 lstr_sz;
66         char                lstr_str[0];
67 } lstr_t;
68
69 #ifndef offsetof
70 # define offsetof(typ,memb)     ((unsigned long)((char *)&(((typ *)0)->memb)))
71 #endif
72
73 static int alloc_count = 0;
74 static int alloc_nob   = 0;
75
76 lstr_t *
77 alloc_lstr(int sz)
78 {
79         lstr_t  *lstr = malloc(offsetof(lstr_t, lstr_str[sz]));
80
81         if (lstr == NULL) {
82                 fprintf(stderr, "Can't allocate lstr\n");
83                 abort();
84         }
85
86         alloc_nob += sz;
87         alloc_count++;
88
89         lstr->lstr_str[0] = 0;
90         lstr->lstr_sz = sz;
91         return lstr;
92 }
93
94 void
95 free_lstr(lstr_t *lstr)
96 {
97         alloc_count--;
98         alloc_nob -= lstr->lstr_sz;
99         free(lstr);
100 }
101
102 void
103 free_lstrs(lstr_t **list)
104 {
105         lstr_t   *lstr;
106
107         while ((lstr = *list) != NULL) {
108                 *list = lstr->lstr_next;
109                 free_lstr(lstr);
110         }
111 }
112
113 void
114 new_lstrs(lstr_t **list, char *prefix, char *postfix,
115           int lo, int hi, int stride)
116 {
117         int    n1 = strlen(prefix);
118         int    n2 = strlen(postfix);
119         int    sz = n1 + 20 + n2 + 1;
120
121         do {
122                 lstr_t *n = alloc_lstr(sz);
123
124                 snprintf(n->lstr_str, sz - 1, "%s%u%s",
125                          prefix, lo, postfix);
126
127                 n->lstr_next = *list;
128                 *list = n;
129
130                 lo += stride;
131         } while (lo <= hi);
132 }
133
134 int
135 expand_lstr(lstr_t **list, lstr_t *l)
136 {
137         int          nob = strlen(l->lstr_str);
138         char        *b1;
139         char        *b2;
140         char        *expr;
141         char        *sep;
142         int          x;
143         int          y;
144         int          z;
145         int          n;
146
147         b1 = strchr(l->lstr_str, '[');
148         if (b1 == NULL) {
149                 l->lstr_next = *list;
150                 *list = l;
151                 return 0;
152         }
153
154         b2 = strchr(b1, ']');
155         if (b2 == NULL || b2 == b1 + 1)
156                 return -1;
157
158         *b1++ = 0;
159         *b2++ = 0;
160         expr = b1;
161         do {
162
163                 sep = strchr(expr, ',');
164                 if (sep != NULL)
165                         *sep++ = 0;
166
167                 nob = strlen(expr);
168                 n = nob;
169                 if (sscanf(expr, "%u%n", &x, &n) >= 1 && n == nob) {
170                         /* simple number */
171                         new_lstrs(list, l->lstr_str, b2, x, x, 1);
172                         continue;
173                 }
174
175                 n = nob;
176                 if (sscanf(expr, "%u-%u%n", &x, &y, &n) >= 2 && n == nob &&
177                     x < y) {
178                         /* simple range */
179                         new_lstrs(list, l->lstr_str, b2, x, y, 1);
180                         continue;
181                 }
182
183                 n = nob;
184                 if (sscanf(expr, "%u-%u/%u%n", &x, &y, &z, &n) >= 3 && n == nob &&
185                     x < y) {
186                         /* strided range */
187                         new_lstrs(list, l->lstr_str, b2, x, y, z);
188                         continue;
189                 }
190
191                 /* syntax error */
192                 return -1;
193         } while ((expr = sep) != NULL);
194
195         free_lstr(l);
196
197         return 1;
198 }
199
200 int
201 expand_strs(char *str, lstr_t **head)
202 {
203         lstr_t  *list = NULL;
204         lstr_t  *nlist;
205         lstr_t  *l;
206         int      rc = 0;
207         int      expanded;
208
209         l = alloc_lstr(strlen(str) + 1);
210         memcpy(l->lstr_str, str, strlen(str) + 1);
211         l->lstr_next = NULL;
212         list = l;
213
214         do {
215                 expanded = 0;
216                 nlist = NULL;
217
218                 while ((l = list) != NULL) {
219                         list = l->lstr_next;
220
221                         rc = expand_lstr(&nlist, l);
222                         if (rc < 0) {
223                                 fprintf(stderr, "Syntax error in \"%s\"\n", str);
224                                 free_lstr(l);
225                                 break;
226                         }
227
228                         expanded |= rc > 0;
229                 }
230
231                 /* re-order onto 'list' */
232                 while ((l = nlist) != NULL) {
233                         nlist = l->lstr_next;
234                         l->lstr_next = list;
235                         list = l;
236                 }
237
238         } while (expanded && rc > 0);
239
240         if (rc >= 0) {
241                 *head = list;
242                 return 0;
243         }
244
245         while ((l = list) != NULL) {
246                 list = l->lstr_next;
247
248                 free_lstr(l);
249         }
250         return rc;
251 }
252
253 int
254 lst_parse_nids(char *str, int *countp, struct lnet_process_id **idspp)
255 {
256         lstr_t  *head = NULL;
257         lstr_t  *l;
258         int      c = 0;
259         int      i;
260         int      rc;
261
262         rc = expand_strs(str, &head);
263         if (rc != 0)
264                 goto out;
265
266         l = head;
267         while (l != NULL) {
268                 l = l->lstr_next;
269                 c++;
270         }
271
272         *idspp = malloc(c * sizeof(struct lnet_process_id));
273         if (*idspp == NULL) {
274                 fprintf(stderr, "Out of memory\n");
275                 rc = -1;
276         }
277
278         *countp = c;
279 out:
280         i = 0;
281         while ((l = head) != NULL) {
282                 head = l->lstr_next;
283
284                 if (rc == 0) {
285                         (*idspp)[i].nid = libcfs_str2nid(l->lstr_str);
286                         if ((*idspp)[i].nid == LNET_NID_ANY) {
287                                 fprintf(stderr, "Invalid nid: %s\n",
288                                         l->lstr_str);
289                                 rc = -1;
290                         }
291
292                         (*idspp)[i].pid = LNET_PID_LUSTRE;
293                         i++;
294                 }
295
296                 free_lstr(l);
297         }
298
299         if (rc == 0)
300                 return 0;
301
302         free(*idspp);
303         *idspp = NULL;
304
305         return rc;
306 }
307
308 char *
309 lst_node_state2str(int state)
310 {
311         if (state == LST_NODE_ACTIVE)
312                 return "Active";
313         if (state == LST_NODE_BUSY)
314                 return "Busy";
315         if (state == LST_NODE_DOWN)
316                 return "Down";
317
318         return "Unknown";
319 }
320
321 int
322 lst_node_str2state(char *str)
323 {
324         if (strcasecmp(str, "active") == 0)
325                 return LST_NODE_ACTIVE;
326         if (strcasecmp(str, "busy") == 0)
327                 return LST_NODE_BUSY;
328         if (strcasecmp(str, "down") == 0)
329                 return LST_NODE_DOWN;
330         if (strcasecmp(str, "unknown") == 0)
331                 return LST_NODE_UNKNOWN;
332         if (strcasecmp(str, "invalid") == 0)
333                 return (LST_NODE_UNKNOWN | LST_NODE_DOWN | LST_NODE_BUSY);
334
335         return -1;
336 }
337
338 char *
339 lst_test_type2name(int type)
340 {
341         if (type == LST_TEST_PING)
342                 return "ping";
343         if (type == LST_TEST_BULK)
344                 return "brw";
345
346         return "unknown";
347 }
348
349 int
350 lst_test_name2type(char *name)
351 {
352         if (strcasecmp(name, "ping") == 0)
353                 return LST_TEST_PING;
354         if (strcasecmp(name, "brw") == 0)
355                 return LST_TEST_BULK;
356
357         return -1;
358 }
359
360 void
361 lst_print_usage(char *cmd)
362 {
363         char *argv[] = { "help", cmd };
364
365         cfs_parser(2, argv, NULL);
366 }
367
368 void
369 lst_print_error(char *sub, const char *def_format, ...)
370 {
371         va_list ap;
372
373         /* local error returned from kernel */
374         switch (errno) {
375         case ESRCH:
376                 fprintf(stderr, "No session exists\n");
377                 return;
378         case ESHUTDOWN:
379                 fprintf(stderr, "Session is shutting down\n");
380                 return;
381         case EACCES:
382                 fprintf(stderr, "Unmatched session key or not root\n");
383                 return;
384         case ENOENT:
385                 fprintf(stderr, "Can't find %s in current session\n", sub);
386                 return;
387         case EINVAL:
388                 fprintf(stderr, "Invalid parameters list in command line\n");
389                 return;
390         case EFAULT:
391                 fprintf(stderr, "Bad parameter address\n");
392                 return;
393         case EEXIST:
394                 fprintf(stderr, "%s already exists\n", sub);
395                 return;
396         default:
397                 va_start(ap, def_format);
398                 vfprintf(stderr, def_format, ap);
399                 va_end(ap);
400
401                 return;
402         }
403 }
404
405 void
406 lst_free_rpcent(struct list_head *head)
407 {
408         struct lstcon_rpc_ent *ent;
409
410         while (!list_empty(head)) {
411                 ent = list_first_entry(head, struct lstcon_rpc_ent, rpe_link);
412
413                 list_del(&ent->rpe_link);
414                 free(ent);
415         }
416 }
417
418 void
419 lst_reset_rpcent(struct list_head *head)
420 {
421         struct lstcon_rpc_ent *ent;
422
423         list_for_each_entry(ent, head, rpe_link) {
424                 ent->rpe_sid       = LST_INVALID_SID;
425                 ent->rpe_peer.nid  = LNET_NID_ANY;
426                 ent->rpe_peer.pid  = LNET_PID_ANY;
427                 ent->rpe_rpc_errno = ent->rpe_fwk_errno = 0;
428         }
429 }
430
431 int
432 lst_alloc_rpcent(struct list_head *head, int count, int offset)
433 {
434         struct lstcon_rpc_ent *ent;
435         int               i;
436
437         for (i = 0; i < count; i++) {
438                 ent = malloc(offsetof(struct lstcon_rpc_ent, rpe_payload[offset]));
439                 if (ent == NULL) {
440                         lst_free_rpcent(head);
441                         return -1;
442                 }
443
444                 memset(ent, 0, offsetof(struct lstcon_rpc_ent, rpe_payload[offset]));
445
446                 ent->rpe_sid      = LST_INVALID_SID;
447                 ent->rpe_peer.nid = LNET_NID_ANY;
448                 ent->rpe_peer.pid = LNET_PID_ANY;
449                 list_add(&ent->rpe_link, head);
450         }
451
452         return 0;
453 }
454
455 void
456 lst_print_transerr(struct list_head *head, char *optstr)
457 {
458         struct lstcon_rpc_ent *ent;
459
460         list_for_each_entry(ent, head, rpe_link) {
461                 if (ent->rpe_rpc_errno == 0 && ent->rpe_fwk_errno == 0)
462                         continue;
463
464                 if (ent->rpe_rpc_errno != 0) {
465                         fprintf(stderr, "%s RPC failed on %s: %s\n",
466                                 optstr, libcfs_id2str(ent->rpe_peer),
467                                 strerror(ent->rpe_rpc_errno));
468                         continue;
469                 }
470
471                 fprintf(stderr, "operation %s failed on %s: %s\n",
472                         optstr, libcfs_id2str(ent->rpe_peer),
473                         strerror(ent->rpe_fwk_errno));
474         }
475 }
476
477 int lst_info_batch_ioctl(char *batch, int test, int server,
478                         struct lstcon_test_batch_ent *entp, int *idxp,
479                         int *ndentp, struct lstcon_node_ent *dentsp);
480
481 int lst_info_group_ioctl(char *name, struct lstcon_ndlist_ent *gent,
482                          int *idx, int *count, struct lstcon_node_ent *dents);
483
484 int lst_query_batch_ioctl(char *batch, int test, int server,
485                           int timeout, struct list_head *head);
486
487 int
488 lst_ioctl(unsigned int opc, void *buf, int len)
489 {
490         struct libcfs_ioctl_data data;
491         int    rc;
492
493         LIBCFS_IOC_INIT (data);
494         data.ioc_u32[0]  = opc;
495         data.ioc_plen1   = len;
496         data.ioc_pbuf1   = (char *)buf;
497         data.ioc_plen2   = sizeof(trans_stat);
498         data.ioc_pbuf2   = (char *)&trans_stat;
499
500         memset(&trans_stat, 0, sizeof(trans_stat));
501
502         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_LNETST, &data);
503
504         /* local error, no valid RPC result */
505         if (rc != 0)
506                 return -1;
507
508         /* RPC error */
509         if (trans_stat.trs_rpc_errno != 0)
510                 return -2;
511
512         /* Framework error */
513         if (trans_stat.trs_fwk_errno != 0)
514                 return -3;
515
516         return 0;
517 }
518
519 int lst_yaml_session(const char *label, const char *timeout, int nlflags,
520                      const char *errmsg)
521 {
522         struct lstcon_ndlist_ent ndinfo = { };
523         struct lst_sid sid = LST_INVALID_SID;
524         /* nlflags being zero means we are destroying the session.
525          * No parsing of reply needed.
526          */
527         bool done = nlflags ? false : true;
528         char nid[LNET_NIDSTR_SIZE];
529         char name[LST_NAME_SIZE];
530         unsigned int key = 0;
531         yaml_emitter_t request;
532         yaml_parser_t reply;
533         yaml_event_t event;
534         struct nl_sock *sk;
535         int rc;
536
537         sk = nl_socket_alloc();
538         if (!sk)
539                 return -1;
540
541         /* Note: NL_AUTO_PID == zero which we use by default for the
542          * session_key when creating a new session. This is considered
543          * an invalid key so we need to get the real session key from
544          * the yaml parser yet to be created. If the user did request
545          * a specific session key then set the socket's port id to this
546          * value.
547          */
548         if (session_key)
549                 nl_socket_set_local_port(sk, session_key);
550
551         /* Setup reply parser to recieve Netlink packets */
552         rc = yaml_parser_initialize(&reply);
553         if (rc == 0) {
554                 nl_socket_free(sk);
555                 return -1;
556         }
557
558         rc = yaml_parser_set_input_netlink(&reply, sk, false);
559         if (rc == 0)
560                 goto parser_error;
561
562         /* Create Netlink emitter to send request to kernel */
563         yaml_emitter_initialize(&request);
564         rc = yaml_emitter_set_output_netlink(&request, sk,
565                                              LNET_SELFTEST_GENL_NAME,
566                                              LNET_SELFTEST_GENL_VERSION,
567                                              LNET_SELFTEST_CMD_SESSIONS,
568                                              nlflags);
569         if (rc == 0)
570                 goto emitter_error;
571
572         yaml_emitter_open(&request);
573         yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
574         rc = yaml_emitter_emit(&request, &event);
575         if (rc == 0)
576                 goto emitter_error;
577
578         yaml_mapping_start_event_initialize(&event, NULL,
579                                             (yaml_char_t *)YAML_MAP_TAG,
580                                             1, YAML_BLOCK_MAPPING_STYLE);
581         rc = yaml_emitter_emit(&request, &event);
582         if (rc == 0)
583                 goto emitter_error;
584
585         yaml_scalar_event_initialize(&event, NULL,
586                                      (yaml_char_t *)YAML_STR_TAG,
587                                      (yaml_char_t *)"sessions",
588                                      strlen("sessions"), 1, 0,
589                                      YAML_PLAIN_SCALAR_STYLE);
590         rc = yaml_emitter_emit(&request, &event);
591         if (rc == 0)
592                 goto emitter_error;
593
594         if (!label) {
595                 yaml_scalar_event_initialize(&event, NULL,
596                                              (yaml_char_t *)YAML_STR_TAG,
597                                              (yaml_char_t *)"",
598                                              strlen(""), 1, 0,
599                                              YAML_PLAIN_SCALAR_STYLE);
600                 rc = yaml_emitter_emit(&request, &event);
601                 if (rc == 0)
602                         goto emitter_error;
603                 goto skip_params;
604         }
605
606         /* sessions: { name: 'name', timeout: 300 }
607          * or
608          * sessions:
609          *   name: 'name'
610          *   timeout: 300
611          */
612         yaml_mapping_start_event_initialize(&event, NULL,
613                                             (yaml_char_t *)YAML_MAP_TAG,
614                                             1, YAML_FLOW_MAPPING_STYLE);
615         rc = yaml_emitter_emit(&request, &event);
616         if (rc == 0)
617                 goto emitter_error;
618
619         yaml_scalar_event_initialize(&event, NULL,
620                                      (yaml_char_t *)YAML_STR_TAG,
621                                      (yaml_char_t *)"name",
622                                      strlen("name"), 1, 0,
623                                      YAML_PLAIN_SCALAR_STYLE);
624         rc = yaml_emitter_emit(&request, &event);
625         if (rc == 0)
626                 goto emitter_error;
627
628         yaml_scalar_event_initialize(&event, NULL,
629                                      (yaml_char_t *)YAML_STR_TAG,
630                                      (yaml_char_t *)label,
631                                      strlen(label), 1, 0,
632                                      YAML_PLAIN_SCALAR_STYLE);
633         rc = yaml_emitter_emit(&request, &event);
634         if (rc == 0)
635                 goto emitter_error;
636
637         if (timeout) {
638                 yaml_scalar_event_initialize(&event, NULL,
639                                              (yaml_char_t *)YAML_STR_TAG,
640                                              (yaml_char_t *)"timeout",
641                                              strlen("timeout"), 1, 0,
642                                              YAML_PLAIN_SCALAR_STYLE);
643                 rc = yaml_emitter_emit(&request, &event);
644                 if (rc == 0)
645                         goto emitter_error;
646
647                 yaml_scalar_event_initialize(&event, NULL,
648                                              (yaml_char_t *)YAML_STR_TAG,
649                                              (yaml_char_t *)timeout,
650                                              strlen(timeout), 1, 0,
651                                              YAML_PLAIN_SCALAR_STYLE);
652                 rc = yaml_emitter_emit(&request, &event);
653                 if (rc == 0)
654                         goto emitter_error;
655         }
656
657         yaml_mapping_end_event_initialize(&event);
658         rc = yaml_emitter_emit(&request, &event);
659         if (rc == 0)
660                 goto emitter_error;
661
662 skip_params:
663         yaml_mapping_end_event_initialize(&event);
664         rc = yaml_emitter_emit(&request, &event);
665         if (rc == 0)
666                 goto emitter_error;
667
668         yaml_document_end_event_initialize(&event, 0);
669         rc = yaml_emitter_emit(&request, &event);
670         if (rc == 0)
671                 goto emitter_error;
672
673         rc = yaml_emitter_close(&request);
674         if (rc == 0) {
675 emitter_error:
676                 yaml_emitter_log_error(&request, stderr);
677                 yaml_emitter_delete(&request);
678                 errmsg = NULL;
679                 goto parser_error;
680         }
681         yaml_emitter_delete(&request);
682
683         while (!done) {
684                 rc = yaml_parser_parse(&reply, &event);
685                 if (rc == 0)
686                         goto parser_error;
687
688                 if (event.type == YAML_SCALAR_EVENT) {
689                         char *tmp, *endp = NULL;
690
691                         if (strcmp((char *)event.data.scalar.value,
692                                    "name") == 0) {
693                                 yaml_event_delete(&event);
694                                 rc = yaml_parser_parse(&reply, &event);
695                                 if (rc == 0)
696                                         goto parser_error;
697
698                                 strncpy(name, (char *)event.data.scalar.value,
699                                         sizeof(name) - 1);
700                         }
701
702                         if (strcmp((char *)event.data.scalar.value,
703                                    "key") == 0) {
704                                 yaml_event_delete(&event);
705                                 rc = yaml_parser_parse(&reply, &event);
706                                 if (rc == 0)
707                                         goto parser_error;
708
709                                 tmp = (char *)event.data.scalar.value;
710                                 key = strtoul(tmp, &endp, 10);
711                                 if (endp == tmp)
712                                         goto parser_error;
713                         }
714
715                         if (strcmp((char *)event.data.scalar.value,
716                                    "timestamp") == 0) {
717                                 yaml_event_delete(&event);
718                                 rc = yaml_parser_parse(&reply, &event);
719                                 if (rc == 0)
720                                         goto parser_error;
721
722                                 tmp = (char *)event.data.scalar.value;
723                                 sid.ses_stamp = strtoll(tmp, &endp, 10);
724                                 if (endp == tmp)
725                                         goto parser_error;
726                         }
727
728                         if (strcmp((char *)event.data.scalar.value,
729                                    "nid") == 0) {
730                                 yaml_event_delete(&event);
731                                 rc = yaml_parser_parse(&reply, &event);
732                                 if (rc == 0)
733                                         goto parser_error;
734
735                                 strncpy(nid, (char *)event.data.scalar.value,
736                                         sizeof(nid) - 1);
737                         }
738
739                         if (strcmp((char *)event.data.scalar.value,
740                                    "nodes") == 0) {
741                                 yaml_event_delete(&event);
742                                 rc = yaml_parser_parse(&reply, &event);
743                                 if (rc == 0)
744                                         goto parser_error;
745
746                                 tmp = (char *)event.data.scalar.value;
747                                 ndinfo.nle_nnode = strtoul(tmp, &endp, 10);
748                                 if (endp == tmp)
749                                         goto parser_error;
750                         }
751                 }
752
753                 done = (event.type == YAML_STREAM_END_EVENT);
754
755                 yaml_event_delete(&event);
756         }
757
758         if (nlflags & NLM_F_CREATE) {
759                 session_features = yaml_parser_get_reader_proto_version(&reply);
760                 session_key = key;
761         }
762 parser_error:
763         if (rc == 0 && errmsg)
764                 yaml_parser_log_error(&reply, stderr, errmsg);
765         yaml_parser_delete(&reply);
766         nl_socket_free(sk);
767
768         if (((nlflags & NLM_F_DUMP) == NLM_F_DUMP) && rc != 0) {
769                 fprintf(stdout,
770                         "%s ID: %ju@%s, KEY: %u FEATURES: %x NODES: %d\n",
771                         name, (uintmax_t)sid.ses_stamp, nid,
772                         key, session_features, ndinfo.nle_nnode);
773         }
774
775         return rc == 0 ? -1 : 0;
776 }
777
778 int
779 lst_new_session_ioctl(char *name, int timeout, int force, struct lst_sid *sid)
780 {
781         struct lstio_session_new_args args = { 0 };
782
783         args.lstio_ses_key     = session_key;
784         args.lstio_ses_timeout = timeout;
785         args.lstio_ses_force   = force;
786         args.lstio_ses_idp     = sid;
787         args.lstio_ses_feats   = session_features;
788         args.lstio_ses_nmlen   = strlen(name);
789         args.lstio_ses_namep   = name;
790
791         return lst_ioctl (LSTIO_SESSION_NEW, &args, sizeof(args));
792 }
793
794 int
795 jt_lst_new_session(int argc, char **argv)
796 {
797         char  buf[LST_NAME_SIZE * 2 + 1];
798         char *name, *timeout_s = NULL;
799         int nlflags = NLM_F_CREATE;
800         struct lst_sid session_id;
801         int   optidx = 0;
802         int   timeout = 300;
803         int   force = 0;
804         int   c;
805         int   rc;
806
807         static const struct option session_opts[] = {
808                 { .name = "timeout", .has_arg = required_argument, .val = 't' },
809                 { .name = "force",   .has_arg = no_argument,       .val = 'f' },
810                 { .name = NULL } };
811
812         while (1) {
813                 c = getopt_long(argc, argv, "ft:",
814                                 session_opts, &optidx);
815                 if (c == -1)
816                         break;
817
818                 switch (c) {
819                 case 'f':
820                         nlflags |= NLM_F_REPLACE;
821                         force = 1;
822                         break;
823                 case 't':
824                         timeout_s = optarg;
825                         break;
826                 default:
827                         lst_print_usage(argv[0]);
828                         return -1;
829                 }
830         }
831
832         if (timeout_s) {
833                 timeout = atoi(timeout_s);
834                 if (timeout <= 0) {
835                         fprintf(stderr, "Invalid timeout value\n");
836                         return -1;
837                 }
838         }
839
840         if (optind == argc - 1) {
841                 name = argv[optind ++];
842                 if (strlen(name) >= LST_NAME_SIZE) {
843                         fprintf(stderr, "Name size is limited to %d\n",
844                                 LST_NAME_SIZE - 1);
845                         return -1;
846                 }
847         } else if (optind == argc) {
848                 char           user[LST_NAME_SIZE];
849                 char           host[LST_NAME_SIZE];
850                 struct passwd *pw = getpwuid(getuid());
851
852                 if (pw == NULL)
853                         snprintf(user, sizeof(user), "%d", (int)getuid());
854                 else
855                         snprintf(user, sizeof(user), "%s", pw->pw_name);
856
857                 rc = gethostname(host, sizeof(host));
858                 if (rc != 0)
859                         snprintf(host, sizeof(host), "unknown_host");
860
861                 snprintf(buf, sizeof(buf), "%s@%s", user, host);
862                 name = buf;
863         } else {
864                 lst_print_usage(argv[0]);
865                 return -1;
866         }
867
868         rc = lst_yaml_session(name, timeout_s, nlflags, "new session");
869         if (rc == 0)
870                 goto success;
871
872         if (session_key == 0) {
873                 fprintf(stderr,
874                         "Can't find env LST_SESSION or value is not valid\n");
875                 return -1;
876         }
877
878         rc = lst_new_session_ioctl(name, timeout, force, &session_id);
879         if (rc != 0) {
880                 lst_print_error("session", "Failed to create session: %s\n",
881                                 strerror(errno));
882                 return rc;
883         }
884 success:
885         fprintf(stdout, "SESSION: %s FEATURES: %x TIMEOUT: %d FORCE: %s\n",
886                 name, session_features, timeout, force ? "Yes" : "No");
887         return 0;
888 }
889
890 int
891 lst_session_info_ioctl(char *name, int len, int *key, unsigned *featp,
892                        struct lst_sid *sid, struct lstcon_ndlist_ent *ndinfo)
893 {
894         struct lstio_session_info_args args = { 0 };
895
896         args.lstio_ses_idp     = sid;
897         args.lstio_ses_keyp    = key;
898         args.lstio_ses_featp   = featp;
899         args.lstio_ses_ndinfo  = ndinfo;
900         args.lstio_ses_nmlen   = len;
901         args.lstio_ses_namep   = name;
902
903         return lst_ioctl(LSTIO_SESSION_INFO, &args, sizeof(args));
904 }
905
906 int
907 jt_lst_show_session(int argc, char **argv)
908 {
909         struct lstcon_ndlist_ent ndinfo;
910         struct lst_sid sid;
911         char name[LST_NAME_SIZE];
912         unsigned int feats;
913         int key;
914         int rc;
915
916         rc = lst_yaml_session(NULL, NULL, NLM_F_DUMP, "show session");
917         if (rc == 0)
918                 return 0;
919
920         rc = lst_session_info_ioctl(name, sizeof(name), &key,
921                                     &feats, &sid, &ndinfo);
922
923         if (rc != 0) {
924                 lst_print_error("session", "Failed to show session: %s\n",
925                                 strerror(errno));
926                 return -1;
927         }
928
929         fprintf(stdout, "%s ID: %ju@%s, KEY: %d FEATURES: %x NODES: %d\n",
930                 name, (uintmax_t)sid.ses_stamp, libcfs_nid2str(sid.ses_nid),
931                 key, feats, ndinfo.nle_nnode);
932
933         return 0;
934 }
935
936 int
937 lst_end_session_ioctl(void)
938 {
939         struct lstio_session_end_args args = { 0 };
940
941         args.lstio_ses_key = session_key;
942         return lst_ioctl(LSTIO_SESSION_END, &args, sizeof(args));
943 }
944
945 int
946 jt_lst_end_session(int argc, char **argv)
947 {
948         int             rc;
949
950         if (session_key == 0) {
951                 fprintf(stderr,
952                         "Can't find env LST_SESSION or value is not valid\n");
953                 return -1;
954         }
955
956         rc = lst_yaml_session(NULL, NULL, 0, "end session");
957         if (rc == 0)
958                 goto finish;
959
960         rc = lst_end_session_ioctl();
961
962         if (rc == 0) {
963                 fprintf(stdout, "session is ended\n");
964                 return 0;
965         }
966
967         if (rc == -1) {
968                 lst_print_error("session", "Failed to end session: %s\n",
969                                 strerror(errno));
970                 return rc;
971         }
972 finish:
973         if (trans_stat.trs_rpc_errno != 0) {
974                 fprintf(stderr,
975                         "[RPC] Failed to send %d session RPCs: %s\n",
976                         lstcon_rpc_stat_failure(&trans_stat, 0),
977                         strerror(trans_stat.trs_rpc_errno));
978         }
979
980         if (trans_stat.trs_fwk_errno != 0) {
981                 fprintf(stderr,
982                         "[FWK] Failed to end session on %d nodes: %s\n",
983                         lstcon_sesop_stat_failure(&trans_stat, 0),
984                         strerror(trans_stat.trs_fwk_errno));
985         }
986
987         return rc;
988 }
989
990 #define LST_NODES_TITLE "\tACTIVE\tBUSY\tDOWN\tUNKNOWN\tTOTAL\n"
991
992 static int lst_yaml_display_groups(yaml_parser_t *reply, char *group,
993                                    int states, bool print)
994 {
995         yaml_event_t event;
996         int rc;
997
998         if (states) {
999                 char name[LST_NAME_SIZE] = {};
1000                 bool done = false;
1001                 int count = 0;
1002
1003                 if (print)
1004                         fprintf(stdout, LST_NODES_TITLE);
1005
1006                 while (!done) {
1007                         rc = yaml_parser_parse(reply, &event);
1008                         if (rc == 0)
1009                                 goto parser_error;
1010
1011                         if (event.type == YAML_MAPPING_START_EVENT) {
1012                                 char *value = NULL;
1013                                 yaml_event_t next;
1014
1015                                 rc = yaml_parser_parse(reply, &next);
1016                                 if (rc == 0)
1017                                         goto parser_error;
1018
1019                                 if (next.type != YAML_SCALAR_EVENT) {
1020                                         yaml_event_delete(&next);
1021                                         continue;
1022                                 }
1023
1024                                 value = (char *)next.data.scalar.value;
1025                                 if (strcmp(value, "groups") == 0) {
1026                                         yaml_event_delete(&next);
1027                                 } else if (strcmp(value, "nid") == 0) {
1028                                         yaml_event_t next;
1029                                         char *tmp;
1030
1031                                         rc = yaml_parser_parse(reply, &next);
1032                                         if (rc == 0)
1033                                                 goto parser_error;
1034
1035                                         fprintf(stdout, "\t%s: ",
1036                                                 (char *)next.data.scalar.value);
1037
1038                                         rc = yaml_parser_parse(reply, &next);
1039                                         if (rc == 0)
1040                                                 goto parser_error;
1041
1042                                         tmp = (char *)next.data.scalar.value;
1043                                         if (strcmp(tmp, "status") == 0) {
1044                                                 yaml_event_t state;
1045
1046                                                 rc = yaml_parser_parse(reply, &state);
1047                                                 if (rc == 0)
1048                                                         goto parser_error;
1049
1050                                                 fprintf(stdout, "%s\n",
1051                                                         (char *)state.data.scalar.value);
1052                                                 count++;
1053                                         }
1054                                 } else {
1055                                         yaml_event_t next;
1056
1057                                         rc = yaml_parser_parse(reply, &next);
1058                                         if (rc == 0)
1059                                                 goto parser_error;
1060
1061                                         strncpy(name, value, sizeof(name) - 1);
1062                                         fprintf(stdout, "Group [ %s ]\n", name);
1063                                         count = 0;
1064
1065                                         if (next.type != YAML_SEQUENCE_START_EVENT) {
1066                                                 fprintf(stdout,
1067                                                         "No nodes found [ %s ]\n",
1068                                                         name);
1069                                         }
1070                                 }
1071                         } else if (event.type == YAML_SEQUENCE_END_EVENT &&
1072                                    count) {
1073                                 fprintf(stdout, "Total %d nodes [ %s ]\n",
1074                                         count, name);
1075                                 count = 0;
1076                         }
1077
1078                         done = (event.type == YAML_STREAM_END_EVENT);
1079                         yaml_event_delete(&event);
1080                 }
1081         } else if (group) {
1082                 int active = 0, busy = 0, down = 0, unknown = 0;
1083                 char group[LST_NAME_SIZE];
1084                 bool done = false;
1085
1086                 while (!done) {
1087                         rc = yaml_parser_parse(reply, &event);
1088                         if (rc == 0)
1089                                 goto parser_error;
1090
1091                         if (event.type == YAML_SCALAR_EVENT) {
1092                                 char *value = (char *)event.data.scalar.value;
1093                                 yaml_event_t next;
1094
1095                                 value = (char *)event.data.scalar.value;
1096                                 if (strcmp(value, "groups") == 0) {
1097                                         yaml_event_delete(&event);
1098                                         continue;
1099                                 }
1100
1101                                 rc = yaml_parser_parse(reply, &next);
1102                                 if (rc == 0)
1103                                         goto parser_error;
1104
1105                                 if (next.type == YAML_SCALAR_EVENT) {
1106                                         int status;
1107
1108                                         status = lst_node_str2state((char *)next.data.scalar.value);
1109                                         switch (status) {
1110                                         case LST_NODE_ACTIVE:
1111                                                 active++;
1112                                                 break;
1113                                         case LST_NODE_BUSY:
1114                                                 busy++;
1115                                                 break;
1116                                         case LST_NODE_DOWN:
1117                                                 down++;
1118                                                 break;
1119                                         case LST_NODE_UNKNOWN:
1120                                                 unknown++;
1121                                         default:
1122                                                 break;
1123                                         }
1124                                 } else if (next.type == YAML_SEQUENCE_START_EVENT) {
1125                                         strncpy(group, value, sizeof(group) - 1);
1126                                         active = 0;
1127                                         busy = 0;
1128                                         down = 0;
1129                                         unknown = 0;
1130                                 }
1131                                 yaml_event_delete(&next);
1132                         } else if (event.type == YAML_SEQUENCE_END_EVENT) {
1133                                 if (strlen(group)) {
1134                                         fprintf(stdout, "\t%d\t%d\t%d\t%d\t%d\t%s\n",
1135                                                 active, busy, down, unknown,
1136                                                 active + busy + down + unknown, group);
1137                                 }
1138                                 memset(group, 0, sizeof(group));
1139                         }
1140                         done = (event.type == YAML_STREAM_END_EVENT);
1141                         yaml_event_delete(&event);
1142                 }
1143         } else {
1144                 bool done = false;
1145                 unsigned int i = 1;
1146
1147                 while (!done) {
1148                         rc = yaml_parser_parse(reply, &event);
1149                         if (rc == 0)
1150                                 goto parser_error;
1151
1152                         if (event.type == YAML_SCALAR_EVENT) {
1153                                 char *value;
1154
1155                                 value = (char *)event.data.scalar.value;
1156                                 if (strlen(value) &&
1157                                     strcmp(value, "groups") != 0) {
1158                                         if (print)
1159                                                 fprintf(stdout, "%d) %s\n",
1160                                                         i, value);
1161                                         i++;
1162                                 }
1163                         }
1164                         done = (event.type == YAML_STREAM_END_EVENT);
1165
1166                         yaml_event_delete(&event);
1167                 }
1168                 if (print)
1169                         fprintf(stdout, "Total %d groups\n", i - 1);
1170                 else
1171                         rc = i - 1;
1172         }
1173 parser_error:
1174         return rc;
1175 }
1176
1177 #define LST_NODES_TITLE "\tACTIVE\tBUSY\tDOWN\tUNKNOWN\tTOTAL\n"
1178
1179 static int lst_yaml_groups(int nlflags, char *name, int states, bool print)
1180 {
1181         yaml_emitter_t request;
1182         yaml_parser_t reply;
1183         yaml_event_t event;
1184         struct nl_sock *sk;
1185         int rc;
1186
1187         sk = nl_socket_alloc();
1188         if (!sk)
1189                 return -EOPNOTSUPP;
1190
1191         /* Setup reply parser to recieve Netlink packets */
1192         rc = yaml_parser_initialize(&reply);
1193         if (rc == 0) {
1194                 nl_socket_free(sk);
1195                 return -EOPNOTSUPP;
1196         }
1197
1198         rc = yaml_parser_set_input_netlink(&reply, sk, false);
1199         if (rc == 0)
1200                 goto parser_error;
1201
1202         /* Create Netlink emitter to send request to kernel */
1203         yaml_emitter_initialize(&request);
1204         rc = yaml_emitter_set_output_netlink(&request, sk,
1205                                              LNET_SELFTEST_GENL_NAME,
1206                                              LNET_SELFTEST_GENL_VERSION,
1207                                              LNET_SELFTEST_CMD_GROUPS,
1208                                              nlflags);
1209         if (rc == 0)
1210                 goto emitter_error;
1211
1212         yaml_emitter_open(&request);
1213         yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
1214         rc = yaml_emitter_emit(&request, &event);
1215         if (rc == 0)
1216                 goto emitter_error;
1217
1218         yaml_mapping_start_event_initialize(&event, NULL,
1219                                             (yaml_char_t *)YAML_MAP_TAG,
1220                                             1, YAML_BLOCK_MAPPING_STYLE);
1221         rc = yaml_emitter_emit(&request, &event);
1222         if (rc == 0)
1223                 goto emitter_error;
1224
1225         yaml_scalar_event_initialize(&event, NULL,
1226                                      (yaml_char_t *)YAML_STR_TAG,
1227                                      (yaml_char_t *)"groups",
1228                                      strlen("groups"), 1, 0,
1229                                      YAML_PLAIN_SCALAR_STYLE);
1230         rc = yaml_emitter_emit(&request, &event);
1231         if (rc == 0)
1232                 goto emitter_error;
1233
1234         if (name) {
1235                 yaml_sequence_start_event_initialize(&event, NULL,
1236                                                      (yaml_char_t *)YAML_SEQ_TAG,
1237                                                      1, YAML_BLOCK_SEQUENCE_STYLE);
1238                 rc = yaml_emitter_emit(&request, &event);
1239                 if (rc == 0)
1240                         goto emitter_error;
1241
1242                 yaml_mapping_start_event_initialize(&event, NULL,
1243                                                     (yaml_char_t *)YAML_MAP_TAG,
1244                                                     1, YAML_BLOCK_MAPPING_STYLE);
1245                 rc = yaml_emitter_emit(&request, &event);
1246                 if (rc == 0)
1247                         goto emitter_error;
1248
1249                 yaml_scalar_event_initialize(&event, NULL,
1250                                              (yaml_char_t *)YAML_STR_TAG,
1251                                              (yaml_char_t *)name,
1252                                              strlen(name), 1, 0,
1253                                              YAML_PLAIN_SCALAR_STYLE);
1254                 rc = yaml_emitter_emit(&request, &event);
1255                 if (rc == 0)
1256                         goto emitter_error;
1257
1258                 if (states) {
1259                         int max = ffs(LST_NODE_UNKNOWN) + 1, i;
1260                         char *state;
1261
1262                         yaml_sequence_start_event_initialize(&event, NULL,
1263                                                              (yaml_char_t *)YAML_SEQ_TAG,
1264                                                              1, YAML_BLOCK_SEQUENCE_STYLE);
1265                         rc = yaml_emitter_emit(&request, &event);
1266                         if (rc == 0)
1267                                 goto emitter_error;
1268
1269
1270                         for (i = 0; i < max; i++) {
1271                                 int mask = states & (1 << i);
1272
1273                                 state = lst_node_state2str(mask);
1274                                 if (mask != LST_NODE_UNKNOWN && strcmp(state, "Unknown") == 0)
1275                                         continue;
1276
1277                                 yaml_mapping_start_event_initialize(&event, NULL,
1278                                                                     (yaml_char_t *)YAML_MAP_TAG,
1279                                                                     1, YAML_BLOCK_MAPPING_STYLE);
1280                                 rc = yaml_emitter_emit(&request, &event);
1281                                 if (rc == 0)
1282                                         goto emitter_error;
1283
1284                                 yaml_scalar_event_initialize(&event, NULL,
1285                                                              (yaml_char_t *)YAML_STR_TAG,
1286                                                              (yaml_char_t *)"status",
1287                                                              strlen("status"), 1, 0,
1288                                                              YAML_PLAIN_SCALAR_STYLE);
1289                                 rc = yaml_emitter_emit(&request, &event);
1290                                 if (rc == 0)
1291                                         goto emitter_error;
1292
1293                                 yaml_scalar_event_initialize(&event, NULL,
1294                                                              (yaml_char_t *)YAML_STR_TAG,
1295                                                              (yaml_char_t *)state,
1296                                                              strlen(state), 1, 0,
1297                                                              YAML_PLAIN_SCALAR_STYLE);
1298                                 rc = yaml_emitter_emit(&request, &event);
1299                                 if (rc == 0)
1300                                         goto emitter_error;
1301
1302                                 yaml_mapping_end_event_initialize(&event);
1303                                 rc = yaml_emitter_emit(&request, &event);
1304                                 if (rc == 0)
1305                                         goto emitter_error;
1306                         }
1307
1308                         yaml_sequence_end_event_initialize(&event);
1309                         rc = yaml_emitter_emit(&request, &event);
1310                         if (rc == 0)
1311                                 goto emitter_error;
1312                 } else {
1313                         yaml_scalar_event_initialize(&event, NULL,
1314                                                      (yaml_char_t *)YAML_STR_TAG,
1315                                                      (yaml_char_t *)"",
1316                                                      strlen(""), 1, 0,
1317                                                      YAML_PLAIN_SCALAR_STYLE);
1318                         rc = yaml_emitter_emit(&request, &event);
1319                         if (rc == 0)
1320                                 goto emitter_error;
1321                 }
1322
1323                 yaml_mapping_end_event_initialize(&event);
1324                 rc = yaml_emitter_emit(&request, &event);
1325                 if (rc == 0)
1326                         goto emitter_error;
1327
1328                 yaml_sequence_end_event_initialize(&event);
1329                 rc = yaml_emitter_emit(&request, &event);
1330                 if (rc == 0)
1331                         goto emitter_error;
1332         } else {
1333                 yaml_scalar_event_initialize(&event, NULL,
1334                                              (yaml_char_t *)YAML_STR_TAG,
1335                                              (yaml_char_t *)"",
1336                                              strlen(""), 1, 0,
1337                                              YAML_PLAIN_SCALAR_STYLE);
1338                 rc = yaml_emitter_emit(&request, &event);
1339                 if (rc == 0)
1340                         goto emitter_error;
1341         }
1342         yaml_mapping_end_event_initialize(&event);
1343         rc = yaml_emitter_emit(&request, &event);
1344         if (rc == 0)
1345                 goto emitter_error;
1346
1347         yaml_document_end_event_initialize(&event, 0);
1348         rc = yaml_emitter_emit(&request, &event);
1349         if (rc == 0)
1350                 goto emitter_error;
1351
1352         rc = yaml_emitter_close(&request);
1353         if (rc == 0) {
1354 emitter_error:
1355                 yaml_emitter_log_error(&request, stderr);
1356                 yaml_emitter_delete(&request);
1357                 rc = -EINVAL;
1358                 goto parser_error;
1359         }
1360         yaml_emitter_delete(&request);
1361
1362         /* display output */
1363         if (nlflags == NLM_F_DUMP)
1364                 rc = lst_yaml_display_groups(&reply, name, states, print);
1365 parser_error:
1366         if (rc == 0)
1367                 yaml_parser_log_error(&reply, stderr, NULL);
1368         yaml_parser_delete(&reply);
1369         nl_socket_free(sk);
1370
1371         if (print)
1372                 rc = rc == 1 ? 0 : -EINVAL;
1373
1374         return rc;
1375 }
1376
1377 int
1378 lst_ping_ioctl(char *str, int type, int timeout,
1379                int count, struct lnet_process_id *ids, struct list_head *head)
1380 {
1381         struct lstio_debug_args args = { 0 };
1382
1383         args.lstio_dbg_key     = session_key;
1384         args.lstio_dbg_type    = type;
1385         args.lstio_dbg_flags   = 0;
1386         args.lstio_dbg_timeout = timeout;
1387         args.lstio_dbg_nmlen   = (str == NULL) ? 0: strlen(str);
1388         args.lstio_dbg_namep   = str;
1389         args.lstio_dbg_count   = count;
1390         args.lstio_dbg_idsp    = ids;
1391         args.lstio_dbg_resultp = head;
1392
1393         return lst_ioctl (LSTIO_DEBUG, &args, sizeof(args));
1394 }
1395
1396 int
1397 lst_get_node_count(int type, char *str, int *countp,
1398                    struct lnet_process_id **idspp)
1399 {
1400         char                    buf[LST_NAME_SIZE];
1401         struct lstcon_test_batch_ent ent;
1402         struct lstcon_ndlist_ent    *entp = &ent.tbe_cli_nle;
1403         struct lst_sid sid;
1404         unsigned                feats;
1405         int                     key;
1406         int                     rc;
1407
1408         switch (type) {
1409         case LST_OPC_SESSION:
1410                 rc = lst_session_info_ioctl(buf, LST_NAME_SIZE,
1411                                             &key, &feats, &sid, entp);
1412                 break;
1413
1414         case LST_OPC_BATCHSRV:
1415                 entp = &ent.tbe_srv_nle;
1416         case LST_OPC_BATCHCLI:
1417                 rc = lst_info_batch_ioctl(str, 0, 0, &ent, NULL, NULL, NULL);
1418                 break;
1419
1420         case LST_OPC_GROUP:
1421                 rc = lst_yaml_groups(NLM_F_DUMP, NULL, 0, false);
1422                 if (rc == -EOPNOTSUPP) {
1423                         rc = lst_info_group_ioctl(str, entp, NULL, NULL, NULL);
1424                 } else if (rc > 0) {
1425                         entp->nle_nnode = rc;
1426                         rc = 0;
1427                 }
1428                 break;
1429
1430         case LST_OPC_NODES:
1431                 rc = lst_parse_nids(str, &entp->nle_nnode, idspp) < 0 ? -1 : 0;
1432                 break;
1433
1434         default:
1435                 rc = -1;
1436                 break;
1437         }
1438
1439         if (rc == 0)
1440                 *countp = entp->nle_nnode;
1441
1442         return rc;
1443 }
1444
1445 int
1446 jt_lst_ping(int argc,  char **argv)
1447 {
1448         struct list_head   head;
1449         struct lnet_process_id *ids = NULL;
1450         struct lstcon_rpc_ent  *ent = NULL;
1451         char              *str = NULL;
1452         int                optidx  = 0;
1453         int                server  = 0;
1454         int                timeout = 5;
1455         int                count   = 0;
1456         int                type    = 0;
1457         int                rc      = 0;
1458         int                c;
1459
1460         static const struct option ping_opts[] = {
1461                 { .name = "session", .has_arg = no_argument,       .val = 's' },
1462                 { .name = "server",  .has_arg = no_argument,       .val = 'v' },
1463                 { .name = "batch",   .has_arg = required_argument, .val = 'b' },
1464                 { .name = "group",   .has_arg = required_argument, .val = 'g' },
1465                 { .name = "nodes",   .has_arg = required_argument, .val = 'n' },
1466                 { .name = "timeout", .has_arg = required_argument, .val = 't' },
1467                 { .name = NULL, } };
1468
1469         if (session_key == 0) {
1470                 fprintf(stderr,
1471                         "Can't find env LST_SESSION or value is not valid\n");
1472                 return -1;
1473         }
1474
1475         while (1) {
1476
1477                 c = getopt_long(argc, argv, "g:b:n:t:sv",
1478                                 ping_opts, &optidx);
1479
1480                 if (c == -1)
1481                         break;
1482
1483                 switch (c) {
1484                 case 's':
1485                         type = LST_OPC_SESSION;
1486                         break;
1487
1488                 case 'g':
1489                         type = LST_OPC_GROUP;
1490                         str = optarg;
1491                         break;
1492
1493                 case 'b':
1494                         type = LST_OPC_BATCHCLI;
1495                         str = optarg;
1496                         break;
1497
1498                 case 'n':
1499                         type = LST_OPC_NODES;
1500                         str = optarg;
1501                         break;
1502
1503                 case 't':
1504                         timeout = atoi(optarg);
1505                         break;
1506
1507                 case 'v':
1508                         server = 1;
1509                         break;
1510
1511                 default:
1512                         lst_print_usage(argv[0]);
1513                         return -1;
1514                 }
1515         }
1516
1517         if (type == 0 || timeout <= 0 || optind != argc) {
1518                 lst_print_usage(argv[0]);
1519                 return -1;
1520         }
1521
1522         if (type == LST_OPC_BATCHCLI && server)
1523                 type = LST_OPC_BATCHSRV;
1524
1525         rc = lst_get_node_count(type, str, &count, &ids);
1526         if (rc < 0) {
1527                 fprintf(stderr, "Failed to get count of nodes from %s: %s\n",
1528                         (str == NULL) ? "session" : str, strerror(errno));
1529                 return -1;
1530         }
1531
1532         INIT_LIST_HEAD(&head);
1533
1534         rc = lst_alloc_rpcent(&head, count, LST_NAME_SIZE);
1535         if (rc != 0) {
1536                 fprintf(stderr, "Out of memory\n");
1537                 goto out;
1538         }
1539
1540         if (count == 0) {
1541                 fprintf(stdout, "Target %s is empty\n",
1542                         (str == NULL) ? "session" : str);
1543                 goto out;
1544         }
1545
1546         rc = lst_ping_ioctl(str, type, timeout, count, ids, &head);
1547         if (rc == -1) { /* local failure */
1548                 lst_print_error("debug", "Failed to ping %s: %s\n",
1549                                 (str == NULL) ? "session" : str,
1550                                 strerror(errno));
1551                 rc = -1;
1552                 goto out;
1553         }
1554
1555         /* ignore RPC errors and framwork errors */
1556         list_for_each_entry(ent, &head, rpe_link) {
1557                 fprintf(stdout, "\t%s: %s [session: %s id: %s]\n",
1558                         libcfs_id2str(ent->rpe_peer),
1559                         lst_node_state2str(ent->rpe_state),
1560                         (ent->rpe_state == LST_NODE_ACTIVE ||
1561                          ent->rpe_state == LST_NODE_BUSY) ?
1562                                 (ent->rpe_rpc_errno == 0 ?
1563                                         &ent->rpe_payload[0] : "Unknown") :
1564                                 "<NULL>", libcfs_nid2str(ent->rpe_sid.ses_nid));
1565         }
1566
1567 out:
1568         lst_free_rpcent(&head);
1569
1570         if (ids != NULL)
1571                 free(ids);
1572
1573         return rc;
1574
1575 }
1576
1577 int
1578 lst_add_nodes_ioctl(char *name, int count, struct lnet_process_id *ids,
1579                     unsigned *featp, struct list_head *resultp)
1580 {
1581         struct lstio_group_nodes_args args = { 0 };
1582
1583         args.lstio_grp_key     = session_key;
1584         args.lstio_grp_nmlen   = strlen(name);
1585         args.lstio_grp_namep   = name;
1586         args.lstio_grp_count   = count;
1587         args.lstio_grp_featp   = featp;
1588         args.lstio_grp_idsp    = ids;
1589         args.lstio_grp_resultp = resultp;
1590
1591         return lst_ioctl(LSTIO_NODES_ADD, &args, sizeof(args));
1592 }
1593
1594 int
1595 lst_del_group_ioctl(char *name)
1596 {
1597         struct lstio_group_del_args args = { 0 };
1598
1599         args.lstio_grp_key   = session_key;
1600         args.lstio_grp_nmlen = strlen(name);
1601         args.lstio_grp_namep = name;
1602
1603         return lst_ioctl(LSTIO_GROUP_DEL, &args, sizeof(args));
1604 }
1605
1606 int
1607 lst_del_group(char *grp_name)
1608 {
1609         int     rc;
1610
1611         rc = lst_del_group_ioctl(grp_name);
1612         if (rc == 0) {
1613                 fprintf(stdout, "Group is deleted\n");
1614                 return 0;
1615         }
1616
1617         if (rc == -1) {
1618                 lst_print_error("group", "Failed to delete group: %s\n",
1619                                 strerror(errno));
1620                 return rc;
1621         }
1622
1623         fprintf(stderr, "Group is deleted with some errors\n");
1624
1625         if (trans_stat.trs_rpc_errno != 0) {
1626                 fprintf(stderr,
1627                         "[RPC] Failed to send %d end session RPCs: %s\n",
1628                         lstcon_rpc_stat_failure(&trans_stat, 0),
1629                         strerror(trans_stat.trs_rpc_errno));
1630         }
1631
1632         if (trans_stat.trs_fwk_errno != 0) {
1633                 fprintf(stderr,
1634                         "[FWK] Failed to end session on %d nodes: %s\n",
1635                 lstcon_sesop_stat_failure(&trans_stat, 0),
1636                 strerror(trans_stat.trs_fwk_errno));
1637         }
1638
1639         return -1;
1640 }
1641
1642 int
1643 lst_add_group_ioctl(char *name)
1644 {
1645         struct lstio_group_add_args args = { 0 };
1646
1647         args.lstio_grp_key     =  session_key;
1648         args.lstio_grp_nmlen   =  strlen(name);
1649         args.lstio_grp_namep   =  name;
1650
1651         return lst_ioctl(LSTIO_GROUP_ADD, &args, sizeof(args));
1652 }
1653
1654 int
1655 jt_lst_add_group(int argc, char **argv)
1656 {
1657         struct list_head   head;
1658         struct lnet_process_id *ids;
1659         char              *name;
1660         unsigned           feats = session_features;
1661         int                count;
1662         int                rc;
1663         int                i;
1664         bool               nodes_added = false;
1665
1666         if (session_key == 0) {
1667                 fprintf(stderr,
1668                         "Can't find env LST_SESSION or value is not valid\n");
1669                 return -1;
1670         }
1671
1672         if (argc < 3) {
1673                 lst_print_usage(argv[0]);
1674                 return -1;
1675         }
1676
1677         name = argv[1];
1678         if (strlen(name) >= LST_NAME_SIZE) {
1679                 fprintf(stderr, "Name length is limited to %d\n",
1680                         LST_NAME_SIZE - 1);
1681                 return -1;
1682         }
1683
1684         rc = lst_add_group_ioctl(name);
1685         if (rc != 0) {
1686                 lst_print_error("group", "Failed to add group %s: %s\n",
1687                                 name, strerror(errno));
1688                 return -1;
1689         }
1690
1691         INIT_LIST_HEAD(&head);
1692
1693         for (i = 2; i < argc; i++) {
1694                 /* parse address list */
1695                 rc = lst_parse_nids(argv[i], &count, &ids);
1696                 if (rc < 0) {
1697                         fprintf(stderr, "Ignore invalid id list %s\n",
1698                                 argv[i]);
1699                         continue;
1700                 }
1701
1702                 if (count == 0)
1703                         continue;
1704
1705                 rc = lst_alloc_rpcent(&head, count, 0);
1706                 if (rc != 0) {
1707                         fprintf(stderr, "Out of memory\n");
1708                         free(ids);
1709                         rc = -1;
1710                         goto failed;
1711                 }
1712
1713                 rc = lst_add_nodes_ioctl(name, count, ids, &feats, &head);
1714
1715                 free(ids);
1716
1717                 if (rc != 0)
1718                         goto failed;
1719
1720                 fprintf(stdout, "%s are added to session\n", argv[i]);
1721
1722                 nodes_added = true;
1723
1724                 if ((feats & session_features) != session_features) {
1725                         fprintf(stdout,
1726                                 "Warning, this session will run with "
1727                                 "compatible mode because some test nodes "
1728                                 "might not understand these features: %x\n",
1729                                 (~feats & session_features));
1730                 }
1731
1732                 lst_free_rpcent(&head);
1733         }
1734
1735         if (!nodes_added) {
1736                 /*
1737                  * The selftest kernel module expects that a group should
1738                  * have at least one node, since it doesn't make sense for
1739                  * an empty group to be added to a test.
1740                  */
1741                 fprintf(stderr,
1742                         "No nodes added successfully, deleting group %s\n",
1743                         name);
1744                 rc = lst_del_group(name);
1745                 if (rc != 0) {
1746                         fprintf(stderr,
1747                                 "Failed to delete group %s."
1748                                 "  Group is empty.\n", name);
1749                 }
1750         }
1751
1752         return rc;
1753
1754 failed:
1755         if (rc == -1) {
1756                 lst_print_error("group", "Failed to add nodes %s: %s\n",
1757                                 argv[i], strerror(errno));
1758
1759         } else {
1760                 if (trans_stat.trs_fwk_errno == EPROTO) {
1761                         fprintf(stderr,
1762                                 "test nodes might have different LST "
1763                                 "features, please disable some features by "
1764                                 "setting LST_FEATURES\n");
1765                 }
1766
1767                 lst_print_transerr(&head, "create session");
1768         }
1769
1770         lst_free_rpcent(&head);
1771
1772         if (!nodes_added) {
1773                 fprintf(stderr,
1774                         "No nodes added successfully, deleting group %s\n",
1775                         name);
1776                 if (lst_del_group(name) != 0) {
1777                         fprintf(stderr,
1778                                 "Failed to delete group %s."
1779                                 "  Group is empty.\n", name);
1780                 }
1781         }
1782
1783         return rc;
1784 }
1785
1786 int
1787 jt_lst_del_group(int argc, char **argv)
1788 {
1789         int     rc;
1790
1791         if (session_key == 0) {
1792                 fprintf(stderr,
1793                         "Can't find env LST_SESSION or value is not valid\n");
1794                 return -1;
1795         }
1796
1797         if (argc != 2) {
1798                 lst_print_usage(argv[0]);
1799                 return -1;
1800         }
1801
1802         rc = lst_del_group(argv[1]);
1803
1804         return rc;
1805 }
1806
1807 int
1808 lst_update_group_ioctl(int opc, char *name, int clean, int count,
1809                        struct lnet_process_id *ids, struct list_head *resultp)
1810 {
1811         struct lstio_group_update_args args = { 0 };
1812
1813         args.lstio_grp_key      = session_key;
1814         args.lstio_grp_opc      = opc;
1815         args.lstio_grp_args     = clean;
1816         args.lstio_grp_nmlen    = strlen(name);
1817         args.lstio_grp_namep    = name;
1818         args.lstio_grp_count    = count;
1819         args.lstio_grp_idsp     = ids;
1820         args.lstio_grp_resultp  = resultp;
1821
1822         return lst_ioctl(LSTIO_GROUP_UPDATE, &args, sizeof(args));
1823 }
1824
1825 int
1826 jt_lst_update_group(int argc, char **argv)
1827 {
1828         struct list_head   head;
1829         struct lnet_process_id *ids = NULL;
1830         char              *str = NULL;
1831         char              *grp = NULL;
1832         int                optidx = 0;
1833         int                count = 0;
1834         int                clean = 0;
1835         int                opc = 0;
1836         int                rc;
1837         int                c;
1838
1839         static const struct option update_group_opts[] = {
1840                 { .name = "refresh", .has_arg = no_argument,       .val = 'f' },
1841                 { .name = "clean",   .has_arg = required_argument, .val = 'c' },
1842                 { .name = "remove",  .has_arg = required_argument, .val = 'r' },
1843                 { .name = NULL } };
1844
1845         if (session_key == 0) {
1846                 fprintf(stderr,
1847                         "Can't find env LST_SESSION or value is not valid\n");
1848                 return -1;
1849         }
1850
1851         while (1) {
1852                 c = getopt_long(argc, argv, "fc:r:",
1853                                 update_group_opts, &optidx);
1854
1855                 /* Detect the end of the options. */
1856                 if (c == -1)
1857                         break;
1858
1859                 switch (c) {
1860                 case 'f':
1861                         if (opc != 0) {
1862                                 lst_print_usage(argv[0]);
1863                                 return -1;
1864                         }
1865                         opc = LST_GROUP_REFRESH;
1866                         break;
1867
1868                 case 'r':
1869                         if (opc != 0) {
1870                                 lst_print_usage(argv[0]);
1871                                 return -1;
1872                         }
1873                         opc = LST_GROUP_RMND;
1874                         str = optarg;
1875                         break;
1876
1877                 case 'c':
1878                         clean = lst_node_str2state(optarg);
1879                         if (opc != 0 || clean <= 0) {
1880                                 lst_print_usage(argv[0]);
1881                                 return -1;
1882                         }
1883                         opc = LST_GROUP_CLEAN;
1884                         break;
1885
1886                 default:
1887                         lst_print_usage(argv[0]);
1888                         return -1;
1889                 }
1890         }
1891
1892         /* no OPC or group is specified */
1893         if (opc == 0 || optind != argc - 1) {
1894                 lst_print_usage(argv[0]);
1895                 return -1;
1896         }
1897
1898         grp = argv[optind];
1899
1900         INIT_LIST_HEAD(&head);
1901
1902         if (opc == LST_GROUP_RMND || opc == LST_GROUP_REFRESH) {
1903                 rc = lst_get_node_count(opc == LST_GROUP_RMND ? LST_OPC_NODES :
1904                                                                 LST_OPC_GROUP,
1905                                         opc == LST_GROUP_RMND ? str : grp,
1906                                         &count, &ids);
1907
1908                 if (rc != 0) {
1909                         fprintf(stderr, "Can't get count of nodes from %s: %s\n",
1910                                 opc == LST_GROUP_RMND ? str : grp,
1911                                 strerror(errno));
1912                         return -1;
1913                 }
1914
1915                 rc = lst_alloc_rpcent(&head, count, 0);
1916                 if (rc != 0) {
1917                         fprintf(stderr, "Out of memory\n");
1918                         free(ids);
1919                         return -1;
1920                 }
1921
1922         }
1923
1924         rc = lst_update_group_ioctl(opc, grp, clean, count, ids, &head);
1925
1926         if (ids != NULL)
1927                 free(ids);
1928
1929         if (rc == 0) {
1930                 lst_free_rpcent(&head);
1931                 return 0;
1932         }
1933
1934         if (rc == -1) {
1935                 lst_free_rpcent(&head);
1936                 lst_print_error("group", "Failed to update group: %s\n",
1937                                 strerror(errno));
1938                 return rc;
1939         }
1940
1941         lst_print_transerr(&head, "Updating group");
1942
1943         lst_free_rpcent(&head);
1944
1945         return rc;
1946 }
1947
1948 int
1949 lst_list_group_ioctl(int len, char *name, int idx)
1950 {
1951         struct lstio_group_list_args args = { 0 };
1952
1953         args.lstio_grp_key   = session_key;
1954         args.lstio_grp_idx   = idx;
1955         args.lstio_grp_nmlen = len;
1956         args.lstio_grp_namep = name;
1957
1958         return lst_ioctl(LSTIO_GROUP_LIST, &args, sizeof(args));
1959 }
1960
1961 int
1962 lst_info_group_ioctl(char *name, struct lstcon_ndlist_ent *gent,
1963                      int *idx, int *count, struct lstcon_node_ent *dents)
1964 {
1965         struct lstio_group_info_args args = { 0 };
1966
1967         args.lstio_grp_key    = session_key;
1968         args.lstio_grp_nmlen  = strlen(name);
1969         args.lstio_grp_namep  = name;
1970         args.lstio_grp_entp   = gent;
1971         args.lstio_grp_idxp   = idx;
1972         args.lstio_grp_ndentp = count;
1973         args.lstio_grp_dentsp = dents;
1974
1975         return lst_ioctl(LSTIO_GROUP_INFO, &args, sizeof(args));
1976 }
1977
1978 int
1979 lst_list_group_all(void)
1980 {
1981         char  name[LST_NAME_SIZE];
1982         int   rc;
1983         int   i;
1984
1985         /* no group is specified, list name of all groups */
1986         for (i = 0; ; i++) {
1987                 rc = lst_list_group_ioctl(LST_NAME_SIZE, name, i);
1988                 if (rc == 0) {
1989                         fprintf(stdout, "%d) %s\n", i + 1, name);
1990                         continue;
1991                 }
1992
1993                 if (errno == ENOENT)
1994                         break;
1995
1996                 lst_print_error("group", "Failed to list group: %s\n",
1997                                 strerror(errno));
1998                 return -1;
1999         }
2000
2001         fprintf(stdout, "Total %d groups\n", i);
2002
2003         return 0;
2004 }
2005
2006 int
2007 jt_lst_list_group(int argc, char **argv)
2008 {
2009         struct lstcon_ndlist_ent gent;
2010         struct lstcon_node_ent   *dents;
2011         int states = 0;
2012         int optidx  = 0;
2013         int verbose = 0;
2014         int active  = 0;
2015         int busy    = 0;
2016         int down    = 0;
2017         int unknown = 0;
2018         int all     = 0;
2019         int count;
2020         int index;
2021         int i;
2022         int j;
2023         int c;
2024         int rc      = 0;
2025         static const struct option list_group_opts[] = {
2026                 { .name = "active",  .has_arg = no_argument, .val = 'a' },
2027                 { .name = "busy",    .has_arg = no_argument, .val = 'b' },
2028                 { .name = "down",    .has_arg = no_argument, .val = 'd' },
2029                 { .name = "unknown", .has_arg = no_argument, .val = 'u' },
2030                 { .name = "all",     .has_arg = no_argument, .val = 'l' },
2031                 { .name = NULL, } };
2032
2033         if (session_key == 0) {
2034                 fprintf(stderr,
2035                         "Can't find env LST_SESSION or value is not valid\n");
2036                 return -1;
2037         }
2038
2039         while (1) {
2040                 c = getopt_long(argc, argv, "abdul",
2041                                 list_group_opts, &optidx);
2042
2043                 if (c == -1)
2044                         break;
2045
2046                 switch (c) {
2047                 case 'a':
2048                         verbose = active = 1;
2049                         states |= LST_NODE_ACTIVE;
2050                         all = 0;
2051                         break;
2052                 case 'b':
2053                         verbose = busy = 1;
2054                         states |= LST_NODE_BUSY;
2055                         all = 0;
2056                         break;
2057                 case 'd':
2058                         verbose = down = 1;
2059                         states |= LST_NODE_DOWN;
2060                         all = 0;
2061                         break;
2062                 case 'u':
2063                         verbose = unknown = 1;
2064                         states |= LST_NODE_UNKNOWN;
2065                         all = 0;
2066                         break;
2067                 case 'l':
2068                         states |= LST_NODE_ACTIVE | LST_NODE_BUSY |
2069                                   LST_NODE_DOWN | LST_NODE_UNKNOWN;
2070                         verbose = all = 1;
2071                         break;
2072                 default:
2073                         lst_print_usage(argv[0]);
2074                         return -1;
2075                 }
2076         }
2077
2078         if (optind == argc) {
2079                 rc = lst_yaml_groups(NLM_F_DUMP, NULL, 0, true);
2080                 if (rc <= 0) {
2081                         if (rc == -EOPNOTSUPP)
2082                                 goto old_api;
2083                         return rc;
2084                 }
2085         } else {
2086                 for (i = optind; i < argc; i++) {
2087                         rc = lst_yaml_groups(NLM_F_DUMP, argv[i], states,
2088                                              i == optind ? true : false);
2089                         if (rc < 0) {
2090                                 if (rc == -EOPNOTSUPP)
2091                                         goto old_api;
2092                                 return rc;
2093                         }
2094                 }
2095                 return 0;
2096         }
2097 old_api:
2098         if (optind == argc) {
2099                 /* no group is specified, list name of all groups */
2100                 rc = lst_list_group_all();
2101
2102                 return rc;
2103         }
2104
2105         if (!verbose)
2106                 fprintf(stdout, LST_NODES_TITLE);
2107
2108         /* list nodes in specified groups */
2109         for (i = optind; i < argc; i++) {
2110                 rc = lst_info_group_ioctl(argv[i], &gent, NULL, NULL, NULL);
2111                 if (rc != 0) {
2112                         if (errno == ENOENT) {
2113                                 rc = 0;
2114                                 break;
2115                         }
2116
2117                         lst_print_error("group", "Failed to list group\n",
2118                                         strerror(errno));
2119                         break;
2120                 }
2121
2122                 if (!verbose) {
2123                         fprintf(stdout, "\t%d\t%d\t%d\t%d\t%d\t%s\n",
2124                                 gent.nle_nactive, gent.nle_nbusy,
2125                                 gent.nle_ndown, gent.nle_nunknown,
2126                                 gent.nle_nnode, argv[i]);
2127                         continue;
2128                 }
2129
2130                 fprintf(stdout, "Group [ %s ]\n", argv[i]);
2131
2132                 if (gent.nle_nnode == 0) {
2133                         fprintf(stdout, "No nodes found [ %s ]\n", argv[i]);
2134                         continue;
2135                 }
2136
2137                 count = gent.nle_nnode;
2138
2139                 dents = malloc(count * sizeof(struct lstcon_node_ent));
2140                 if (dents == NULL) {
2141                         fprintf(stderr, "Failed to malloc: %s\n",
2142                                 strerror(errno));
2143                         return -1;
2144                 }
2145
2146                 index = 0;
2147                 rc = lst_info_group_ioctl(argv[i], &gent, &index, &count, dents);
2148                 if (rc != 0) {
2149                         lst_print_error("group", "Failed to list group: %s\n",
2150                                         strerror(errno));
2151                         free(dents);
2152                         return -1;
2153                 }
2154
2155                 for (j = 0, c = 0; j < count; j++) {
2156                         if (all ||
2157                             ((active  &&  dents[j].nde_state == LST_NODE_ACTIVE) ||
2158                              (busy    &&  dents[j].nde_state == LST_NODE_BUSY)   ||
2159                              (down    &&  dents[j].nde_state == LST_NODE_DOWN)   ||
2160                              (unknown &&  dents[j].nde_state == LST_NODE_UNKNOWN))) {
2161
2162                                 fprintf(stdout, "\t%s: %s\n",
2163                                         libcfs_id2str(dents[j].nde_id),
2164                                         lst_node_state2str(dents[j].nde_state));
2165                                 c++;
2166                         }
2167                 }
2168
2169                 fprintf(stdout, "Total %d nodes [ %s ]\n", c, argv[i]);
2170
2171                 free(dents);
2172         }
2173
2174         return rc;
2175 }
2176
2177 int
2178 lst_stat_ioctl(char *name, int count, struct lnet_process_id *idsp,
2179                int timeout, struct list_head *resultp)
2180 {
2181         struct lstio_stat_args args = { 0 };
2182
2183         args.lstio_sta_key     = session_key;
2184         args.lstio_sta_timeout = timeout;
2185         args.lstio_sta_nmlen   = strlen(name);
2186         args.lstio_sta_namep   = name;
2187         args.lstio_sta_count   = count;
2188         args.lstio_sta_idsp    = idsp;
2189         args.lstio_sta_resultp = resultp;
2190
2191         return lst_ioctl(LSTIO_STAT_QUERY, &args, sizeof(args));
2192 }
2193
2194 typedef struct {
2195         struct list_head              srp_link;
2196         int                     srp_count;
2197         char                   *srp_name;
2198         struct lnet_process_id      *srp_ids;
2199         struct list_head              srp_result[2];
2200 } lst_stat_req_param_t;
2201
2202 static void
2203 lst_stat_req_param_free(lst_stat_req_param_t *srp)
2204 {
2205         int     i;
2206
2207         for (i = 0; i < 2; i++)
2208                 lst_free_rpcent(&srp->srp_result[i]);
2209
2210         if (srp->srp_ids != NULL)
2211                 free(srp->srp_ids);
2212
2213         free(srp);
2214 }
2215
2216 static int
2217 lst_stat_req_param_alloc(char *name, lst_stat_req_param_t **srpp, int save_old)
2218 {
2219         lst_stat_req_param_t *srp = NULL;
2220         int                   count = save_old ? 2 : 1;
2221         int                   rc;
2222         int                   i;
2223
2224         srp = malloc(sizeof(*srp));
2225         if (srp == NULL)
2226                 return -ENOMEM;
2227
2228         memset(srp, 0, sizeof(*srp));
2229         INIT_LIST_HEAD(&srp->srp_result[0]);
2230         INIT_LIST_HEAD(&srp->srp_result[1]);
2231
2232         rc = lst_get_node_count(LST_OPC_GROUP, name,
2233                                 &srp->srp_count, NULL);
2234         if (rc != 0 && errno == ENOENT) {
2235                 rc = lst_get_node_count(LST_OPC_NODES, name,
2236                                         &srp->srp_count, &srp->srp_ids);
2237         }
2238
2239         if (rc != 0) {
2240                 fprintf(stderr,
2241                         "Failed to get count of nodes from %s: %s\n",
2242                         name, strerror(errno));
2243                 lst_stat_req_param_free(srp);
2244
2245                 return rc;
2246         }
2247
2248         srp->srp_name = name;
2249
2250         for (i = 0; i < count; i++) {
2251                 rc = lst_alloc_rpcent(&srp->srp_result[i], srp->srp_count,
2252                                       sizeof(struct sfw_counters)  +
2253                                       sizeof(struct srpc_counters) +
2254                                       sizeof(struct lnet_counters_common));
2255                 if (rc != 0) {
2256                         fprintf(stderr, "Out of memory\n");
2257                         break;
2258                 }
2259         }
2260
2261         if (rc == 0) {
2262                 *srpp = srp;
2263                 return 0;
2264         }
2265
2266         lst_stat_req_param_free(srp);
2267
2268         return rc;
2269 }
2270
2271 typedef struct {
2272         /* TODO */
2273         int foo;
2274 } lst_srpc_stat_result;
2275
2276 #define LST_LNET_AVG    0
2277 #define LST_LNET_MIN    1
2278 #define LST_LNET_MAX    2
2279
2280 typedef struct {
2281         float           lnet_avg_sndrate;
2282         float           lnet_min_sndrate;
2283         float           lnet_max_sndrate;
2284         float           lnet_total_sndrate;
2285
2286         float           lnet_avg_rcvrate;
2287         float           lnet_min_rcvrate;
2288         float           lnet_max_rcvrate;
2289         float           lnet_total_rcvrate;
2290
2291         float           lnet_avg_sndperf;
2292         float           lnet_min_sndperf;
2293         float           lnet_max_sndperf;
2294         float           lnet_total_sndperf;
2295
2296         float           lnet_avg_rcvperf;
2297         float           lnet_min_rcvperf;
2298         float           lnet_max_rcvperf;
2299         float           lnet_total_rcvperf;
2300
2301         int             lnet_stat_count;
2302 } lst_lnet_stat_result_t;
2303
2304 lst_lnet_stat_result_t lnet_stat_result;
2305
2306 static float
2307 lst_lnet_stat_value(int bw, int send, int off)
2308 {
2309         float  *p;
2310
2311         p = bw ? &lnet_stat_result.lnet_avg_sndperf :
2312                  &lnet_stat_result.lnet_avg_sndrate;
2313
2314         if (!send)
2315                 p += 4;
2316
2317         p += off;
2318
2319         return *p;
2320 }
2321
2322 static void
2323 lst_cal_lnet_stat(float delta, struct lnet_counters_common *lnet_new,
2324                   struct lnet_counters_common *lnet_old, int mbs)
2325 {
2326         float perf;
2327         float rate;
2328         unsigned int unit_divisor;
2329
2330         unit_divisor = (mbs) ? (1000 * 1000) : (1024 * 1024);
2331         perf = (float)(lnet_new->lcc_send_length -
2332                        lnet_old->lcc_send_length) / unit_divisor / delta;
2333         lnet_stat_result.lnet_total_sndperf += perf;
2334
2335         if (lnet_stat_result.lnet_min_sndperf > perf ||
2336             lnet_stat_result.lnet_min_sndperf == 0)
2337                 lnet_stat_result.lnet_min_sndperf = perf;
2338
2339         if (lnet_stat_result.lnet_max_sndperf < perf)
2340                 lnet_stat_result.lnet_max_sndperf = perf;
2341
2342         perf = (float)(lnet_new->lcc_recv_length -
2343                        lnet_old->lcc_recv_length) / unit_divisor / delta;
2344         lnet_stat_result.lnet_total_rcvperf += perf;
2345
2346         if (lnet_stat_result.lnet_min_rcvperf > perf ||
2347             lnet_stat_result.lnet_min_rcvperf == 0)
2348                 lnet_stat_result.lnet_min_rcvperf = perf;
2349
2350         if (lnet_stat_result.lnet_max_rcvperf < perf)
2351                 lnet_stat_result.lnet_max_rcvperf = perf;
2352
2353         rate = (lnet_new->lcc_send_count - lnet_old->lcc_send_count) / delta;
2354         lnet_stat_result.lnet_total_sndrate += rate;
2355
2356         if (lnet_stat_result.lnet_min_sndrate > rate ||
2357             lnet_stat_result.lnet_min_sndrate == 0)
2358                 lnet_stat_result.lnet_min_sndrate = rate;
2359
2360         if (lnet_stat_result.lnet_max_sndrate < rate)
2361                 lnet_stat_result.lnet_max_sndrate = rate;
2362
2363         rate = (lnet_new->lcc_recv_count - lnet_old->lcc_recv_count) / delta;
2364         lnet_stat_result.lnet_total_rcvrate += rate;
2365
2366         if (lnet_stat_result.lnet_min_rcvrate > rate ||
2367             lnet_stat_result.lnet_min_rcvrate == 0)
2368                 lnet_stat_result.lnet_min_rcvrate = rate;
2369
2370         if (lnet_stat_result.lnet_max_rcvrate < rate)
2371                 lnet_stat_result.lnet_max_rcvrate = rate;
2372
2373         lnet_stat_result.lnet_stat_count++;
2374
2375         lnet_stat_result.lnet_avg_sndrate = lnet_stat_result.lnet_total_sndrate /
2376                                             lnet_stat_result.lnet_stat_count;
2377         lnet_stat_result.lnet_avg_rcvrate = lnet_stat_result.lnet_total_rcvrate /
2378                                             lnet_stat_result.lnet_stat_count;
2379
2380         lnet_stat_result.lnet_avg_sndperf = lnet_stat_result.lnet_total_sndperf /
2381                                             lnet_stat_result.lnet_stat_count;
2382         lnet_stat_result.lnet_avg_rcvperf = lnet_stat_result.lnet_total_rcvperf /
2383                                             lnet_stat_result.lnet_stat_count;
2384 }
2385
2386 static void
2387 lst_print_lnet_stat(char *name, int bwrt, int rdwr, int type, int mbs)
2388 {
2389         int     start1 = 0;
2390         int     end1   = 1;
2391         int     start2 = 0;
2392         int     end2   = 1;
2393         int     i;
2394         int     j;
2395         char   *units;
2396
2397         if (lnet_stat_result.lnet_stat_count == 0)
2398                 return;
2399
2400         units = (mbs) ? "MB/s  " : "MiB/s ";
2401
2402         if (bwrt == 1) /* bw only */
2403                 start1 = 1;
2404
2405         if (bwrt == 2) /* rates only */
2406                 end1 = 0;
2407
2408         if (rdwr == 1) /* recv only */
2409                 start2 = 1;
2410
2411         if (rdwr == 2) /* send only */
2412                 end2 = 0;
2413
2414         for (i = start1; i <= end1; i++) {
2415                 fprintf(stdout, "[LNet %s of %s]\n",
2416                         i == 0 ? "Rates" : "Bandwidth", name);
2417
2418                 for (j = start2; j <= end2; j++) {
2419                         fprintf(stdout, "[%c] ", j == 0 ? 'R' : 'W');
2420
2421                         if ((type & 1) != 0) {
2422                                 fprintf(stdout, i == 0 ? "Avg: %-8.0f RPC/s " :
2423                                                          "Avg: %-8.2f %s",
2424                                         lst_lnet_stat_value(i, j, 0), units);
2425                         }
2426
2427                         if ((type & 2) != 0) {
2428                                 fprintf(stdout, i == 0 ? "Min: %-8.0f RPC/s " :
2429                                                          "Min: %-8.2f %s",
2430                                         lst_lnet_stat_value(i, j, 1), units);
2431                         }
2432
2433                         if ((type & 4) != 0) {
2434                                 fprintf(stdout, i == 0 ? "Max: %-8.0f RPC/s" :
2435                                                          "Max: %-8.2f %s",
2436                                         lst_lnet_stat_value(i, j, 2), units);
2437                         }
2438
2439                         fprintf(stdout, "\n");
2440                 }
2441         }
2442 }
2443
2444 static void
2445 lst_print_stat(char *name, struct list_head *resultp,
2446                int idx, int lnet, int bwrt, int rdwr, int type,
2447                int mbs)
2448 {
2449         struct list_head tmp[2];
2450         struct lstcon_rpc_ent *new;
2451         struct lstcon_rpc_ent *old;
2452         struct sfw_counters *sfwk_new;
2453         struct sfw_counters *sfwk_old;
2454         struct srpc_counters *srpc_new;
2455         struct srpc_counters *srpc_old;
2456         struct lnet_counters_common *lnet_new;
2457         struct lnet_counters_common *lnet_old;
2458         float delta;
2459         int errcount = 0;
2460
2461         INIT_LIST_HEAD(&tmp[0]);
2462         INIT_LIST_HEAD(&tmp[1]);
2463
2464         memset(&lnet_stat_result, 0, sizeof(lnet_stat_result));
2465
2466         while (!list_empty(&resultp[idx])) {
2467                 if (list_empty(&resultp[1 - idx])) {
2468                         fprintf(stderr, "Group is changed, re-run stat\n");
2469                         break;
2470                 }
2471
2472                 new = list_first_entry(&resultp[idx], struct lstcon_rpc_ent,
2473                                        rpe_link);
2474                 old = list_first_entry(&resultp[1 - idx], struct lstcon_rpc_ent,
2475                                        rpe_link);
2476
2477                 /* first time get stats result, can't calculate diff */
2478                 if (new->rpe_peer.nid == LNET_NID_ANY)
2479                         break;
2480
2481                 if (new->rpe_peer.nid != old->rpe_peer.nid ||
2482                     new->rpe_peer.pid != old->rpe_peer.pid) {
2483                         /* Something wrong. i.e, somebody change the group */
2484                         break;
2485                 }
2486
2487                 list_move_tail(&new->rpe_link, &tmp[idx]);
2488
2489                 list_move_tail(&old->rpe_link, &tmp[1 - idx]);
2490
2491                 if (new->rpe_rpc_errno != 0 || new->rpe_fwk_errno != 0 ||
2492                     old->rpe_rpc_errno != 0 || old->rpe_fwk_errno != 0) {
2493                         errcount++;
2494                         continue;
2495                 }
2496
2497                 sfwk_new = (struct sfw_counters *)&new->rpe_payload[0];
2498                 sfwk_old = (struct sfw_counters *)&old->rpe_payload[0];
2499
2500                 srpc_new = (struct srpc_counters *)((char *)sfwk_new +
2501                                                     sizeof(*sfwk_new));
2502                 srpc_old = (struct srpc_counters *)((char *)sfwk_old +
2503                                                     sizeof(*sfwk_old));
2504
2505                 lnet_new = (struct lnet_counters_common *)((char *)srpc_new +
2506                                                            sizeof(*srpc_new));
2507                 lnet_old = (struct lnet_counters_common *)((char *)srpc_old +
2508                                                            sizeof(*srpc_old));
2509
2510                 /* Prior to version 2.3, the running_ms was a counter for
2511                  * the number of running tests. Since 2.3, running_ms is
2512                  * changed to hold the millisecond since the start of
2513                  * the work item. The rpe_stamp field was formerly used,
2514                  * but is no longer. In 2.12 rpe_stamp was changed to
2515                  * struct timespec64 and has nanosecond resolution, in
2516                  * case it is needed in the future.
2517                  */
2518                 delta = (float)(sfwk_new->running_ms -
2519                                 sfwk_old->running_ms) / 1000;
2520
2521                 if (!lnet) /* TODO */
2522                         continue;
2523
2524                 lst_cal_lnet_stat(delta, lnet_new, lnet_old, mbs);
2525         }
2526
2527         list_splice(&tmp[idx], &resultp[idx]);
2528         list_splice(&tmp[1 - idx], &resultp[1 - idx]);
2529
2530         if (errcount > 0)
2531                 fprintf(stdout, "Failed to stat on %d nodes\n", errcount);
2532
2533         if (!lnet)  /* TODO */
2534                 return;
2535
2536         lst_print_lnet_stat(name, bwrt, rdwr, type, mbs);
2537 }
2538
2539 int
2540 jt_lst_stat(int argc, char **argv)
2541 {
2542         struct list_head        head;
2543         lst_stat_req_param_t *srp;
2544         time_t                last    = 0;
2545         int                   optidx  = 0;
2546         int                   timeout = 5; /* default timeout, 5 sec */
2547         int                   delay   = 5; /* default delay, 5 sec */
2548         int                   count   = -1; /* run forever */
2549         int                   lnet    = 1; /* lnet stat by default */
2550         int                   bwrt    = 0;
2551         int                   rdwr    = 0;
2552         int                   type    = -1;
2553         int                   idx     = 0;
2554         int                   rc;
2555         int                   c;
2556         int                   mbs     = 0; /* report as MB/s */
2557
2558         static const struct option stat_opts[] = {
2559                 { .name = "timeout", .has_arg = required_argument, .val = 't' },
2560                 { .name = "delay",   .has_arg = required_argument, .val = 'd' },
2561                 { .name = "count",   .has_arg = required_argument, .val = 'o' },
2562                 { .name = "lnet",    .has_arg = no_argument,       .val = 'l' },
2563                 { .name = "rpc",     .has_arg = no_argument,       .val = 'c' },
2564                 { .name = "bw",      .has_arg = no_argument,       .val = 'b' },
2565                 { .name = "rate",    .has_arg = no_argument,       .val = 'a' },
2566                 { .name = "read",    .has_arg = no_argument,       .val = 'r' },
2567                 { .name = "write",   .has_arg = no_argument,       .val = 'w' },
2568                 { .name = "avg",     .has_arg = no_argument,       .val = 'g' },
2569                 { .name = "min",     .has_arg = no_argument,       .val = 'n' },
2570                 { .name = "max",     .has_arg = no_argument,       .val = 'x' },
2571                 { .name = "mbs",     .has_arg = no_argument,       .val = 'm' },
2572                 { .name = NULL } };
2573
2574         if (session_key == 0) {
2575                 fprintf(stderr,
2576                         "Can't find env LST_SESSION or value is not valid\n");
2577                 return -1;
2578         }
2579
2580         while (1) {
2581                 c = getopt_long(argc, argv, "t:d:lcbarwgnxm", stat_opts,
2582                                 &optidx);
2583
2584                 if (c == -1)
2585                         break;
2586
2587                 switch (c) {
2588                 case 't':
2589                         timeout = atoi(optarg);
2590                         break;
2591                 case 'd':
2592                         delay = atoi(optarg);
2593                         break;
2594                 case 'o':
2595                         count = atoi(optarg);
2596                         break;
2597                 case 'l':
2598                         lnet = 1;
2599                         break;
2600                 case 'c':
2601                         lnet = 0;
2602                         break;
2603                 case 'b':
2604                         bwrt |= 1;
2605                         break;
2606                 case 'a':
2607                         bwrt |= 2;
2608                         break;
2609                 case 'r':
2610                         rdwr |= 1;
2611                         break;
2612                 case 'w':
2613                         rdwr |= 2;
2614                         break;
2615                 case 'g':
2616                         if (type == -1) {
2617                                 type = 1;
2618                                 break;
2619                         }
2620                         type |= 1;
2621                         break;
2622                 case 'n':
2623                         if (type == -1) {
2624                                 type = 2;
2625                                 break;
2626                         }
2627                         type |= 2;
2628                         break;
2629                 case 'x':
2630                         if (type == -1) {
2631                                 type = 4;
2632                                 break;
2633                         }
2634                         type |= 4;
2635                         break;
2636                 case 'm':
2637                         mbs = 1;
2638                         break;
2639
2640                 default:
2641                         lst_print_usage(argv[0]);
2642                         return -1;
2643                 }
2644         }
2645
2646         if (optind == argc) {
2647                 lst_print_usage(argv[0]);
2648                 return -1;
2649         }
2650
2651         if (timeout <= 0 || delay <= 0) {
2652                 fprintf(stderr, "Invalid timeout or delay value\n");
2653                 return -1;
2654         }
2655
2656         if (count < -1) {
2657             fprintf(stderr, "Invalid count value\n");
2658             return -1;
2659         }
2660
2661         /* extra count to get first data point */
2662         if (count != -1)
2663             count++;
2664
2665         INIT_LIST_HEAD(&head);
2666
2667         while (optind < argc) {
2668                 rc = lst_stat_req_param_alloc(argv[optind++], &srp, 1);
2669                 if (rc != 0)
2670                         goto out;
2671
2672                 list_add_tail(&srp->srp_link, &head);
2673         }
2674
2675         do {
2676                 time_t  now = time(NULL);
2677
2678                 if (now - last < delay) {
2679                         sleep(delay - now + last);
2680                         time(&now);
2681                 }
2682                 last = now;
2683
2684                 list_for_each_entry(srp, &head, srp_link) {
2685                         rc = lst_stat_ioctl(srp->srp_name,
2686                                             srp->srp_count, srp->srp_ids,
2687                                             timeout, &srp->srp_result[idx]);
2688                         if (rc == -1) {
2689                                 lst_print_error("stat", "Failed to stat %s: %s\n",
2690                                                 srp->srp_name, strerror(errno));
2691                                 goto out;
2692                         }
2693
2694                         lst_print_stat(srp->srp_name, srp->srp_result,
2695                                        idx, lnet, bwrt, rdwr, type, mbs);
2696
2697                         lst_reset_rpcent(&srp->srp_result[1 - idx]);
2698                 }
2699
2700                 idx = 1 - idx;
2701
2702                 if (count > 0)
2703                         count--;
2704         } while (count == -1 || count > 0);
2705
2706 out:
2707         while (!list_empty(&head)) {
2708                 srp = list_first_entry(&head, lst_stat_req_param_t, srp_link);
2709
2710                 list_del(&srp->srp_link);
2711                 lst_stat_req_param_free(srp);
2712         }
2713
2714         return rc;
2715 }
2716
2717 int
2718 jt_lst_show_error(int argc, char **argv)
2719 {
2720         struct list_head       head;
2721         lst_stat_req_param_t  *srp;
2722         struct lstcon_rpc_ent *ent;
2723         struct sfw_counters   *sfwk;
2724         struct srpc_counters  *srpc;
2725         int                    show_rpc = 1;
2726         int                    optidx = 0;
2727         int                    rc = 0;
2728         int                    ecount;
2729         int                    c;
2730
2731         static const struct option show_error_opts[] = {
2732                 { .name = "session", .has_arg = no_argument, .val = 's' },
2733                 { .name = NULL, } };
2734
2735         if (session_key == 0) {
2736                 fprintf(stderr,
2737                         "Can't find env LST_SESSION or value is not valid\n");
2738                 return -1;
2739         }
2740
2741         while (1) {
2742                 c = getopt_long(argc, argv, "s", show_error_opts, &optidx);
2743
2744                 if (c == -1)
2745                         break;
2746
2747                 switch (c) {
2748                 case 's':
2749                         show_rpc  = 0;
2750                         break;
2751
2752                 default:
2753                         lst_print_usage(argv[0]);
2754                         return -1;
2755                 }
2756         }
2757
2758         if (optind == argc) {
2759                 lst_print_usage(argv[0]);
2760                 return -1;
2761         }
2762
2763         INIT_LIST_HEAD(&head);
2764
2765         while (optind < argc) {
2766                 rc = lst_stat_req_param_alloc(argv[optind++], &srp, 0);
2767                 if (rc != 0)
2768                         goto out;
2769
2770                 list_add_tail(&srp->srp_link, &head);
2771         }
2772
2773         list_for_each_entry(srp, &head, srp_link) {
2774                 rc = lst_stat_ioctl(srp->srp_name, srp->srp_count,
2775                                     srp->srp_ids, 10, &srp->srp_result[0]);
2776
2777                 if (rc == -1) {
2778                         lst_print_error(srp->srp_name, "Failed to show errors of %s: %s\n",
2779                                         srp->srp_name, strerror(errno));
2780                         goto out;
2781                 }
2782
2783                 fprintf(stdout, "%s:\n", srp->srp_name);
2784
2785                 ecount = 0;
2786
2787                 list_for_each_entry(ent, &srp->srp_result[0], rpe_link) {
2788                         if (ent->rpe_rpc_errno != 0) {
2789                                 ecount ++;
2790                                 fprintf(stderr, "RPC failure, can't show error on %s\n",
2791                                         libcfs_id2str(ent->rpe_peer));
2792                                 continue;
2793                         }
2794
2795                         if (ent->rpe_fwk_errno != 0) {
2796                                 ecount ++;
2797                                 fprintf(stderr, "Framework failure, can't show error on %s\n",
2798                                         libcfs_id2str(ent->rpe_peer));
2799                                 continue;
2800                         }
2801
2802                         sfwk = (struct sfw_counters *)&ent->rpe_payload[0];
2803                         srpc = (struct srpc_counters *)((char *)sfwk + sizeof(*sfwk));
2804
2805                         if (srpc->errors == 0 &&
2806                             sfwk->brw_errors == 0 && sfwk->ping_errors == 0)
2807                                 continue;
2808
2809                         if (!show_rpc  &&
2810                             sfwk->brw_errors == 0 && sfwk->ping_errors == 0)
2811                                 continue;
2812
2813                         ecount ++;
2814
2815                         fprintf(stderr, "%s: [Session %d brw errors, %d ping errors]%c",
2816                                 libcfs_id2str(ent->rpe_peer),
2817                                 sfwk->brw_errors, sfwk->ping_errors,
2818                                 show_rpc  ? ' ' : '\n');
2819
2820                         if (!show_rpc)
2821                                 continue;
2822
2823                         fprintf(stderr, "[RPC: %d errors, %d dropped, %d expired]\n",
2824                                 srpc->errors, srpc->rpcs_dropped, srpc->rpcs_expired);
2825                 }
2826
2827                 fprintf(stdout, "Total %d error nodes in %s\n", ecount, srp->srp_name);
2828         }
2829 out:
2830         while (!list_empty(&head)) {
2831                 srp = list_first_entry(&head, lst_stat_req_param_t, srp_link);
2832
2833                 list_del(&srp->srp_link);
2834                 lst_stat_req_param_free(srp);
2835         }
2836
2837         return rc;
2838 }
2839
2840 int
2841 lst_add_batch_ioctl(char *name)
2842 {
2843         struct lstio_batch_add_args args = { 0 };
2844
2845         args.lstio_bat_key   = session_key;
2846         args.lstio_bat_nmlen = strlen(name);
2847         args.lstio_bat_namep = name;
2848
2849         return lst_ioctl (LSTIO_BATCH_ADD, &args, sizeof(args));
2850 }
2851
2852 int
2853 jt_lst_add_batch(int argc, char **argv)
2854 {
2855         char   *name;
2856         int     rc;
2857
2858         if (session_key == 0) {
2859                 fprintf(stderr,
2860                         "Can't find env LST_SESSION or value is not valid\n");
2861                 return -1;
2862         }
2863
2864         if (argc != 2) {
2865                 lst_print_usage(argv[0]);
2866                 return -1;
2867         }
2868
2869         name = argv[1];
2870         if (strlen(name) >= LST_NAME_SIZE) {
2871                 fprintf(stderr, "Name length is limited to %d\n",
2872                         LST_NAME_SIZE - 1);
2873                 return -1;
2874         }
2875
2876         rc = lst_add_batch_ioctl(name);
2877         if (rc == 0)
2878                 return 0;
2879
2880         lst_print_error("batch", "Failed to create batch: %s\n",
2881                         strerror(errno));
2882
2883         return -1;
2884 }
2885
2886 int
2887 lst_start_batch_ioctl(char *name, int timeout, struct list_head *resultp)
2888 {
2889         struct lstio_batch_run_args args = { 0 };
2890
2891         args.lstio_bat_key     = session_key;
2892         args.lstio_bat_timeout = timeout;
2893         args.lstio_bat_nmlen   = strlen(name);
2894         args.lstio_bat_namep   = name;
2895         args.lstio_bat_resultp = resultp;
2896
2897         return lst_ioctl(LSTIO_BATCH_START, &args, sizeof(args));
2898 }
2899
2900 int
2901 jt_lst_start_batch(int argc, char **argv)
2902 {
2903         struct list_head  head;
2904         char             *batch;
2905         int               optidx = 0;
2906         int               timeout = 0;
2907         int               count = 0;
2908         int               rc;
2909         int               c;
2910
2911         static const struct option start_batch_opts[] = {
2912                 { .name = "timeout", .has_arg = required_argument, .val = 't' },
2913                 { .name = NULL } };
2914
2915         if (session_key == 0) {
2916                 fprintf(stderr,
2917                         "Can't find env LST_SESSION or value is not valid\n");
2918                 return -1;
2919         }
2920
2921         while (1) {
2922                 c = getopt_long(argc, argv, "t:",
2923                                 start_batch_opts, &optidx);
2924
2925                 /* Detect the end of the options. */
2926                 if (c == -1)
2927                         break;
2928
2929                 switch (c) {
2930                 case 't':
2931                         timeout = atoi(optarg);
2932                         break;
2933                 default:
2934                         lst_print_usage(argv[0]);
2935                         return -1;
2936                 }
2937         }
2938
2939         if (optind == argc) {
2940                 batch = LST_DEFAULT_BATCH;
2941
2942         } else if (optind == argc - 1) {
2943                 batch = argv[optind];
2944
2945         } else {
2946                 lst_print_usage(argv[0]);
2947                 return -1;
2948         }
2949
2950         rc = lst_get_node_count(LST_OPC_BATCHCLI, batch, &count, NULL);
2951         if (rc != 0) {
2952                 fprintf(stderr, "Failed to get count of nodes from %s: %s\n",
2953                         batch, strerror(errno));
2954                 return -1;
2955         }
2956
2957         INIT_LIST_HEAD(&head);
2958
2959         rc = lst_alloc_rpcent(&head, count, 0);
2960         if (rc != 0) {
2961                 fprintf(stderr, "Out of memory\n");
2962                 return -1;
2963         }
2964
2965         rc = lst_start_batch_ioctl(batch, timeout, &head);
2966
2967         if (rc == 0) {
2968                 fprintf(stdout, "%s is running now\n", batch);
2969                 lst_free_rpcent(&head);
2970                 return 0;
2971         }
2972
2973         if (rc == -1) {
2974                 lst_print_error("batch", "Failed to start batch: %s\n",
2975                                 strerror(errno));
2976                 lst_free_rpcent(&head);
2977                 return rc;
2978         }
2979
2980         lst_print_transerr(&head, "Run batch");
2981
2982         lst_free_rpcent(&head);
2983
2984         return rc;
2985 }
2986
2987 int
2988 lst_stop_batch_ioctl(char *name, int force, struct list_head *resultp)
2989 {
2990         struct lstio_batch_stop_args args = { 0 };
2991
2992         args.lstio_bat_key     = session_key;
2993         args.lstio_bat_force   = force;
2994         args.lstio_bat_nmlen   = strlen(name);
2995         args.lstio_bat_namep   = name;
2996         args.lstio_bat_resultp = resultp;
2997
2998         return lst_ioctl(LSTIO_BATCH_STOP, &args, sizeof(args));
2999 }
3000
3001 int
3002 jt_lst_stop_batch(int argc, char **argv)
3003 {
3004         struct list_head  head;
3005         char             *batch;
3006         int               force = 0;
3007         int               optidx;
3008         int               count;
3009         int               rc;
3010         int               c;
3011
3012         static const struct option stop_batch_opts[] = {
3013                 { .name = "force", .has_arg = no_argument, .val = 'f' },
3014                 { .name = NULL } };
3015
3016         if (session_key == 0) {
3017                 fprintf(stderr,
3018                         "Can't find env LST_SESSION or value is not valid\n");
3019                 return -1;
3020         }
3021
3022         while (1) {
3023                 c = getopt_long(argc, argv, "f",
3024                                 stop_batch_opts, &optidx);
3025
3026                 /* Detect the end of the options. */
3027                 if (c == -1)
3028                         break;
3029
3030                 switch (c) {
3031                 case 'f':
3032                         force = 1;
3033                         break;
3034                 default:
3035                         lst_print_usage(argv[0]);
3036                         return -1;
3037                 }
3038         }
3039
3040         if (optind == argc) {
3041                 batch = LST_DEFAULT_BATCH;
3042
3043         } else if (optind == argc - 1) {
3044                 batch = argv[optind];
3045
3046         } else {
3047                 lst_print_usage(argv[0]);
3048                 return -1;
3049         }
3050
3051         rc = lst_get_node_count(LST_OPC_BATCHCLI, batch, &count, NULL);
3052         if (rc != 0) {
3053                 fprintf(stderr, "Failed to get count of nodes from %s: %s\n",
3054                         batch, strerror(errno));
3055                 return -1;
3056         }
3057
3058         INIT_LIST_HEAD(&head);
3059
3060         rc = lst_alloc_rpcent(&head, count, 0);
3061         if (rc != 0) {
3062                 fprintf(stderr, "Out of memory\n");
3063                 return -1;
3064         }
3065
3066         rc = lst_stop_batch_ioctl(batch, force, &head);
3067         if (rc != 0)
3068                 goto out;
3069
3070         while (1) {
3071                 lst_reset_rpcent(&head);
3072
3073                 rc = lst_query_batch_ioctl(batch, 0, 0, 30, &head);
3074                 if (rc != 0)
3075                         goto out;
3076
3077                 if (lstcon_tsbqry_stat_run(&trans_stat, 0)  == 0 &&
3078                     lstcon_tsbqry_stat_failure(&trans_stat, 0) == 0)
3079                         break;
3080
3081                 fprintf(stdout, "%d batch in stopping\n",
3082                         lstcon_tsbqry_stat_run(&trans_stat, 0));
3083                 sleep(1);
3084         }
3085
3086         fprintf(stdout, "Batch is stopped\n");
3087         lst_free_rpcent(&head);
3088
3089         return 0;
3090 out:
3091         if (rc == -1) {
3092                 lst_print_error("batch", "Failed to stop batch: %s\n",
3093                                 strerror(errno));
3094                 lst_free_rpcent(&head);
3095                 return -1;
3096         }
3097
3098         lst_print_transerr(&head, "stop batch");
3099
3100         lst_free_rpcent(&head);
3101
3102         return rc;
3103 }
3104
3105 int
3106 lst_list_batch_ioctl(int len, char *name, int index)
3107 {
3108         struct lstio_batch_list_args args = { 0 };
3109
3110         args.lstio_bat_key   = session_key;
3111         args.lstio_bat_idx   = index;
3112         args.lstio_bat_nmlen = len;
3113         args.lstio_bat_namep = name;
3114
3115         return lst_ioctl(LSTIO_BATCH_LIST, &args, sizeof(args));
3116 }
3117
3118 int
3119 lst_info_batch_ioctl(char *batch, int test, int server,
3120                      struct lstcon_test_batch_ent *entp, int *idxp,
3121                      int *ndentp, struct lstcon_node_ent *dentsp)
3122 {
3123         struct lstio_batch_info_args args = { 0 };
3124
3125         args.lstio_bat_key     = session_key;
3126         args.lstio_bat_nmlen   = strlen(batch);
3127         args.lstio_bat_namep   = batch;
3128         args.lstio_bat_server  = server;
3129         args.lstio_bat_testidx = test;
3130         args.lstio_bat_entp    = entp;
3131         args.lstio_bat_idxp    = idxp;
3132         args.lstio_bat_ndentp  = ndentp;
3133         args.lstio_bat_dentsp  = dentsp;
3134
3135         return lst_ioctl(LSTIO_BATCH_INFO, &args, sizeof(args));
3136 }
3137
3138 int
3139 lst_list_batch_all(void)
3140 {
3141         char name[LST_NAME_SIZE];
3142         int  rc;
3143         int  i;
3144
3145         for (i = 0; ; i++) {
3146                 rc = lst_list_batch_ioctl(LST_NAME_SIZE, name, i);
3147                 if (rc == 0) {
3148                         fprintf(stdout, "%d) %s\n", i + 1, name);
3149                         continue;
3150                 }
3151
3152                 if (errno == ENOENT)
3153                         break;
3154
3155                 lst_print_error("batch", "Failed to list batch: %s\n",
3156                                 strerror(errno));
3157                 return rc;
3158         }
3159
3160         fprintf(stdout, "Total %d batches\n", i);
3161
3162         return 0;
3163 }
3164
3165 int
3166 lst_list_tsb_nodes(char *batch, int test, int server,
3167                    int count, int active, int invalid)
3168 {
3169         struct lstcon_node_ent *dents;
3170         int                index = 0;
3171         int                rc;
3172         int                c;
3173         int                i;
3174
3175         if (count == 0)
3176                 return 0;
3177
3178         /* verbose list, show nodes in batch or test */
3179         dents = malloc(count * sizeof(struct lstcon_node_ent));
3180         if (dents == NULL) {
3181                 fprintf(stdout, "Can't allocate memory\n");
3182                 return -1;
3183         }
3184
3185         rc = lst_info_batch_ioctl(batch, test, server,
3186                                   NULL, &index, &count, dents);
3187         if (rc != 0) {
3188                 free(dents);
3189                 lst_print_error((test > 0) ? "test" : "batch",
3190                                 (test > 0) ? "Failed to query test: %s\n" :
3191                                              "Failed to query batch: %s\n",
3192                                 strerror(errno));
3193                 return -1;
3194         }
3195
3196         for (i = 0, c = 0; i < count; i++) {
3197                 if ((!active  && dents[i].nde_state == LST_NODE_ACTIVE) ||
3198                     (!invalid && (dents[i].nde_state == LST_NODE_BUSY  ||
3199                                   dents[i].nde_state == LST_NODE_DOWN  ||
3200                                   dents[i].nde_state == LST_NODE_UNKNOWN)))
3201                         continue;
3202
3203                 fprintf(stdout, "\t%s: %s\n",
3204                         libcfs_id2str(dents[i].nde_id),
3205                         lst_node_state2str(dents[i].nde_state));
3206                 c++;
3207         }
3208
3209         fprintf(stdout, "Total %d nodes\n", c);
3210         free(dents);
3211
3212         return 0;
3213 }
3214
3215 int
3216 jt_lst_list_batch(int argc, char **argv)
3217 {
3218         struct lstcon_test_batch_ent ent;
3219         char *batch   = NULL;
3220         int   optidx  = 0;
3221         int   verbose = 0; /* list nodes in batch or test */
3222         int   invalid = 0;
3223         int   active  = 0;
3224         int   server  = 0;
3225         int   ntest   = 0;
3226         int   test    = 0;
3227         int   c       = 0;
3228         int   rc;
3229
3230         static const struct option list_batch_opts[] = {
3231                 { .name = "test",    .has_arg = required_argument, .val = 't' },
3232                 { .name = "invalid", .has_arg = no_argument,       .val = 'i' },
3233                 { .name = "active",  .has_arg = no_argument,       .val = 'a' },
3234                 { .name = "all",     .has_arg = no_argument,       .val = 'l' },
3235                 { .name = "server",  .has_arg = no_argument,       .val = 's' },
3236                 { .name = NULL, } };
3237
3238         if (session_key == 0) {
3239                 fprintf(stderr,
3240                         "Can't find env LST_SESSION or value is not valid\n");
3241                 return -1;
3242         }
3243
3244         while (1) {
3245                 c = getopt_long(argc, argv, "ailst:",
3246                                 list_batch_opts, &optidx);
3247
3248                 if (c == -1)
3249                         break;
3250
3251                 switch (c) {
3252                 case 'a':
3253                         verbose = active = 1;
3254                         break;
3255                 case 'i':
3256                         verbose = invalid = 1;
3257                         break;
3258                 case 'l':
3259                         verbose = active = invalid = 1;
3260                         break;
3261                 case 's':
3262                         server = 1;
3263                         break;
3264                 case 't':
3265                         test = atoi(optarg);
3266                         ntest = 1;
3267                         break;
3268                 default:
3269                         lst_print_usage(argv[0]);
3270                         return -1;
3271                 }
3272         }
3273
3274         if (optind == argc) {
3275                 /* list all batches */
3276                 rc = lst_list_batch_all();
3277                 return rc;
3278         }
3279
3280         if (ntest == 1 && test <= 0) {
3281                 fprintf(stderr, "Invalid test id, test id starts from 1\n");
3282                 return -1;
3283         }
3284
3285         if (optind != argc - 1) {
3286                 lst_print_usage(argv[0]);
3287                 return -1;
3288         }
3289
3290         batch = argv[optind];
3291
3292 loop:
3293         /* show detail of specified batch or test */
3294         rc = lst_info_batch_ioctl(batch, test, server,
3295                                   &ent, NULL, NULL, NULL);
3296         if (rc != 0) {
3297                 lst_print_error((test > 0) ? "test" : "batch",
3298                                 (test > 0) ? "Failed to query test: %s\n" :
3299                                              "Failed to query batch: %s\n",
3300                                 strerror(errno));
3301                 return -1;
3302         }
3303
3304         if (verbose) {
3305                 /* list nodes in test or batch */
3306                 rc = lst_list_tsb_nodes(batch, test, server,
3307                                         server ? ent.tbe_srv_nle.nle_nnode :
3308                                                  ent.tbe_cli_nle.nle_nnode,
3309                                         active, invalid);
3310                 return rc;
3311         }
3312
3313         /* only show number of hosts in batch or test */
3314         if (test == 0) {
3315                 fprintf(stdout, "Batch: %s Tests: %d State: %d\n",
3316                         batch, ent.u.tbe_batch.bae_ntest,
3317                         ent.u.tbe_batch.bae_state);
3318                 ntest = ent.u.tbe_batch.bae_ntest;
3319                 test = 1; /* starting from test 1 */
3320
3321         } else {
3322                 fprintf(stdout,
3323                         "\tTest %d(%s) (loop: %d, concurrency: %d)\n",
3324                         test, lst_test_type2name(ent.u.tbe_test.tse_type),
3325                         ent.u.tbe_test.tse_loop,
3326                         ent.u.tbe_test.tse_concur);
3327                 ntest --;
3328                 test ++;
3329         }
3330
3331         fprintf(stdout, LST_NODES_TITLE);
3332         fprintf(stdout, "client\t%d\t%d\t%d\t%d\t%d\n"
3333                         "server\t%d\t%d\t%d\t%d\t%d\n",
3334                 ent.tbe_cli_nle.nle_nactive,
3335                 ent.tbe_cli_nle.nle_nbusy,
3336                 ent.tbe_cli_nle.nle_ndown,
3337                 ent.tbe_cli_nle.nle_nunknown,
3338                 ent.tbe_cli_nle.nle_nnode,
3339                 ent.tbe_srv_nle.nle_nactive,
3340                 ent.tbe_srv_nle.nle_nbusy,
3341                 ent.tbe_srv_nle.nle_ndown,
3342                 ent.tbe_srv_nle.nle_nunknown,
3343                 ent.tbe_srv_nle.nle_nnode);
3344
3345         if (ntest != 0)
3346                 goto loop;
3347
3348         return 0;
3349 }
3350
3351 int
3352 lst_query_batch_ioctl(char *batch, int test, int server,
3353                       int timeout, struct list_head *head)
3354 {
3355         struct lstio_batch_query_args args = { 0 };
3356
3357         args.lstio_bat_key     = session_key;
3358         args.lstio_bat_testidx = test;
3359         args.lstio_bat_client  = !(server);
3360         args.lstio_bat_timeout = timeout;
3361         args.lstio_bat_nmlen   = strlen(batch);
3362         args.lstio_bat_namep   = batch;
3363         args.lstio_bat_resultp = head;
3364
3365         return lst_ioctl(LSTIO_BATCH_QUERY, &args, sizeof(args));
3366 }
3367
3368 void
3369 lst_print_tsb_verbose(struct list_head *head,
3370                       int active, int idle, int error)
3371 {
3372         struct lstcon_rpc_ent *ent;
3373
3374         list_for_each_entry(ent, head, rpe_link) {
3375                 if (ent->rpe_priv[0] == 0 && active)
3376                         continue;
3377
3378                 if (ent->rpe_priv[0] != 0 && idle)
3379                         continue;
3380
3381                 if (ent->rpe_fwk_errno == 0 && error)
3382                         continue;
3383
3384                 fprintf(stdout, "%s [%s]: %s\n",
3385                         libcfs_id2str(ent->rpe_peer),
3386                         lst_node_state2str(ent->rpe_state),
3387                         ent->rpe_rpc_errno != 0 ?
3388                                 strerror(ent->rpe_rpc_errno) :
3389                                 (ent->rpe_priv[0] > 0 ? "Running" : "Idle"));
3390         }
3391 }
3392
3393 int
3394 jt_lst_query_batch(int argc, char **argv)
3395 {
3396         struct lstcon_test_batch_ent ent;
3397         struct list_head head;
3398         char   *batch   = NULL;
3399         time_t  last    = 0;
3400         int     optidx  = 0;
3401         int     verbose = 0;
3402         int     server  = 0;
3403         int     timeout = 5; /* default 5 seconds */
3404         int     delay   = 5; /* default 5 seconds */
3405         int     loop    = 1; /* default 1 loop */
3406         int     active  = 0;
3407         int     error   = 0;
3408         int     idle    = 0;
3409         int     count   = 0;
3410         int     test    = 0;
3411         int     rc      = 0;
3412         int     c       = 0;
3413         int     i;
3414
3415         static const struct option query_batch_opts[] = {
3416                 { .name = "timeout", .has_arg = required_argument, .val = 'o' },
3417                 { .name = "delay",   .has_arg = required_argument, .val = 'd' },
3418                 { .name = "loop",    .has_arg = required_argument, .val = 'c' },
3419                 { .name = "test",    .has_arg = required_argument, .val = 't' },
3420                 { .name = "server",  .has_arg = no_argument,       .val = 's' },
3421                 { .name = "active",  .has_arg = no_argument,       .val = 'a' },
3422                 { .name = "idle",    .has_arg = no_argument,       .val = 'i' },
3423                 { .name = "error",   .has_arg = no_argument,       .val = 'e' },
3424                 { .name = "all",     .has_arg = no_argument,       .val = 'l' },
3425                 { .name = NULL, } };
3426
3427         if (session_key == 0) {
3428                 fprintf(stderr,
3429                         "Can't find env LST_SESSION or value is not valid\n");
3430                 return -1;
3431         }
3432
3433         while (1) {
3434                 c = getopt_long(argc, argv, "o:d:c:t:saiel",
3435                                 query_batch_opts, &optidx);
3436
3437                 /* Detect the end of the options. */
3438                 if (c == -1)
3439                         break;
3440
3441                 switch (c) {
3442                 case 'o':
3443                         timeout = atoi(optarg);
3444                         break;
3445                 case 'd':
3446                         delay = atoi(optarg);
3447                         break;
3448                 case 'c':
3449                         loop = atoi(optarg);
3450                         break;
3451                 case 't':
3452                         test = atoi(optarg);
3453                         break;
3454                 case 's':
3455                         server = 1;
3456                         break;
3457                 case 'a':
3458                         active = verbose = 1;
3459                         break;
3460                 case 'i':
3461                         idle = verbose = 1;
3462                         break;
3463                 case 'e':
3464                         error = verbose = 1;
3465                         break;
3466                 case 'l':
3467                         verbose = 1;
3468                         break;
3469                 default:
3470                         lst_print_usage(argv[0]);
3471                         return -1;
3472                 }
3473         }
3474
3475         if (test < 0 || timeout <= 0 || delay <= 0 || loop <= 0) {
3476                 lst_print_usage(argv[0]);
3477                 return -1;
3478         }
3479
3480         if (optind == argc) {
3481                 batch = LST_DEFAULT_BATCH;
3482
3483         } else if (optind == argc - 1) {
3484                 batch = argv[optind];
3485
3486         } else {
3487                 lst_print_usage(argv[0]);
3488                 return -1;
3489         }
3490
3491
3492         INIT_LIST_HEAD(&head);
3493
3494         if (verbose) {
3495                 rc = lst_info_batch_ioctl(batch, test, server,
3496                                           &ent, NULL, NULL, NULL);
3497                 if (rc != 0) {
3498                         fprintf(stderr, "Failed to query %s [%d]: %s\n",
3499                                 batch, test, strerror(errno));
3500                         return -1;
3501                 }
3502
3503                 count = server ? ent.tbe_srv_nle.nle_nnode :
3504                                  ent.tbe_cli_nle.nle_nnode;
3505                 if (count == 0) {
3506                         fprintf(stdout, "Batch or test is empty\n");
3507                         return 0;
3508                 }
3509         }
3510
3511         rc = lst_alloc_rpcent(&head, count, 0);
3512         if (rc != 0) {
3513                 fprintf(stderr, "Out of memory\n");
3514                 return rc;
3515         }
3516
3517         for (i = 0; i < loop; i++) {
3518                 time_t  now = time(NULL);
3519
3520                 if (now - last < delay) {
3521                         sleep(delay - now + last);
3522                         time(&now);
3523                 }
3524
3525                 last = now;
3526
3527                 rc = lst_query_batch_ioctl(batch, test,
3528                                            server, timeout, &head);
3529                 if (rc == -1) {
3530                         fprintf(stderr, "Failed to query batch: %s\n",
3531                                 strerror(errno));
3532                         break;
3533                 }
3534
3535                 if (verbose) {
3536                         /* Verbose mode */
3537                         lst_print_tsb_verbose(&head, active, idle, error);
3538                         continue;
3539                 }
3540
3541                 fprintf(stdout, "%s [%d] ", batch, test);
3542
3543                 if (lstcon_rpc_stat_failure(&trans_stat, 0) != 0) {
3544                         fprintf(stdout, "%d of %d nodes are unknown, ",
3545                                 lstcon_rpc_stat_failure(&trans_stat, 0),
3546                                 lstcon_rpc_stat_total(&trans_stat, 0));
3547                 }
3548
3549                 if (lstcon_rpc_stat_failure(&trans_stat, 0) == 0 &&
3550                     lstcon_tsbqry_stat_run(&trans_stat, 0)  == 0  &&
3551                     lstcon_tsbqry_stat_failure(&trans_stat, 0) == 0) {
3552                         fprintf(stdout, "is stopped\n");
3553                         continue;
3554                 }
3555
3556                 if (lstcon_rpc_stat_failure(&trans_stat, 0) == 0 &&
3557                     lstcon_tsbqry_stat_idle(&trans_stat, 0) == 0 &&
3558                     lstcon_tsbqry_stat_failure(&trans_stat, 0) == 0) {
3559                         fprintf(stdout, "is running\n");
3560                         continue;
3561                 }
3562
3563                 fprintf(stdout, "stopped: %d , running: %d, failed: %d\n",
3564                                 lstcon_tsbqry_stat_idle(&trans_stat, 0),
3565                                 lstcon_tsbqry_stat_run(&trans_stat, 0),
3566                                 lstcon_tsbqry_stat_failure(&trans_stat, 0));
3567         }
3568
3569         lst_free_rpcent(&head);
3570
3571         return rc;
3572 }
3573
3574 int
3575 lst_parse_distribute(char *dstr, int *dist, int *span)
3576 {
3577         *dist = atoi(dstr);
3578         if (*dist <= 0)
3579                 return -1;
3580
3581         dstr = strchr(dstr, ':');
3582         if (dstr == NULL)
3583                 return -1;
3584
3585         *span = atoi(dstr + 1);
3586         if (*span <= 0)
3587                 return -1;
3588
3589         return 0;
3590 }
3591
3592 int
3593 lst_get_bulk_param(int argc, char **argv, struct lst_test_bulk_param *bulk)
3594 {
3595         char   *tok = NULL;
3596         char   *end = NULL;
3597         int     rc  = 0;
3598         int     i   = 0;
3599
3600         bulk->blk_size  = 4096;
3601         bulk->blk_opc   = LST_BRW_READ;
3602         bulk->blk_flags = LST_BRW_CHECK_NONE;
3603         bulk->blk_srv_off = bulk->blk_cli_off = 0;
3604
3605         while (i < argc) {
3606                 if (strcasestr(argv[i], "check=") == argv[i] ||
3607                     strcasestr(argv[i], "c=") == argv[i]) {
3608                         tok = strchr(argv[i], '=') + 1;
3609
3610                         if (strcasecmp(tok, "full") == 0) {
3611                                 bulk->blk_flags = LST_BRW_CHECK_FULL;
3612                         } else if (strcasecmp(tok, "simple") == 0) {
3613                                 bulk->blk_flags = LST_BRW_CHECK_SIMPLE;
3614                         } else {
3615                                 fprintf(stderr, "Unknow flag %s\n", tok);
3616                                 return -1;
3617                         }
3618
3619                 } else if (strcasestr(argv[i], "size=") == argv[i] ||
3620                            strcasestr(argv[i], "s=") == argv[i]) {
3621                         tok = strchr(argv[i], '=') + 1;
3622
3623                         bulk->blk_size = strtol(tok, &end, 0);
3624                         if (bulk->blk_size <= 0) {
3625                                 fprintf(stderr, "Invalid size %s\n", tok);
3626                                 return -1;
3627                         }
3628
3629                         if (end == NULL)
3630                                 return 0;
3631
3632                         if (*end == 'k' || *end == 'K')
3633                                 bulk->blk_size *= 1024;
3634                         else if (*end == 'm' || *end == 'M')
3635                                 bulk->blk_size *= 1024 * 1024;
3636
3637                         if (bulk->blk_size > LNET_MTU) {
3638                                 fprintf(stderr, "Size exceed limitation: %d bytes\n",
3639                                         bulk->blk_size);
3640                                 return -1;
3641                         }
3642
3643                 } else if (strcasestr(argv[i], "off=") == argv[i]) {
3644                         int     off;
3645
3646                         tok = strchr(argv[i], '=') + 1;
3647
3648                         off = strtol(tok, &end, 0);
3649                         /* NB: align with sizeof(__u64) to simplify page
3650                          * checking implementation */
3651                         if (off < 0 || off % sizeof(__u64) != 0) {
3652                                 fprintf(stderr,
3653                                         "Invalid offset %s/%d, it should be "
3654                                         "postive value and multiple of %d\n",
3655                                         tok, off, (int)sizeof(__u64));
3656                                 return -1;
3657                         }
3658
3659                         /* NB: blk_srv_off is reserved so far */
3660                         bulk->blk_cli_off = bulk->blk_srv_off = off;
3661                         if (end == NULL)
3662                                 return 0;
3663
3664                 } else if (strcasecmp(argv[i], "read") == 0 ||
3665                            strcasecmp(argv[i], "r") == 0) {
3666                         bulk->blk_opc = LST_BRW_READ;
3667
3668                 } else if (strcasecmp(argv[i], "write") == 0 ||
3669                            strcasecmp(argv[i], "w") == 0) {
3670                         bulk->blk_opc = LST_BRW_WRITE;
3671
3672                 } else {
3673                         fprintf(stderr, "Unknow parameter: %s\n", argv[i]);
3674                         return -1;
3675                 }
3676
3677                 i++;
3678         }
3679
3680         return rc;
3681 }
3682
3683 int
3684 lst_get_test_param(char *test, int argc, char **argv, void **param, int *plen)
3685 {
3686         struct lst_test_bulk_param *bulk = NULL;
3687         struct lst_test_ping_param *ping = NULL;
3688         int                    type;
3689
3690         type = lst_test_name2type(test);
3691         if (type < 0) {
3692                 fprintf(stderr, "Unknow test name %s\n", test);
3693                 return -1;
3694         }
3695
3696         switch (type) {
3697         case LST_TEST_PING:
3698                 /* unused but needs for kernel part */
3699                 ping = malloc(sizeof(*ping));
3700                 if (ping == NULL) {
3701                         fprintf(stderr, "Out of memory\n");
3702                         return -1;
3703                 }
3704                 memset(ping, 0, sizeof(*ping));
3705
3706                 *param = ping;
3707                 *plen  = sizeof(*ping);
3708
3709                 break;
3710
3711         case LST_TEST_BULK:
3712                 bulk = malloc(sizeof(*bulk));
3713                 if (bulk == NULL) {
3714                         fprintf(stderr, "Out of memory\n");
3715                         return -1;
3716                 }
3717
3718                 memset(bulk, 0, sizeof(*bulk));
3719
3720                 if (lst_get_bulk_param(argc, argv, bulk) != 0) {
3721                         free(bulk);
3722                         return -1;
3723                 }
3724
3725                 *param = bulk;
3726                 *plen  = sizeof(*bulk);
3727
3728                 break;
3729
3730         default:
3731                 break;
3732         }
3733
3734         /* TODO: parse more parameter */
3735         return type;
3736 }
3737
3738 int
3739 lst_add_test_ioctl(char *batch, int type, int loop, int concur,
3740                    int dist, int span, char *sgrp, char *dgrp,
3741                    void *param, int plen, int *retp, struct list_head *resultp)
3742 {
3743         struct lstio_test_args args = { 0 };
3744
3745         args.lstio_tes_key        = session_key;
3746         args.lstio_tes_bat_nmlen  = strlen(batch);
3747         args.lstio_tes_bat_name   = batch;
3748         args.lstio_tes_type       = type;
3749         args.lstio_tes_oneside    = 0;
3750         args.lstio_tes_loop       = loop;
3751         args.lstio_tes_concur     = concur;
3752         args.lstio_tes_dist       = dist;
3753         args.lstio_tes_span       = span;
3754         args.lstio_tes_sgrp_nmlen = strlen(sgrp);
3755         args.lstio_tes_sgrp_name  = sgrp;
3756         args.lstio_tes_dgrp_nmlen = strlen(dgrp);
3757         args.lstio_tes_dgrp_name  = dgrp;
3758         args.lstio_tes_param_len  = plen;
3759         args.lstio_tes_param      = param;
3760         args.lstio_tes_retp       = retp;
3761         args.lstio_tes_resultp    = resultp;
3762
3763         return lst_ioctl(LSTIO_TEST_ADD, &args, sizeof(args));
3764 }
3765
3766 int
3767 jt_lst_add_test(int argc, char **argv)
3768 {
3769         struct list_head head;
3770         char *batch  = NULL;
3771         char *test   = NULL;
3772         char *dstr   = NULL;
3773         char *from   = NULL;
3774         char *to     = NULL;
3775         void *param  = NULL;
3776         int   optidx = 0;
3777         int   concur = 1;
3778         int   loop   = -1;
3779         int   dist   = 1;
3780         int   span   = 1;
3781         int   plen   = 0;
3782         int   fcount = 0;
3783         int   tcount = 0;
3784         int   ret    = 0;
3785         int   type;
3786         int   rc;
3787         int   c;
3788
3789         static const struct option add_test_opts[] = {
3790         { .name = "batch",       .has_arg = required_argument, .val = 'b' },
3791         { .name = "concurrency", .has_arg = required_argument, .val = 'c' },
3792         { .name = "distribute",  .has_arg = required_argument, .val = 'd' },
3793         { .name = "from",        .has_arg = required_argument, .val = 'f' },
3794         { .name = "to",          .has_arg = required_argument, .val = 't' },
3795         { .name = "loop",        .has_arg = required_argument, .val = 'l' },
3796         { .name = NULL } };
3797
3798         if (session_key == 0) {
3799                 fprintf(stderr,
3800                         "Can't find env LST_SESSION or value is not valid\n");
3801                 return -1;
3802         }
3803
3804         while (1) {
3805                 c = getopt_long(argc, argv, "b:c:d:f:l:t:",
3806                                 add_test_opts, &optidx);
3807
3808                 /* Detect the end of the options. */
3809                 if (c == -1)
3810                         break;
3811
3812                 switch (c) {
3813                 case 'b':
3814                         batch = optarg;
3815                         break;
3816                 case 'c':
3817                         concur = atoi(optarg);
3818                         break;
3819                 case 'd':
3820                         dstr = optarg;
3821                         break;
3822                 case 'f':
3823                         from = optarg;
3824                         break;
3825                 case 'l':
3826                         loop = atoi(optarg);
3827                         break;
3828                 case 't':
3829                         to = optarg;
3830                         break;
3831                 default:
3832                         lst_print_usage(argv[0]);
3833                         return -1;
3834                 }
3835         }
3836
3837         if (optind == argc || from == NULL || to == NULL) {
3838                 lst_print_usage(argv[0]);
3839                 return -1;
3840         }
3841
3842         if (concur <= 0 || concur > LST_MAX_CONCUR) {
3843                 fprintf(stderr, "Invalid concurrency of test: %d\n", concur);
3844                 return -1;
3845         }
3846
3847         if (batch == NULL)
3848                 batch = LST_DEFAULT_BATCH;
3849
3850         if (dstr != NULL) {
3851                 rc = lst_parse_distribute(dstr, &dist, &span);
3852                 if (rc != 0) {
3853                         fprintf(stderr, "Invalid distribution: %s\n", dstr);
3854                         return -1;
3855                 }
3856         }
3857
3858         test = argv[optind++];
3859
3860         argc -= optind;
3861         argv += optind;
3862
3863         type = lst_get_test_param(test, argc, argv, &param, &plen);
3864         if (type < 0) {
3865                 fprintf(stderr, "Failed to add test (%s)\n", test);
3866                 return -1;
3867         }
3868
3869         INIT_LIST_HEAD(&head);
3870
3871         rc = lst_get_node_count(LST_OPC_GROUP, from, &fcount, NULL);
3872         if (rc != 0) {
3873                 fprintf(stderr, "Can't get count of nodes from %s: %s\n",
3874                         from, strerror(errno));
3875                 goto out;
3876         }
3877
3878         rc = lst_get_node_count(LST_OPC_GROUP, to, &tcount, NULL);
3879         if (rc != 0) {
3880                 fprintf(stderr, "Can't get count of nodes from %s: %s\n",
3881                         to, strerror(errno));
3882                 goto out;
3883         }
3884
3885         rc = lst_alloc_rpcent(&head, fcount > tcount ? fcount : tcount, 0);
3886         if (rc != 0) {
3887                 fprintf(stderr, "Out of memory\n");
3888                 goto out;
3889         }
3890
3891         rc = lst_add_test_ioctl(batch, type, loop, concur,
3892                                 dist, span, from, to, param, plen, &ret, &head);
3893
3894         if (rc == 0) {
3895                 fprintf(stdout, "Test was added successfully\n");
3896                 if (ret != 0) {
3897                         fprintf(stdout, "Server group contains userland test "
3898                                 "nodes, old version of tcplnd can't accept "
3899                                 "connection request\n");
3900                 }
3901
3902                 goto out;
3903         }
3904
3905         if (rc == -1) {
3906                 lst_print_error("test", "Failed to add test: %s\n",
3907                                 strerror(errno));
3908                 goto out;
3909         }
3910
3911         lst_print_transerr(&head, "add test");
3912 out:
3913         lst_free_rpcent(&head);
3914
3915         if (param != NULL)
3916                 free(param);
3917
3918         return rc;
3919 }
3920
3921 static command_t lst_cmdlist[] = {
3922         {"new_session",         jt_lst_new_session,     NULL,
3923          "Usage: lst new_session [--timeout TIME] [--force] [NAME]"                     },
3924         {"end_session",         jt_lst_end_session,     NULL,
3925          "Usage: lst end_session"                                                       },
3926         {"show_session",        jt_lst_show_session,    NULL,
3927          "Usage: lst show_session"                                                      },
3928         {"ping",                jt_lst_ping ,           NULL,
3929          "Usage: lst ping  [--group NAME] [--batch NAME] [--session] [--nodes IDS]"     },
3930         {"add_group",           jt_lst_add_group,       NULL,
3931          "Usage: lst group NAME IDs [IDs]..."                                           },
3932         {"del_group",           jt_lst_del_group,       NULL,
3933          "Usage: lst del_group NAME"                                                    },
3934         {"update_group",        jt_lst_update_group,    NULL,
3935          "Usage: lst update_group NAME [--clean] [--refresh] [--remove IDs]"            },
3936         {"list_group",          jt_lst_list_group,      NULL,
3937           "Usage: lst list_group [--active] [--busy] [--down] [--unknown] GROUP ..."    },
3938         {"stat",                jt_lst_stat,            NULL,
3939          "Usage: lst stat [--bw] [--rate] [--read] [--write] [--max] [--min] [--avg] "
3940          " [--mbs] [--timeout #] [--delay #] [--count #] GROUP [GROUP]"                 },
3941         {"show_error",          jt_lst_show_error,      NULL,
3942          "Usage: lst show_error NAME | IDS ..."                                         },
3943         {"add_batch",           jt_lst_add_batch,       NULL,
3944          "Usage: lst add_batch NAME"                                                    },
3945         {"run",                 jt_lst_start_batch,     NULL,
3946          "Usage: lst run [--timeout TIME] [NAME]"                                       },
3947         {"stop",                jt_lst_stop_batch,      NULL,
3948          "Usage: lst stop [--force] BATCH_NAME"                                         },
3949         {"list_batch",          jt_lst_list_batch,      NULL,
3950          "Usage: lst list_batch NAME [--test ID] [--server]"                            },
3951         {"query",               jt_lst_query_batch,     NULL,
3952          "Usage: lst query [--test ID] [--server] [--timeout TIME] NAME"                },
3953         {"add_test",            jt_lst_add_test,        NULL,
3954          "Usage: lst add_test [--batch BATCH] [--loop #] [--concurrency #] "
3955          " [--distribute #:#] [--from GROUP] [--to GROUP] TEST..."                      },
3956         {0,                     0,                      0,      NULL                    }
3957 };
3958
3959 int
3960 lst_initialize(void)
3961 {
3962         char   *key;
3963         char   *feats;
3964
3965         feats = getenv("LST_FEATURES");
3966         if (feats != NULL)
3967                 session_features = strtol(feats, NULL, 16);
3968
3969         if ((session_features & ~LST_FEATS_MASK) != 0) {
3970                 fprintf(stderr,
3971                         "Unsupported session features %x, "
3972                         "only support these features so far: %x\n",
3973                         (session_features & ~LST_FEATS_MASK), LST_FEATS_MASK);
3974                 return -1;
3975         }
3976
3977         key = getenv("LST_SESSION");
3978
3979         if (key == NULL) {
3980                 session_key = 0;
3981                 return 0;
3982         }
3983
3984         session_key = atoi(key);
3985
3986         return 0;
3987 }
3988
3989 int main(int argc, char **argv)
3990 {
3991         int rc = 0;
3992
3993         setlinebuf(stdout);
3994
3995         rc = lst_initialize();
3996         if (rc < 0)
3997                 goto errorout;
3998
3999         rc = lustre_lnet_config_lib_init();
4000         if (rc < 0)
4001                 goto errorout;
4002
4003         rc = cfs_parser(argc, argv, lst_cmdlist);
4004
4005 errorout:
4006         return rc;
4007 }