Whamcloud - gitweb
LU-6210 lnet: Change positional struct initializers to C99
[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, 2016, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  *
32  * lnet/selftest/conctl.c
33  *
34  * Author: Liang Zhen <liangzhen@clusterfs.com>
35  */
36 #include <errno.h>
37 #include <getopt.h>
38 #include <inttypes.h>
39 #include <pwd.h>
40 #include <unistd.h>
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <sys/ioctl.h>
46 #include <time.h>
47
48 #include <libcfs/util/list.h>
49 #include <libcfs/util/ioctl.h>
50 #include <libcfs/util/parser.h>
51 #include <lnet/lnetctl.h>
52 #include <lnet/lnetst.h>
53 #include <lnet/lnet.h>
54 #include <utils/obdctl.h>
55
56 struct lst_sid LST_INVALID_SID = { .ses_nid = LNET_NID_ANY, .ses_stamp = -1 };
57 static struct lst_sid session_id;
58 static int                 session_key;
59
60 /* All nodes running 2.6.50 or later understand feature LST_FEAT_BULK_LEN */
61 static unsigned         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, lnet_process_id_t **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(lnet_process_id_t));
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
519 lst_new_session_ioctl(char *name, int timeout, int force, struct lst_sid *sid)
520 {
521         struct lstio_session_new_args args = { 0 };
522
523         args.lstio_ses_key     = session_key;
524         args.lstio_ses_timeout = timeout;
525         args.lstio_ses_force   = force;
526         args.lstio_ses_idp     = sid;
527         args.lstio_ses_feats   = session_features;
528         args.lstio_ses_nmlen   = strlen(name);
529         args.lstio_ses_namep   = name;
530
531         return lst_ioctl (LSTIO_SESSION_NEW, &args, sizeof(args));
532 }
533
534 int
535 jt_lst_new_session(int argc, char **argv)
536 {
537         char  buf[LST_NAME_SIZE];
538         char *name;
539         int   optidx = 0;
540         int   timeout = 300;
541         int   force = 0;
542         int   c;
543         int   rc;
544
545         static const struct option session_opts[] = {
546                 { .name = "timeout", .has_arg = required_argument, .val = 't' },
547                 { .name = "force",   .has_arg = no_argument,       .val = 'f' },
548                 { .name = NULL } };
549
550         if (session_key == 0) {
551                 fprintf(stderr,
552                         "Can't find env LST_SESSION or value is not valid\n");
553                 return -1;
554         }
555
556         while (1) {
557
558                 c = getopt_long(argc, argv, "ft:",
559                                 session_opts, &optidx);
560
561                 if (c == -1)
562                         break;
563
564                 switch (c) {
565                 case 'f':
566                         force = 1;
567                         break;
568                 case 't':
569                         timeout = atoi(optarg);
570                         break;
571                 default:
572                         lst_print_usage(argv[0]);
573                         return -1;
574                 }
575         }
576
577         if (timeout <= 0) {
578                 fprintf(stderr, "Invalid timeout value\n");
579                 return -1;
580         }
581
582         if (optind == argc - 1) {
583                 name = argv[optind ++];
584                 if (strlen(name) >= LST_NAME_SIZE) {
585                         fprintf(stderr, "Name size is limited to %d\n",
586                                 LST_NAME_SIZE - 1);
587                         return -1;
588                 }
589
590         } else if (optind == argc) {
591                 char           user[LST_NAME_SIZE];
592                 char           host[LST_NAME_SIZE];
593                 struct passwd *pw = getpwuid(getuid());
594
595                 if (pw == NULL)
596                         snprintf(user, sizeof(user), "%d", (int)getuid());
597                 else
598                         snprintf(user, sizeof(user), "%s", pw->pw_name);
599
600                 rc = gethostname(host, sizeof(host));
601                 if (rc != 0)
602                         snprintf(host, sizeof(host), "unknown_host");
603
604                 snprintf(buf, sizeof(buf), "%s@%s", user, host);
605                 name = buf;
606
607         } else {
608                 lst_print_usage(argv[0]);
609                 return -1;
610         }
611
612         rc = lst_new_session_ioctl(name, timeout, force, &session_id);
613         if (rc != 0) {
614                 lst_print_error("session", "Failed to create session: %s\n",
615                                 strerror(errno));
616                 return rc;
617         }
618
619         fprintf(stdout, "SESSION: %s FEATURES: %x TIMEOUT: %d FORCE: %s\n",
620                 name, session_features, timeout, force ? "Yes" : "No");
621         return 0;
622 }
623
624 int
625 lst_session_info_ioctl(char *name, int len, int *key, unsigned *featp,
626                        struct lst_sid *sid, struct lstcon_ndlist_ent *ndinfo)
627 {
628         struct lstio_session_info_args args = { 0 };
629
630         args.lstio_ses_idp     = sid;
631         args.lstio_ses_keyp    = key;
632         args.lstio_ses_featp   = featp;
633         args.lstio_ses_ndinfo  = ndinfo;
634         args.lstio_ses_nmlen   = len;
635         args.lstio_ses_namep   = name;
636
637         return lst_ioctl(LSTIO_SESSION_INFO, &args, sizeof(args));
638 }
639
640 int
641 jt_lst_show_session(int argc, char **argv)
642 {
643         struct lstcon_ndlist_ent ndinfo;
644         struct lst_sid sid;
645         char                name[LST_NAME_SIZE];
646         unsigned            feats;
647         int                 key;
648         int                 rc;
649
650         rc = lst_session_info_ioctl(name, sizeof(name), &key,
651                                     &feats, &sid, &ndinfo);
652
653         if (rc != 0) {
654                 lst_print_error("session", "Failed to show session: %s\n",
655                                 strerror(errno));
656                 return -1;
657         }
658
659         fprintf(stdout, "%s ID: %ju@%s, KEY: %d FEATURES: %x NODES: %d\n",
660                 name, (uintmax_t)sid.ses_stamp, libcfs_nid2str(sid.ses_nid),
661                 key, feats, ndinfo.nle_nnode);
662
663         return 0;
664 }
665
666 int
667 lst_end_session_ioctl(void)
668 {
669         struct lstio_session_end_args args = { 0 };
670
671         args.lstio_ses_key = session_key;
672         return lst_ioctl(LSTIO_SESSION_END, &args, sizeof(args));
673 }
674
675 int
676 jt_lst_end_session(int argc, char **argv)
677 {
678         int             rc;
679
680         if (session_key == 0) {
681                 fprintf(stderr,
682                         "Can't find env LST_SESSION or value is not valid\n");
683                 return -1;
684         }
685
686         rc = lst_end_session_ioctl();
687
688         if (rc == 0) {
689                 fprintf(stdout, "session is ended\n");
690                 return 0;
691         }
692
693         if (rc == -1) {
694                 lst_print_error("session", "Failed to end session: %s\n",
695                                 strerror(errno));
696                 return rc;
697         }
698
699         if (trans_stat.trs_rpc_errno != 0) {
700                 fprintf(stderr,
701                         "[RPC] Failed to send %d session RPCs: %s\n",
702                         lstcon_rpc_stat_failure(&trans_stat, 0),
703                         strerror(trans_stat.trs_rpc_errno));
704         }
705
706         if (trans_stat.trs_fwk_errno != 0) {
707                 fprintf(stderr,
708                         "[FWK] Failed to end session on %d nodes: %s\n",
709                         lstcon_sesop_stat_failure(&trans_stat, 0),
710                         strerror(trans_stat.trs_fwk_errno));
711         }
712
713         return rc;
714 }
715
716 int
717 lst_ping_ioctl(char *str, int type, int timeout,
718                int count, lnet_process_id_t *ids, struct list_head *head)
719 {
720         struct lstio_debug_args args = { 0 };
721
722         args.lstio_dbg_key     = session_key;
723         args.lstio_dbg_type    = type;
724         args.lstio_dbg_flags   = 0;
725         args.lstio_dbg_timeout = timeout;
726         args.lstio_dbg_nmlen   = (str == NULL) ? 0: strlen(str);
727         args.lstio_dbg_namep   = str;
728         args.lstio_dbg_count   = count;
729         args.lstio_dbg_idsp    = ids;
730         args.lstio_dbg_resultp = head;
731
732         return lst_ioctl (LSTIO_DEBUG, &args, sizeof(args));
733 }
734
735 int
736 lst_get_node_count(int type, char *str, int *countp, lnet_process_id_t **idspp)
737 {
738         char                    buf[LST_NAME_SIZE];
739         struct lstcon_test_batch_ent ent;
740         struct lstcon_ndlist_ent    *entp = &ent.tbe_cli_nle;
741         struct lst_sid sid;
742         unsigned                feats;
743         int                     key;
744         int                     rc;
745
746         switch (type) {
747         case LST_OPC_SESSION:
748                 rc = lst_session_info_ioctl(buf, LST_NAME_SIZE,
749                                             &key, &feats, &sid, entp);
750                 break;
751
752         case LST_OPC_BATCHSRV:
753                 entp = &ent.tbe_srv_nle;
754         case LST_OPC_BATCHCLI:
755                 rc = lst_info_batch_ioctl(str, 0, 0, &ent, NULL, NULL, NULL);
756                 break;
757
758         case LST_OPC_GROUP:
759                 rc = lst_info_group_ioctl(str, entp, NULL, NULL, NULL);
760                 break;
761
762         case LST_OPC_NODES:
763                 rc = lst_parse_nids(str, &entp->nle_nnode, idspp) < 0 ? -1 : 0;
764                 break;
765
766         default:
767                 rc = -1;
768                 break;
769         }
770
771         if (rc == 0)
772                 *countp = entp->nle_nnode;
773
774         return rc;
775 }
776
777 int
778 jt_lst_ping(int argc,  char **argv)
779 {
780         struct list_head   head;
781         lnet_process_id_t *ids = NULL;
782         struct lstcon_rpc_ent  *ent = NULL;
783         char              *str = NULL;
784         int                optidx  = 0;
785         int                server  = 0;
786         int                timeout = 5;
787         int                count   = 0;
788         int                type    = 0;
789         int                rc      = 0;
790         int                c;
791
792         static const struct option ping_opts[] = {
793                 { .name = "session", .has_arg = no_argument,       .val = 's' },
794                 { .name = "server",  .has_arg = no_argument,       .val = 'v' },
795                 { .name = "batch",   .has_arg = required_argument, .val = 'b' },
796                 { .name = "group",   .has_arg = required_argument, .val = 'g' },
797                 { .name = "nodes",   .has_arg = required_argument, .val = 'n' },
798                 { .name = "timeout", .has_arg = required_argument, .val = 't' },
799                 { .name = NULL, } };
800
801         if (session_key == 0) {
802                 fprintf(stderr,
803                         "Can't find env LST_SESSION or value is not valid\n");
804                 return -1;
805         }
806
807         while (1) {
808
809                 c = getopt_long(argc, argv, "g:b:n:t:sv",
810                                 ping_opts, &optidx);
811
812                 if (c == -1)
813                         break;
814
815                 switch (c) {
816                 case 's':
817                         type = LST_OPC_SESSION;
818                         break;
819
820                 case 'g':
821                         type = LST_OPC_GROUP;
822                         str = optarg;
823                         break;
824
825                 case 'b':
826                         type = LST_OPC_BATCHCLI;
827                         str = optarg;
828                         break;
829
830                 case 'n':
831                         type = LST_OPC_NODES;
832                         str = optarg;
833                         break;
834
835                 case 't':
836                         timeout = atoi(optarg);
837                         break;
838
839                 case 'v':
840                         server = 1;
841                         break;
842
843                 default:
844                         lst_print_usage(argv[0]);
845                         return -1;
846                 }
847         }
848
849         if (type == 0 || timeout <= 0 || optind != argc) {
850                 lst_print_usage(argv[0]);
851                 return -1;
852         }
853
854         if (type == LST_OPC_BATCHCLI && server)
855                 type = LST_OPC_BATCHSRV;
856
857         rc = lst_get_node_count(type, str, &count, &ids);
858         if (rc < 0) {
859                 fprintf(stderr, "Failed to get count of nodes from %s: %s\n",
860                         (str == NULL) ? "session" : str, strerror(errno));
861                 return -1;
862         }
863
864         INIT_LIST_HEAD(&head);
865
866         rc = lst_alloc_rpcent(&head, count, LST_NAME_SIZE);
867         if (rc != 0) {
868                 fprintf(stderr, "Out of memory\n");
869                 goto out;
870         }
871
872         if (count == 0) {
873                 fprintf(stdout, "Target %s is empty\n",
874                         (str == NULL) ? "session" : str);
875                 goto out;
876         }
877
878         rc = lst_ping_ioctl(str, type, timeout, count, ids, &head);
879         if (rc == -1) { /* local failure */
880                 lst_print_error("debug", "Failed to ping %s: %s\n",
881                                 (str == NULL) ? "session" : str,
882                                 strerror(errno));
883                 rc = -1;
884                 goto out;
885         }
886
887         /* ignore RPC errors and framwork errors */
888         list_for_each_entry(ent, &head, rpe_link) {
889                 fprintf(stdout, "\t%s: %s [session: %s id: %s]\n",
890                         libcfs_id2str(ent->rpe_peer),
891                         lst_node_state2str(ent->rpe_state),
892                         (ent->rpe_state == LST_NODE_ACTIVE ||
893                          ent->rpe_state == LST_NODE_BUSY) ?
894                                 (ent->rpe_rpc_errno == 0 ?
895                                         &ent->rpe_payload[0] : "Unknown") :
896                                 "<NULL>", libcfs_nid2str(ent->rpe_sid.ses_nid));
897         }
898
899 out:
900         lst_free_rpcent(&head);
901
902         if (ids != NULL)
903                 free(ids);
904
905         return rc;
906
907 }
908
909 int
910 lst_add_nodes_ioctl(char *name, int count, lnet_process_id_t *ids,
911                     unsigned *featp, struct list_head *resultp)
912 {
913         struct lstio_group_nodes_args args = { 0 };
914
915         args.lstio_grp_key     = session_key;
916         args.lstio_grp_nmlen   = strlen(name);
917         args.lstio_grp_namep   = name;
918         args.lstio_grp_count   = count;
919         args.lstio_grp_featp   = featp;
920         args.lstio_grp_idsp    = ids;
921         args.lstio_grp_resultp = resultp;
922
923         return lst_ioctl(LSTIO_NODES_ADD, &args, sizeof(args));
924 }
925
926 int
927 lst_del_group_ioctl(char *name)
928 {
929         struct lstio_group_del_args args = { 0 };
930
931         args.lstio_grp_key   = session_key;
932         args.lstio_grp_nmlen = strlen(name);
933         args.lstio_grp_namep = name;
934
935         return lst_ioctl(LSTIO_GROUP_DEL, &args, sizeof(args));
936 }
937
938 int
939 lst_del_group(char *grp_name)
940 {
941         int     rc;
942
943         rc = lst_del_group_ioctl(grp_name);
944         if (rc == 0) {
945                 fprintf(stdout, "Group is deleted\n");
946                 return 0;
947         }
948
949         if (rc == -1) {
950                 lst_print_error("group", "Failed to delete group: %s\n",
951                                 strerror(errno));
952                 return rc;
953         }
954
955         fprintf(stderr, "Group is deleted with some errors\n");
956
957         if (trans_stat.trs_rpc_errno != 0) {
958                 fprintf(stderr,
959                         "[RPC] Failed to send %d end session RPCs: %s\n",
960                         lstcon_rpc_stat_failure(&trans_stat, 0),
961                         strerror(trans_stat.trs_rpc_errno));
962         }
963
964         if (trans_stat.trs_fwk_errno != 0) {
965                 fprintf(stderr,
966                         "[FWK] Failed to end session on %d nodes: %s\n",
967                 lstcon_sesop_stat_failure(&trans_stat, 0),
968                 strerror(trans_stat.trs_fwk_errno));
969         }
970
971         return -1;
972 }
973
974 int
975 lst_add_group_ioctl(char *name)
976 {
977         struct lstio_group_add_args args = { 0 };
978
979         args.lstio_grp_key     =  session_key;
980         args.lstio_grp_nmlen   =  strlen(name);
981         args.lstio_grp_namep   =  name;
982
983         return lst_ioctl(LSTIO_GROUP_ADD, &args, sizeof(args));
984 }
985
986 int
987 jt_lst_add_group(int argc, char **argv)
988 {
989         struct list_head   head;
990         lnet_process_id_t *ids;
991         char              *name;
992         unsigned           feats = session_features;
993         int                count;
994         int                rc;
995         int                i;
996         bool               nodes_added = false;
997
998         if (session_key == 0) {
999                 fprintf(stderr,
1000                         "Can't find env LST_SESSION or value is not valid\n");
1001                 return -1;
1002         }
1003
1004         if (argc < 3) {
1005                 lst_print_usage(argv[0]);
1006                 return -1;
1007         }
1008
1009         name = argv[1];
1010         if (strlen(name) >= LST_NAME_SIZE) {
1011                 fprintf(stderr, "Name length is limited to %d\n",
1012                         LST_NAME_SIZE - 1);
1013                 return -1;
1014         }
1015
1016         rc = lst_add_group_ioctl(name);
1017         if (rc != 0) {
1018                 lst_print_error("group", "Failed to add group %s: %s\n",
1019                                 name, strerror(errno));
1020                 return -1;
1021         }
1022
1023         INIT_LIST_HEAD(&head);
1024
1025         for (i = 2; i < argc; i++) {
1026                 /* parse address list */
1027                 rc = lst_parse_nids(argv[i], &count, &ids);
1028                 if (rc < 0) {
1029                         fprintf(stderr, "Ignore invalid id list %s\n",
1030                                 argv[i]);
1031                         continue;
1032                 }
1033
1034                 if (count == 0)
1035                         continue;
1036
1037                 rc = lst_alloc_rpcent(&head, count, 0);
1038                 if (rc != 0) {
1039                         fprintf(stderr, "Out of memory\n");
1040                         free(ids);
1041                         rc = -1;
1042                         goto failed;
1043                 }
1044
1045                 rc = lst_add_nodes_ioctl(name, count, ids, &feats, &head);
1046
1047                 free(ids);
1048
1049                 if (rc != 0)
1050                         goto failed;
1051
1052                 fprintf(stdout, "%s are added to session\n", argv[i]);
1053
1054                 nodes_added = true;
1055
1056                 if ((feats & session_features) != session_features) {
1057                         fprintf(stdout,
1058                                 "Warning, this session will run with "
1059                                 "compatible mode because some test nodes "
1060                                 "might not understand these features: %x\n",
1061                                 (~feats & session_features));
1062                 }
1063
1064                 lst_free_rpcent(&head);
1065         }
1066
1067         if (!nodes_added) {
1068                 /*
1069                  * The selftest kernel module expects that a group should
1070                  * have at least one node, since it doesn't make sense for
1071                  * an empty group to be added to a test.
1072                  */
1073                 fprintf(stderr,
1074                         "No nodes added successfully, deleting group %s\n",
1075                         name);
1076                 rc = lst_del_group(name);
1077                 if (rc != 0) {
1078                         fprintf(stderr,
1079                                 "Failed to delete group %s."
1080                                 "  Group is empty.\n", name);
1081                 }
1082         }
1083
1084         return rc;
1085
1086 failed:
1087         if (rc == -1) {
1088                 lst_print_error("group", "Failed to add nodes %s: %s\n",
1089                                 argv[i], strerror(errno));
1090
1091         } else {
1092                 if (trans_stat.trs_fwk_errno == EPROTO) {
1093                         fprintf(stderr,
1094                                 "test nodes might have different LST "
1095                                 "features, please disable some features by "
1096                                 "setting LST_FEATURES\n");
1097                 }
1098
1099                 lst_print_transerr(&head, "create session");
1100         }
1101
1102         lst_free_rpcent(&head);
1103
1104         if (!nodes_added) {
1105                 fprintf(stderr,
1106                         "No nodes added successfully, deleting group %s\n",
1107                         name);
1108                 if (lst_del_group(name) != 0) {
1109                         fprintf(stderr,
1110                                 "Failed to delete group %s."
1111                                 "  Group is empty.\n", name);
1112                 }
1113         }
1114
1115         return rc;
1116 }
1117
1118 int
1119 jt_lst_del_group(int argc, char **argv)
1120 {
1121         int     rc;
1122
1123         if (session_key == 0) {
1124                 fprintf(stderr,
1125                         "Can't find env LST_SESSION or value is not valid\n");
1126                 return -1;
1127         }
1128
1129         if (argc != 2) {
1130                 lst_print_usage(argv[0]);
1131                 return -1;
1132         }
1133
1134         rc = lst_del_group(argv[1]);
1135
1136         return rc;
1137 }
1138
1139 int
1140 lst_update_group_ioctl(int opc, char *name, int clean, int count,
1141                        lnet_process_id_t *ids, struct list_head *resultp)
1142 {
1143         struct lstio_group_update_args args = { 0 };
1144
1145         args.lstio_grp_key      = session_key;
1146         args.lstio_grp_opc      = opc;
1147         args.lstio_grp_args     = clean;
1148         args.lstio_grp_nmlen    = strlen(name);
1149         args.lstio_grp_namep    = name;
1150         args.lstio_grp_count    = count;
1151         args.lstio_grp_idsp     = ids;
1152         args.lstio_grp_resultp  = resultp;
1153
1154         return lst_ioctl(LSTIO_GROUP_UPDATE, &args, sizeof(args));
1155 }
1156
1157 int
1158 jt_lst_update_group(int argc, char **argv)
1159 {
1160         struct list_head   head;
1161         lnet_process_id_t *ids = NULL;
1162         char              *str = NULL;
1163         char              *grp = NULL;
1164         int                optidx = 0;
1165         int                count = 0;
1166         int                clean = 0;
1167         int                opc = 0;
1168         int                rc;
1169         int                c;
1170
1171         static const struct option update_group_opts[] = {
1172                 { .name = "refresh", .has_arg = no_argument,       .val = 'f' },
1173                 { .name = "clean",   .has_arg = required_argument, .val = 'c' },
1174                 { .name = "remove",  .has_arg = required_argument, .val = 'r' },
1175                 { .name = NULL } };
1176
1177         if (session_key == 0) {
1178                 fprintf(stderr,
1179                         "Can't find env LST_SESSION or value is not valid\n");
1180                 return -1;
1181         }
1182
1183         while (1) {
1184                 c = getopt_long(argc, argv, "fc:r:",
1185                                 update_group_opts, &optidx);
1186
1187                 /* Detect the end of the options. */
1188                 if (c == -1)
1189                         break;
1190
1191                 switch (c) {
1192                 case 'f':
1193                         if (opc != 0) {
1194                                 lst_print_usage(argv[0]);
1195                                 return -1;
1196                         }
1197                         opc = LST_GROUP_REFRESH;
1198                         break;
1199
1200                 case 'r':
1201                         if (opc != 0) {
1202                                 lst_print_usage(argv[0]);
1203                                 return -1;
1204                         }
1205                         opc = LST_GROUP_RMND;
1206                         str = optarg;
1207                         break;
1208
1209                 case 'c':
1210                         clean = lst_node_str2state(optarg);
1211                         if (opc != 0 || clean <= 0) {
1212                                 lst_print_usage(argv[0]);
1213                                 return -1;
1214                         }
1215                         opc = LST_GROUP_CLEAN;
1216                         break;
1217
1218                 default:
1219                         lst_print_usage(argv[0]);
1220                         return -1;
1221                 }
1222         }
1223
1224         /* no OPC or group is specified */
1225         if (opc == 0 || optind != argc - 1) {
1226                 lst_print_usage(argv[0]);
1227                 return -1;
1228         }
1229
1230         grp = argv[optind];
1231
1232         INIT_LIST_HEAD(&head);
1233
1234         if (opc == LST_GROUP_RMND || opc == LST_GROUP_REFRESH) {
1235                 rc = lst_get_node_count(opc == LST_GROUP_RMND ? LST_OPC_NODES :
1236                                                                 LST_OPC_GROUP,
1237                                         opc == LST_GROUP_RMND ? str : grp,
1238                                         &count, &ids);
1239
1240                 if (rc != 0) {
1241                         fprintf(stderr, "Can't get count of nodes from %s: %s\n",
1242                                 opc == LST_GROUP_RMND ? str : grp,
1243                                 strerror(errno));
1244                         return -1;
1245                 }
1246
1247                 rc = lst_alloc_rpcent(&head, count, 0);
1248                 if (rc != 0) {
1249                         fprintf(stderr, "Out of memory\n");
1250                         free(ids);
1251                         return -1;
1252                 }
1253
1254         }
1255
1256         rc = lst_update_group_ioctl(opc, grp, clean, count, ids, &head);
1257
1258         if (ids != NULL)
1259                 free(ids);
1260
1261         if (rc == 0) {
1262                 lst_free_rpcent(&head);
1263                 return 0;
1264         }
1265
1266         if (rc == -1) {
1267                 lst_free_rpcent(&head);
1268                 lst_print_error("group", "Failed to update group: %s\n",
1269                                 strerror(errno));
1270                 return rc;
1271         }
1272
1273         lst_print_transerr(&head, "Updating group");
1274
1275         lst_free_rpcent(&head);
1276
1277         return rc;
1278 }
1279
1280 int
1281 lst_list_group_ioctl(int len, char *name, int idx)
1282 {
1283         struct lstio_group_list_args args = { 0 };
1284
1285         args.lstio_grp_key   = session_key;
1286         args.lstio_grp_idx   = idx;
1287         args.lstio_grp_nmlen = len;
1288         args.lstio_grp_namep = name;
1289
1290         return lst_ioctl(LSTIO_GROUP_LIST, &args, sizeof(args));
1291 }
1292
1293 int
1294 lst_info_group_ioctl(char *name, struct lstcon_ndlist_ent *gent,
1295                      int *idx, int *count, struct lstcon_node_ent *dents)
1296 {
1297         struct lstio_group_info_args args = { 0 };
1298
1299         args.lstio_grp_key    = session_key;
1300         args.lstio_grp_nmlen  = strlen(name);
1301         args.lstio_grp_namep  = name;
1302         args.lstio_grp_entp   = gent;
1303         args.lstio_grp_idxp   = idx;
1304         args.lstio_grp_ndentp = count;
1305         args.lstio_grp_dentsp = dents;
1306
1307         return lst_ioctl(LSTIO_GROUP_INFO, &args, sizeof(args));
1308 }
1309
1310 int
1311 lst_list_group_all(void)
1312 {
1313         char  name[LST_NAME_SIZE];
1314         int   rc;
1315         int   i;
1316
1317         /* no group is specified, list name of all groups */
1318         for (i = 0; ; i++) {
1319                 rc = lst_list_group_ioctl(LST_NAME_SIZE, name, i);
1320                 if (rc == 0) {
1321                         fprintf(stdout, "%d) %s\n", i + 1, name);
1322                         continue;
1323                 }
1324
1325                 if (errno == ENOENT)
1326                         break;
1327
1328                 lst_print_error("group", "Failed to list group: %s\n",
1329                                 strerror(errno));
1330                 return -1;
1331         }
1332
1333         fprintf(stdout, "Total %d groups\n", i);
1334
1335         return 0;
1336 }
1337
1338 #define LST_NODES_TITLE "\tACTIVE\tBUSY\tDOWN\tUNKNOWN\tTOTAL\n"
1339
1340 int
1341 jt_lst_list_group(int argc, char **argv)
1342 {
1343         struct lstcon_ndlist_ent gent;
1344         struct lstcon_node_ent   *dents;
1345         int optidx  = 0;
1346         int verbose = 0;
1347         int active  = 0;
1348         int busy    = 0;
1349         int down    = 0;
1350         int unknown = 0;
1351         int all     = 0;
1352         int count;
1353         int index;
1354         int i;
1355         int j;
1356         int c;
1357         int rc      = 0;
1358
1359         static const struct option list_group_opts[] = {
1360                 { .name = "active",  .has_arg = no_argument, .val = 'a' },
1361                 { .name = "busy",    .has_arg = no_argument, .val = 'b' },
1362                 { .name = "down",    .has_arg = no_argument, .val = 'd' },
1363                 { .name = "unknown", .has_arg = no_argument, .val = 'u' },
1364                 { .name = "all",     .has_arg = no_argument, .val = 'l' },
1365                 { .name = NULL, } };
1366
1367         if (session_key == 0) {
1368                 fprintf(stderr,
1369                         "Can't find env LST_SESSION or value is not valid\n");
1370                 return -1;
1371         }
1372
1373         while (1) {
1374                 c = getopt_long(argc, argv, "abdul",
1375                                 list_group_opts, &optidx);
1376
1377                 if (c == -1)
1378                         break;
1379
1380                 switch (c) {
1381                 case 'a':
1382                         verbose = active = 1;
1383                         all = 0;
1384                         break;
1385                 case 'b':
1386                         verbose = busy = 1;
1387                         all = 0;
1388                         break;
1389                 case 'd':
1390                         verbose = down = 1;
1391                         all = 0;
1392                         break;
1393                 case 'u':
1394                         verbose = unknown = 1;
1395                         all = 0;
1396                         break;
1397                 case 'l':
1398                         verbose = all = 1;
1399                         break;
1400                 default:
1401                         lst_print_usage(argv[0]);
1402                         return -1;
1403                 }
1404         }
1405
1406         if (optind == argc) {
1407                 /* no group is specified, list name of all groups */
1408                 rc = lst_list_group_all();
1409
1410                 return rc;
1411         }
1412
1413         if (!verbose)
1414                 fprintf(stdout, LST_NODES_TITLE);
1415
1416         /* list nodes in specified groups */
1417         for (i = optind; i < argc; i++) {
1418                 rc = lst_info_group_ioctl(argv[i], &gent, NULL, NULL, NULL);
1419                 if (rc != 0) {
1420                         if (errno == ENOENT) {
1421                                 rc = 0;
1422                                 break;
1423                         }
1424
1425                         lst_print_error("group", "Failed to list group\n",
1426                                         strerror(errno));
1427                         break;
1428                 }
1429
1430                 if (!verbose) {
1431                         fprintf(stdout, "\t%d\t%d\t%d\t%d\t%d\t%s\n",
1432                                 gent.nle_nactive, gent.nle_nbusy,
1433                                 gent.nle_ndown, gent.nle_nunknown,
1434                                 gent.nle_nnode, argv[i]);
1435                         continue;
1436                 }
1437
1438                 fprintf(stdout, "Group [ %s ]\n", argv[i]);
1439
1440                 if (gent.nle_nnode == 0) {
1441                         fprintf(stdout, "No nodes found [ %s ]\n", argv[i]);
1442                         continue;
1443                 }
1444
1445                 count = gent.nle_nnode;
1446
1447                 dents = malloc(count * sizeof(struct lstcon_node_ent));
1448                 if (dents == NULL) {
1449                         fprintf(stderr, "Failed to malloc: %s\n",
1450                                 strerror(errno));
1451                         return -1;
1452                 }
1453
1454                 index = 0;
1455                 rc = lst_info_group_ioctl(argv[i], &gent, &index, &count, dents);
1456                 if (rc != 0) {
1457                         lst_print_error("group", "Failed to list group: %s\n",
1458                                         strerror(errno));
1459                         free(dents);
1460                         return -1;
1461                 }
1462
1463                 for (j = 0, c = 0; j < count; j++) {
1464                         if (all ||
1465                             ((active  &&  dents[j].nde_state == LST_NODE_ACTIVE) ||
1466                              (busy    &&  dents[j].nde_state == LST_NODE_BUSY)   ||
1467                              (down    &&  dents[j].nde_state == LST_NODE_DOWN)   ||
1468                              (unknown &&  dents[j].nde_state == LST_NODE_UNKNOWN))) {
1469
1470                                 fprintf(stdout, "\t%s: %s\n",
1471                                         libcfs_id2str(dents[j].nde_id),
1472                                         lst_node_state2str(dents[j].nde_state));
1473                                 c++;
1474                         }
1475                 }
1476
1477                 fprintf(stdout, "Total %d nodes [ %s ]\n", c, argv[i]);
1478
1479                 free(dents);
1480         }
1481
1482         return rc;
1483 }
1484
1485 int
1486 lst_stat_ioctl (char *name, int count, lnet_process_id_t *idsp,
1487                 int timeout, struct list_head *resultp)
1488 {
1489         struct lstio_stat_args args = { 0 };
1490
1491         args.lstio_sta_key     = session_key;
1492         args.lstio_sta_timeout = timeout;
1493         args.lstio_sta_nmlen   = strlen(name);
1494         args.lstio_sta_namep   = name;
1495         args.lstio_sta_count   = count;
1496         args.lstio_sta_idsp    = idsp;
1497         args.lstio_sta_resultp = resultp;
1498
1499         return lst_ioctl(LSTIO_STAT_QUERY, &args, sizeof(args));
1500 }
1501
1502 typedef struct {
1503         struct list_head              srp_link;
1504         int                     srp_count;
1505         char                   *srp_name;
1506         lnet_process_id_t      *srp_ids;
1507         struct list_head              srp_result[2];
1508 } lst_stat_req_param_t;
1509
1510 static void
1511 lst_stat_req_param_free(lst_stat_req_param_t *srp)
1512 {
1513         int     i;
1514
1515         for (i = 0; i < 2; i++)
1516                 lst_free_rpcent(&srp->srp_result[i]);
1517
1518         if (srp->srp_ids != NULL)
1519                 free(srp->srp_ids);
1520
1521         free(srp);
1522 }
1523
1524 static int
1525 lst_stat_req_param_alloc(char *name, lst_stat_req_param_t **srpp, int save_old)
1526 {
1527         lst_stat_req_param_t *srp = NULL;
1528         int                   count = save_old ? 2 : 1;
1529         int                   rc;
1530         int                   i;
1531
1532         srp = malloc(sizeof(*srp));
1533         if (srp == NULL)
1534                 return -ENOMEM;
1535
1536         memset(srp, 0, sizeof(*srp));
1537         INIT_LIST_HEAD(&srp->srp_result[0]);
1538         INIT_LIST_HEAD(&srp->srp_result[1]);
1539
1540         rc = lst_get_node_count(LST_OPC_GROUP, name,
1541                                 &srp->srp_count, NULL);
1542         if (rc != 0 && errno == ENOENT) {
1543                 rc = lst_get_node_count(LST_OPC_NODES, name,
1544                                         &srp->srp_count, &srp->srp_ids);
1545         }
1546
1547         if (rc != 0) {
1548                 fprintf(stderr,
1549                         "Failed to get count of nodes from %s: %s\n",
1550                         name, strerror(errno));
1551                 lst_stat_req_param_free(srp);
1552
1553                 return rc;
1554         }
1555
1556         srp->srp_name = name;
1557
1558         for (i = 0; i < count; i++) {
1559                 rc = lst_alloc_rpcent(&srp->srp_result[i], srp->srp_count,
1560                                       sizeof(struct sfw_counters)  +
1561                                       sizeof(struct srpc_counters) +
1562                                       sizeof(lnet_counters_t));
1563                 if (rc != 0) {
1564                         fprintf(stderr, "Out of memory\n");
1565                         break;
1566                 }
1567         }
1568
1569         if (rc == 0) {
1570                 *srpp = srp;
1571                 return 0;
1572         }
1573
1574         lst_stat_req_param_free(srp);
1575
1576         return rc;
1577 }
1578
1579 typedef struct {
1580         /* TODO */
1581         int foo;
1582 } lst_srpc_stat_result;
1583
1584 #define LST_LNET_AVG    0
1585 #define LST_LNET_MIN    1
1586 #define LST_LNET_MAX    2
1587
1588 typedef struct {
1589         float           lnet_avg_sndrate;
1590         float           lnet_min_sndrate;
1591         float           lnet_max_sndrate;
1592         float           lnet_total_sndrate;
1593
1594         float           lnet_avg_rcvrate;
1595         float           lnet_min_rcvrate;
1596         float           lnet_max_rcvrate;
1597         float           lnet_total_rcvrate;
1598
1599         float           lnet_avg_sndperf;
1600         float           lnet_min_sndperf;
1601         float           lnet_max_sndperf;
1602         float           lnet_total_sndperf;
1603
1604         float           lnet_avg_rcvperf;
1605         float           lnet_min_rcvperf;
1606         float           lnet_max_rcvperf;
1607         float           lnet_total_rcvperf;
1608
1609         int             lnet_stat_count;
1610 } lst_lnet_stat_result_t;
1611
1612 lst_lnet_stat_result_t lnet_stat_result;
1613
1614 static float
1615 lst_lnet_stat_value(int bw, int send, int off)
1616 {
1617         float  *p;
1618
1619         p = bw ? &lnet_stat_result.lnet_avg_sndperf :
1620                  &lnet_stat_result.lnet_avg_sndrate;
1621
1622         if (!send)
1623                 p += 4;
1624
1625         p += off;
1626
1627         return *p;
1628 }
1629
1630 static void
1631 lst_timeval_diff(struct timeval *tv1,
1632                  struct timeval *tv2, struct timeval *df)
1633 {
1634         if (tv1->tv_usec >= tv2->tv_usec) {
1635                 df->tv_sec  = tv1->tv_sec - tv2->tv_sec;
1636                 df->tv_usec = tv1->tv_usec - tv2->tv_usec;
1637                 return;
1638         }
1639
1640         df->tv_sec  = tv1->tv_sec - 1 - tv2->tv_sec;
1641         df->tv_usec = tv1->tv_usec + 1000000 - tv2->tv_usec;
1642
1643         return;
1644 }
1645
1646 static void
1647 lst_cal_lnet_stat(float delta, lnet_counters_t *lnet_new,
1648                   lnet_counters_t *lnet_old, int mbs)
1649 {
1650         float perf;
1651         float rate;
1652         unsigned int unit_divisor;
1653
1654         unit_divisor = (mbs) ? (1000 * 1000) : (1024 * 1024);
1655         perf = (float)(lnet_new->send_length -
1656                        lnet_old->send_length) / unit_divisor / delta;
1657         lnet_stat_result.lnet_total_sndperf += perf;
1658
1659         if (lnet_stat_result.lnet_min_sndperf > perf ||
1660             lnet_stat_result.lnet_min_sndperf == 0)
1661                 lnet_stat_result.lnet_min_sndperf = perf;
1662
1663         if (lnet_stat_result.lnet_max_sndperf < perf)
1664                 lnet_stat_result.lnet_max_sndperf = perf;
1665
1666         perf = (float)(lnet_new->recv_length -
1667                        lnet_old->recv_length) / unit_divisor / delta;
1668         lnet_stat_result.lnet_total_rcvperf += perf;
1669
1670         if (lnet_stat_result.lnet_min_rcvperf > perf ||
1671             lnet_stat_result.lnet_min_rcvperf == 0)
1672                 lnet_stat_result.lnet_min_rcvperf = perf;
1673
1674         if (lnet_stat_result.lnet_max_rcvperf < perf)
1675                 lnet_stat_result.lnet_max_rcvperf = perf;
1676
1677         rate = (lnet_new->send_count - lnet_old->send_count) / delta;
1678         lnet_stat_result.lnet_total_sndrate += rate;
1679
1680         if (lnet_stat_result.lnet_min_sndrate > rate ||
1681             lnet_stat_result.lnet_min_sndrate == 0)
1682                 lnet_stat_result.lnet_min_sndrate = rate;
1683
1684         if (lnet_stat_result.lnet_max_sndrate < rate)
1685                 lnet_stat_result.lnet_max_sndrate = rate;
1686
1687         rate = (lnet_new->recv_count - lnet_old->recv_count) / delta;
1688         lnet_stat_result.lnet_total_rcvrate += rate;
1689
1690         if (lnet_stat_result.lnet_min_rcvrate > rate ||
1691             lnet_stat_result.lnet_min_rcvrate == 0)
1692                 lnet_stat_result.lnet_min_rcvrate = rate;
1693
1694         if (lnet_stat_result.lnet_max_rcvrate < rate)
1695                 lnet_stat_result.lnet_max_rcvrate = rate;
1696
1697         lnet_stat_result.lnet_stat_count++;
1698
1699         lnet_stat_result.lnet_avg_sndrate = lnet_stat_result.lnet_total_sndrate /
1700                                             lnet_stat_result.lnet_stat_count;
1701         lnet_stat_result.lnet_avg_rcvrate = lnet_stat_result.lnet_total_rcvrate /
1702                                             lnet_stat_result.lnet_stat_count;
1703
1704         lnet_stat_result.lnet_avg_sndperf = lnet_stat_result.lnet_total_sndperf /
1705                                             lnet_stat_result.lnet_stat_count;
1706         lnet_stat_result.lnet_avg_rcvperf = lnet_stat_result.lnet_total_rcvperf /
1707                                             lnet_stat_result.lnet_stat_count;
1708 }
1709
1710 static void
1711 lst_print_lnet_stat(char *name, int bwrt, int rdwr, int type, int mbs)
1712 {
1713         int     start1 = 0;
1714         int     end1   = 1;
1715         int     start2 = 0;
1716         int     end2   = 1;
1717         int     i;
1718         int     j;
1719         char   *units;
1720
1721         if (lnet_stat_result.lnet_stat_count == 0)
1722                 return;
1723
1724         units = (mbs) ? "MB/s  " : "MiB/s ";
1725
1726         if (bwrt == 1) /* bw only */
1727                 start1 = 1;
1728
1729         if (bwrt == 2) /* rates only */
1730                 end1 = 0;
1731
1732         if (rdwr == 1) /* recv only */
1733                 start2 = 1;
1734
1735         if (rdwr == 2) /* send only */
1736                 end2 = 0;
1737
1738         for (i = start1; i <= end1; i++) {
1739                 fprintf(stdout, "[LNet %s of %s]\n",
1740                         i == 0 ? "Rates" : "Bandwidth", name);
1741
1742                 for (j = start2; j <= end2; j++) {
1743                         fprintf(stdout, "[%c] ", j == 0 ? 'R' : 'W');
1744
1745                         if ((type & 1) != 0) {
1746                                 fprintf(stdout, i == 0 ? "Avg: %-8.0f RPC/s " :
1747                                                          "Avg: %-8.2f %s",
1748                                         lst_lnet_stat_value(i, j, 0), units);
1749                         }
1750
1751                         if ((type & 2) != 0) {
1752                                 fprintf(stdout, i == 0 ? "Min: %-8.0f RPC/s " :
1753                                                          "Min: %-8.2f %s",
1754                                         lst_lnet_stat_value(i, j, 1), units);
1755                         }
1756
1757                         if ((type & 4) != 0) {
1758                                 fprintf(stdout, i == 0 ? "Max: %-8.0f RPC/s" :
1759                                                          "Max: %-8.2f %s",
1760                                         lst_lnet_stat_value(i, j, 2), units);
1761                         }
1762
1763                         fprintf(stdout, "\n");
1764                 }
1765         }
1766 }
1767
1768 static void
1769 lst_print_stat(char *name, struct list_head *resultp,
1770                int idx, int lnet, int bwrt, int rdwr, int type,
1771                int mbs)
1772 {
1773         struct list_head        tmp[2];
1774         struct lstcon_rpc_ent *new;
1775         struct lstcon_rpc_ent *old;
1776         struct sfw_counters   *sfwk_new;
1777         struct sfw_counters   *sfwk_old;
1778         struct srpc_counters  *srpc_new;
1779         struct srpc_counters  *srpc_old;
1780         lnet_counters_t  *lnet_new;
1781         lnet_counters_t  *lnet_old;
1782         float             delta;
1783         int               errcount = 0;
1784
1785         INIT_LIST_HEAD(&tmp[0]);
1786         INIT_LIST_HEAD(&tmp[1]);
1787
1788         memset(&lnet_stat_result, 0, sizeof(lnet_stat_result));
1789
1790         while (!list_empty(&resultp[idx])) {
1791                 if (list_empty(&resultp[1 - idx])) {
1792                         fprintf(stderr, "Group is changed, re-run stat\n");
1793                         break;
1794                 }
1795
1796                 new = list_entry(resultp[idx].next, struct lstcon_rpc_ent,
1797                                      rpe_link);
1798                 old = list_entry(resultp[1 - idx].next, struct lstcon_rpc_ent,
1799                                      rpe_link);
1800
1801                 /* first time get stats result, can't calculate diff */
1802                 if (new->rpe_peer.nid == LNET_NID_ANY)
1803                         break;
1804
1805                 if (new->rpe_peer.nid != old->rpe_peer.nid ||
1806                     new->rpe_peer.pid != old->rpe_peer.pid) {
1807                         /* Something wrong. i.e, somebody change the group */
1808                         break;
1809                 }
1810
1811                 list_del(&new->rpe_link);
1812                 list_add_tail(&new->rpe_link, &tmp[idx]);
1813
1814                 list_del(&old->rpe_link);
1815                 list_add_tail(&old->rpe_link, &tmp[1 - idx]);
1816
1817                 if (new->rpe_rpc_errno != 0 || new->rpe_fwk_errno != 0 ||
1818                     old->rpe_rpc_errno != 0 || old->rpe_fwk_errno != 0) {
1819                         errcount ++;
1820                         continue;
1821                 }
1822
1823                 sfwk_new = (struct sfw_counters *)&new->rpe_payload[0];
1824                 sfwk_old = (struct sfw_counters *)&old->rpe_payload[0];
1825
1826                 srpc_new = (struct srpc_counters *)((char *)sfwk_new + sizeof(*sfwk_new));
1827                 srpc_old = (struct srpc_counters *)((char *)sfwk_old + sizeof(*sfwk_old));
1828
1829                 lnet_new = (lnet_counters_t *)((char *)srpc_new + sizeof(*srpc_new));
1830                 lnet_old = (lnet_counters_t *)((char *)srpc_old + sizeof(*srpc_old));
1831
1832                 /* Prior to version 2.3, the running_ms field was a counter for
1833                  * the number of running tests.  We are looking at this value
1834                  * to determine if it is a millisecond timestamep (>= 2.3) or a
1835                  * test counter (< 2.3).  The number 500 is being used for this
1836                  * barrier as the test counter should never get this high, and
1837                  * the timestamp should never get this low. */
1838
1839                 if (sfwk_new->running_ms > 500) {
1840                         /* use the timestamp from the remote node, not our
1841                          * rpe_stamp from when we copied up the data out of
1842                          * the kernel */
1843
1844                         delta = (float) (sfwk_new->running_ms -
1845                                         sfwk_old->running_ms) / 1000;
1846                 } else {
1847                         struct timeval    tv;
1848
1849                         lst_timeval_diff(&new->rpe_stamp, &old->rpe_stamp, &tv);
1850                         delta = tv.tv_sec + (float)tv.tv_usec / 1000000;
1851                 }
1852
1853                 if (!lnet) /* TODO */
1854                         continue;
1855
1856                 lst_cal_lnet_stat(delta, lnet_new, lnet_old, mbs);
1857         }
1858
1859         list_splice(&tmp[idx], &resultp[idx]);
1860         list_splice(&tmp[1 - idx], &resultp[1 - idx]);
1861
1862         if (errcount > 0)
1863                 fprintf(stdout, "Failed to stat on %d nodes\n", errcount);
1864
1865         if (!lnet)  /* TODO */
1866                 return;
1867
1868         lst_print_lnet_stat(name, bwrt, rdwr, type, mbs);
1869 }
1870
1871 int
1872 jt_lst_stat(int argc, char **argv)
1873 {
1874         struct list_head        head;
1875         lst_stat_req_param_t *srp;
1876         time_t                last    = 0;
1877         int                   optidx  = 0;
1878         int                   timeout = 5; /* default timeout, 5 sec */
1879         int                   delay   = 5; /* default delay, 5 sec */
1880         int                   count   = -1; /* run forever */
1881         int                   lnet    = 1; /* lnet stat by default */
1882         int                   bwrt    = 0;
1883         int                   rdwr    = 0;
1884         int                   type    = -1;
1885         int                   idx     = 0;
1886         int                   rc;
1887         int                   c;
1888         int                   mbs     = 0; /* report as MB/s */
1889
1890         static const struct option stat_opts[] = {
1891                 { .name = "timeout", .has_arg = required_argument, .val = 't' },
1892                 { .name = "delay",   .has_arg = required_argument, .val = 'd' },
1893                 { .name = "count",   .has_arg = required_argument, .val = 'o' },
1894                 { .name = "lnet",    .has_arg = no_argument,       .val = 'l' },
1895                 { .name = "rpc",     .has_arg = no_argument,       .val = 'c' },
1896                 { .name = "bw",      .has_arg = no_argument,       .val = 'b' },
1897                 { .name = "rate",    .has_arg = no_argument,       .val = 'a' },
1898                 { .name = "read",    .has_arg = no_argument,       .val = 'r' },
1899                 { .name = "write",   .has_arg = no_argument,       .val = 'w' },
1900                 { .name = "avg",     .has_arg = no_argument,       .val = 'g' },
1901                 { .name = "min",     .has_arg = no_argument,       .val = 'n' },
1902                 { .name = "max",     .has_arg = no_argument,       .val = 'x' },
1903                 { .name = "mbs",     .has_arg = no_argument,       .val = 'm' },
1904                 { .name = NULL } };
1905
1906         if (session_key == 0) {
1907                 fprintf(stderr,
1908                         "Can't find env LST_SESSION or value is not valid\n");
1909                 return -1;
1910         }
1911
1912         while (1) {
1913                 c = getopt_long(argc, argv, "t:d:lcbarwgnxm", stat_opts,
1914                                 &optidx);
1915
1916                 if (c == -1)
1917                         break;
1918
1919                 switch (c) {
1920                 case 't':
1921                         timeout = atoi(optarg);
1922                         break;
1923                 case 'd':
1924                         delay = atoi(optarg);
1925                         break;
1926                 case 'o':
1927                         count = atoi(optarg);
1928                         break;
1929                 case 'l':
1930                         lnet = 1;
1931                         break;
1932                 case 'c':
1933                         lnet = 0;
1934                         break;
1935                 case 'b':
1936                         bwrt |= 1;
1937                         break;
1938                 case 'a':
1939                         bwrt |= 2;
1940                         break;
1941                 case 'r':
1942                         rdwr |= 1;
1943                         break;
1944                 case 'w':
1945                         rdwr |= 2;
1946                         break;
1947                 case 'g':
1948                         if (type == -1) {
1949                                 type = 1;
1950                                 break;
1951                         }
1952                         type |= 1;
1953                         break;
1954                 case 'n':
1955                         if (type == -1) {
1956                                 type = 2;
1957                                 break;
1958                         }
1959                         type |= 2;
1960                         break;
1961                 case 'x':
1962                         if (type == -1) {
1963                                 type = 4;
1964                                 break;
1965                         }
1966                         type |= 4;
1967                         break;
1968                 case 'm':
1969                         mbs = 1;
1970                         break;
1971
1972                 default:
1973                         lst_print_usage(argv[0]);
1974                         return -1;
1975                 }
1976         }
1977
1978         if (optind == argc) {
1979                 lst_print_usage(argv[0]);
1980                 return -1;
1981         }
1982
1983         if (timeout <= 0 || delay <= 0) {
1984                 fprintf(stderr, "Invalid timeout or delay value\n");
1985                 return -1;
1986         }
1987
1988         if (count < -1) {
1989             fprintf(stderr, "Invalid count value\n");
1990             return -1;
1991         }
1992
1993         /* extra count to get first data point */
1994         if (count != -1)
1995             count++;
1996
1997         INIT_LIST_HEAD(&head);
1998
1999         while (optind < argc) {
2000                 rc = lst_stat_req_param_alloc(argv[optind++], &srp, 1);
2001                 if (rc != 0)
2002                         goto out;
2003
2004                 list_add_tail(&srp->srp_link, &head);
2005         }
2006
2007         do {
2008                 time_t  now = time(NULL);
2009
2010                 if (now - last < delay) {
2011                         sleep(delay - now + last);
2012                         time(&now);
2013                 }
2014                 last = now;
2015
2016                 list_for_each_entry(srp, &head, srp_link) {
2017                         rc = lst_stat_ioctl(srp->srp_name,
2018                                             srp->srp_count, srp->srp_ids,
2019                                             timeout, &srp->srp_result[idx]);
2020                         if (rc == -1) {
2021                                 lst_print_error("stat", "Failed to stat %s: %s\n",
2022                                                 srp->srp_name, strerror(errno));
2023                                 goto out;
2024                         }
2025
2026                         lst_print_stat(srp->srp_name, srp->srp_result,
2027                                        idx, lnet, bwrt, rdwr, type, mbs);
2028
2029                         lst_reset_rpcent(&srp->srp_result[1 - idx]);
2030                 }
2031
2032                 idx = 1 - idx;
2033
2034                 if (count > 0)
2035                         count--;
2036         } while (count == -1 || count > 0);
2037
2038 out:
2039         while (!list_empty(&head)) {
2040                 srp = list_entry(head.next, lst_stat_req_param_t, srp_link);
2041
2042                 list_del(&srp->srp_link);
2043                 lst_stat_req_param_free(srp);
2044         }
2045
2046         return rc;
2047 }
2048
2049 int
2050 jt_lst_show_error(int argc, char **argv)
2051 {
2052         struct list_head       head;
2053         lst_stat_req_param_t  *srp;
2054         struct lstcon_rpc_ent *ent;
2055         struct sfw_counters   *sfwk;
2056         struct srpc_counters  *srpc;
2057         int                    show_rpc = 1;
2058         int                    optidx = 0;
2059         int                    rc = 0;
2060         int                    ecount;
2061         int                    c;
2062
2063         static const struct option show_error_opts[] = {
2064                 { .name = "session", .has_arg = no_argument, .val = 's' },
2065                 { .name = NULL, } };
2066
2067         if (session_key == 0) {
2068                 fprintf(stderr,
2069                         "Can't find env LST_SESSION or value is not valid\n");
2070                 return -1;
2071         }
2072
2073         while (1) {
2074                 c = getopt_long(argc, argv, "s", show_error_opts, &optidx);
2075
2076                 if (c == -1)
2077                         break;
2078
2079                 switch (c) {
2080                 case 's':
2081                         show_rpc  = 0;
2082                         break;
2083
2084                 default:
2085                         lst_print_usage(argv[0]);
2086                         return -1;
2087                 }
2088         }
2089
2090         if (optind == argc) {
2091                 lst_print_usage(argv[0]);
2092                 return -1;
2093         }
2094
2095         INIT_LIST_HEAD(&head);
2096
2097         while (optind < argc) {
2098                 rc = lst_stat_req_param_alloc(argv[optind++], &srp, 0);
2099                 if (rc != 0)
2100                         goto out;
2101
2102                 list_add_tail(&srp->srp_link, &head);
2103         }
2104
2105         list_for_each_entry(srp, &head, srp_link) {
2106                 rc = lst_stat_ioctl(srp->srp_name, srp->srp_count,
2107                                     srp->srp_ids, 10, &srp->srp_result[0]);
2108
2109                 if (rc == -1) {
2110                         lst_print_error(srp->srp_name, "Failed to show errors of %s: %s\n",
2111                                         srp->srp_name, strerror(errno));
2112                         goto out;
2113                 }
2114
2115                 fprintf(stdout, "%s:\n", srp->srp_name);
2116
2117                 ecount = 0;
2118
2119                 list_for_each_entry(ent, &srp->srp_result[0], rpe_link) {
2120                         if (ent->rpe_rpc_errno != 0) {
2121                                 ecount ++;
2122                                 fprintf(stderr, "RPC failure, can't show error on %s\n",
2123                                         libcfs_id2str(ent->rpe_peer));
2124                                 continue;
2125                         }
2126
2127                         if (ent->rpe_fwk_errno != 0) {
2128                                 ecount ++;
2129                                 fprintf(stderr, "Framework failure, can't show error on %s\n",
2130                                         libcfs_id2str(ent->rpe_peer));
2131                                 continue;
2132                         }
2133
2134                         sfwk = (struct sfw_counters *)&ent->rpe_payload[0];
2135                         srpc = (struct srpc_counters *)((char *)sfwk + sizeof(*sfwk));
2136
2137                         if (srpc->errors == 0 &&
2138                             sfwk->brw_errors == 0 && sfwk->ping_errors == 0)
2139                                 continue;
2140
2141                         if (!show_rpc  &&
2142                             sfwk->brw_errors == 0 && sfwk->ping_errors == 0)
2143                                 continue;
2144
2145                         ecount ++;
2146
2147                         fprintf(stderr, "%s: [Session %d brw errors, %d ping errors]%c",
2148                                 libcfs_id2str(ent->rpe_peer),
2149                                 sfwk->brw_errors, sfwk->ping_errors,
2150                                 show_rpc  ? ' ' : '\n');
2151
2152                         if (!show_rpc)
2153                                 continue;
2154
2155                         fprintf(stderr, "[RPC: %d errors, %d dropped, %d expired]\n",
2156                                 srpc->errors, srpc->rpcs_dropped, srpc->rpcs_expired);
2157                 }
2158
2159                 fprintf(stdout, "Total %d error nodes in %s\n", ecount, srp->srp_name);
2160         }
2161 out:
2162         while (!list_empty(&head)) {
2163                 srp = list_entry(head.next, lst_stat_req_param_t, srp_link);
2164
2165                 list_del(&srp->srp_link);
2166                 lst_stat_req_param_free(srp);
2167         }
2168
2169         return rc;
2170 }
2171
2172 int
2173 lst_add_batch_ioctl(char *name)
2174 {
2175         struct lstio_batch_add_args args = { 0 };
2176
2177         args.lstio_bat_key   = session_key;
2178         args.lstio_bat_nmlen = strlen(name);
2179         args.lstio_bat_namep = name;
2180
2181         return lst_ioctl (LSTIO_BATCH_ADD, &args, sizeof(args));
2182 }
2183
2184 int
2185 jt_lst_add_batch(int argc, char **argv)
2186 {
2187         char   *name;
2188         int     rc;
2189
2190         if (session_key == 0) {
2191                 fprintf(stderr,
2192                         "Can't find env LST_SESSION or value is not valid\n");
2193                 return -1;
2194         }
2195
2196         if (argc != 2) {
2197                 lst_print_usage(argv[0]);
2198                 return -1;
2199         }
2200
2201         name = argv[1];
2202         if (strlen(name) >= LST_NAME_SIZE) {
2203                 fprintf(stderr, "Name length is limited to %d\n",
2204                         LST_NAME_SIZE - 1);
2205                 return -1;
2206         }
2207
2208         rc = lst_add_batch_ioctl(name);
2209         if (rc == 0)
2210                 return 0;
2211
2212         lst_print_error("batch", "Failed to create batch: %s\n",
2213                         strerror(errno));
2214
2215         return -1;
2216 }
2217
2218 int
2219 lst_start_batch_ioctl(char *name, int timeout, struct list_head *resultp)
2220 {
2221         struct lstio_batch_run_args args = { 0 };
2222
2223         args.lstio_bat_key     = session_key;
2224         args.lstio_bat_timeout = timeout;
2225         args.lstio_bat_nmlen   = strlen(name);
2226         args.lstio_bat_namep   = name;
2227         args.lstio_bat_resultp = resultp;
2228
2229         return lst_ioctl(LSTIO_BATCH_START, &args, sizeof(args));
2230 }
2231
2232 int
2233 jt_lst_start_batch(int argc, char **argv)
2234 {
2235         struct list_head  head;
2236         char             *batch;
2237         int               optidx = 0;
2238         int               timeout = 0;
2239         int               count = 0;
2240         int               rc;
2241         int               c;
2242
2243         static const struct option start_batch_opts[] = {
2244                 { .name = "timeout", .has_arg = required_argument, .val = 't' },
2245                 { .name = NULL } };
2246
2247         if (session_key == 0) {
2248                 fprintf(stderr,
2249                         "Can't find env LST_SESSION or value is not valid\n");
2250                 return -1;
2251         }
2252
2253         while (1) {
2254                 c = getopt_long(argc, argv, "t:",
2255                                 start_batch_opts, &optidx);
2256
2257                 /* Detect the end of the options. */
2258                 if (c == -1)
2259                         break;
2260
2261                 switch (c) {
2262                 case 't':
2263                         timeout = atoi(optarg);
2264                         break;
2265                 default:
2266                         lst_print_usage(argv[0]);
2267                         return -1;
2268                 }
2269         }
2270
2271         if (optind == argc) {
2272                 batch = LST_DEFAULT_BATCH;
2273
2274         } else if (optind == argc - 1) {
2275                 batch = argv[optind];
2276
2277         } else {
2278                 lst_print_usage(argv[0]);
2279                 return -1;
2280         }
2281
2282         rc = lst_get_node_count(LST_OPC_BATCHCLI, batch, &count, NULL);
2283         if (rc != 0) {
2284                 fprintf(stderr, "Failed to get count of nodes from %s: %s\n",
2285                         batch, strerror(errno));
2286                 return -1;
2287         }
2288
2289         INIT_LIST_HEAD(&head);
2290
2291         rc = lst_alloc_rpcent(&head, count, 0);
2292         if (rc != 0) {
2293                 fprintf(stderr, "Out of memory\n");
2294                 return -1;
2295         }
2296
2297         rc = lst_start_batch_ioctl(batch, timeout, &head);
2298
2299         if (rc == 0) {
2300                 fprintf(stdout, "%s is running now\n", batch);
2301                 lst_free_rpcent(&head);
2302                 return 0;
2303         }
2304
2305         if (rc == -1) {
2306                 lst_print_error("batch", "Failed to start batch: %s\n",
2307                                 strerror(errno));
2308                 lst_free_rpcent(&head);
2309                 return rc;
2310         }
2311
2312         lst_print_transerr(&head, "Run batch");
2313
2314         lst_free_rpcent(&head);
2315
2316         return rc;
2317 }
2318
2319 int
2320 lst_stop_batch_ioctl(char *name, int force, struct list_head *resultp)
2321 {
2322         struct lstio_batch_stop_args args = { 0 };
2323
2324         args.lstio_bat_key     = session_key;
2325         args.lstio_bat_force   = force;
2326         args.lstio_bat_nmlen   = strlen(name);
2327         args.lstio_bat_namep   = name;
2328         args.lstio_bat_resultp = resultp;
2329
2330         return lst_ioctl(LSTIO_BATCH_STOP, &args, sizeof(args));
2331 }
2332
2333 int
2334 jt_lst_stop_batch(int argc, char **argv)
2335 {
2336         struct list_head  head;
2337         char             *batch;
2338         int               force = 0;
2339         int               optidx;
2340         int               count;
2341         int               rc;
2342         int               c;
2343
2344         static const struct option stop_batch_opts[] = {
2345                 { .name = "force", .has_arg = no_argument, .val = 'f' },
2346                 { .name = NULL } };
2347
2348         if (session_key == 0) {
2349                 fprintf(stderr,
2350                         "Can't find env LST_SESSION or value is not valid\n");
2351                 return -1;
2352         }
2353
2354         while (1) {
2355                 c = getopt_long(argc, argv, "f",
2356                                 stop_batch_opts, &optidx);
2357
2358                 /* Detect the end of the options. */
2359                 if (c == -1)
2360                         break;
2361
2362                 switch (c) {
2363                 case 'f':
2364                         force = 1;
2365                         break;
2366                 default:
2367                         lst_print_usage(argv[0]);
2368                         return -1;
2369                 }
2370         }
2371
2372         if (optind == argc) {
2373                 batch = LST_DEFAULT_BATCH;
2374
2375         } else if (optind == argc - 1) {
2376                 batch = argv[optind];
2377
2378         } else {
2379                 lst_print_usage(argv[0]);
2380                 return -1;
2381         }
2382
2383         rc = lst_get_node_count(LST_OPC_BATCHCLI, batch, &count, NULL);
2384         if (rc != 0) {
2385                 fprintf(stderr, "Failed to get count of nodes from %s: %s\n",
2386                         batch, strerror(errno));
2387                 return -1;
2388         }
2389
2390         INIT_LIST_HEAD(&head);
2391
2392         rc = lst_alloc_rpcent(&head, count, 0);
2393         if (rc != 0) {
2394                 fprintf(stderr, "Out of memory\n");
2395                 return -1;
2396         }
2397
2398         rc = lst_stop_batch_ioctl(batch, force, &head);
2399         if (rc != 0)
2400                 goto out;
2401
2402         while (1) {
2403                 lst_reset_rpcent(&head);
2404
2405                 rc = lst_query_batch_ioctl(batch, 0, 0, 30, &head);
2406                 if (rc != 0)
2407                         goto out;
2408
2409                 if (lstcon_tsbqry_stat_run(&trans_stat, 0)  == 0 &&
2410                     lstcon_tsbqry_stat_failure(&trans_stat, 0) == 0)
2411                         break;
2412
2413                 fprintf(stdout, "%d batch in stopping\n",
2414                         lstcon_tsbqry_stat_run(&trans_stat, 0));
2415                 sleep(1);
2416         }
2417
2418         fprintf(stdout, "Batch is stopped\n");
2419         lst_free_rpcent(&head);
2420
2421         return 0;
2422 out:
2423         if (rc == -1) {
2424                 lst_print_error("batch", "Failed to stop batch: %s\n",
2425                                 strerror(errno));
2426                 lst_free_rpcent(&head);
2427                 return -1;
2428         }
2429
2430         lst_print_transerr(&head, "stop batch");
2431
2432         lst_free_rpcent(&head);
2433
2434         return rc;
2435 }
2436
2437 int
2438 lst_list_batch_ioctl(int len, char *name, int index)
2439 {
2440         struct lstio_batch_list_args args = { 0 };
2441
2442         args.lstio_bat_key   = session_key;
2443         args.lstio_bat_idx   = index;
2444         args.lstio_bat_nmlen = len;
2445         args.lstio_bat_namep = name;
2446
2447         return lst_ioctl(LSTIO_BATCH_LIST, &args, sizeof(args));
2448 }
2449
2450 int
2451 lst_info_batch_ioctl(char *batch, int test, int server,
2452                      struct lstcon_test_batch_ent *entp, int *idxp,
2453                      int *ndentp, struct lstcon_node_ent *dentsp)
2454 {
2455         struct lstio_batch_info_args args = { 0 };
2456
2457         args.lstio_bat_key     = session_key;
2458         args.lstio_bat_nmlen   = strlen(batch);
2459         args.lstio_bat_namep   = batch;
2460         args.lstio_bat_server  = server;
2461         args.lstio_bat_testidx = test;
2462         args.lstio_bat_entp    = entp;
2463         args.lstio_bat_idxp    = idxp;
2464         args.lstio_bat_ndentp  = ndentp;
2465         args.lstio_bat_dentsp  = dentsp;
2466
2467         return lst_ioctl(LSTIO_BATCH_INFO, &args, sizeof(args));
2468 }
2469
2470 int
2471 lst_list_batch_all(void)
2472 {
2473         char name[LST_NAME_SIZE];
2474         int  rc;
2475         int  i;
2476
2477         for (i = 0; ; i++) {
2478                 rc = lst_list_batch_ioctl(LST_NAME_SIZE, name, i);
2479                 if (rc == 0) {
2480                         fprintf(stdout, "%d) %s\n", i + 1, name);
2481                         continue;
2482                 }
2483
2484                 if (errno == ENOENT)
2485                         break;
2486
2487                 lst_print_error("batch", "Failed to list batch: %s\n",
2488                                 strerror(errno));
2489                 return rc;
2490         }
2491
2492         fprintf(stdout, "Total %d batches\n", i);
2493
2494         return 0;
2495 }
2496
2497 int
2498 lst_list_tsb_nodes(char *batch, int test, int server,
2499                    int count, int active, int invalid)
2500 {
2501         struct lstcon_node_ent *dents;
2502         int                index = 0;
2503         int                rc;
2504         int                c;
2505         int                i;
2506
2507         if (count == 0)
2508                 return 0;
2509
2510         /* verbose list, show nodes in batch or test */
2511         dents = malloc(count * sizeof(struct lstcon_node_ent));
2512         if (dents == NULL) {
2513                 fprintf(stdout, "Can't allocate memory\n");
2514                 return -1;
2515         }
2516
2517         rc = lst_info_batch_ioctl(batch, test, server,
2518                                   NULL, &index, &count, dents);
2519         if (rc != 0) {
2520                 free(dents);
2521                 lst_print_error((test > 0) ? "test" : "batch",
2522                                 (test > 0) ? "Failed to query test: %s\n" :
2523                                              "Failed to query batch: %s\n",
2524                                 strerror(errno));
2525                 return -1;
2526         }
2527
2528         for (i = 0, c = 0; i < count; i++) {
2529                 if ((!active  && dents[i].nde_state == LST_NODE_ACTIVE) ||
2530                     (!invalid && (dents[i].nde_state == LST_NODE_BUSY  ||
2531                                   dents[i].nde_state == LST_NODE_DOWN  ||
2532                                   dents[i].nde_state == LST_NODE_UNKNOWN)))
2533                         continue;
2534
2535                 fprintf(stdout, "\t%s: %s\n",
2536                         libcfs_id2str(dents[i].nde_id),
2537                         lst_node_state2str(dents[i].nde_state));
2538                 c++;
2539         }
2540
2541         fprintf(stdout, "Total %d nodes\n", c);
2542         free(dents);
2543
2544         return 0;
2545 }
2546
2547 int
2548 jt_lst_list_batch(int argc, char **argv)
2549 {
2550         struct lstcon_test_batch_ent ent;
2551         char *batch   = NULL;
2552         int   optidx  = 0;
2553         int   verbose = 0; /* list nodes in batch or test */
2554         int   invalid = 0;
2555         int   active  = 0;
2556         int   server  = 0;
2557         int   ntest   = 0;
2558         int   test    = 0;
2559         int   c       = 0;
2560         int   rc;
2561
2562         static const struct option list_batch_opts[] = {
2563                 { .name = "test",    .has_arg = required_argument, .val = 't' },
2564                 { .name = "invalid", .has_arg = no_argument,       .val = 'i' },
2565                 { .name = "active",  .has_arg = no_argument,       .val = 'a' },
2566                 { .name = "all",     .has_arg = no_argument,       .val = 'l' },
2567                 { .name = "server",  .has_arg = no_argument,       .val = 's' },
2568                 { .name = NULL, } };
2569
2570         if (session_key == 0) {
2571                 fprintf(stderr,
2572                         "Can't find env LST_SESSION or value is not valid\n");
2573                 return -1;
2574         }
2575
2576         while (1) {
2577                 c = getopt_long(argc, argv, "ailst:",
2578                                 list_batch_opts, &optidx);
2579
2580                 if (c == -1)
2581                         break;
2582
2583                 switch (c) {
2584                 case 'a':
2585                         verbose = active = 1;
2586                         break;
2587                 case 'i':
2588                         verbose = invalid = 1;
2589                         break;
2590                 case 'l':
2591                         verbose = active = invalid = 1;
2592                         break;
2593                 case 's':
2594                         server = 1;
2595                         break;
2596                 case 't':
2597                         test = atoi(optarg);
2598                         ntest = 1;
2599                         break;
2600                 default:
2601                         lst_print_usage(argv[0]);
2602                         return -1;
2603                 }
2604         }
2605
2606         if (optind == argc) {
2607                 /* list all batches */
2608                 rc = lst_list_batch_all();
2609                 return rc;
2610         }
2611
2612         if (ntest == 1 && test <= 0) {
2613                 fprintf(stderr, "Invalid test id, test id starts from 1\n");
2614                 return -1;
2615         }
2616
2617         if (optind != argc - 1) {
2618                 lst_print_usage(argv[0]);
2619                 return -1;
2620         }
2621
2622         batch = argv[optind];
2623
2624 loop:
2625         /* show detail of specified batch or test */
2626         rc = lst_info_batch_ioctl(batch, test, server,
2627                                   &ent, NULL, NULL, NULL);
2628         if (rc != 0) {
2629                 lst_print_error((test > 0) ? "test" : "batch",
2630                                 (test > 0) ? "Failed to query test: %s\n" :
2631                                              "Failed to query batch: %s\n",
2632                                 strerror(errno));
2633                 return -1;
2634         }
2635
2636         if (verbose) {
2637                 /* list nodes in test or batch */
2638                 rc = lst_list_tsb_nodes(batch, test, server,
2639                                         server ? ent.tbe_srv_nle.nle_nnode :
2640                                                  ent.tbe_cli_nle.nle_nnode,
2641                                         active, invalid);
2642                 return rc;
2643         }
2644
2645         /* only show number of hosts in batch or test */
2646         if (test == 0) {
2647                 fprintf(stdout, "Batch: %s Tests: %d State: %d\n",
2648                         batch, ent.u.tbe_batch.bae_ntest,
2649                         ent.u.tbe_batch.bae_state);
2650                 ntest = ent.u.tbe_batch.bae_ntest;
2651                 test = 1; /* starting from test 1 */
2652
2653         } else {
2654                 fprintf(stdout,
2655                         "\tTest %d(%s) (loop: %d, concurrency: %d)\n",
2656                         test, lst_test_type2name(ent.u.tbe_test.tse_type),
2657                         ent.u.tbe_test.tse_loop,
2658                         ent.u.tbe_test.tse_concur);
2659                 ntest --;
2660                 test ++;
2661         }
2662
2663         fprintf(stdout, LST_NODES_TITLE);
2664         fprintf(stdout, "client\t%d\t%d\t%d\t%d\t%d\n"
2665                         "server\t%d\t%d\t%d\t%d\t%d\n",
2666                 ent.tbe_cli_nle.nle_nactive,
2667                 ent.tbe_cli_nle.nle_nbusy,
2668                 ent.tbe_cli_nle.nle_ndown,
2669                 ent.tbe_cli_nle.nle_nunknown,
2670                 ent.tbe_cli_nle.nle_nnode,
2671                 ent.tbe_srv_nle.nle_nactive,
2672                 ent.tbe_srv_nle.nle_nbusy,
2673                 ent.tbe_srv_nle.nle_ndown,
2674                 ent.tbe_srv_nle.nle_nunknown,
2675                 ent.tbe_srv_nle.nle_nnode);
2676
2677         if (ntest != 0)
2678                 goto loop;
2679
2680         return 0;
2681 }
2682
2683 int
2684 lst_query_batch_ioctl(char *batch, int test, int server,
2685                       int timeout, struct list_head *head)
2686 {
2687         struct lstio_batch_query_args args = { 0 };
2688
2689         args.lstio_bat_key     = session_key;
2690         args.lstio_bat_testidx = test;
2691         args.lstio_bat_client  = !(server);
2692         args.lstio_bat_timeout = timeout;
2693         args.lstio_bat_nmlen   = strlen(batch);
2694         args.lstio_bat_namep   = batch;
2695         args.lstio_bat_resultp = head;
2696
2697         return lst_ioctl(LSTIO_BATCH_QUERY, &args, sizeof(args));
2698 }
2699
2700 void
2701 lst_print_tsb_verbose(struct list_head *head,
2702                       int active, int idle, int error)
2703 {
2704         struct lstcon_rpc_ent *ent;
2705
2706         list_for_each_entry(ent, head, rpe_link) {
2707                 if (ent->rpe_priv[0] == 0 && active)
2708                         continue;
2709
2710                 if (ent->rpe_priv[0] != 0 && idle)
2711                         continue;
2712
2713                 if (ent->rpe_fwk_errno == 0 && error)
2714                         continue;
2715
2716                 fprintf(stdout, "%s [%s]: %s\n",
2717                         libcfs_id2str(ent->rpe_peer),
2718                         lst_node_state2str(ent->rpe_state),
2719                         ent->rpe_rpc_errno != 0 ?
2720                                 strerror(ent->rpe_rpc_errno) :
2721                                 (ent->rpe_priv[0] > 0 ? "Running" : "Idle"));
2722         }
2723 }
2724
2725 int
2726 jt_lst_query_batch(int argc, char **argv)
2727 {
2728         struct lstcon_test_batch_ent ent;
2729         struct list_head head;
2730         char   *batch   = NULL;
2731         time_t  last    = 0;
2732         int     optidx  = 0;
2733         int     verbose = 0;
2734         int     server  = 0;
2735         int     timeout = 5; /* default 5 seconds */
2736         int     delay   = 5; /* default 5 seconds */
2737         int     loop    = 1; /* default 1 loop */
2738         int     active  = 0;
2739         int     error   = 0;
2740         int     idle    = 0;
2741         int     count   = 0;
2742         int     test    = 0;
2743         int     rc      = 0;
2744         int     c       = 0;
2745         int     i;
2746
2747         static const struct option query_batch_opts[] = {
2748                 { .name = "timeout", .has_arg = required_argument, .val = 'o' },
2749                 { .name = "delay",   .has_arg = required_argument, .val = 'd' },
2750                 { .name = "loop",    .has_arg = required_argument, .val = 'c' },
2751                 { .name = "test",    .has_arg = required_argument, .val = 't' },
2752                 { .name = "server",  .has_arg = no_argument,       .val = 's' },
2753                 { .name = "active",  .has_arg = no_argument,       .val = 'a' },
2754                 { .name = "idle",    .has_arg = no_argument,       .val = 'i' },
2755                 { .name = "error",   .has_arg = no_argument,       .val = 'e' },
2756                 { .name = "all",     .has_arg = no_argument,       .val = 'l' },
2757                 { .name = NULL, } };
2758
2759         if (session_key == 0) {
2760                 fprintf(stderr,
2761                         "Can't find env LST_SESSION or value is not valid\n");
2762                 return -1;
2763         }
2764
2765         while (1) {
2766                 c = getopt_long(argc, argv, "o:d:c:t:saiel",
2767                                 query_batch_opts, &optidx);
2768
2769                 /* Detect the end of the options. */
2770                 if (c == -1)
2771                         break;
2772
2773                 switch (c) {
2774                 case 'o':
2775                         timeout = atoi(optarg);
2776                         break;
2777                 case 'd':
2778                         delay = atoi(optarg);
2779                         break;
2780                 case 'c':
2781                         loop = atoi(optarg);
2782                         break;
2783                 case 't':
2784                         test = atoi(optarg);
2785                         break;
2786                 case 's':
2787                         server = 1;
2788                         break;
2789                 case 'a':
2790                         active = verbose = 1;
2791                         break;
2792                 case 'i':
2793                         idle = verbose = 1;
2794                         break;
2795                 case 'e':
2796                         error = verbose = 1;
2797                         break;
2798                 case 'l':
2799                         verbose = 1;
2800                         break;
2801                 default:
2802                         lst_print_usage(argv[0]);
2803                         return -1;
2804                 }
2805         }
2806
2807         if (test < 0 || timeout <= 0 || delay <= 0 || loop <= 0) {
2808                 lst_print_usage(argv[0]);
2809                 return -1;
2810         }
2811
2812         if (optind == argc) {
2813                 batch = LST_DEFAULT_BATCH;
2814
2815         } else if (optind == argc - 1) {
2816                 batch = argv[optind];
2817
2818         } else {
2819                 lst_print_usage(argv[0]);
2820                 return -1;
2821         }
2822
2823
2824         INIT_LIST_HEAD(&head);
2825
2826         if (verbose) {
2827                 rc = lst_info_batch_ioctl(batch, test, server,
2828                                           &ent, NULL, NULL, NULL);
2829                 if (rc != 0) {
2830                         fprintf(stderr, "Failed to query %s [%d]: %s\n",
2831                                 batch, test, strerror(errno));
2832                         return -1;
2833                 }
2834
2835                 count = server ? ent.tbe_srv_nle.nle_nnode :
2836                                  ent.tbe_cli_nle.nle_nnode;
2837                 if (count == 0) {
2838                         fprintf(stdout, "Batch or test is empty\n");
2839                         return 0;
2840                 }
2841         }
2842
2843         rc = lst_alloc_rpcent(&head, count, 0);
2844         if (rc != 0) {
2845                 fprintf(stderr, "Out of memory\n");
2846                 return rc;
2847         }
2848
2849         for (i = 0; i < loop; i++) {
2850                 time_t  now = time(NULL);
2851
2852                 if (now - last < delay) {
2853                         sleep(delay - now + last);
2854                         time(&now);
2855                 }
2856
2857                 last = now;
2858
2859                 rc = lst_query_batch_ioctl(batch, test,
2860                                            server, timeout, &head);
2861                 if (rc == -1) {
2862                         fprintf(stderr, "Failed to query batch: %s\n",
2863                                 strerror(errno));
2864                         break;
2865                 }
2866
2867                 if (verbose) {
2868                         /* Verbose mode */
2869                         lst_print_tsb_verbose(&head, active, idle, error);
2870                         continue;
2871                 }
2872
2873                 fprintf(stdout, "%s [%d] ", batch, test);
2874
2875                 if (lstcon_rpc_stat_failure(&trans_stat, 0) != 0) {
2876                         fprintf(stdout, "%d of %d nodes are unknown, ",
2877                                 lstcon_rpc_stat_failure(&trans_stat, 0),
2878                                 lstcon_rpc_stat_total(&trans_stat, 0));
2879                 }
2880
2881                 if (lstcon_rpc_stat_failure(&trans_stat, 0) == 0 &&
2882                     lstcon_tsbqry_stat_run(&trans_stat, 0)  == 0  &&
2883                     lstcon_tsbqry_stat_failure(&trans_stat, 0) == 0) {
2884                         fprintf(stdout, "is stopped\n");
2885                         continue;
2886                 }
2887
2888                 if (lstcon_rpc_stat_failure(&trans_stat, 0) == 0 &&
2889                     lstcon_tsbqry_stat_idle(&trans_stat, 0) == 0 &&
2890                     lstcon_tsbqry_stat_failure(&trans_stat, 0) == 0) {
2891                         fprintf(stdout, "is running\n");
2892                         continue;
2893                 }
2894
2895                 fprintf(stdout, "stopped: %d , running: %d, failed: %d\n",
2896                                 lstcon_tsbqry_stat_idle(&trans_stat, 0),
2897                                 lstcon_tsbqry_stat_run(&trans_stat, 0),
2898                                 lstcon_tsbqry_stat_failure(&trans_stat, 0));
2899         }
2900
2901         lst_free_rpcent(&head);
2902
2903         return rc;
2904 }
2905
2906 int
2907 lst_parse_distribute(char *dstr, int *dist, int *span)
2908 {
2909         *dist = atoi(dstr);
2910         if (*dist <= 0)
2911                 return -1;
2912
2913         dstr = strchr(dstr, ':');
2914         if (dstr == NULL)
2915                 return -1;
2916
2917         *span = atoi(dstr + 1);
2918         if (*span <= 0)
2919                 return -1;
2920
2921         return 0;
2922 }
2923
2924 int
2925 lst_get_bulk_param(int argc, char **argv, struct lst_test_bulk_param *bulk)
2926 {
2927         char   *tok = NULL;
2928         char   *end = NULL;
2929         int     rc  = 0;
2930         int     i   = 0;
2931
2932         bulk->blk_size  = 4096;
2933         bulk->blk_opc   = LST_BRW_READ;
2934         bulk->blk_flags = LST_BRW_CHECK_NONE;
2935         bulk->blk_srv_off = bulk->blk_cli_off = 0;
2936
2937         while (i < argc) {
2938                 if (strcasestr(argv[i], "check=") == argv[i] ||
2939                     strcasestr(argv[i], "c=") == argv[i]) {
2940                         tok = strchr(argv[i], '=') + 1;
2941
2942                         if (strcasecmp(tok, "full") == 0) {
2943                                 bulk->blk_flags = LST_BRW_CHECK_FULL;
2944                         } else if (strcasecmp(tok, "simple") == 0) {
2945                                 bulk->blk_flags = LST_BRW_CHECK_SIMPLE;
2946                         } else {
2947                                 fprintf(stderr, "Unknow flag %s\n", tok);
2948                                 return -1;
2949                         }
2950
2951                 } else if (strcasestr(argv[i], "size=") == argv[i] ||
2952                            strcasestr(argv[i], "s=") == argv[i]) {
2953                         int max_size = sysconf(_SC_PAGESIZE) * LNET_MAX_IOV;
2954
2955                         tok = strchr(argv[i], '=') + 1;
2956
2957                         bulk->blk_size = strtol(tok, &end, 0);
2958                         if (bulk->blk_size <= 0) {
2959                                 fprintf(stderr, "Invalid size %s\n", tok);
2960                                 return -1;
2961                         }
2962
2963                         if (end == NULL)
2964                                 return 0;
2965
2966                         if (*end == 'k' || *end == 'K')
2967                                 bulk->blk_size *= 1024;
2968                         else if (*end == 'm' || *end == 'M')
2969                                 bulk->blk_size *= 1024 * 1024;
2970
2971                         if (bulk->blk_size > max_size) {
2972                                 fprintf(stderr, "Size exceed limitation: %d bytes\n",
2973                                         bulk->blk_size);
2974                                 return -1;
2975                         }
2976
2977                 } else if (strcasestr(argv[i], "off=") == argv[i]) {
2978                         int     off;
2979
2980                         tok = strchr(argv[i], '=') + 1;
2981
2982                         off = strtol(tok, &end, 0);
2983                         /* NB: align with sizeof(__u64) to simplify page
2984                          * checking implementation */
2985                         if (off < 0 || off % sizeof(__u64) != 0) {
2986                                 fprintf(stderr,
2987                                         "Invalid offset %s/%d, it should be "
2988                                         "postive value and multiple of %d\n",
2989                                         tok, off, (int)sizeof(__u64));
2990                                 return -1;
2991                         }
2992
2993                         /* NB: blk_srv_off is reserved so far */
2994                         bulk->blk_cli_off = bulk->blk_srv_off = off;
2995                         if (end == NULL)
2996                                 return 0;
2997
2998                 } else if (strcasecmp(argv[i], "read") == 0 ||
2999                            strcasecmp(argv[i], "r") == 0) {
3000                         bulk->blk_opc = LST_BRW_READ;
3001
3002                 } else if (strcasecmp(argv[i], "write") == 0 ||
3003                            strcasecmp(argv[i], "w") == 0) {
3004                         bulk->blk_opc = LST_BRW_WRITE;
3005
3006                 } else {
3007                         fprintf(stderr, "Unknow parameter: %s\n", argv[i]);
3008                         return -1;
3009                 }
3010
3011                 i++;
3012         }
3013
3014         return rc;
3015 }
3016
3017 int
3018 lst_get_test_param(char *test, int argc, char **argv, void **param, int *plen)
3019 {
3020         struct lst_test_bulk_param *bulk = NULL;
3021         int                    type;
3022
3023         type = lst_test_name2type(test);
3024         if (type < 0) {
3025                 fprintf(stderr, "Unknow test name %s\n", test);
3026                 return -1;
3027         }
3028
3029         switch (type) {
3030         case LST_TEST_PING:
3031                 break;
3032
3033         case LST_TEST_BULK:
3034                 bulk = malloc(sizeof(*bulk));
3035                 if (bulk == NULL) {
3036                         fprintf(stderr, "Out of memory\n");
3037                         return -1;
3038                 }
3039
3040                 memset(bulk, 0, sizeof(*bulk));
3041
3042                 if (lst_get_bulk_param(argc, argv, bulk) != 0) {
3043                         free(bulk);
3044                         return -1;
3045                 }
3046
3047                 *param = bulk;
3048                 *plen  = sizeof(*bulk);
3049
3050                 break;
3051
3052         default:
3053                 break;
3054         }
3055
3056         /* TODO: parse more parameter */
3057         return type;
3058 }
3059
3060 int
3061 lst_add_test_ioctl(char *batch, int type, int loop, int concur,
3062                    int dist, int span, char *sgrp, char *dgrp,
3063                    void *param, int plen, int *retp, struct list_head *resultp)
3064 {
3065         struct lstio_test_args args = { 0 };
3066
3067         args.lstio_tes_key        = session_key;
3068         args.lstio_tes_bat_nmlen  = strlen(batch);
3069         args.lstio_tes_bat_name   = batch;
3070         args.lstio_tes_type       = type;
3071         args.lstio_tes_oneside    = 0;
3072         args.lstio_tes_loop       = loop;
3073         args.lstio_tes_concur     = concur;
3074         args.lstio_tes_dist       = dist;
3075         args.lstio_tes_span       = span;
3076         args.lstio_tes_sgrp_nmlen = strlen(sgrp);
3077         args.lstio_tes_sgrp_name  = sgrp;
3078         args.lstio_tes_dgrp_nmlen = strlen(dgrp);
3079         args.lstio_tes_dgrp_name  = dgrp;
3080         args.lstio_tes_param_len  = plen;
3081         args.lstio_tes_param      = param;
3082         args.lstio_tes_retp       = retp;
3083         args.lstio_tes_resultp    = resultp;
3084
3085         return lst_ioctl(LSTIO_TEST_ADD, &args, sizeof(args));
3086 }
3087
3088 int
3089 jt_lst_add_test(int argc, char **argv)
3090 {
3091         struct list_head head;
3092         char *batch  = NULL;
3093         char *test   = NULL;
3094         char *dstr   = NULL;
3095         char *from   = NULL;
3096         char *to     = NULL;
3097         void *param  = NULL;
3098         int   optidx = 0;
3099         int   concur = 1;
3100         int   loop   = -1;
3101         int   dist   = 1;
3102         int   span   = 1;
3103         int   plen   = 0;
3104         int   fcount = 0;
3105         int   tcount = 0;
3106         int   ret    = 0;
3107         int   type;
3108         int   rc;
3109         int   c;
3110
3111         static const struct option add_test_opts[] = {
3112         { .name = "batch",       .has_arg = required_argument, .val = 'b' },
3113         { .name = "concurrency", .has_arg = required_argument, .val = 'c' },
3114         { .name = "distribute",  .has_arg = required_argument, .val = 'd' },
3115         { .name = "from",        .has_arg = required_argument, .val = 'f' },
3116         { .name = "to",          .has_arg = required_argument, .val = 't' },
3117         { .name = "loop",        .has_arg = required_argument, .val = 'l' },
3118         { .name = NULL } };
3119
3120         if (session_key == 0) {
3121                 fprintf(stderr,
3122                         "Can't find env LST_SESSION or value is not valid\n");
3123                 return -1;
3124         }
3125
3126         while (1) {
3127                 c = getopt_long(argc, argv, "b:c:d:f:l:t:",
3128                                 add_test_opts, &optidx);
3129
3130                 /* Detect the end of the options. */
3131                 if (c == -1)
3132                         break;
3133
3134                 switch (c) {
3135                 case 'b':
3136                         batch = optarg;
3137                         break;
3138                 case 'c':
3139                         concur = atoi(optarg);
3140                         break;
3141                 case 'd':
3142                         dstr = optarg;
3143                         break;
3144                 case 'f':
3145                         from = optarg;
3146                         break;
3147                 case 'l':
3148                         loop = atoi(optarg);
3149                         break;
3150                 case 't':
3151                         to = optarg;
3152                         break;
3153                 default:
3154                         lst_print_usage(argv[0]);
3155                         return -1;
3156                 }
3157         }
3158
3159         if (optind == argc || from == NULL || to == NULL) {
3160                 lst_print_usage(argv[0]);
3161                 return -1;
3162         }
3163
3164         if (concur <= 0 || concur > LST_MAX_CONCUR) {
3165                 fprintf(stderr, "Invalid concurrency of test: %d\n", concur);
3166                 return -1;
3167         }
3168
3169         if (batch == NULL)
3170                 batch = LST_DEFAULT_BATCH;
3171
3172         if (dstr != NULL) {
3173                 rc = lst_parse_distribute(dstr, &dist, &span);
3174                 if (rc != 0) {
3175                         fprintf(stderr, "Invalid distribution: %s\n", dstr);
3176                         return -1;
3177                 }
3178         }
3179
3180         test = argv[optind++];
3181
3182         argc -= optind;
3183         argv += optind;
3184
3185         type = lst_get_test_param(test, argc, argv, &param, &plen);
3186         if (type < 0) {
3187                 fprintf(stderr, "Failed to add test (%s)\n", test);
3188                 return -1;
3189         }
3190
3191         INIT_LIST_HEAD(&head);
3192
3193         rc = lst_get_node_count(LST_OPC_GROUP, from, &fcount, NULL);
3194         if (rc != 0) {
3195                 fprintf(stderr, "Can't get count of nodes from %s: %s\n",
3196                         from, strerror(errno));
3197                 goto out;
3198         }
3199
3200         rc = lst_get_node_count(LST_OPC_GROUP, to, &tcount, NULL);
3201         if (rc != 0) {
3202                 fprintf(stderr, "Can't get count of nodes from %s: %s\n",
3203                         to, strerror(errno));
3204                 goto out;
3205         }
3206
3207         rc = lst_alloc_rpcent(&head, fcount > tcount ? fcount : tcount, 0);
3208         if (rc != 0) {
3209                 fprintf(stderr, "Out of memory\n");
3210                 goto out;
3211         }
3212
3213         rc = lst_add_test_ioctl(batch, type, loop, concur,
3214                                 dist, span, from, to, param, plen, &ret, &head);
3215
3216         if (rc == 0) {
3217                 fprintf(stdout, "Test was added successfully\n");
3218                 if (ret != 0) {
3219                         fprintf(stdout, "Server group contains userland test "
3220                                 "nodes, old version of tcplnd can't accept "
3221                                 "connection request\n");
3222                 }
3223
3224                 goto out;
3225         }
3226
3227         if (rc == -1) {
3228                 lst_print_error("test", "Failed to add test: %s\n",
3229                                 strerror(errno));
3230                 goto out;
3231         }
3232
3233         lst_print_transerr(&head, "add test");
3234 out:
3235         lst_free_rpcent(&head);
3236
3237         if (param != NULL)
3238                 free(param);
3239
3240         return rc;
3241 }
3242
3243 static command_t lst_cmdlist[] = {
3244         {"new_session",         jt_lst_new_session,     NULL,
3245          "Usage: lst new_session [--timeout TIME] [--force] [NAME]"                     },
3246         {"end_session",         jt_lst_end_session,     NULL,
3247          "Usage: lst end_session"                                                       },
3248         {"show_session",        jt_lst_show_session,    NULL,
3249          "Usage: lst show_session"                                                      },
3250         {"ping",                jt_lst_ping ,           NULL,
3251          "Usage: lst ping  [--group NAME] [--batch NAME] [--session] [--nodes IDS]"     },
3252         {"add_group",           jt_lst_add_group,       NULL,
3253          "Usage: lst group NAME IDs [IDs]..."                                           },
3254         {"del_group",           jt_lst_del_group,       NULL,
3255          "Usage: lst del_group NAME"                                                    },
3256         {"update_group",        jt_lst_update_group,    NULL,
3257          "Usage: lst update_group NAME [--clean] [--refresh] [--remove IDs]"            },
3258         {"list_group",          jt_lst_list_group,      NULL,
3259           "Usage: lst list_group [--active] [--busy] [--down] [--unknown] GROUP ..."    },
3260         {"stat",                jt_lst_stat,            NULL,
3261          "Usage: lst stat [--bw] [--rate] [--read] [--write] [--max] [--min] [--avg] "
3262          " [--mbs] [--timeout #] [--delay #] [--count #] GROUP [GROUP]"                 },
3263         {"show_error",          jt_lst_show_error,      NULL,
3264          "Usage: lst show_error NAME | IDS ..."                                         },
3265         {"add_batch",           jt_lst_add_batch,       NULL,
3266          "Usage: lst add_batch NAME"                                                    },
3267         {"run",                 jt_lst_start_batch,     NULL,
3268          "Usage: lst run [--timeout TIME] [NAME]"                                       },
3269         {"stop",                jt_lst_stop_batch,      NULL,
3270          "Usage: lst stop [--force] BATCH_NAME"                                         },
3271         {"list_batch",          jt_lst_list_batch,      NULL,
3272          "Usage: lst list_batch NAME [--test ID] [--server]"                            },
3273         {"query",               jt_lst_query_batch,     NULL,
3274          "Usage: lst query [--test ID] [--server] [--timeout TIME] NAME"                },
3275         {"add_test",            jt_lst_add_test,        NULL,
3276          "Usage: lst add_test [--batch BATCH] [--loop #] [--concurrency #] "
3277          " [--distribute #:#] [--from GROUP] [--to GROUP] TEST..."                      },
3278         {"help",                Parser_help,            0,     "help"                   },
3279         {0,                     0,                      0,      NULL                    }
3280 };
3281
3282 int
3283 lst_initialize(void)
3284 {
3285         char   *key;
3286         char   *feats;
3287
3288         feats = getenv("LST_FEATURES");
3289         if (feats != NULL)
3290                 session_features = strtol(feats, NULL, 16);
3291
3292         if ((session_features & ~LST_FEATS_MASK) != 0) {
3293                 fprintf(stderr,
3294                         "Unsupported session features %x, "
3295                         "only support these features so far: %x\n",
3296                         (session_features & ~LST_FEATS_MASK), LST_FEATS_MASK);
3297                 return -1;
3298         }
3299
3300         key = getenv("LST_SESSION");
3301
3302         if (key == NULL) {
3303                 session_key = 0;
3304                 return 0;
3305         }
3306
3307         session_key = atoi(key);
3308
3309         return 0;
3310 }
3311
3312 int
3313 main(int argc, char **argv)
3314 {
3315         int rc = 0;
3316
3317         setlinebuf(stdout);
3318
3319         rc = lst_initialize();
3320         if (rc < 0)
3321                 goto errorout;
3322
3323         rc = ptl_initialize(argc, argv);
3324         if (rc < 0)
3325                 goto errorout;
3326
3327         Parser_init("lst > ", lst_cmdlist);
3328
3329         if (argc != 1)  {
3330                 rc = Parser_execarg(argc - 1, argv + 1, lst_cmdlist);
3331                 goto errorout;
3332         }
3333
3334         Parser_commands();
3335
3336 errorout:
3337         return rc;
3338 }