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