Whamcloud - gitweb
LU-12846 mdd: return error while delete failed
[fs/lustre-release.git] / lustre / utils / obd.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) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2011, 2017, 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  * lustre/utils/obd.c
33  *
34  * Author: Peter J. Braam <braam@clusterfs.com>
35  * Author: Phil Schwan <phil@clusterfs.com>
36  * Author: Andreas Dilger <adilger@clusterfs.com>
37  * Author: Robert Read <rread@clusterfs.com>
38  */
39
40 #include <sys/ioctl.h>
41 #include <sys/socket.h>
42 #include <sys/stat.h>
43 #include <sys/time.h>
44 #include <sys/types.h>
45 #include <sys/un.h>
46 #include <sys/wait.h>
47
48 #include <ctype.h>
49 #include <errno.h>
50 #include <fcntl.h>
51 #include <getopt.h>
52 #include <signal.h>
53 #include <stdarg.h>
54 #include <stdbool.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <time.h>
59 #include <unistd.h>
60 #include <limits.h>
61 #include "obdctl.h"
62 #include "lustreapi_internal.h"
63 #include <libcfs/util/list.h>
64 #include <libcfs/util/ioctl.h>
65 #include <libcfs/util/param.h>
66 #include <libcfs/util/parser.h>
67 #include <libcfs/util/string.h>
68
69 #include <linux/lnet/nidstr.h>
70 #include <linux/lnet/lnetctl.h>
71 #include <linux/lustre/lustre_barrier_user.h>
72 #include <linux/lustre/lustre_cfg.h>
73 #include <linux/lustre/lustre_ioctl.h>
74 #include <linux/lustre/lustre_ostid.h>
75 #include <linux/lustre/lustre_param.h>
76 #include <linux/lustre/lustre_ver.h>
77
78 #include <lustre/lustreapi.h>
79
80 #define MAX_STRING_SIZE 128
81
82 #if HAVE_LIBPTHREAD
83 #include <sys/ipc.h>
84 #include <sys/shm.h>
85 #include <pthread.h>
86
87 #define MAX_THREADS 4096
88 #define MAX_BASE_ID 0xffffffff
89 #define NIDSTRING_LENGTH 64
90 struct shared_data {
91         pthread_mutex_t mutex;
92         pthread_cond_t  cond;
93         int       stopping;
94         struct {
95                 __u64 counters[MAX_THREADS];
96                 __u64 offsets[MAX_THREADS];
97                 int   thr_running;
98                 int   start_barrier;
99                 int   stop_barrier;
100                 struct timeval start_time;
101                 struct timeval end_time;
102         } body;
103 };
104
105 static struct shared_data *shared_data;
106 static __u64 counter_snapshot[2][MAX_THREADS];
107 static int prev_valid;
108 static struct timeval prev_time;
109 static int thread;
110 static int nthreads;
111 #else
112 const int thread = 0;
113 const int nthreads = 1;
114 #endif
115
116 static int cur_device = -1;
117
118 int lcfg_ioctl(char *func, int dev_id, struct lustre_cfg *lcfg)
119 {
120         struct obd_ioctl_data data;
121         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
122         int rc;
123
124         memset(&data, 0, sizeof(data));
125         data.ioc_dev = cur_device;
126         data.ioc_type = LUSTRE_CFG_TYPE;
127         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
128                                         lcfg->lcfg_buflens);
129         data.ioc_pbuf1 = (void *)lcfg;
130         memset(buf, 0, sizeof(rawbuf));
131         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
132         if (rc) {
133                 fprintf(stderr, "error: %s: invalid ioctl\n", jt_cmdname(func));
134                 return rc;
135         }
136
137         rc =  l_ioctl(dev_id, OBD_IOC_PROCESS_CFG, buf);
138
139         return rc;
140 }
141
142 static int do_device(char *func, char *devname);
143
144 static int get_mgs_device()
145 {
146         char mgs[] = "$MGS";
147         static int mgs_device = -1;
148
149         if (mgs_device == -1) {
150                 int rc;
151                 do_disconnect(NULL, 1);
152                 rc = do_device("mgsioc", mgs);
153                 if (rc) {
154                         fprintf(stderr,
155                                 "This command must be run on the MGS.\n");
156                         errno = ENODEV;
157                         return -1;
158                 }
159                 mgs_device = cur_device;
160         }
161         return mgs_device;
162 }
163
164 /* Returns -1 on error with errno set */
165 int lcfg_mgs_ioctl(char *func, int dev_id, struct lustre_cfg *lcfg)
166 {
167         struct obd_ioctl_data data;
168         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
169         int rc;
170
171         memset(&data, 0, sizeof(data));
172         rc = data.ioc_dev = get_mgs_device();
173         if (rc < 0)
174                 goto out;
175         data.ioc_type = LUSTRE_CFG_TYPE;
176         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
177                                         lcfg->lcfg_buflens);
178         data.ioc_pbuf1 = (void *)lcfg;
179         memset(buf, 0, sizeof(rawbuf));
180         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
181         if (rc) {
182                 fprintf(stderr, "error: %s: invalid ioctl\n", jt_cmdname(func));
183                 return rc;
184         }
185
186         rc = l_ioctl(dev_id, OBD_IOC_PARAM, buf);
187 out:
188         if (rc && errno == ENOSYS)
189                 fprintf(stderr, "Make sure cfg_device is set first.\n");
190
191         return rc;
192 }
193
194 char *obdo_print(struct obdo *obd)
195 {
196         char buf[1024];
197
198         snprintf(buf, sizeof(buf), "id: %#jx\ngrp: %#jx\natime: %ju\n"
199                  "mtime: %ju\nctime: %ju\nsize: %ju\nblocks: %ju"
200                  "\nblksize: %u\nmode: %o\nuid: %d\ngid: %d\nflags: %x\n"
201                  "misc: %x\nnlink: %d,\nvalid %#jx\n",
202                  (uintmax_t)ostid_id(&obd->o_oi),
203                  (uintmax_t)ostid_seq(&obd->o_oi),
204                  (uintmax_t)obd->o_atime, (uintmax_t)obd->o_mtime,
205                  (uintmax_t)obd->o_ctime, (uintmax_t)obd->o_size,
206                  (uintmax_t)obd->o_blocks, obd->o_blksize, obd->o_mode,
207                  obd->o_uid, obd->o_gid, obd->o_flags, obd->o_misc,
208                  obd->o_nlink, (uintmax_t)obd->o_valid);
209         return strdup(buf);
210 }
211
212
213 #define BAD_VERBOSE (-999999999)
214
215 #define N2D_OFF 0x100      /* So we can tell between error codes and devices */
216
217 static int do_name2dev(char *func, char *name)
218 {
219         struct obd_ioctl_data data;
220         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
221         int rc;
222
223         memset(&data, 0, sizeof(data));
224         data.ioc_dev = cur_device;
225         data.ioc_inllen1 = strlen(name) + 1;
226         data.ioc_inlbuf1 = name;
227
228         memset(buf, 0, sizeof(rawbuf));
229         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
230         if (rc < 0) {
231                 fprintf(stderr, "error: %s: invalid ioctl\n", jt_cmdname(func));
232                 return -rc;
233         }
234         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_NAME2DEV, buf);
235         if (rc < 0)
236                 return errno;
237         rc = llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
238         if (rc) {
239                 fprintf(stderr, "error: %s: invalid reply\n", jt_cmdname(func));
240                 return rc;
241         }
242
243         return data.ioc_dev + N2D_OFF;
244 }
245
246 /*
247  * resolve a device name to a device number.
248  * supports a number, $name or %uuid.
249  */
250 int parse_devname(char *func, char *name)
251 {
252         int rc;
253         int ret = -1;
254         int try_digit;
255
256         if (!name)
257                 return ret;
258
259         try_digit = isdigit(name[0]);
260
261         if (name[0] == '$' || name[0] == '%')
262                 name++;
263
264         rc = do_name2dev(func, name);
265         if (rc >= N2D_OFF)
266                 return rc - N2D_OFF;
267
268         if (try_digit)
269                 ret = strtoul(name, NULL, 0);
270         else
271                 fprintf(stderr, "No device found for name %s: %s\n",
272                                 name, strerror(rc));
273         return ret;
274 }
275
276 char *jt_cmdname(char *func)
277 {
278         static char buf[512];
279
280         if (thread) {
281                 sprintf(buf, "%s-%d", func, thread);
282                 return buf;
283         }
284
285         return func;
286 }
287
288 #define difftime(a, b)                                  \
289         ((a)->tv_sec - (b)->tv_sec +                    \
290          ((a)->tv_usec - (b)->tv_usec) / 1000000.0)
291
292 static int be_verbose(int verbose, struct timeval *next_time,
293                       __u64 num, __u64 *next_num, int num_total)
294 {
295         struct timeval now;
296
297         if (!verbose)
298                 return 0;
299
300         if (next_time != NULL)
301                 gettimeofday(&now, NULL);
302
303         /* A positive verbosity means to print every X iterations */
304         if (verbose > 0 && (num >= *next_num || num >= num_total)) {
305                 *next_num += verbose;
306                 if (next_time) {
307                         next_time->tv_sec = now.tv_sec - verbose;
308                         next_time->tv_usec = now.tv_usec;
309                 }
310                 return 1;
311         }
312
313         /* A negative verbosity means to print at most each X seconds */
314         if (verbose < 0 && next_time != NULL &&
315             difftime(&now, next_time) >= 0.0){
316                 next_time->tv_sec = now.tv_sec - verbose;
317                 next_time->tv_usec = now.tv_usec;
318                 *next_num = num;
319                 return 1;
320         }
321
322         return 0;
323 }
324
325 static int get_verbose(char *func, const char *arg)
326 {
327         int verbose;
328         char *end;
329
330         if (!arg || arg[0] == 'v')
331                 verbose = 1;
332         else if (arg[0] == 's' || arg[0] == 'q')
333                 verbose = 0;
334         else {
335                 verbose = (int)strtoul(arg, &end, 0);
336                 if (*end) {
337                         fprintf(stderr, "error: %s: bad verbose option '%s'\n",
338                                 jt_cmdname(func), arg);
339                         return BAD_VERBOSE;
340                 }
341         }
342
343         if (verbose < 0)
344                 printf("Print status every %d seconds\n", -verbose);
345         else if (verbose == 1)
346                 printf("Print status every operation\n");
347         else if (verbose > 1)
348                 printf("Print status every %d operations\n", verbose);
349
350         return verbose;
351 }
352
353 int do_disconnect(char *func, int verbose)
354 {
355         lcfg_set_devname(NULL);
356         cur_device = -1;
357         return 0;
358 }
359
360 #ifdef MAX_THREADS
361 static int shmem_setup(void)
362 {
363         pthread_mutexattr_t mattr;
364         pthread_condattr_t  cattr;
365         int                 rc;
366         int                 shmid;
367
368         /* Create new segment */
369         shmid = shmget(IPC_PRIVATE, sizeof(*shared_data), 0600);
370         if (shmid == -1) {
371                 fprintf(stderr, "Can't create shared data: %s\n",
372                         strerror(errno));
373                 return errno;
374         }
375
376         /* Attatch to new segment */
377         shared_data = (struct shared_data *)shmat(shmid, NULL, 0);
378
379         if (shared_data == (struct shared_data *)(-1)) {
380                 fprintf(stderr, "Can't attach shared data: %s\n",
381                         strerror(errno));
382                 shared_data = NULL;
383                 return errno;
384         }
385
386         /* Mark segment as destroyed, so it will disappear when we exit.
387          * Forks will inherit attached segments, so we should be OK.
388          */
389         if (shmctl(shmid, IPC_RMID, NULL) == -1) {
390                 fprintf(stderr, "Can't destroy shared data: %s\n",
391                         strerror(errno));
392                 return errno;
393         }
394
395         pthread_mutexattr_init(&mattr);
396         pthread_condattr_init(&cattr);
397
398         rc = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
399         if (rc != 0) {
400                 fprintf(stderr, "Can't set shared mutex attr\n");
401                 goto out;
402         }
403
404         rc = pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
405         if (rc != 0) {
406                 fprintf(stderr, "Can't set shared cond attr\n");
407                 goto out;
408         }
409
410         pthread_mutex_init(&shared_data->mutex, &mattr);
411         pthread_cond_init(&shared_data->cond, &cattr);
412 out:
413         pthread_mutexattr_destroy(&mattr);
414         pthread_condattr_destroy(&cattr);
415
416         return rc;
417 }
418
419 static inline void shmem_lock(void)
420 {
421         pthread_mutex_lock(&shared_data->mutex);
422 }
423
424 static inline void shmem_unlock(void)
425 {
426         pthread_mutex_unlock(&shared_data->mutex);
427 }
428
429 static inline void shmem_wait(void)
430 {
431         pthread_cond_wait(&shared_data->cond, &shared_data->mutex);
432 }
433
434 static inline void shmem_wakeup_all(void)
435 {
436         pthread_cond_broadcast(&shared_data->cond);
437 }
438
439 static inline void shmem_reset(int total_threads)
440 {
441         if (shared_data == NULL)
442                 return;
443
444         memset(&shared_data->body, 0, sizeof(shared_data->body));
445         memset(counter_snapshot, 0, sizeof(counter_snapshot));
446         prev_valid = 0;
447         shared_data->stopping = 0;
448         shared_data->body.start_barrier = total_threads;
449         shared_data->body.stop_barrier = total_threads;
450 }
451
452 static inline void shmem_bump(__u32 counter)
453 {
454         static bool running_not_bumped = true;
455
456         if (shared_data == NULL || thread <= 0 || thread > MAX_THREADS)
457                 return;
458
459         shmem_lock();
460         shared_data->body.counters[thread - 1] += counter;
461         if (running_not_bumped) {
462                 shared_data->body.thr_running++;
463                 running_not_bumped = false;
464         }
465         shmem_unlock();
466 }
467
468 static void shmem_total(int total_threads)
469 {
470         __u64 total = 0;
471         double secs;
472         int i;
473
474         if (shared_data == NULL || total_threads > MAX_THREADS)
475                 return;
476
477         shmem_lock();
478         for (i = 0; i < total_threads; i++)
479                 total += shared_data->body.counters[i];
480
481         secs = difftime(&shared_data->body.end_time,
482                         &shared_data->body.start_time);
483         shmem_unlock();
484
485         printf("Total: total %ju threads %d sec %f %f/second\n",
486                (uintmax_t)total, total_threads, secs, total / secs);
487 }
488
489 static void shmem_snap(int total_threads, int live_threads)
490 {
491         struct timeval this_time;
492         int non_zero = 0;
493         __u64 total = 0;
494         double secs;
495         int running;
496         int i;
497
498         if (shared_data == NULL || total_threads > MAX_THREADS)
499                 return;
500
501         shmem_lock();
502         memcpy(counter_snapshot[0], shared_data->body.counters,
503                total_threads * sizeof(counter_snapshot[0][0]));
504         running = shared_data->body.thr_running;
505         shmem_unlock();
506
507         gettimeofday(&this_time, NULL);
508
509         for (i = 0; i < total_threads; i++) {
510                 long long this_count =
511                         counter_snapshot[0][i] - counter_snapshot[1][i];
512
513                 if (this_count != 0) {
514                         non_zero++;
515                         total += this_count;
516                 }
517         }
518
519         secs = difftime(&this_time, &prev_time);
520         if (prev_valid && secs > 1.0) {   /* someone screwed with the time? */
521                 printf("%d/%d Total: %f/second\n", non_zero, total_threads,
522                        total / secs);
523
524                 memcpy(counter_snapshot[1], counter_snapshot[0],
525                        total_threads * sizeof(counter_snapshot[0][0]));
526                 prev_time = this_time;
527         }
528         if (!prev_valid && running == total_threads) {
529                 prev_valid = 1;
530                 /* drop counters when all threads were started */
531                 memcpy(counter_snapshot[1], counter_snapshot[0],
532                        total_threads * sizeof(counter_snapshot[0][0]));
533                 prev_time = this_time;
534         }
535 }
536
537 static void shmem_stop(void)
538 {
539         if (shared_data == NULL)
540                 return;
541
542         shared_data->stopping = 1;
543 }
544
545 static void shmem_cleanup(void)
546 {
547         if (shared_data == NULL)
548                 return;
549
550         shmem_stop();
551
552         pthread_mutex_destroy(&shared_data->mutex);
553         pthread_cond_destroy(&shared_data->cond);
554 }
555
556 static int shmem_running(void)
557 {
558         return (shared_data == NULL || !shared_data->stopping);
559 }
560
561 static void shmem_end_time_locked(void)
562 {
563         shared_data->body.stop_barrier--;
564         if (shared_data->body.stop_barrier == 0)
565                 gettimeofday(&shared_data->body.end_time, NULL);
566 }
567
568 static void shmem_start_time_locked(void)
569 {
570         shared_data->body.start_barrier--;
571         if (shared_data->body.start_barrier == 0) {
572                 shmem_wakeup_all();
573                 gettimeofday(&shared_data->body.start_time, NULL);
574         } else {
575                 shmem_wait();
576         }
577 }
578
579 #else
580 static int shmem_setup(void)
581 {
582         return 0;
583 }
584
585 static inline void shmem_reset(int total_threads)
586 {
587 }
588
589 static inline void shmem_bump(__u32 counters)
590 {
591 }
592
593 static void shmem_lock()
594 {
595 }
596
597 static void shmem_unlock()
598 {
599 }
600
601 static void shmem_cleanup(void)
602 {
603 }
604
605 static int shmem_running(void)
606 {
607         return 1;
608 }
609 #endif
610
611 extern command_t cmdlist[];
612
613 static int do_device(char *func, char *devname)
614 {
615         int dev;
616
617         dev = parse_devname(func, devname);
618         if (dev < 0)
619                 return -1;
620
621         lcfg_set_devname(devname);
622         cur_device = dev;
623         return 0;
624 }
625
626 int jt_obd_get_device()
627 {
628         return cur_device;
629 }
630
631 int jt_obd_device(int argc, char **argv)
632 {
633         int rc;
634
635         if (argc > 2)
636                 return CMD_HELP;
637
638         if (argc == 1) {
639                 printf("current device is %d - %s\n",
640                        cur_device, lcfg_get_devname() ? : "not set");
641                 return 0;
642         }
643         rc = do_device("device", argv[1]);
644         return rc;
645 }
646
647 int jt_opt_device(int argc, char **argv)
648 {
649         int ret;
650         int rc;
651
652         if (argc < 3)
653                 return CMD_HELP;
654
655         rc = do_device("device", argv[1]);
656
657         if (!rc)
658                 rc = Parser_execarg(argc - 2, argv + 2, cmdlist);
659
660         ret = do_disconnect(argv[0], 0);
661         if (!rc)
662                 rc = ret;
663
664         return rc;
665 }
666
667 #ifdef MAX_THREADS
668 static void parent_sighandler (int sig)
669 {
670         return;
671 }
672
673 int jt_opt_threads(int argc, char **argv)
674 {
675         static char      cmdstr[129];
676         sigset_t         saveset;
677         sigset_t         sigset;
678         struct sigaction sigact;
679         struct sigaction saveact1;
680         struct sigaction saveact2;
681         unsigned long    threads;
682         __u64            next_thread;
683         int verbose;
684         int rc = 0;
685         int report_count = -1;
686         char *end;
687         int i;
688
689         if (argc < 5)
690                 return CMD_HELP;
691
692         threads = strtoul(argv[1], &end, 0);
693
694         if (*end == '.')
695                 report_count = strtoul(end + 1, &end, 0);
696
697         if (*end || threads > MAX_THREADS) {
698                 fprintf(stderr, "error: %s: invalid thread count '%s'\n",
699                         jt_cmdname(argv[0]), argv[1]);
700                 return CMD_HELP;
701         }
702
703         verbose = get_verbose(argv[0], argv[2]);
704         if (verbose == BAD_VERBOSE)
705                 return CMD_HELP;
706
707         if (verbose != 0) {
708                 snprintf(cmdstr, sizeof(cmdstr), "%s", argv[4]);
709                 for (i = 5; i < argc; i++)
710                         snprintf(cmdstr + strlen(cmdstr),
711                                  sizeof(cmdstr) - strlen(cmdstr),
712                                  " %s", argv[i]);
713
714                 printf("%s: starting %ld threads on device %s running %s\n",
715                        argv[0], threads, argv[3], cmdstr);
716         }
717
718         shmem_reset(threads);
719
720         sigemptyset(&sigset);
721         sigaddset(&sigset, SIGALRM);
722         sigaddset(&sigset, SIGCHLD);
723         sigprocmask(SIG_BLOCK, &sigset, &saveset);
724
725         nthreads = threads;
726
727         for (i = 1, next_thread = verbose; i <= threads; i++) {
728                 rc = fork();
729                 if (rc < 0) {
730                         fprintf(stderr, "error: %s: #%d - %s\n", argv[0], i,
731                                 strerror(rc = errno));
732                         break;
733                 } else if (rc == 0) {
734                         sigprocmask(SIG_SETMASK, &saveset, NULL);
735
736                         thread = i;
737                         argv[2] = "--device";
738                         exit(jt_opt_device(argc - 2, argv + 2));
739                 } else if (be_verbose(verbose, NULL, i, &next_thread, threads))
740                         printf("%s: thread #%d (PID %d) started\n",
741                                argv[0], i, rc);
742                 rc = 0;
743         }
744
745         if (!thread) {          /* parent process */
746                 int live_threads = threads;
747
748                 sigemptyset(&sigset);
749                 sigemptyset(&sigact.sa_mask);
750                 sigact.sa_handler = parent_sighandler;
751                 sigact.sa_flags = 0;
752
753                 sigaction(SIGALRM, &sigact, &saveact1);
754                 sigaction(SIGCHLD, &sigact, &saveact2);
755
756                 while (live_threads > 0) {
757                         int status;
758                         pid_t ret;
759
760                         if (verbose < 0)        /* periodic stats */
761                                 alarm(-verbose);
762
763                         sigsuspend(&sigset);
764                         alarm(0);
765
766                         while (live_threads > 0) {
767                                 ret = waitpid(0, &status, WNOHANG);
768                                 if (ret == 0)
769                                         break;
770
771                                 if (ret < 0) {
772                                         fprintf(stderr, "error: %s: wait - %s\n",
773                                                 argv[0], strerror(errno));
774                                         if (!rc)
775                                                 rc = errno;
776                                         continue;
777                                 } else {
778                                         /*
779                                          * This is a hack.  We _should_ be able
780                                          * to use WIFEXITED(status) to see if
781                                          * there was an error, but it appears
782                                          * to be broken and it always returns 1
783                                          * (OK).  See wait(2).
784                                          */
785                                         int err = WEXITSTATUS(status);
786                                         if (err || WIFSIGNALED(status))
787                                                 fprintf(stderr,
788                                                         "%s: PID %d had rc=%d\n",
789                                                         argv[0], ret, err);
790                                         if (!rc)
791                                                 rc = err;
792
793                                         live_threads--;
794                                 }
795                         }
796
797                         /* Show stats while all threads running */
798                         if (verbose < 0) {
799                                 shmem_snap(threads, live_threads);
800                                 if (report_count > 0 && --report_count == 0)
801                                         shmem_stop();
802                         }
803                 }
804                 sigaction(SIGCHLD, &saveact2, NULL);
805                 sigaction(SIGALRM, &saveact1, NULL);
806         }
807
808         shmem_total(threads);
809         sigprocmask(SIG_SETMASK, &saveset, NULL);
810
811         return rc;
812 }
813 #else
814 int jt_opt_threads(int argc, char **argv)
815 {
816         fprintf(stderr, "%s not-supported in a single-threaded runtime\n",
817                 jt_cmdname(argv[0]));
818         return CMD_HELP;
819 }
820 #endif
821
822 int jt_opt_net(int argc, char **argv)
823 {
824         char *arg2[3];
825         int rc;
826
827         if (argc < 3)
828                 return CMD_HELP;
829
830         arg2[0] = argv[0];
831         arg2[1] = argv[1];
832         arg2[2] = NULL;
833         rc = jt_ptl_network (2, arg2);
834
835         if (!rc)
836                 rc = Parser_execarg(argc - 2, argv + 2, cmdlist);
837
838         return rc;
839 }
840
841 #ifdef HAVE_SERVER_SUPPORT
842 /* Place this here so we can build tools that work with
843  * older Lustre versions
844  */
845 #ifndef OBD_IOC_NO_TRANSNO
846 #define OBD_IOC_NO_TRANSNO      _IOW('f', 140, OBD_IOC_DATA_TYPE)
847 #endif
848
849 int jt_obd_no_transno(int argc, char **argv)
850 {
851         struct obd_ioctl_data data;
852         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
853         glob_t path;
854         int count;
855         int fd;
856         int rc;
857
858         if (argc != 1)
859                 return CMD_HELP;
860
861         memset(buf, 0, sizeof(rawbuf));
862
863         rc = cfs_get_param_paths(&path, "no_transno");
864         if (rc != 0)
865                 goto old_ioctl;
866
867         fd = open(path.gl_pathv[0], O_WRONLY);
868         if (fd < 0) {
869                 cfs_free_param_data(&path);
870                 goto old_ioctl;
871         }
872
873         snprintf(rawbuf, sizeof(rawbuf), "%d", cur_device);
874
875         count = write(fd, rawbuf, strlen(rawbuf));
876         if (count < 0)
877                 rc = errno;
878
879         cfs_free_param_data(&path);
880         close(fd);
881         if (rc)
882                 goto old_ioctl;
883
884         return 0;
885
886 old_ioctl:
887 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
888         memset(&data, 0, sizeof(data));
889         data.ioc_dev = cur_device;
890
891         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
892         if (rc) {
893                 fprintf(stderr, "error: %s: invalid ioctl\n",
894                         jt_cmdname(argv[0]));
895                 return rc;
896         }
897         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_NO_TRANSNO, buf);
898         if (rc < 0)
899                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
900                         strerror(rc = errno));
901 #endif
902         return rc;
903 }
904 #endif /* HAVE_SERVER_SUPPORT */
905
906 int jt_obd_set_readonly(int argc, char **argv)
907 {
908         struct obd_ioctl_data data;
909         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
910         int rc;
911
912         memset(&data, 0, sizeof(data));
913         data.ioc_dev = cur_device;
914
915         if (argc != 1)
916                 return CMD_HELP;
917
918         memset(buf, 0, sizeof(rawbuf));
919         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
920         if (rc) {
921                 fprintf(stderr, "error: %s: invalid ioctl\n",
922                         jt_cmdname(argv[0]));
923                 return rc;
924         }
925         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_SET_READONLY, buf);
926         if (rc < 0)
927                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
928                         strerror(rc = errno));
929
930         return rc;
931 }
932
933 int jt_obd_abort_recovery(int argc, char **argv)
934 {
935         struct obd_ioctl_data data;
936         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
937         int rc;
938
939         memset(&data, 0, sizeof(data));
940         data.ioc_dev = cur_device;
941
942         if (argc != 1)
943                 return CMD_HELP;
944
945         memset(buf, 0, sizeof(rawbuf));
946         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
947         if (rc) {
948                 fprintf(stderr, "error: %s: invalid ioctl\n",
949                         jt_cmdname(argv[0]));
950                 return rc;
951         }
952         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_ABORT_RECOVERY, buf);
953         if (rc < 0)
954                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
955                         strerror(rc = errno));
956
957         return rc;
958 }
959
960 int jt_get_version(int argc, char **argv)
961 {
962         char version[128];
963         int rc;
964
965         if (argc != 1)
966                 return CMD_HELP;
967
968         rc = llapi_get_version_string(version, sizeof(version));
969         if (rc)
970                 printf("Lustre version: %s\n", LUSTRE_VERSION_STRING);
971         else
972                 printf("Lustre version: %s\n", version);
973
974         return 0;
975 }
976
977 static void print_obd_line(char *s)
978 {
979         const char *param = "osc/%s/ost_conn_uuid";
980         char buf[MAX_STRING_SIZE];
981         char obd_name[MAX_OBD_NAME];
982         FILE *fp = NULL;
983         glob_t path;
984         char *ptr;
985 retry:
986         /* obd device type is the first 3 characters of param name */
987         snprintf(buf, sizeof(buf), " %%*d %%*s %.3s %%%zus %%*s %%*d ",
988                  param, sizeof(obd_name) - 1);
989         if (sscanf(s, buf, obd_name) == 0)
990                 goto try_mdc;
991         if (cfs_get_param_paths(&path, param, obd_name) != 0)
992                 goto try_mdc;
993         fp = fopen(path.gl_pathv[0], "r");
994         if (fp == NULL) {
995                 /* need to free path data before retry */
996                 cfs_free_param_data(&path);
997 try_mdc:
998                 if (param[0] == 'o') { /* failed with osc, try mdc */
999                         param = "mdc/%s/mds_conn_uuid";
1000                         goto retry;
1001                 }
1002                 buf[0] = '\0';
1003                 goto fail_print;
1004         }
1005
1006         /* should not ignore fgets(3)'s return value */
1007         if (!fgets(buf, sizeof(buf), fp)) {
1008                 fprintf(stderr, "reading from %s: %s", buf, strerror(errno));
1009                 goto fail_close;
1010         }
1011
1012 fail_close:
1013         fclose(fp);
1014         cfs_free_param_data(&path);
1015
1016         /* trim trailing newlines */
1017         ptr = strrchr(buf, '\n');
1018         if (ptr)
1019                 *ptr = '\0';
1020 fail_print:
1021         ptr = strrchr(s, '\n');
1022         if (ptr)
1023                 *ptr = '\0';
1024         printf("%s%s%s\n", s, buf[0] ? " " : "", buf);
1025 }
1026
1027 /* get device list by ioctl */
1028 int jt_obd_list_ioctl(int argc, char **argv)
1029 {
1030         int rc, index;
1031         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1032         struct obd_ioctl_data *data = (struct obd_ioctl_data *)buf;
1033
1034         if (argc > 2)
1035                 return CMD_HELP;
1036         /* Just ignore a -t option.  Only supported with /proc. */
1037         else if (argc == 2 && strcmp(argv[1], "-t") != 0)
1038                 return CMD_HELP;
1039
1040         for (index = 0;; index++) {
1041                 memset(buf, 0, sizeof(rawbuf));
1042                 data->ioc_version = OBD_IOCTL_VERSION;
1043                 data->ioc_inllen1 =
1044                         sizeof(rawbuf) - __ALIGN_KERNEL(sizeof(*data), 8);
1045                 data->ioc_inlbuf1 = buf + __ALIGN_KERNEL(sizeof(*data), 8);
1046                 data->ioc_len = obd_ioctl_packlen(data);
1047                 data->ioc_count = index;
1048
1049                 rc = l_ioctl(OBD_DEV_ID, OBD_IOC_GETDEVICE, buf);
1050                 if (rc != 0)
1051                         break;
1052                 printf("%s\n", (char *)data->ioc_bulk);
1053         }
1054         if (rc != 0) {
1055                 if (errno == ENOENT)
1056                         /* no device or the last device */
1057                         rc = 0;
1058                 else
1059                         fprintf(stderr,
1060                                 "Error getting device list: %s: check dmesg\n",
1061                                 strerror(errno));
1062         }
1063         return rc;
1064 }
1065
1066 int jt_obd_list(int argc, char **argv)
1067 {
1068         char buf[MAX_STRING_SIZE];
1069         int print_obd = 0;
1070         glob_t path;
1071         FILE *fp;
1072
1073         if (argc > 2)
1074                 return CMD_HELP;
1075
1076         if (argc == 2) {
1077                 if (strcmp(argv[1], "-t") == 0)
1078                         print_obd = 1;
1079                 else
1080                         return CMD_HELP;
1081         }
1082
1083         if (cfs_get_param_paths(&path, "devices") ||
1084             !(fp = fopen(path.gl_pathv[0], "r"))) {
1085                 cfs_free_param_data(&path);
1086
1087                 return jt_obd_list_ioctl(argc, argv);
1088         }
1089
1090         while (fgets(buf, sizeof(buf), fp) != NULL)
1091                 if (print_obd)
1092                         print_obd_line(buf);
1093                 else
1094                         printf("%s", buf);
1095
1096         cfs_free_param_data(&path);
1097         fclose(fp);
1098         return 0;
1099 }
1100
1101 struct jt_fid_space {
1102         __u64   jt_seq;
1103         __u64   jt_id;
1104         int     jt_width;
1105 };
1106
1107 int jt_obd_alloc_fids(struct jt_fid_space *space, struct lu_fid *fid,
1108                       __u64 *count)
1109 {
1110         int rc;
1111
1112         if (space->jt_seq == 0 || space->jt_id == space->jt_width) {
1113                 struct obd_ioctl_data  data;
1114                 char rawbuf[MAX_IOC_BUFLEN];
1115                 char *buf = rawbuf;
1116                 __u64 seqnr;
1117                 int max_count;
1118
1119                 memset(&data, 0, sizeof(data));
1120                 data.ioc_dev = cur_device;
1121
1122                 data.ioc_pbuf1 = (char *)&seqnr;
1123                 data.ioc_plen1 = sizeof(seqnr);
1124
1125                 data.ioc_pbuf2 = (char *)&max_count;
1126                 data.ioc_plen2 = sizeof(max_count);
1127
1128                 memset(buf, 0, sizeof(rawbuf));
1129                 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1130                 if (rc) {
1131                         fprintf(stderr, "error: invalid ioctl rc = %d\n", rc);
1132                         return rc;
1133                 }
1134
1135                 rc = l_ioctl(OBD_DEV_ID, OBD_IOC_ECHO_ALLOC_SEQ, buf);
1136                 if (rc) {
1137                         fprintf(stderr, "ioctl error: rc = %d\n", rc);
1138                         return rc;
1139                 }
1140
1141                 space->jt_seq = *(__u64 *)data.ioc_pbuf1;
1142                 space->jt_width = *(int *)data.ioc_pbuf2;
1143                 space->jt_id = 1;
1144         }
1145         fid->f_seq = space->jt_seq;
1146         fid->f_oid = space->jt_id;
1147         fid->f_ver = 0;
1148
1149         space->jt_id = space->jt_id + *count;
1150         if (space->jt_id > space->jt_width)
1151                 space->jt_id = space->jt_width;
1152
1153         *count = space->jt_id - fid->f_oid;
1154         return 0;
1155 }
1156
1157 #define MD_STEP_COUNT 1000
1158 int jt_obd_md_common(int argc, char **argv, int cmd)
1159 {
1160         struct obd_ioctl_data  data;
1161         struct timeval         start;
1162         struct timeval         end_time;
1163         char                   rawbuf[MAX_IOC_BUFLEN];
1164         char                  *buf = rawbuf;
1165         int                    mode = 0000644;
1166         int                    create_mode;
1167         int                    rc = 0;
1168         char                  *parent_basedir = NULL;
1169         char                   dirname[4096];
1170         int                    parent_base_id = 0;
1171         int                    parent_count = 1;
1172         __u64                  child_base_id = -1;
1173         int                    stripe_count = 0;
1174         int                    stripe_index = -1;
1175         int                    count = 0;
1176         char                  *end;
1177         __u64                  seconds = 0;
1178         double                 diff;
1179         int                    c;
1180         __u64                  total_count = 0;
1181         char                  *name = NULL;
1182         struct jt_fid_space    fid_space = {0};
1183         int                    version = 0;
1184         struct option long_opts[] = {
1185         { .val = 'b',   .name = "child_base_id",
1186                                                 .has_arg = required_argument },
1187         { .val = 'c',   .name = "stripe_count",
1188                                                 .has_arg = required_argument },
1189         { .val = 'd',   .name = "parent_basedir",
1190                                                 .has_arg = required_argument },
1191         { .val = 'D',   .name = "parent_dircount",
1192                                                 .has_arg = required_argument },
1193         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument },
1194         { .val = 'm',   .name = "mode",         .has_arg = required_argument },
1195         { .val = 'n',   .name = "count",        .has_arg = required_argument },
1196         { .val = 't',   .name = "time",         .has_arg = required_argument },
1197         { .val = 'v',   .name = "version",      .has_arg = no_argument },
1198         { .name = NULL } };
1199
1200         while ((c = getopt_long(argc, argv, "b:c:d:D:m:n:t:v",
1201                                 long_opts, NULL)) >= 0) {
1202                 switch (c) {
1203                 case 'b':
1204                         child_base_id = strtoull(optarg, &end, 0);
1205                         if (*end) {
1206                                 fprintf(stderr, "error: %s: bad child_base_id"
1207                                         " '%s'\n", jt_cmdname(argv[0]), optarg);
1208                                 return CMD_HELP;
1209                         }
1210                         break;
1211                 case 'c':
1212                         stripe_count = strtoul(optarg, &end, 0);
1213                         if (*end) {
1214                                 fprintf(stderr, "error: %s: bad stripe count"
1215                                         " '%s'\n", jt_cmdname(argv[0]), optarg);
1216                                 return CMD_HELP;
1217                         }
1218                         break;
1219                 case 'd':
1220                         parent_basedir = optarg;
1221                         break;
1222                 case 'D':
1223                         parent_count = strtoul(optarg, &end, 0);
1224                         if (*end) {
1225                                 fprintf(stderr, "error: %s: bad parent count"
1226                                         " '%s'\n", jt_cmdname(argv[0]), optarg);
1227                                 return CMD_HELP;
1228                         }
1229                         break;
1230                 case 'i':
1231                         stripe_index = strtoul(optarg, &end, 0);
1232                         if (*end) {
1233                                 fprintf(stderr, "error: %s: bad stripe index"
1234                                         " '%s'\n", jt_cmdname(argv[0]), optarg);
1235                                 return CMD_HELP;
1236                         }
1237                         break;
1238                 case 'm':
1239                         mode = strtoul(optarg, &end, 0);
1240                         if (*end) {
1241                                 fprintf(stderr, "error: %s: bad mode '%s'\n",
1242                                         jt_cmdname(argv[0]), optarg);
1243                                 return CMD_HELP;
1244                         }
1245                         break;
1246                 case 'n':
1247                         total_count = strtoul(optarg, &end, 0);
1248                         if (*end || total_count == 0) {
1249                                 fprintf(stderr, "%s: bad child count '%s'\n",
1250                                         jt_cmdname(argv[0]), optarg);
1251                                 return CMD_HELP;
1252                         }
1253                         break;
1254                 case 't':
1255                         seconds = strtoull(optarg, &end, 0);
1256                         if (*end) {
1257                                 fprintf(stderr, "error: %s: seconds '%s'\n",
1258                                         jt_cmdname(argv[0]), optarg);
1259                                 return CMD_HELP;
1260                         }
1261                         break;
1262                 case 'v':
1263                         version = 1;
1264                         break;
1265                 default:
1266                         fprintf(stderr, "error: %s: option '%s' "
1267                                 "unrecognized\n", argv[0], argv[optind - 1]);
1268                         return CMD_HELP;
1269                 }
1270         }
1271
1272         memset(&data, 0, sizeof(data));
1273         data.ioc_dev = cur_device;
1274         if (child_base_id == -1) {
1275                 if (optind >= argc)
1276                         return CMD_HELP;
1277                 name = argv[optind];
1278                 total_count = 1;
1279         } else {
1280                 if (optind < argc) {
1281                         fprintf(stderr, "child_base_id and name can not"
1282                                         " specified at the same time\n");
1283                         return CMD_HELP;
1284                 }
1285         }
1286
1287         if (stripe_count == 0 && stripe_index != -1) {
1288                 fprintf(stderr, "If stripe_count is 0, stripe_index can not be specified\n");
1289                 return CMD_HELP;
1290         }
1291
1292         if (total_count == 0 && seconds == 0) {
1293                 fprintf(stderr, "count or seconds needs to be indicated\n");
1294                 return CMD_HELP;
1295         }
1296
1297         if (parent_count <= 0) {
1298                 fprintf(stderr, "parent count must < 0\n");
1299                 return CMD_HELP;
1300         }
1301
1302 #ifdef MAX_THREADS
1303         if (thread) {
1304                 shmem_lock();
1305                 /* threads interleave */
1306                 if (parent_base_id != -1)
1307                         parent_base_id += (thread - 1) % parent_count;
1308
1309                 if (child_base_id != -1)
1310                         child_base_id +=  (thread - 1) * \
1311                                           (MAX_BASE_ID / nthreads);
1312
1313                 shmem_start_time_locked();
1314                 shmem_unlock();
1315         }
1316 #endif
1317         /* If parent directory is not specified, try to get the directory
1318          * from name */
1319         if (parent_basedir == NULL) {
1320                 char *last_lash;
1321                 if (name == NULL) {
1322                         fprintf(stderr,
1323                                 "parent_basedir or name must be indicated!\n");
1324                         return CMD_HELP;
1325                 }
1326                 /*Get directory and name from name*/
1327                 last_lash = strrchr(name, '/');
1328                 if (last_lash == NULL || name[0] != '/') {
1329                         fprintf(stderr, "Can not locate %s\n", name);
1330                         return CMD_HELP;
1331                 }
1332
1333                 if (last_lash == name) {
1334                         sprintf(dirname, "%s", "/");
1335                         name++;
1336                 } else {
1337                         int namelen = (unsigned long)last_lash -
1338                                       (unsigned long)name + 1;
1339                         snprintf(dirname, namelen, "%s", name);
1340                         name = last_lash + 1;
1341                 }
1342
1343                 data.ioc_pbuf1 = dirname;
1344                 data.ioc_plen1 = strlen(dirname);
1345
1346                 data.ioc_pbuf2 = name;
1347                 data.ioc_plen2 = strlen(name);
1348         } else {
1349                 if (name != NULL) {
1350                         data.ioc_pbuf2 = name;
1351                         data.ioc_plen2 = strlen(name);
1352                 }
1353                 if (parent_base_id > 0)
1354                         sprintf(dirname, "%s%d", parent_basedir,
1355                                 parent_base_id);
1356                 else
1357                         sprintf(dirname, "%s", parent_basedir);
1358                 data.ioc_pbuf1 = dirname;
1359                 data.ioc_plen1 = strlen(dirname);
1360         }
1361
1362         if (cmd == ECHO_MD_MKDIR || cmd == ECHO_MD_RMDIR)
1363                 create_mode = S_IFDIR;
1364         else
1365                 create_mode = S_IFREG;
1366
1367         data.ioc_obdo1.o_mode = mode | S_IFDIR;
1368         data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE |
1369                                  OBD_MD_FLFLAGS | OBD_MD_FLGROUP;
1370         data.ioc_command = cmd;
1371
1372         gettimeofday(&start, NULL);
1373         while (shmem_running()) {
1374                 struct lu_fid fid = { 0 };
1375
1376                 if (child_base_id != -1)
1377                         data.ioc_obdo2.o_oi.oi.oi_id = child_base_id;
1378                 data.ioc_obdo2.o_mode = mode | create_mode;
1379                 data.ioc_obdo2.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE |
1380                                          OBD_MD_FLMODE | OBD_MD_FLFLAGS |
1381                                          OBD_MD_FLGROUP;
1382                 data.ioc_obdo2.o_misc = stripe_count;
1383                 data.ioc_obdo2.o_stripe_idx = stripe_index;
1384
1385                 if (total_count > 0) {
1386                         if ((total_count - count) > MD_STEP_COUNT)
1387                                 data.ioc_count = MD_STEP_COUNT;
1388                         else
1389                                 data.ioc_count = total_count - count;
1390                 } else {
1391                         data.ioc_count = MD_STEP_COUNT;
1392                 }
1393
1394                 if (cmd == ECHO_MD_CREATE || cmd == ECHO_MD_MKDIR) {
1395                         /*Allocate fids for the create */
1396                         rc = jt_obd_alloc_fids(&fid_space, &fid,
1397                                                &data.ioc_count);
1398                         if (rc) {
1399                                 fprintf(stderr, "Allocate fids error %d.\n",rc);
1400                                 return rc;
1401                         }
1402                         data.ioc_obdo1.o_oi.oi_fid = fid;
1403                 }
1404
1405                 child_base_id += data.ioc_count;
1406                 count += data.ioc_count;
1407
1408                 memset(buf, 0, sizeof(rawbuf));
1409                 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1410                 if (rc) {
1411                         fprintf(stderr, "error: %s: invalid ioctl %d\n",
1412                                 jt_cmdname(argv[0]), rc);
1413                         return rc;
1414                 }
1415
1416                 rc = l_ioctl(OBD_DEV_ID, OBD_IOC_ECHO_MD, buf);
1417                 if (rc) {
1418                         fprintf(stderr, "error: %s: %s\n",
1419                                 jt_cmdname(argv[0]), strerror(rc = errno));
1420                         return rc;
1421                 }
1422                 shmem_bump(data.ioc_count);
1423
1424                 gettimeofday(&end_time, NULL);
1425                 diff = difftime(&end_time, &start);
1426                 if (seconds > 0 && (__u64)diff > seconds)
1427                         break;
1428
1429                 if (count >= total_count && total_count > 0)
1430                         break;
1431         }
1432
1433         if (count > 0 && version) {
1434                 gettimeofday(&end_time, NULL);
1435                 diff = difftime(&end_time, &start);
1436                 printf("%s: %d in %.3fs (%.3f /s): %s",
1437                         jt_cmdname(argv[0]), count, diff,
1438                         (double)count/diff, ctime(&end_time.tv_sec));
1439         }
1440
1441 #ifdef MAX_THREADS
1442         if (thread) {
1443                 shmem_lock();
1444                 shmem_end_time_locked();
1445                 shmem_unlock();
1446         }
1447 #endif
1448         return rc;
1449 }
1450
1451 int jt_obd_test_create(int argc, char **argv)
1452 {
1453         return jt_obd_md_common(argc, argv, ECHO_MD_CREATE);
1454 }
1455
1456 int jt_obd_test_mkdir(int argc, char **argv)
1457 {
1458         return jt_obd_md_common(argc, argv, ECHO_MD_MKDIR);
1459 }
1460
1461 int jt_obd_test_destroy(int argc, char **argv)
1462 {
1463         return jt_obd_md_common(argc, argv, ECHO_MD_DESTROY);
1464 }
1465
1466 int jt_obd_test_rmdir(int argc, char **argv)
1467 {
1468         return jt_obd_md_common(argc, argv, ECHO_MD_RMDIR);
1469 }
1470
1471 int jt_obd_test_lookup(int argc, char **argv)
1472 {
1473         return jt_obd_md_common(argc, argv, ECHO_MD_LOOKUP);
1474 }
1475
1476 int jt_obd_test_setxattr(int argc, char **argv)
1477 {
1478         return jt_obd_md_common(argc, argv, ECHO_MD_SETATTR);
1479 }
1480
1481 int jt_obd_test_md_getattr(int argc, char **argv)
1482 {
1483         return jt_obd_md_common(argc, argv, ECHO_MD_GETATTR);
1484 }
1485
1486 int jt_obd_create(int argc, char **argv)
1487 {
1488         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1489         struct obd_ioctl_data data;
1490         struct timeval next_time;
1491         __u64 count = 1, next_count, base_id = 1;
1492         int verbose = 1, mode = 0100644, rc = 0, i;
1493         char *end;
1494
1495         memset(&data, 0, sizeof(data));
1496         data.ioc_dev = cur_device;
1497         if (argc < 2 || argc > 4)
1498                 return CMD_HELP;
1499
1500         count = strtoull(argv[1], &end, 0);
1501         if (*end) {
1502                 fprintf(stderr, "error: %s: invalid iteration count '%s'\n",
1503                         jt_cmdname(argv[0]), argv[1]);
1504                 return CMD_HELP;
1505         }
1506
1507         if (argc > 2) {
1508                 mode = strtoul(argv[2], &end, 0);
1509                 if (*end) {
1510                         fprintf(stderr, "error: %s: invalid mode '%s'\n",
1511                                 jt_cmdname(argv[0]), argv[2]);
1512                         return CMD_HELP;
1513                 }
1514                 if (!(mode & S_IFMT))
1515                         mode |= S_IFREG;
1516         }
1517
1518         if (argc > 3) {
1519                 verbose = get_verbose(argv[0], argv[3]);
1520                 if (verbose == BAD_VERBOSE)
1521                         return CMD_HELP;
1522         }
1523
1524         printf("%s: %jd objects\n", jt_cmdname(argv[0]), (uintmax_t)count);
1525         gettimeofday(&next_time, NULL);
1526         next_time.tv_sec -= verbose;
1527
1528         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1529         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
1530                 /*
1531                  * base_id is 1 so we don't need to worry about it being
1532                  * greater than OBIF_MAX_OID
1533                  */
1534                 data.ioc_obdo1.o_oi.oi_fid.f_oid = base_id;
1535                 data.ioc_obdo1.o_mode = mode;
1536                 data.ioc_obdo1.o_uid = 0;
1537                 data.ioc_obdo1.o_gid = 0;
1538                 data.ioc_obdo1.o_projid = 0;
1539                 data.ioc_obdo1.o_valid = OBD_MD_FLTYPE | OBD_MD_FLMODE |
1540                                          OBD_MD_FLID | OBD_MD_FLUID |
1541                                          OBD_MD_FLGID | OBD_MD_FLGROUP |
1542                                          OBD_MD_FLPROJID;
1543
1544                 memset(buf, 0, sizeof(rawbuf));
1545                 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1546                 if (rc) {
1547                         fprintf(stderr, "error: %s: invalid ioctl\n",
1548                                 jt_cmdname(argv[0]));
1549                         return rc;
1550                 }
1551                 rc = l_ioctl(OBD_DEV_ID, OBD_IOC_CREATE, buf);
1552                 llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
1553                 shmem_bump(1);
1554                 if (rc < 0) {
1555                         fprintf(stderr, "error: %s: #%d - %s\n",
1556                                 jt_cmdname(argv[0]), i, strerror(rc = errno));
1557                         break;
1558                 }
1559                 if (!(data.ioc_obdo1.o_valid & OBD_MD_FLID)) {
1560                         fprintf(stderr, "error: %s: oid not valid #%d:%#jx\n",
1561                                 jt_cmdname(argv[0]), i,
1562                                 (uintmax_t)data.ioc_obdo1.o_valid);
1563                         rc = EINVAL;
1564                         break;
1565                 }
1566
1567                 if (be_verbose(verbose, &next_time, i, &next_count, count))
1568                         printf("%s: #%d is object id %#jx\n",
1569                                jt_cmdname(argv[0]), i,
1570                                (uintmax_t) ostid_id(&data.ioc_obdo1.o_oi));
1571         }
1572
1573         return rc;
1574 }
1575
1576 int jt_obd_setattr(int argc, char **argv)
1577 {
1578         struct obd_ioctl_data data;
1579         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1580         __u64 objid;
1581         char *end;
1582         int mode;
1583         int rc;
1584
1585         memset(&data, 0, sizeof(data));
1586         data.ioc_dev = cur_device;
1587         if (argc != 2)
1588                 return CMD_HELP;
1589
1590         objid = strtoull(argv[1], &end, 0);
1591         if (*end) {
1592                 fprintf(stderr, "error: %s: objid '%s' is not a number\n",
1593                         jt_cmdname(argv[0]), argv[1]);
1594                 return CMD_HELP;
1595         }
1596
1597         if (objid >= OBIF_MAX_OID) {
1598                 fprintf(stderr, "error: %s: invalid objid '%s'\n",
1599                         jt_cmdname(argv[0]), argv[1]);
1600                 return CMD_HELP;
1601         }
1602
1603         mode = strtoul(argv[2], &end, 0);
1604         if (*end) {
1605                 fprintf(stderr, "error: %s: invalid mode '%s'\n",
1606                         jt_cmdname(argv[0]), argv[2]);
1607                 return CMD_HELP;
1608         }
1609
1610         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1611         data.ioc_obdo1.o_mode = S_IFREG | mode;
1612         data.ioc_obdo1.o_oi.oi_fid.f_oid = objid;
1613         data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE;
1614
1615         memset(buf, 0, sizeof(rawbuf));
1616         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1617         if (rc) {
1618                 fprintf(stderr, "error: %s: invalid ioctl\n",
1619                         jt_cmdname(argv[0]));
1620                 return rc;
1621         }
1622         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_SETATTR, buf);
1623         if (rc < 0)
1624                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
1625                         strerror(rc = errno));
1626
1627         return rc;
1628 }
1629
1630 int jt_obd_test_setattr(int argc, char **argv)
1631 {
1632         struct obd_ioctl_data data;
1633         struct timeval start, next_time;
1634         __u64 i, count, next_count;
1635         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1636         int verbose = 1;
1637         __u64 objid = 3;
1638         char *end;
1639         int rc = 0;
1640
1641         if (argc < 2 || argc > 4)
1642                 return CMD_HELP;
1643
1644         memset(&data, 0, sizeof(data));
1645         data.ioc_dev = cur_device;
1646         count = strtoull(argv[1], &end, 0);
1647         if (*end) {
1648                 fprintf(stderr, "error: %s: invalid iteration count '%s'\n",
1649                         jt_cmdname(argv[0]), argv[1]);
1650                 return CMD_HELP;
1651         }
1652
1653         if (argc >= 3) {
1654                 verbose = get_verbose(argv[0], argv[2]);
1655                 if (verbose == BAD_VERBOSE)
1656                         return CMD_HELP;
1657         }
1658
1659         if (argc >= 4) {
1660                 if (argv[3][0] == 't') {
1661                         objid = strtoull(argv[3] + 1, &end, 0);
1662                         if (thread)
1663                                 objid += thread - 1;
1664                 } else
1665                         objid = strtoull(argv[3], &end, 0);
1666                 if (*end) {
1667                         fprintf(stderr, "error: %s: invalid objid '%s'\n",
1668                                 jt_cmdname(argv[0]), argv[3]);
1669                         return CMD_HELP;
1670                 }
1671         }
1672
1673         gettimeofday(&start, NULL);
1674         next_time.tv_sec = start.tv_sec - verbose;
1675         next_time.tv_usec = start.tv_usec;
1676         if (verbose != 0)
1677                 printf("%s: setting %jd attrs (objid %#jx): %s",
1678                        jt_cmdname(argv[0]), (uintmax_t)count,
1679                        (uintmax_t)objid, ctime(&start.tv_sec));
1680
1681         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1682         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
1683                 if (objid >= OBIF_MAX_OID) {
1684                         fprintf(stderr, "errr: %s: invalid objid '%llu'\n",
1685                                 jt_cmdname(argv[0]), (unsigned long long)objid);
1686                         return -E2BIG;
1687                 }
1688
1689                 data.ioc_obdo1.o_oi.oi_fid.f_oid = objid;
1690                 data.ioc_obdo1.o_mode = S_IFREG;
1691                 data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE |
1692                                          OBD_MD_FLMODE;
1693                 memset(buf, 0, sizeof(rawbuf));
1694                 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1695                 if (rc) {
1696                         fprintf(stderr, "error: %s: invalid ioctl\n",
1697                                 jt_cmdname(argv[0]));
1698                         return rc;
1699                 }
1700                 rc = l_ioctl(OBD_DEV_ID, OBD_IOC_SETATTR, &data);
1701                 shmem_bump(1);
1702                 if (rc < 0) {
1703                         fprintf(stderr, "error: %s: #%jd - %d:%s\n",
1704                                 jt_cmdname(argv[0]), (uintmax_t)i,
1705                                 errno, strerror(rc = errno));
1706                         break;
1707                 }
1708                 if (be_verbose(verbose, &next_time, i, &next_count, count))
1709                         printf("%s: set attr #%jd\n",
1710                                jt_cmdname(argv[0]), (uintmax_t)i);
1711         }
1712
1713         if (!rc) {
1714                 struct timeval end;
1715                 double diff;
1716
1717                 gettimeofday(&end, NULL);
1718
1719                 diff = difftime(&end, &start);
1720
1721                 --i;
1722                 if (verbose != 0)
1723                         printf("%s: %jd attrs in %.3fs (%.3f attr/s): %s",
1724                                jt_cmdname(argv[0]), (uintmax_t)i, diff,
1725                                i / diff, ctime(&end.tv_sec));
1726         }
1727         return rc;
1728 }
1729
1730 int jt_obd_destroy(int argc, char **argv)
1731 {
1732         struct obd_ioctl_data data;
1733         struct timeval next_time;
1734         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1735         __u64 count = 1, next_count;
1736         int verbose = 1;
1737         __u64 id;
1738         char *end;
1739         int rc = 0, i;
1740
1741         memset(&data, 0, sizeof(data));
1742         data.ioc_dev = cur_device;
1743         if (argc < 2 || argc > 4)
1744                 return CMD_HELP;
1745
1746         errno = 0;
1747         id = strtoull(argv[1], &end, 0);
1748         if (*end || id == 0 || errno != 0) {
1749                 fprintf(stderr, "error: %s: invalid objid '%s'\n",
1750                         jt_cmdname(argv[0]), argv[1]);
1751                 return CMD_HELP;
1752         }
1753         if (argc > 2) {
1754                 count = strtoull(argv[2], &end, 0);
1755                 if (*end) {
1756                         fprintf(stderr,
1757                                 "error: %s: invalid iteration count '%s'\n",
1758                                 jt_cmdname(argv[0]), argv[2]);
1759                         return CMD_HELP;
1760                 }
1761         }
1762
1763         if (argc > 3) {
1764                 verbose = get_verbose(argv[0], argv[3]);
1765                 if (verbose == BAD_VERBOSE)
1766                         return CMD_HELP;
1767         }
1768
1769         printf("%s: %jd objects\n", jt_cmdname(argv[0]), (uintmax_t)count);
1770         gettimeofday(&next_time, NULL);
1771         next_time.tv_sec -= verbose;
1772
1773         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1774         for (i = 1, next_count = verbose; i <= count && shmem_running();
1775              i++, id++) {
1776                 if (id >= OBIF_MAX_OID) {
1777                         fprintf(stderr, "errr: %s: invalid objid '%llu'\n",
1778                                 jt_cmdname(argv[0]), (unsigned long long)id);
1779                         return -E2BIG;
1780                 }
1781
1782                 data.ioc_obdo1.o_oi.oi_fid.f_oid = id;
1783                 data.ioc_obdo1.o_mode = S_IFREG | 0644;
1784                 data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLMODE;
1785
1786                 memset(buf, 0, sizeof(rawbuf));
1787                 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1788                 if (rc) {
1789                         fprintf(stderr, "error: %s: invalid ioctl\n",
1790                                 jt_cmdname(argv[0]));
1791                         return rc;
1792                 }
1793                 rc = l_ioctl(OBD_DEV_ID, OBD_IOC_DESTROY, buf);
1794                 llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
1795                 shmem_bump(1);
1796                 if (rc < 0) {
1797                         fprintf(stderr, "error: %s: objid %#jx: %s\n",
1798                                 jt_cmdname(argv[0]), (uintmax_t)id,
1799                                 strerror(rc = errno));
1800                         break;
1801                 }
1802
1803                 if (be_verbose(verbose, &next_time, i, &next_count, count))
1804                         printf("%s: #%d is object id %#jx\n",
1805                                jt_cmdname(argv[0]), i, (uintmax_t)id);
1806         }
1807
1808         return rc;
1809 }
1810
1811 int jt_obd_getattr(int argc, char **argv)
1812 {
1813         struct obd_ioctl_data data;
1814         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1815         __u64 objid;
1816         char *end;
1817         int rc;
1818
1819         if (argc != 2)
1820                 return CMD_HELP;
1821
1822         objid = strtoull(argv[1], &end, 0);
1823         if (*end) {
1824                 fprintf(stderr, "error: %s: objid '%s' is not a number\n",
1825                         jt_cmdname(argv[0]), argv[1]);
1826                 return CMD_HELP;
1827         }
1828
1829         if (objid >= OBIF_MAX_OID) {
1830                 fprintf(stderr, "error: %s: invalid objid '%s'\n",
1831                         jt_cmdname(argv[0]), argv[1]);
1832                 return CMD_HELP;
1833         }
1834
1835         memset(&data, 0, sizeof(data));
1836         data.ioc_dev = cur_device;
1837         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1838         data.ioc_obdo1.o_oi.oi_fid.f_oid = objid;
1839         /* to help obd filter */
1840         data.ioc_obdo1.o_mode = 0100644;
1841         data.ioc_obdo1.o_valid = 0xffffffff;
1842         printf("%s: object id %#jx\n", jt_cmdname(argv[0]),
1843                (uintmax_t)ostid_id(&data.ioc_obdo1.o_oi));
1844
1845         memset(buf, 0, sizeof(rawbuf));
1846         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1847         if (rc) {
1848                 fprintf(stderr, "error: %s: invalid ioctl\n",
1849                         jt_cmdname(argv[0]));
1850                 return rc;
1851         }
1852         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_GETATTR, buf);
1853         llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
1854         if (rc) {
1855                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
1856                         strerror(rc = errno));
1857         } else {
1858                 printf("%s: object id %ju, mode %o\n", jt_cmdname(argv[0]),
1859                        (uintmax_t)ostid_id(&data.ioc_obdo1.o_oi),
1860                        data.ioc_obdo1.o_mode);
1861         }
1862         return rc;
1863 }
1864
1865 int jt_obd_test_getattr(int argc, char **argv)
1866 {
1867         struct obd_ioctl_data data;
1868         struct timeval start, next_time;
1869         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1870         __u64 i, count, next_count;
1871         int verbose = 1;
1872         __u64 objid = 3;
1873         char *end;
1874         int rc = 0;
1875
1876         if (argc < 2 || argc > 4)
1877                 return CMD_HELP;
1878
1879         memset(&data, 0, sizeof(data));
1880         data.ioc_dev = cur_device;
1881         count = strtoull(argv[1], &end, 0);
1882         if (*end) {
1883                 fprintf(stderr, "error: %s: invalid iteration count '%s'\n",
1884                         jt_cmdname(argv[0]), argv[1]);
1885                 return CMD_HELP;
1886         }
1887
1888         if (argc >= 3) {
1889                 verbose = get_verbose(argv[0], argv[2]);
1890                 if (verbose == BAD_VERBOSE)
1891                         return CMD_HELP;
1892         }
1893
1894         if (argc >= 4) {
1895                 if (argv[3][0] == 't') {
1896                         objid = strtoull(argv[3] + 1, &end, 0);
1897                         if (thread)
1898                                 objid += thread - 1;
1899                 } else
1900                         objid = strtoull(argv[3], &end, 0);
1901                 if (*end) {
1902                         fprintf(stderr, "error: %s: invalid objid '%s'\n",
1903                                 jt_cmdname(argv[0]), argv[3]);
1904                         return CMD_HELP;
1905                 }
1906         }
1907
1908         gettimeofday(&start, NULL);
1909         next_time.tv_sec = start.tv_sec - verbose;
1910         next_time.tv_usec = start.tv_usec;
1911         if (verbose != 0)
1912                 printf("%s: getting %jd attrs (objid %#jx): %s",
1913                        jt_cmdname(argv[0]), (uintmax_t)count,
1914                        (uintmax_t)objid, ctime(&start.tv_sec));
1915
1916         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1917         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
1918                 if (objid >= OBIF_MAX_OID) {
1919                         fprintf(stderr, "errr: %s: invalid objid '%llu'\n",
1920                                 jt_cmdname(argv[0]), (unsigned long long)objid);
1921                         return -E2BIG;
1922                 }
1923
1924                 data.ioc_obdo1.o_oi.oi_fid.f_oid = objid;
1925                 data.ioc_obdo1.o_mode = S_IFREG;
1926                 data.ioc_obdo1.o_valid = 0xffffffff;
1927                 memset(buf, 0, sizeof(rawbuf));
1928                 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1929                 if (rc) {
1930                         fprintf(stderr, "error: %s: invalid ioctl\n",
1931                                 jt_cmdname(argv[0]));
1932                         return rc;
1933                 }
1934                 rc = l_ioctl(OBD_DEV_ID, OBD_IOC_GETATTR, &data);
1935                 shmem_bump(1);
1936                 if (rc < 0) {
1937                         fprintf(stderr, "error: %s: #%jd - %d:%s\n",
1938                                 jt_cmdname(argv[0]), (uintmax_t)i,
1939                                 errno, strerror(rc = errno));
1940                         break;
1941                 }
1942                 if (be_verbose(verbose, &next_time, i, &next_count, count))
1943                         printf("%s: got attr #%jd\n",
1944                                jt_cmdname(argv[0]), (uintmax_t)i);
1945         }
1946
1947         if (!rc) {
1948                 struct timeval end;
1949                 double diff;
1950
1951                 gettimeofday(&end, NULL);
1952
1953                 diff = difftime(&end, &start);
1954
1955                 --i;
1956                 if (verbose != 0)
1957                         printf("%s: %jd attrs in %.3fs (%.3f attr/s): %s",
1958                                jt_cmdname(argv[0]), (uintmax_t)i, diff,
1959                                i / diff, ctime(&end.tv_sec));
1960         }
1961
1962         return rc;
1963 }
1964
1965 /* test_brw <cnt>                                               count
1966         <r|w[r(repeat)x(noverify)]>                             mode
1967         <q|v|#(print interval)>                                 verbosity
1968         <npages[+offset]>                                       blocksize
1969         <[[<interleave_threads>]t(inc obj by thread#)]obj>      object
1970         [p|g<args>]                                             batch */
1971 int jt_obd_test_brw(int argc, char **argv)
1972 {
1973         struct obd_ioctl_data data;
1974         struct timeval start, next_time;
1975         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1976         __u64 count, next_count, len, stride, thr_offset = 0, objid = 3;
1977         int write = 0, verbose = 1, cmd, i, rc = 0, pages = 1;
1978         int offset_pages = 0;
1979         long n;
1980         int repeat_offset = 0;
1981         unsigned long long ull;
1982         int  nthr_per_obj = 0;
1983         int  verify = 1;
1984         int  obj_idx = 0;
1985         char *end;
1986
1987         if (argc < 2 || argc > 7) {
1988                 fprintf(stderr, "error: %s: bad number of arguments: %d\n",
1989                         jt_cmdname(argv[0]), argc);
1990                 return CMD_HELP;
1991         }
1992
1993         count = strtoull(argv[1], &end, 0);
1994         if (*end) {
1995                 fprintf(stderr, "error: %s: bad iteration count '%s'\n",
1996                         jt_cmdname(argv[0]), argv[1]);
1997                 return CMD_HELP;
1998         }
1999
2000         if (argc >= 3) {
2001                 if (argv[2][0] == 'w' || argv[2][0] == '1')
2002                         write = 1;
2003                 /* else it's a read */
2004
2005                 if (argv[2][0] != 0)
2006                         for (i = 1; argv[2][i] != 0; i++)
2007                                 switch (argv[2][i]) {
2008                                 case 'r':
2009                                         repeat_offset = 1;
2010                                         break;
2011
2012                                 case 'x':
2013                                         verify = 0;
2014                                         break;
2015
2016                                 default:
2017                                         fprintf (stderr, "Can't parse cmd '%s'\n",
2018                                                  argv[2]);
2019                                         return CMD_HELP;
2020                                 }
2021         }
2022
2023         if (argc >= 4) {
2024                 verbose = get_verbose(argv[0], argv[3]);
2025                 if (verbose == BAD_VERBOSE)
2026                         return CMD_HELP;
2027         }
2028
2029         if (argc >= 5) {
2030                 pages = strtoul(argv[4], &end, 0);
2031
2032                 if (*end == '+')
2033                         offset_pages = strtoul(end + 1, &end, 0);
2034
2035                 if (*end != 0 ||
2036                     offset_pages < 0 || offset_pages >= pages) {
2037                         fprintf(stderr, "error: %s: bad npages[+offset] parameter '%s'\n",
2038                                 jt_cmdname(argv[0]), argv[4]);
2039                         return CMD_HELP;
2040                 }
2041         }
2042
2043         if (argc >= 6) {
2044                 if (thread &&
2045                     (n = strtol(argv[5], &end, 0)) > 0 &&
2046                     *end == 't' &&
2047                     (ull = strtoull(end + 1, &end, 0)) > 0 &&
2048                     *end == 0) {
2049                         nthr_per_obj = n;
2050                         objid = ull;
2051                 } else if (thread &&
2052                            argv[5][0] == 't') {
2053                         nthr_per_obj = 1;
2054                         objid = strtoull(argv[5] + 1, &end, 0);
2055                 } else {
2056                         nthr_per_obj = 0;
2057                         objid = strtoull(argv[5], &end, 0);
2058                 }
2059                 if (*end) {
2060                         fprintf(stderr, "error: %s: bad objid '%s'\n",
2061                                 jt_cmdname(argv[0]), argv[5]);
2062                         return CMD_HELP;
2063                 }
2064         }
2065
2066         memset(&data, 0, sizeof(data));
2067         data.ioc_dev = cur_device;
2068
2069         /* communicate the 'type' of brw test and batching to echo_client.
2070          * don't start.  we'd love to refactor this lctl->echo_client
2071          * interface */
2072         data.ioc_pbuf1 = (void *)1;
2073         data.ioc_plen1 = 1;
2074
2075         if (argc >= 7) {
2076                 switch(argv[6][0]) {
2077                         case 'g': /* plug and unplug */
2078                                 data.ioc_pbuf1 = (void *)2;
2079                                 data.ioc_plen1 = strtoull(argv[6] + 1, &end,
2080                                                           0);
2081                                 break;
2082                         case 'p': /* prep and commit */
2083                                 data.ioc_pbuf1 = (void *)3;
2084                                 data.ioc_plen1 = strtoull(argv[6] + 1, &end,
2085                                                           0);
2086                                 break;
2087                         default:
2088                                 fprintf(stderr, "error: %s: batching '%s' "
2089                                         "needs to specify 'p' or 'g'\n",
2090                                         jt_cmdname(argv[0]), argv[6]);
2091                                 return CMD_HELP;
2092                 }
2093
2094                 if (*end) {
2095                         fprintf(stderr, "error: %s: bad batching '%s'\n",
2096                                 jt_cmdname(argv[0]), argv[6]);
2097                         return CMD_HELP;
2098                 }
2099                 data.ioc_plen1 *= getpagesize();
2100         }
2101
2102         len = pages * getpagesize();
2103         thr_offset = offset_pages * getpagesize();
2104         stride = len;
2105
2106 #ifdef MAX_THREADS
2107         if (thread) {
2108                 shmem_lock ();
2109                 if (nthr_per_obj != 0) {
2110                         /* threads interleave */
2111                         obj_idx = (thread - 1)/nthr_per_obj;
2112                         objid += obj_idx;
2113                         stride *= nthr_per_obj;
2114                         if ((thread - 1) % nthr_per_obj == 0) {
2115                                 shared_data->body.offsets[obj_idx] =
2116                                         stride + thr_offset;
2117                         }
2118                         thr_offset += ((thread - 1) % nthr_per_obj) * len;
2119                 } else {
2120                         /* threads disjoint */
2121                         thr_offset += (thread - 1) * len;
2122                 }
2123
2124                 shmem_start_time_locked();
2125                 shmem_unlock ();
2126         }
2127 #endif
2128
2129         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
2130         if (objid >= OBIF_MAX_OID) {
2131                 fprintf(stderr, "errr: %s: invalid objid '%llu'\n",
2132                         jt_cmdname(argv[0]), (unsigned long long)objid);
2133                 return -E2BIG;
2134         }
2135
2136         data.ioc_obdo1.o_oi.oi_fid.f_oid = objid;
2137         data.ioc_obdo1.o_mode = S_IFREG;
2138         data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE |
2139                                  OBD_MD_FLFLAGS | OBD_MD_FLGROUP;
2140         data.ioc_obdo1.o_flags = (verify ? OBD_FL_DEBUG_CHECK : 0);
2141         data.ioc_count = len;
2142         data.ioc_offset = (repeat_offset ? 0 : thr_offset);
2143
2144         gettimeofday(&start, NULL);
2145         next_time.tv_sec = start.tv_sec - verbose;
2146         next_time.tv_usec = start.tv_usec;
2147
2148         if (verbose != 0)
2149                 printf("%s: %s %jux%d pages (obj %#jx, off %ju): %s",
2150                        jt_cmdname(argv[0]), write ? "writing" : "reading",
2151                        (uintmax_t)count, pages, (uintmax_t) objid,
2152                        (uintmax_t)data.ioc_offset, ctime(&start.tv_sec));
2153
2154         cmd = write ? OBD_IOC_BRW_WRITE : OBD_IOC_BRW_READ;
2155         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
2156                 data.ioc_obdo1.o_valid &= ~(OBD_MD_FLBLOCKS|OBD_MD_FLGRANT);
2157                 memset(buf, 0, sizeof(rawbuf));
2158                 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2159                 if (rc) {
2160                         fprintf(stderr, "error: %s: invalid ioctl\n",
2161                                 jt_cmdname(argv[0]));
2162                         return rc;
2163                 }
2164                 rc = l_ioctl(OBD_DEV_ID, cmd, buf);
2165                 shmem_bump(1);
2166                 if (rc) {
2167                         fprintf(stderr, "error: %s: #%d - %s on %s\n",
2168                                 jt_cmdname(argv[0]), i, strerror(rc = errno),
2169                                 write ? "write" : "read");
2170                         break;
2171                 } else if (be_verbose(verbose, &next_time, i,
2172                                       &next_count, count)) {
2173                         shmem_lock ();
2174                         printf("%s: %s number %d @ %jd:%ju for %d\n",
2175                                jt_cmdname(argv[0]), write ? "write" : "read", i,
2176                                (uintmax_t)ostid_id(&data.ioc_obdo1.o_oi),
2177                                (uintmax_t)data.ioc_offset,
2178                                (int)(pages * getpagesize()));
2179                         shmem_unlock ();
2180                 }
2181
2182                 if (!repeat_offset) {
2183 #ifdef MAX_THREADS
2184                         if (stride == len) {
2185                                 data.ioc_offset += stride;
2186                         } else if (i < count) {
2187                                 shmem_lock ();
2188                                 data.ioc_offset =
2189                                         shared_data->body.offsets[obj_idx];
2190                                 shared_data->body.offsets[obj_idx] += len;
2191                                 shmem_unlock ();
2192                         }
2193 #else
2194                         data.ioc_offset += len;
2195                         obj_idx = 0; /* avoids an unused var warning */
2196 #endif
2197                 }
2198         }
2199
2200         if (!rc) {
2201                 struct timeval end;
2202                 double diff;
2203
2204                 gettimeofday(&end, NULL);
2205
2206                 diff = difftime(&end, &start);
2207
2208                 --i;
2209                 if (verbose != 0)
2210                         printf("%s: %s %dx%d pages in %.3fs (%.3f MB/s): %s",
2211                                jt_cmdname(argv[0]), write ? "wrote" : "read",
2212                                i, pages, diff,
2213                                ((double)i * pages * getpagesize()) /
2214                                (diff * 1048576.0),
2215                                ctime(&end.tv_sec));
2216         }
2217
2218 #ifdef MAX_THREADS
2219         if (thread) {
2220                 shmem_lock();
2221                 shmem_end_time_locked();
2222                 shmem_unlock();
2223         }
2224 #endif
2225         return rc;
2226 }
2227
2228 int jt_obd_lov_getconfig(int argc, char **argv)
2229 {
2230         struct obd_ioctl_data data;
2231         struct lov_desc desc;
2232         struct obd_uuid *uuidarray;
2233         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2234         __u32 *obdgens;
2235         char *path;
2236         int rc, fd;
2237
2238         memset(&data, 0, sizeof(data));
2239         data.ioc_dev = cur_device;
2240
2241         if (argc != 2)
2242                 return CMD_HELP;
2243
2244         path = argv[1];
2245         fd = open(path, O_RDONLY);
2246         if (fd < 0) {
2247                 fprintf(stderr, "open \"%s\" failed: %s\n", path,
2248                         strerror(errno));
2249                 return -errno;
2250         }
2251
2252         memset(&desc, 0, sizeof(desc));
2253         obd_str2uuid(&desc.ld_uuid, argv[1]);
2254         desc.ld_tgt_count = ((MAX_IOC_BUFLEN-sizeof(data)-sizeof(desc)) /
2255                              (sizeof(*uuidarray) + sizeof(*obdgens)));
2256
2257 repeat:
2258         uuidarray = calloc(desc.ld_tgt_count, sizeof(*uuidarray));
2259         if (!uuidarray) {
2260                 fprintf(stderr, "error: %s: no memory for %d uuid's\n",
2261                         jt_cmdname(argv[0]), desc.ld_tgt_count);
2262                 rc = -ENOMEM;
2263                 goto out;
2264         }
2265         obdgens = calloc(desc.ld_tgt_count, sizeof(*obdgens));
2266         if (!obdgens) {
2267                 fprintf(stderr, "error: %s: no memory for %d generation #'s\n",
2268                         jt_cmdname(argv[0]), desc.ld_tgt_count);
2269                 rc = -ENOMEM;
2270                 goto out_uuidarray;
2271         }
2272
2273         memset(buf, 0, sizeof(rawbuf));
2274         data.ioc_inllen1 = sizeof(desc);
2275         data.ioc_inlbuf1 = (char *)&desc;
2276         data.ioc_inllen2 = desc.ld_tgt_count * sizeof(*uuidarray);
2277         data.ioc_inlbuf2 = (char *)uuidarray;
2278         data.ioc_inllen3 = desc.ld_tgt_count * sizeof(*obdgens);
2279         data.ioc_inlbuf3 = (char *)obdgens;
2280
2281         if (llapi_ioctl_pack(&data, &buf, sizeof(rawbuf))) {
2282                 fprintf(stderr, "error: %s: invalid ioctl\n",
2283                         jt_cmdname(argv[0]));
2284                 rc = -EINVAL;
2285                 goto out_obdgens;
2286         }
2287         rc = ioctl(fd, OBD_IOC_LOV_GET_CONFIG, buf);
2288         if (rc == -ENOSPC) {
2289                 free(uuidarray);
2290                 free(obdgens);
2291                 goto repeat;
2292         } else if (rc) {
2293                 fprintf(stderr, "error: %s: ioctl error: %s\n",
2294                         jt_cmdname(argv[0]), strerror(rc = errno));
2295         } else {
2296                 struct obd_uuid *uuidp;
2297                 __u32 *genp;
2298                 int i;
2299
2300                 if (llapi_ioctl_unpack(&data, buf, sizeof(rawbuf))) {
2301                         fprintf(stderr, "error: %s: invalid reply\n",
2302                                 jt_cmdname(argv[0]));
2303                         rc = -EINVAL;
2304                         goto out;
2305                 }
2306                 if (desc.ld_default_stripe_count == (__u32)-1)
2307                         printf("default_stripe_count: %d\n", -1);
2308                 else
2309                         printf("default_stripe_count: %u\n",
2310                                desc.ld_default_stripe_count);
2311                 printf("default_stripe_size: %ju\n",
2312                        (uintmax_t)desc.ld_default_stripe_size);
2313                 printf("default_stripe_offset: %jd\n",
2314                        (uintmax_t)desc.ld_default_stripe_offset);
2315                 printf("default_stripe_pattern: %u\n", desc.ld_pattern);
2316                 printf("obd_count: %u\n", desc.ld_tgt_count);
2317                 printf("OBDS:\tobdidx\t\tobdgen\t\t obduuid\n");
2318                 uuidp = uuidarray;
2319                 genp = obdgens;
2320                 for (i = 0; i < desc.ld_tgt_count; i++, uuidp++, genp++)
2321                         printf("\t%6u\t%14u\t\t %s\n", i, *genp, (char *)uuidp);
2322         }
2323 out_obdgens:
2324         free(obdgens);
2325 out_uuidarray:
2326         free(uuidarray);
2327 out:
2328         close(fd);
2329         return rc;
2330 }
2331
2332 static int do_activate(int argc, char **argv, int flag)
2333 {
2334         struct obd_ioctl_data data;
2335         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2336         int rc;
2337
2338         memset(&data, 0, sizeof(data));
2339         data.ioc_dev = cur_device;
2340         if (argc != 1)
2341                 return CMD_HELP;
2342
2343         /* reuse offset for 'active' */
2344         data.ioc_offset = flag;
2345
2346         memset(buf, 0, sizeof(rawbuf));
2347         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2348         if (rc) {
2349                 fprintf(stderr, "error: %s: invalid ioctl\n",
2350                         jt_cmdname(argv[0]));
2351                 return rc;
2352         }
2353         rc = l_ioctl(OBD_DEV_ID, IOC_OSC_SET_ACTIVE, buf);
2354         if (rc)
2355                 fprintf(stderr, "error: %s: failed: %s\n",
2356                         jt_cmdname(argv[0]), strerror(rc = errno));
2357
2358         return rc;
2359 }
2360
2361 /**
2362  * Replace nids for given device.
2363  * lctl replace_nids <devicename> <nid1>[,nid2,nid3]
2364  * Command should be started on MGS server.
2365  * Only MGS server should be started (command execution
2366  * returns error in another cases). Command mount
2367  * -t lustre <MDT partition> -o nosvc <mount point>
2368  * can be used for that.
2369  *
2370  * llogs for MDTs and clients are processed. All
2371  * records copied as is except add_uuid and setup. This records
2372  * are skipped and recorded with new nids and uuid.
2373  *
2374  * \see mgs_replace_nids
2375  * \see mgs_replace_log
2376  * \see mgs_replace_nids_handler
2377  */
2378 int jt_replace_nids(int argc, char **argv)
2379 {
2380         int rc;
2381         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2382         struct obd_ioctl_data data;
2383
2384         memset(&data, 0, sizeof(data));
2385         data.ioc_dev = get_mgs_device();
2386         if (argc != 3)
2387                 return CMD_HELP;
2388
2389         data.ioc_inllen1 = strlen(argv[1]) + 1;
2390         data.ioc_inlbuf1 = argv[1];
2391
2392         data.ioc_inllen2 = strlen(argv[2]) + 1;
2393         data.ioc_inlbuf2 = argv[2];
2394         memset(buf, 0, sizeof(rawbuf));
2395         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2396         if (rc) {
2397                 fprintf(stderr, "error: %s: invalid ioctl\n",
2398                         jt_cmdname(argv[0]));
2399                 return rc;
2400         }
2401
2402         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_REPLACE_NIDS, buf);
2403         if (rc < 0) {
2404                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
2405                         strerror(rc = errno));
2406         }
2407
2408         return rc;
2409 }
2410
2411 /**
2412  * Clear config logs for given device or filesystem.
2413  * lctl clear_conf <devicename|fsname>
2414  * Command has to be run on MGS node having MGS device mounted with -o
2415  * nosvc.
2416  *
2417  * Configuration logs for filesystem or one particular log is
2418  * processed. New log is created, original log is read, its records
2419  * marked SKIP do not get copied to new log. Others are copied as-is.
2420  * Original file is renamed to log.${time}.bak.
2421  *
2422  * \see mgs_clear_configs
2423  * \see mgs_replace_log
2424  * \see mgs_clear_config_handler
2425  **/
2426 int jt_lcfg_clear(int argc, char **argv)
2427 {
2428         int rc;
2429         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2430         struct obd_ioctl_data data;
2431
2432         memset(&data, 0, sizeof(data));
2433         data.ioc_dev = get_mgs_device();
2434         if (argc != 2)
2435                 return CMD_HELP;
2436
2437         data.ioc_inllen1 = strlen(argv[1]) + 1;
2438         data.ioc_inlbuf1 = argv[1];
2439
2440         memset(buf, 0, sizeof(rawbuf));
2441         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2442         if (rc) {
2443                 fprintf(stderr, "error: %s: invalid ioctl\n",
2444                         jt_cmdname(argv[0]));
2445                 return rc;
2446         }
2447
2448         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_CLEAR_CONFIGS, buf);
2449         if (rc < 0) {
2450                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
2451                         strerror(rc = errno));
2452         }
2453
2454         return rc;
2455 }
2456
2457 int jt_obd_deactivate(int argc, char **argv)
2458 {
2459         return do_activate(argc, argv, 0);
2460 }
2461
2462 int jt_obd_activate(int argc, char **argv)
2463 {
2464         return do_activate(argc, argv, 1);
2465 }
2466
2467 int jt_obd_recover(int argc, char **argv)
2468 {
2469         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2470         struct obd_ioctl_data data;
2471         int rc;
2472
2473         memset(&data, 0, sizeof(data));
2474         data.ioc_dev = cur_device;
2475         if (argc > 2)
2476                 return CMD_HELP;
2477
2478         if (argc == 2) {
2479                 data.ioc_inllen1 = strlen(argv[1]) + 1;
2480                 data.ioc_inlbuf1 = argv[1];
2481         }
2482
2483         memset(buf, 0, sizeof(rawbuf));
2484         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2485         if (rc) {
2486                 fprintf(stderr, "error: %s: invalid ioctl\n",
2487                         jt_cmdname(argv[0]));
2488                 return rc;
2489         }
2490         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_CLIENT_RECOVER, buf);
2491         if (rc < 0) {
2492                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
2493                         strerror(rc = errno));
2494         }
2495
2496         return rc;
2497 }
2498
2499 int jt_obd_mdc_lookup(int argc, char **argv)
2500 {
2501         struct obd_ioctl_data data;
2502         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2503         char *parent, *child;
2504         int rc, fd, verbose = 1;
2505
2506         if (argc < 3 || argc > 4)
2507                 return CMD_HELP;
2508
2509         parent = argv[1];
2510         child = argv[2];
2511         if (argc == 4)
2512                 verbose = get_verbose(argv[0], argv[3]);
2513
2514         memset(&data, 0, sizeof(data));
2515         data.ioc_dev = cur_device;
2516
2517         data.ioc_inllen1 = strlen(child) + 1;
2518         data.ioc_inlbuf1 = child;
2519
2520         memset(buf, 0, sizeof(rawbuf));
2521         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2522         if (rc) {
2523                 fprintf(stderr, "error: %s: invalid ioctl\n",
2524                         jt_cmdname(argv[0]));
2525                 return rc;
2526         }
2527
2528         fd = open(parent, O_RDONLY);
2529         if (fd < 0) {
2530                 fprintf(stderr, "open \"%s\" failed: %s\n", parent,
2531                         strerror(errno));
2532                 return -1;
2533         }
2534
2535         rc = ioctl(fd, IOC_MDC_LOOKUP, buf);
2536         if (rc < 0) {
2537                 fprintf(stderr, "error: %s: ioctl error: %s\n",
2538                         jt_cmdname(argv[0]), strerror(rc = errno));
2539         }
2540         close(fd);
2541
2542         if (verbose) {
2543                 rc = llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
2544                 if (rc) {
2545                         fprintf(stderr, "error: %s: invalid reply\n",
2546                                 jt_cmdname(argv[0]));
2547                         return rc;
2548                 }
2549                 printf("%s: mode %o uid %d gid %d\n", child,
2550                        data.ioc_obdo1.o_mode, data.ioc_obdo1.o_uid,
2551                        data.ioc_obdo1.o_gid);
2552         }
2553
2554         return rc;
2555 }
2556
2557 int jt_lcfg_fork(int argc, char **argv)
2558 {
2559         struct obd_ioctl_data data;
2560         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2561         int rc;
2562
2563         if (argc != 3)
2564                 return CMD_HELP;
2565
2566         memset(&data, 0, sizeof(data));
2567         data.ioc_dev = get_mgs_device();
2568         data.ioc_inllen1 = strlen(argv[1]) + 1;
2569         data.ioc_inlbuf1 = argv[1];
2570         data.ioc_inllen2 = strlen(argv[2]) + 1;
2571         data.ioc_inlbuf2 = argv[2];
2572
2573         memset(buf, 0, sizeof(rawbuf));
2574         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2575         if (rc) {
2576                 fprintf(stderr, "error: %s: invalid ioctl\n",
2577                         jt_cmdname(argv[0]));
2578                 return rc;
2579         }
2580
2581         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LCFG_FORK, buf);
2582         if (rc < 0)
2583                 fprintf(stderr, "error: %s: OBD_IOC_LCFG_FORK failed: %s\n",
2584                         jt_cmdname(argv[0]), strerror(errno));
2585
2586         return rc;
2587 }
2588
2589 int jt_lcfg_erase(int argc, char **argv)
2590 {
2591         struct obd_ioctl_data data;
2592         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2593         int rc;
2594
2595         if (argc == 3) {
2596                 if (strncmp(argv[2], "-q", strlen("-q")) != 0 &&
2597                     strncmp(argv[2], "--quiet", strlen("--quiet")) != 0)
2598                         return CMD_HELP;
2599         } else if (argc != 2) {
2600                 return CMD_HELP;
2601         }
2602
2603         memset(&data, 0, sizeof(data));
2604         data.ioc_dev = get_mgs_device();
2605         data.ioc_inllen1 = strlen(argv[1]) + 1;
2606         data.ioc_inlbuf1 = argv[1];
2607
2608         memset(buf, 0, sizeof(rawbuf));
2609         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2610         if (rc) {
2611                 fprintf(stderr, "error: %s: invalid ioctl\n",
2612                         jt_cmdname(argv[0]));
2613                 return rc;
2614         }
2615
2616         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LCFG_ERASE, buf);
2617         if (rc < 0)
2618                 fprintf(stderr, "error: %s: OBD_IOC_LCFG_ERASE failed: %s\n",
2619                         jt_cmdname(argv[0]), strerror(errno));
2620
2621         return rc;
2622 }
2623
2624 int jt_llog_catlist(int argc, char **argv)
2625 {
2626         struct obd_ioctl_data data;
2627         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2628         int rc;
2629
2630         if (argc != 1)
2631                 return CMD_HELP;
2632
2633         memset(&data, 0, sizeof(data));
2634         data.ioc_dev = cur_device;
2635         data.ioc_inllen1 = sizeof(rawbuf) - __ALIGN_KERNEL(sizeof(data), 8);
2636         memset(buf, 0, sizeof(rawbuf));
2637         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2638         if (rc) {
2639                 fprintf(stderr, "error: %s: invalid ioctl\n",
2640                         jt_cmdname(argv[0]));
2641                 return rc;
2642         }
2643         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_CATLOGLIST, buf);
2644         if (rc == 0)
2645                 fprintf(stdout, "%s", ((struct obd_ioctl_data *)buf)->ioc_bulk);
2646         else
2647                 fprintf(stderr, "OBD_IOC_CATLOGLIST failed: %s\n",
2648                         strerror(errno));
2649
2650         return rc;
2651 }
2652
2653 int jt_llog_info(int argc, char **argv)
2654 {
2655         const struct option long_opts[] = {
2656         /* Allow optional "--catalog" for compatibility with llog commands. */
2657         { .val = 'c',   .name = "catalog",      .has_arg = required_argument },
2658         { .val = 'h',   .name = "help",         .has_arg = no_argument },
2659         { .name = NULL } };
2660         struct obd_ioctl_data data = { 0 };
2661         char rawbuf[MAX_IOC_BUFLEN] = "", *buf = rawbuf;
2662         char *cmd = argv[0];
2663         char *catalog = NULL;
2664         int rc, c;
2665
2666         while ((c = getopt_long(argc, argv, "c:h", long_opts, NULL)) != -1) {
2667                 switch (c) {
2668                 case 'c':
2669                         catalog = optarg;
2670                         break;
2671                 case 'h':
2672                 default:
2673                         return CMD_HELP;
2674                 }
2675         }
2676         argc -= optind;
2677         argv += optind;
2678         /* support "logname" positional parameter */
2679         if (argc == 1) {
2680                 if (catalog) {
2681                         fprintf(stderr,
2682                                 "%s: catalog is set, unknown argument '%s'\n",
2683                                 cmd, optarg);
2684                         return CMD_HELP;
2685                 }
2686                 catalog = argv[0];
2687         } else if (!catalog || argc > 1) {
2688                 return CMD_HELP;
2689         }
2690
2691         data.ioc_dev = cur_device;
2692         data.ioc_inllen1 = strlen(catalog) + 1;
2693         data.ioc_inlbuf1 = catalog;
2694         data.ioc_inllen2 = sizeof(rawbuf) - __ALIGN_KERNEL(sizeof(data), 8) -
2695                            __ALIGN_KERNEL(data.ioc_inllen1, 8);
2696         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2697         if (rc) {
2698                 fprintf(stderr, "%s: ioctl_pack failed for catalog '%s': %s\n",
2699                         jt_cmdname(cmd), catalog, strerror(-rc));
2700                 return rc;
2701         }
2702
2703         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_INFO, buf);
2704         if (rc == 0)
2705                 fprintf(stdout, "%s", ((struct obd_ioctl_data *)buf)->ioc_bulk);
2706         else
2707                 fprintf(stderr, "%s: OBD_IOC_LLOG_INFO failed: %s\n",
2708                         jt_cmdname(cmd), strerror(errno));
2709
2710         return rc;
2711 }
2712
2713 int jt_llog_print_cb(const char *record, void *private)
2714 {
2715         printf("%s\n", record);
2716
2717         return 0;
2718 }
2719
2720 static int
2721 llog_process_records(int (record_cb)(const char *record, void *private),
2722                      const char *record, void *private, bool reverse)
2723 {
2724         char *ptr = NULL;
2725         char *tmp = NULL;
2726         int rc = 0;
2727
2728         if (!reverse) {
2729                 do {
2730                         ptr = strchr(record, '\n');
2731                         if (ptr)
2732                                 *ptr = '\0';
2733                         rc = record_cb(record, private);
2734                         if (rc)
2735                                 goto out;
2736                         if (ptr)
2737                                 record = ptr + 1;
2738                 } while (ptr && *(ptr + 1));
2739         } else {
2740                 tmp = (char *)record;
2741
2742                 ptr = strrchr(record, '\n');
2743                 if (ptr)
2744                         *ptr = '\0';
2745                 else
2746                         goto out;
2747                 while ((ptr = strrchr(record, '\n'))) {
2748                         tmp = ptr + 1;
2749                         *ptr = '\0';
2750                         rc = record_cb(tmp, private);
2751                         if (rc)
2752                                 goto out;
2753                 };
2754                 rc = record_cb(record, private);
2755                 if (rc)
2756                         goto out;
2757         }
2758 out:
2759         return rc;
2760 }
2761
2762 /**
2763  * Iterate over llog records, typically YAML-formatted configuration logs
2764  *
2765  * \param logname[in]   name of llog file or FID
2766  * \param start[in]     first record to process
2767  * \param end[in]       last record to process (inclusive)
2768  * \param cb[in]        callback for records. Return -ve error, or +ve abort.
2769  * \param private[in,out] private data passed to the \a record_cb function
2770  * \param reverse[in]   print the llog records from the beginning or the end
2771  *
2772  * \retval              0 on success
2773  *                      others handled by the caller
2774  */
2775 int jt_llog_print_iter(char *logname, long start, long end,
2776                        int (record_cb)(const char *record, void *private),
2777                        void *private, bool reverse)
2778 {
2779         struct obd_ioctl_data data = { 0 };
2780         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2781         char startbuf[16], endbuf[16];
2782         static long inc = sizeof(rawbuf) / 128;
2783         long rec;
2784         int rc = 0;
2785
2786         if (end == -1)
2787                 end = 0x7fffffff;
2788
2789         data.ioc_dev = cur_device;
2790         data.ioc_inlbuf1 = logname;
2791         data.ioc_inllen1 = strlen(logname) + 1;
2792
2793         /*
2794          * Estimate about 128 characters per configuration record.  Not all
2795          * records will be printed in any case, so they should easily fit.  If
2796          * not, the kernel will return -EOVERFLOW and ask for fewer records.
2797          *
2798          * We don't want to request records from the kernel one-at-a-time, as
2799          * it restarts the config llog iteration from the beginning, so we
2800          * fetch multiple records from the kernel per call and split locally.
2801          */
2802         for (rec = start; rec < end; rec += inc) {
2803                 char *record = ((struct obd_ioctl_data *)buf)->ioc_bulk;
2804
2805 retry:
2806                 snprintf(startbuf, sizeof(startbuf), "%lu", rec);
2807                 snprintf(endbuf, sizeof(endbuf), "%lu",
2808                          end < rec + inc - 1 ? end : rec + inc - 1);
2809
2810                 /* start and end record numbers are passed as ASCII digits */
2811                 data.ioc_inlbuf2 = startbuf;
2812                 data.ioc_inllen2 = strlen(startbuf) + 1;
2813                 data.ioc_inlbuf3 = endbuf;
2814                 data.ioc_inllen3 = strlen(endbuf) + 1;
2815
2816                 data.ioc_inllen4 = sizeof(rawbuf) -
2817                         __ALIGN_KERNEL(sizeof(data), 8) -
2818                         __ALIGN_KERNEL(data.ioc_inllen1, 8) -
2819                         __ALIGN_KERNEL(data.ioc_inllen2, 8) -
2820                         __ALIGN_KERNEL(data.ioc_inllen3, 8);
2821                 memset(buf, 0, sizeof(rawbuf));
2822                 rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
2823                 if (rc) {
2824                         fprintf(stderr, "%s: invalid ioctl data\n", logname);
2825                         goto out;
2826                 }
2827
2828                 rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_PRINT, buf);
2829                 if (rc == -EOVERFLOW && inc > 2) {
2830                         inc /= 2;
2831                         goto retry;
2832                 }
2833                 if (rc) {
2834                         fprintf(stderr, "%s: OBD_IOC_LLOG_PRINT failed: %s\n",
2835                                 logname, strerror(errno));
2836                         rc = -errno;
2837                         goto out;
2838                 }
2839
2840                 /* There is no "end of list" marker, record was not modified */
2841                 if (strcmp(record, logname) == 0)
2842                         break;
2843
2844                 rc = llog_process_records(record_cb, record, private, reverse);
2845                 if (rc)
2846                         goto out;
2847         }
2848
2849 out:
2850         return rc;
2851 }
2852
2853 static int llog_parse_catalog_start_end(int *argc, char **argv[],
2854                                         char **catalog, long *start, long *end)
2855 {
2856         const struct option long_opts[] = {
2857         /* the --catalog option is not required, just for consistency */
2858         { .val = 'c',   .name = "catalog",      .has_arg = required_argument },
2859         { .val = 'e',   .name = "end",          .has_arg = required_argument },
2860         { .val = 'h',   .name = "help",         .has_arg = no_argument },
2861         { .val = 's',   .name = "start",        .has_arg = required_argument },
2862         { .name = NULL } };
2863         char *cmd = (*argv)[0];
2864         char *endp;
2865         int c;
2866
2867         if (catalog == NULL || start == NULL || end == NULL)
2868                 return -EINVAL;
2869
2870         /* now process command line arguments*/
2871         while ((c = getopt_long(*argc, *argv, "c:e:hs:",
2872                                 long_opts, NULL)) != -1) {
2873                 switch (c) {
2874                 case 'c':
2875                         *catalog = optarg;
2876                         break;
2877                 case 'e':
2878                         *end = strtol(optarg, &endp, 0);
2879                         if (*endp != '\0') {
2880                                 fprintf(stderr, "%s: bad end value '%s'\n",
2881                                         cmd, optarg);
2882                                 return CMD_HELP;
2883                         }
2884                         break;
2885                 case 's':
2886                         *start = strtol(optarg, &endp, 0);
2887                         if (*endp != '\0') {
2888                                 fprintf(stderr, "%s: bad start value '%s'\n",
2889                                         cmd, optarg);
2890                                 return CMD_HELP;
2891                         }
2892                         break;
2893                 case 'h':
2894                 default:
2895                         return CMD_HELP;
2896                 }
2897         }
2898         *argc -= optind;
2899         *argv += optind;
2900
2901         /* support old optional positional parameters only if they were
2902          * not already specified with named arguments: logname [start [end]]
2903          */
2904         if (*argc >= 1) {
2905                 if (*catalog) {
2906                         fprintf(stderr,
2907                                 "%s: catalog is set, unknown argument '%s'\n",
2908                                 cmd, (*argv)[0]);
2909                         return CMD_HELP;
2910                 }
2911                 *catalog = (*argv)[0];
2912                 (*argc)--;
2913                 (*argv)++;
2914         }
2915
2916         if (*argc >= 1) {
2917                 if (*start != 1) {
2918                         fprintf(stderr,
2919                                 "%s: --start is set, unknown argument '%s'\n",
2920                                 cmd, (*argv)[0]);
2921                         return CMD_HELP;
2922                 }
2923
2924                 *start = strtol((*argv)[0], &endp, 0);
2925                 if (*endp != '\0') {
2926                         fprintf(stderr, "%s: bad start value '%s'\n",
2927                                 cmd, (*argv)[0]);
2928                         return CMD_HELP;
2929                 }
2930                 (*argc)--;
2931                 (*argv)++;
2932         }
2933         if (*argc >= 1) {
2934                 if (*end != -1) {
2935                         fprintf(stderr,
2936                                 "%s: --end is set, unknown argument '%s'\n",
2937                                 cmd, (*argv)[0]);
2938                         return CMD_HELP;
2939                 }
2940
2941                 *end = strtol((*argv)[0], &endp, 0);
2942                 if (*endp != '\0') {
2943                         fprintf(stderr, "%s: bad end value '%s'\n",
2944                                 cmd, (*argv)[0]);
2945                         return CMD_HELP;
2946                 }
2947                 (*argc)--;
2948                 (*argv)++;
2949         }
2950         if (*argc > 1) {
2951                 fprintf(stderr, "%s: unknown argument '%s'\n", cmd, (*argv)[0]);
2952                 return CMD_HELP;
2953         }
2954
2955         if (*end != -1 && *end < *start) {
2956                 fprintf(stderr, "%s: end '%lu' less than than start '%lu'\n",
2957                         cmd, *end, *start);
2958                 return CMD_HELP;
2959         }
2960
2961         return 0;
2962 }
2963
2964 int jt_llog_print(int argc, char **argv)
2965 {
2966         char *catalog = NULL;
2967         long start = 1, end = -1;
2968         int rc;
2969
2970         rc = llog_parse_catalog_start_end(&argc, &argv, &catalog, &start, &end);
2971         if (rc)
2972                 return rc;
2973
2974         rc = jt_llog_print_iter(catalog, start, end, jt_llog_print_cb,
2975                                 NULL, false);
2976
2977         return rc;
2978 }
2979
2980 /* Parse catalog, log ID, and optionally a log index with either optional
2981  * arguments or positional arguments.  Only the initial catalog argument
2982  * may be positional with other optional arguments.
2983  *
2984  * The positional arguments option should eventually be phased out.
2985  */
2986 static int llog_parse_catalog_log_idx(int *argc, char ***argv, const char *opts,
2987                                       int max_args, struct obd_ioctl_data *data)
2988 {
2989         const struct option long_opts[] = {
2990         /* the --catalog option is not required, just for consistency */
2991         { .val = 'c',   .name = "catalog",      .has_arg = required_argument },
2992         { .val = 'h',   .name = "help",         .has_arg = no_argument },
2993         { .val = 'i',   .name = "log_idx",      .has_arg = required_argument },
2994         { .val = 'l',   .name = "log_id",       .has_arg = required_argument },
2995         { .name = NULL } };
2996         int c;
2997
2998         /* sanity check */
2999         if (!data || *argc <= 1)
3000                 return -1;
3001
3002         data->ioc_dev = cur_device;
3003
3004         /* now process command line arguments*/
3005         while ((c = getopt_long(*argc, *argv, opts, long_opts, NULL)) != -1) {
3006                 switch (c) {
3007                 case 'c':
3008                         data->ioc_inllen1 = strlen(optarg) + 1;
3009                         data->ioc_inlbuf1 = optarg;
3010                         break;
3011                 case 'i':
3012                         data->ioc_inllen3 = strlen(optarg) + 1;
3013                         data->ioc_inlbuf3 = optarg;
3014                         break;
3015                 case 'l': /* The log_id option isn't currently needed for
3016                            * cancel as mdt_iocontrol() handles IOC_LLOG_CANCEL,
3017                            * but we may as well keep it for now.
3018                            */
3019                         data->ioc_inllen2 = strlen(optarg) + 1;
3020                         data->ioc_inlbuf2 = optarg;
3021                         break;
3022                 case 'h':
3023                 default:
3024                         return CMD_HELP;
3025                 }
3026         }
3027
3028         *argc -= optind;
3029         *argv += optind;
3030
3031         /* Allow catalog to be specified as first option without --catalog */
3032         if (data->ioc_inlbuf1 == NULL && *argc > 0) {
3033                 data->ioc_inlbuf1 = (*argv)[0];
3034                 data->ioc_inllen1 = strlen((*argv)[0]) + 1;
3035                 (*argc)--;
3036                 (*argv)++;
3037         }
3038
3039         return 0;
3040 }
3041
3042 int jt_llog_cancel(int argc, char **argv)
3043 {
3044         struct obd_ioctl_data data = { 0 };
3045         char rawbuf[MAX_IOC_BUFLEN] = "", *buf = rawbuf;
3046         char *cmd = argv[0];
3047         int rc;
3048
3049         /* Parse catalog file (in inlbuf1) and named parameters */
3050         rc = llog_parse_catalog_log_idx(&argc, &argv, "c:hi:l:", 3, &data);
3051
3052         /* Handle old positional parameters if not using named parameters,
3053          * either "<catalog> <log_idx>" or "<catalog> <log_id> <log_idx>".
3054          * It was "inlbuf3 = log_idx", and "inlbuf2 = log_id" (ignored by
3055          * config log cancel), and shows why I hate positional parameters.
3056          */
3057         if (argc == 1) {
3058                 data.ioc_inllen3 = strlen(argv[0]) + 1;
3059                 data.ioc_inlbuf3 = argv[0];
3060         } else if (argc == 2) {
3061                 data.ioc_inllen2 = strlen(argv[0]) + 1;
3062                 data.ioc_inlbuf2 = argv[0];
3063                 data.ioc_inllen3 = strlen(argv[1]) + 1;
3064                 data.ioc_inlbuf3 = argv[1];
3065         }
3066
3067         if (data.ioc_inlbuf1 == NULL || data.ioc_inlbuf3 == NULL)
3068                 /* missing mandatory parameters */
3069                 return CMD_HELP;
3070
3071         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
3072         if (rc) {
3073                 fprintf(stderr, "%s: ioctl_pack for catalog '%s' failed: %s\n",
3074                         jt_cmdname(cmd), data.ioc_inlbuf1, strerror(-rc));
3075                 return rc;
3076         }
3077
3078         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_CANCEL, buf);
3079         if (rc)
3080                 fprintf(stderr, "%s: cancel catalog '%s:%s' failed: %s\n",
3081                         jt_cmdname(cmd), data.ioc_inlbuf1, data.ioc_inlbuf3,
3082                         strerror(errno));
3083
3084         return rc;
3085 }
3086
3087 int jt_llog_check(int argc, char **argv)
3088 {
3089         struct obd_ioctl_data data = { 0 };
3090         char rawbuf[MAX_IOC_BUFLEN] = "", *buf = rawbuf;
3091         char *catalog = NULL;
3092         char startbuf[16], endbuf[16];
3093         long start = 1, end = -1;
3094         char *cmd = argv[0];
3095         int rc;
3096
3097         rc = llog_parse_catalog_start_end(&argc, &argv, &catalog, &start, &end);
3098         if (rc)
3099                 return rc;
3100
3101         if (end == -1)
3102                 end = 0x7fffffff;
3103
3104         data.ioc_dev = cur_device;
3105         data.ioc_inllen1 = strlen(catalog) + 1;
3106         data.ioc_inlbuf1 = catalog;
3107
3108         snprintf(startbuf, sizeof(startbuf), "%lu", start);
3109         snprintf(endbuf, sizeof(endbuf), "%lu", end);
3110         /* start and end record numbers are passed as ASCII digits */
3111         data.ioc_inllen2 = strlen(startbuf) + 1;
3112         data.ioc_inlbuf2 = startbuf;
3113         data.ioc_inllen3 = strlen(endbuf) + 1;
3114         data.ioc_inlbuf3 = endbuf;
3115
3116         data.ioc_inllen4 = sizeof(rawbuf) - __ALIGN_KERNEL(sizeof(data), 8) -
3117                            __ALIGN_KERNEL(data.ioc_inllen1, 8) -
3118                            __ALIGN_KERNEL(data.ioc_inllen2, 8) -
3119                            __ALIGN_KERNEL(data.ioc_inllen3, 8);
3120         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
3121         if (rc) {
3122                 fprintf(stderr, "%s: ioctl_pack failed for catalog '%s': %s\n",
3123                         jt_cmdname(cmd), data.ioc_inlbuf1, strerror(-rc));
3124                 return rc;
3125         }
3126
3127         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_CHECK, buf);
3128         if (rc == 0)
3129                 fprintf(stdout, "%s", ((struct obd_ioctl_data *)buf)->ioc_bulk);
3130         else
3131                 fprintf(stderr, "%s: OBD_IOC_LLOG_CHECK failed: %s\n",
3132                         jt_cmdname(cmd), strerror(errno));
3133         return rc;
3134 }
3135
3136 int jt_llog_remove(int argc, char **argv)
3137 {
3138         struct obd_ioctl_data data = { 0 };
3139         char rawbuf[MAX_IOC_BUFLEN] = "", *buf = rawbuf;
3140         char *cmd = argv[0];
3141         int rc;
3142
3143         rc = llog_parse_catalog_log_idx(&argc, &argv, "c:hl:", 2, &data);
3144         if (rc)
3145                 return rc;
3146
3147         if (argc == 1) {
3148                 if (data.ioc_inlbuf2) {
3149                         fprintf(stderr,
3150                                 "%s: --log_id is set, unknown argument '%s'\n",
3151                                 jt_cmdname(cmd), argv[0]);
3152                         return CMD_HELP;
3153                 }
3154
3155                 data.ioc_inllen2 = strlen(argv[0]) + 1;
3156                 data.ioc_inlbuf2 = argv[0];
3157         }
3158         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
3159         if (rc) {
3160                 fprintf(stderr, "%s: ioctl_pack for catalog '%s' failed: %s\n",
3161                         jt_cmdname(cmd), data.ioc_inlbuf1, strerror(-rc));
3162                 return rc;
3163         }
3164
3165         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_REMOVE, buf);
3166         if (rc)
3167                 fprintf(stderr, "%s: cancel catalog '%s:%s' failed: %s\n",
3168                         jt_cmdname(cmd), data.ioc_inlbuf1, data.ioc_inlbuf2,
3169                         strerror(-rc));
3170
3171         return rc;
3172 }
3173
3174 static void signal_server(int sig)
3175 {
3176         if (sig == SIGINT) {
3177                 do_disconnect("sigint", 1);
3178                 exit(1);
3179         } else {
3180                 fprintf(stderr, "%s: got signal %d\n", jt_cmdname("sigint"),
3181                         sig);
3182         }
3183 }
3184
3185 int obd_initialize(int argc, char **argv)
3186 {
3187         if (shmem_setup() != 0)
3188                 return -1;
3189
3190         register_ioc_dev(OBD_DEV_ID, OBD_DEV_PATH);
3191
3192         return 0;
3193 }
3194
3195 void obd_finalize(int argc, char **argv)
3196 {
3197         struct sigaction sigact;
3198
3199         /* sigact initialization */
3200         sigact.sa_handler = signal_server;
3201         sigfillset(&sigact.sa_mask);
3202         sigact.sa_flags = SA_RESTART;
3203         /* coverity[uninit_use_in_call] */
3204         sigaction(SIGINT, &sigact, NULL);
3205
3206         shmem_cleanup();
3207         do_disconnect(argv[0], 1);
3208 }
3209
3210 /**
3211  * Get the index of the last llog record
3212  *
3213  * logid:            [0x3:0xa:0x0]:0
3214  * flags:            4 (plain)
3215  * records_count:    57
3216  * last_index:       57
3217  *
3218  * \param logname[in]   pointer to config log name
3219  *
3220  * \retval              > 0 on success
3221  *                      <= 0 on error
3222  */
3223 static long llog_last_index(char *logname)
3224 {
3225         struct obd_ioctl_data data = { 0 };
3226         char rawbuf[MAX_IOC_BUFLEN] = "", *buf = rawbuf;
3227         char *last_index;
3228         long rc;
3229
3230         data.ioc_dev = cur_device;
3231         data.ioc_inllen1 = strlen(logname) + 1;
3232         data.ioc_inlbuf1 = logname;
3233         data.ioc_inllen2 = sizeof(rawbuf) - __ALIGN_KERNEL(sizeof(data), 8) -
3234                            __ALIGN_KERNEL(data.ioc_inllen1, 8);
3235         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
3236         if (rc) {
3237                 fprintf(stderr, "%s: ioctl_pack failed for catalog '%s': %s\n",
3238                         __func__, logname, strerror(-rc));
3239                 return rc;
3240         }
3241
3242         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_INFO, buf);
3243         if (rc == 0) {
3244                 last_index = strstr(((struct obd_ioctl_data *)buf)->ioc_bulk,
3245                                     "last_index:");
3246                 return strtol(last_index + 11, NULL, 10);
3247         } else {
3248                 rc = -errno;
3249         }
3250
3251         return rc;
3252 }
3253
3254 static char *get_llog_event_name(__u32 cmd)
3255 {
3256         struct lcfg_type_data *data;
3257
3258         data = lcfg_cmd2data(cmd);
3259         if (data)
3260                 return data->ltd_name;
3261         return NULL;
3262 }
3263
3264 static char *get_event_filter(__u32 cmd)
3265 {
3266         char *event_name;
3267         char *filter = NULL;
3268         int len;
3269
3270         event_name = get_llog_event_name(cmd);
3271         if (event_name) {
3272                 /* 9 bytes for "event: , " */
3273                 len = 9 + strlen(event_name);
3274                 filter = malloc(len + 1);
3275                 if (!filter)
3276                         return NULL;
3277                 memset(filter, 0, len + 1);
3278                 snprintf(filter, len, "event: %s, ", event_name);
3279                 return filter;
3280         }
3281
3282         return NULL;
3283 }
3284
3285 /**
3286  * Callback to search ostname in llog
3287  * - { index: 23, event: attach, device: lustre-OST0000-osc, type: osc,
3288  *     UUID: lustre-clilov_UUID }
3289  * - { index: 24, event: setup, device: lustre-OST0000-osc,
3290  *     UUID: lustre-OST0000_UUID, node: 192.168.0.120@tcp }
3291  * - { index: 25, event: add_osc, device: lustre-clilov,
3292  *     ost: lustre-OST0000_UUID, index: 0, gen: 1 }
3293  *
3294  * \param record[in]    pointer to llog record
3295  * \param data[in]      pointer to ostname
3296  *
3297  * \retval              1 if ostname is found
3298  *                      0 if ostname is not found
3299  *                      -ENOENT if ostname is deleted
3300  */
3301 static int llog_search_ost_cb(const char *record, void *data)
3302 {
3303         char *ostname = data;
3304         char ost_filter[MAX_STRING_SIZE] = {'\0'};
3305         char *add_osc, *del_osc, *setup, *cleanup;
3306
3307         add_osc = get_event_filter(LCFG_LOV_ADD_OBD);
3308         del_osc = get_event_filter(LCFG_LOV_DEL_OBD);
3309         setup = get_event_filter(LCFG_SETUP);
3310         cleanup = get_event_filter(LCFG_CLEANUP);
3311         if (!add_osc || !del_osc || !setup || !cleanup)
3312                 return -ENOMEM;
3313
3314         if (ostname && ostname[0])
3315                 snprintf(ost_filter, sizeof(ost_filter), " %s,", ostname);
3316
3317         if (strstr(record, ost_filter)) {
3318                 if (strstr(record, add_osc) || strstr(record, setup))
3319                         return 1;
3320                 if (strstr(record, del_osc) || strstr(record, cleanup))
3321                         return -ENOENT;
3322         }
3323
3324         free(add_osc);
3325         free(del_osc);
3326         free(setup);
3327         free(cleanup);
3328
3329         return 0;
3330 }
3331
3332 /**
3333  * Search ost in llog
3334  *
3335  * \param logname[in]           pointer to config log name
3336  * \param last_index[in]        the index of the last llog record
3337  * \param ostname[in]           pointer to ost name
3338  *
3339  * \retval                      1 if ostname is found
3340  *                              0 if ostname is not found
3341  */
3342 static int llog_search_ost(char *logname, long last_index, char *ostname)
3343 {
3344         long start, end, inc = MAX_IOC_BUFLEN / 128;
3345         int rc = 0;
3346
3347         for (end = last_index; end > 1; end -= inc) {
3348                 start = end - inc > 0 ? end - inc : 1;
3349                 rc = jt_llog_print_iter(logname, start, end, llog_search_ost_cb,
3350                                         ostname, true);
3351                 if (rc)
3352                         break;
3353         }
3354
3355         return (rc == 1 ? 1 : 0);
3356 }
3357
3358 struct llog_pool_data {
3359         char lpd_fsname[LUSTRE_MAXFSNAME + 1];
3360         char lpd_poolname[LOV_MAXPOOLNAME + 1];
3361         char lpd_ostname[MAX_OBD_NAME + 1];
3362         enum lcfg_command_type lpd_cmd_type;
3363         bool lpd_pool_exists;
3364         int lpd_ost_num;
3365 };
3366
3367 /**
3368  * Called for each formatted line in the config log (within range).
3369  *
3370  * - { index: 74, event: new_pool, device: tfs-clilov, fsname: tfs, pool: tmp }
3371  * - { index: 77, event: add_pool, device: tfs-clilov, fsname: tfs, pool: tmp,
3372  *     ost: tfs-OST0000_UUID }
3373  * - { index: 224, event: remove_pool, device: tfs-clilov, fsname: tfs,
3374  *     pool: tmp, ost: tfs-OST0003_UUID }
3375  * - { index: 227, event: del_pool, device: tfs-clilov, fsname: tfs, pool: tmp }
3376  *
3377  * \param record[in]    pointer to llog record
3378  * \param data[in]      pointer to llog_pool_data
3379  *
3380  * \retval              1 if pool or OST is found
3381  *                      0 if pool or OST is not found
3382  *                      -ENOENT if pool or OST is removed
3383  */
3384 static int llog_search_pool_cb(const char *record, void *data)
3385 {
3386         struct llog_pool_data *lpd = data;
3387         char pool_filter[MAX_STRING_SIZE] = "";
3388         char *new_pool, *del_pool, *add_pool, *rem_pool;
3389         char *found = NULL;
3390         int fs_pool_len = 0, rc = 0;
3391
3392         new_pool = get_event_filter(LCFG_POOL_NEW);
3393         del_pool = get_event_filter(LCFG_POOL_DEL);
3394         add_pool = get_event_filter(LCFG_POOL_ADD);
3395         rem_pool = get_event_filter(LCFG_POOL_REM);
3396         if (!new_pool || !del_pool || !add_pool || !rem_pool) {
3397                 rc = -ENOMEM;
3398                 goto out;
3399         }
3400
3401         fs_pool_len = 16 + strlen(lpd->lpd_fsname) + strlen(lpd->lpd_poolname);
3402         snprintf(pool_filter, fs_pool_len + 1, "fsname: %s, pool: %s",
3403                  lpd->lpd_fsname, lpd->lpd_poolname);
3404
3405         /* search poolname */
3406         found = strstr(record, pool_filter);
3407         if (found &&
3408             (found[fs_pool_len] == ' ' || found[fs_pool_len] == ',')) {
3409                 if (strstr(record, new_pool)) {
3410                         lpd->lpd_pool_exists = true;
3411                         rc = 1;
3412                         goto out;
3413                 }
3414                 if (strstr(record, del_pool)) {
3415                         lpd->lpd_pool_exists = false;
3416                         rc = -ENOENT;
3417                         goto out;
3418                 }
3419
3420                 if (lpd->lpd_cmd_type == LCFG_POOL_NEW ||
3421                     lpd->lpd_cmd_type == LCFG_POOL_DEL) {
3422                         if (strstr(record, add_pool))
3423                                 lpd->lpd_ost_num++;
3424                         if (strstr(record, rem_pool))
3425                                 lpd->lpd_ost_num--;
3426                 } else if (lpd->lpd_ostname && lpd->lpd_ostname[0]) {
3427                         if (strstr(record, lpd->lpd_ostname)) {
3428                                 lpd->lpd_pool_exists = true;
3429                                 if (strstr(record, add_pool)) {
3430                                         lpd->lpd_ost_num = 1;
3431                                         rc = 1;
3432                                         goto out;
3433                                 }
3434                                 if (strstr(record, rem_pool)) {
3435                                         lpd->lpd_ost_num = 0;
3436                                         rc = -ENOENT;
3437                                         goto out;
3438                                 }
3439                         }
3440                 }
3441         }
3442 out:
3443         if (new_pool)
3444                 free(new_pool);
3445         if (del_pool)
3446                 free(del_pool);
3447         if (add_pool)
3448                 free(add_pool);
3449         if (rem_pool)
3450                 free(rem_pool);
3451
3452         return rc;
3453 }
3454
3455 /* Search pool and its ost in llog
3456  *
3457  * \param logname[in]           pointer to config log name
3458  * \param last_index[in]        the index of the last llog record
3459  * \param fsname[in]            pointer to filesystem name
3460  * \param poolname[in]          pointer pool name
3461  * \param ostname[in]           pointer to OST name(OSTnnnn-UUID)
3462  * \param cmd[in]               pool command type
3463  *
3464  * \retval                      < 0 on error
3465  *                              0 if pool is empty or OST is not found
3466  *                              1 if pool is not empty or OST is found
3467  */
3468 static int llog_search_pool(char *logname, long last_index, char *fsname,
3469                             char *poolname, char *ostname,
3470                             enum lcfg_command_type cmd)
3471 {
3472         struct llog_pool_data lpd;
3473         long start, end, inc = MAX_IOC_BUFLEN / 128;
3474         int rc = 0;
3475
3476         memset(&lpd, 0, sizeof(lpd));
3477         lpd.lpd_cmd_type = cmd;
3478         lpd.lpd_pool_exists = false;
3479         lpd.lpd_ost_num = 0;
3480         strncpy(lpd.lpd_fsname, fsname, sizeof(lpd.lpd_fsname) - 1);
3481         if (poolname && poolname[0])
3482                 strncpy(lpd.lpd_poolname, poolname,
3483                         sizeof(lpd.lpd_poolname) - 1);
3484         if (ostname && ostname[0])
3485                 strncpy(lpd.lpd_ostname, ostname, sizeof(lpd.lpd_ostname) - 1);
3486
3487         for (end = last_index; end > 1; end -= inc) {
3488                 start = end - inc > 0 ? end - inc : 1;
3489                 rc = jt_llog_print_iter(logname, start, end,
3490                                         llog_search_pool_cb, &lpd, true);
3491                 if (rc) {
3492                         if (rc == 1 && lpd.lpd_pool_exists)
3493                                 rc = lpd.lpd_ost_num ? 1 : 0;
3494                         else if (rc == -ENOENT && lpd.lpd_pool_exists &&
3495                                  !lpd.lpd_ost_num)
3496                                 rc = 0;
3497                         goto out;
3498                 }
3499         }
3500
3501         rc = -ENOENT;
3502 out:
3503         return rc;
3504 }
3505
3506 static bool combined_mgs_mds(char *fsname)
3507 {
3508         glob_t path;
3509         int rc;
3510
3511         rc = cfs_get_param_paths(&path, "mdt/%s-MDT0000", fsname);
3512         if (!rc)
3513                 cfs_free_param_data(&path);
3514
3515         if (get_mgs_device() > 0 && !rc)
3516                 return true;
3517
3518         return false;
3519 }
3520
3521 /*
3522  * if pool is NULL, search ostname in target_obd
3523  * if pool is not NULL:
3524  *  - if pool not found returns errno < 0
3525  *  - if ostname is NULL, returns 1 if pool is not empty and 0 if pool empty
3526  *  - if ostname is not NULL, returns 1 if OST is in pool and 0 if not
3527  */
3528 int lctl_search_ost(char *fsname, char *poolname, char *ostname,
3529                     enum lcfg_command_type cmd)
3530 {
3531         char logname[MAX_OBD_NAME] = {'\0'};
3532         long last_index;
3533
3534         if (fsname && fsname[0] == '\0')
3535                 fsname = NULL;
3536         if (!fsname)
3537                 return -EINVAL;
3538
3539         if (combined_mgs_mds(fsname))
3540                 return llapi_search_ost(fsname, poolname, ostname);
3541
3542         /* fetch the last_index of llog record */
3543         snprintf(logname, sizeof(logname), "%s-client", fsname);
3544         last_index = llog_last_index(logname);
3545         if (last_index < 0)
3546                 return last_index;
3547
3548         /* if pool is NULL, search ostname in target_obd */
3549         if (!poolname && ostname)
3550                 return llog_search_ost(logname, last_index, ostname);
3551
3552         return llog_search_pool(logname, last_index, fsname, poolname,
3553                                 ostname, cmd);
3554 }
3555
3556 static int check_pool_cmd(enum lcfg_command_type cmd,
3557                           char *fsname, char *poolname,
3558                           char *ostname)
3559 {
3560         int rc;
3561
3562         rc = lctl_search_ost(fsname, poolname, ostname, cmd);
3563         if (rc < 0 && (cmd != LCFG_POOL_NEW)) {
3564                 fprintf(stderr, "Pool %s.%s not found\n",
3565                         fsname, poolname);
3566                 return rc;
3567         }
3568
3569         switch (cmd) {
3570         case LCFG_POOL_NEW: {
3571                 if (ostname != NULL)
3572                         return -EINVAL;
3573
3574                 if (rc >= 0) {
3575                         fprintf(stderr, "Pool %s.%s already exists\n",
3576                                 fsname, poolname);
3577                         return -EEXIST;
3578                 }
3579                 return 0;
3580         }
3581         case LCFG_POOL_DEL: {
3582                 if (ostname != NULL)
3583                         return -EINVAL;
3584
3585                 if (rc == 1) {
3586                         fprintf(stderr, "Pool %s.%s not empty, "
3587                                 "please remove all members\n",
3588                                 fsname, poolname);
3589                         return -ENOTEMPTY;
3590                 }
3591                 return 0;
3592         }
3593         case LCFG_POOL_ADD: {
3594                 if (rc == 1) {
3595                         fprintf(stderr, "OST %s is already in pool %s.%s\n",
3596                                 ostname, fsname, poolname);
3597                         return -EEXIST;
3598                 }
3599                 rc = lctl_search_ost(fsname, NULL, ostname, cmd);
3600                 if (rc == 0) {
3601                         fprintf(stderr, "OST %s is not part of the '%s' fs.\n",
3602                                 ostname, fsname);
3603                         return -ENOENT;
3604                 }
3605                 return 0;
3606         }
3607         case LCFG_POOL_REM: {
3608                 if (rc == 0) {
3609                         fprintf(stderr, "OST %s not found in pool %s.%s\n",
3610                                 ostname, fsname, poolname);
3611                         return -ENOENT;
3612                 }
3613                 return 0;
3614         }
3615         default:
3616                 break;
3617         } /* switch */
3618         return -EINVAL;
3619 }
3620
3621 /* This check only verifies that the changes have been "pushed out" to
3622    the client successfully.  This involves waiting for a config update,
3623    and so may fail because of problems in that code or post-command
3624    network loss. So reporting a warning is appropriate, but not a failure.
3625 */
3626 static int check_pool_cmd_result(enum lcfg_command_type cmd,
3627                                  char *fsname, char *poolname,
3628                                  char *ostname)
3629 {
3630         int cpt = 10;
3631         int rc = 0;
3632
3633         switch (cmd) {
3634         case LCFG_POOL_NEW: {
3635                 do {
3636                         rc = lctl_search_ost(fsname, poolname, NULL, cmd);
3637                         if (rc == -ENODEV)
3638                                 return rc;
3639                         if (rc < 0)
3640                                 sleep(2);
3641                         cpt--;
3642                 } while ((rc < 0) && (cpt > 0));
3643                 if (rc >= 0) {
3644                         fprintf(stderr, "Pool %s.%s created\n",
3645                                 fsname, poolname);
3646                         return 0;
3647                 } else {
3648                         fprintf(stderr, "Warning, pool %s.%s not found\n",
3649                                 fsname, poolname);
3650                         return -ENOENT;
3651                 }
3652         }
3653         case LCFG_POOL_DEL: {
3654                 do {
3655                         rc = lctl_search_ost(fsname, poolname, NULL, cmd);
3656                         if (rc == -ENODEV)
3657                                 return rc;
3658                         if (rc >= 0)
3659                                 sleep(2);
3660                         cpt--;
3661                 } while ((rc >= 0) && (cpt > 0));
3662                 if (rc < 0) {
3663                         fprintf(stderr, "Pool %s.%s destroyed\n",
3664                                 fsname, poolname);
3665                         return 0;
3666                 } else {
3667                         fprintf(stderr, "Warning, pool %s.%s still found\n",
3668                                 fsname, poolname);
3669                         return -EEXIST;
3670                 }
3671         }
3672         case LCFG_POOL_ADD: {
3673                 do {
3674                         rc = lctl_search_ost(fsname, poolname, ostname, cmd);
3675                         if (rc == -ENODEV)
3676                                 return rc;
3677                         if (rc != 1)
3678                                 sleep(2);
3679                         cpt--;
3680                 } while ((rc != 1) && (cpt > 0));
3681                 if (rc == 1) {
3682                         fprintf(stderr, "OST %s added to pool %s.%s\n",
3683                                 ostname, fsname, poolname);
3684                         return 0;
3685                 } else {
3686                         fprintf(stderr, "Warning, OST %s not found in pool %s.%s\n",
3687                                 ostname, fsname, poolname);
3688                         return -ENOENT;
3689                 }
3690         }
3691         case LCFG_POOL_REM: {
3692                 do {
3693                         rc = lctl_search_ost(fsname, poolname, ostname, cmd);
3694                         if (rc == -ENODEV)
3695                                 return rc;
3696                         if (rc == 1)
3697                                 sleep(2);
3698                         cpt--;
3699                 } while ((rc == 1) && (cpt > 0));
3700                 if (rc != 1) {
3701                         fprintf(stderr, "OST %s removed from pool %s.%s\n",
3702                                 ostname, fsname, poolname);
3703                         return 0;
3704                 } else {
3705                         fprintf(stderr, "Warning, OST %s still found in pool %s.%s\n",
3706                                 ostname, fsname, poolname);
3707                         return -EEXIST;
3708                 }
3709         }
3710         default:
3711                 break;
3712         }
3713         return -EINVAL;
3714 }
3715
3716 static int check_and_complete_ostname(char *fsname, char *ostname)
3717 {
3718         char *ptr;
3719         char real_ostname[MAX_OBD_NAME + 1];
3720         char i;
3721
3722         /* if OST name does not start with fsname, we add it */
3723         /* if not check if the fsname is the right one */
3724         ptr = strchr(ostname, '-');
3725         if (ptr == NULL) {
3726                 sprintf(real_ostname, "%s-%s", fsname, ostname);
3727         } else if (strncmp(ostname, fsname, strlen(fsname)) != 0) {
3728                 fprintf(stderr, "%s does not start with fsname %s\n",
3729                         ostname, fsname);
3730                 return -EINVAL;
3731         } else {
3732                 if (strlen(ostname) > sizeof(real_ostname)-1)
3733                         return -E2BIG;
3734                 strncpy(real_ostname, ostname, sizeof(real_ostname));
3735         }
3736         /* real_ostname is fsname-????? */
3737         ptr = real_ostname + strlen(fsname) + 1;
3738         if (strncmp(ptr, "OST", 3) != 0) {
3739                 fprintf(stderr, "%s does not start by %s-OST nor OST\n",
3740                         ostname, fsname);
3741                 return -EINVAL;
3742         }
3743         /* real_ostname is fsname-OST????? */
3744         ptr += 3;
3745         for (i = 0; i < 4; i++) {
3746                 if (!isxdigit(*ptr)) {
3747                         fprintf(stderr,
3748                                 "ost's index in %s is not an hexa number\n",
3749                                 ostname);
3750                         return -EINVAL;
3751                 }
3752                 ptr++;
3753         }
3754         /* real_ostname is fsname-OSTXXXX????? */
3755         /* if OST name does not end with _UUID, we add it */
3756         if (*ptr == '\0') {
3757                 strcat(real_ostname, "_UUID");
3758         } else if (strcmp(ptr, "_UUID") != 0) {
3759                 fprintf(stderr,
3760                         "ostname %s does not end with _UUID\n", ostname);
3761                 return -EINVAL;
3762         }
3763         /* real_ostname is fsname-OSTXXXX_UUID */
3764         strcpy(ostname, real_ostname);
3765         return 0;
3766 }
3767
3768 /* returns 0 or -errno */
3769 static int pool_cmd(enum lcfg_command_type cmd,
3770                     char *cmdname, char *fullpoolname,
3771                     char *fsname, char *poolname, char *ostname)
3772 {
3773         int rc = 0;
3774         struct obd_ioctl_data data;
3775         struct lustre_cfg_bufs bufs;
3776         struct lustre_cfg *lcfg;
3777         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
3778
3779         rc = check_pool_cmd(cmd, fsname, poolname, ostname);
3780         if (rc == -ENODEV)
3781                 fprintf(stderr, "Can't verify pool command since there "
3782                         "is no local MDT or client, proceeding anyhow...\n");
3783         else if (rc)
3784                 return rc;
3785
3786         lustre_cfg_bufs_reset(&bufs, NULL);
3787         lustre_cfg_bufs_set_string(&bufs, 0, cmdname);
3788         lustre_cfg_bufs_set_string(&bufs, 1, fullpoolname);
3789         if (ostname != NULL)
3790                 lustre_cfg_bufs_set_string(&bufs, 2, ostname);
3791
3792
3793         lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
3794         if (lcfg == NULL)
3795                 return -ENOMEM;
3796         lustre_cfg_init(lcfg, cmd, &bufs);
3797
3798         memset(&data, 0, sizeof(data));
3799         rc = data.ioc_dev = get_mgs_device();
3800         if (rc < 0)
3801                 goto out;
3802
3803         data.ioc_type = LUSTRE_CFG_TYPE;
3804         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
3805                                         lcfg->lcfg_buflens);
3806         data.ioc_pbuf1 = (void *)lcfg;
3807
3808         memset(buf, 0, sizeof(rawbuf));
3809         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
3810         if (rc) {
3811                 fprintf(stderr, "error: %s: invalid ioctl\n",
3812                         jt_cmdname(cmdname));
3813                 free(lcfg);
3814                 return rc;
3815         }
3816         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_POOL, buf);
3817 out:
3818         if (rc)
3819                 rc = -errno;
3820         switch (rc) {
3821         case -ENAMETOOLONG:
3822                 fprintf(stderr, "error: %s: either the pool or file "
3823                         "system name is too long (max pool name len "
3824                         "is %d and file system name is %d)\n",
3825                         jt_cmdname(cmdname), LOV_MAXPOOLNAME,
3826                         LUSTRE_MAXFSNAME);
3827                 break;
3828         case -EINVAL:
3829                 fprintf(stderr, "error: %s can contain only "
3830                         "alphanumeric characters, underscores, and "
3831                         "dashes besides the required '.'\n",
3832                         jt_cmdname(cmdname));
3833         default:
3834                 break;
3835         }
3836         free(lcfg);
3837         return rc;
3838 }
3839
3840 /**
3841  * Format and send the ioctl to the MGS.
3842  *
3843  * \param       cmd             IOCTL to send
3844  * \param       ret_data        void pointer to return anything from
3845  *                              ioctl
3846  * \param       num_args        number of arguments to pack into the
3847  *                              ioctl buffer
3848  * \param       argv[]          variable number of string arguments
3849  *
3850  * \retval                      0 on success
3851  */
3852 static int nodemap_cmd(enum lcfg_command_type cmd, void *ret_data,
3853                        unsigned int ret_size, ...)
3854 {
3855         va_list                 ap;
3856         char                    *arg;
3857         int                     i = 0;
3858         struct lustre_cfg_bufs  bufs;
3859         struct obd_ioctl_data   data;
3860         struct lustre_cfg       *lcfg;
3861         char                    rawbuf[MAX_IOC_BUFLEN];
3862         char                    *buf = rawbuf;
3863         int                     rc = 0;
3864
3865         lustre_cfg_bufs_reset(&bufs, NULL);
3866
3867         va_start(ap, ret_size);
3868         arg = va_arg(ap, char *);
3869         while (arg != NULL) {
3870                 lustre_cfg_bufs_set_string(&bufs, i, arg);
3871                 i++;
3872                 arg = va_arg(ap, char *);
3873         }
3874         va_end(ap);
3875
3876         lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
3877         if (lcfg == NULL)
3878                 return -ENOMEM;
3879         lustre_cfg_init(lcfg, cmd, &bufs);
3880
3881         memset(&data, 0, sizeof(data));
3882         rc = data.ioc_dev = get_mgs_device();
3883         if (rc < 0)
3884                 goto out;
3885
3886         data.ioc_type = LUSTRE_CFG_TYPE;
3887         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
3888                          lcfg->lcfg_buflens);
3889         data.ioc_pbuf1 = (void *)lcfg;
3890
3891         memset(buf, 0, sizeof(rawbuf));
3892         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
3893         if (rc != 0) {
3894                 fprintf(stderr, "error: invalid ioctl: %08x errno: %d with "
3895                                "rc=%d\n", cmd, errno, rc);
3896                 goto out;
3897         }
3898
3899         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_NODEMAP, buf);
3900         if (rc != 0) {
3901                 fprintf(stderr, "error: invalid ioctl: %08x errno: %d with "
3902                                "rc=%d\n", cmd, errno, rc);
3903                 goto out;
3904         }
3905
3906         if (ret_data != NULL) {
3907                 rc = llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
3908                 if (rc != 0)
3909                         goto out;
3910
3911                 if (ret_size > data.ioc_plen1)
3912                         ret_size = data.ioc_plen1;
3913
3914                 memcpy(ret_data, data.ioc_pbuf1, ret_size);
3915         }
3916 out:
3917         free(lcfg);
3918
3919         return rc;
3920 }
3921
3922 /**
3923  * activate nodemap functions
3924  *
3925  * \param       argc            number of args
3926  * \param       argv[]          variable string arguments
3927  *
3928  * argv[0]                      1 for activate or 0 for deactivate
3929  *
3930  * \retval                      0 on success
3931  */
3932 int jt_nodemap_activate(int argc, char **argv)
3933 {
3934         int rc;
3935
3936         rc = nodemap_cmd(LCFG_NODEMAP_ACTIVATE, NULL, 0, argv[0], argv[1],
3937                          NULL);
3938
3939         if (rc != 0) {
3940                 errno = -rc;
3941                 perror(argv[0]);
3942         }
3943
3944         return rc;
3945 }
3946
3947 /**
3948  * add a nodemap
3949  *
3950  * \param       argc            number of args
3951  * \param       argv[]          variable string arguments
3952  *
3953  * argv[0]                      nodemap name
3954  *
3955  * \retval                      0 on success
3956  */
3957 int jt_nodemap_add(int argc, char **argv)
3958 {
3959         int rc;
3960
3961         rc = llapi_nodemap_exists(argv[1]);
3962         if (rc == 0) {
3963                 fprintf(stderr, "error: %s existing nodemap name\n", argv[1]);
3964                 return 1;
3965         }
3966
3967         rc = nodemap_cmd(LCFG_NODEMAP_ADD, NULL, 0, argv[0], argv[1], NULL);
3968
3969         if (rc != 0) {
3970                 errno = -rc;
3971                 perror(argv[0]);
3972         }
3973
3974         return rc;
3975 }
3976
3977 /**
3978  * delete a nodemap
3979  *
3980  * \param       argc            number of args
3981  * \param       argv[]          variable string arguments
3982  *
3983  * argv[0]                      nodemap name
3984  *
3985  * \retval                      0 on success
3986  */
3987 int jt_nodemap_del(int argc, char **argv)
3988 {
3989         int rc;
3990
3991         rc = llapi_nodemap_exists(argv[1]);
3992         if (rc != 0) {
3993                 fprintf(stderr, "error: %s not existing nodemap name\n",
3994                         argv[1]);
3995                 return rc;
3996         }
3997         rc = nodemap_cmd(LCFG_NODEMAP_DEL, NULL, 0, argv[0], argv[1], NULL);
3998
3999         if (rc != 0) {
4000                 errno = -rc;
4001                 perror(argv[0]);
4002         }
4003
4004         return rc;
4005 }
4006
4007 /**
4008  * test a nid for nodemap membership
4009  *
4010  * \param       argc            number of args
4011  * \param       argv[]          variable string arguments
4012  *
4013  * argv[0]                      properly formatted nid
4014  *
4015  * \retval                      0 on success
4016  */
4017 int jt_nodemap_test_nid(int argc, char **argv)
4018 {
4019
4020         char    rawbuf[MAX_IOC_BUFLEN];
4021         int     rc;
4022
4023         rc = nodemap_cmd(LCFG_NODEMAP_TEST_NID, &rawbuf, sizeof(rawbuf),
4024                          argv[0], argv[1], NULL);
4025         if (rc == 0)
4026                 printf("%s\n", (char *)rawbuf);
4027
4028         return rc;
4029 }
4030
4031 /**
4032  * test a nodemap id pair for mapping
4033  *
4034  * \param       argc            number of args
4035  * \param       argv[[]         variable string arguments
4036  *
4037  * \retval                      0 on success
4038  *
4039  * The argv array should contain the nodemap name, the id
4040  * to checking the mapping on, and the id type (UID or GID)
4041  *
4042  */
4043 int jt_nodemap_test_id(int argc, char **argv)
4044 {
4045         char    rawbuf[MAX_IOC_BUFLEN];
4046         char    *nidstr = NULL;
4047         char    *idstr = NULL;
4048         char    *typestr = NULL;
4049         int     rc = 0;
4050         int     c;
4051
4052         static struct option long_opts[] = {
4053                 { .val = 'i',   .name = "id",   .has_arg = required_argument },
4054                 { .val = 'n',   .name = "nid",  .has_arg = required_argument },
4055                 { .val = 't',   .name = "idtype",
4056                                                 .has_arg = required_argument },
4057                 { .name = NULL } };
4058
4059         while ((c = getopt_long(argc, argv, "n:t:i:",
4060                                 long_opts, NULL)) != -1) {
4061                 switch (c) {
4062                 case 'n':
4063                         nidstr = optarg;
4064                         break;
4065                 case 't':
4066                         typestr = optarg;
4067                         break;
4068                 case 'i':
4069                         idstr = optarg;
4070                         break;
4071                 }
4072         }
4073
4074         if (nidstr == NULL || typestr == NULL || idstr == NULL) {
4075                 fprintf(stderr, "usage: nodemap_test_id --nid <nid> "
4076                                 "--idtype [uid|gid] --id <id>\n");
4077                 return -1;
4078         }
4079
4080         rc = nodemap_cmd(LCFG_NODEMAP_TEST_ID, &rawbuf, sizeof(rawbuf),
4081                          argv[0], nidstr, typestr, idstr);
4082         if (rc == 0)
4083                 printf("%s\n", (char *)rawbuf);
4084
4085         return rc;
4086 }
4087
4088 /**
4089  * parse nid range
4090  *
4091  * \param       nodemap_range   --range string
4092  * \param       nid_range       nid range string, min_nid:max_nid
4093  *
4094  * \retval                      0 on success
4095  */
4096 static int parse_nid_range(char *nodemap_range, char *nid_range, int range_len)
4097 {
4098         char                    min_nid[LNET_NIDSTR_SIZE + 1];
4099         char                    max_nid[LNET_NIDSTR_SIZE + 1];
4100         struct list_head        nidlist;
4101         int                     rc = 0;
4102
4103         INIT_LIST_HEAD(&nidlist);
4104
4105         if (cfs_parse_nidlist(nodemap_range, strlen(nodemap_range),
4106                               &nidlist) <= 0) {
4107                 fprintf(stderr,
4108                         "error: nodemap_xxx_range: can't parse nid range: %s\n",
4109                         nodemap_range);
4110                 return -1;
4111         }
4112
4113         rc = cfs_nidrange_find_min_max(&nidlist, &min_nid[0], &max_nid[0],
4114                                        LNET_NIDSTR_SIZE);
4115         if (rc < 0) {
4116                 if (rc == -EINVAL)
4117                         fprintf(stderr,
4118                                 "error: nodemap_xxx_range: nid range uses "
4119                                 "currently unsupported features\n");
4120                 else if (rc == -ERANGE)
4121                         fprintf(stderr,
4122                                 "error: nodemap_xxx_range: nodemap ranges must "
4123                                 "be contiguous\n");
4124
4125                 return rc;
4126         }
4127
4128         snprintf(nid_range, range_len, "%s:%s", min_nid, max_nid);
4129
4130         return rc;
4131 }
4132
4133 /**
4134  * add an nid range to a nodemap
4135  *
4136  * \param       argc            number of args
4137  * \param       argv[]          variable string arguments
4138  *
4139  * --name                       nodemap name
4140  * --range                      properly formatted nid range
4141  *
4142  * \retval                      0 on success
4143  */
4144 int jt_nodemap_add_range(int argc, char **argv)
4145 {
4146         char                    *nodemap_name = NULL;
4147         char                    *nodemap_range = NULL;
4148         char                    nid_range[2 * LNET_NIDSTR_SIZE + 2];
4149         int                     rc = 0;
4150         int                     c;
4151
4152         static struct option long_opts[] = {
4153         { .val = 'n',   .name = "name",         .has_arg = required_argument },
4154         { .val = 'r',   .name = "range",        .has_arg = required_argument },
4155         { .name = NULL } };
4156
4157         while ((c = getopt_long(argc, argv, "n:r:",
4158                                 long_opts, NULL)) != -1) {
4159                 switch (c) {
4160                 case 'n':
4161                         nodemap_name = optarg;
4162                         break;
4163                 case 'r':
4164                         nodemap_range = optarg;
4165                         break;
4166                 }
4167         }
4168
4169         if (nodemap_name == NULL || nodemap_range == NULL) {
4170                 fprintf(stderr, "usage: nodemap_add_range --name <name> "
4171                                 "--range <range>\n");
4172                 return -1;
4173         }
4174
4175         rc = parse_nid_range(nodemap_range, nid_range, sizeof(nid_range));
4176         if (rc) {
4177                 errno = -rc;
4178                 return rc;
4179         }
4180         rc = nodemap_cmd(LCFG_NODEMAP_ADD_RANGE, NULL, 0, argv[0],
4181                          nodemap_name, nid_range, NULL);
4182         if (rc != 0) {
4183                 errno = -rc;
4184                 fprintf(stderr, "error: %s: cannot add range '%s' to nodemap "
4185                                 "'%s': rc = %d\n",
4186                         jt_cmdname(argv[0]), nodemap_range, nodemap_name, rc);
4187         }
4188
4189         return rc;
4190 }
4191
4192 /**
4193  * delete an nid range to a nodemap
4194  *
4195  * \param       argc            number of args
4196  * \param       argv[]          variable string arguments
4197  *
4198  * --name                       nodemap name
4199  * --range                      properly formatted nid range
4200  *
4201  * \retval                      0 on success
4202  */
4203 int jt_nodemap_del_range(int argc, char **argv)
4204 {
4205         char                    *nodemap_name = NULL;
4206         char                    *nodemap_range = NULL;
4207         char                    nid_range[2 * LNET_NIDSTR_SIZE + 2];
4208         int                     rc = 0;
4209         int                     c;
4210
4211         static struct option long_opts[] = {
4212         { .val = 'n',   .name = "name",         .has_arg = required_argument },
4213         { .val = 'r',   .name = "range",        .has_arg = required_argument },
4214         { .name = NULL } };
4215
4216         while ((c = getopt_long(argc, argv, "n:r:",
4217                                 long_opts, NULL)) != -1) {
4218                 switch (c) {
4219                 case 'n':
4220                         nodemap_name = optarg;
4221                         break;
4222                 case 'r':
4223                         nodemap_range = optarg;
4224                         break;
4225                 }
4226         }
4227
4228         if (nodemap_name == NULL || nodemap_range == NULL) {
4229                 fprintf(stderr, "usage: nodemap_del_range --name <name> "
4230                                 "--range <range>\n");
4231                 return -1;
4232         }
4233
4234         rc = parse_nid_range(nodemap_range, nid_range, sizeof(nid_range));
4235         if (rc) {
4236                 errno = -rc;
4237                 return rc;
4238         }
4239         rc = nodemap_cmd(LCFG_NODEMAP_DEL_RANGE, NULL, 0, argv[0],
4240                          nodemap_name, nid_range, NULL);
4241         if (rc != 0) {
4242                 errno = -rc;
4243                 fprintf(stderr, "error: %s: cannot delete range '%s' to "
4244                                "nodemap '%s': rc = %d\n",
4245                         jt_cmdname(argv[0]), nodemap_range, nodemap_name, rc);
4246         }
4247
4248         return rc;
4249 }
4250
4251 /**
4252  * set a fileset on a nodemap
4253  *
4254  * \param       argc            number of args
4255  * \param       argv[]          variable string arguments
4256  *
4257  * --name                       nodemap name
4258  * --fileset                    fileset name
4259  *
4260  * \retval                      0 on success
4261  */
4262 int jt_nodemap_set_fileset(int argc, char **argv)
4263 {
4264         char *nodemap_name = NULL;
4265         char *fileset_name = NULL;
4266         int   rc = 0;
4267         int   c;
4268
4269         static struct option long_opts[] = {
4270         { .val = 'f',   .name = "fileset",      .has_arg = required_argument },
4271         { .val = 'n',   .name = "name",         .has_arg = required_argument },
4272         { .name = NULL } };
4273
4274         while ((c = getopt_long(argc, argv, "n:f:",
4275                                 long_opts, NULL)) != -1) {
4276                 switch (c) {
4277                 case 'n':
4278                         nodemap_name = optarg;
4279                         break;
4280                 case 'f':
4281                         fileset_name = optarg;
4282                         break;
4283                 }
4284         }
4285
4286         if (nodemap_name == NULL || fileset_name == NULL) {
4287                 fprintf(stderr, "usage: nodemap_set_fileset --name <name> "
4288                                 "--fileset <fileset>\n");
4289                 return -1;
4290         }
4291
4292         rc = nodemap_cmd(LCFG_NODEMAP_SET_FILESET, NULL, 0, argv[0],
4293                          nodemap_name, fileset_name, NULL);
4294         if (rc != 0) {
4295                 errno = -rc;
4296                 fprintf(stderr, "error: %s: cannot set fileset '%s' on nodemap "
4297                                 "'%s': rc = %d\n",
4298                         jt_cmdname(argv[0]), fileset_name, nodemap_name, rc);
4299         }
4300
4301         return rc;
4302 }
4303
4304 /**
4305  * set SELinux policy info on a nodemap
4306  *
4307  * \param       argc            number of args
4308  * \param       argv[]          variable string arguments
4309  *
4310  * --name                       nodemap name
4311  * --sepol                      SELinux policy info
4312  *
4313  * \retval                      0 on success
4314  */
4315 int jt_nodemap_set_sepol(int argc, char **argv)
4316 {
4317         char *nodemap_name = NULL;
4318         char *sepol = NULL;
4319         int   rc = 0;
4320         int   c;
4321
4322         static struct option long_options[] = {
4323                 {
4324                         .name           = "name",
4325                         .has_arg        = required_argument,
4326                         .val            = 'n',
4327                 },
4328                 {
4329                         .name           = "sepol",
4330                         .has_arg        = required_argument,
4331                         .val            = 's',
4332                 },
4333                 {
4334                         .name = NULL,
4335                 }
4336         };
4337
4338         while ((c = getopt_long(argc, argv, "n:s:",
4339                                 long_options, NULL)) != -1) {
4340                 switch (c) {
4341                 case 'n':
4342                         nodemap_name = optarg;
4343                         break;
4344                 case 's':
4345                         sepol = optarg;
4346                         break;
4347                 }
4348         }
4349
4350         if (nodemap_name == NULL || sepol == NULL) {
4351                 fprintf(stderr, "usage: nodemap_set_sepol --name <name> "
4352                                 "--sepol <sepol>\n");
4353                 return -1;
4354         }
4355
4356         rc = nodemap_cmd(LCFG_NODEMAP_SET_SEPOL, NULL, 0, argv[0],
4357                          nodemap_name, sepol, NULL);
4358         if (rc != 0) {
4359                 errno = -rc;
4360                 fprintf(stderr, "error: %s: cannot set sepol '%s' on nodemap "
4361                                 "'%s': rc = %d\n",
4362                         jt_cmdname(argv[0]), sepol, nodemap_name, rc);
4363         }
4364
4365         return rc;
4366 }
4367
4368 /**
4369  * modify a nodemap's behavior
4370  *
4371  * \param       argc            number of args
4372  * \param       argv[]          variable string arguments
4373  *
4374  * --name                       nodemap name
4375  * --property                   nodemap property to change
4376  *                              admin, trusted, squash_uid, squash_gid)
4377  * --value                      value to set property
4378  *
4379  * \retval                      0 on success
4380  */
4381 int jt_nodemap_modify(int argc, char **argv)
4382 {
4383         int                     c;
4384         int                     rc = 0;
4385         enum lcfg_command_type  cmd = 0;
4386         char                    *nodemap_name = NULL;
4387         char                    *param = NULL;
4388         char                    *value = NULL;
4389
4390         static struct option long_opts[] = {
4391         { .val = 'n',   .name = "name",         .has_arg = required_argument },
4392         { .val = 'p',   .name = "property",     .has_arg = required_argument },
4393         { .val = 'v',   .name = "value",        .has_arg = required_argument },
4394         { .name = NULL } };
4395
4396         while ((c = getopt_long(argc, argv, "n:p:v:",
4397                                 long_opts, NULL)) != -1) {
4398                 switch (c) {
4399                 case 'n':
4400                         nodemap_name = optarg;
4401                         break;
4402                 case 'p':
4403                         param = optarg;
4404                         break;
4405                 case 'v':
4406                         value = optarg;
4407                         break;
4408                 }
4409         }
4410
4411         if (nodemap_name == NULL || param == NULL || value == NULL) {
4412                 fprintf(stderr, "usage: nodemap_modify --name <nodemap_name> "
4413                                 "--property <property_name> --value <value>\n");
4414                 fprintf(stderr, "valid properties: admin trusted map_mode "
4415                                 "squash_uid squash_gid deny_unknown audit_mode\n");
4416                 return -1;
4417         }
4418
4419         if (strcmp("admin", param) == 0) {
4420                 cmd = LCFG_NODEMAP_ADMIN;
4421         } else if (strcmp("trusted", param) == 0) {
4422                 cmd = LCFG_NODEMAP_TRUSTED;
4423         } else if (strcmp("deny_unknown", param) == 0) {
4424                 cmd = LCFG_NODEMAP_DENY_UNKNOWN;
4425         } else if (strcmp("squash_uid", param) == 0) {
4426                 cmd = LCFG_NODEMAP_SQUASH_UID;
4427         } else if (strcmp("squash_gid", param) == 0) {
4428                 cmd = LCFG_NODEMAP_SQUASH_GID;
4429         } else if (strcmp("map_mode", param) == 0) {
4430                 cmd = LCFG_NODEMAP_MAP_MODE;
4431         } else if (strcmp("audit_mode", param) == 0) {
4432                 cmd = LCFG_NODEMAP_AUDIT_MODE;
4433         } else {
4434                 fprintf(stderr, "error: %s: nodemap_modify invalid "
4435                                 "subcommand: %s\n",
4436                         jt_cmdname(argv[0]), param);
4437                 return -1;
4438         }
4439
4440         rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, param,
4441                          value, NULL);
4442         if (rc != 0) {
4443                 errno = -rc;
4444                 fprintf(stderr, "error: %s: cannot modify nodemap '%s' "
4445                                "to param '%s': value '%s': rc = %d\n",
4446                         jt_cmdname(argv[0]), nodemap_name, param, value, rc);
4447         }
4448
4449         return rc;
4450 }
4451
4452 int jt_nodemap_add_idmap(int argc, char **argv)
4453 {
4454         int                     c;
4455         enum                    lcfg_command_type cmd = 0;
4456         char                    *nodemap_name = NULL;
4457         char                    *idmap = NULL;
4458         char                    *idtype = NULL;
4459         int                     rc = 0;
4460
4461         static struct option long_opts[] = {
4462         { .val = 'i',   .name = "idtype",       .has_arg = required_argument },
4463         { .val = 'm',   .name = "idmap",        .has_arg = required_argument },
4464         { .val = 'n',   .name = "name",         .has_arg = required_argument },
4465         { .name = NULL } };
4466
4467         while ((c = getopt_long(argc, argv, "n:m:i:",
4468                                 long_opts, NULL)) != -1) {
4469                 switch (c) {
4470                 case 'n':
4471                         nodemap_name = optarg;
4472                         break;
4473                 case 'm':
4474                         idmap = optarg;
4475                         break;
4476                 case 'i':
4477                         idtype = optarg;
4478                         break;
4479                 }
4480         }
4481
4482         if (nodemap_name == NULL || idmap == NULL || idtype == NULL) {
4483                 fprintf(stderr, "usage: %s --name <name> --idtype [uid | gid]"
4484                         " --idmap <client id>:<filesystem id>\n", argv[0]);
4485                 return -1;
4486         }
4487
4488         if (strcmp("uid", idtype) == 0) {
4489                 cmd = LCFG_NODEMAP_ADD_UIDMAP;
4490         } else if (strcmp("gid", idtype) == 0) {
4491                 cmd = LCFG_NODEMAP_ADD_GIDMAP;
4492         } else {
4493                 fprintf(stderr, "usage: %s --name <name> --idtype [uid | gid]"
4494                         " --idmap <client id>:<filesystem id>\n", argv[0]);
4495                 return -1;
4496         }
4497
4498         rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, idmap, NULL);
4499         if (rc != 0) {
4500                 errno = -rc;
4501                 fprintf(stderr, "cannot add %smap '%s' to nodemap '%s'"
4502                         ": rc = %d\n", idtype, idmap, nodemap_name, rc);
4503         }
4504
4505         return rc;
4506 }
4507
4508 int jt_nodemap_del_idmap(int argc, char **argv)
4509 {
4510         int                     c;
4511         enum                    lcfg_command_type cmd = 0;
4512         char                    *nodemap_name = NULL;
4513         char                    *idmap = NULL;
4514         char                    *idtype = NULL;
4515         int                     rc = 0;
4516
4517         static struct option long_opts[] = {
4518         { .val = 'i',   .name = "idtype",       .has_arg = required_argument },
4519         { .val = 'm',   .name = "idmap",        .has_arg = required_argument },
4520         { .val = 'n',   .name = "name",         .has_arg = required_argument },
4521         { .name = NULL } };
4522
4523         while ((c = getopt_long(argc, argv, "n:m:i:",
4524                                 long_opts, NULL)) != -1) {
4525                 switch (c) {
4526                 case 'n':
4527                         nodemap_name = optarg;
4528                         break;
4529                 case 'm':
4530                         idmap = optarg;
4531                         break;
4532                 case 'i':
4533                         idtype = optarg;
4534                         break;
4535                 }
4536         }
4537
4538         if (nodemap_name == NULL || idmap == NULL || idtype == NULL) {
4539                 fprintf(stderr, "usage: %s --name <name> --idtype [uid | gid]"
4540                         " --idmap <client id>:<filesystem id>\n", argv[0]);
4541                 return -1;
4542         }
4543
4544         if (strcmp("uid", idtype) == 0)
4545                 cmd = LCFG_NODEMAP_DEL_UIDMAP;
4546         else
4547                 cmd = LCFG_NODEMAP_DEL_GIDMAP;
4548
4549         rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, idmap, NULL);
4550         if (rc != 0) {
4551                 errno = -rc;
4552                 fprintf(stderr, "cannot delete %smap '%s' from nodemap '%s'"
4553                         ": rc = %d\n", idtype, idmap, nodemap_name, rc);
4554         }
4555
4556         return rc;
4557 }
4558
4559 /*
4560  * this function tranforms a rule [start-end/step] into an array
4561  * of matching numbers
4562  * supported forms are:
4563  * [start]                : just this number
4564  * [start-end]            : all numbers from start to end
4565  * [start-end/step]       : numbers from start to end with increment of step
4566  * on return, format contains a printf format string which can be used
4567  * to generate all the strings
4568  */
4569 static int get_array_idx(char *rule, char *format, int **array)
4570 {
4571         char *start, *end, *ptr;
4572         unsigned int lo, hi, step;
4573         int array_sz = 0;
4574         int i, array_idx;
4575         int rc;
4576
4577         start = strchr(rule, '[');
4578         end = strchr(rule, ']');
4579         if ((start == NULL) || (end == NULL)) {
4580                 *array = malloc(sizeof(int));
4581                 if (*array == NULL)
4582                         return 0;
4583                 strcpy(format, rule);
4584                 array_sz = 1;
4585                 return array_sz;
4586         }
4587         *start = '\0';
4588         *end = '\0';
4589         end++;
4590         start++;
4591         /* put in format the printf format (the rule without the range) */
4592         sprintf(format, "%s%%.4x%s", rule, end);
4593
4594         array_idx = 0;
4595         array_sz = 0;
4596         *array = NULL;
4597         /* loop on , separator */
4598         do {
4599                 /* extract the 3 fields */
4600                 rc = sscanf(start, "%x-%x/%u", &lo, &hi, &step);
4601                 switch (rc) {
4602                 case 0:
4603                         goto err;
4604                 case 1: {
4605                         void *tmp;
4606
4607                         array_sz++;
4608                         tmp = realloc(*array, array_sz * sizeof(int));
4609                         if (tmp == NULL)
4610                                 goto err;
4611                         *array = tmp;
4612                         (*array)[array_idx] = lo;
4613                         array_idx++;
4614                         break;
4615                 }
4616                 case 2: {
4617                         step = 1;
4618                         /* do not break to share code with case 3: */
4619                 }
4620                 case 3: {
4621                         void *tmp;
4622
4623                         if ((hi < lo) || (step == 0))
4624                                 goto err;
4625                         array_sz += (hi - lo) / step + 1;
4626                         tmp = realloc(*array, array_sz * sizeof(int));
4627                         if (tmp == NULL)
4628                                 goto err;
4629                         *array = tmp;
4630                         for (i = lo; i <= hi; i+=step, array_idx++)
4631                                 (*array)[array_idx] = i;
4632                         break;
4633                 }
4634                 }
4635                 ptr = strchr(start, ',');
4636                 if (ptr != NULL)
4637                         start = ptr + 1;
4638
4639         } while (ptr != NULL);
4640         return array_sz;
4641 err:
4642         if (*array != NULL) {
4643                 free(*array);
4644                 *array = NULL;
4645         }
4646         return 0;
4647 }
4648
4649 struct llog_pool_name {
4650         char lpn_name[UUID_MAX];
4651         struct list_head lpn_list;
4652 };
4653
4654 struct llog_pool_list_data {
4655         char lpld_fsname[LUSTRE_MAXFSNAME + 1];
4656         char lpld_poolname[LOV_MAXPOOLNAME + 1];
4657         bool lpld_exists;
4658         struct list_head lpld_list_head;
4659 };
4660
4661 /**
4662  * Callback to list pool information in llog
4663  * - { index: 74, event: new_pool, device: tfs-clilov, fsname: tfs, pool: tmp }
4664  * - { index: 77, event: add_pool, device: tfs-clilov, fsname: tfs, pool: tmp,
4665  *     ost: tfs-OST0000_UUID }
4666  * - { index: 224, event: remove_pool, device: tfs-clilov, fsname: tfs,
4667  *     pool: tmp, ost: tfs-OST0003_UUID }
4668  * - { index: 227, event: del_pool, device: tfs-clilov, fsname: tfs, pool: tmp }
4669  *
4670  * \param record[in]    pointer to llog record
4671  * \param data[in]      pointer to struct llog_pool_list_data
4672  *
4673  * \retval              0 on success
4674  *                      <0 on error
4675  */
4676 static int llog_poollist_cb(const char *record, void *data)
4677 {
4678         struct llog_pool_list_data *lpld = data;
4679         char pool_filter[MAX_STRING_SIZE] = "";
4680         char *new_record, *del_record, *del_pool, *found;
4681         char type[10] = "";
4682         int filter_len, rc = 0;
4683
4684         filter_len = snprintf(pool_filter, sizeof(pool_filter), " fsname: %s,",
4685                               lpld->lpld_fsname);
4686         if (lpld->lpld_poolname[0] == '\0') {
4687                 new_record = get_event_filter(LCFG_POOL_NEW);
4688                 del_record = get_event_filter(LCFG_POOL_DEL);
4689                 strncpy(type, " pool: ", sizeof(type));
4690         } else {
4691                 filter_len += snprintf(pool_filter + filter_len,
4692                                        sizeof(pool_filter) - filter_len,
4693                                        " pool: %s", lpld->lpld_poolname);
4694                 new_record = get_event_filter(LCFG_POOL_ADD);
4695                 del_record = get_event_filter(LCFG_POOL_REM);
4696                 strncpy(type, " ost: ", sizeof(type));
4697         }
4698         del_pool = get_event_filter(LCFG_POOL_DEL);
4699
4700         if (!new_record || !del_record || !del_pool) {
4701                 rc = -ENOMEM;
4702                 goto out;
4703         }
4704
4705         found = strstr(record, pool_filter);
4706         if (found &&
4707             (found[filter_len] == ' ' || found[filter_len] == ',')) {
4708                 struct llog_pool_name *tmp = NULL;
4709                 struct list_head *head = &lpld->lpld_list_head;
4710                 char *name;
4711                 int name_len, type_len = strlen(type);
4712
4713                 lpld->lpld_exists = true;
4714                 if (strstr(record, new_record)) {
4715                         name = strstr(record, type);
4716                         /* 2 bytes for " }" */
4717                         name_len = strlen(name) - type_len - 2;
4718                         if (name_len <= 0 || name_len > sizeof(tmp->lpn_name))
4719                                 return -EINVAL;
4720                         tmp = malloc(sizeof(struct llog_pool_name));
4721                         if (tmp == NULL) {
4722                                 rc = -ENOMEM;
4723                                 goto out;
4724                         }
4725                         memset(tmp, 0, sizeof(struct llog_pool_name));
4726                         strncpy(tmp->lpn_name, name + type_len, name_len);
4727                         list_add_tail(&tmp->lpn_list, &lpld->lpld_list_head);
4728                 } else if (strstr(record, del_record)) {
4729                         name = strstr(record, type);
4730                         name_len = strlen(name) - type_len - 2;
4731                         list_for_each_entry(tmp, head, lpn_list) {
4732                                 if (strncmp(tmp->lpn_name, name + type_len,
4733                                             name_len) == 0 &&
4734                                             tmp->lpn_name[name_len] == '\0') {
4735                                         list_del(&tmp->lpn_list);
4736                                         free(tmp);
4737                                         break;
4738                                 }
4739                         }
4740                 }
4741                 /* verify if the specified pool still exists */
4742                 if (lpld->lpld_poolname[0] && strstr(record, del_pool))
4743                         lpld->lpld_exists = false;
4744         }
4745 out:
4746         if (new_record)
4747                 free(new_record);
4748         if (del_record)
4749                 free(del_record);
4750         if (del_pool)
4751                 free(del_pool);
4752
4753         return rc;
4754 }
4755
4756 /**
4757  * List pool information by config log
4758  *
4759  * \param fsname[in]    pointer to filesystem name
4760  * \param poolname[in]  pointer to pool name
4761  *
4762  * \retval              0 on success
4763  *                      < 0 on error
4764  */
4765 int llog_poollist(char *fsname, char *poolname)
4766 {
4767         char logname[MAX_OBD_NAME] = {'\0'};
4768         struct llog_pool_list_data lpld;
4769         struct llog_pool_name *tmp;
4770         struct list_head *head;
4771         int rc = 0;
4772
4773         if (fsname && fsname[0] == '\0')
4774                 fsname = NULL;
4775         if (!fsname)
4776                 return -EINVAL;
4777
4778         memset(&lpld, 0, sizeof(lpld));
4779         INIT_LIST_HEAD(&lpld.lpld_list_head);
4780         lpld.lpld_exists = false;
4781         strncpy(lpld.lpld_fsname, fsname, sizeof(lpld.lpld_fsname) - 1);
4782         if (poolname && poolname[0])
4783                 strncpy(lpld.lpld_poolname, poolname,
4784                         sizeof(lpld.lpld_poolname) - 1);
4785         snprintf(logname, sizeof(logname), "%s-client", fsname);
4786         rc = jt_llog_print_iter(logname, 0, -1, llog_poollist_cb, &lpld, false);
4787
4788         if (poolname && poolname[0])
4789                 printf("Pool: %s.%s\n", fsname, poolname);
4790         else
4791                 printf("Pools from %s:\n", fsname);
4792
4793         head = &lpld.lpld_list_head;
4794         if (poolname && poolname[0] && !lpld.lpld_exists && list_empty(head))
4795                 return -ENOENT;
4796
4797         list_for_each_entry(tmp, head, lpn_list) {
4798                 if (poolname && poolname[0])
4799                         printf("%s\n", tmp->lpn_name);
4800                 else
4801                         printf("%s.%s\n", fsname, tmp->lpn_name);
4802                 list_del(&tmp->lpn_list);
4803                 free(tmp);
4804         }
4805
4806         return rc;
4807 }
4808
4809 static bool get_pools_path(char *fsname)
4810 {
4811         glob_t path;
4812         int rc;
4813
4814         rc = cfs_get_param_paths(&path, "lov/%s-*/pools", fsname);
4815         if (!rc)
4816                 cfs_free_param_data(&path);
4817
4818         return (rc == 0);
4819 }
4820
4821 static int extract_fsname_poolname(char **argv, char *fsname,
4822                                    char *poolname)
4823 {
4824         char *cmd = argv[0], *param = argv[1];
4825         char *ptr;
4826         int rc;
4827
4828         snprintf(fsname, PATH_MAX + 1, "%s", param);
4829         ptr = strchr(fsname, '.');
4830         if (ptr == NULL) {
4831                 if (strcmp(cmd, "pool_list") == 0) {
4832                         poolname = NULL;
4833                         goto out;
4834                 }
4835                 fprintf(stderr, ". is missing in %s\n", fsname);
4836                 rc = -EINVAL;
4837                 goto err;
4838         }
4839
4840         if ((ptr - fsname) == 0) {
4841                 fprintf(stderr, "fsname is empty\n");
4842                 rc = -EINVAL;
4843                 goto err;
4844         }
4845
4846         *ptr = '\0';
4847         ++ptr;
4848
4849         if (strlen(ptr) == 0) {
4850                 fprintf(stderr, "poolname is empty\n");
4851                 rc = -EINVAL;
4852                 goto err;
4853         }
4854
4855         strncpy(poolname, ptr, LOV_MAXPOOLNAME);
4856         poolname[LOV_MAXPOOLNAME] = '\0';
4857
4858         if (strncmp(poolname, "none", LOV_MAXPOOLNAME) == 0) {
4859                 fprintf(stderr, "poolname cannot be 'none'\n");
4860                 return -EINVAL;
4861         }
4862 out:
4863         return 0;
4864
4865 err:
4866         fprintf(stderr, "argument %s must be <fsname>.<poolname>\n", param);
4867         return rc;
4868 }
4869
4870 int jt_pool_cmd(int argc, char **argv)
4871 {
4872         enum lcfg_command_type cmd;
4873         char fsname[PATH_MAX + 1];
4874         char poolname[LOV_MAXPOOLNAME + 1];
4875         char *ostnames_buf = NULL;
4876         int i, rc;
4877         int *array = NULL, array_sz;
4878         struct {
4879                 int     rc;
4880                 char   *ostname;
4881         } *cmds = NULL;
4882
4883         switch (argc) {
4884         case 0:
4885         case 1: return CMD_HELP;
4886         case 2: {
4887                 rc = extract_fsname_poolname(argv, fsname, poolname);
4888                 if (rc)
4889                         break;
4890
4891                 if (strcmp("pool_new", argv[0]) == 0) {
4892                         cmd = LCFG_POOL_NEW;
4893                 } else if (strcmp("pool_destroy", argv[0]) == 0) {
4894                         cmd = LCFG_POOL_DEL;
4895                 } else if (strcmp("pool_list", argv[0]) == 0) {
4896                         if (get_pools_path(fsname))
4897                                 return llapi_poollist(argv[1]);
4898                         if (get_mgs_device() > 0)
4899                                 return llog_poollist(fsname, poolname);
4900                         fprintf(stderr, "Cannot run pool_list command "
4901                                 "since there is no local MGS/MDT or client\n");
4902                         return CMD_HELP;
4903                 } else {
4904                         return CMD_HELP;
4905                 }
4906
4907                 rc = pool_cmd(cmd, argv[0], argv[1], fsname, poolname, NULL);
4908                 if (rc)
4909                         break;
4910
4911                 check_pool_cmd_result(cmd, fsname, poolname, NULL);
4912                 break;
4913         }
4914         default: {
4915                 char format[2 * MAX_OBD_NAME];
4916
4917                 if (strcmp("pool_remove", argv[0]) == 0)
4918                         cmd = LCFG_POOL_REM;
4919                 else if (strcmp("pool_add", argv[0]) == 0)
4920                         cmd = LCFG_POOL_ADD;
4921                 else
4922                         return CMD_HELP;
4923
4924                 rc = extract_fsname_poolname(argv, fsname, poolname);
4925                 if (rc)
4926                         break;
4927
4928                 for (i = 2; i < argc; i++) {
4929                         int j;
4930
4931                         array_sz = get_array_idx(argv[i], format, &array);
4932                         if (array_sz == 0)
4933                                 return CMD_HELP;
4934
4935                         cmds = malloc(array_sz * sizeof(cmds[0]));
4936                         if (cmds != NULL) {
4937                                 ostnames_buf = malloc(array_sz *
4938                                                       (MAX_OBD_NAME + 1));
4939                         } else {
4940                                 free(array);
4941                                 rc = -ENOMEM;
4942                                 goto out;
4943                         }
4944
4945                         for (j = 0; j < array_sz; j++) {
4946                                 char ostname[MAX_OBD_NAME + 1];
4947
4948                                 snprintf(ostname, MAX_OBD_NAME, format,
4949                                          array[j]);
4950                                 ostname[MAX_OBD_NAME] = '\0';
4951
4952                                 rc = check_and_complete_ostname(fsname,ostname);
4953                                 if (rc) {
4954                                         free(array);
4955                                         free(cmds);
4956                                         if (ostnames_buf)
4957                                                 free(ostnames_buf);
4958                                         goto out;
4959                                 }
4960                                 if (ostnames_buf != NULL) {
4961                                         cmds[j].ostname =
4962                                           &ostnames_buf[(MAX_OBD_NAME + 1) * j];
4963                                         strcpy(cmds[j].ostname, ostname);
4964                                 } else {
4965                                         cmds[j].ostname = NULL;
4966                                 }
4967                                 cmds[j].rc = pool_cmd(cmd, argv[0], argv[1],
4968                                                       fsname, poolname,
4969                                                       ostname);
4970                                 /* Return an err if any of the add/dels fail */
4971                                 if (!rc)
4972                                         rc = cmds[j].rc;
4973                         }
4974                         for (j = 0; j < array_sz; j++) {
4975                                 if (!cmds[j].rc) {
4976                                         char ostname[MAX_OBD_NAME + 1];
4977
4978                                         if (!cmds[j].ostname) {
4979                                                 snprintf(ostname, MAX_OBD_NAME,
4980                                                          format, array[j]);
4981                                                 ostname[MAX_OBD_NAME] = '\0';
4982                                                 check_and_complete_ostname(
4983                                                         fsname, ostname);
4984                                         } else {
4985                                                 strcpy(ostname,
4986                                                        cmds[j].ostname);
4987                                         }
4988                                         check_pool_cmd_result(cmd, fsname,
4989                                                               poolname,ostname);
4990                                 }
4991                         }
4992                         if (array_sz > 0)
4993                                 free(array);
4994                         if (cmds)
4995                                 free(cmds);
4996                         if (ostnames_buf != NULL)
4997                                 free(ostnames_buf);
4998                 }
4999                 /* fall through */
5000         }
5001         } /* switch */
5002
5003 out:
5004         if (rc != 0) {
5005                 errno = -rc;
5006                 perror(argv[0]);
5007         }
5008
5009         return rc;
5010 }
5011
5012 #ifdef HAVE_SERVER_SUPPORT
5013 static const char *barrier_status2name(enum barrier_status status)
5014 {
5015         switch (status) {
5016         case BS_INIT:
5017                 return "init";
5018         case BS_FREEZING_P1:
5019                 return "freezing_p1";
5020         case BS_FREEZING_P2:
5021                 return "freezing_p2";
5022         case BS_FROZEN:
5023                 return "frozen";
5024         case BS_THAWING:
5025                 return "thawing";
5026         case BS_THAWED:
5027                 return "thawed";
5028         case BS_FAILED:
5029                 return "failed";
5030         case BS_EXPIRED:
5031                 return "expired";
5032         case BS_RESCAN:
5033                 return "rescan";
5034         default:
5035                 return "unknown";
5036         }
5037 }
5038
5039 int jt_barrier_freeze(int argc, char **argv)
5040 {
5041         struct obd_ioctl_data data;
5042         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
5043         struct barrier_ctl bc;
5044         int rc;
5045
5046         if (argc < 2 || argc > 3)
5047                 return CMD_HELP;
5048
5049         memset(&data, 0, sizeof(data));
5050         rc = data.ioc_dev = get_mgs_device();
5051         if (rc < 0)
5052                 return rc;
5053
5054         memset(&bc, 0, sizeof(bc));
5055         bc.bc_version = BARRIER_VERSION_V1;
5056         bc.bc_cmd = BC_FREEZE;
5057         if (argc == 3)
5058                 bc.bc_timeout = atoi(argv[2]);
5059         if (bc.bc_timeout == 0)
5060                 bc.bc_timeout = BARRIER_TIMEOUT_DEFAULT;
5061
5062         if (strlen(argv[1]) > 8) {
5063                 fprintf(stderr, "%s: fsname name %s is too long. "
5064                         "It should not exceed 8.\n", argv[0], argv[1]);
5065                 return -EINVAL;
5066         }
5067
5068         strncpy(bc.bc_name, argv[1], sizeof(bc.bc_name));
5069         data.ioc_inlbuf1 = (char *)&bc;
5070         data.ioc_inllen1 = sizeof(bc);
5071         memset(buf, 0, sizeof(rawbuf));
5072         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
5073         if (rc) {
5074                 fprintf(stderr, "Fail to pack ioctl data: rc = %d.\n", rc);
5075                 return rc;
5076         }
5077
5078         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_BARRIER, buf);
5079         if (rc < 0)
5080                 fprintf(stderr, "Fail to freeze barrier for %s: %s\n",
5081                         argv[1], strerror(errno));
5082
5083         return rc;
5084 }
5085
5086 int jt_barrier_thaw(int argc, char **argv)
5087 {
5088         struct obd_ioctl_data data;
5089         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
5090         struct barrier_ctl bc;
5091         int rc;
5092
5093         if (argc != 2)
5094                 return CMD_HELP;
5095
5096         memset(&data, 0, sizeof(data));
5097         rc = data.ioc_dev = get_mgs_device();
5098         if (rc < 0)
5099                 return rc;
5100
5101         memset(&bc, 0, sizeof(bc));
5102         bc.bc_version = BARRIER_VERSION_V1;
5103         bc.bc_cmd = BC_THAW;
5104
5105         if (strlen(argv[1]) > 8) {
5106                 fprintf(stderr, "fsname name %s is too long. "
5107                         "It should not exceed 8.\n", argv[1]);
5108                 return -EINVAL;
5109         }
5110
5111         strncpy(bc.bc_name, argv[1], sizeof(bc.bc_name));
5112         data.ioc_inlbuf1 = (char *)&bc;
5113         data.ioc_inllen1 = sizeof(bc);
5114         memset(buf, 0, sizeof(rawbuf));
5115         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
5116         if (rc) {
5117                 fprintf(stderr, "Fail to pack ioctl data: rc = %d.\n", rc);
5118                 return rc;
5119         }
5120
5121         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_BARRIER, buf);
5122         if (rc < 0)
5123                 fprintf(stderr, "Fail to thaw barrier for %s: %s\n",
5124                         argv[1], strerror(errno));
5125
5126         return rc;
5127 }
5128
5129 int __jt_barrier_stat(const char *fsname, struct barrier_ctl *bc)
5130 {
5131         struct obd_ioctl_data data;
5132         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
5133         int rc;
5134
5135         memset(&data, 0, sizeof(data));
5136         rc = data.ioc_dev = get_mgs_device();
5137         if (rc < 0)
5138                 return rc;
5139
5140         memset(bc, 0, sizeof(*bc));
5141         bc->bc_version = BARRIER_VERSION_V1;
5142         bc->bc_cmd = BC_STAT;
5143         strncpy(bc->bc_name, fsname, sizeof(bc->bc_name) - 1);
5144         data.ioc_inlbuf1 = (char *)bc;
5145         data.ioc_inllen1 = sizeof(*bc);
5146         memset(buf, 0, sizeof(rawbuf));
5147         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
5148         if (rc) {
5149                 fprintf(stderr, "Fail to pack ioctl data: rc = %d.\n", rc);
5150                 return rc;
5151         }
5152
5153         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_BARRIER, buf);
5154         if (rc < 0)
5155                 fprintf(stderr, "Fail to query barrier for %s: %s\n",
5156                         fsname, strerror(errno));
5157         else
5158                 llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
5159
5160         return rc;
5161 }
5162
5163 int jt_barrier_stat(int argc, char **argv)
5164 {
5165         struct barrier_ctl bc;
5166         static struct option long_opt_barrier_stat[] = {
5167                 {
5168                         .val            = 's',
5169                         .name           = "state",
5170                         .has_arg        = no_argument,
5171                 },
5172                 {       .val            = 't',
5173                         .name           = "timeout",
5174                         .has_arg        = no_argument,
5175                 },
5176                 {
5177                         NULL
5178                 }
5179         };
5180         const char *name;
5181         int index;
5182         int opt;
5183         int rc;
5184         bool state = false;
5185         bool timeout = false;
5186
5187         while ((opt = getopt_long(argc, argv, "st", long_opt_barrier_stat,
5188                                   &index)) != EOF) {
5189                 switch (opt) {
5190                 case 's':
5191                         state = true;
5192                         break;
5193                 case 't':
5194                         timeout = true;
5195                         break;
5196                 default:
5197                         return CMD_HELP;
5198                 }
5199         }
5200
5201         if (optind >= argc)
5202                 return CMD_HELP;
5203
5204         name = argv[optind];
5205         if (strlen(name) > 8) {
5206                 fprintf(stderr, "fsname name %s is too long. "
5207                         "It should not exceed 8.\n", name);
5208                 return -EINVAL;
5209         }
5210
5211         rc = __jt_barrier_stat(name, &bc);
5212         if (!rc) {
5213                 if (state && !timeout)
5214                         printf("%s\n", barrier_status2name(bc.bc_status));
5215                 else if (timeout && !state)
5216                         printf("%d\n",
5217                                (bc.bc_status == BS_FREEZING_P1 ||
5218                                 bc.bc_status == BS_FREEZING_P2 ||
5219                                 bc.bc_status == BS_FROZEN) ?
5220                                bc.bc_timeout : 0);
5221                 else
5222                         printf("state: %s\ntimeout: %d seconds\n",
5223                                barrier_status2name(bc.bc_status),
5224                                (bc.bc_status == BS_FREEZING_P1 ||
5225                                 bc.bc_status == BS_FREEZING_P2 ||
5226                                 bc.bc_status == BS_FROZEN) ?
5227                                bc.bc_timeout : 0);
5228         }
5229
5230         return rc;
5231 }
5232
5233 int jt_barrier_rescan(int argc, char **argv)
5234 {
5235         struct obd_ioctl_data data;
5236         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
5237         struct barrier_ctl bc;
5238         int rc;
5239
5240         if (argc < 2 || argc > 3)
5241                 return CMD_HELP;
5242
5243         memset(&data, 0, sizeof(data));
5244         rc = data.ioc_dev = get_mgs_device();
5245         if (rc < 0)
5246                 return rc;
5247
5248         memset(&bc, 0, sizeof(bc));
5249         bc.bc_version = BARRIER_VERSION_V1;
5250         bc.bc_cmd = BC_RESCAN;
5251         if (argc == 3)
5252                 bc.bc_timeout = atoi(argv[2]);
5253         if (bc.bc_timeout == 0)
5254                 bc.bc_timeout = BARRIER_TIMEOUT_DEFAULT;
5255
5256         if (strlen(argv[1]) > 8) {
5257                 fprintf(stderr, "fsname name %s is too long. "
5258                         "It should not exceed 8.\n", argv[1]);
5259                 return -EINVAL;
5260         }
5261
5262         strncpy(bc.bc_name, argv[1], sizeof(bc.bc_name));
5263         data.ioc_inlbuf1 = (char *)&bc;
5264         data.ioc_inllen1 = sizeof(bc);
5265         memset(buf, 0, sizeof(rawbuf));
5266         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
5267         if (rc) {
5268                 fprintf(stderr, "Fail to pack ioctl data: rc = %d.\n", rc);
5269                 return rc;
5270         }
5271
5272         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_BARRIER, buf);
5273         if (rc < 0) {
5274                 fprintf(stderr, "Fail to rescan barrier bitmap for %s: %s\n",
5275                         argv[1], strerror(errno));
5276         } else {
5277                 llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
5278                 printf("%u of %u MDT(s) in the filesystem %s are inactive\n",
5279                        bc.bc_absence, bc.bc_total, argv[1]);
5280         }
5281
5282         return rc;
5283 }
5284 #endif /* HAVE_SERVER_SUPPORT */
5285
5286 int jt_get_obj_version(int argc, char **argv)
5287 {
5288         struct lu_fid fid;
5289         struct obd_ioctl_data data;
5290         __u64 version, id = ULLONG_MAX, group = ULLONG_MAX;
5291         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf, *fidstr;
5292         int rc, c;
5293
5294         while ((c = getopt(argc, argv, "i:g:")) != -1) {
5295                 switch (c) {
5296                 case 'i':
5297                         id = strtoull(optarg, NULL, 0);
5298                         break;
5299                 case 'g':
5300                         group = strtoull(optarg, NULL, 0);
5301                         break;
5302                 default:
5303                         return CMD_HELP;
5304                 }
5305         }
5306
5307         argc -= optind;
5308         fidstr = *(argv + optind);
5309
5310         if (!(id != ULLONG_MAX && group != ULLONG_MAX && argc == 0) &&
5311             !(id == ULLONG_MAX && group == ULLONG_MAX && argc == 1))
5312                 return CMD_HELP;
5313
5314         memset(&data, 0, sizeof data);
5315         data.ioc_dev = cur_device;
5316         if (argc == 1) {
5317                 rc = llapi_fid_parse(fidstr, &fid, NULL);
5318                 if (rc) {
5319                         fprintf(stderr, "%s: error parsing FID '%s': %s\n",
5320                                 jt_cmdname(argv[0]), fidstr, strerror(-rc));
5321                         return rc;
5322                 }
5323
5324                 data.ioc_inlbuf1 = (char *)&fid;
5325                 data.ioc_inllen1 = sizeof(fid);
5326         } else {
5327                 data.ioc_inlbuf3 = (char *)&id;
5328                 data.ioc_inllen3 = sizeof(id);
5329                 data.ioc_inlbuf4 = (char *)&group;
5330                 data.ioc_inllen4 = sizeof(group);
5331         }
5332         data.ioc_inlbuf2 = (char *) &version;
5333         data.ioc_inllen2 = sizeof version;
5334
5335         memset(buf, 0, sizeof *buf);
5336         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
5337         if (rc) {
5338                 fprintf(stderr, "error: %s: packing ioctl arguments: %s\n",
5339                         jt_cmdname(argv[0]), strerror(-rc));
5340                 return rc;
5341         }
5342
5343         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_GET_OBJ_VERSION, buf);
5344         if (rc == -1) {
5345                 fprintf(stderr, "error: %s: ioctl: %s\n",
5346                         jt_cmdname(argv[0]), strerror(errno));
5347                 return -errno;
5348         }
5349
5350         llapi_ioctl_unpack(&data, buf, sizeof rawbuf);
5351         printf("%#jx\n", (uintmax_t)version);
5352
5353         return 0;
5354 }
5355
5356 int jt_changelog_register(int argc, char **argv)
5357 {
5358         struct obd_ioctl_data    data = { 0 };
5359         char                     rawbuf[MAX_IOC_BUFLEN] = "";
5360         char                    *buf = rawbuf;
5361         char                    *device = lcfg_get_devname();
5362         bool                     print_name_only = false;
5363         int                      c;
5364         int                      rc;
5365
5366         if (argc > 2)
5367                 return CMD_HELP;
5368
5369         while ((c = getopt(argc, argv, "hn")) >= 0) {
5370                 switch (c) {
5371                 case 'n':
5372                         print_name_only = true;
5373                         break;
5374                 case 'h':
5375                 default:
5376                         return CMD_HELP;
5377                 }
5378         }
5379
5380         if (cur_device < 0 || device == NULL)
5381                 return CMD_HELP;
5382
5383         data.ioc_dev = cur_device;
5384
5385         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
5386         if (rc < 0) {
5387                 fprintf(stderr, "error: %s: cannot pack ioctl: %s\n",
5388                         jt_cmdname(argv[0]), strerror(-rc));
5389                return rc;
5390         }
5391
5392         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_CHANGELOG_REG, buf);
5393         if (rc < 0) {
5394                 rc = -errno;
5395                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
5396                         strerror(-rc));
5397                 return rc;
5398         }
5399
5400         llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
5401
5402         if (data.ioc_u32_1 == 0) {
5403                 fprintf(stderr, "received invalid userid!\n");
5404                 return -EPROTO;
5405         }
5406
5407         if (print_name_only)
5408                 printf("%s%u\n", CHANGELOG_USER_PREFIX, data.ioc_u32_1);
5409         else
5410                 printf("%s: Registered changelog userid '%s%u'\n",
5411                        device, CHANGELOG_USER_PREFIX, data.ioc_u32_1);
5412
5413         return 0;
5414 }
5415
5416 int jt_changelog_deregister(int argc, char **argv)
5417 {
5418         struct obd_ioctl_data    data = { 0 };
5419         char                     rawbuf[MAX_IOC_BUFLEN] = "";
5420         char                    *buf = rawbuf;
5421         char                    *device = lcfg_get_devname();
5422         int                      id;
5423         int                      rc;
5424
5425         if (argc != 2 || cur_device < 0 || device == NULL)
5426                 return CMD_HELP;
5427
5428         rc = sscanf(argv[1], CHANGELOG_USER_PREFIX"%d", &id);
5429         if (rc != 1 || id <= 0) {
5430                 fprintf(stderr,
5431                         "error: %s: expected id of the form %s<num> got '%s'\n",
5432                         jt_cmdname(argv[0]), CHANGELOG_USER_PREFIX, argv[1]);
5433                 return CMD_HELP;
5434         }
5435
5436         data.ioc_dev = cur_device;
5437         data.ioc_u32_1 = id;
5438
5439         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
5440         if (rc < 0) {
5441                 fprintf(stderr, "error: %s: invalid ioctl\n",
5442                         jt_cmdname(argv[0]));
5443                 return rc;
5444         }
5445
5446         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_CHANGELOG_DEREG, buf);
5447         if (rc < 0) {
5448                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
5449                         strerror(rc = errno));
5450                 return rc;
5451         }
5452
5453         llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
5454         printf("%s: Deregistered changelog user '%s%u'\n",
5455                device, CHANGELOG_USER_PREFIX, data.ioc_u32_1);
5456
5457         return 0;
5458 }
5459
5460 int jt_pcc_add(int argc, char **argv)
5461 {
5462         struct option long_opts[] = {
5463                 { .val = 'p', .name = "param", .has_arg = required_argument },
5464                 { .name = NULL } };
5465         const char *mntpath;
5466         const char *pccpath;
5467         char *param = NULL;
5468         char cmd[PATH_MAX];
5469         int rc;
5470
5471         optind = 1;
5472         while ((rc = getopt_long(argc, argv, "p:",
5473                 long_opts, NULL)) != -1) {
5474                 switch (rc) {
5475                 case 'p':
5476                         param = optarg;
5477                         break;
5478                 default:
5479                         return CMD_HELP;
5480                 }
5481         }
5482
5483         if (!param) {
5484                 fprintf(stderr, "%s: must specify the config param for PCC\n",
5485                         jt_cmdname(argv[0]));
5486                 return CMD_HELP;
5487         }
5488
5489         if (optind + 2 != argc) {
5490                 fprintf(stderr,
5491                         "%s: must specify mount path and PCC path %d:%d\n",
5492                         jt_cmdname(argv[0]), optind, argc);
5493                 return CMD_HELP;
5494         }
5495
5496         mntpath = argv[optind++];
5497         pccpath = argv[optind];
5498
5499         snprintf(cmd, PATH_MAX, "add %s %s", pccpath, param);
5500         rc = llapi_pccdev_set(mntpath, cmd);
5501         if (rc < 0)
5502                 fprintf(stderr, "%s: failed to run '%s' on %s\n",
5503                         jt_cmdname(argv[0]), cmd, mntpath);
5504
5505         return rc;
5506 }
5507
5508 int jt_pcc_del(int argc, char **argv)
5509 {
5510         const char *mntpath;
5511         const char *pccpath;
5512         char cmd[PATH_MAX];
5513         int rc;
5514
5515         optind = 1;
5516         if (argc != 3) {
5517                 fprintf(stderr, "%s: require 3 arguments\n",
5518                         jt_cmdname(argv[0]));
5519                 return CMD_HELP;
5520         }
5521
5522         mntpath = argv[optind++];
5523         pccpath = argv[optind++];
5524
5525         snprintf(cmd, PATH_MAX, "del %s", pccpath);
5526         rc = llapi_pccdev_set(mntpath, cmd);
5527         if (rc < 0)
5528                 fprintf(stderr, "%s: failed to run '%s' on %s\n",
5529                         jt_cmdname(argv[0]), cmd, mntpath);
5530
5531         return rc;
5532 }
5533
5534 int jt_pcc_clear(int argc, char **argv)
5535 {
5536         const char *mntpath;
5537         int rc;
5538
5539         optind = 1;
5540         if (argc != 2) {
5541                 fprintf(stderr, "%s: require 2 arguments\n",
5542                         jt_cmdname(argv[0]));
5543                 return CMD_HELP;
5544         }
5545
5546         mntpath = argv[optind];
5547         rc = llapi_pccdev_set(mntpath, "clear");
5548         if (rc < 0)
5549                 fprintf(stderr, "%s: failed to run 'clear' on %s\n",
5550                         jt_cmdname(argv[0]), mntpath);
5551
5552         return rc;
5553 }
5554
5555 int jt_pcc_list(int argc, char **argv)
5556 {
5557         const char *mntpath;
5558         int rc;
5559
5560         optind = 1;
5561         if (argc != 2) {
5562                 fprintf(stderr, "%s: require 2 arguments\n",
5563                         jt_cmdname(argv[0]));
5564                 return CMD_HELP;
5565         }
5566
5567         mntpath = argv[optind];
5568         rc = llapi_pccdev_get(mntpath);
5569         if (rc < 0)
5570                 fprintf(stderr, "%s: failed to run 'pcc list' on %s\n",
5571                         jt_cmdname(argv[0]), mntpath);
5572
5573         return rc;
5574 }