Whamcloud - gitweb
LU-5170 utils: Add support for --list-commands option
[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, 2016, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  *
32  * 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
62 #include "obdctl.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 <lnet/nidstr.h>
70 #include <lustre/lustre_ostid.h>
71 #include <lustre_cfg.h>
72 #include <lustre_ioctl.h>
73 #include <lustre_ver.h>
74
75 #include <lnet/lnetctl.h>
76 #include <lustre/lustreapi.h>
77 #include <lustre_param.h>
78
79 #define MAX_STRING_SIZE 128
80
81 #if HAVE_LIBPTHREAD
82 #include <sys/ipc.h>
83 #include <sys/shm.h>
84 #include <pthread.h>
85
86 #define MAX_THREADS 4096
87 #define MAX_BASE_ID 0xffffffff
88 #define NIDSTRING_LENGTH 64
89 struct shared_data {
90         pthread_mutex_t mutex;
91         pthread_cond_t  cond;
92         int       stopping;
93         struct {
94                 __u64 counters[MAX_THREADS];
95                 __u64 offsets[MAX_THREADS];
96                 int   thr_running;
97                 int   start_barrier;
98                 int   stop_barrier;
99                 struct timeval start_time;
100                 struct timeval end_time;
101         } body;
102 };
103
104 static struct shared_data *shared_data;
105 static __u64 counter_snapshot[2][MAX_THREADS];
106 static int prev_valid;
107 static struct timeval prev_time;
108 static int thread;
109 static int nthreads;
110 #else
111 const int thread = 0;
112 const int nthreads = 1;
113 #endif
114
115 static int cur_device = -1;
116
117 static int l2_ioctl(int dev_id, int opc, void *buf)
118 {
119         return l_ioctl(dev_id, opc, buf);
120 }
121
122 int lcfg_ioctl(char * func, int dev_id, struct lustre_cfg *lcfg)
123 {
124         struct obd_ioctl_data data;
125         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
126         int rc;
127
128         memset(&data, 0, sizeof(data));
129         data.ioc_dev = cur_device;
130         data.ioc_type = LUSTRE_CFG_TYPE;
131         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
132                                         lcfg->lcfg_buflens);
133         data.ioc_pbuf1 = (void *)lcfg;
134         memset(buf, 0, sizeof(rawbuf));
135         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
136         if (rc) {
137                 fprintf(stderr, "error: %s: invalid ioctl\n",
138                         jt_cmdname(func));
139                 return rc;
140         }
141
142         rc =  l_ioctl(dev_id, OBD_IOC_PROCESS_CFG, buf);
143
144         return rc;
145 }
146
147 static int do_device(char *func, char *devname);
148
149 static int get_mgs_device()
150 {
151         char mgs[] = "$MGS";
152         static int mgs_device = -1;
153
154         if (mgs_device == -1) {
155                 int rc;
156                 do_disconnect(NULL, 1);
157                 rc = do_device("mgsioc", mgs);
158                 if (rc) {
159                         fprintf(stderr,
160                                 "This command must be run on the MGS.\n");
161                         errno = ENODEV;
162                         return -1;
163                 }
164                 mgs_device = cur_device;
165         }
166         return mgs_device;
167 }
168
169 /* Returns -1 on error with errno set */
170 int lcfg_mgs_ioctl(char *func, int dev_id, struct lustre_cfg *lcfg)
171 {
172         struct obd_ioctl_data data;
173         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
174         int rc;
175
176         memset(&data, 0, sizeof(data));
177         rc = data.ioc_dev = get_mgs_device();
178         if (rc < 0)
179                 goto out;
180         data.ioc_type = LUSTRE_CFG_TYPE;
181         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
182                                         lcfg->lcfg_buflens);
183         data.ioc_pbuf1 = (void *)lcfg;
184         memset(buf, 0, sizeof(rawbuf));
185         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
186         if (rc) {
187                 fprintf(stderr, "error: %s: invalid ioctl\n",
188                         jt_cmdname(func));
189                 return rc;
190         }
191
192         rc = l_ioctl(dev_id, OBD_IOC_PARAM, buf);
193 out:
194         if (rc) {
195                 if (errno == ENOSYS)
196                         fprintf(stderr, "Make sure cfg_device is set first.\n");
197         }
198         return rc;
199 }
200
201 char *obdo_print(struct obdo *obd)
202 {
203         char buf[1024];
204
205         snprintf(buf, sizeof(buf), "id: %#jx\ngrp: %#jx\natime: %ju\n"
206                  "mtime: %ju\nctime: %ju\nsize: %ju\nblocks: %ju"
207                  "\nblksize: %u\nmode: %o\nuid: %d\ngid: %d\nflags: %x\n"
208                  "misc: %x\nnlink: %d,\nvalid %#jx\n",
209                  (uintmax_t)ostid_id(&obd->o_oi),
210                  (uintmax_t)ostid_seq(&obd->o_oi),
211                  (uintmax_t)obd->o_atime, (uintmax_t)obd->o_mtime,
212                  (uintmax_t)obd->o_ctime, (uintmax_t)obd->o_size,
213                  (uintmax_t)obd->o_blocks, obd->o_blksize, obd->o_mode,
214                  obd->o_uid, obd->o_gid, obd->o_flags, obd->o_misc,
215                  obd->o_nlink, (uintmax_t)obd->o_valid);
216         return strdup(buf);
217 }
218
219
220 #define BAD_VERBOSE (-999999999)
221
222 #define N2D_OFF 0x100      /* So we can tell between error codes and devices */
223
224 static int do_name2dev(char *func, char *name)
225 {
226         struct obd_ioctl_data data;
227         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
228         int rc;
229
230         memset(&data, 0, sizeof(data));
231         data.ioc_dev = cur_device;
232         data.ioc_inllen1 = strlen(name) + 1;
233         data.ioc_inlbuf1 = name;
234
235         memset(buf, 0, sizeof(rawbuf));
236         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
237         if (rc < 0) {
238                 fprintf(stderr, "error: %s: invalid ioctl\n",
239                         jt_cmdname(func));
240                 return -rc;
241         }
242         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_NAME2DEV, buf);
243         if (rc < 0)
244                 return errno;
245         rc = obd_ioctl_unpack(&data, buf, sizeof(rawbuf));
246         if (rc) {
247                 fprintf(stderr, "error: %s: invalid reply\n",
248                         jt_cmdname(func));
249                 return rc;
250         }
251
252         return data.ioc_dev + N2D_OFF;
253 }
254
255 /*
256  * resolve a device name to a device number.
257  * supports a number, $name or %uuid.
258  */
259 int parse_devname(char *func, char *name)
260 {
261         int rc;
262         int ret = -1;
263
264         if (!name)
265                 return ret;
266         if (isdigit(name[0])) {
267                 ret = strtoul(name, NULL, 0);
268         } else {
269                 if (name[0] == '$' || name[0] == '%')
270                         name++;
271                 rc = do_name2dev(func, name);
272                 if (rc >= N2D_OFF) {
273                         ret = rc - N2D_OFF;
274                         // printf("Name %s is device %d\n", name, ret);
275                 } else {
276                         fprintf(stderr, "No device found for name %s: %s\n",
277                                 name, strerror(rc));
278                 }
279         }
280         return ret;
281 }
282
283 char *jt_cmdname(char *func)
284 {
285         static char buf[512];
286
287         if (thread) {
288                 sprintf(buf, "%s-%d", func, thread);
289                 return buf;
290         }
291
292         return func;
293 }
294
295 #define difftime(a, b)                                  \
296         ((a)->tv_sec - (b)->tv_sec +                    \
297          ((a)->tv_usec - (b)->tv_usec) / 1000000.0)
298
299 static int be_verbose(int verbose, struct timeval *next_time,
300                       __u64 num, __u64 *next_num, int num_total)
301 {
302         struct timeval now;
303
304         if (!verbose)
305                 return 0;
306
307         if (next_time != NULL)
308                 gettimeofday(&now, NULL);
309
310         /* A positive verbosity means to print every X iterations */
311         if (verbose > 0 && (num >= *next_num || num >= num_total)) {
312                 *next_num += verbose;
313                 if (next_time) {
314                         next_time->tv_sec = now.tv_sec - verbose;
315                         next_time->tv_usec = now.tv_usec;
316                 }
317                 return 1;
318         }
319
320         /* A negative verbosity means to print at most each X seconds */
321         if (verbose < 0 && next_time != NULL &&
322             difftime(&now, next_time) >= 0.0){
323                 next_time->tv_sec = now.tv_sec - verbose;
324                 next_time->tv_usec = now.tv_usec;
325                 *next_num = num;
326                 return 1;
327         }
328
329         return 0;
330 }
331
332 static int get_verbose(char *func, const char *arg)
333 {
334         int verbose;
335         char *end;
336
337         if (!arg || arg[0] == 'v')
338                 verbose = 1;
339         else if (arg[0] == 's' || arg[0] == 'q')
340                 verbose = 0;
341         else {
342                 verbose = (int)strtoul(arg, &end, 0);
343                 if (*end) {
344                         fprintf(stderr, "error: %s: bad verbose option '%s'\n",
345                                 jt_cmdname(func), arg);
346                         return BAD_VERBOSE;
347                 }
348         }
349
350         if (verbose < 0)
351                 printf("Print status every %d seconds\n", -verbose);
352         else if (verbose == 1)
353                 printf("Print status every operation\n");
354         else if (verbose > 1)
355                 printf("Print status every %d operations\n", verbose);
356
357         return verbose;
358 }
359
360 int do_disconnect(char *func, int verbose)
361 {
362         lcfg_set_devname(NULL);
363         cur_device = -1;
364         return 0;
365 }
366
367 #ifdef MAX_THREADS
368 static int shmem_setup(void)
369 {
370         pthread_mutexattr_t mattr;
371         pthread_condattr_t  cattr;
372         int                 rc;
373         int                 shmid;
374
375         /* Create new segment */
376         shmid = shmget(IPC_PRIVATE, sizeof(*shared_data), 0600);
377         if (shmid == -1) {
378                 fprintf(stderr, "Can't create shared data: %s\n",
379                         strerror(errno));
380                 return errno;
381         }
382
383         /* Attatch to new segment */
384         shared_data = (struct shared_data *)shmat(shmid, NULL, 0);
385
386         if (shared_data == (struct shared_data *)(-1)) {
387                 fprintf(stderr, "Can't attach shared data: %s\n",
388                         strerror(errno));
389                 shared_data = NULL;
390                 return errno;
391         }
392
393         /* Mark segment as destroyed, so it will disappear when we exit.
394          * Forks will inherit attached segments, so we should be OK.
395          */
396         if (shmctl(shmid, IPC_RMID, NULL) == -1) {
397                 fprintf(stderr, "Can't destroy shared data: %s\n",
398                         strerror(errno));
399                 return errno;
400         }
401
402         pthread_mutexattr_init(&mattr);
403         pthread_condattr_init(&cattr);
404
405         rc = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
406         if (rc != 0) {
407                 fprintf(stderr, "Can't set shared mutex attr\n");
408                 goto out;
409         }
410
411         rc = pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
412         if (rc != 0) {
413                 fprintf(stderr, "Can't set shared cond attr\n");
414                 goto out;
415         }
416
417         pthread_mutex_init(&shared_data->mutex, &mattr);
418         pthread_cond_init(&shared_data->cond, &cattr);
419 out:
420         pthread_mutexattr_destroy(&mattr);
421         pthread_condattr_destroy(&cattr);
422
423         return rc;
424 }
425
426 static inline void shmem_lock(void)
427 {
428         pthread_mutex_lock(&shared_data->mutex);
429 }
430
431 static inline void shmem_unlock(void)
432 {
433         pthread_mutex_unlock(&shared_data->mutex);
434 }
435
436 static inline void shmem_wait(void)
437 {
438         pthread_cond_wait(&shared_data->cond, &shared_data->mutex);
439 }
440
441 static inline void shmem_wakeup_all(void)
442 {
443         pthread_cond_broadcast(&shared_data->cond);
444 }
445
446 static inline void shmem_reset(int total_threads)
447 {
448         if (shared_data == NULL)
449                 return;
450
451         memset(&shared_data->body, 0, sizeof(shared_data->body));
452         memset(counter_snapshot, 0, sizeof(counter_snapshot));
453         prev_valid = 0;
454         shared_data->stopping = 0;
455         shared_data->body.start_barrier = total_threads;
456         shared_data->body.stop_barrier = total_threads;
457 }
458
459 static inline void shmem_bump(__u32 counter)
460 {
461         static bool running_not_bumped = true;
462
463         if (shared_data == NULL || thread <= 0 || thread > MAX_THREADS)
464                 return;
465
466         shmem_lock();
467         shared_data->body.counters[thread - 1] += counter;
468         if (running_not_bumped) {
469                 shared_data->body.thr_running++;
470                 running_not_bumped = false;
471         }
472         shmem_unlock();
473 }
474
475 static void shmem_total(int total_threads)
476 {
477         __u64 total = 0;
478         double secs;
479         int i;
480
481         if (shared_data == NULL || total_threads > MAX_THREADS)
482                 return;
483
484         shmem_lock();
485         for (i = 0; i < total_threads; i++)
486                 total += shared_data->body.counters[i];
487
488         secs = difftime(&shared_data->body.end_time,
489                         &shared_data->body.start_time);
490         shmem_unlock();
491
492         printf("Total: total %ju threads %d sec %f %f/second\n",
493                (uintmax_t)total, total_threads, secs, total / secs);
494
495         return;
496 }
497
498 static void shmem_snap(int total_threads, int live_threads)
499 {
500         struct timeval this_time;
501         int non_zero = 0;
502         __u64 total = 0;
503         double secs;
504         int running;
505         int i;
506
507         if (shared_data == NULL || total_threads > MAX_THREADS)
508                 return;
509
510         shmem_lock();
511         memcpy(counter_snapshot[0], shared_data->body.counters,
512                total_threads * sizeof(counter_snapshot[0][0]));
513         running = shared_data->body.thr_running;
514         shmem_unlock();
515
516         gettimeofday(&this_time, NULL);
517
518         for (i = 0; i < total_threads; i++) {
519                 long long this_count =
520                         counter_snapshot[0][i] - counter_snapshot[1][i];
521
522                 if (this_count != 0) {
523                         non_zero++;
524                         total += this_count;
525                 }
526         }
527
528         secs = difftime(&this_time, &prev_time);
529         if (prev_valid && secs > 1.0)    /* someone screwed with the time? */
530                 printf("%d/%d Total: %f/second\n", non_zero, total_threads,
531                        total / secs);
532
533         memcpy(counter_snapshot[1], counter_snapshot[0],
534                total_threads * sizeof(counter_snapshot[0][0]));
535         prev_time = this_time;
536         if (!prev_valid &&
537             running == total_threads)
538                 prev_valid = 1;
539 }
540
541 static void shmem_stop(void)
542 {
543         if (shared_data == NULL)
544                 return;
545
546         shared_data->stopping = 1;
547 }
548
549 static void shmem_cleanup(void)
550 {
551         if (shared_data == NULL)
552                 return;
553
554         shmem_stop();
555
556         pthread_mutex_destroy(&shared_data->mutex);
557         pthread_cond_destroy(&shared_data->cond);
558 }
559
560 static int shmem_running(void)
561 {
562         return (shared_data == NULL || !shared_data->stopping);
563 }
564
565 static void shmem_end_time_locked(void)
566 {
567         shared_data->body.stop_barrier--;
568         if (shared_data->body.stop_barrier == 0)
569                 gettimeofday(&shared_data->body.end_time, NULL);
570 }
571
572 static void shmem_start_time_locked(void)
573 {
574         shared_data->body.start_barrier--;
575         if (shared_data->body.start_barrier == 0) {
576                 shmem_wakeup_all();
577                 gettimeofday(&shared_data->body.start_time, NULL);
578         } else {
579                 shmem_wait();
580         }
581 }
582
583 #else
584 static int shmem_setup(void)
585 {
586         return 0;
587 }
588
589 static inline void shmem_reset(int total_threads)
590 {
591 }
592
593 static inline void shmem_bump(__u32 counters)
594 {
595 }
596
597 static void shmem_lock()
598 {
599 }
600
601 static void shmem_unlock()
602 {
603 }
604
605 static void shmem_cleanup(void)
606 {
607 }
608
609 static int shmem_running(void)
610 {
611         return 1;
612 }
613 #endif
614
615 extern command_t cmdlist[];
616
617 static int do_device(char *func, char *devname)
618 {
619         int dev;
620
621         dev = parse_devname(func, devname);
622         if (dev < 0)
623                 return -1;
624
625         lcfg_set_devname(devname);
626         cur_device = dev;
627         return 0;
628 }
629
630 int jt_obd_get_device()
631 {
632         return cur_device;
633 }
634
635 int jt_obd_device(int argc, char **argv)
636 {
637         int rc;
638
639         if (argc > 2)
640                 return CMD_HELP;
641
642         if (argc == 1) {
643                 printf("current device is %d - %s\n",
644                        cur_device, lcfg_get_devname() ? : "not set");
645                 return 0;
646         }
647         rc = do_device("device", argv[1]);
648         return rc;
649 }
650
651 int jt_opt_device(int argc, char **argv)
652 {
653         int ret;
654         int rc;
655
656         if (argc < 3)
657                 return CMD_HELP;
658
659         rc = do_device("device", argv[1]);
660
661         if (!rc)
662                 rc = Parser_execarg(argc - 2, argv + 2, cmdlist);
663
664         ret = do_disconnect(argv[0], 0);
665         if (!rc)
666                 rc = ret;
667
668         return rc;
669 }
670
671 #ifdef MAX_THREADS
672 static void parent_sighandler (int sig)
673 {
674         return;
675 }
676
677 int jt_opt_threads(int argc, char **argv)
678 {
679         static char      cmdstr[128];
680         sigset_t         saveset;
681         sigset_t         sigset;
682         struct sigaction sigact;
683         struct sigaction saveact1;
684         struct sigaction saveact2;
685         unsigned long    threads;
686         __u64            next_thread;
687         int verbose;
688         int rc = 0;
689         int report_count = -1;
690         char *end;
691         int i;
692
693         if (argc < 5)
694                 return CMD_HELP;
695
696         threads = strtoul(argv[1], &end, 0);
697
698         if (*end == '.')
699                 report_count = strtoul(end + 1, &end, 0);
700
701         if (*end || threads > MAX_THREADS) {
702                 fprintf(stderr, "error: %s: invalid thread count '%s'\n",
703                         jt_cmdname(argv[0]), argv[1]);
704                 return CMD_HELP;
705         }
706
707         verbose = get_verbose(argv[0], argv[2]);
708         if (verbose == BAD_VERBOSE)
709                 return CMD_HELP;
710
711         if (verbose != 0) {
712                 snprintf(cmdstr, sizeof(cmdstr), "%s", argv[4]);
713                 for (i = 5; i < argc; i++)
714                         snprintf(cmdstr + strlen(cmdstr), sizeof(cmdstr),
715                                  " %s", argv[i]);
716
717                 printf("%s: starting %ld threads on device %s running %s\n",
718                        argv[0], threads, argv[3], cmdstr);
719         }
720
721         shmem_reset(threads);
722
723         sigemptyset(&sigset);
724         sigaddset(&sigset, SIGALRM);
725         sigaddset(&sigset, SIGCHLD);
726         sigprocmask(SIG_BLOCK, &sigset, &saveset);
727
728         nthreads = threads;
729
730         for (i = 1, next_thread = verbose; i <= threads; i++) {
731                 rc = fork();
732                 if (rc < 0) {
733                         fprintf(stderr, "error: %s: #%d - %s\n", argv[0], i,
734                                 strerror(rc = errno));
735                         break;
736                 } else if (rc == 0) {
737                         sigprocmask(SIG_SETMASK, &saveset, NULL);
738
739                         thread = i;
740                         argv[2] = "--device";
741                         exit(jt_opt_device(argc - 2, argv + 2));
742                 } else if (be_verbose(verbose, NULL, i, &next_thread, threads))
743                         printf("%s: thread #%d (PID %d) started\n",
744                                argv[0], i, rc);
745                 rc = 0;
746         }
747
748         if (!thread) {          /* parent process */
749                 int live_threads = threads;
750
751                 sigemptyset(&sigset);
752                 sigemptyset(&sigact.sa_mask);
753                 sigact.sa_handler = parent_sighandler;
754                 sigact.sa_flags = 0;
755
756                 sigaction(SIGALRM, &sigact, &saveact1);
757                 sigaction(SIGCHLD, &sigact, &saveact2);
758
759                 while (live_threads > 0) {
760                         int status;
761                         pid_t ret;
762
763                         if (verbose < 0)        /* periodic stats */
764                                 alarm(-verbose);
765
766                         sigsuspend(&sigset);
767                         alarm(0);
768
769                         while (live_threads > 0) {
770                                 ret = waitpid(0, &status, WNOHANG);
771                                 if (ret == 0)
772                                         break;
773
774                                 if (ret < 0) {
775                                         fprintf(stderr, "error: %s: wait - %s\n",
776                                                 argv[0], strerror(errno));
777                                         if (!rc)
778                                                 rc = errno;
779                                         continue;
780                                 } else {
781                                         /*
782                                          * This is a hack.  We _should_ be able
783                                          * to use WIFEXITED(status) to see if
784                                          * there was an error, but it appears
785                                          * to be broken and it always returns 1
786                                          * (OK).  See wait(2).
787                                          */
788                                         int err = WEXITSTATUS(status);
789                                         if (err || WIFSIGNALED(status))
790                                                 fprintf(stderr,
791                                                         "%s: PID %d had rc=%d\n",
792                                                         argv[0], ret, err);
793                                         if (!rc)
794                                                 rc = err;
795
796                                         live_threads--;
797                                 }
798                         }
799
800                         /* Show stats while all threads running */
801                         if (verbose < 0) {
802                                 shmem_snap(threads, live_threads);
803                                 if (report_count > 0 && --report_count == 0)
804                                         shmem_stop();
805                         }
806                 }
807                 sigaction(SIGCHLD, &saveact2, NULL);
808                 sigaction(SIGALRM, &saveact1, NULL);
809         }
810
811         shmem_total(threads);
812         sigprocmask(SIG_SETMASK, &saveset, NULL);
813
814         return rc;
815 }
816 #else
817 int jt_opt_threads(int argc, char **argv)
818 {
819         fprintf(stderr, "%s not-supported in a single-threaded runtime\n",
820                 jt_cmdname(argv[0]));
821         return CMD_HELP;
822 }
823 #endif
824
825 int jt_opt_net(int argc, char **argv)
826 {
827         char *arg2[3];
828         int rc;
829
830         if (argc < 3)
831                 return CMD_HELP;
832
833         arg2[0] = argv[0];
834         arg2[1] = argv[1];
835         arg2[2] = NULL;
836         rc = jt_ptl_network (2, arg2);
837
838         if (!rc)
839                 rc = Parser_execarg(argc - 2, argv + 2, cmdlist);
840
841         return rc;
842 }
843
844 int jt_obd_no_transno(int argc, char **argv)
845 {
846         struct obd_ioctl_data data;
847         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
848         int rc;
849
850         memset(&data, 0, sizeof(data));
851         data.ioc_dev = cur_device;
852
853         if (argc != 1)
854                 return CMD_HELP;
855
856         memset(buf, 0, sizeof(rawbuf));
857         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
858         if (rc) {
859                 fprintf(stderr, "error: %s: invalid ioctl\n",
860                         jt_cmdname(argv[0]));
861                 return rc;
862         }
863         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_NO_TRANSNO, buf);
864         if (rc < 0)
865                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
866                         strerror(rc = errno));
867
868         return rc;
869 }
870
871 int jt_obd_set_readonly(int argc, char **argv)
872 {
873         struct obd_ioctl_data data;
874         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
875         int rc;
876
877         memset(&data, 0, sizeof(data));
878         data.ioc_dev = cur_device;
879
880         if (argc != 1)
881                 return CMD_HELP;
882
883         memset(buf, 0, sizeof(rawbuf));
884         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
885         if (rc) {
886                 fprintf(stderr, "error: %s: invalid ioctl\n",
887                         jt_cmdname(argv[0]));
888                 return rc;
889         }
890         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_SET_READONLY, buf);
891         if (rc < 0)
892                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
893                         strerror(rc = errno));
894
895         return rc;
896 }
897
898 int jt_obd_abort_recovery(int argc, char **argv)
899 {
900         struct obd_ioctl_data data;
901         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
902         int rc;
903
904         memset(&data, 0, sizeof(data));
905         data.ioc_dev = cur_device;
906
907         if (argc != 1)
908                 return CMD_HELP;
909
910         memset(buf, 0, sizeof(rawbuf));
911         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
912         if (rc) {
913                 fprintf(stderr, "error: %s: invalid ioctl\n",
914                         jt_cmdname(argv[0]));
915                 return rc;
916         }
917         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_ABORT_RECOVERY, buf);
918         if (rc < 0)
919                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
920                         strerror(rc = errno));
921
922         return rc;
923 }
924
925 int jt_get_version(int argc, char **argv)
926 {
927         char version[128];
928         int rc;
929
930         if (argc != 1)
931                 return CMD_HELP;
932
933         rc = llapi_get_version_string(version, sizeof(version));
934         if (rc)
935                 printf("Lustre version: %s\n", LUSTRE_VERSION_STRING);
936         else
937                 printf("Lustre version: %s\n", version);
938
939         return 0;
940 }
941
942 static void print_obd_line(char *s)
943 {
944         const char *param = "osc/%s/ost_conn_uuid";
945         char buf[MAX_STRING_SIZE];
946         char obd_name[MAX_OBD_NAME];
947         FILE *fp = NULL;
948         glob_t path;
949         char *ptr;
950 retry:
951         /* obd device type is the first 3 characters of param name */
952         snprintf(buf, sizeof(buf), " %%*d %%*s %.3s %%%zus %%*s %%*d ",
953                  param, sizeof(obd_name) - 1);
954         if (sscanf(s, buf, obd_name) == 0)
955                 goto try_mdc;
956         if (cfs_get_param_paths(&path, param, obd_name) != 0)
957                 goto try_mdc;
958         fp = fopen(path.gl_pathv[0], "r");
959         if (fp == NULL) {
960                 /* need to free path data before retry */
961                 cfs_free_param_data(&path);
962 try_mdc:
963                 if (param[0] == 'o') { /* failed with osc, try mdc */
964                         param = "mdc/%s/mds_conn_uuid";
965                         goto retry;
966                 }
967                 buf[0] = '\0';
968                 goto fail_print;
969         }
970
971         /* should not ignore fgets(3)'s return value */
972         if (!fgets(buf, sizeof(buf), fp)) {
973                 fprintf(stderr, "reading from %s: %s", buf, strerror(errno));
974                 goto fail_close;
975         }
976
977 fail_close:
978         fclose(fp);
979         cfs_free_param_data(&path);
980
981         /* trim trailing newlines */
982         ptr = strrchr(buf, '\n');
983         if (ptr)
984                 *ptr = '\0';
985 fail_print:
986         ptr = strrchr(s, '\n');
987         if (ptr)
988                 *ptr = '\0';
989         printf("%s%s%s\n", s, buf[0] ? " " : "", buf);
990 }
991
992 /* get device list by ioctl */
993 int jt_obd_list_ioctl(int argc, char **argv)
994 {
995         int rc, index;
996         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
997         struct obd_ioctl_data *data = (struct obd_ioctl_data *)buf;
998
999         if (argc > 2)
1000                 return CMD_HELP;
1001         /* Just ignore a -t option.  Only supported with /proc. */
1002         else if (argc == 2 && strcmp(argv[1], "-t") != 0)
1003                 return CMD_HELP;
1004
1005         for (index = 0;; index++) {
1006                 memset(buf, 0, sizeof(rawbuf));
1007                 data->ioc_version = OBD_IOCTL_VERSION;
1008                 data->ioc_inllen1 =
1009                         sizeof(rawbuf) - cfs_size_round(sizeof(*data));
1010                 data->ioc_inlbuf1 = buf + cfs_size_round(sizeof(*data));
1011                 data->ioc_len = obd_ioctl_packlen(data);
1012                 data->ioc_count = index;
1013
1014                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_GETDEVICE, buf);
1015                 if (rc != 0)
1016                         break;
1017                 printf("%s\n", (char *)data->ioc_bulk);
1018         }
1019         if (rc != 0) {
1020                 if (errno == ENOENT)
1021                         /* no device or the last device */
1022                         rc = 0;
1023                 else
1024                         fprintf(stderr, "Error getting device list: %s: "
1025                                 "check dmesg.\n", strerror(errno));
1026         }
1027         return rc;
1028 }
1029
1030 int jt_obd_list(int argc, char **argv)
1031 {
1032         char buf[MAX_STRING_SIZE];
1033         int print_obd = 0;
1034         glob_t path;
1035         FILE *fp;
1036
1037         if (argc > 2)
1038                 return CMD_HELP;
1039         else if (argc == 2) {
1040                 if (strcmp(argv[1], "-t") == 0)
1041                         print_obd = 1;
1042                 else
1043                         return CMD_HELP;
1044         }
1045
1046         if (cfs_get_param_paths(&path, "devices") != 0)
1047                 return -errno;
1048
1049         fp = fopen(path.gl_pathv[0], "r");
1050         if (fp == NULL) {
1051                 fprintf(stderr, "error: %s: %s opening %s\n",
1052                         jt_cmdname(argv[0]), strerror(errno), path.gl_pathv[0]);
1053                 cfs_free_param_data(&path);
1054                 return jt_obd_list_ioctl(argc, argv);
1055         }
1056
1057         while (fgets(buf, sizeof(buf), fp) != NULL)
1058                 if (print_obd)
1059                         print_obd_line(buf);
1060                 else
1061                         printf("%s", buf);
1062
1063         cfs_free_param_data(&path);
1064         fclose(fp);
1065         return 0;
1066 }
1067
1068 struct jt_fid_space {
1069         __u64   jt_seq;
1070         __u64   jt_id;
1071         int     jt_width;
1072 };
1073
1074 int jt_obd_alloc_fids(struct jt_fid_space *space, struct lu_fid *fid,
1075                       __u64 *count)
1076 {
1077         int rc;
1078
1079         if (space->jt_seq == 0 || space->jt_id == space->jt_width) {
1080                 struct obd_ioctl_data  data;
1081                 char rawbuf[MAX_IOC_BUFLEN];
1082                 char *buf = rawbuf;
1083                 __u64 seqnr;
1084                 int max_count;
1085
1086                 memset(&data, 0, sizeof(data));
1087                 data.ioc_dev = cur_device;
1088
1089                 data.ioc_pbuf1 = (char *)&seqnr;
1090                 data.ioc_plen1 = sizeof(seqnr);
1091
1092                 data.ioc_pbuf2 = (char *)&max_count;
1093                 data.ioc_plen2 = sizeof(max_count);
1094
1095                 memset(buf, 0, sizeof(rawbuf));
1096                 rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
1097                 if (rc) {
1098                         fprintf(stderr, "error: invalid ioctl rc = %d\n", rc);
1099                         return rc;
1100                 }
1101
1102                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_ECHO_ALLOC_SEQ, buf);
1103                 if (rc) {
1104                         fprintf(stderr, "ioctl error: rc = %d\n", rc);
1105                         return rc;
1106                 }
1107
1108                 space->jt_seq = *(__u64 *)data.ioc_pbuf1;
1109                 space->jt_width = *(int *)data.ioc_pbuf2;
1110                 space->jt_id = 1;
1111         }
1112         fid->f_seq = space->jt_seq;
1113         fid->f_oid = space->jt_id;
1114         fid->f_ver = 0;
1115
1116         space->jt_id = space->jt_id + *count;
1117         if (space->jt_id > space->jt_width)
1118                 space->jt_id = space->jt_width;
1119
1120         *count = space->jt_id - fid->f_oid;
1121         return 0;
1122 }
1123
1124 #define MD_STEP_COUNT 1000
1125 int jt_obd_md_common(int argc, char **argv, int cmd)
1126 {
1127         struct obd_ioctl_data  data;
1128         struct timeval         start;
1129         struct timeval         end_time;
1130         char                   rawbuf[MAX_IOC_BUFLEN];
1131         char                  *buf = rawbuf;
1132         int                    mode = 0000644;
1133         int                    create_mode;
1134         int                    rc = 0;
1135         char                  *parent_basedir = NULL;
1136         char                   dirname[4096];
1137         int                    parent_base_id = 0;
1138         int                    parent_count = 1;
1139         __u64                  child_base_id = -1;
1140         int                    stripe_count = 0;
1141         int                    stripe_index = -1;
1142         int                    count = 0;
1143         char                  *end;
1144         __u64                  seconds = 0;
1145         double                 diff;
1146         int                    c;
1147         __u64                  total_count = 0;
1148         char                  *name = NULL;
1149         struct jt_fid_space    fid_space = {0};
1150         int                    version = 0;
1151         struct option          long_opts[] = {
1152                 {"child_base_id",     required_argument, 0, 'b'},
1153                 {"stripe_count",      required_argument, 0, 'c'},
1154                 {"parent_basedir",    required_argument, 0, 'd'},
1155                 {"parent_dircount",   required_argument, 0, 'D'},
1156                 {"stripe_index",      required_argument, 0, 'i'},
1157                 {"mode",              required_argument, 0, 'm'},
1158                 {"count",             required_argument, 0, 'n'},
1159                 {"time",              required_argument, 0, 't'},
1160                 {"version",           no_argument,       0, 'v'},
1161                 {0, 0, 0, 0}
1162         };
1163
1164         while ((c = getopt_long(argc, argv, "b:c:d:D:m:n:t:v",
1165                                 long_opts, NULL)) >= 0) {
1166                 switch (c) {
1167                 case 'b':
1168                         child_base_id = strtoull(optarg, &end, 0);
1169                         if (*end) {
1170                                 fprintf(stderr, "error: %s: bad child_base_id"
1171                                         " '%s'\n", jt_cmdname(argv[0]), optarg);
1172                                 return CMD_HELP;
1173                         }
1174                         break;
1175                 case 'c':
1176                         stripe_count = strtoul(optarg, &end, 0);
1177                         if (*end) {
1178                                 fprintf(stderr, "error: %s: bad stripe count"
1179                                         " '%s'\n", jt_cmdname(argv[0]), optarg);
1180                                 return CMD_HELP;
1181                         }
1182                         break;
1183                 case 'd':
1184                         parent_basedir = optarg;
1185                         break;
1186                 case 'D':
1187                         parent_count = strtoul(optarg, &end, 0);
1188                         if (*end) {
1189                                 fprintf(stderr, "error: %s: bad parent count"
1190                                         " '%s'\n", jt_cmdname(argv[0]), optarg);
1191                                 return CMD_HELP;
1192                         }
1193                         break;
1194                 case 'i':
1195                         stripe_index = strtoul(optarg, &end, 0);
1196                         if (*end) {
1197                                 fprintf(stderr, "error: %s: bad stripe index"
1198                                         " '%s'\n", jt_cmdname(argv[0]), optarg);
1199                                 return CMD_HELP;
1200                         }
1201                         break;
1202                 case 'm':
1203                         mode = strtoul(optarg, &end, 0);
1204                         if (*end) {
1205                                 fprintf(stderr, "error: %s: bad mode '%s'\n",
1206                                         jt_cmdname(argv[0]), optarg);
1207                                 return CMD_HELP;
1208                         }
1209                         break;
1210                 case 'n':
1211                         total_count = strtoul(optarg, &end, 0);
1212                         if (*end || total_count == 0) {
1213                                 fprintf(stderr, "%s: bad child count '%s'\n",
1214                                         jt_cmdname(argv[0]), optarg);
1215                                 return CMD_HELP;
1216                         }
1217                         break;
1218                 case 't':
1219                         seconds = strtoull(optarg, &end, 0);
1220                         if (*end) {
1221                                 fprintf(stderr, "error: %s: seconds '%s'\n",
1222                                         jt_cmdname(argv[0]), optarg);
1223                                 return CMD_HELP;
1224                         }
1225                         break;
1226                 case 'v':
1227                         version = 1;
1228                         break;
1229                 default:
1230                         fprintf(stderr, "error: %s: option '%s' "
1231                                 "unrecognized\n", argv[0], argv[optind - 1]);
1232                         return CMD_HELP;
1233                 }
1234         }
1235
1236         memset(&data, 0, sizeof(data));
1237         data.ioc_dev = cur_device;
1238         if (child_base_id == -1) {
1239                 if (optind >= argc)
1240                         return CMD_HELP;
1241                 name = argv[optind];
1242                 total_count = 1;
1243         } else {
1244                 if (optind < argc) {
1245                         fprintf(stderr, "child_base_id and name can not"
1246                                         " specified at the same time\n");
1247                         return CMD_HELP;
1248                 }
1249         }
1250
1251         if (stripe_count == 0 && stripe_index != -1) {
1252                 fprintf(stderr, "If stripe_count is 0, stripe_index can not"
1253                                 "be specified\n");
1254                 return CMD_HELP;
1255         }
1256
1257         if (total_count == 0 && seconds == 0) {
1258                 fprintf(stderr, "count or seconds needs to be indicated\n");
1259                 return CMD_HELP;
1260         }
1261
1262         if (parent_count <= 0) {
1263                 fprintf(stderr, "parent count must < 0\n");
1264                 return CMD_HELP;
1265         }
1266
1267 #ifdef MAX_THREADS
1268         if (thread) {
1269                 shmem_lock();
1270                 /* threads interleave */
1271                 if (parent_base_id != -1)
1272                         parent_base_id += (thread - 1) % parent_count;
1273
1274                 if (child_base_id != -1)
1275                         child_base_id +=  (thread - 1) * \
1276                                           (MAX_BASE_ID / nthreads);
1277
1278                 shmem_start_time_locked();
1279                 shmem_unlock();
1280         }
1281 #endif
1282         /* If parent directory is not specified, try to get the directory
1283          * from name */
1284         if (parent_basedir == NULL) {
1285                 char *last_lash;
1286                 if (name == NULL) {
1287                         fprintf(stderr, "parent_basedir or name must be"
1288                                         "indicated!\n");
1289                         return CMD_HELP;
1290                 }
1291                 /*Get directory and name from name*/
1292                 last_lash = strrchr(name, '/');
1293                 if (last_lash == NULL || name[0] != '/') {
1294                         fprintf(stderr, "Can not locate %s\n", name);
1295                         return CMD_HELP;
1296                 }
1297
1298                 if (last_lash == name) {
1299                         sprintf(dirname, "%s", "/");
1300                         name++;
1301                 } else {
1302                         int namelen = (unsigned long)last_lash -
1303                                       (unsigned long)name + 1;
1304                         snprintf(dirname, namelen, "%s", name);
1305                         name = last_lash + 1;
1306                 }
1307
1308                 data.ioc_pbuf1 = dirname;
1309                 data.ioc_plen1 = strlen(dirname);
1310
1311                 data.ioc_pbuf2 = name;
1312                 data.ioc_plen2 = strlen(name);
1313         } else {
1314                 if (name != NULL) {
1315                         data.ioc_pbuf2 = name;
1316                         data.ioc_plen2 = strlen(name);
1317                 }
1318                 if (parent_base_id > 0)
1319                         sprintf(dirname, "%s%d", parent_basedir,
1320                                 parent_base_id);
1321                 else
1322                         sprintf(dirname, "%s", parent_basedir);
1323                 data.ioc_pbuf1 = dirname;
1324                 data.ioc_plen1 = strlen(dirname);
1325         }
1326
1327         if (cmd == ECHO_MD_MKDIR || cmd == ECHO_MD_RMDIR)
1328                 create_mode = S_IFDIR;
1329         else
1330                 create_mode = S_IFREG;
1331
1332         data.ioc_obdo1.o_mode = mode | S_IFDIR;
1333         data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE |
1334                                  OBD_MD_FLFLAGS | OBD_MD_FLGROUP;
1335         data.ioc_command = cmd;
1336
1337         gettimeofday(&start, NULL);
1338         while (shmem_running()) {
1339                 struct lu_fid fid = { 0 };
1340
1341                 if (child_base_id != -1)
1342                         data.ioc_obdo2.o_oi.oi.oi_id = child_base_id;
1343                 data.ioc_obdo2.o_mode = mode | create_mode;
1344                 data.ioc_obdo2.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE |
1345                                          OBD_MD_FLMODE | OBD_MD_FLFLAGS |
1346                                          OBD_MD_FLGROUP;
1347                 data.ioc_obdo2.o_misc = stripe_count;
1348                 data.ioc_obdo2.o_stripe_idx = stripe_index;
1349
1350                 if (total_count > 0) {
1351                         if ((total_count - count) > MD_STEP_COUNT)
1352                                 data.ioc_count = MD_STEP_COUNT;
1353                         else
1354                                 data.ioc_count = total_count - count;
1355                 } else {
1356                         data.ioc_count = MD_STEP_COUNT;
1357                 }
1358
1359                 if (cmd == ECHO_MD_CREATE || cmd == ECHO_MD_MKDIR) {
1360                         /*Allocate fids for the create */
1361                         rc = jt_obd_alloc_fids(&fid_space, &fid,
1362                                                &data.ioc_count);
1363                         if (rc) {
1364                                 fprintf(stderr, "Allocate fids error %d.\n",rc);
1365                                 return rc;
1366                         }
1367                         fid_to_ostid(&fid, &data.ioc_obdo1.o_oi);
1368                 }
1369
1370                 child_base_id += data.ioc_count;
1371                 count += data.ioc_count;
1372
1373                 memset(buf, 0, sizeof(rawbuf));
1374                 rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
1375                 if (rc) {
1376                         fprintf(stderr, "error: %s: invalid ioctl %d\n",
1377                                 jt_cmdname(argv[0]), rc);
1378                         return rc;
1379                 }
1380
1381                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_ECHO_MD, buf);
1382                 if (rc) {
1383                         fprintf(stderr, "error: %s: %s\n",
1384                                 jt_cmdname(argv[0]), strerror(rc = errno));
1385                         return rc;
1386                 }
1387                 shmem_bump(data.ioc_count);
1388
1389                 gettimeofday(&end_time, NULL);
1390                 diff = difftime(&end_time, &start);
1391                 if (seconds > 0 && (__u64)diff > seconds)
1392                         break;
1393
1394                 if (count >= total_count && total_count > 0)
1395                         break;
1396         }
1397
1398         if (count > 0 && version) {
1399                 gettimeofday(&end_time, NULL);
1400                 diff = difftime(&end_time, &start);
1401                 printf("%s: %d in %.3fs (%.3f /s): %s",
1402                         jt_cmdname(argv[0]), count, diff,
1403                         (double)count/diff, ctime(&end_time.tv_sec));
1404         }
1405
1406 #ifdef MAX_THREADS
1407         if (thread) {
1408                 shmem_lock();
1409                 shmem_end_time_locked();
1410                 shmem_unlock();
1411         }
1412 #endif
1413         return rc;
1414 }
1415
1416 int jt_obd_test_create(int argc, char **argv)
1417 {
1418         return jt_obd_md_common(argc, argv, ECHO_MD_CREATE);
1419 }
1420
1421 int jt_obd_test_mkdir(int argc, char **argv)
1422 {
1423         return jt_obd_md_common(argc, argv, ECHO_MD_MKDIR);
1424 }
1425
1426 int jt_obd_test_destroy(int argc, char **argv)
1427 {
1428         return jt_obd_md_common(argc, argv, ECHO_MD_DESTROY);
1429 }
1430
1431 int jt_obd_test_rmdir(int argc, char **argv)
1432 {
1433         return jt_obd_md_common(argc, argv, ECHO_MD_RMDIR);
1434 }
1435
1436 int jt_obd_test_lookup(int argc, char **argv)
1437 {
1438         return jt_obd_md_common(argc, argv, ECHO_MD_LOOKUP);
1439 }
1440
1441 int jt_obd_test_setxattr(int argc, char **argv)
1442 {
1443         return jt_obd_md_common(argc, argv, ECHO_MD_SETATTR);
1444 }
1445
1446 int jt_obd_test_md_getattr(int argc, char **argv)
1447 {
1448         return jt_obd_md_common(argc, argv, ECHO_MD_GETATTR);
1449 }
1450
1451 int jt_obd_create(int argc, char **argv)
1452 {
1453         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1454         struct obd_ioctl_data data;
1455         struct timeval next_time;
1456         __u64 count = 1, next_count, base_id = 1;
1457         int verbose = 1, mode = 0100644, rc = 0, i;
1458         char *end;
1459
1460         memset(&data, 0, sizeof(data));
1461         data.ioc_dev = cur_device;
1462         if (argc < 2 || argc > 4)
1463                 return CMD_HELP;
1464
1465         count = strtoull(argv[1], &end, 0);
1466         if (*end) {
1467                 fprintf(stderr, "error: %s: invalid iteration count '%s'\n",
1468                         jt_cmdname(argv[0]), argv[1]);
1469                 return CMD_HELP;
1470         }
1471
1472         if (argc > 2) {
1473                 mode = strtoul(argv[2], &end, 0);
1474                 if (*end) {
1475                         fprintf(stderr, "error: %s: invalid mode '%s'\n",
1476                                 jt_cmdname(argv[0]), argv[2]);
1477                         return CMD_HELP;
1478                 }
1479                 if (!(mode & S_IFMT))
1480                         mode |= S_IFREG;
1481         }
1482
1483         if (argc > 3) {
1484                 verbose = get_verbose(argv[0], argv[3]);
1485                 if (verbose == BAD_VERBOSE)
1486                         return CMD_HELP;
1487         }
1488
1489         printf("%s: %jd objects\n", jt_cmdname(argv[0]), (uintmax_t)count);
1490         gettimeofday(&next_time, NULL);
1491         next_time.tv_sec -= verbose;
1492
1493         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1494         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
1495                 data.ioc_obdo1.o_mode = mode;
1496                 ostid_set_id(&data.ioc_obdo1.o_oi, base_id);
1497                 data.ioc_obdo1.o_uid = 0;
1498                 data.ioc_obdo1.o_gid = 0;
1499                 data.ioc_obdo1.o_valid = OBD_MD_FLTYPE | OBD_MD_FLMODE |
1500                                          OBD_MD_FLID | OBD_MD_FLUID |
1501                                          OBD_MD_FLGID | OBD_MD_FLGROUP;
1502
1503                 memset(buf, 0, sizeof(rawbuf));
1504                 rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
1505                 if (rc) {
1506                         fprintf(stderr, "error: %s: invalid ioctl\n",
1507                                 jt_cmdname(argv[0]));
1508                         return rc;
1509                 }
1510                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_CREATE, buf);
1511                 obd_ioctl_unpack(&data, buf, sizeof(rawbuf));
1512                 shmem_bump(1);
1513                 if (rc < 0) {
1514                         fprintf(stderr, "error: %s: #%d - %s\n",
1515                                 jt_cmdname(argv[0]), i, strerror(rc = errno));
1516                         break;
1517                 }
1518                 if (!(data.ioc_obdo1.o_valid & OBD_MD_FLID)) {
1519                         fprintf(stderr, "error: %s: oid not valid #%d:%#jx\n",
1520                                 jt_cmdname(argv[0]), i,
1521                                 (uintmax_t)data.ioc_obdo1.o_valid);
1522                         rc = EINVAL;
1523                         break;
1524                 }
1525
1526                 if (be_verbose(verbose, &next_time, i, &next_count, count))
1527                         printf("%s: #%d is object id %#jx\n",
1528                                jt_cmdname(argv[0]), i,
1529                                (uintmax_t) ostid_id(&data.ioc_obdo1.o_oi));
1530         }
1531         return rc;
1532 }
1533
1534 int jt_obd_setattr(int argc, char **argv)
1535 {
1536         struct obd_ioctl_data data;
1537         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1538         char *end;
1539         int rc;
1540
1541         memset(&data, 0, sizeof(data));
1542         data.ioc_dev = cur_device;
1543         if (argc != 2)
1544                 return CMD_HELP;
1545
1546         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1547         ostid_set_id(&data.ioc_obdo1.o_oi, strtoull(argv[1], &end, 0));
1548         if (*end) {
1549                 fprintf(stderr, "error: %s: invalid objid '%s'\n",
1550                         jt_cmdname(argv[0]), argv[1]);
1551                 return CMD_HELP;
1552         }
1553         data.ioc_obdo1.o_mode = S_IFREG | strtoul(argv[2], &end, 0);
1554         if (*end) {
1555                 fprintf(stderr, "error: %s: invalid mode '%s'\n",
1556                         jt_cmdname(argv[0]), argv[2]);
1557                 return CMD_HELP;
1558         }
1559         data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE;
1560
1561         memset(buf, 0, sizeof(rawbuf));
1562         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
1563         if (rc) {
1564                 fprintf(stderr, "error: %s: invalid ioctl\n",
1565                         jt_cmdname(argv[0]));
1566                 return rc;
1567         }
1568         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_SETATTR, buf);
1569         if (rc < 0)
1570                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
1571                         strerror(rc = errno));
1572
1573         return rc;
1574 }
1575
1576 int jt_obd_test_setattr(int argc, char **argv)
1577 {
1578         struct obd_ioctl_data data;
1579         struct timeval start, next_time;
1580         __u64 i, count, next_count;
1581         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1582         int verbose = 1;
1583         __u64 objid = 3;
1584         char *end;
1585         int rc = 0;
1586
1587         if (argc < 2 || argc > 4)
1588                 return CMD_HELP;
1589
1590         memset(&data, 0, sizeof(data));
1591         data.ioc_dev = cur_device;
1592         count = strtoull(argv[1], &end, 0);
1593         if (*end) {
1594                 fprintf(stderr, "error: %s: invalid iteration count '%s'\n",
1595                         jt_cmdname(argv[0]), argv[1]);
1596                 return CMD_HELP;
1597         }
1598
1599         if (argc >= 3) {
1600                 verbose = get_verbose(argv[0], argv[2]);
1601                 if (verbose == BAD_VERBOSE)
1602                         return CMD_HELP;
1603         }
1604
1605         if (argc >= 4) {
1606                 if (argv[3][0] == 't') {
1607                         objid = strtoull(argv[3] + 1, &end, 0);
1608                         if (thread)
1609                                 objid += thread - 1;
1610                 } else
1611                         objid = strtoull(argv[3], &end, 0);
1612                 if (*end) {
1613                         fprintf(stderr, "error: %s: invalid objid '%s'\n",
1614                                 jt_cmdname(argv[0]), argv[3]);
1615                         return CMD_HELP;
1616                 }
1617         }
1618
1619         gettimeofday(&start, NULL);
1620         next_time.tv_sec = start.tv_sec - verbose;
1621         next_time.tv_usec = start.tv_usec;
1622         if (verbose != 0)
1623                 printf("%s: setting %jd attrs (objid %#jx): %s",
1624                        jt_cmdname(argv[0]), (uintmax_t)count,
1625                        (uintmax_t)objid, ctime(&start.tv_sec));
1626
1627         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1628         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
1629                 ostid_set_id(&data.ioc_obdo1.o_oi, objid);
1630                 data.ioc_obdo1.o_mode = S_IFREG;
1631                 data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE;
1632                 memset(buf, 0, sizeof(rawbuf));
1633                 rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
1634                 if (rc) {
1635                         fprintf(stderr, "error: %s: invalid ioctl\n",
1636                                 jt_cmdname(argv[0]));
1637                         return rc;
1638                 }
1639                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_SETATTR, &data);
1640                 shmem_bump(1);
1641                 if (rc < 0) {
1642                         fprintf(stderr, "error: %s: #%jd - %d:%s\n",
1643                                 jt_cmdname(argv[0]), (uintmax_t)i,
1644                                 errno, strerror(rc = errno));
1645                         break;
1646                 } else {
1647                         if (be_verbose
1648                             (verbose, &next_time, i, &next_count, count))
1649                                 printf("%s: set attr #%jd\n",
1650                                        jt_cmdname(argv[0]), (uintmax_t)i);
1651                 }
1652         }
1653
1654         if (!rc) {
1655                 struct timeval end;
1656                 double diff;
1657
1658                 gettimeofday(&end, NULL);
1659
1660                 diff = difftime(&end, &start);
1661
1662                 --i;
1663                 if (verbose != 0)
1664                         printf("%s: %jd attrs in %.3fs (%.3f attr/s): %s",
1665                                jt_cmdname(argv[0]), (uintmax_t)i, diff,
1666                                i / diff, ctime(&end.tv_sec));
1667         }
1668         return rc;
1669 }
1670
1671 int jt_obd_destroy(int argc, char **argv)
1672 {
1673         struct obd_ioctl_data data;
1674         struct timeval next_time;
1675         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1676         __u64 count = 1, next_count;
1677         int verbose = 1;
1678         __u64 id;
1679         char *end;
1680         int rc = 0, i;
1681
1682         memset(&data, 0, sizeof(data));
1683         data.ioc_dev = cur_device;
1684         if (argc < 2 || argc > 4)
1685                 return CMD_HELP;
1686
1687         id = strtoull(argv[1], &end, 0);
1688         if (*end || id == 0 || errno != 0) {
1689                 fprintf(stderr, "error: %s: invalid objid '%s'\n",
1690                         jt_cmdname(argv[0]), argv[1]);
1691                 return CMD_HELP;
1692         }
1693         if (argc > 2) {
1694                 count = strtoull(argv[2], &end, 0);
1695                 if (*end) {
1696                         fprintf(stderr,
1697                                 "error: %s: invalid iteration count '%s'\n",
1698                                 jt_cmdname(argv[0]), argv[2]);
1699                         return CMD_HELP;
1700                 }
1701         }
1702
1703         if (argc > 3) {
1704                 verbose = get_verbose(argv[0], argv[3]);
1705                 if (verbose == BAD_VERBOSE)
1706                         return CMD_HELP;
1707         }
1708
1709         printf("%s: %jd objects\n", jt_cmdname(argv[0]), (uintmax_t)count);
1710         gettimeofday(&next_time, NULL);
1711         next_time.tv_sec -= verbose;
1712
1713         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1714         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++, id++) {
1715                 ostid_set_id(&data.ioc_obdo1.o_oi, id);
1716                 data.ioc_obdo1.o_mode = S_IFREG | 0644;
1717                 data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLMODE;
1718
1719                 memset(buf, 0, sizeof(rawbuf));
1720                 rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
1721                 if (rc) {
1722                         fprintf(stderr, "error: %s: invalid ioctl\n",
1723                                 jt_cmdname(argv[0]));
1724                         return rc;
1725                 }
1726                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_DESTROY, buf);
1727                 obd_ioctl_unpack(&data, buf, sizeof(rawbuf));
1728                 shmem_bump(1);
1729                 if (rc < 0) {
1730                         fprintf(stderr, "error: %s: objid %#jx: %s\n",
1731                                 jt_cmdname(argv[0]), (uintmax_t)id,
1732                                 strerror(rc = errno));
1733                         break;
1734                 }
1735
1736                 if (be_verbose(verbose, &next_time, i, &next_count, count))
1737                         printf("%s: #%d is object id %#jx\n",
1738                                jt_cmdname(argv[0]), i, (uintmax_t)id);
1739         }
1740
1741         return rc;
1742 }
1743
1744 int jt_obd_getattr(int argc, char **argv)
1745 {
1746         struct obd_ioctl_data data;
1747         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1748         char *end;
1749         int rc;
1750
1751         if (argc != 2)
1752                 return CMD_HELP;
1753
1754         memset(&data, 0, sizeof(data));
1755         data.ioc_dev = cur_device;
1756         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1757         ostid_set_id(&data.ioc_obdo1.o_oi, strtoull(argv[1], &end, 0));
1758         if (*end) {
1759                 fprintf(stderr, "error: %s: invalid objid '%s'\n",
1760                         jt_cmdname(argv[0]), argv[1]);
1761                 return CMD_HELP;
1762         }
1763         /* to help obd filter */
1764         data.ioc_obdo1.o_mode = 0100644;
1765         data.ioc_obdo1.o_valid = 0xffffffff;
1766         printf("%s: object id %#jx\n", jt_cmdname(argv[0]),
1767                (uintmax_t)ostid_id(&data.ioc_obdo1.o_oi));
1768
1769         memset(buf, 0, sizeof(rawbuf));
1770         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
1771         if (rc) {
1772                 fprintf(stderr, "error: %s: invalid ioctl\n",
1773                         jt_cmdname(argv[0]));
1774                 return rc;
1775         }
1776         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_GETATTR, buf);
1777         obd_ioctl_unpack(&data, buf, sizeof(rawbuf));
1778         if (rc) {
1779                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
1780                         strerror(rc = errno));
1781         } else {
1782                 printf("%s: object id %ju, mode %o\n", jt_cmdname(argv[0]),
1783                        (uintmax_t)ostid_id(&data.ioc_obdo1.o_oi),
1784                        data.ioc_obdo1.o_mode);
1785         }
1786         return rc;
1787 }
1788
1789 int jt_obd_test_getattr(int argc, char **argv)
1790 {
1791         struct obd_ioctl_data data;
1792         struct timeval start, next_time;
1793         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1794         __u64 i, count, next_count;
1795         int verbose = 1;
1796         __u64 objid = 3;
1797         char *end;
1798         int rc = 0;
1799
1800         if (argc < 2 || argc > 4)
1801                 return CMD_HELP;
1802
1803         memset(&data, 0, sizeof(data));
1804         data.ioc_dev = cur_device;
1805         count = strtoull(argv[1], &end, 0);
1806         if (*end) {
1807                 fprintf(stderr, "error: %s: invalid iteration count '%s'\n",
1808                         jt_cmdname(argv[0]), argv[1]);
1809                 return CMD_HELP;
1810         }
1811
1812         if (argc >= 3) {
1813                 verbose = get_verbose(argv[0], argv[2]);
1814                 if (verbose == BAD_VERBOSE)
1815                         return CMD_HELP;
1816         }
1817
1818         if (argc >= 4) {
1819                 if (argv[3][0] == 't') {
1820                         objid = strtoull(argv[3] + 1, &end, 0);
1821                         if (thread)
1822                                 objid += thread - 1;
1823                 } else
1824                         objid = strtoull(argv[3], &end, 0);
1825                 if (*end) {
1826                         fprintf(stderr, "error: %s: invalid objid '%s'\n",
1827                                 jt_cmdname(argv[0]), argv[3]);
1828                         return CMD_HELP;
1829                 }
1830         }
1831
1832         gettimeofday(&start, NULL);
1833         next_time.tv_sec = start.tv_sec - verbose;
1834         next_time.tv_usec = start.tv_usec;
1835         if (verbose != 0)
1836                 printf("%s: getting %jd attrs (objid %#jx): %s",
1837                        jt_cmdname(argv[0]), (uintmax_t) count,
1838                        (uintmax_t)objid, ctime(&start.tv_sec));
1839
1840         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1841         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
1842                 ostid_set_id(&data.ioc_obdo1.o_oi, objid);
1843                 data.ioc_obdo1.o_mode = S_IFREG;
1844                 data.ioc_obdo1.o_valid = 0xffffffff;
1845                 memset(buf, 0, sizeof(rawbuf));
1846                 rc = obd_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 = l2_ioctl(OBD_DEV_ID, OBD_IOC_GETATTR, &data);
1853                 shmem_bump(1);
1854                 if (rc < 0) {
1855                         fprintf(stderr, "error: %s: #%jd - %d:%s\n",
1856                                 jt_cmdname(argv[0]), (uintmax_t)i,
1857                                 errno, strerror(rc = errno));
1858                         break;
1859                 } else {
1860                         if (be_verbose
1861                             (verbose, &next_time, i, &next_count, count))
1862                                 printf("%s: got attr #%jd\n",
1863                                        jt_cmdname(argv[0]), (uintmax_t)i);
1864                 }
1865         }
1866
1867         if (!rc) {
1868                 struct timeval end;
1869                 double diff;
1870
1871                 gettimeofday(&end, NULL);
1872
1873                 diff = difftime(&end, &start);
1874
1875                 --i;
1876                 if (verbose != 0)
1877                         printf("%s: %jd attrs in %.3fs (%.3f attr/s): %s",
1878                                jt_cmdname(argv[0]), (uintmax_t) i, diff,
1879                                i / diff, ctime(&end.tv_sec));
1880         }
1881         return rc;
1882 }
1883
1884 /* test_brw <cnt>                                               count
1885         <r|w[r(repeat)x(noverify)]>                             mode
1886         <q|v|#(print interval)>                                 verbosity
1887         <npages[+offset]>                                       blocksize
1888         <[[<interleave_threads>]t(inc obj by thread#)]obj>      object
1889         [p|g<args>]                                             batch */
1890 int jt_obd_test_brw(int argc, char **argv)
1891 {
1892         struct obd_ioctl_data data;
1893         struct timeval start, next_time;
1894         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1895         __u64 count, next_count, len, stride, thr_offset = 0, objid = 3;
1896         int write = 0, verbose = 1, cmd, i, rc = 0, pages = 1;
1897         int offset_pages = 0;
1898         long n;
1899         int repeat_offset = 0;
1900         unsigned long long ull;
1901         int  nthr_per_obj = 0;
1902         int  verify = 1;
1903         int  obj_idx = 0;
1904         char *end;
1905
1906         if (argc < 2 || argc > 7) {
1907                 fprintf(stderr, "error: %s: bad number of arguments: %d\n",
1908                         jt_cmdname(argv[0]), argc);
1909                 return CMD_HELP;
1910         }
1911
1912         count = strtoull(argv[1], &end, 0);
1913         if (*end) {
1914                 fprintf(stderr, "error: %s: bad iteration count '%s'\n",
1915                         jt_cmdname(argv[0]), argv[1]);
1916                 return CMD_HELP;
1917         }
1918
1919         if (argc >= 3) {
1920                 if (argv[2][0] == 'w' || argv[2][0] == '1')
1921                         write = 1;
1922                 /* else it's a read */
1923
1924                 if (argv[2][0] != 0)
1925                         for (i = 1; argv[2][i] != 0; i++)
1926                                 switch (argv[2][i]) {
1927                                 case 'r':
1928                                         repeat_offset = 1;
1929                                         break;
1930
1931                                 case 'x':
1932                                         verify = 0;
1933                                         break;
1934
1935                                 default:
1936                                         fprintf (stderr, "Can't parse cmd '%s'\n",
1937                                                  argv[2]);
1938                                         return CMD_HELP;
1939                                 }
1940         }
1941
1942         if (argc >= 4) {
1943                 verbose = get_verbose(argv[0], argv[3]);
1944                 if (verbose == BAD_VERBOSE)
1945                         return CMD_HELP;
1946         }
1947
1948         if (argc >= 5) {
1949                 pages = strtoul(argv[4], &end, 0);
1950
1951                 if (*end == '+')
1952                         offset_pages = strtoul(end + 1, &end, 0);
1953
1954                 if (*end != 0 ||
1955                     offset_pages < 0 || offset_pages >= pages) {
1956                         fprintf(stderr, "error: %s: bad npages[+offset] parameter '%s'\n",
1957                                 jt_cmdname(argv[0]), argv[4]);
1958                         return CMD_HELP;
1959                 }
1960         }
1961
1962         if (argc >= 6) {
1963                 if (thread &&
1964                     (n = strtol(argv[5], &end, 0)) > 0 &&
1965                     *end == 't' &&
1966                     (ull = strtoull(end + 1, &end, 0)) > 0 &&
1967                     *end == 0) {
1968                         nthr_per_obj = n;
1969                         objid = ull;
1970                 } else if (thread &&
1971                            argv[5][0] == 't') {
1972                         nthr_per_obj = 1;
1973                         objid = strtoull(argv[5] + 1, &end, 0);
1974                 } else {
1975                         nthr_per_obj = 0;
1976                         objid = strtoull(argv[5], &end, 0);
1977                 }
1978                 if (*end) {
1979                         fprintf(stderr, "error: %s: bad objid '%s'\n",
1980                                 jt_cmdname(argv[0]), argv[5]);
1981                         return CMD_HELP;
1982                 }
1983         }
1984
1985         memset(&data, 0, sizeof(data));
1986         data.ioc_dev = cur_device;
1987
1988         /* communicate the 'type' of brw test and batching to echo_client.
1989          * don't start.  we'd love to refactor this lctl->echo_client
1990          * interface */
1991         data.ioc_pbuf1 = (void *)1;
1992         data.ioc_plen1 = 1;
1993
1994         if (argc >= 7) {
1995                 switch(argv[6][0]) {
1996                         case 'g': /* plug and unplug */
1997                                 data.ioc_pbuf1 = (void *)2;
1998                                 data.ioc_plen1 = strtoull(argv[6] + 1, &end,
1999                                                           0);
2000                                 break;
2001                         case 'p': /* prep and commit */
2002                                 data.ioc_pbuf1 = (void *)3;
2003                                 data.ioc_plen1 = strtoull(argv[6] + 1, &end,
2004                                                           0);
2005                                 break;
2006                         default:
2007                                 fprintf(stderr, "error: %s: batching '%s' "
2008                                         "needs to specify 'p' or 'g'\n",
2009                                         jt_cmdname(argv[0]), argv[6]);
2010                                 return CMD_HELP;
2011                 }
2012
2013                 if (*end) {
2014                         fprintf(stderr, "error: %s: bad batching '%s'\n",
2015                                 jt_cmdname(argv[0]), argv[6]);
2016                         return CMD_HELP;
2017                 }
2018                 data.ioc_plen1 *= getpagesize();
2019         }
2020
2021         len = pages * getpagesize();
2022         thr_offset = offset_pages * getpagesize();
2023         stride = len;
2024
2025 #ifdef MAX_THREADS
2026         if (thread) {
2027                 shmem_lock ();
2028                 if (nthr_per_obj != 0) {
2029                         /* threads interleave */
2030                         obj_idx = (thread - 1)/nthr_per_obj;
2031                         objid += obj_idx;
2032                         stride *= nthr_per_obj;
2033                         if ((thread - 1) % nthr_per_obj == 0) {
2034                                 shared_data->body.offsets[obj_idx] =
2035                                         stride + thr_offset;
2036                         }
2037                         thr_offset += ((thread - 1) % nthr_per_obj) * len;
2038                 } else {
2039                         /* threads disjoint */
2040                         thr_offset += (thread - 1) * len;
2041                 }
2042
2043                 shmem_start_time_locked();
2044                 shmem_unlock ();
2045         }
2046 #endif
2047
2048         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
2049         ostid_set_id(&data.ioc_obdo1.o_oi, objid);
2050         data.ioc_obdo1.o_mode = S_IFREG;
2051         data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE |
2052                                  OBD_MD_FLFLAGS | OBD_MD_FLGROUP;
2053         data.ioc_obdo1.o_flags = (verify ? OBD_FL_DEBUG_CHECK : 0);
2054         data.ioc_count = len;
2055         data.ioc_offset = (repeat_offset ? 0 : thr_offset);
2056
2057         gettimeofday(&start, NULL);
2058         next_time.tv_sec = start.tv_sec - verbose;
2059         next_time.tv_usec = start.tv_usec;
2060
2061         if (verbose != 0)
2062                 printf("%s: %s %jux%d pages (obj %#jx, off %ju): %s",
2063                        jt_cmdname(argv[0]), write ? "writing" : "reading",
2064                        (uintmax_t)count, pages, (uintmax_t) objid,
2065                        (uintmax_t)data.ioc_offset, ctime(&start.tv_sec));
2066
2067         cmd = write ? OBD_IOC_BRW_WRITE : OBD_IOC_BRW_READ;
2068         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
2069                 data.ioc_obdo1.o_valid &= ~(OBD_MD_FLBLOCKS|OBD_MD_FLGRANT);
2070                 memset(buf, 0, sizeof(rawbuf));
2071                 rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2072                 if (rc) {
2073                         fprintf(stderr, "error: %s: invalid ioctl\n",
2074                                 jt_cmdname(argv[0]));
2075                         return rc;
2076                 }
2077                 rc = l2_ioctl(OBD_DEV_ID, cmd, buf);
2078                 shmem_bump(1);
2079                 if (rc) {
2080                         fprintf(stderr, "error: %s: #%d - %s on %s\n",
2081                                 jt_cmdname(argv[0]), i, strerror(rc = errno),
2082                                 write ? "write" : "read");
2083                         break;
2084                 } else if (be_verbose(verbose, &next_time,i, &next_count,count)) {
2085                         shmem_lock ();
2086                         printf("%s: %s number %d @ %jd:%ju for %d\n",
2087                                jt_cmdname(argv[0]), write ? "write" : "read", i,
2088                                (uintmax_t)ostid_id(&data.ioc_obdo1.o_oi),
2089                                (uintmax_t)data.ioc_offset,
2090                                (int)(pages * getpagesize()));
2091                         shmem_unlock ();
2092                 }
2093
2094                 if (!repeat_offset) {
2095 #ifdef MAX_THREADS
2096                         if (stride == len) {
2097                                 data.ioc_offset += stride;
2098                         } else if (i < count) {
2099                                 shmem_lock ();
2100                                 data.ioc_offset =
2101                                         shared_data->body.offsets[obj_idx];
2102                                 shared_data->body.offsets[obj_idx] += len;
2103                                 shmem_unlock ();
2104                         }
2105 #else
2106                         data.ioc_offset += len;
2107                         obj_idx = 0; /* avoids an unused var warning */
2108 #endif
2109                 }
2110         }
2111
2112         if (!rc) {
2113                 struct timeval end;
2114                 double diff;
2115
2116                 gettimeofday(&end, NULL);
2117
2118                 diff = difftime(&end, &start);
2119
2120                 --i;
2121                 if (verbose != 0)
2122                         printf("%s: %s %dx%d pages in %.3fs (%.3f MB/s): %s",
2123                                jt_cmdname(argv[0]), write ? "wrote" : "read",
2124                                i, pages, diff,
2125                                ((double)i * pages * getpagesize()) /
2126                                (diff * 1048576.0),
2127                                ctime(&end.tv_sec));
2128         }
2129
2130 #ifdef MAX_THREADS
2131         if (thread) {
2132                 shmem_lock();
2133                 shmem_end_time_locked();
2134                 shmem_unlock();
2135         }
2136 #endif
2137         return rc;
2138 }
2139
2140 int jt_obd_lov_getconfig(int argc, char **argv)
2141 {
2142         struct obd_ioctl_data data;
2143         struct lov_desc desc;
2144         struct obd_uuid *uuidarray;
2145         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2146         __u32 *obdgens;
2147         char *path;
2148         int rc, fd;
2149
2150         memset(&data, 0, sizeof(data));
2151         data.ioc_dev = cur_device;
2152
2153         if (argc != 2)
2154                 return CMD_HELP;
2155
2156         path = argv[1];
2157         fd = open(path, O_RDONLY);
2158         if (fd < 0) {
2159                 fprintf(stderr, "open \"%s\" failed: %s\n", path,
2160                         strerror(errno));
2161                 return -errno;
2162         }
2163
2164         memset(&desc, 0, sizeof(desc));
2165         obd_str2uuid(&desc.ld_uuid, argv[1]);
2166         desc.ld_tgt_count = ((OBD_MAX_IOCTL_BUFFER-sizeof(data)-sizeof(desc)) /
2167                              (sizeof(*uuidarray) + sizeof(*obdgens)));
2168
2169 repeat:
2170         uuidarray = calloc(desc.ld_tgt_count, sizeof(*uuidarray));
2171         if (!uuidarray) {
2172                 fprintf(stderr, "error: %s: no memory for %d uuid's\n",
2173                         jt_cmdname(argv[0]), desc.ld_tgt_count);
2174                 rc = -ENOMEM;
2175                 goto out;
2176         }
2177         obdgens = calloc(desc.ld_tgt_count, sizeof(*obdgens));
2178         if (!obdgens) {
2179                 fprintf(stderr, "error: %s: no memory for %d generation #'s\n",
2180                         jt_cmdname(argv[0]), desc.ld_tgt_count);
2181                 rc = -ENOMEM;
2182                 goto out_uuidarray;
2183         }
2184
2185         memset(buf, 0, sizeof(rawbuf));
2186         data.ioc_inllen1 = sizeof(desc);
2187         data.ioc_inlbuf1 = (char *)&desc;
2188         data.ioc_inllen2 = desc.ld_tgt_count * sizeof(*uuidarray);
2189         data.ioc_inlbuf2 = (char *)uuidarray;
2190         data.ioc_inllen3 = desc.ld_tgt_count * sizeof(*obdgens);
2191         data.ioc_inlbuf3 = (char *)obdgens;
2192
2193         if (obd_ioctl_pack(&data, &buf, sizeof(rawbuf))) {
2194                 fprintf(stderr, "error: %s: invalid ioctl\n",
2195                         jt_cmdname(argv[0]));
2196                 rc = -EINVAL;
2197                 goto out_obdgens;
2198         }
2199         rc = ioctl(fd, OBD_IOC_LOV_GET_CONFIG, buf);
2200         if (rc == -ENOSPC) {
2201                 free(uuidarray);
2202                 free(obdgens);
2203                 goto repeat;
2204         } else if (rc) {
2205                 fprintf(stderr, "error: %s: ioctl error: %s\n",
2206                         jt_cmdname(argv[0]), strerror(rc = errno));
2207         } else {
2208                 struct obd_uuid *uuidp;
2209                 __u32 *genp;
2210                 int i;
2211
2212                 if (obd_ioctl_unpack(&data, buf, sizeof(rawbuf))) {
2213                         fprintf(stderr, "error: %s: invalid reply\n",
2214                                 jt_cmdname(argv[0]));
2215                         rc = -EINVAL;
2216                         goto out;
2217                 }
2218                 if (desc.ld_default_stripe_count == (__u32)-1)
2219                         printf("default_stripe_count: %d\n", -1);
2220                 else
2221                         printf("default_stripe_count: %u\n",
2222                                desc.ld_default_stripe_count);
2223                 printf("default_stripe_size: %ju\n",
2224                        (uintmax_t)desc.ld_default_stripe_size);
2225                 printf("default_stripe_offset: %ju\n",
2226                        (uintmax_t)desc.ld_default_stripe_offset);
2227                 printf("default_stripe_pattern: %u\n", desc.ld_pattern);
2228                 printf("obd_count: %u\n", desc.ld_tgt_count);
2229                 printf("OBDS:\tobdidx\t\tobdgen\t\t obduuid\n");
2230                 uuidp = uuidarray;
2231                 genp = obdgens;
2232                 for (i = 0; i < desc.ld_tgt_count; i++, uuidp++, genp++)
2233                         printf("\t%6u\t%14u\t\t %s\n", i, *genp, (char *)uuidp);
2234         }
2235 out_obdgens:
2236         free(obdgens);
2237 out_uuidarray:
2238         free(uuidarray);
2239 out:
2240         close(fd);
2241         return rc;
2242 }
2243
2244 static int do_activate(int argc, char **argv, int flag)
2245 {
2246         struct obd_ioctl_data data;
2247         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2248         int rc;
2249
2250         memset(&data, 0, sizeof(data));
2251         data.ioc_dev = cur_device;
2252         if (argc != 1)
2253                 return CMD_HELP;
2254
2255         /* reuse offset for 'active' */
2256         data.ioc_offset = flag;
2257
2258         memset(buf, 0, sizeof(rawbuf));
2259         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2260         if (rc) {
2261                 fprintf(stderr, "error: %s: invalid ioctl\n",
2262                         jt_cmdname(argv[0]));
2263                 return rc;
2264         }
2265         rc = l2_ioctl(OBD_DEV_ID, IOC_OSC_SET_ACTIVE, buf);
2266         if (rc)
2267                 fprintf(stderr, "error: %s: failed: %s\n",
2268                         jt_cmdname(argv[0]), strerror(rc = errno));
2269
2270         return rc;
2271 }
2272
2273 /**
2274  * Replace nids for given device.
2275  * lctl replace_nids <devicename> <nid1>[,nid2,nid3]
2276  * Command should be started on MGS server.
2277  * Only MGS server should be started (command execution
2278  * returns error in another cases). Command mount
2279  * -t lustre <MDT partition> -o nosvc <mount point>
2280  * can be used for that.
2281  *
2282  * llogs for MDTs and clients are processed. All
2283  * records copied as is except add_uuid and setup. This records
2284  * are skipped and recorded with new nids and uuid.
2285  *
2286  * \see mgs_replace_nids
2287  * \see mgs_replace_nids_log
2288  * \see mgs_replace_handler
2289  */
2290 int jt_replace_nids(int argc, char **argv)
2291 {
2292         int rc;
2293         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2294         struct obd_ioctl_data data;
2295
2296         memset(&data, 0, sizeof(data));
2297         data.ioc_dev = get_mgs_device();
2298         if (argc != 3)
2299                 return CMD_HELP;
2300
2301         data.ioc_inllen1 = strlen(argv[1]) + 1;
2302         data.ioc_inlbuf1 = argv[1];
2303
2304         data.ioc_inllen2 = strlen(argv[2]) + 1;
2305         data.ioc_inlbuf2 = argv[2];
2306         memset(buf, 0, sizeof(rawbuf));
2307         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2308         if (rc) {
2309                 fprintf(stderr, "error: %s: invalid ioctl\n",
2310                         jt_cmdname(argv[0]));
2311                 return rc;
2312         }
2313
2314         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_REPLACE_NIDS, buf);
2315         if (rc < 0) {
2316                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
2317                         strerror(rc = errno));
2318         }
2319
2320         return rc;
2321 }
2322
2323 int jt_obd_deactivate(int argc, char **argv)
2324 {
2325         return do_activate(argc, argv, 0);
2326 }
2327
2328 int jt_obd_activate(int argc, char **argv)
2329 {
2330         return do_activate(argc, argv, 1);
2331 }
2332
2333 int jt_obd_recover(int argc, char **argv)
2334 {
2335         int rc;
2336         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2337         struct obd_ioctl_data data;
2338
2339         memset(&data, 0, sizeof(data));
2340         data.ioc_dev = cur_device;
2341         if (argc > 2)
2342                 return CMD_HELP;
2343
2344         if (argc == 2) {
2345                 data.ioc_inllen1 = strlen(argv[1]) + 1;
2346                 data.ioc_inlbuf1 = argv[1];
2347         }
2348
2349         memset(buf, 0, sizeof(rawbuf));
2350         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2351         if (rc) {
2352                 fprintf(stderr, "error: %s: invalid ioctl\n",
2353                         jt_cmdname(argv[0]));
2354                 return rc;
2355         }
2356         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_CLIENT_RECOVER, buf);
2357         if (rc < 0) {
2358                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
2359                         strerror(rc = errno));
2360         }
2361
2362         return rc;
2363 }
2364
2365 int jt_obd_mdc_lookup(int argc, char **argv)
2366 {
2367         struct obd_ioctl_data data;
2368         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2369         char *parent, *child;
2370         int rc, fd, verbose = 1;
2371
2372         if (argc < 3 || argc > 4)
2373                 return CMD_HELP;
2374
2375         parent = argv[1];
2376         child = argv[2];
2377         if (argc == 4)
2378                 verbose = get_verbose(argv[0], argv[3]);
2379
2380         memset(&data, 0, sizeof(data));
2381         data.ioc_dev = cur_device;
2382
2383         data.ioc_inllen1 = strlen(child) + 1;
2384         data.ioc_inlbuf1 = child;
2385
2386         memset(buf, 0, sizeof(rawbuf));
2387         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2388         if (rc) {
2389                 fprintf(stderr, "error: %s: invalid ioctl\n",
2390                         jt_cmdname(argv[0]));
2391                 return rc;
2392         }
2393
2394         fd = open(parent, O_RDONLY);
2395         if (fd < 0) {
2396                 fprintf(stderr, "open \"%s\" failed: %s\n", parent,
2397                         strerror(errno));
2398                 return -1;
2399         }
2400
2401         rc = ioctl(fd, IOC_MDC_LOOKUP, buf);
2402         if (rc < 0) {
2403                 fprintf(stderr, "error: %s: ioctl error: %s\n",
2404                         jt_cmdname(argv[0]), strerror(rc = errno));
2405         }
2406         close(fd);
2407
2408         if (verbose) {
2409                 rc = obd_ioctl_unpack(&data, buf, sizeof(rawbuf));
2410                 if (rc) {
2411                         fprintf(stderr, "error: %s: invalid reply\n",
2412                                 jt_cmdname(argv[0]));
2413                         return rc;
2414                 }
2415                 printf("%s: mode %o uid %d gid %d\n", child,
2416                        data.ioc_obdo1.o_mode, data.ioc_obdo1.o_uid,
2417                        data.ioc_obdo1.o_gid);
2418         }
2419
2420         return rc;
2421 }
2422
2423 int jt_llog_catlist(int argc, char **argv)
2424 {
2425         struct obd_ioctl_data data;
2426         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2427         int rc;
2428
2429         if (argc != 1)
2430                 return CMD_HELP;
2431
2432         memset(&data, 0, sizeof(data));
2433         data.ioc_dev = cur_device;
2434         data.ioc_inllen1 = sizeof(rawbuf) - cfs_size_round(sizeof(data));
2435         memset(buf, 0, sizeof(rawbuf));
2436         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2437         if (rc) {
2438                 fprintf(stderr, "error: %s: invalid ioctl\n",
2439                         jt_cmdname(argv[0]));
2440                 return rc;
2441         }
2442         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_CATLOGLIST, buf);
2443         if (rc == 0)
2444                 fprintf(stdout, "%s", ((struct obd_ioctl_data*)buf)->ioc_bulk);
2445         else
2446                 fprintf(stderr, "OBD_IOC_CATLOGLIST failed: %s\n",
2447                         strerror(errno));
2448
2449         return rc;
2450 }
2451
2452 int jt_llog_info(int argc, char **argv)
2453 {
2454         struct obd_ioctl_data data;
2455         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2456         int rc;
2457
2458         if (argc != 2)
2459                 return CMD_HELP;
2460
2461         memset(&data, 0, sizeof(data));
2462         data.ioc_dev = cur_device;
2463         data.ioc_inllen1 = strlen(argv[1]) + 1;
2464         data.ioc_inlbuf1 = argv[1];
2465         data.ioc_inllen2 = sizeof(rawbuf) - cfs_size_round(sizeof(data)) -
2466                 cfs_size_round(data.ioc_inllen1);
2467         memset(buf, 0, sizeof(rawbuf));
2468         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2469         if (rc) {
2470                 fprintf(stderr, "error: %s: invalid ioctl\n",
2471                         jt_cmdname(argv[0]));
2472                 return rc;
2473         }
2474
2475         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_INFO, buf);
2476         if (rc == 0)
2477                 fprintf(stdout, "%s", ((struct obd_ioctl_data*)buf)->ioc_bulk);
2478         else
2479                 fprintf(stderr, "OBD_IOC_LLOG_INFO failed: %s\n",
2480                         strerror(errno));
2481
2482         return rc;
2483 }
2484
2485 int jt_llog_print(int argc, char **argv)
2486 {
2487         struct obd_ioctl_data data;
2488         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2489         int rc;
2490
2491         if (argc != 2 && argc != 4)
2492                 return CMD_HELP;
2493
2494         memset(&data, 0, sizeof(data));
2495         data.ioc_dev = cur_device;
2496         data.ioc_inllen1 = strlen(argv[1]) + 1;
2497         data.ioc_inlbuf1 = argv[1];
2498         if (argc == 4) {
2499                 data.ioc_inllen2 = strlen(argv[2]) + 1;
2500                 data.ioc_inlbuf2 = argv[2];
2501                 data.ioc_inllen3 = strlen(argv[3]) + 1;
2502                 data.ioc_inlbuf3 = argv[3];
2503         } else {
2504                 char from[2] = "1", to[3] = "-1";
2505                 data.ioc_inllen2 = strlen(from) + 1;
2506                 data.ioc_inlbuf2 = from;
2507                 data.ioc_inllen3 = strlen(to) + 1;
2508                 data.ioc_inlbuf3 = to;
2509         }
2510         data.ioc_inllen4 = sizeof(rawbuf) - cfs_size_round(sizeof(data)) -
2511                 cfs_size_round(data.ioc_inllen1) -
2512                 cfs_size_round(data.ioc_inllen2) -
2513                 cfs_size_round(data.ioc_inllen3);
2514         memset(buf, 0, sizeof(rawbuf));
2515         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2516         if (rc) {
2517                 fprintf(stderr, "error: %s: invalid ioctl\n",
2518                         jt_cmdname(argv[0]));
2519                 return rc;
2520         }
2521
2522         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_PRINT, buf);
2523         if (rc == 0)
2524                 fprintf(stdout, "%s", ((struct obd_ioctl_data*)buf)->ioc_bulk);
2525         else
2526                 fprintf(stderr, "OBD_IOC_LLOG_PRINT failed: %s\n",
2527                         strerror(errno));
2528
2529         return rc;
2530 }
2531
2532 static int llog_cancel_parse_optional(int argc, char **argv,
2533                                       struct obd_ioctl_data *data)
2534 {
2535         int cOpt;
2536         const char *const short_options = "c:l:i:h";
2537         const struct option long_options[] = {
2538                 {"catalog", required_argument, NULL, 'c'},
2539                 {"log_id", required_argument, NULL, 'l'},
2540                 {"log_idx", required_argument, NULL, 'i'},
2541                 {"help", no_argument, NULL, 'h'},
2542                 {NULL, 0, NULL, 0}
2543         };
2544
2545         /* sanity check */
2546         if (!data || argc <= 1) {
2547                 return -1;
2548         }
2549
2550         /*now process command line arguments*/
2551         while ((cOpt = getopt_long(argc, argv, short_options,
2552                                         long_options, NULL)) != -1) {
2553                 switch (cOpt) {
2554                 case 'c':
2555                         data->ioc_inllen1 = strlen(optarg) + 1;
2556                         data->ioc_inlbuf1 = optarg;
2557                         break;
2558
2559                 case 'l':
2560                         data->ioc_inllen2 = strlen(optarg) + 1;
2561                         data->ioc_inlbuf2 = optarg;
2562                         break;
2563
2564                 case 'i':
2565                         data->ioc_inllen3 = strlen(optarg) + 1;
2566                         data->ioc_inlbuf3 = optarg;
2567                         break;
2568
2569                 case 'h':
2570                 default:
2571                         return -1;
2572                 }
2573         }
2574
2575         if ((data->ioc_inlbuf1 == NULL) || (data->ioc_inlbuf3 == NULL)) {
2576                 /* missing mandatory parameters */
2577                 return -1;
2578         }
2579
2580         return 0;
2581 }
2582
2583 int jt_llog_cancel(int argc, char **argv)
2584 {
2585         struct obd_ioctl_data data;
2586         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2587         int rc, i;
2588
2589         /* check that the arguments provided are either all
2590          * optional or all positional.  No mixing allowed
2591          *
2592          * if argc is 4 or 3 then check all arguments to ensure that none
2593          * of them start with a '-'.  If so then this is invalid.
2594          * Otherwise if arg is > 4 then assume that this is optional
2595          * arguments, and parse as such ignoring any thing that's not
2596          * optional.  The result is that user must use optional arguments
2597          * for all mandatory parameters.  Code will ignore all other args
2598          *
2599          * The positional arguments option should eventually be phased out.
2600          */
2601         memset(&data, 0, sizeof(data));
2602         data.ioc_dev = cur_device;
2603
2604         if (argc == 3 || argc == 4) {
2605                 for (i = 1; i < argc; i++) {
2606                         if (argv[i][0] == '-')
2607                                 return CMD_HELP;
2608                 }
2609                 data.ioc_inllen1 = strlen(argv[1]) + 1;
2610                 data.ioc_inlbuf1 = argv[1];
2611                 if (argc == 4) {
2612                         data.ioc_inllen2 = strlen(argv[2]) + 1;
2613                         data.ioc_inlbuf2 = argv[2];
2614                         data.ioc_inllen3 = strlen(argv[3]) + 1;
2615                         data.ioc_inlbuf3 = argv[3];
2616                 } else {
2617                         data.ioc_inllen3 = strlen(argv[2]) + 1;
2618                         data.ioc_inlbuf3 = argv[2];
2619                 }
2620         } else {
2621                 if (llog_cancel_parse_optional(argc, argv, &data) != 0)
2622                         return CMD_HELP;
2623         }
2624
2625         memset(buf, 0, sizeof(rawbuf));
2626         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2627         if (rc) {
2628                 fprintf(stderr, "error: %s: invalid ioctl\n",
2629                         jt_cmdname(argv[0]));
2630                 return rc;
2631         }
2632
2633         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_CANCEL, buf);
2634         if (rc == 0)
2635                 fprintf(stdout, "index %s was canceled.\n",
2636                         argc == 4 ? argv[3] : argv[2]);
2637         else
2638                 fprintf(stderr, "OBD_IOC_LLOG_CANCEL failed: %s\n",
2639                         strerror(errno));
2640
2641         return rc;
2642 }
2643
2644 int jt_llog_check(int argc, char **argv)
2645 {
2646         struct obd_ioctl_data data;
2647         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2648         int rc;
2649
2650         if (argc != 2 && argc != 4)
2651                 return CMD_HELP;
2652
2653         memset(&data, 0, sizeof(data));
2654         data.ioc_dev = cur_device;
2655         data.ioc_inllen1 = strlen(argv[1]) + 1;
2656         data.ioc_inlbuf1 = argv[1];
2657         if (argc == 4) {
2658                 data.ioc_inllen2 = strlen(argv[2]) + 1;
2659                 data.ioc_inlbuf2 = argv[2];
2660                 data.ioc_inllen3 = strlen(argv[3]) + 1;
2661                 data.ioc_inlbuf3 = argv[3];
2662         } else {
2663                 char from[2] = "1", to[3] = "-1";
2664                 data.ioc_inllen2 = strlen(from) + 1;
2665                 data.ioc_inlbuf2 = from;
2666                 data.ioc_inllen3 = strlen(to) + 1;
2667                 data.ioc_inlbuf3 = to;
2668         }
2669         data.ioc_inllen4 = sizeof(rawbuf) - cfs_size_round(sizeof(data)) -
2670                 cfs_size_round(data.ioc_inllen1) -
2671                 cfs_size_round(data.ioc_inllen2) -
2672                 cfs_size_round(data.ioc_inllen3);
2673         memset(buf, 0, sizeof(rawbuf));
2674         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2675         if (rc) {
2676                 fprintf(stderr, "error: %s: invalid ioctl\n",
2677                         jt_cmdname(argv[0]));
2678                 return rc;
2679         }
2680
2681         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_CHECK, buf);
2682         if (rc == 0)
2683                 fprintf(stdout, "%s", ((struct obd_ioctl_data*)buf)->ioc_bulk);
2684         else
2685                 fprintf(stderr, "OBD_IOC_LLOG_CHECK failed: %s\n",
2686                         strerror(errno));
2687         return rc;
2688 }
2689
2690 int jt_llog_remove(int argc, char **argv)
2691 {
2692         struct obd_ioctl_data data;
2693         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2694         int rc;
2695
2696         if (argc != 3 && argc != 2)
2697                 return CMD_HELP;
2698
2699         memset(&data, 0, sizeof(data));
2700         data.ioc_dev = cur_device;
2701         data.ioc_inllen1 = strlen(argv[1]) + 1;
2702         data.ioc_inlbuf1 = argv[1];
2703         if (argc == 3){
2704                 data.ioc_inllen2 = strlen(argv[2]) + 1;
2705                 data.ioc_inlbuf2 = argv[2];
2706         }
2707         memset(buf, 0, sizeof(rawbuf));
2708         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2709         if (rc) {
2710                 fprintf(stderr, "error: %s: invalid ioctl\n",
2711                         jt_cmdname(argv[0]));
2712                 return rc;
2713         }
2714
2715         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_REMOVE, buf);
2716         if (rc == 0) {
2717                 if (argc == 2)
2718                         fprintf(stdout, "log %s is removed.\n", argv[1]);
2719                 else
2720                         fprintf(stdout, "the log in catalog %s is removed. \n",
2721                                 argv[1]);
2722         } else
2723                 fprintf(stderr, "OBD_IOC_LLOG_REMOVE failed: %s\n",
2724                         strerror(errno));
2725
2726         return rc;
2727 }
2728
2729 static void signal_server(int sig)
2730 {
2731         if (sig == SIGINT) {
2732                 do_disconnect("sigint", 1);
2733                 exit(1);
2734         } else
2735                 fprintf(stderr, "%s: got signal %d\n", jt_cmdname("sigint"), sig);
2736 }
2737
2738 int obd_initialize(int argc, char **argv)
2739 {
2740         if (shmem_setup() != 0)
2741                 return -1;
2742
2743         register_ioc_dev(OBD_DEV_ID, OBD_DEV_PATH,
2744                          OBD_DEV_MAJOR, OBD_DEV_MINOR);
2745
2746         return 0;
2747 }
2748
2749 void obd_finalize(int argc, char **argv)
2750 {
2751         struct sigaction sigact;
2752
2753         /* sigact initialization */
2754         sigact.sa_handler = signal_server;
2755         sigfillset(&sigact.sa_mask);
2756         sigact.sa_flags = SA_RESTART;
2757         /* coverity[uninit_use_in_call] */
2758         sigaction(SIGINT, &sigact, NULL);
2759
2760         shmem_cleanup();
2761         do_disconnect(argv[0], 1);
2762 }
2763
2764 static int check_pool_cmd(enum lcfg_command_type cmd,
2765                           char *fsname, char *poolname,
2766                           char *ostname)
2767 {
2768         int rc;
2769
2770         rc = llapi_search_ost(fsname, poolname, ostname);
2771         if (rc < 0 && (cmd != LCFG_POOL_NEW)) {
2772                 fprintf(stderr, "Pool %s.%s not found\n",
2773                         fsname, poolname);
2774                 return rc;
2775         }
2776
2777         switch (cmd) {
2778         case LCFG_POOL_NEW: {
2779                 if (ostname != NULL)
2780                         return -EINVAL;
2781
2782                 if (rc >= 0) {
2783                         fprintf(stderr, "Pool %s.%s already exists\n",
2784                                 fsname, poolname);
2785                         return -EEXIST;
2786                 }
2787                 return 0;
2788         }
2789         case LCFG_POOL_DEL: {
2790                 if (ostname != NULL)
2791                         return -EINVAL;
2792
2793                 if (rc == 1) {
2794                         fprintf(stderr, "Pool %s.%s not empty, "
2795                                 "please remove all members\n",
2796                                 fsname, poolname);
2797                         return -ENOTEMPTY;
2798                 }
2799                 return 0;
2800         }
2801         case LCFG_POOL_ADD: {
2802                 if (rc == 1) {
2803                         fprintf(stderr, "OST %s is already in pool %s.%s\n",
2804                                 ostname, fsname, poolname);
2805                         return -EEXIST;
2806                 }
2807                 rc = llapi_search_ost(fsname, NULL, ostname);
2808                 if (rc == 0) {
2809                         fprintf(stderr, "OST %s is not part of the '%s' fs.\n",
2810                                 ostname, fsname);
2811                         return -ENOENT;
2812                 }
2813                 return 0;
2814         }
2815         case LCFG_POOL_REM: {
2816                 if (rc == 0) {
2817                         fprintf(stderr, "OST %s not found in pool %s.%s\n",
2818                                 ostname, fsname, poolname);
2819                         return -ENOENT;
2820                 }
2821                 return 0;
2822         }
2823         default:
2824                 break;
2825         } /* switch */
2826         return -EINVAL;
2827 }
2828
2829 /* This check only verifies that the changes have been "pushed out" to
2830    the client successfully.  This involves waiting for a config update,
2831    and so may fail because of problems in that code or post-command
2832    network loss. So reporting a warning is appropriate, but not a failure.
2833 */
2834 static int check_pool_cmd_result(enum lcfg_command_type cmd,
2835                                  char *fsname, char *poolname,
2836                                  char *ostname)
2837 {
2838         int cpt = 10;
2839         int rc = 0;
2840
2841         switch (cmd) {
2842         case LCFG_POOL_NEW: {
2843                 do {
2844                         rc = llapi_search_ost(fsname, poolname, NULL);
2845                         if (rc == -ENODEV)
2846                                 return rc;
2847                         if (rc < 0)
2848                                 sleep(2);
2849                         cpt--;
2850                 } while ((rc < 0) && (cpt > 0));
2851                 if (rc >= 0) {
2852                         fprintf(stderr, "Pool %s.%s created\n",
2853                                 fsname, poolname);
2854                         return 0;
2855                 } else {
2856                         fprintf(stderr, "Warning, pool %s.%s not found\n",
2857                                 fsname, poolname);
2858                         return -ENOENT;
2859                 }
2860         }
2861         case LCFG_POOL_DEL: {
2862                 do {
2863                         rc = llapi_search_ost(fsname, poolname, NULL);
2864                         if (rc == -ENODEV)
2865                                 return rc;
2866                         if (rc >= 0)
2867                                 sleep(2);
2868                         cpt--;
2869                 } while ((rc >= 0) && (cpt > 0));
2870                 if (rc < 0) {
2871                         fprintf(stderr, "Pool %s.%s destroyed\n",
2872                                 fsname, poolname);
2873                         return 0;
2874                 } else {
2875                         fprintf(stderr, "Warning, pool %s.%s still found\n",
2876                                 fsname, poolname);
2877                         return -EEXIST;
2878                 }
2879         }
2880         case LCFG_POOL_ADD: {
2881                 do {
2882                         rc = llapi_search_ost(fsname, poolname, ostname);
2883                         if (rc == -ENODEV)
2884                                 return rc;
2885                         if (rc != 1)
2886                                 sleep(2);
2887                         cpt--;
2888                 } while ((rc != 1) && (cpt > 0));
2889                 if (rc == 1) {
2890                         fprintf(stderr, "OST %s added to pool %s.%s\n",
2891                                 ostname, fsname, poolname);
2892                         return 0;
2893                 } else {
2894                         fprintf(stderr, "Warning, OST %s not found in pool %s.%s\n",
2895                                 ostname, fsname, poolname);
2896                         return -ENOENT;
2897                 }
2898         }
2899         case LCFG_POOL_REM: {
2900                 do {
2901                         rc = llapi_search_ost(fsname, poolname, ostname);
2902                         if (rc == -ENODEV)
2903                                 return rc;
2904                         if (rc == 1)
2905                                 sleep(2);
2906                         cpt--;
2907                 } while ((rc == 1) && (cpt > 0));
2908                 if (rc != 1) {
2909                         fprintf(stderr, "OST %s removed from pool %s.%s\n",
2910                                 ostname, fsname, poolname);
2911                         return 0;
2912                 } else {
2913                         fprintf(stderr, "Warning, OST %s still found in pool %s.%s\n",
2914                                 ostname, fsname, poolname);
2915                         return -EEXIST;
2916                 }
2917         }
2918         default:
2919                 break;
2920         }
2921         return -EINVAL;
2922 }
2923
2924 static int check_and_complete_ostname(char *fsname, char *ostname)
2925 {
2926         char *ptr;
2927         char real_ostname[MAX_OBD_NAME + 1];
2928         char i;
2929
2930         /* if OST name does not start with fsname, we add it */
2931         /* if not check if the fsname is the right one */
2932         ptr = strchr(ostname, '-');
2933         if (ptr == NULL) {
2934                 sprintf(real_ostname, "%s-%s", fsname, ostname);
2935         } else if (strncmp(ostname, fsname, strlen(fsname)) != 0) {
2936                 fprintf(stderr, "%s does not start with fsname %s\n",
2937                         ostname, fsname);
2938                 return -EINVAL;
2939         } else {
2940                 if (strlen(ostname) > sizeof(real_ostname)-1)
2941                         return -E2BIG;
2942                 strncpy(real_ostname, ostname, sizeof(real_ostname));
2943         }
2944         /* real_ostname is fsname-????? */
2945         ptr = real_ostname + strlen(fsname) + 1;
2946         if (strncmp(ptr, "OST", 3) != 0) {
2947                 fprintf(stderr, "%s does not start by %s-OST nor OST\n",
2948                         ostname, fsname);
2949                 return -EINVAL;
2950         }
2951         /* real_ostname is fsname-OST????? */
2952         ptr += 3;
2953         for (i = 0; i < 4; i++) {
2954                 if (!isxdigit(*ptr)) {
2955                         fprintf(stderr,
2956                                 "ost's index in %s is not an hexa number\n",
2957                                 ostname);
2958                         return -EINVAL;
2959                 }
2960                 ptr++;
2961         }
2962         /* real_ostname is fsname-OSTXXXX????? */
2963         /* if OST name does not end with _UUID, we add it */
2964         if (*ptr == '\0') {
2965                 strcat(real_ostname, "_UUID");
2966         } else if (strcmp(ptr, "_UUID") != 0) {
2967                 fprintf(stderr,
2968                         "ostname %s does not end with _UUID\n", ostname);
2969                 return -EINVAL;
2970         }
2971         /* real_ostname is fsname-OSTXXXX_UUID */
2972         strcpy(ostname, real_ostname);
2973         return 0;
2974 }
2975
2976 /* returns 0 or -errno */
2977 static int pool_cmd(enum lcfg_command_type cmd,
2978                     char *cmdname, char *fullpoolname,
2979                     char *fsname, char *poolname, char *ostname)
2980 {
2981         int rc = 0;
2982         struct obd_ioctl_data data;
2983         struct lustre_cfg_bufs bufs;
2984         struct lustre_cfg *lcfg;
2985         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2986
2987         rc = check_pool_cmd(cmd, fsname, poolname, ostname);
2988         if (rc == -ENODEV)
2989                 fprintf(stderr, "Can't verify pool command since there "
2990                         "is no local MDT or client, proceeding anyhow...\n");
2991         else if (rc)
2992                 return rc;
2993
2994         lustre_cfg_bufs_reset(&bufs, NULL);
2995         lustre_cfg_bufs_set_string(&bufs, 0, cmdname);
2996         lustre_cfg_bufs_set_string(&bufs, 1, fullpoolname);
2997         if (ostname != NULL)
2998                 lustre_cfg_bufs_set_string(&bufs, 2, ostname);
2999
3000         lcfg = lustre_cfg_new(cmd, &bufs);
3001         if (lcfg == NULL)
3002                 return -ENOMEM;
3003
3004         memset(&data, 0, sizeof(data));
3005         rc = data.ioc_dev = get_mgs_device();
3006         if (rc < 0)
3007                 goto out;
3008
3009         data.ioc_type = LUSTRE_CFG_TYPE;
3010         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
3011                                         lcfg->lcfg_buflens);
3012         data.ioc_pbuf1 = (void *)lcfg;
3013
3014         memset(buf, 0, sizeof(rawbuf));
3015         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
3016         if (rc) {
3017                 fprintf(stderr, "error: %s: invalid ioctl\n",
3018                         jt_cmdname(cmdname));
3019                 lustre_cfg_free(lcfg);
3020                 return rc;
3021         }
3022         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_POOL, buf);
3023 out:
3024         if (rc)
3025                 rc = -errno;
3026         lustre_cfg_free(lcfg);
3027         return rc;
3028 }
3029
3030 /**
3031  * Format and send the ioctl to the MGS.
3032  *
3033  * \param       cmd             IOCTL to send
3034  * \param       ret_data        void pointer to return anything from
3035  *                              ioctl
3036  * \param       num_args        number of arguments to pack into the
3037  *                              ioctl buffer
3038  * \param       argv[]          variable number of string arguments
3039  *
3040  * \retval                      0 on success
3041  */
3042 static int nodemap_cmd(enum lcfg_command_type cmd, void *ret_data,
3043                        unsigned int ret_size, ...)
3044 {
3045         va_list                 ap;
3046         char                    *arg;
3047         int                     i = 0;
3048         struct lustre_cfg_bufs  bufs;
3049         struct obd_ioctl_data   data;
3050         struct lustre_cfg       *lcfg;
3051         char                    rawbuf[MAX_IOC_BUFLEN];
3052         char                    *buf = rawbuf;
3053         int                     rc = 0;
3054
3055         lustre_cfg_bufs_reset(&bufs, NULL);
3056
3057         va_start(ap, ret_size);
3058         arg = va_arg(ap, char *);
3059         while (arg != NULL) {
3060                 lustre_cfg_bufs_set_string(&bufs, i, arg);
3061                 i++;
3062                 arg = va_arg(ap, char *);
3063         }
3064         va_end(ap);
3065
3066         lcfg = lustre_cfg_new(cmd, &bufs);
3067         if (lcfg == NULL)
3068                 return -ENOMEM;
3069
3070         memset(&data, 0, sizeof(data));
3071         rc = data.ioc_dev = get_mgs_device();
3072         if (rc < 0)
3073                 goto out;
3074
3075         data.ioc_type = LUSTRE_CFG_TYPE;
3076         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
3077                          lcfg->lcfg_buflens);
3078         data.ioc_pbuf1 = (void *)lcfg;
3079
3080         memset(buf, 0, sizeof(rawbuf));
3081         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
3082         if (rc != 0) {
3083                 fprintf(stderr, "error: invalid ioctl: %08x errno: %d with "
3084                                "rc=%d\n", cmd, errno, rc);
3085                 goto out;
3086         }
3087
3088         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_NODEMAP, buf);
3089         if (rc != 0) {
3090                 fprintf(stderr, "error: invalid ioctl: %08x errno: %d with "
3091                                "rc=%d\n", cmd, errno, rc);
3092                 goto out;
3093         }
3094
3095         if (ret_data != NULL) {
3096                 rc = obd_ioctl_unpack(&data, buf, sizeof(rawbuf));
3097                 if (rc != 0)
3098                         goto out;
3099
3100                 if (ret_size > data.ioc_plen1)
3101                         ret_size = data.ioc_plen1;
3102
3103                 memcpy(ret_data, data.ioc_pbuf1, ret_size);
3104         }
3105 out:
3106         lustre_cfg_free(lcfg);
3107
3108         return rc;
3109 }
3110
3111 /**
3112  * activate nodemap functions
3113  *
3114  * \param       argc            number of args
3115  * \param       argv[]          variable string arguments
3116  *
3117  * argv[0]                      1 for activate or 0 for deactivate
3118  *
3119  * \retval                      0 on success
3120  */
3121 int jt_nodemap_activate(int argc, char **argv)
3122 {
3123         int rc;
3124
3125         rc = nodemap_cmd(LCFG_NODEMAP_ACTIVATE, NULL, 0, argv[0], argv[1],
3126                          NULL);
3127
3128         if (rc != 0) {
3129                 errno = -rc;
3130                 perror(argv[0]);
3131         }
3132
3133         return rc;
3134 }
3135
3136 /**
3137  * add a nodemap
3138  *
3139  * \param       argc            number of args
3140  * \param       argv[]          variable string arguments
3141  *
3142  * argv[0]                      nodemap name
3143  *
3144  * \retval                      0 on success
3145  */
3146 int jt_nodemap_add(int argc, char **argv)
3147 {
3148         int rc;
3149
3150         rc = llapi_nodemap_exists(argv[1]);
3151         if (rc == 0) {
3152                 fprintf(stderr, "error: %s existing nodemap name\n", argv[1]);
3153                 return 1;
3154         }
3155
3156         rc = nodemap_cmd(LCFG_NODEMAP_ADD, NULL, 0, argv[0], argv[1], NULL);
3157
3158         if (rc != 0) {
3159                 errno = -rc;
3160                 perror(argv[0]);
3161         }
3162
3163         return rc;
3164 }
3165
3166 /**
3167  * delete a nodemap
3168  *
3169  * \param       argc            number of args
3170  * \param       argv[]          variable string arguments
3171  *
3172  * argv[0]                      nodemap name
3173  *
3174  * \retval                      0 on success
3175  */
3176 int jt_nodemap_del(int argc, char **argv)
3177 {
3178         int rc;
3179
3180         rc = llapi_nodemap_exists(argv[1]);
3181         if (rc != 0) {
3182                 fprintf(stderr, "error: %s not existing nodemap name\n",
3183                         argv[1]);
3184                 return rc;
3185         }
3186         rc = nodemap_cmd(LCFG_NODEMAP_DEL, NULL, 0, argv[0], argv[1], NULL);
3187
3188         if (rc != 0) {
3189                 errno = -rc;
3190                 perror(argv[0]);
3191         }
3192
3193         return rc;
3194 }
3195
3196 /**
3197  * test a nid for nodemap membership
3198  *
3199  * \param       argc            number of args
3200  * \param       argv[]          variable string arguments
3201  *
3202  * argv[0]                      properly formatted nid
3203  *
3204  * \retval                      0 on success
3205  */
3206 int jt_nodemap_test_nid(int argc, char **argv)
3207 {
3208
3209         char    rawbuf[MAX_IOC_BUFLEN];
3210         int     rc;
3211
3212         rc = nodemap_cmd(LCFG_NODEMAP_TEST_NID, &rawbuf, sizeof(rawbuf),
3213                          argv[0], argv[1], NULL);
3214         if (rc == 0)
3215                 printf("%s\n", (char *)rawbuf);
3216
3217         return rc;
3218 }
3219
3220 /**
3221  * test a nodemap id pair for mapping
3222  *
3223  * \param       argc            number of args
3224  * \param       argv[[]         variable string arguments
3225  *
3226  * \retval                      0 on success
3227  *
3228  * The argv array should contain the nodemap name, the id
3229  * to checking the mapping on, and the id type (UID or GID)
3230  *
3231  */
3232 int jt_nodemap_test_id(int argc, char **argv)
3233 {
3234         char    rawbuf[MAX_IOC_BUFLEN];
3235         char    *nidstr = NULL;
3236         char    *idstr = NULL;
3237         char    *typestr = NULL;
3238         int     rc = 0;
3239         int     c;
3240
3241         static struct option long_options[] = {
3242                 {
3243                         .name           = "nid",
3244                         .has_arg        = required_argument,
3245                         .flag           = 0,
3246                         .val            = 'n',
3247                 },
3248                 {
3249                         .name           = "idtype",
3250                         .has_arg        = required_argument,
3251                         .flag           = 0,
3252                         .val            = 't',
3253                 },
3254                 {
3255                         .name           = "id",
3256                         .has_arg        = required_argument,
3257                         .flag           = 0,
3258                         .val            = 'i',
3259                 },
3260                 {
3261                         NULL
3262                 }
3263         };
3264
3265         while ((c = getopt_long(argc, argv, "n:t:i:",
3266                                 long_options, NULL)) != -1) {
3267                 switch (c) {
3268                 case 'n':
3269                         nidstr = optarg;
3270                         break;
3271                 case 't':
3272                         typestr = optarg;
3273                         break;
3274                 case 'i':
3275                         idstr = optarg;
3276                         break;
3277                 }
3278         }
3279
3280         if (nidstr == NULL || typestr == NULL || idstr == NULL) {
3281                 fprintf(stderr, "usage: nodemap_test_id --nid <nid> "
3282                                 "--idtype [uid|gid] --id <id>\n");
3283                 return -1;
3284         }
3285
3286         rc = nodemap_cmd(LCFG_NODEMAP_TEST_ID, &rawbuf, sizeof(rawbuf),
3287                          argv[0], nidstr, typestr, idstr);
3288         if (rc == 0)
3289                 printf("%s\n", (char *)rawbuf);
3290
3291         return rc;
3292 }
3293
3294 /**
3295  * add an nid range to a nodemap
3296  *
3297  * \param       argc            number of args
3298  * \param       argv[]          variable string arguments
3299  *
3300  * --name                       nodemap name
3301  * --range                      properly formatted nid range
3302  *
3303  * \retval                      0 on success
3304  */
3305 int jt_nodemap_add_range(int argc, char **argv)
3306 {
3307         char                    *nodemap_name = NULL;
3308         char                    *nodemap_range = NULL;
3309         struct list_head        nidlist;
3310         char                    min_nid[LNET_NIDSTR_SIZE + 1];
3311         char                    max_nid[LNET_NIDSTR_SIZE + 1];
3312         char                    nid_range[2 * LNET_NIDSTR_SIZE + 2];
3313         int                     rc = 0;
3314         int                     c;
3315
3316         static struct option long_options[] = {
3317                 {
3318                         .name           = "name",
3319                         .has_arg        = required_argument,
3320                         .flag           = 0,
3321                         .val            = 'n',
3322                 },
3323                 {
3324                         .name           = "range",
3325                         .has_arg        = required_argument,
3326                         .flag           = 0,
3327                         .val            = 'r',
3328                 },
3329                 {
3330                         NULL
3331                 }
3332         };
3333
3334         INIT_LIST_HEAD(&nidlist);
3335
3336         while ((c = getopt_long(argc, argv, "n:r:",
3337                                 long_options, NULL)) != -1) {
3338                 switch (c) {
3339                 case 'n':
3340                         nodemap_name = optarg;
3341                         break;
3342                 case 'r':
3343                         nodemap_range = optarg;
3344                         break;
3345                 }
3346         }
3347
3348         if (nodemap_name == NULL || nodemap_range == NULL) {
3349                 fprintf(stderr, "usage: nodemap_add_range --name <name> "
3350                                 "--range <range>\n");
3351                 return -1;
3352         }
3353
3354         if (cfs_parse_nidlist(nodemap_range, strlen(nodemap_range),
3355                               &nidlist) <= 0) {
3356                 fprintf(stderr, "error: %s: can't parse nid range: %s\n",
3357                         jt_cmdname(argv[0]), nodemap_range);
3358                 return -1;
3359         }
3360
3361         if (!cfs_nidrange_is_contiguous(&nidlist)) {
3362                 fprintf(stderr, "error: %s: nodemap ranges must be "
3363                         "contiguous\n", jt_cmdname(argv[0]));
3364                 return -1;
3365         }
3366
3367         cfs_nidrange_find_min_max(&nidlist, &min_nid[0], &max_nid[0],
3368                                   LNET_NIDSTR_SIZE);
3369         snprintf(nid_range, sizeof(nid_range), "%s:%s", min_nid, max_nid);
3370
3371         rc = nodemap_cmd(LCFG_NODEMAP_ADD_RANGE, NULL, 0, argv[0],
3372                          nodemap_name, nid_range, NULL);
3373         if (rc != 0) {
3374                 errno = -rc;
3375                 fprintf(stderr, "error: %s: cannot add range '%s' to nodemap "
3376                                 "'%s': rc = %d\n",
3377                         jt_cmdname(argv[0]), nodemap_range, nodemap_name, rc);
3378         }
3379
3380         return rc;
3381 }
3382
3383 /**
3384  * delete an nid range to a nodemap
3385  *
3386  * \param       argc            number of args
3387  * \param       argv[]          variable string arguments
3388  *
3389  * --name                       nodemap name
3390  * --range                      properly formatted nid range
3391  *
3392  * \retval                      0 on success
3393  */
3394 int jt_nodemap_del_range(int argc, char **argv)
3395 {
3396         char                    *nodemap_name = NULL;
3397         char                    *nodemap_range = NULL;
3398         struct list_head        nidlist;
3399         char                    min_nid[LNET_NIDSTR_SIZE + 1];
3400         char                    max_nid[LNET_NIDSTR_SIZE + 1];
3401         char                    nid_range[2 * LNET_NIDSTR_SIZE + 2];
3402         int                     rc = 0;
3403         int                     c;
3404
3405         static struct option long_options[] = {
3406                 {
3407                         .name           = "name",
3408                         .has_arg        = required_argument,
3409                         .flag           = 0,
3410                         .val            = 'n',
3411                 },
3412                 {
3413                         .name           = "range",
3414                         .has_arg        = required_argument,
3415                         .flag           = 0,
3416                         .val            = 'r',
3417                 },
3418                 {
3419                         NULL
3420                 }
3421         };
3422
3423         INIT_LIST_HEAD(&nidlist);
3424
3425         while ((c = getopt_long(argc, argv, "n:r:",
3426                                 long_options, NULL)) != -1) {
3427                 switch (c) {
3428                 case 'n':
3429                         nodemap_name = optarg;
3430                         break;
3431                 case 'r':
3432                         nodemap_range = optarg;
3433                         break;
3434                 }
3435         }
3436
3437         if (nodemap_name == NULL || nodemap_range == NULL) {
3438                 fprintf(stderr, "usage: nodemap_del_range --name <name> "
3439                                 "--range <range>\n");
3440                 return -1;
3441         }
3442
3443         if (cfs_parse_nidlist(nodemap_range, strlen(nodemap_range),
3444                               &nidlist) <= 0) {
3445                 fprintf(stderr, "error: %s: can't parse nid range: %s\n",
3446                         jt_cmdname(argv[0]), nodemap_range);
3447                 return -1;
3448         }
3449
3450         if (!cfs_nidrange_is_contiguous(&nidlist)) {
3451                 fprintf(stderr, "error: %s: nodemap ranges must be "
3452                         "contiguous\n", jt_cmdname(argv[0]));
3453                 return -1;
3454         }
3455
3456         cfs_nidrange_find_min_max(&nidlist, &min_nid[0], &max_nid[0],
3457                                   LNET_NIDSTR_SIZE);
3458         snprintf(nid_range, sizeof(nid_range), "%s:%s", min_nid, max_nid);
3459
3460         rc = nodemap_cmd(LCFG_NODEMAP_DEL_RANGE, NULL, 0, argv[0],
3461                          nodemap_name, nid_range, NULL);
3462         if (rc != 0) {
3463                 errno = -rc;
3464                 fprintf(stderr, "error: %s: cannot delete range '%s' to "
3465                                "nodemap '%s': rc = %d\n",
3466                         jt_cmdname(argv[0]), nodemap_range, nodemap_name, rc);
3467         }
3468
3469         return rc;
3470 }
3471
3472 /**
3473  * set a fileset on a nodemap
3474  *
3475  * \param       argc            number of args
3476  * \param       argv[]          variable string arguments
3477  *
3478  * --name                       nodemap name
3479  * --fileset                    fileset name
3480  *
3481  * \retval                      0 on success
3482  */
3483 int jt_nodemap_set_fileset(int argc, char **argv)
3484 {
3485         char *nodemap_name = NULL;
3486         char *fileset_name = NULL;
3487         int   rc = 0;
3488         int   c;
3489
3490         static struct option long_options[] = {
3491                 {
3492                         .name           = "name",
3493                         .has_arg        = required_argument,
3494                         .flag           = 0,
3495                         .val            = 'n',
3496                 },
3497                 {
3498                         .name           = "fileset",
3499                         .has_arg        = required_argument,
3500                         .flag           = 0,
3501                         .val            = 'f',
3502                 },
3503                 {
3504                         NULL
3505                 }
3506         };
3507
3508         while ((c = getopt_long(argc, argv, "n:f:",
3509                                 long_options, NULL)) != -1) {
3510                 switch (c) {
3511                 case 'n':
3512                         nodemap_name = optarg;
3513                         break;
3514                 case 'f':
3515                         fileset_name = optarg;
3516                         break;
3517                 }
3518         }
3519
3520         if (nodemap_name == NULL || fileset_name == NULL) {
3521                 fprintf(stderr, "usage: nodemap_set_fileset --name <name> "
3522                                 "--fileset <fileset>\n");
3523                 return -1;
3524         }
3525
3526         rc = nodemap_cmd(LCFG_NODEMAP_SET_FILESET, NULL, 0, argv[0],
3527                          nodemap_name, fileset_name, NULL);
3528         if (rc != 0) {
3529                 errno = -rc;
3530                 fprintf(stderr, "error: %s: cannot set fileset '%s' on nodemap "
3531                                 "'%s': rc = %d\n",
3532                         jt_cmdname(argv[0]), fileset_name, nodemap_name, rc);
3533         }
3534
3535         return rc;
3536 }
3537
3538 /**
3539  * modify a nodemap's behavior
3540  *
3541  * \param       argc            number of args
3542  * \param       argv[]          variable string arguments
3543  *
3544  * --name                       nodemap name
3545  * --property                   nodemap property to change
3546  *                              admin, trusted, squash_uid, squash_gid)
3547  * --value                      value to set property
3548  *
3549  * \retval                      0 on success
3550  */
3551 int jt_nodemap_modify(int argc, char **argv)
3552 {
3553         int                     c;
3554         int                     rc = 0;
3555         enum lcfg_command_type  cmd = 0;
3556         char                    *nodemap_name = NULL;
3557         char                    *param = NULL;
3558         char                    *value = NULL;
3559
3560         static struct option long_options[] = {
3561                 {
3562                         .name           = "name",
3563                         .has_arg        = required_argument,
3564                         .flag           = 0,
3565                         .val            = 'n',
3566                 },
3567                 {
3568                         .name           = "property",
3569                         .has_arg        = required_argument,
3570                         .flag           = 0,
3571                         .val            = 'p',
3572                 },
3573                 {
3574                         .name           = "value",
3575                         .has_arg        = required_argument,
3576                         .flag           = 0,
3577                         .val            = 'v',
3578                 },
3579                 {
3580                         NULL
3581                 }
3582         };
3583
3584         while ((c = getopt_long(argc, argv, "n:p:v:",
3585                                 long_options, NULL)) != -1) {
3586                 switch (c) {
3587                 case 'n':
3588                         nodemap_name = optarg;
3589                         break;
3590                 case 'p':
3591                         param = optarg;
3592                         break;
3593                 case 'v':
3594                         value = optarg;
3595                         break;
3596                 }
3597         }
3598
3599         if (nodemap_name == NULL || param == NULL || value == NULL) {
3600                 fprintf(stderr, "usage: nodemap_modify --name <nodemap_name> "
3601                                 "--property <property_name> --value <value>\n");
3602                 fprintf(stderr, "valid properties: admin trusted "
3603                                 "squash_uid squash_gid deny_unknown\n");
3604                 return -1;
3605         }
3606
3607         if (strcmp("admin", param) == 0) {
3608                 cmd = LCFG_NODEMAP_ADMIN;
3609         } else if (strcmp("trusted", param) == 0) {
3610                 cmd = LCFG_NODEMAP_TRUSTED;
3611         } else if (strcmp("deny_unknown", param) == 0) {
3612                 cmd = LCFG_NODEMAP_DENY_UNKNOWN;
3613         } else if (strcmp("squash_uid", param) == 0) {
3614                 cmd = LCFG_NODEMAP_SQUASH_UID;
3615         } else if (strcmp("squash_gid", param) == 0) {
3616                 cmd = LCFG_NODEMAP_SQUASH_GID;
3617         } else {
3618                 fprintf(stderr, "error: %s: nodemap_modify invalid "
3619                                 "subcommand: %s\n",
3620                         jt_cmdname(argv[0]), param);
3621                 return -1;
3622         }
3623
3624         rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, param,
3625                          value, NULL);
3626         if (rc != 0) {
3627                 errno = -rc;
3628                 fprintf(stderr, "error: %s: cannot modify nodemap '%s' "
3629                                "to param '%s': value '%s': rc = %d\n",
3630                         jt_cmdname(argv[0]), nodemap_name, param, value, rc);
3631         }
3632
3633         return rc;
3634 }
3635
3636 int jt_nodemap_add_idmap(int argc, char **argv)
3637 {
3638         int                     c;
3639         enum                    lcfg_command_type cmd = 0;
3640         char                    *nodemap_name = NULL;
3641         char                    *idmap = NULL;
3642         char                    *idtype = NULL;
3643         int                     rc = 0;
3644
3645         static struct option long_options[] = {
3646                 {
3647                         .name           = "name",
3648                         .has_arg        = required_argument,
3649                         .flag           = 0,
3650                         .val            = 'n',
3651                 },
3652                 {
3653                         .name           = "idmap",
3654                         .has_arg        = required_argument,
3655                         .flag           = 0,
3656                         .val            = 'm',
3657                 },
3658                 {
3659                         .name           = "idtype",
3660                         .has_arg        = required_argument,
3661                         .flag           = 0,
3662                         .val            = 'i',
3663                 },
3664                 {
3665                         NULL
3666                 }
3667         };
3668
3669         while ((c = getopt_long(argc, argv, "n:m:i:",
3670                                 long_options, NULL)) != -1) {
3671                 switch (c) {
3672                 case 'n':
3673                         nodemap_name = optarg;
3674                         break;
3675                 case 'm':
3676                         idmap = optarg;
3677                         break;
3678                 case 'i':
3679                         idtype = optarg;
3680                         break;
3681                 }
3682         }
3683
3684         if (nodemap_name == NULL || idmap == NULL || idtype == NULL) {
3685                 fprintf(stderr, "usage: %s --name <name> --idtype [uid | gid]"
3686                         " --idmap <client id>:<filesystem id>\n", argv[0]);
3687                 return -1;
3688         }
3689
3690         if (strcmp("uid", idtype) == 0) {
3691                 cmd = LCFG_NODEMAP_ADD_UIDMAP;
3692         } else if (strcmp("gid", idtype) == 0) {
3693                 cmd = LCFG_NODEMAP_ADD_GIDMAP;
3694         } else {
3695                 fprintf(stderr, "usage: %s --name <name> --idtype [uid | gid]"
3696                         " --idmap <client id>:<filesystem id>\n", argv[0]);
3697                 return -1;
3698         }
3699
3700         rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, idmap, NULL);
3701         if (rc != 0) {
3702                 errno = -rc;
3703                 fprintf(stderr, "cannot add %smap '%s' to nodemap '%s'"
3704                         ": rc = %d\n", idtype, idmap, nodemap_name, rc);
3705         }
3706
3707         return rc;
3708 }
3709
3710 int jt_nodemap_del_idmap(int argc, char **argv)
3711 {
3712         int                     c;
3713         enum                    lcfg_command_type cmd = 0;
3714         char                    *nodemap_name = NULL;
3715         char                    *idmap = NULL;
3716         char                    *idtype = NULL;
3717         int                     rc = 0;
3718
3719         static struct option long_options[] = {
3720                 {
3721                         .name           = "name",
3722                         .has_arg        = required_argument,
3723                         .flag           = 0,
3724                         .val            = 'n',
3725                 },
3726                 {
3727                         .name           = "idmap",
3728                         .has_arg        = required_argument,
3729                         .flag           = 0,
3730                         .val            = 'm',
3731                 },
3732                 {
3733                         .name           = "idtype",
3734                         .has_arg        = required_argument,
3735                         .flag           = 0,
3736                         .val            = 'i',
3737                 },
3738                 {
3739                         NULL
3740                 }
3741         };
3742
3743         while ((c = getopt_long(argc, argv, "n:m:i:",
3744                                 long_options, NULL)) != -1) {
3745                 switch (c) {
3746                 case 'n':
3747                         nodemap_name = optarg;
3748                         break;
3749                 case 'm':
3750                         idmap = optarg;
3751                         break;
3752                 case 'i':
3753                         idtype = optarg;
3754                         break;
3755                 }
3756         }
3757
3758         if (nodemap_name == NULL || idmap == NULL || idtype == NULL) {
3759                 fprintf(stderr, "usage: %s --name <name> --idtype [uid | gid]"
3760                         " --idmap <client id>:<filesystem id>\n", argv[0]);
3761                 return -1;
3762         }
3763
3764         if (strcmp("uid", idtype) == 0)
3765                 cmd = LCFG_NODEMAP_DEL_UIDMAP;
3766         else
3767                 cmd = LCFG_NODEMAP_DEL_GIDMAP;
3768
3769         rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, idmap, NULL);
3770         if (rc != 0) {
3771                 errno = -rc;
3772                 fprintf(stderr, "cannot delete %smap '%s' from nodemap '%s'"
3773                         ": rc = %d\n", idtype, idmap, nodemap_name, rc);
3774         }
3775
3776         return rc;
3777 }
3778
3779 /*
3780  * this function tranforms a rule [start-end/step] into an array
3781  * of matching numbers
3782  * supported forms are:
3783  * [start]                : just this number
3784  * [start-end]            : all numbers from start to end
3785  * [start-end/step]       : numbers from start to end with increment of step
3786  * on return, format contains a printf format string which can be used
3787  * to generate all the strings
3788  */
3789 static int get_array_idx(char *rule, char *format, int **array)
3790 {
3791         char *start, *end, *ptr;
3792         unsigned int lo, hi, step;
3793         int array_sz = 0;
3794         int i, array_idx;
3795         int rc;
3796
3797         start = strchr(rule, '[');
3798         end = strchr(rule, ']');
3799         if ((start == NULL) || (end == NULL)) {
3800                 *array = malloc(sizeof(int));
3801                 if (*array == NULL)
3802                         return 0;
3803                 strcpy(format, rule);
3804                 array_sz = 1;
3805                 return array_sz;
3806         }
3807         *start = '\0';
3808         *end = '\0';
3809         end++;
3810         start++;
3811         /* put in format the printf format (the rule without the range) */
3812         sprintf(format, "%s%%.4x%s", rule, end);
3813
3814         array_idx = 0;
3815         array_sz = 0;
3816         *array = NULL;
3817         /* loop on , separator */
3818         do {
3819                 /* extract the 3 fields */
3820                 rc = sscanf(start, "%x-%x/%u", &lo, &hi, &step);
3821                 switch (rc) {
3822                 case 0:
3823                         goto err;
3824                 case 1: {
3825                         void *tmp;
3826
3827                         array_sz++;
3828                         tmp = realloc(*array, array_sz * sizeof(int));
3829                         if (tmp == NULL)
3830                                 goto err;
3831                         *array = tmp;
3832                         (*array)[array_idx] = lo;
3833                         array_idx++;
3834                         break;
3835                 }
3836                 case 2: {
3837                         step = 1;
3838                         /* do not break to share code with case 3: */
3839                 }
3840                 case 3: {
3841                         void *tmp;
3842
3843                         if ((hi < lo) || (step == 0))
3844                                 goto err;
3845                         array_sz += (hi - lo) / step + 1;
3846                         tmp = realloc(*array, array_sz * sizeof(int));
3847                         if (tmp == NULL)
3848                                 goto err;
3849                         *array = tmp;
3850                         for (i = lo; i <= hi; i+=step, array_idx++)
3851                                 (*array)[array_idx] = i;
3852                         break;
3853                 }
3854                 }
3855                 ptr = strchr(start, ',');
3856                 if (ptr != NULL)
3857                         start = ptr + 1;
3858
3859         } while (ptr != NULL);
3860         return array_sz;
3861 err:
3862         if (*array != NULL) {
3863                 free(*array);
3864                 *array = NULL;
3865         }
3866         return 0;
3867 }
3868
3869 static int extract_fsname_poolname(const char *arg, char *fsname,
3870                                    char *poolname)
3871 {
3872         char *ptr;
3873         int rc;
3874
3875         strlcpy(fsname, arg, PATH_MAX + 1);
3876         ptr = strchr(fsname, '.');
3877         if (ptr == NULL) {
3878                 fprintf(stderr, ". is missing in %s\n", fsname);
3879                 rc = -EINVAL;
3880                 goto err;
3881         }
3882
3883         if ((ptr - fsname) == 0) {
3884                 fprintf(stderr, "fsname is empty\n");
3885                 rc = -EINVAL;
3886                 goto err;
3887         }
3888
3889         *ptr = '\0';
3890         ++ptr;
3891
3892         rc = lustre_is_fsname_valid(fsname, 1, LUSTRE_MAXFSNAME);
3893         if (rc < 0) {
3894                 fprintf(stderr, "filesystem name %s must be 1-%d chars\n",
3895                         fsname, LUSTRE_MAXFSNAME);
3896                 rc = -EINVAL;
3897                 goto err;
3898         } else if (rc > 0) {
3899                 fprintf(stderr, "char '%c' not allowed in filesystem name\n",
3900                         rc);
3901                 rc = -EINVAL;
3902                 goto err;
3903         }
3904
3905         rc = lustre_is_poolname_valid(ptr, 1, LOV_MAXPOOLNAME);
3906         if (rc == -1) {
3907                 fprintf(stderr, "poolname is empty\n");
3908                 rc = -EINVAL;
3909                 goto err;
3910         } else if (rc == -2) {
3911                 fprintf(stderr,
3912                         "poolname %s is too long (max is %d)\n",
3913                         ptr, LOV_MAXPOOLNAME);
3914                 rc = -ENAMETOOLONG;
3915                 goto err;
3916         } else if (rc > 0) {
3917                 fprintf(stderr, "char '%c' not allowed in pool name '%s'\n",
3918                         rc, ptr);
3919                 rc = -EINVAL;
3920                 goto err;
3921         }
3922
3923         strncpy(poolname, ptr, LOV_MAXPOOLNAME);
3924         poolname[LOV_MAXPOOLNAME] = '\0';
3925         return 0;
3926
3927 err:
3928         fprintf(stderr, "argument %s must be <fsname>.<poolname>\n", arg);
3929         return rc;
3930 }
3931
3932 int jt_pool_cmd(int argc, char **argv)
3933 {
3934         enum lcfg_command_type cmd;
3935         char fsname[PATH_MAX + 1];
3936         char poolname[LOV_MAXPOOLNAME + 1];
3937         char *ostnames_buf = NULL;
3938         int i, rc;
3939         int *array = NULL, array_sz;
3940         struct {
3941                 int     rc;
3942                 char   *ostname;
3943         } *cmds = NULL;
3944
3945         switch (argc) {
3946         case 0:
3947         case 1: return CMD_HELP;
3948         case 2: {
3949                 if (strcmp("pool_new", argv[0]) == 0)
3950                         cmd = LCFG_POOL_NEW;
3951                 else if (strcmp("pool_destroy", argv[0]) == 0)
3952                         cmd = LCFG_POOL_DEL;
3953                 else if (strcmp("pool_list", argv[0]) == 0)
3954                          return llapi_poollist(argv[1]);
3955                 else return CMD_HELP;
3956
3957                 rc = extract_fsname_poolname(argv[1], fsname, poolname);
3958                 if (rc)
3959                         break;
3960
3961                 rc = pool_cmd(cmd, argv[0], argv[1], fsname, poolname, NULL);
3962                 if (rc)
3963                         break;
3964
3965                 check_pool_cmd_result(cmd, fsname, poolname, NULL);
3966                 break;
3967         }
3968         default: {
3969                 char format[2*MAX_OBD_NAME];
3970
3971                 if (strcmp("pool_remove", argv[0]) == 0) {
3972                         cmd = LCFG_POOL_REM;
3973                 } else if (strcmp("pool_add", argv[0]) == 0) {
3974                         cmd = LCFG_POOL_ADD;
3975                 } else {
3976                         return CMD_HELP;
3977                 }
3978
3979                 rc = extract_fsname_poolname(argv[1], fsname, poolname);
3980                 if (rc)
3981                         break;
3982
3983                 for (i = 2; i < argc; i++) {
3984                         int j;
3985
3986                         array_sz = get_array_idx(argv[i], format, &array);
3987                         if (array_sz == 0)
3988                                 return CMD_HELP;
3989
3990                         cmds = malloc(array_sz * sizeof(cmds[0]));
3991                         if (cmds != NULL) {
3992                                 ostnames_buf = malloc(array_sz *
3993                                                       (MAX_OBD_NAME + 1));
3994                         } else {
3995                                 free(array);
3996                                 rc = -ENOMEM;
3997                                 goto out;
3998                         }
3999
4000                         for (j = 0; j < array_sz; j++) {
4001                                 char ostname[MAX_OBD_NAME + 1];
4002
4003                                 snprintf(ostname, MAX_OBD_NAME, format,
4004                                          array[j]);
4005                                 ostname[MAX_OBD_NAME] = '\0';
4006
4007                                 rc = check_and_complete_ostname(fsname,ostname);
4008                                 if (rc) {
4009                                         free(array);
4010                                         free(cmds);
4011                                         if (ostnames_buf)
4012                                                 free(ostnames_buf);
4013                                         goto out;
4014                                 }
4015                                 if (ostnames_buf != NULL) {
4016                                         cmds[j].ostname =
4017                                           &ostnames_buf[(MAX_OBD_NAME + 1) * j];
4018                                         strcpy(cmds[j].ostname, ostname);
4019                                 } else {
4020                                         cmds[j].ostname = NULL;
4021                                 }
4022                                 cmds[j].rc = pool_cmd(cmd, argv[0], argv[1],
4023                                                       fsname, poolname,
4024                                                       ostname);
4025                                 /* Return an err if any of the add/dels fail */
4026                                 if (!rc)
4027                                         rc = cmds[j].rc;
4028                         }
4029                         for (j = 0; j < array_sz; j++) {
4030                                 if (!cmds[j].rc) {
4031                                         char ostname[MAX_OBD_NAME + 1];
4032
4033                                         if (!cmds[j].ostname) {
4034                                                 snprintf(ostname, MAX_OBD_NAME,
4035                                                          format, array[j]);
4036                                                 ostname[MAX_OBD_NAME] = '\0';
4037                                                 check_and_complete_ostname(
4038                                                         fsname, ostname);
4039                                         } else {
4040                                                 strcpy(ostname,
4041                                                        cmds[j].ostname);
4042                                         }
4043                                         check_pool_cmd_result(cmd, fsname,
4044                                                               poolname,ostname);
4045                                 }
4046                         }
4047                         if (array_sz > 0)
4048                                 free(array);
4049                         if (cmds)
4050                                 free(cmds);
4051                         if (ostnames_buf != NULL)
4052                                 free(ostnames_buf);
4053                 }
4054                 /* fall through */
4055         }
4056         } /* switch */
4057
4058 out:
4059         if (rc != 0) {
4060                 errno = -rc;
4061                 perror(argv[0]);
4062         }
4063
4064         return rc;
4065 }
4066
4067 int jt_get_obj_version(int argc, char **argv)
4068 {
4069         struct lu_fid fid;
4070         struct obd_ioctl_data data;
4071         __u64 version, id = ULLONG_MAX, group = ULLONG_MAX;
4072         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf, *fidstr;
4073         int rc, c;
4074
4075         while ((c = getopt(argc, argv, "i:g:")) != -1) {
4076                 switch (c) {
4077                 case 'i':
4078                         id = strtoull(optarg, NULL, 0);
4079                         break;
4080                 case 'g':
4081                         group = strtoull(optarg, NULL, 0);
4082                         break;
4083                 default:
4084                         return CMD_HELP;
4085                 }
4086         }
4087
4088         argc -= optind;
4089         argv += optind;
4090
4091         if (!(id != ULLONG_MAX && group != ULLONG_MAX && argc == 0) &&
4092             !(id == ULLONG_MAX && group == ULLONG_MAX && argc == 1))
4093                 return CMD_HELP;
4094
4095         memset(&data, 0, sizeof data);
4096         data.ioc_dev = cur_device;
4097         if (argc == 1) {
4098                 fidstr = *argv;
4099                 while (*fidstr == '[')
4100                         fidstr++;
4101                 sscanf(fidstr, SFID, RFID(&fid));
4102
4103                 data.ioc_inlbuf1 = (char *) &fid;
4104                 data.ioc_inllen1 = sizeof fid;
4105         } else {
4106                 data.ioc_inlbuf3 = (char *) &id;
4107                 data.ioc_inllen3 = sizeof id;
4108                 data.ioc_inlbuf4 = (char *) &group;
4109                 data.ioc_inllen4 = sizeof group;
4110         }
4111         data.ioc_inlbuf2 = (char *) &version;
4112         data.ioc_inllen2 = sizeof version;
4113
4114         memset(buf, 0, sizeof *buf);
4115         rc = obd_ioctl_pack(&data, &buf, sizeof rawbuf);
4116         if (rc) {
4117                 fprintf(stderr, "error: %s: packing ioctl arguments: %s\n",
4118                         jt_cmdname(argv[0]), strerror(-rc));
4119                 return rc;
4120         }
4121
4122         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_GET_OBJ_VERSION, buf);
4123         if (rc == -1) {
4124                 fprintf(stderr, "error: %s: ioctl: %s\n",
4125                         jt_cmdname(argv[0]), strerror(errno));
4126                 return -errno;
4127         }
4128
4129         obd_ioctl_unpack(&data, buf, sizeof rawbuf);
4130         printf("%#jx\n", (uintmax_t)version);
4131         return 0;
4132 }
4133
4134 int jt_changelog_register(int argc, char **argv)
4135 {
4136         struct obd_ioctl_data    data = { 0 };
4137         char                     rawbuf[MAX_IOC_BUFLEN] = "";
4138         char                    *buf = rawbuf;
4139         char                    *device = lcfg_get_devname();
4140         bool                     print_name_only = false;
4141         int                      c;
4142         int                      rc;
4143
4144         if (argc > 2)
4145                 return CMD_HELP;
4146
4147         while ((c = getopt(argc, argv, "hn")) >= 0) {
4148                 switch (c) {
4149                 case 'n':
4150                         print_name_only = true;
4151                         break;
4152                 case 'h':
4153                 default:
4154                         return CMD_HELP;
4155                 }
4156         }
4157
4158         if (cur_device < 0 || device == NULL)
4159                 return CMD_HELP;
4160
4161         data.ioc_dev = cur_device;
4162
4163         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
4164         if (rc < 0) {
4165                 fprintf(stderr, "error: %s: cannot pack ioctl: %s\n",
4166                         jt_cmdname(argv[0]), strerror(-rc));
4167                return rc;
4168         }
4169
4170         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_CHANGELOG_REG, buf);
4171         if (rc < 0) {
4172                 rc = -errno;
4173                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
4174                         strerror(-rc));
4175                 return rc;
4176         }
4177
4178         obd_ioctl_unpack(&data, buf, sizeof(rawbuf));
4179
4180         if (data.ioc_u32_1 == 0) {
4181                 fprintf(stderr, "received invalid userid!\n");
4182                 return -EPROTO;
4183         }
4184
4185         if (print_name_only)
4186                 printf("%s%u\n", CHANGELOG_USER_PREFIX, data.ioc_u32_1);
4187         else
4188                 printf("%s: Registered changelog userid '%s%u'\n",
4189                        device, CHANGELOG_USER_PREFIX, data.ioc_u32_1);
4190
4191         return 0;
4192 }
4193
4194 int jt_changelog_deregister(int argc, char **argv)
4195 {
4196         struct obd_ioctl_data    data = { 0 };
4197         char                     rawbuf[MAX_IOC_BUFLEN] = "";
4198         char                    *buf = rawbuf;
4199         char                    *device = lcfg_get_devname();
4200         int                      id;
4201         int                      rc;
4202
4203         if (argc != 2 || cur_device < 0 || device == NULL)
4204                 return CMD_HELP;
4205
4206         rc = sscanf(argv[1], CHANGELOG_USER_PREFIX"%d", &id);
4207         if (rc != 1 || id <= 0) {
4208                 fprintf(stderr,
4209                         "error: %s: expected id of the form %s<num> got '%s'\n",
4210                         jt_cmdname(argv[0]), CHANGELOG_USER_PREFIX, argv[1]);
4211                 return CMD_HELP;
4212         }
4213
4214         data.ioc_dev = cur_device;
4215         data.ioc_u32_1 = id;
4216
4217         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
4218         if (rc < 0) {
4219                 fprintf(stderr, "error: %s: invalid ioctl\n",
4220                         jt_cmdname(argv[0]));
4221                 return rc;
4222         }
4223
4224         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_CHANGELOG_DEREG, buf);
4225         if (rc < 0) {
4226                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
4227                         strerror(rc = errno));
4228                 return rc;
4229         }
4230
4231         obd_ioctl_unpack(&data, buf, sizeof(rawbuf));
4232         printf("%s: Deregistered changelog user '%s%u'\n",
4233                device, CHANGELOG_USER_PREFIX, data.ioc_u32_1);
4234
4235         return 0;
4236 }