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