Whamcloud - gitweb
LU-6349 ptlrpc: remove LUSTRE_MSG_MAGIC_V1 support
[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.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2014, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/utils/obd.c
37  *
38  * Author: Peter J. Braam <braam@clusterfs.com>
39  * Author: Phil Schwan <phil@clusterfs.com>
40  * Author: Andreas Dilger <adilger@clusterfs.com>
41  * Author: Robert Read <rread@clusterfs.com>
42  */
43
44 #include <sys/ioctl.h>
45 #include <sys/socket.h>
46 #include <sys/stat.h>
47 #include <sys/time.h>
48 #include <sys/types.h>
49 #include <sys/un.h>
50 #include <sys/wait.h>
51
52 #include <ctype.h>
53 #include <errno.h>
54 #include <fcntl.h>
55 #include <getopt.h>
56 #include <glob.h>
57 #include <signal.h>
58 #include <stdarg.h>
59 #include <stdbool.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <time.h>
64 #include <unistd.h>
65
66 #include "obdctl.h"
67 #include <libcfs/libcfs.h>
68 #include <libcfs/util/ioctl.h>
69 #include <libcfs/util/parser.h>
70
71 #include <lnet/nidstr.h>
72 #include <lustre/lustre_idl.h>
73 #include <lustre_cfg.h>
74 #include <lustre_ioctl.h>
75 #include <lustre/lustre_build_version.h>
76
77 #include <lnet/lnetctl.h>
78 #include <lustre/lustreapi.h>
79
80 #define MAX_STRING_SIZE 128
81 #define DEVICES_LIST "/proc/fs/lustre/devices"
82
83 #if HAVE_LIBPTHREAD
84 #include <sys/ipc.h>
85 #include <sys/shm.h>
86 #include <pthread.h>
87
88 #define MAX_THREADS 4096
89 #define MAX_BASE_ID 0xffffffff
90 #define NIDSTRING_LENGTH 64
91 struct shared_data {
92         pthread_mutex_t mutex;
93         pthread_cond_t  cond;
94         int       stopping;
95         struct {
96                 __u64 counters[MAX_THREADS];
97                 __u64 offsets[MAX_THREADS];
98                 int   thr_running;
99                 int   start_barrier;
100                 int   stop_barrier;
101                 struct timeval start_time;
102                 struct timeval end_time;
103         } body;
104 };
105
106 static struct shared_data *shared_data;
107 static __u64 counter_snapshot[2][MAX_THREADS];
108 static int prev_valid;
109 static struct timeval prev_time;
110 static int thread;
111 static int nthreads;
112 #else
113 const int thread = 0;
114 const int nthreads = 1;
115 #endif
116
117 static int cur_device = -1;
118
119 static int l2_ioctl(int dev_id, int opc, void *buf)
120 {
121         return l_ioctl(dev_id, opc, buf);
122 }
123
124 int lcfg_ioctl(char * func, int dev_id, struct lustre_cfg *lcfg)
125 {
126         struct obd_ioctl_data data;
127         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
128         int rc;
129
130         memset(&data, 0, sizeof(data));
131         data.ioc_dev = cur_device;
132         data.ioc_type = LUSTRE_CFG_TYPE;
133         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
134                                         lcfg->lcfg_buflens);
135         data.ioc_pbuf1 = (void *)lcfg;
136         memset(buf, 0, sizeof(rawbuf));
137         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
138         if (rc) {
139                 fprintf(stderr, "error: %s: invalid ioctl\n",
140                         jt_cmdname(func));
141                 return rc;
142         }
143
144         rc =  l_ioctl(dev_id, OBD_IOC_PROCESS_CFG, buf);
145
146         return rc;
147 }
148
149 static int do_device(char *func, char *devname);
150
151 static int get_mgs_device()
152 {
153         char mgs[] = "$MGS";
154         static int mgs_device = -1;
155
156         if (mgs_device == -1) {
157                 int rc;
158                 do_disconnect(NULL, 1);
159                 rc = do_device("mgsioc", mgs);
160                 if (rc) {
161                         fprintf(stderr,
162                                 "This command must be run on the MGS.\n");
163                         errno = ENODEV;
164                         return -1;
165                 }
166                 mgs_device = cur_device;
167         }
168         return mgs_device;
169 }
170
171 /* Returns -1 on error with errno set */
172 int lcfg_mgs_ioctl(char *func, int dev_id, struct lustre_cfg *lcfg)
173 {
174         struct obd_ioctl_data data;
175         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
176         int rc;
177
178         memset(&data, 0, sizeof(data));
179         rc = data.ioc_dev = get_mgs_device();
180         if (rc < 0)
181                 goto out;
182         data.ioc_type = LUSTRE_CFG_TYPE;
183         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
184                                         lcfg->lcfg_buflens);
185         data.ioc_pbuf1 = (void *)lcfg;
186         memset(buf, 0, sizeof(rawbuf));
187         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
188         if (rc) {
189                 fprintf(stderr, "error: %s: invalid ioctl\n",
190                         jt_cmdname(func));
191                 return rc;
192         }
193
194         rc = l_ioctl(dev_id, OBD_IOC_PARAM, buf);
195 out:
196         if (rc) {
197                 if (errno == ENOSYS)
198                         fprintf(stderr, "Make sure cfg_device is set first.\n");
199         }
200         return rc;
201 }
202
203 char *obdo_print(struct obdo *obd)
204 {
205         char buf[1024];
206
207         sprintf(buf, "id: "LPX64"\ngrp: "LPX64"\natime: "LPU64"\nmtime: "LPU64
208                 "\nctime: "LPU64"\nsize: "LPU64"\nblocks: "LPU64
209                 "\nblksize: %u\nmode: %o\nuid: %d\ngid: %d\nflags: %x\n"
210                 "misc: %x\nnlink: %d,\nvalid "LPX64"\n",
211                 ostid_id(&obd->o_oi), ostid_seq(&obd->o_oi), obd->o_atime,
212                 obd->o_mtime, obd->o_ctime,
213                 obd->o_size, 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, 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 "LPU64" threads %d sec %f %f/second\n",
493                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         int rc;
928         char rawbuf[MAX_IOC_BUFLEN];
929         char *version;
930
931         if (argc != 1)
932                 return CMD_HELP;
933
934         rc = llapi_get_version(rawbuf, MAX_IOC_BUFLEN, &version);
935         if (rc)
936                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
937                         strerror(-rc));
938         else
939                 printf("Lustre version: %s\n", version);
940
941         return rc;
942 }
943
944 static void print_obd_line(char *s)
945 {
946         char buf[MAX_STRING_SIZE];
947         char obd_name[MAX_OBD_NAME];
948         FILE *fp = NULL;
949         char *ptr;
950
951         snprintf(buf, sizeof(buf), " %%*d %%*s osc %%%zus %%*s %%*d ",
952                  sizeof(obd_name) - 1);
953         if (sscanf(s, buf, obd_name) == 0)
954                 goto try_mdc;
955         snprintf(buf, sizeof(buf),
956                  "/proc/fs/lustre/osc/%s/ost_conn_uuid", obd_name);
957         if ((fp = fopen(buf, "r")) == NULL)
958                 goto try_mdc;
959         goto got_one;
960
961 try_mdc:
962         snprintf(buf, sizeof(buf), " %%*d %%*s mdc %%%zus %%*s %%*d ",
963                  sizeof(obd_name) - 1);
964         if (sscanf(s, buf, obd_name) == 0)
965                 goto fail;
966         snprintf(buf, sizeof(buf),
967                  "/proc/fs/lustre/mdc/%s/mds_conn_uuid", obd_name);
968         if ((fp = fopen(buf, "r")) == NULL)
969                 goto fail;
970
971 got_one:
972         /* should not ignore fgets(3)'s return value */
973         if (!fgets(buf, sizeof(buf), fp)) {
974                 fprintf(stderr, "reading from %s: %s", buf, strerror(errno));
975                 fclose(fp);
976                 return;
977         }
978         fclose(fp);
979
980         /* trim trailing newlines */
981         ptr = strrchr(buf, '\n');
982         if (ptr) *ptr = '\0';
983         ptr = strrchr(s, '\n');
984         if (ptr) *ptr = '\0';
985
986         printf("%s %s\n", s, buf);
987         return;
988
989 fail:
990         printf("%s", s);
991         return;
992 }
993
994 /* get device list by ioctl */
995 int jt_obd_list_ioctl(int argc, char **argv)
996 {
997         int rc, index;
998         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
999         struct obd_ioctl_data *data = (struct obd_ioctl_data *)buf;
1000
1001         if (argc > 2)
1002                 return CMD_HELP;
1003         /* Just ignore a -t option.  Only supported with /proc. */
1004         else if (argc == 2 && strcmp(argv[1], "-t") != 0)
1005                 return CMD_HELP;
1006
1007         for (index = 0;; index++) {
1008                 memset(buf, 0, sizeof(rawbuf));
1009                 data->ioc_version = OBD_IOCTL_VERSION;
1010                 data->ioc_inllen1 =
1011                         sizeof(rawbuf) - cfs_size_round(sizeof(*data));
1012                 data->ioc_inlbuf1 = buf + cfs_size_round(sizeof(*data));
1013                 data->ioc_len = obd_ioctl_packlen(data);
1014                 data->ioc_count = index;
1015
1016                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_GETDEVICE, buf);
1017                 if (rc != 0)
1018                         break;
1019                 printf("%s\n", (char *)data->ioc_bulk);
1020         }
1021         if (rc != 0) {
1022                 if (errno == ENOENT)
1023                         /* no device or the last device */
1024                         rc = 0;
1025                 else
1026                         fprintf(stderr, "Error getting device list: %s: "
1027                                 "check dmesg.\n", strerror(errno));
1028         }
1029         return rc;
1030 }
1031
1032 int jt_obd_list(int argc, char **argv)
1033 {
1034         int rc;
1035         char buf[MAX_STRING_SIZE];
1036         FILE *fp = NULL;
1037         int print_obd = 0;
1038
1039         if (argc > 2)
1040                 return CMD_HELP;
1041         else if (argc == 2) {
1042                 if (strcmp(argv[1], "-t") == 0)
1043                         print_obd = 1;
1044                 else
1045                         return CMD_HELP;
1046         }
1047
1048         fp = fopen(DEVICES_LIST, "r");
1049         if (fp == NULL) {
1050                 fprintf(stderr, "error: %s: %s opening "DEVICES_LIST"\n",
1051                         jt_cmdname(argv[0]), strerror(rc =  errno));
1052                 return jt_obd_list_ioctl(argc, argv);
1053         }
1054
1055         while (fgets(buf, sizeof(buf), fp) != NULL)
1056                 if (print_obd)
1057                         print_obd_line(buf);
1058                 else
1059                         printf("%s", buf);
1060
1061         fclose(fp);
1062         return 0;
1063 }
1064
1065 struct jt_fid_space {
1066         __u64   jt_seq;
1067         __u64   jt_id;
1068         int     jt_width;
1069 };
1070
1071 int jt_obd_alloc_fids(struct jt_fid_space *space, struct lu_fid *fid,
1072                       __u64 *count)
1073 {
1074         int rc;
1075
1076         if (space->jt_seq == 0 || space->jt_id == space->jt_width) {
1077                 struct obd_ioctl_data  data;
1078                 char rawbuf[MAX_IOC_BUFLEN];
1079                 char *buf = rawbuf;
1080                 __u64 seqnr;
1081                 int max_count;
1082
1083                 memset(&data, 0, sizeof(data));
1084                 data.ioc_dev = cur_device;
1085
1086                 data.ioc_pbuf1 = (char *)&seqnr;
1087                 data.ioc_plen1 = sizeof(seqnr);
1088
1089                 data.ioc_pbuf2 = (char *)&max_count;
1090                 data.ioc_plen2 = sizeof(max_count);
1091
1092                 memset(buf, 0, sizeof(rawbuf));
1093                 rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
1094                 if (rc) {
1095                         fprintf(stderr, "error: invalid ioctl rc = %d\n", rc);
1096                         return rc;
1097                 }
1098
1099                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_ECHO_ALLOC_SEQ, buf);
1100                 if (rc) {
1101                         fprintf(stderr, "ioctl error: rc = %d\n", rc);
1102                         return rc;
1103                 }
1104
1105                 space->jt_seq = *(__u64 *)data.ioc_pbuf1;
1106                 space->jt_width = *(int *)data.ioc_pbuf2;
1107                 space->jt_id = 1;
1108         }
1109         fid->f_seq = space->jt_seq;
1110         fid->f_oid = space->jt_id;
1111         fid->f_ver = 0;
1112
1113         space->jt_id = space->jt_id + *count;
1114         if (space->jt_id > space->jt_width)
1115                 space->jt_id = space->jt_width;
1116
1117         *count = space->jt_id - fid->f_oid;
1118         return 0;
1119 }
1120
1121 #define MD_STEP_COUNT 1000
1122 int jt_obd_md_common(int argc, char **argv, int cmd)
1123 {
1124         struct obd_ioctl_data  data;
1125         struct timeval         start;
1126         struct timeval         end_time;
1127         char                   rawbuf[MAX_IOC_BUFLEN];
1128         char                  *buf = rawbuf;
1129         int                    mode = 0000644;
1130         int                    create_mode;
1131         int                    rc = 0;
1132         char                  *parent_basedir = NULL;
1133         char                   dirname[4096];
1134         int                    parent_base_id = 0;
1135         int                    parent_count = 1;
1136         __u64                  child_base_id = -1;
1137         int                    stripe_count = 0;
1138         int                    stripe_index = -1;
1139         int                    count = 0;
1140         char                  *end;
1141         __u64                  seconds = 0;
1142         double                 diff;
1143         int                    c;
1144         __u64                  total_count = 0;
1145         char                  *name = NULL;
1146         struct jt_fid_space    fid_space = {0};
1147         int                    version = 0;
1148         struct option          long_opts[] = {
1149                 {"child_base_id",     required_argument, 0, 'b'},
1150                 {"stripe_count",      required_argument, 0, 'c'},
1151                 {"parent_basedir",    required_argument, 0, 'd'},
1152                 {"parent_dircount",   required_argument, 0, 'D'},
1153                 {"stripe_index",      required_argument, 0, 'i'},
1154                 {"mode",              required_argument, 0, 'm'},
1155                 {"count",             required_argument, 0, 'n'},
1156                 {"time",              required_argument, 0, 't'},
1157                 {"version",           no_argument,       0, 'v'},
1158                 {0, 0, 0, 0}
1159         };
1160
1161         while ((c = getopt_long(argc, argv, "b:c:d:D:m:n:t:v",
1162                                 long_opts, NULL)) >= 0) {
1163                 switch (c) {
1164                 case 'b':
1165                         child_base_id = strtoull(optarg, &end, 0);
1166                         if (*end) {
1167                                 fprintf(stderr, "error: %s: bad child_base_id"
1168                                         " '%s'\n", jt_cmdname(argv[0]), optarg);
1169                                 return CMD_HELP;
1170                         }
1171                         break;
1172                 case 'c':
1173                         stripe_count = strtoul(optarg, &end, 0);
1174                         if (*end) {
1175                                 fprintf(stderr, "error: %s: bad stripe count"
1176                                         " '%s'\n", jt_cmdname(argv[0]), optarg);
1177                                 return CMD_HELP;
1178                         }
1179                         break;
1180                 case 'd':
1181                         parent_basedir = optarg;
1182                         break;
1183                 case 'D':
1184                         parent_count = strtoul(optarg, &end, 0);
1185                         if (*end) {
1186                                 fprintf(stderr, "error: %s: bad parent count"
1187                                         " '%s'\n", jt_cmdname(argv[0]), optarg);
1188                                 return CMD_HELP;
1189                         }
1190                         break;
1191                 case 'i':
1192                         stripe_index = strtoul(optarg, &end, 0);
1193                         if (*end) {
1194                                 fprintf(stderr, "error: %s: bad stripe index"
1195                                         " '%s'\n", jt_cmdname(argv[0]), optarg);
1196                                 return CMD_HELP;
1197                         }
1198                         break;
1199                 case 'm':
1200                         mode = strtoul(optarg, &end, 0);
1201                         if (*end) {
1202                                 fprintf(stderr, "error: %s: bad mode '%s'\n",
1203                                         jt_cmdname(argv[0]), optarg);
1204                                 return CMD_HELP;
1205                         }
1206                         break;
1207                 case 'n':
1208                         total_count = strtoul(optarg, &end, 0);
1209                         if (*end || total_count == 0) {
1210                                 fprintf(stderr, "%s: bad child count '%s'\n",
1211                                         jt_cmdname(argv[0]), optarg);
1212                                 return CMD_HELP;
1213                         }
1214                         break;
1215                 case 't':
1216                         seconds = strtoull(optarg, &end, 0);
1217                         if (*end) {
1218                                 fprintf(stderr, "error: %s: seconds '%s'\n",
1219                                         jt_cmdname(argv[0]), optarg);
1220                                 return CMD_HELP;
1221                         }
1222                         break;
1223                 case 'v':
1224                         version = 1;
1225                         break;
1226                 default:
1227                         fprintf(stderr, "error: %s: option '%s' "
1228                                 "unrecognized\n", argv[0], argv[optind - 1]);
1229                         return CMD_HELP;
1230                 }
1231         }
1232
1233         memset(&data, 0, sizeof(data));
1234         data.ioc_dev = cur_device;
1235         if (child_base_id == -1) {
1236                 if (optind >= argc)
1237                         return CMD_HELP;
1238                 name = argv[optind];
1239                 total_count = 1;
1240         } else {
1241                 if (optind < argc) {
1242                         fprintf(stderr, "child_base_id and name can not"
1243                                         " specified at the same time\n");
1244                         return CMD_HELP;
1245                 }
1246         }
1247
1248         if (stripe_count == 0 && stripe_index != -1) {
1249                 fprintf(stderr, "If stripe_count is 0, stripe_index can not"
1250                                 "be specified\n");
1251                 return CMD_HELP;
1252         }
1253
1254         if (total_count == 0 && seconds == 0) {
1255                 fprintf(stderr, "count or seconds needs to be indicated\n");
1256                 return CMD_HELP;
1257         }
1258
1259         if (parent_count <= 0) {
1260                 fprintf(stderr, "parent count must < 0\n");
1261                 return CMD_HELP;
1262         }
1263
1264 #ifdef MAX_THREADS
1265         if (thread) {
1266                 shmem_lock();
1267                 /* threads interleave */
1268                 if (parent_base_id != -1)
1269                         parent_base_id += (thread - 1) % parent_count;
1270
1271                 if (child_base_id != -1)
1272                         child_base_id +=  (thread - 1) * \
1273                                           (MAX_BASE_ID / nthreads);
1274
1275                 shmem_start_time_locked();
1276                 shmem_unlock();
1277         }
1278 #endif
1279         /* If parent directory is not specified, try to get the directory
1280          * from name */
1281         if (parent_basedir == NULL) {
1282                 char *last_lash;
1283                 if (name == NULL) {
1284                         fprintf(stderr, "parent_basedir or name must be"
1285                                         "indicated!\n");
1286                         return CMD_HELP;
1287                 }
1288                 /*Get directory and name from name*/
1289                 last_lash = strrchr(name, '/');
1290                 if (last_lash == NULL || name[0] != '/') {
1291                         fprintf(stderr, "Can not locate %s\n", name);
1292                         return CMD_HELP;
1293                 }
1294
1295                 if (last_lash == name) {
1296                         sprintf(dirname, "%s", "/");
1297                         name++;
1298                 } else {
1299                         int namelen = (unsigned long)last_lash -
1300                                       (unsigned long)name + 1;
1301                         snprintf(dirname, namelen, "%s", name);
1302                         name = last_lash + 1;
1303                 }
1304
1305                 data.ioc_pbuf1 = dirname;
1306                 data.ioc_plen1 = strlen(dirname);
1307
1308                 data.ioc_pbuf2 = name;
1309                 data.ioc_plen2 = strlen(name);
1310         } else {
1311                 if (name != NULL) {
1312                         data.ioc_pbuf2 = name;
1313                         data.ioc_plen2 = strlen(name);
1314                 }
1315                 if (parent_base_id > 0)
1316                         sprintf(dirname, "%s%d", parent_basedir,
1317                                 parent_base_id);
1318                 else
1319                         sprintf(dirname, "%s", parent_basedir);
1320                 data.ioc_pbuf1 = dirname;
1321                 data.ioc_plen1 = strlen(dirname);
1322         }
1323
1324         if (cmd == ECHO_MD_MKDIR || cmd == ECHO_MD_RMDIR)
1325                 create_mode = S_IFDIR;
1326         else
1327                 create_mode = S_IFREG;
1328
1329         data.ioc_obdo1.o_mode = mode | S_IFDIR;
1330         data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE |
1331                                  OBD_MD_FLFLAGS | OBD_MD_FLGROUP;
1332         data.ioc_command = cmd;
1333
1334         gettimeofday(&start, NULL);
1335         while (shmem_running()) {
1336                 struct lu_fid fid = { 0 };
1337
1338                 if (child_base_id != -1)
1339                         data.ioc_obdo2.o_oi.oi.oi_id = child_base_id;
1340                 data.ioc_obdo2.o_mode = mode | create_mode;
1341                 data.ioc_obdo2.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE |
1342                                          OBD_MD_FLMODE | OBD_MD_FLFLAGS |
1343                                          OBD_MD_FLGROUP;
1344                 data.ioc_obdo2.o_misc = stripe_count;
1345                 data.ioc_obdo2.o_stripe_idx = stripe_index;
1346
1347                 if (total_count > 0) {
1348                         if ((total_count - count) > MD_STEP_COUNT)
1349                                 data.ioc_count = MD_STEP_COUNT;
1350                         else
1351                                 data.ioc_count = total_count - count;
1352                 } else {
1353                         data.ioc_count = MD_STEP_COUNT;
1354                 }
1355
1356                 if (cmd == ECHO_MD_CREATE || cmd == ECHO_MD_MKDIR) {
1357                         /*Allocate fids for the create */
1358                         rc = jt_obd_alloc_fids(&fid_space, &fid,
1359                                                &data.ioc_count);
1360                         if (rc) {
1361                                 fprintf(stderr, "Allocate fids error %d.\n",rc);
1362                                 return rc;
1363                         }
1364                         fid_to_ostid(&fid, &data.ioc_obdo1.o_oi);
1365                 }
1366
1367                 child_base_id += data.ioc_count;
1368                 count += data.ioc_count;
1369
1370                 memset(buf, 0, sizeof(rawbuf));
1371                 rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
1372                 if (rc) {
1373                         fprintf(stderr, "error: %s: invalid ioctl %d\n",
1374                                 jt_cmdname(argv[0]), rc);
1375                         return rc;
1376                 }
1377
1378                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_ECHO_MD, buf);
1379                 if (rc) {
1380                         fprintf(stderr, "error: %s: %s\n",
1381                                 jt_cmdname(argv[0]), strerror(rc = errno));
1382                         return rc;
1383                 }
1384                 shmem_bump(data.ioc_count);
1385
1386                 gettimeofday(&end_time, NULL);
1387                 diff = difftime(&end_time, &start);
1388                 if (seconds > 0 && (__u64)diff > seconds)
1389                         break;
1390
1391                 if (count >= total_count && total_count > 0)
1392                         break;
1393         }
1394
1395         if (count > 0 && version) {
1396                 gettimeofday(&end_time, NULL);
1397                 diff = difftime(&end_time, &start);
1398                 printf("%s: %d in %.3fs (%.3f /s): %s",
1399                         jt_cmdname(argv[0]), count, diff,
1400                         (double)count/diff, ctime(&end_time.tv_sec));
1401         }
1402
1403 #ifdef MAX_THREADS
1404         if (thread) {
1405                 shmem_lock();
1406                 shmem_end_time_locked();
1407                 shmem_unlock();
1408         }
1409 #endif
1410         return rc;
1411 }
1412
1413 int jt_obd_test_create(int argc, char **argv)
1414 {
1415         return jt_obd_md_common(argc, argv, ECHO_MD_CREATE);
1416 }
1417
1418 int jt_obd_test_mkdir(int argc, char **argv)
1419 {
1420         return jt_obd_md_common(argc, argv, ECHO_MD_MKDIR);
1421 }
1422
1423 int jt_obd_test_destroy(int argc, char **argv)
1424 {
1425         return jt_obd_md_common(argc, argv, ECHO_MD_DESTROY);
1426 }
1427
1428 int jt_obd_test_rmdir(int argc, char **argv)
1429 {
1430         return jt_obd_md_common(argc, argv, ECHO_MD_RMDIR);
1431 }
1432
1433 int jt_obd_test_lookup(int argc, char **argv)
1434 {
1435         return jt_obd_md_common(argc, argv, ECHO_MD_LOOKUP);
1436 }
1437
1438 int jt_obd_test_setxattr(int argc, char **argv)
1439 {
1440         return jt_obd_md_common(argc, argv, ECHO_MD_SETATTR);
1441 }
1442
1443 int jt_obd_test_md_getattr(int argc, char **argv)
1444 {
1445         return jt_obd_md_common(argc, argv, ECHO_MD_GETATTR);
1446 }
1447
1448 int jt_obd_create(int argc, char **argv)
1449 {
1450         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1451         struct obd_ioctl_data data;
1452         struct timeval next_time;
1453         __u64 count = 1, next_count, base_id = 1;
1454         int verbose = 1, mode = 0100644, rc = 0, i;
1455         char *end;
1456
1457         memset(&data, 0, sizeof(data));
1458         data.ioc_dev = cur_device;
1459         if (argc < 2 || argc > 4)
1460                 return CMD_HELP;
1461
1462         count = strtoull(argv[1], &end, 0);
1463         if (*end) {
1464                 fprintf(stderr, "error: %s: invalid iteration count '%s'\n",
1465                         jt_cmdname(argv[0]), argv[1]);
1466                 return CMD_HELP;
1467         }
1468
1469         if (argc > 2) {
1470                 mode = strtoul(argv[2], &end, 0);
1471                 if (*end) {
1472                         fprintf(stderr, "error: %s: invalid mode '%s'\n",
1473                                 jt_cmdname(argv[0]), argv[2]);
1474                         return CMD_HELP;
1475                 }
1476                 if (!(mode & S_IFMT))
1477                         mode |= S_IFREG;
1478         }
1479
1480         if (argc > 3) {
1481                 verbose = get_verbose(argv[0], argv[3]);
1482                 if (verbose == BAD_VERBOSE)
1483                         return CMD_HELP;
1484         }
1485
1486         printf("%s: "LPD64" objects\n", jt_cmdname(argv[0]), count);
1487         gettimeofday(&next_time, NULL);
1488         next_time.tv_sec -= verbose;
1489
1490         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1491         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
1492                 data.ioc_obdo1.o_mode = mode;
1493                 ostid_set_id(&data.ioc_obdo1.o_oi, base_id);
1494                 data.ioc_obdo1.o_uid = 0;
1495                 data.ioc_obdo1.o_gid = 0;
1496                 data.ioc_obdo1.o_valid = OBD_MD_FLTYPE | OBD_MD_FLMODE |
1497                                          OBD_MD_FLID | OBD_MD_FLUID |
1498                                          OBD_MD_FLGID | OBD_MD_FLGROUP;
1499
1500                 memset(buf, 0, sizeof(rawbuf));
1501                 rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
1502                 if (rc) {
1503                         fprintf(stderr, "error: %s: invalid ioctl\n",
1504                                 jt_cmdname(argv[0]));
1505                         return rc;
1506                 }
1507                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_CREATE, buf);
1508                 obd_ioctl_unpack(&data, buf, sizeof(rawbuf));
1509                 shmem_bump(1);
1510                 if (rc < 0) {
1511                         fprintf(stderr, "error: %s: #%d - %s\n",
1512                                 jt_cmdname(argv[0]), i, strerror(rc = errno));
1513                         break;
1514                 }
1515                 if (!(data.ioc_obdo1.o_valid & OBD_MD_FLID)) {
1516                         fprintf(stderr,"error: %s: oid not valid #%d:"LPX64"\n",
1517                                 jt_cmdname(argv[0]), i, data.ioc_obdo1.o_valid);
1518                         rc = EINVAL;
1519                         break;
1520                 }
1521
1522                 if (be_verbose(verbose, &next_time, i, &next_count, count))
1523                         printf("%s: #%d is object id "LPX64"\n",
1524                                jt_cmdname(argv[0]), i,
1525                                ostid_id(&data.ioc_obdo1.o_oi));
1526         }
1527         return rc;
1528 }
1529
1530 int jt_obd_setattr(int argc, char **argv)
1531 {
1532         struct obd_ioctl_data data;
1533         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1534         char *end;
1535         int rc;
1536
1537         memset(&data, 0, sizeof(data));
1538         data.ioc_dev = cur_device;
1539         if (argc != 2)
1540                 return CMD_HELP;
1541
1542         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1543         ostid_set_id(&data.ioc_obdo1.o_oi, strtoull(argv[1], &end, 0));
1544         if (*end) {
1545                 fprintf(stderr, "error: %s: invalid objid '%s'\n",
1546                         jt_cmdname(argv[0]), argv[1]);
1547                 return CMD_HELP;
1548         }
1549         data.ioc_obdo1.o_mode = S_IFREG | strtoul(argv[2], &end, 0);
1550         if (*end) {
1551                 fprintf(stderr, "error: %s: invalid mode '%s'\n",
1552                         jt_cmdname(argv[0]), argv[2]);
1553                 return CMD_HELP;
1554         }
1555         data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE;
1556
1557         memset(buf, 0, sizeof(rawbuf));
1558         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
1559         if (rc) {
1560                 fprintf(stderr, "error: %s: invalid ioctl\n",
1561                         jt_cmdname(argv[0]));
1562                 return rc;
1563         }
1564         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_SETATTR, buf);
1565         if (rc < 0)
1566                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
1567                         strerror(rc = errno));
1568
1569         return rc;
1570 }
1571
1572 int jt_obd_test_setattr(int argc, char **argv)
1573 {
1574         struct obd_ioctl_data data;
1575         struct timeval start, next_time;
1576         __u64 i, count, next_count;
1577         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1578         int verbose = 1;
1579         __u64 objid = 3;
1580         char *end;
1581         int rc = 0;
1582
1583         if (argc < 2 || argc > 4)
1584                 return CMD_HELP;
1585
1586         memset(&data, 0, sizeof(data));
1587         data.ioc_dev = cur_device;
1588         count = strtoull(argv[1], &end, 0);
1589         if (*end) {
1590                 fprintf(stderr, "error: %s: invalid iteration count '%s'\n",
1591                         jt_cmdname(argv[0]), argv[1]);
1592                 return CMD_HELP;
1593         }
1594
1595         if (argc >= 3) {
1596                 verbose = get_verbose(argv[0], argv[2]);
1597                 if (verbose == BAD_VERBOSE)
1598                         return CMD_HELP;
1599         }
1600
1601         if (argc >= 4) {
1602                 if (argv[3][0] == 't') {
1603                         objid = strtoull(argv[3] + 1, &end, 0);
1604                         if (thread)
1605                                 objid += thread - 1;
1606                 } else
1607                         objid = strtoull(argv[3], &end, 0);
1608                 if (*end) {
1609                         fprintf(stderr, "error: %s: invalid objid '%s'\n",
1610                                 jt_cmdname(argv[0]), argv[3]);
1611                         return CMD_HELP;
1612                 }
1613         }
1614
1615         gettimeofday(&start, NULL);
1616         next_time.tv_sec = start.tv_sec - verbose;
1617         next_time.tv_usec = start.tv_usec;
1618         if (verbose != 0)
1619                 printf("%s: setting "LPD64" attrs (objid "LPX64"): %s",
1620                        jt_cmdname(argv[0]), count, objid, ctime(&start.tv_sec));
1621
1622         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1623         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
1624                 ostid_set_id(&data.ioc_obdo1.o_oi, objid);
1625                 data.ioc_obdo1.o_mode = S_IFREG;
1626                 data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE;
1627                 memset(buf, 0, sizeof(rawbuf));
1628                 rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
1629                 if (rc) {
1630                         fprintf(stderr, "error: %s: invalid ioctl\n",
1631                                 jt_cmdname(argv[0]));
1632                         return rc;
1633                 }
1634                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_SETATTR, &data);
1635                 shmem_bump(1);
1636                 if (rc < 0) {
1637                         fprintf(stderr, "error: %s: #"LPD64" - %d:%s\n",
1638                                 jt_cmdname(argv[0]), i, errno, strerror(rc = errno));
1639                         break;
1640                 } else {
1641                         if (be_verbose
1642                             (verbose, &next_time, i, &next_count, count))
1643                                 printf("%s: set attr #"LPD64"\n",
1644                                        jt_cmdname(argv[0]), i);
1645                 }
1646         }
1647
1648         if (!rc) {
1649                 struct timeval end;
1650                 double diff;
1651
1652                 gettimeofday(&end, NULL);
1653
1654                 diff = difftime(&end, &start);
1655
1656                 --i;
1657                 if (verbose != 0)
1658                         printf("%s: "LPD64" attrs in %.3fs (%.3f attr/s): %s",
1659                                jt_cmdname(argv[0]), i, diff, i / diff,
1660                                ctime(&end.tv_sec));
1661         }
1662         return rc;
1663 }
1664
1665 int jt_obd_destroy(int argc, char **argv)
1666 {
1667         struct obd_ioctl_data data;
1668         struct timeval next_time;
1669         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1670         __u64 count = 1, next_count;
1671         int verbose = 1;
1672         __u64 id;
1673         char *end;
1674         int rc = 0, i;
1675
1676         memset(&data, 0, sizeof(data));
1677         data.ioc_dev = cur_device;
1678         if (argc < 2 || argc > 4)
1679                 return CMD_HELP;
1680
1681         id = strtoull(argv[1], &end, 0);
1682         if (*end || id == 0 || errno != 0) {
1683                 fprintf(stderr, "error: %s: invalid objid '%s'\n",
1684                         jt_cmdname(argv[0]), argv[1]);
1685                 return CMD_HELP;
1686         }
1687         if (argc > 2) {
1688                 count = strtoull(argv[2], &end, 0);
1689                 if (*end) {
1690                         fprintf(stderr,
1691                                 "error: %s: invalid iteration count '%s'\n",
1692                                 jt_cmdname(argv[0]), argv[2]);
1693                         return CMD_HELP;
1694                 }
1695         }
1696
1697         if (argc > 3) {
1698                 verbose = get_verbose(argv[0], argv[3]);
1699                 if (verbose == BAD_VERBOSE)
1700                         return CMD_HELP;
1701         }
1702
1703         printf("%s: "LPD64" objects\n", jt_cmdname(argv[0]), count);
1704         gettimeofday(&next_time, NULL);
1705         next_time.tv_sec -= verbose;
1706
1707         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1708         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++, id++) {
1709                 ostid_set_id(&data.ioc_obdo1.o_oi, id);
1710                 data.ioc_obdo1.o_mode = S_IFREG | 0644;
1711                 data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLMODE;
1712
1713                 memset(buf, 0, sizeof(rawbuf));
1714                 rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
1715                 if (rc) {
1716                         fprintf(stderr, "error: %s: invalid ioctl\n",
1717                                 jt_cmdname(argv[0]));
1718                         return rc;
1719                 }
1720                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_DESTROY, buf);
1721                 obd_ioctl_unpack(&data, buf, sizeof(rawbuf));
1722                 shmem_bump(1);
1723                 if (rc < 0) {
1724                         fprintf(stderr, "error: %s: objid "LPX64": %s\n",
1725                                 jt_cmdname(argv[0]), id, strerror(rc = errno));
1726                         break;
1727                 }
1728
1729                 if (be_verbose(verbose, &next_time, i, &next_count, count))
1730                         printf("%s: #%d is object id "LPX64"\n",
1731                                jt_cmdname(argv[0]), i, id);
1732         }
1733
1734         return rc;
1735 }
1736
1737 int jt_obd_getattr(int argc, char **argv)
1738 {
1739         struct obd_ioctl_data data;
1740         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1741         char *end;
1742         int rc;
1743
1744         if (argc != 2)
1745                 return CMD_HELP;
1746
1747         memset(&data, 0, sizeof(data));
1748         data.ioc_dev = cur_device;
1749         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1750         ostid_set_id(&data.ioc_obdo1.o_oi, strtoull(argv[1], &end, 0));
1751         if (*end) {
1752                 fprintf(stderr, "error: %s: invalid objid '%s'\n",
1753                         jt_cmdname(argv[0]), argv[1]);
1754                 return CMD_HELP;
1755         }
1756         /* to help obd filter */
1757         data.ioc_obdo1.o_mode = 0100644;
1758         data.ioc_obdo1.o_valid = 0xffffffff;
1759         printf("%s: object id "LPX64"\n", jt_cmdname(argv[0]),
1760                ostid_id(&data.ioc_obdo1.o_oi));
1761
1762         memset(buf, 0, sizeof(rawbuf));
1763         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
1764         if (rc) {
1765                 fprintf(stderr, "error: %s: invalid ioctl\n",
1766                         jt_cmdname(argv[0]));
1767                 return rc;
1768         }
1769         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_GETATTR, buf);
1770         obd_ioctl_unpack(&data, buf, sizeof(rawbuf));
1771         if (rc) {
1772                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
1773                         strerror(rc = errno));
1774         } else {
1775                 printf("%s: object id "LPU64", mode %o\n", jt_cmdname(argv[0]),
1776                        ostid_id(&data.ioc_obdo1.o_oi), data.ioc_obdo1.o_mode);
1777         }
1778         return rc;
1779 }
1780
1781 int jt_obd_test_getattr(int argc, char **argv)
1782 {
1783         struct obd_ioctl_data data;
1784         struct timeval start, next_time;
1785         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1786         __u64 i, count, next_count;
1787         int verbose = 1;
1788         __u64 objid = 3;
1789         char *end;
1790         int rc = 0;
1791
1792         if (argc < 2 || argc > 4)
1793                 return CMD_HELP;
1794
1795         memset(&data, 0, sizeof(data));
1796         data.ioc_dev = cur_device;
1797         count = strtoull(argv[1], &end, 0);
1798         if (*end) {
1799                 fprintf(stderr, "error: %s: invalid iteration count '%s'\n",
1800                         jt_cmdname(argv[0]), argv[1]);
1801                 return CMD_HELP;
1802         }
1803
1804         if (argc >= 3) {
1805                 verbose = get_verbose(argv[0], argv[2]);
1806                 if (verbose == BAD_VERBOSE)
1807                         return CMD_HELP;
1808         }
1809
1810         if (argc >= 4) {
1811                 if (argv[3][0] == 't') {
1812                         objid = strtoull(argv[3] + 1, &end, 0);
1813                         if (thread)
1814                                 objid += thread - 1;
1815                 } else
1816                         objid = strtoull(argv[3], &end, 0);
1817                 if (*end) {
1818                         fprintf(stderr, "error: %s: invalid objid '%s'\n",
1819                                 jt_cmdname(argv[0]), argv[3]);
1820                         return CMD_HELP;
1821                 }
1822         }
1823
1824         gettimeofday(&start, NULL);
1825         next_time.tv_sec = start.tv_sec - verbose;
1826         next_time.tv_usec = start.tv_usec;
1827         if (verbose != 0)
1828                 printf("%s: getting "LPD64" attrs (objid "LPX64"): %s",
1829                        jt_cmdname(argv[0]), count, objid, ctime(&start.tv_sec));
1830
1831         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
1832         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
1833                 ostid_set_id(&data.ioc_obdo1.o_oi, objid);
1834                 data.ioc_obdo1.o_mode = S_IFREG;
1835                 data.ioc_obdo1.o_valid = 0xffffffff;
1836                 memset(buf, 0, sizeof(rawbuf));
1837                 rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
1838                 if (rc) {
1839                         fprintf(stderr, "error: %s: invalid ioctl\n",
1840                                 jt_cmdname(argv[0]));
1841                         return rc;
1842                 }
1843                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_GETATTR, &data);
1844                 shmem_bump(1);
1845                 if (rc < 0) {
1846                         fprintf(stderr, "error: %s: #"LPD64" - %d:%s\n",
1847                                 jt_cmdname(argv[0]), i, errno, strerror(rc = errno));
1848                         break;
1849                 } else {
1850                         if (be_verbose
1851                             (verbose, &next_time, i, &next_count, count))
1852                                 printf("%s: got attr #"LPD64"\n",
1853                                        jt_cmdname(argv[0]), i);
1854                 }
1855         }
1856
1857         if (!rc) {
1858                 struct timeval end;
1859                 double diff;
1860
1861                 gettimeofday(&end, NULL);
1862
1863                 diff = difftime(&end, &start);
1864
1865                 --i;
1866                 if (verbose != 0)
1867                         printf("%s: "LPD64" attrs in %.3fs (%.3f attr/s): %s",
1868                                jt_cmdname(argv[0]), i, diff, i / diff,
1869                                ctime(&end.tv_sec));
1870         }
1871         return rc;
1872 }
1873
1874 /* test_brw <cnt>                                               count
1875         <r|w[r(repeat)x(noverify)]>                             mode
1876         <q|v|#(print interval)>                                 verbosity
1877         <npages[+offset]>                                       blocksize
1878         <[[<interleave_threads>]t(inc obj by thread#)]obj>      object
1879         [p|g<args>]                                             batch */
1880 int jt_obd_test_brw(int argc, char **argv)
1881 {
1882         struct obd_ioctl_data data;
1883         struct timeval start, next_time;
1884         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1885         __u64 count, next_count, len, stride, thr_offset = 0, objid = 3;
1886         int write = 0, verbose = 1, cmd, i, rc = 0, pages = 1;
1887         int offset_pages = 0;
1888         long n;
1889         int repeat_offset = 0;
1890         unsigned long long ull;
1891         int  nthr_per_obj = 0;
1892         int  verify = 1;
1893         int  obj_idx = 0;
1894         char *end;
1895
1896         if (argc < 2 || argc > 7) {
1897                 fprintf(stderr, "error: %s: bad number of arguments: %d\n",
1898                         jt_cmdname(argv[0]), argc);
1899                 return CMD_HELP;
1900         }
1901
1902         count = strtoull(argv[1], &end, 0);
1903         if (*end) {
1904                 fprintf(stderr, "error: %s: bad iteration count '%s'\n",
1905                         jt_cmdname(argv[0]), argv[1]);
1906                 return CMD_HELP;
1907         }
1908
1909         if (argc >= 3) {
1910                 if (argv[2][0] == 'w' || argv[2][0] == '1')
1911                         write = 1;
1912                 /* else it's a read */
1913
1914                 if (argv[2][0] != 0)
1915                         for (i = 1; argv[2][i] != 0; i++)
1916                                 switch (argv[2][i]) {
1917                                 case 'r':
1918                                         repeat_offset = 1;
1919                                         break;
1920
1921                                 case 'x':
1922                                         verify = 0;
1923                                         break;
1924
1925                                 default:
1926                                         fprintf (stderr, "Can't parse cmd '%s'\n",
1927                                                  argv[2]);
1928                                         return CMD_HELP;
1929                                 }
1930         }
1931
1932         if (argc >= 4) {
1933                 verbose = get_verbose(argv[0], argv[3]);
1934                 if (verbose == BAD_VERBOSE)
1935                         return CMD_HELP;
1936         }
1937
1938         if (argc >= 5) {
1939                 pages = strtoul(argv[4], &end, 0);
1940
1941                 if (*end == '+')
1942                         offset_pages = strtoul(end + 1, &end, 0);
1943
1944                 if (*end != 0 ||
1945                     offset_pages < 0 || offset_pages >= pages) {
1946                         fprintf(stderr, "error: %s: bad npages[+offset] parameter '%s'\n",
1947                                 jt_cmdname(argv[0]), argv[4]);
1948                         return CMD_HELP;
1949                 }
1950         }
1951
1952         if (argc >= 6) {
1953                 if (thread &&
1954                     (n = strtol(argv[5], &end, 0)) > 0 &&
1955                     *end == 't' &&
1956                     (ull = strtoull(end + 1, &end, 0)) > 0 &&
1957                     *end == 0) {
1958                         nthr_per_obj = n;
1959                         objid = ull;
1960                 } else if (thread &&
1961                            argv[5][0] == 't') {
1962                         nthr_per_obj = 1;
1963                         objid = strtoull(argv[5] + 1, &end, 0);
1964                 } else {
1965                         nthr_per_obj = 0;
1966                         objid = strtoull(argv[5], &end, 0);
1967                 }
1968                 if (*end) {
1969                         fprintf(stderr, "error: %s: bad objid '%s'\n",
1970                                 jt_cmdname(argv[0]), argv[5]);
1971                         return CMD_HELP;
1972                 }
1973         }
1974
1975         memset(&data, 0, sizeof(data));
1976         data.ioc_dev = cur_device;
1977
1978         /* communicate the 'type' of brw test and batching to echo_client.
1979          * don't start.  we'd love to refactor this lctl->echo_client
1980          * interface */
1981         data.ioc_pbuf1 = (void *)1;
1982         data.ioc_plen1 = 1;
1983
1984         if (argc >= 7) {
1985                 switch(argv[6][0]) {
1986                         case 'g': /* plug and unplug */
1987                                 data.ioc_pbuf1 = (void *)2;
1988                                 data.ioc_plen1 = strtoull(argv[6] + 1, &end,
1989                                                           0);
1990                                 break;
1991                         case 'p': /* prep and commit */
1992                                 data.ioc_pbuf1 = (void *)3;
1993                                 data.ioc_plen1 = strtoull(argv[6] + 1, &end,
1994                                                           0);
1995                                 break;
1996                         default:
1997                                 fprintf(stderr, "error: %s: batching '%s' "
1998                                         "needs to specify 'p' or 'g'\n",
1999                                         jt_cmdname(argv[0]), argv[6]);
2000                                 return CMD_HELP;
2001                 }
2002
2003                 if (*end) {
2004                         fprintf(stderr, "error: %s: bad batching '%s'\n",
2005                                 jt_cmdname(argv[0]), argv[6]);
2006                         return CMD_HELP;
2007                 }
2008                 data.ioc_plen1 *= getpagesize();
2009         }
2010
2011         len = pages * getpagesize();
2012         thr_offset = offset_pages * getpagesize();
2013         stride = len;
2014
2015 #ifdef MAX_THREADS
2016         if (thread) {
2017                 shmem_lock ();
2018                 if (nthr_per_obj != 0) {
2019                         /* threads interleave */
2020                         obj_idx = (thread - 1)/nthr_per_obj;
2021                         objid += obj_idx;
2022                         stride *= nthr_per_obj;
2023                         if ((thread - 1) % nthr_per_obj == 0) {
2024                                 shared_data->body.offsets[obj_idx] =
2025                                         stride + thr_offset;
2026                         }
2027                         thr_offset += ((thread - 1) % nthr_per_obj) * len;
2028                 } else {
2029                         /* threads disjoint */
2030                         thr_offset += (thread - 1) * len;
2031                 }
2032
2033                 shmem_start_time_locked();
2034                 shmem_unlock ();
2035         }
2036 #endif
2037
2038         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
2039         ostid_set_id(&data.ioc_obdo1.o_oi, objid);
2040         data.ioc_obdo1.o_mode = S_IFREG;
2041         data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE |
2042                                  OBD_MD_FLFLAGS | OBD_MD_FLGROUP;
2043         data.ioc_obdo1.o_flags = (verify ? OBD_FL_DEBUG_CHECK : 0);
2044         data.ioc_count = len;
2045         data.ioc_offset = (repeat_offset ? 0 : thr_offset);
2046
2047         gettimeofday(&start, NULL);
2048         next_time.tv_sec = start.tv_sec - verbose;
2049         next_time.tv_usec = start.tv_usec;
2050
2051         if (verbose != 0)
2052                 printf("%s: %s "LPU64"x%d pages (obj "LPX64", off "LPU64"): %s",
2053                        jt_cmdname(argv[0]), write ? "writing" : "reading", count,
2054                        pages, objid, data.ioc_offset, ctime(&start.tv_sec));
2055
2056         cmd = write ? OBD_IOC_BRW_WRITE : OBD_IOC_BRW_READ;
2057         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
2058                 data.ioc_obdo1.o_valid &= ~(OBD_MD_FLBLOCKS|OBD_MD_FLGRANT);
2059                 memset(buf, 0, sizeof(rawbuf));
2060                 rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2061                 if (rc) {
2062                         fprintf(stderr, "error: %s: invalid ioctl\n",
2063                                 jt_cmdname(argv[0]));
2064                         return rc;
2065                 }
2066                 rc = l2_ioctl(OBD_DEV_ID, cmd, buf);
2067                 shmem_bump(1);
2068                 if (rc) {
2069                         fprintf(stderr, "error: %s: #%d - %s on %s\n",
2070                                 jt_cmdname(argv[0]), i, strerror(rc = errno),
2071                                 write ? "write" : "read");
2072                         break;
2073                 } else if (be_verbose(verbose, &next_time,i, &next_count,count)) {
2074                         shmem_lock ();
2075                         printf("%s: %s number %d @ "LPD64":"LPU64" for %d\n",
2076                                jt_cmdname(argv[0]), write ? "write" : "read", i,
2077                                ostid_id(&data.ioc_obdo1.o_oi), data.ioc_offset,
2078                                (int)(pages * getpagesize()));
2079                         shmem_unlock ();
2080                 }
2081
2082                 if (!repeat_offset) {
2083 #ifdef MAX_THREADS
2084                         if (stride == len) {
2085                                 data.ioc_offset += stride;
2086                         } else if (i < count) {
2087                                 shmem_lock ();
2088                                 data.ioc_offset =
2089                                         shared_data->body.offsets[obj_idx];
2090                                 shared_data->body.offsets[obj_idx] += len;
2091                                 shmem_unlock ();
2092                         }
2093 #else
2094                         data.ioc_offset += len;
2095                         obj_idx = 0; /* avoids an unused var warning */
2096 #endif
2097                 }
2098         }
2099
2100         if (!rc) {
2101                 struct timeval end;
2102                 double diff;
2103
2104                 gettimeofday(&end, NULL);
2105
2106                 diff = difftime(&end, &start);
2107
2108                 --i;
2109                 if (verbose != 0)
2110                         printf("%s: %s %dx%d pages in %.3fs (%.3f MB/s): %s",
2111                                jt_cmdname(argv[0]), write ? "wrote" : "read",
2112                                i, pages, diff,
2113                                ((double)i * pages * getpagesize()) /
2114                                (diff * 1048576.0),
2115                                ctime(&end.tv_sec));
2116         }
2117
2118 #ifdef MAX_THREADS
2119         if (thread) {
2120                 shmem_lock();
2121                 shmem_end_time_locked();
2122                 shmem_unlock();
2123         }
2124 #endif
2125         return rc;
2126 }
2127
2128 int jt_obd_lov_getconfig(int argc, char **argv)
2129 {
2130         struct obd_ioctl_data data;
2131         struct lov_desc desc;
2132         struct obd_uuid *uuidarray;
2133         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2134         __u32 *obdgens;
2135         char *path;
2136         int rc, fd;
2137
2138         memset(&data, 0, sizeof(data));
2139         data.ioc_dev = cur_device;
2140
2141         if (argc != 2)
2142                 return CMD_HELP;
2143
2144         path = argv[1];
2145         fd = open(path, O_RDONLY);
2146         if (fd < 0) {
2147                 fprintf(stderr, "open \"%s\" failed: %s\n", path,
2148                         strerror(errno));
2149                 return -errno;
2150         }
2151
2152         memset(&desc, 0, sizeof(desc));
2153         obd_str2uuid(&desc.ld_uuid, argv[1]);
2154         desc.ld_tgt_count = ((OBD_MAX_IOCTL_BUFFER-sizeof(data)-sizeof(desc)) /
2155                              (sizeof(*uuidarray) + sizeof(*obdgens)));
2156
2157 repeat:
2158         uuidarray = calloc(desc.ld_tgt_count, sizeof(*uuidarray));
2159         if (!uuidarray) {
2160                 fprintf(stderr, "error: %s: no memory for %d uuid's\n",
2161                         jt_cmdname(argv[0]), desc.ld_tgt_count);
2162                 rc = -ENOMEM;
2163                 goto out;
2164         }
2165         obdgens = calloc(desc.ld_tgt_count, sizeof(*obdgens));
2166         if (!obdgens) {
2167                 fprintf(stderr, "error: %s: no memory for %d generation #'s\n",
2168                         jt_cmdname(argv[0]), desc.ld_tgt_count);
2169                 rc = -ENOMEM;
2170                 goto out_uuidarray;
2171         }
2172
2173         memset(buf, 0, sizeof(rawbuf));
2174         data.ioc_inllen1 = sizeof(desc);
2175         data.ioc_inlbuf1 = (char *)&desc;
2176         data.ioc_inllen2 = desc.ld_tgt_count * sizeof(*uuidarray);
2177         data.ioc_inlbuf2 = (char *)uuidarray;
2178         data.ioc_inllen3 = desc.ld_tgt_count * sizeof(*obdgens);
2179         data.ioc_inlbuf3 = (char *)obdgens;
2180
2181         if (obd_ioctl_pack(&data, &buf, sizeof(rawbuf))) {
2182                 fprintf(stderr, "error: %s: invalid ioctl\n",
2183                         jt_cmdname(argv[0]));
2184                 rc = -EINVAL;
2185                 goto out_obdgens;
2186         }
2187         rc = ioctl(fd, OBD_IOC_LOV_GET_CONFIG, buf);
2188         if (rc == -ENOSPC) {
2189                 free(uuidarray);
2190                 free(obdgens);
2191                 goto repeat;
2192         } else if (rc) {
2193                 fprintf(stderr, "error: %s: ioctl error: %s\n",
2194                         jt_cmdname(argv[0]), strerror(rc = errno));
2195         } else {
2196                 struct obd_uuid *uuidp;
2197                 __u32 *genp;
2198                 int i;
2199
2200                 if (obd_ioctl_unpack(&data, buf, sizeof(rawbuf))) {
2201                         fprintf(stderr, "error: %s: invalid reply\n",
2202                                 jt_cmdname(argv[0]));
2203                         rc = -EINVAL;
2204                         goto out;
2205                 }
2206                 if (desc.ld_default_stripe_count == (__u32)-1)
2207                         printf("default_stripe_count: %d\n", -1);
2208                 else
2209                         printf("default_stripe_count: %u\n",
2210                                desc.ld_default_stripe_count);
2211                 printf("default_stripe_size: "LPU64"\n",
2212                        desc.ld_default_stripe_size);
2213                 printf("default_stripe_offset: "LPU64"\n",
2214                        desc.ld_default_stripe_offset);
2215                 printf("default_stripe_pattern: %u\n", desc.ld_pattern);
2216                 printf("obd_count: %u\n", desc.ld_tgt_count);
2217                 printf("OBDS:\tobdidx\t\tobdgen\t\t obduuid\n");
2218                 uuidp = uuidarray;
2219                 genp = obdgens;
2220                 for (i = 0; i < desc.ld_tgt_count; i++, uuidp++, genp++)
2221                         printf("\t%6u\t%14u\t\t %s\n", i, *genp, (char *)uuidp);
2222         }
2223 out_obdgens:
2224         free(obdgens);
2225 out_uuidarray:
2226         free(uuidarray);
2227 out:
2228         close(fd);
2229         return rc;
2230 }
2231
2232 static int do_activate(int argc, char **argv, int flag)
2233 {
2234         struct obd_ioctl_data data;
2235         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2236         int rc;
2237
2238         memset(&data, 0, sizeof(data));
2239         data.ioc_dev = cur_device;
2240         if (argc != 1)
2241                 return CMD_HELP;
2242
2243         /* reuse offset for 'active' */
2244         data.ioc_offset = flag;
2245
2246         memset(buf, 0, sizeof(rawbuf));
2247         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2248         if (rc) {
2249                 fprintf(stderr, "error: %s: invalid ioctl\n",
2250                         jt_cmdname(argv[0]));
2251                 return rc;
2252         }
2253         rc = l2_ioctl(OBD_DEV_ID, IOC_OSC_SET_ACTIVE, buf);
2254         if (rc)
2255                 fprintf(stderr, "error: %s: failed: %s\n",
2256                         jt_cmdname(argv[0]), strerror(rc = errno));
2257
2258         return rc;
2259 }
2260
2261 /**
2262  * Replace nids for given device.
2263  * lctl replace_nids <devicename> <nid1>[,nid2,nid3]
2264  * Command should be started on MGS server.
2265  * Only MGS server should be started (command execution
2266  * returns error in another cases). Command mount
2267  * -t lustre <MDT partition> -o nosvc <mount point>
2268  * can be used for that.
2269  *
2270  * llogs for MDTs and clients are processed. All
2271  * records copied as is except add_uuid and setup. This records
2272  * are skipped and recorded with new nids and uuid.
2273  *
2274  * \see mgs_replace_nids
2275  * \see mgs_replace_nids_log
2276  * \see mgs_replace_handler
2277  */
2278 int jt_replace_nids(int argc, char **argv)
2279 {
2280         int rc;
2281         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2282         struct obd_ioctl_data data;
2283
2284         memset(&data, 0, sizeof(data));
2285         data.ioc_dev = get_mgs_device();
2286         if (argc != 3)
2287                 return CMD_HELP;
2288
2289         data.ioc_inllen1 = strlen(argv[1]) + 1;
2290         data.ioc_inlbuf1 = argv[1];
2291
2292         data.ioc_inllen2 = strlen(argv[2]) + 1;
2293         data.ioc_inlbuf2 = argv[2];
2294         memset(buf, 0, sizeof(rawbuf));
2295         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2296         if (rc) {
2297                 fprintf(stderr, "error: %s: invalid ioctl\n",
2298                         jt_cmdname(argv[0]));
2299                 return rc;
2300         }
2301
2302         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_REPLACE_NIDS, buf);
2303         if (rc < 0) {
2304                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
2305                         strerror(rc = errno));
2306         }
2307
2308         return rc;
2309 }
2310
2311 int jt_obd_deactivate(int argc, char **argv)
2312 {
2313         return do_activate(argc, argv, 0);
2314 }
2315
2316 int jt_obd_activate(int argc, char **argv)
2317 {
2318         return do_activate(argc, argv, 1);
2319 }
2320
2321 int jt_obd_recover(int argc, char **argv)
2322 {
2323         int rc;
2324         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2325         struct obd_ioctl_data data;
2326
2327         memset(&data, 0, sizeof(data));
2328         data.ioc_dev = cur_device;
2329         if (argc > 2)
2330                 return CMD_HELP;
2331
2332         if (argc == 2) {
2333                 data.ioc_inllen1 = strlen(argv[1]) + 1;
2334                 data.ioc_inlbuf1 = argv[1];
2335         }
2336
2337         memset(buf, 0, sizeof(rawbuf));
2338         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2339         if (rc) {
2340                 fprintf(stderr, "error: %s: invalid ioctl\n",
2341                         jt_cmdname(argv[0]));
2342                 return rc;
2343         }
2344         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_CLIENT_RECOVER, buf);
2345         if (rc < 0) {
2346                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
2347                         strerror(rc = errno));
2348         }
2349
2350         return rc;
2351 }
2352
2353 int jt_obd_mdc_lookup(int argc, char **argv)
2354 {
2355         struct obd_ioctl_data data;
2356         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2357         char *parent, *child;
2358         int rc, fd, verbose = 1;
2359
2360         if (argc < 3 || argc > 4)
2361                 return CMD_HELP;
2362
2363         parent = argv[1];
2364         child = argv[2];
2365         if (argc == 4)
2366                 verbose = get_verbose(argv[0], argv[3]);
2367
2368         memset(&data, 0, sizeof(data));
2369         data.ioc_dev = cur_device;
2370
2371         data.ioc_inllen1 = strlen(child) + 1;
2372         data.ioc_inlbuf1 = child;
2373
2374         memset(buf, 0, sizeof(rawbuf));
2375         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2376         if (rc) {
2377                 fprintf(stderr, "error: %s: invalid ioctl\n",
2378                         jt_cmdname(argv[0]));
2379                 return rc;
2380         }
2381
2382         fd = open(parent, O_RDONLY);
2383         if (fd < 0) {
2384                 fprintf(stderr, "open \"%s\" failed: %s\n", parent,
2385                         strerror(errno));
2386                 return -1;
2387         }
2388
2389         rc = ioctl(fd, IOC_MDC_LOOKUP, buf);
2390         if (rc < 0) {
2391                 fprintf(stderr, "error: %s: ioctl error: %s\n",
2392                         jt_cmdname(argv[0]), strerror(rc = errno));
2393         }
2394         close(fd);
2395
2396         if (verbose) {
2397                 rc = obd_ioctl_unpack(&data, buf, sizeof(rawbuf));
2398                 if (rc) {
2399                         fprintf(stderr, "error: %s: invalid reply\n",
2400                                 jt_cmdname(argv[0]));
2401                         return rc;
2402                 }
2403                 printf("%s: mode %o uid %d gid %d\n", child,
2404                        data.ioc_obdo1.o_mode, data.ioc_obdo1.o_uid,
2405                        data.ioc_obdo1.o_gid);
2406         }
2407
2408         return rc;
2409 }
2410
2411 int jt_cfg_dump_log(int argc, char **argv)
2412 {
2413         struct obd_ioctl_data data;
2414         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2415         int rc;
2416
2417         if (argc != 2)
2418                 return CMD_HELP;
2419
2420         memset(&data, 0, sizeof(data));
2421         data.ioc_dev = cur_device;
2422         data.ioc_inllen1 = strlen(argv[1]) + 1;
2423         data.ioc_inlbuf1 = argv[1];
2424
2425         memset(buf, 0, sizeof(rawbuf));
2426         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2427         if (rc) {
2428                 fprintf(stderr, "error: %s: invalid ioctl\n",
2429                         jt_cmdname(argv[0]));
2430                 return rc;
2431         }
2432         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_DUMP_LOG, buf);
2433         if (rc < 0)
2434                 fprintf(stderr, "OBD_IOC_DUMP_LOG failed: %s\n",
2435                         strerror(errno));
2436
2437         return rc;
2438 }
2439
2440 int jt_llog_catlist(int argc, char **argv)
2441 {
2442         struct obd_ioctl_data data;
2443         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2444         int rc;
2445
2446         if (argc != 1)
2447                 return CMD_HELP;
2448
2449         memset(&data, 0, sizeof(data));
2450         data.ioc_dev = cur_device;
2451         data.ioc_inllen1 = sizeof(rawbuf) - cfs_size_round(sizeof(data));
2452         memset(buf, 0, sizeof(rawbuf));
2453         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2454         if (rc) {
2455                 fprintf(stderr, "error: %s: invalid ioctl\n",
2456                         jt_cmdname(argv[0]));
2457                 return rc;
2458         }
2459         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_CATLOGLIST, buf);
2460         if (rc == 0)
2461                 fprintf(stdout, "%s", ((struct obd_ioctl_data*)buf)->ioc_bulk);
2462         else
2463                 fprintf(stderr, "OBD_IOC_CATLOGLIST failed: %s\n",
2464                         strerror(errno));
2465
2466         return rc;
2467 }
2468
2469 int jt_llog_info(int argc, char **argv)
2470 {
2471         struct obd_ioctl_data data;
2472         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2473         int rc;
2474
2475         if (argc != 2)
2476                 return CMD_HELP;
2477
2478         memset(&data, 0, sizeof(data));
2479         data.ioc_dev = cur_device;
2480         data.ioc_inllen1 = strlen(argv[1]) + 1;
2481         data.ioc_inlbuf1 = argv[1];
2482         data.ioc_inllen2 = sizeof(rawbuf) - cfs_size_round(sizeof(data)) -
2483                 cfs_size_round(data.ioc_inllen1);
2484         memset(buf, 0, sizeof(rawbuf));
2485         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2486         if (rc) {
2487                 fprintf(stderr, "error: %s: invalid ioctl\n",
2488                         jt_cmdname(argv[0]));
2489                 return rc;
2490         }
2491
2492         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_INFO, buf);
2493         if (rc == 0)
2494                 fprintf(stdout, "%s", ((struct obd_ioctl_data*)buf)->ioc_bulk);
2495         else
2496                 fprintf(stderr, "OBD_IOC_LLOG_INFO failed: %s\n",
2497                         strerror(errno));
2498
2499         return rc;
2500 }
2501
2502 int jt_llog_print(int argc, char **argv)
2503 {
2504         struct obd_ioctl_data data;
2505         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2506         int rc;
2507
2508         if (argc != 2 && argc != 4)
2509                 return CMD_HELP;
2510
2511         memset(&data, 0, sizeof(data));
2512         data.ioc_dev = cur_device;
2513         data.ioc_inllen1 = strlen(argv[1]) + 1;
2514         data.ioc_inlbuf1 = argv[1];
2515         if (argc == 4) {
2516                 data.ioc_inllen2 = strlen(argv[2]) + 1;
2517                 data.ioc_inlbuf2 = argv[2];
2518                 data.ioc_inllen3 = strlen(argv[3]) + 1;
2519                 data.ioc_inlbuf3 = argv[3];
2520         } else {
2521                 char from[2] = "1", to[3] = "-1";
2522                 data.ioc_inllen2 = strlen(from) + 1;
2523                 data.ioc_inlbuf2 = from;
2524                 data.ioc_inllen3 = strlen(to) + 1;
2525                 data.ioc_inlbuf3 = to;
2526         }
2527         data.ioc_inllen4 = sizeof(rawbuf) - cfs_size_round(sizeof(data)) -
2528                 cfs_size_round(data.ioc_inllen1) -
2529                 cfs_size_round(data.ioc_inllen2) -
2530                 cfs_size_round(data.ioc_inllen3);
2531         memset(buf, 0, sizeof(rawbuf));
2532         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2533         if (rc) {
2534                 fprintf(stderr, "error: %s: invalid ioctl\n",
2535                         jt_cmdname(argv[0]));
2536                 return rc;
2537         }
2538
2539         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_PRINT, buf);
2540         if (rc == 0)
2541                 fprintf(stdout, "%s", ((struct obd_ioctl_data*)buf)->ioc_bulk);
2542         else
2543                 fprintf(stderr, "OBD_IOC_LLOG_PRINT failed: %s\n",
2544                         strerror(errno));
2545
2546         return rc;
2547 }
2548
2549 static int llog_cancel_parse_optional(int argc, char **argv,
2550                                       struct obd_ioctl_data *data)
2551 {
2552         int cOpt;
2553         const char *const short_options = "c:l:i:h";
2554         const struct option long_options[] = {
2555                 {"catalog", required_argument, NULL, 'c'},
2556                 {"log_id", required_argument, NULL, 'l'},
2557                 {"log_idx", required_argument, NULL, 'i'},
2558                 {"help", no_argument, NULL, 'h'},
2559                 {NULL, 0, NULL, 0}
2560         };
2561
2562         /* sanity check */
2563         if (!data || argc <= 1) {
2564                 return -1;
2565         }
2566
2567         /*now process command line arguments*/
2568         while ((cOpt = getopt_long(argc, argv, short_options,
2569                                         long_options, NULL)) != -1) {
2570                 switch (cOpt) {
2571                 case 'c':
2572                         data->ioc_inllen1 = strlen(optarg) + 1;
2573                         data->ioc_inlbuf1 = optarg;
2574                         break;
2575
2576                 case 'l':
2577                         data->ioc_inllen2 = strlen(optarg) + 1;
2578                         data->ioc_inlbuf2 = optarg;
2579                         break;
2580
2581                 case 'i':
2582                         data->ioc_inllen3 = strlen(optarg) + 1;
2583                         data->ioc_inlbuf3 = optarg;
2584                         break;
2585
2586                 case 'h':
2587                 default:
2588                         return -1;
2589                 }
2590         }
2591
2592         if ((data->ioc_inlbuf1 == NULL) || (data->ioc_inlbuf3 == NULL)) {
2593                 /* missing mandatory parameters */
2594                 return -1;
2595         }
2596
2597         return 0;
2598 }
2599
2600 int jt_llog_cancel(int argc, char **argv)
2601 {
2602         struct obd_ioctl_data data;
2603         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2604         int rc, i;
2605
2606         /* check that the arguments provided are either all
2607          * optional or all positional.  No mixing allowed
2608          *
2609          * if argc is 4 or 3 then check all arguments to ensure that none
2610          * of them start with a '-'.  If so then this is invalid.
2611          * Otherwise if arg is > 4 then assume that this is optional
2612          * arguments, and parse as such ignoring any thing that's not
2613          * optional.  The result is that user must use optional arguments
2614          * for all mandatory parameters.  Code will ignore all other args
2615          *
2616          * The positional arguments option should eventually be phased out.
2617          */
2618         memset(&data, 0, sizeof(data));
2619         data.ioc_dev = cur_device;
2620
2621         if (argc == 3 || argc == 4) {
2622                 for (i = 1; i < argc; i++) {
2623                         if (argv[i][0] == '-')
2624                                 return CMD_HELP;
2625                 }
2626                 data.ioc_inllen1 = strlen(argv[1]) + 1;
2627                 data.ioc_inlbuf1 = argv[1];
2628                 if (argc == 4) {
2629                         data.ioc_inllen2 = strlen(argv[2]) + 1;
2630                         data.ioc_inlbuf2 = argv[2];
2631                         data.ioc_inllen3 = strlen(argv[3]) + 1;
2632                         data.ioc_inlbuf3 = argv[3];
2633                 } else {
2634                         data.ioc_inllen3 = strlen(argv[2]) + 1;
2635                         data.ioc_inlbuf3 = argv[2];
2636                 }
2637         } else {
2638                 if (llog_cancel_parse_optional(argc, argv, &data) != 0)
2639                         return CMD_HELP;
2640         }
2641
2642         memset(buf, 0, sizeof(rawbuf));
2643         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2644         if (rc) {
2645                 fprintf(stderr, "error: %s: invalid ioctl\n",
2646                         jt_cmdname(argv[0]));
2647                 return rc;
2648         }
2649
2650         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_CANCEL, buf);
2651         if (rc == 0)
2652                 fprintf(stdout, "index %s was canceled.\n",
2653                         argc == 4 ? argv[3] : argv[2]);
2654         else
2655                 fprintf(stderr, "OBD_IOC_LLOG_CANCEL failed: %s\n",
2656                         strerror(errno));
2657
2658         return rc;
2659 }
2660
2661 int jt_llog_check(int argc, char **argv)
2662 {
2663         struct obd_ioctl_data data;
2664         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2665         int rc;
2666
2667         if (argc != 2 && argc != 4)
2668                 return CMD_HELP;
2669
2670         memset(&data, 0, sizeof(data));
2671         data.ioc_dev = cur_device;
2672         data.ioc_inllen1 = strlen(argv[1]) + 1;
2673         data.ioc_inlbuf1 = argv[1];
2674         if (argc == 4) {
2675                 data.ioc_inllen2 = strlen(argv[2]) + 1;
2676                 data.ioc_inlbuf2 = argv[2];
2677                 data.ioc_inllen3 = strlen(argv[3]) + 1;
2678                 data.ioc_inlbuf3 = argv[3];
2679         } else {
2680                 char from[2] = "1", to[3] = "-1";
2681                 data.ioc_inllen2 = strlen(from) + 1;
2682                 data.ioc_inlbuf2 = from;
2683                 data.ioc_inllen3 = strlen(to) + 1;
2684                 data.ioc_inlbuf3 = to;
2685         }
2686         data.ioc_inllen4 = sizeof(rawbuf) - cfs_size_round(sizeof(data)) -
2687                 cfs_size_round(data.ioc_inllen1) -
2688                 cfs_size_round(data.ioc_inllen2) -
2689                 cfs_size_round(data.ioc_inllen3);
2690         memset(buf, 0, sizeof(rawbuf));
2691         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2692         if (rc) {
2693                 fprintf(stderr, "error: %s: invalid ioctl\n",
2694                         jt_cmdname(argv[0]));
2695                 return rc;
2696         }
2697
2698         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_CHECK, buf);
2699         if (rc == 0)
2700                 fprintf(stdout, "%s", ((struct obd_ioctl_data*)buf)->ioc_bulk);
2701         else
2702                 fprintf(stderr, "OBD_IOC_LLOG_CHECK failed: %s\n",
2703                         strerror(errno));
2704         return rc;
2705 }
2706
2707 int jt_llog_remove(int argc, char **argv)
2708 {
2709         struct obd_ioctl_data data;
2710         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
2711         int rc;
2712
2713         if (argc != 3 && argc != 2)
2714                 return CMD_HELP;
2715
2716         memset(&data, 0, sizeof(data));
2717         data.ioc_dev = cur_device;
2718         data.ioc_inllen1 = strlen(argv[1]) + 1;
2719         data.ioc_inlbuf1 = argv[1];
2720         if (argc == 3){
2721                 data.ioc_inllen2 = strlen(argv[2]) + 1;
2722                 data.ioc_inlbuf2 = argv[2];
2723         }
2724         memset(buf, 0, sizeof(rawbuf));
2725         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2726         if (rc) {
2727                 fprintf(stderr, "error: %s: invalid ioctl\n",
2728                         jt_cmdname(argv[0]));
2729                 return rc;
2730         }
2731
2732         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_REMOVE, buf);
2733         if (rc == 0) {
2734                 if (argc == 2)
2735                         fprintf(stdout, "log %s is removed.\n", argv[1]);
2736                 else
2737                         fprintf(stdout, "the log in catalog %s is removed. \n",
2738                                 argv[1]);
2739         } else
2740                 fprintf(stderr, "OBD_IOC_LLOG_REMOVE failed: %s\n",
2741                         strerror(errno));
2742
2743         return rc;
2744 }
2745
2746 /* attach a regular file to virtual block device.
2747  * return vaule:
2748  *  -1: fatal error
2749  *  1: error, it always means the command run failed
2750  *  0: success
2751  */
2752 static int jt_blockdev_run_process(const char *file, char *argv[])
2753 {
2754         pid_t pid;
2755         int rc;
2756
2757         pid = vfork();
2758         if (pid == 0) { /* child process */
2759                 /* don't print error messages */
2760                 close(1), close(2);
2761                 (void)execvp(file, argv);
2762                 exit(-1);
2763         } else if (pid > 0) {
2764                 int status;
2765
2766                 rc = waitpid(pid, &status, 0);
2767                 if (rc < 0 || !WIFEXITED(status))
2768                         return -1;
2769
2770                 return WEXITSTATUS(status);
2771         }
2772
2773         return -1;
2774 }
2775
2776 static int jt_blockdev_find_module(const char *module)
2777 {
2778         FILE *fp;
2779         int found = 0;
2780         char buf[1024];
2781         char *ptr;
2782
2783         fp = fopen("/proc/modules", "r");
2784         if (fp == NULL)
2785                 return -1;
2786
2787         while (fgets(buf, 1024, fp) != NULL) {
2788                 ptr = strchr(buf, ' ');
2789                 if (ptr != NULL)
2790                         *ptr = 0;
2791                 if (strcmp(module, buf) == 0) {
2792                         found = 1;
2793                         break;
2794                 }
2795         }
2796         fclose(fp);
2797
2798         return found;
2799 }
2800
2801 static int jt_blockdev_probe_module(const char *module)
2802 {
2803         char buf[1024];
2804         char *argv[10];
2805         int c, rc;
2806
2807         if (jt_blockdev_find_module(module) == 1)
2808                 return 0;
2809
2810         /* run modprobe first */
2811         c = 0;
2812         argv[c++] = "/sbin/modprobe";
2813         argv[c++] = "-q";
2814         argv[c++] = (char *)module;
2815         argv[c++] = NULL;
2816         rc = jt_blockdev_run_process("modprobe", argv);
2817         if (rc != 1)
2818                 return rc;
2819
2820         /* cannot find the module in default directory ... */
2821         sprintf(buf, "../llite/%s.ko", module);
2822         c = 0;
2823         argv[c++] = "/sbin/insmod";
2824         argv[c++] = buf;
2825         argv[c++] = NULL;
2826         rc = jt_blockdev_run_process("insmod", argv);
2827         return rc ? -1 : 0;
2828 }
2829
2830 int jt_blockdev_attach(int argc, char **argv)
2831 {
2832         int rc, fd;
2833         struct stat st;
2834         char *filename, *devname;
2835         unsigned long dev;
2836
2837         if (argc != 3)
2838                 return CMD_HELP;
2839
2840         if (jt_blockdev_probe_module("llite_lloop") < 0) {
2841                 fprintf(stderr, "error: cannot find module llite_lloop.(k)o\n");
2842                 return ENOENT;
2843         }
2844
2845         filename = argv[1];
2846         devname = argv[2];
2847
2848         fd = open(filename, O_RDWR);
2849         if (fd < 0) {
2850                 fprintf(stderr, "file %s can't be opened(%s)\n\n",
2851                         filename, strerror(errno));
2852                 return CMD_HELP;
2853         }
2854
2855         rc = ioctl(fd, LL_IOC_LLOOP_ATTACH, &dev);
2856         if (rc < 0) {
2857                 rc = errno;
2858                 fprintf(stderr, "attach error(%s)\n", strerror(rc));
2859                 goto out;
2860         }
2861
2862         rc = stat(devname, &st);
2863         if (rc == 0 && (!S_ISBLK(st.st_mode) || st.st_rdev != dev)) {
2864                 rc = EEXIST;
2865         } else if (rc < 0) {
2866                 if (errno == ENOENT &&
2867                     !mknod(devname, S_IFBLK|S_IRUSR|S_IWUSR, dev))
2868                         rc = 0;
2869                 else
2870                         rc = errno;
2871         }
2872
2873         if (rc) {
2874                 fprintf(stderr, "error: the file %s could be attached to block "
2875                                 "device %X but creating %s failed: %s\n"
2876                                 "now detaching the block device..",
2877                         filename, (int)dev, devname, strerror(rc));
2878
2879                 (void)ioctl(fd, LL_IOC_LLOOP_DETACH_BYDEV, dev);
2880                 fprintf(stderr, "%s\n", strerror(errno));
2881         }
2882 out:
2883         close(fd);
2884         return -rc;
2885 }
2886
2887 int jt_blockdev_detach(int argc, char **argv)
2888 {
2889         char *filename;
2890         int rc, fd;
2891
2892         if (argc != 2)
2893                 return CMD_HELP;
2894
2895         filename = argv[1];
2896         fd = open(filename, O_RDONLY);
2897         if (fd < 0) {
2898                 fprintf(stderr, "cannot open file %s error %s\n",
2899                         filename, strerror(errno));
2900                 return CMD_HELP;
2901         }
2902
2903         rc = ioctl(fd, LL_IOC_LLOOP_DETACH, 0);
2904         if (rc < 0) {
2905                 rc = errno;
2906                 fprintf(stderr, "detach error(%s)\n", strerror(rc));
2907         } else {
2908                 (void)unlink(filename);
2909         }
2910
2911         close(fd);
2912         return -rc;
2913 }
2914
2915 int jt_blockdev_info(int argc, char **argv)
2916 {
2917         char *filename;
2918         int rc, fd;
2919         struct lu_fid fid;
2920
2921         if (argc != 2)
2922                 return CMD_HELP;
2923
2924         filename = argv[1];
2925         fd = open(filename, O_RDONLY);
2926         if (fd < 0) {
2927                 fprintf(stderr, "cannot open file %s error: %s\n",
2928                         filename, strerror(errno));
2929                 return CMD_HELP;
2930         }
2931
2932         rc = ioctl(fd, LL_IOC_LLOOP_INFO, &fid);
2933         if (rc < 0) {
2934                 rc = errno;
2935                 fprintf(stderr, "error: %s\n", strerror(errno));
2936                 goto out;
2937         }
2938         fprintf(stdout, "lloop device info: ");
2939         if (fid_is_zero(&fid))
2940                 fprintf(stdout, "Not attached\n");
2941         else
2942                 fprintf(stdout, "attached to inode "DFID"\n", PFID(&fid));
2943 out:
2944         close(fd);
2945         return -rc;
2946 }
2947
2948 static void signal_server(int sig)
2949 {
2950         if (sig == SIGINT) {
2951                 do_disconnect("sigint", 1);
2952                 exit(1);
2953         } else
2954                 fprintf(stderr, "%s: got signal %d\n", jt_cmdname("sigint"), sig);
2955 }
2956
2957 int obd_initialize(int argc, char **argv)
2958 {
2959         if (shmem_setup() != 0)
2960                 return -1;
2961
2962         register_ioc_dev(OBD_DEV_ID, OBD_DEV_PATH,
2963                          OBD_DEV_MAJOR, OBD_DEV_MINOR);
2964
2965         return 0;
2966 }
2967
2968 void obd_finalize(int argc, char **argv)
2969 {
2970         struct sigaction sigact;
2971
2972         /* sigact initialization */
2973         sigact.sa_handler = signal_server;
2974         sigfillset(&sigact.sa_mask);
2975         sigact.sa_flags = SA_RESTART;
2976         /* coverity[uninit_use_in_call] */
2977         sigaction(SIGINT, &sigact, NULL);
2978
2979         shmem_cleanup();
2980         do_disconnect(argv[0], 1);
2981 }
2982
2983 static int check_pool_cmd(enum lcfg_command_type cmd,
2984                           char *fsname, char *poolname,
2985                           char *ostname)
2986 {
2987         int rc;
2988
2989         rc = llapi_search_ost(fsname, poolname, ostname);
2990         if (rc < 0 && (cmd != LCFG_POOL_NEW)) {
2991                 fprintf(stderr, "Pool %s.%s not found\n",
2992                         fsname, poolname);
2993                 return rc;
2994         }
2995
2996         switch (cmd) {
2997         case LCFG_POOL_NEW: {
2998                 LASSERT(ostname == NULL);
2999                 if (rc >= 0) {
3000                         fprintf(stderr, "Pool %s.%s already exists\n",
3001                                 fsname, poolname);
3002                         return -EEXIST;
3003                 }
3004                 return 0;
3005         }
3006         case LCFG_POOL_DEL: {
3007                 LASSERT(ostname == NULL);
3008                 if (rc == 1) {
3009                         fprintf(stderr, "Pool %s.%s not empty, "
3010                                 "please remove all members\n",
3011                                 fsname, poolname);
3012                         return -ENOTEMPTY;
3013                 }
3014                 return 0;
3015         }
3016         case LCFG_POOL_ADD: {
3017                 if (rc == 1) {
3018                         fprintf(stderr, "OST %s is already in pool %s.%s\n",
3019                                 ostname, fsname, poolname);
3020                         return -EEXIST;
3021                 }
3022                 rc = llapi_search_ost(fsname, NULL, ostname);
3023                 if (rc == 0) {
3024                         fprintf(stderr, "OST %s is not part of the '%s' fs.\n",
3025                                 ostname, fsname);
3026                         return -ENOENT;
3027                 }
3028                 return 0;
3029         }
3030         case LCFG_POOL_REM: {
3031                 if (rc == 0) {
3032                         fprintf(stderr, "OST %s not found in pool %s.%s\n",
3033                                 ostname, fsname, poolname);
3034                         return -ENOENT;
3035                 }
3036                 return 0;
3037         }
3038         default:
3039                 break;
3040         } /* switch */
3041         return -EINVAL;
3042 }
3043
3044 /* This check only verifies that the changes have been "pushed out" to
3045    the client successfully.  This involves waiting for a config update,
3046    and so may fail because of problems in that code or post-command
3047    network loss. So reporting a warning is appropriate, but not a failure.
3048 */
3049 static int check_pool_cmd_result(enum lcfg_command_type cmd,
3050                                  char *fsname, char *poolname,
3051                                  char *ostname)
3052 {
3053         int cpt = 10;
3054         int rc = 0;
3055
3056         switch (cmd) {
3057         case LCFG_POOL_NEW: {
3058                 do {
3059                         rc = llapi_search_ost(fsname, poolname, NULL);
3060                         if (rc == -ENODEV)
3061                                 return rc;
3062                         if (rc < 0)
3063                                 sleep(2);
3064                         cpt--;
3065                 } while ((rc < 0) && (cpt > 0));
3066                 if (rc >= 0) {
3067                         fprintf(stderr, "Pool %s.%s created\n",
3068                                 fsname, poolname);
3069                         return 0;
3070                 } else {
3071                         fprintf(stderr, "Warning, pool %s.%s not found\n",
3072                                 fsname, poolname);
3073                         return -ENOENT;
3074                 }
3075         }
3076         case LCFG_POOL_DEL: {
3077                 do {
3078                         rc = llapi_search_ost(fsname, poolname, NULL);
3079                         if (rc == -ENODEV)
3080                                 return rc;
3081                         if (rc >= 0)
3082                                 sleep(2);
3083                         cpt--;
3084                 } while ((rc >= 0) && (cpt > 0));
3085                 if (rc < 0) {
3086                         fprintf(stderr, "Pool %s.%s destroyed\n",
3087                                 fsname, poolname);
3088                         return 0;
3089                 } else {
3090                         fprintf(stderr, "Warning, pool %s.%s still found\n",
3091                                 fsname, poolname);
3092                         return -EEXIST;
3093                 }
3094         }
3095         case LCFG_POOL_ADD: {
3096                 do {
3097                         rc = llapi_search_ost(fsname, poolname, ostname);
3098                         if (rc == -ENODEV)
3099                                 return rc;
3100                         if (rc != 1)
3101                                 sleep(2);
3102                         cpt--;
3103                 } while ((rc != 1) && (cpt > 0));
3104                 if (rc == 1) {
3105                         fprintf(stderr, "OST %s added to pool %s.%s\n",
3106                                 ostname, fsname, poolname);
3107                         return 0;
3108                 } else {
3109                         fprintf(stderr, "Warning, OST %s not found in pool %s.%s\n",
3110                                 ostname, fsname, poolname);
3111                         return -ENOENT;
3112                 }
3113         }
3114         case LCFG_POOL_REM: {
3115                 do {
3116                         rc = llapi_search_ost(fsname, poolname, ostname);
3117                         if (rc == -ENODEV)
3118                                 return rc;
3119                         if (rc == 1)
3120                                 sleep(2);
3121                         cpt--;
3122                 } while ((rc == 1) && (cpt > 0));
3123                 if (rc != 1) {
3124                         fprintf(stderr, "OST %s removed from pool %s.%s\n",
3125                                 ostname, fsname, poolname);
3126                         return 0;
3127                 } else {
3128                         fprintf(stderr, "Warning, OST %s still found in pool %s.%s\n",
3129                                 ostname, fsname, poolname);
3130                         return -EEXIST;
3131                 }
3132         }
3133         default:
3134                 break;
3135         }
3136         return -EINVAL;
3137 }
3138
3139 static int check_and_complete_ostname(char *fsname, char *ostname)
3140 {
3141         char *ptr;
3142         char real_ostname[MAX_OBD_NAME + 1];
3143         char i;
3144
3145         /* if OST name does not start with fsname, we add it */
3146         /* if not check if the fsname is the right one */
3147         ptr = strchr(ostname, '-');
3148         if (ptr == NULL) {
3149                 sprintf(real_ostname, "%s-%s", fsname, ostname);
3150         } else if (strncmp(ostname, fsname, strlen(fsname)) != 0) {
3151                 fprintf(stderr, "%s does not start with fsname %s\n",
3152                         ostname, fsname);
3153                 return -EINVAL;
3154         } else {
3155                 if (strlen(ostname) > sizeof(real_ostname)-1)
3156                         return -E2BIG;
3157                 strncpy(real_ostname, ostname, sizeof(real_ostname));
3158         }
3159         /* real_ostname is fsname-????? */
3160         ptr = real_ostname + strlen(fsname) + 1;
3161         if (strncmp(ptr, "OST", 3) != 0) {
3162                 fprintf(stderr, "%s does not start by %s-OST nor OST\n",
3163                         ostname, fsname);
3164                 return -EINVAL;
3165         }
3166         /* real_ostname is fsname-OST????? */
3167         ptr += 3;
3168         for (i = 0; i < 4; i++) {
3169                 if (!isxdigit(*ptr)) {
3170                         fprintf(stderr,
3171                                 "ost's index in %s is not an hexa number\n",
3172                                 ostname);
3173                         return -EINVAL;
3174                 }
3175                 ptr++;
3176         }
3177         /* real_ostname is fsname-OSTXXXX????? */
3178         /* if OST name does not end with _UUID, we add it */
3179         if (*ptr == '\0') {
3180                 strcat(real_ostname, "_UUID");
3181         } else if (strcmp(ptr, "_UUID") != 0) {
3182                 fprintf(stderr,
3183                         "ostname %s does not end with _UUID\n", ostname);
3184                 return -EINVAL;
3185         }
3186         /* real_ostname is fsname-OSTXXXX_UUID */
3187         strcpy(ostname, real_ostname);
3188         return 0;
3189 }
3190
3191 /* returns 0 or -errno */
3192 static int pool_cmd(enum lcfg_command_type cmd,
3193                     char *cmdname, char *fullpoolname,
3194                     char *fsname, char *poolname, char *ostname)
3195 {
3196         int rc = 0;
3197         struct obd_ioctl_data data;
3198         struct lustre_cfg_bufs bufs;
3199         struct lustre_cfg *lcfg;
3200         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
3201
3202         rc = check_pool_cmd(cmd, fsname, poolname, ostname);
3203         if (rc == -ENODEV)
3204                 fprintf(stderr, "Can't verify pool command since there "
3205                         "is no local MDT or client, proceeding anyhow...\n");
3206         else if (rc)
3207                 return rc;
3208
3209         lustre_cfg_bufs_reset(&bufs, NULL);
3210         lustre_cfg_bufs_set_string(&bufs, 0, cmdname);
3211         lustre_cfg_bufs_set_string(&bufs, 1, fullpoolname);
3212         if (ostname != NULL)
3213                 lustre_cfg_bufs_set_string(&bufs, 2, ostname);
3214
3215         lcfg = lustre_cfg_new(cmd, &bufs);
3216         if (lcfg == NULL)
3217                 return -ENOMEM;
3218
3219         memset(&data, 0, sizeof(data));
3220         rc = data.ioc_dev = get_mgs_device();
3221         if (rc < 0)
3222                 goto out;
3223
3224         data.ioc_type = LUSTRE_CFG_TYPE;
3225         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
3226                                         lcfg->lcfg_buflens);
3227         data.ioc_pbuf1 = (void *)lcfg;
3228
3229         memset(buf, 0, sizeof(rawbuf));
3230         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
3231         if (rc) {
3232                 fprintf(stderr, "error: %s: invalid ioctl\n",
3233                         jt_cmdname(cmdname));
3234                 lustre_cfg_free(lcfg);
3235                 return rc;
3236         }
3237         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_POOL, buf);
3238 out:
3239         if (rc)
3240                 rc = -errno;
3241         lustre_cfg_free(lcfg);
3242         return rc;
3243 }
3244
3245 /**
3246  * Format and send the ioctl to the MGS.
3247  *
3248  * \param       cmd             IOCTL to send
3249  * \param       ret_data        void pointer to return anything from
3250  *                              ioctl
3251  * \param       num_args        number of arguments to pack into the
3252  *                              ioctl buffer
3253  * \param       argv[]          variable number of string arguments
3254  *
3255  * \retval                      0 on success
3256  */
3257 static int nodemap_cmd(enum lcfg_command_type cmd, void *ret_data,
3258                        unsigned int ret_size, ...)
3259 {
3260         va_list                 ap;
3261         char                    *arg;
3262         int                     i = 0;
3263         struct lustre_cfg_bufs  bufs;
3264         struct obd_ioctl_data   data;
3265         struct lustre_cfg       *lcfg;
3266         char                    rawbuf[MAX_IOC_BUFLEN];
3267         char                    *buf = rawbuf;
3268         int                     rc = 0;
3269
3270         lustre_cfg_bufs_reset(&bufs, NULL);
3271
3272         va_start(ap, ret_size);
3273         arg = va_arg(ap, char *);
3274         while (arg != NULL) {
3275                 lustre_cfg_bufs_set_string(&bufs, i, arg);
3276                 i++;
3277                 arg = va_arg(ap, char *);
3278         }
3279         va_end(ap);
3280
3281         lcfg = lustre_cfg_new(cmd, &bufs);
3282         if (lcfg == NULL)
3283                 return -ENOMEM;
3284
3285         memset(&data, 0, sizeof(data));
3286         rc = data.ioc_dev = get_mgs_device();
3287         if (rc < 0)
3288                 goto out;
3289
3290         data.ioc_type = LUSTRE_CFG_TYPE;
3291         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
3292                          lcfg->lcfg_buflens);
3293         data.ioc_pbuf1 = (void *)lcfg;
3294
3295         memset(buf, 0, sizeof(rawbuf));
3296         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
3297         if (rc != 0) {
3298                 fprintf(stderr, "error: invalid ioctl: %08x errno: %d with "
3299                                "rc=%d\n", cmd, errno, rc);
3300                 goto out;
3301         }
3302
3303         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_NODEMAP, buf);
3304         if (rc != 0) {
3305                 fprintf(stderr, "error: invalid ioctl: %08x errno: %d with "
3306                                "rc=%d\n", cmd, errno, rc);
3307                 goto out;
3308         }
3309
3310         if (ret_data != NULL) {
3311                 rc = obd_ioctl_unpack(&data, buf, sizeof(rawbuf));
3312                 if (rc != 0)
3313                         goto out;
3314
3315                 if (ret_size > data.ioc_plen1)
3316                         ret_size = data.ioc_plen1;
3317
3318                 memcpy(ret_data, data.ioc_pbuf1, ret_size);
3319         }
3320 out:
3321         lustre_cfg_free(lcfg);
3322
3323         return rc;
3324 }
3325
3326 /**
3327  * activate nodemap functions
3328  *
3329  * \param       argc            number of args
3330  * \param       argv[]          variable string arguments
3331  *
3332  * argv[0]                      1 for activate or 0 for deactivate
3333  *
3334  * \retval                      0 on success
3335  */
3336 int jt_nodemap_activate(int argc, char **argv)
3337 {
3338         int rc;
3339
3340         rc = nodemap_cmd(LCFG_NODEMAP_ACTIVATE, NULL, 0, argv[0], argv[1],
3341                          NULL);
3342
3343         if (rc != 0) {
3344                 errno = -rc;
3345                 perror(argv[0]);
3346         }
3347
3348         return rc;
3349 }
3350
3351 /**
3352  * add a nodemap
3353  *
3354  * \param       argc            number of args
3355  * \param       argv[]          variable string arguments
3356  *
3357  * argv[0]                      nodemap name
3358  *
3359  * \retval                      0 on success
3360  */
3361 int jt_nodemap_add(int argc, char **argv)
3362 {
3363         int rc;
3364
3365         rc = llapi_nodemap_exists(argv[1]);
3366         if (rc == 0) {
3367                 fprintf(stderr, "error: %s existing nodemap name\n", argv[1]);
3368                 return 1;
3369         }
3370
3371         rc = nodemap_cmd(LCFG_NODEMAP_ADD, NULL, 0, argv[0], argv[1], NULL);
3372
3373         if (rc != 0) {
3374                 errno = -rc;
3375                 perror(argv[0]);
3376         }
3377
3378         return rc;
3379 }
3380
3381 /**
3382  * delete a nodemap
3383  *
3384  * \param       argc            number of args
3385  * \param       argv[]          variable string arguments
3386  *
3387  * argv[0]                      nodemap name
3388  *
3389  * \retval                      0 on success
3390  */
3391 int jt_nodemap_del(int argc, char **argv)
3392 {
3393         int rc;
3394
3395         rc = llapi_nodemap_exists(argv[1]);
3396         if (rc != 0) {
3397                 fprintf(stderr, "error: %s not existing nodemap name\n",
3398                         argv[1]);
3399                 return rc;
3400         }
3401         rc = nodemap_cmd(LCFG_NODEMAP_DEL, NULL, 0, argv[0], argv[1], NULL);
3402
3403         if (rc != 0) {
3404                 errno = -rc;
3405                 perror(argv[0]);
3406         }
3407
3408         return rc;
3409 }
3410
3411 /**
3412  * test a nid for nodemap membership
3413  *
3414  * \param       argc            number of args
3415  * \param       argv[]          variable string arguments
3416  *
3417  * argv[0]                      properly formatted nid
3418  *
3419  * \retval                      0 on success
3420  */
3421 int jt_nodemap_test_nid(int argc, char **argv)
3422 {
3423
3424         char    rawbuf[MAX_IOC_BUFLEN];
3425         int     rc;
3426
3427         rc = nodemap_cmd(LCFG_NODEMAP_TEST_NID, &rawbuf, sizeof(rawbuf),
3428                          argv[0], argv[1], NULL);
3429         if (rc == 0)
3430                 printf("%s\n", (char *)rawbuf);
3431
3432         return rc;
3433 }
3434
3435 /**
3436  * test a nodemap id pair for mapping
3437  *
3438  * \param       argc            number of args
3439  * \param       argv[[]         variable string arguments
3440  *
3441  * \retval                      0 on success
3442  *
3443  * The argv array should contain the nodemap name, the id
3444  * to checking the mapping on, and the id type (UID or GID)
3445  *
3446  */
3447 int jt_nodemap_test_id(int argc, char **argv)
3448 {
3449         char    rawbuf[MAX_IOC_BUFLEN];
3450         char    *nidstr = NULL;
3451         char    *idstr = NULL;
3452         char    *typestr = NULL;
3453         int     rc = 0;
3454         int     c;
3455
3456         static struct option long_options[] = {
3457                 {
3458                         .name           = "nid",
3459                         .has_arg        = required_argument,
3460                         .flag           = 0,
3461                         .val            = 'n',
3462                 },
3463                 {
3464                         .name           = "idtype",
3465                         .has_arg        = required_argument,
3466                         .flag           = 0,
3467                         .val            = 't',
3468                 },
3469                 {
3470                         .name           = "id",
3471                         .has_arg        = required_argument,
3472                         .flag           = 0,
3473                         .val            = 'i',
3474                 },
3475                 {
3476                         NULL
3477                 }
3478         };
3479
3480         while ((c = getopt_long(argc, argv, "n:t:i:",
3481                                 long_options, NULL)) != -1) {
3482                 switch (c) {
3483                 case 'n':
3484                         nidstr = optarg;
3485                         break;
3486                 case 't':
3487                         typestr = optarg;
3488                         break;
3489                 case 'i':
3490                         idstr = optarg;
3491                         break;
3492                 }
3493         }
3494
3495         if (nidstr == NULL || typestr == NULL || idstr == NULL) {
3496                 fprintf(stderr, "usage: nodemap_test_id --nid <nid> "
3497                                 "--idtype [uid|gid] --id <id>\n");
3498                 return -1;
3499         }
3500
3501         rc = nodemap_cmd(LCFG_NODEMAP_TEST_ID, &rawbuf, sizeof(rawbuf),
3502                          argv[0], nidstr, typestr, idstr);
3503         if (rc == 0)
3504                 printf("%s\n", (char *)rawbuf);
3505
3506         return rc;
3507 }
3508
3509 /**
3510  * add an nid range to a nodemap
3511  *
3512  * \param       argc            number of args
3513  * \param       argv[]          variable string arguments
3514  *
3515  * --name                       nodemap name
3516  * --range                      properly formatted nid range
3517  *
3518  * \retval                      0 on success
3519  */
3520 int jt_nodemap_add_range(int argc, char **argv)
3521 {
3522         char                    *nodemap_name = NULL;
3523         char                    *nodemap_range = NULL;
3524         struct list_head        nidlist;
3525         char                    min_nid[LNET_NIDSTR_SIZE + 1];
3526         char                    max_nid[LNET_NIDSTR_SIZE + 1];
3527         char                    nid_range[2 * LNET_NIDSTR_SIZE + 2];
3528         int                     rc = 0;
3529         int                     c;
3530
3531         static struct option long_options[] = {
3532                 {
3533                         .name           = "name",
3534                         .has_arg        = required_argument,
3535                         .flag           = 0,
3536                         .val            = 'n',
3537                 },
3538                 {
3539                         .name           = "range",
3540                         .has_arg        = required_argument,
3541                         .flag           = 0,
3542                         .val            = 'r',
3543                 },
3544                 {
3545                         NULL
3546                 }
3547         };
3548
3549         INIT_LIST_HEAD(&nidlist);
3550
3551         while ((c = getopt_long(argc, argv, "n:r:",
3552                                 long_options, NULL)) != -1) {
3553                 switch (c) {
3554                 case 'n':
3555                         nodemap_name = optarg;
3556                         break;
3557                 case 'r':
3558                         nodemap_range = optarg;
3559                         break;
3560                 }
3561         }
3562
3563         if (nodemap_name == NULL || nodemap_range == NULL) {
3564                 fprintf(stderr, "usage: nodemap_add_range --name <name> "
3565                                 "--range <range>\n");
3566                 return -1;
3567         }
3568
3569         if (cfs_parse_nidlist(nodemap_range, strlen(nodemap_range),
3570                               &nidlist) <= 0) {
3571                 fprintf(stderr, "error: %s: can't parse nid range: %s\n",
3572                         jt_cmdname(argv[0]), nodemap_range);
3573                 return -1;
3574         }
3575
3576         if (!cfs_nidrange_is_contiguous(&nidlist)) {
3577                 fprintf(stderr, "error: %s: nodemap ranges must be "
3578                         "contiguous\n", jt_cmdname(argv[0]));
3579                 return -1;
3580         }
3581
3582         cfs_nidrange_find_min_max(&nidlist, &min_nid[0], &max_nid[0],
3583                                   LNET_NIDSTR_SIZE);
3584         snprintf(nid_range, sizeof(nid_range), "%s:%s", min_nid, max_nid);
3585
3586         rc = nodemap_cmd(LCFG_NODEMAP_ADD_RANGE, NULL, 0, argv[0],
3587                          nodemap_name, nid_range, NULL);
3588         if (rc != 0) {
3589                 errno = -rc;
3590                 fprintf(stderr, "error: %s: cannot add range '%s' to nodemap "
3591                                 "'%s': rc = %d\n",
3592                         jt_cmdname(argv[0]), nodemap_range, nodemap_name, rc);
3593         }
3594
3595         return rc;
3596 }
3597
3598 /**
3599  * delete an nid range to a nodemap
3600  *
3601  * \param       argc            number of args
3602  * \param       argv[]          variable string arguments
3603  *
3604  * --name                       nodemap name
3605  * --range                      properly formatted nid range
3606  *
3607  * \retval                      0 on success
3608  */
3609 int jt_nodemap_del_range(int argc, char **argv)
3610 {
3611         char                    *nodemap_name = NULL;
3612         char                    *nodemap_range = NULL;
3613         struct list_head        nidlist;
3614         char                    min_nid[LNET_NIDSTR_SIZE + 1];
3615         char                    max_nid[LNET_NIDSTR_SIZE + 1];
3616         char                    nid_range[2 * LNET_NIDSTR_SIZE + 2];
3617         int                     rc = 0;
3618         int                     c;
3619
3620         static struct option long_options[] = {
3621                 {
3622                         .name           = "name",
3623                         .has_arg        = required_argument,
3624                         .flag           = 0,
3625                         .val            = 'n',
3626                 },
3627                 {
3628                         .name           = "range",
3629                         .has_arg        = required_argument,
3630                         .flag           = 0,
3631                         .val            = 'r',
3632                 },
3633                 {
3634                         NULL
3635                 }
3636         };
3637
3638         INIT_LIST_HEAD(&nidlist);
3639
3640         while ((c = getopt_long(argc, argv, "n:r:",
3641                                 long_options, NULL)) != -1) {
3642                 switch (c) {
3643                 case 'n':
3644                         nodemap_name = optarg;
3645                         break;
3646                 case 'r':
3647                         nodemap_range = optarg;
3648                         break;
3649                 }
3650         }
3651
3652         if (nodemap_name == NULL || nodemap_range == NULL) {
3653                 fprintf(stderr, "usage: nodemap_del_range --name <name> "
3654                                 "--range <range>\n");
3655                 return -1;
3656         }
3657
3658         if (cfs_parse_nidlist(nodemap_range, strlen(nodemap_range),
3659                               &nidlist) <= 0) {
3660                 fprintf(stderr, "error: %s: can't parse nid range: %s\n",
3661                         jt_cmdname(argv[0]), nodemap_range);
3662                 return -1;
3663         }
3664
3665         if (!cfs_nidrange_is_contiguous(&nidlist)) {
3666                 fprintf(stderr, "error: %s: nodemap ranges must be "
3667                         "contiguous\n", jt_cmdname(argv[0]));
3668                 return -1;
3669         }
3670
3671         cfs_nidrange_find_min_max(&nidlist, &min_nid[0], &max_nid[0],
3672                                   LNET_NIDSTR_SIZE);
3673         snprintf(nid_range, sizeof(nid_range), "%s:%s", min_nid, max_nid);
3674
3675         rc = nodemap_cmd(LCFG_NODEMAP_DEL_RANGE, NULL, 0, argv[0],
3676                          nodemap_name, nid_range, NULL);
3677         if (rc != 0) {
3678                 errno = -rc;
3679                 fprintf(stderr, "error: %s: cannot delete range '%s' to "
3680                                "nodemap '%s': rc = %d\n",
3681                         jt_cmdname(argv[0]), nodemap_range, nodemap_name, rc);
3682         }
3683
3684         return rc;
3685 }
3686
3687 /**
3688  * modify a nodemap's behavior
3689  *
3690  * \param       argc            number of args
3691  * \param       argv[]          variable string arguments
3692  *
3693  * --name                       nodemap name
3694  * --property                   nodemap property to change
3695  *                              admin, trusted, squash_uid, squash_gid)
3696  * --value                      value to set property
3697  *
3698  * \retval                      0 on success
3699  */
3700 int jt_nodemap_modify(int argc, char **argv)
3701 {
3702         int                     c;
3703         int                     rc = 0;
3704         enum lcfg_command_type  cmd = 0;
3705         char                    *nodemap_name = NULL;
3706         char                    *param = NULL;
3707         char                    *value = NULL;
3708
3709         static struct option long_options[] = {
3710                 {
3711                         .name           = "name",
3712                         .has_arg        = required_argument,
3713                         .flag           = 0,
3714                         .val            = 'n',
3715                 },
3716                 {
3717                         .name           = "property",
3718                         .has_arg        = required_argument,
3719                         .flag           = 0,
3720                         .val            = 'p',
3721                 },
3722                 {
3723                         .name           = "value",
3724                         .has_arg        = required_argument,
3725                         .flag           = 0,
3726                         .val            = 'v',
3727                 },
3728                 {
3729                         NULL
3730                 }
3731         };
3732
3733         while ((c = getopt_long(argc, argv, "n:p:v:",
3734                                 long_options, NULL)) != -1) {
3735                 switch (c) {
3736                 case 'n':
3737                         nodemap_name = optarg;
3738                         break;
3739                 case 'p':
3740                         param = optarg;
3741                         break;
3742                 case 'v':
3743                         value = optarg;
3744                         break;
3745                 }
3746         }
3747
3748         if (nodemap_name == NULL || param == NULL || value == NULL) {
3749                 fprintf(stderr, "usage: nodemap_modify --name <nodemap_name> "
3750                                 "--property <property_name> --value <value>\n");
3751                 fprintf(stderr, "valid properties: admin trusted "
3752                                 "squash_uid squash_gid\n");
3753                 return -1;
3754         }
3755
3756         if (strcmp("admin", param) == 0) {
3757                 cmd = LCFG_NODEMAP_ADMIN;
3758         } else if (strcmp("trusted", param) == 0) {
3759                 cmd = LCFG_NODEMAP_TRUSTED;
3760         } else if (strcmp("squash_uid", param) == 0) {
3761                 cmd = LCFG_NODEMAP_SQUASH_UID;
3762         } else if (strcmp("squash_gid", param) == 0) {
3763                 cmd = LCFG_NODEMAP_SQUASH_GID;
3764         } else {
3765                 fprintf(stderr, "error: %s: nodemap_modify invalid "
3766                                 "subcommand: %s\n",
3767                         jt_cmdname(argv[0]), param);
3768                 return -1;
3769         }
3770
3771         rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, param,
3772                          value, NULL);
3773         if (rc != 0) {
3774                 errno = -rc;
3775                 fprintf(stderr, "error: %s: cannot modify nodemap '%s' "
3776                                "to param '%s': value '%s': rc = %d\n",
3777                         jt_cmdname(argv[0]), nodemap_name, param, value, rc);
3778         }
3779
3780         return rc;
3781 }
3782
3783 int jt_nodemap_add_idmap(int argc, char **argv)
3784 {
3785         int                     c;
3786         enum                    lcfg_command_type cmd = 0;
3787         char                    *nodemap_name = NULL;
3788         char                    *idmap = NULL;
3789         char                    *idtype = NULL;
3790         int                     rc = 0;
3791
3792         static struct option long_options[] = {
3793                 {
3794                         .name           = "name",
3795                         .has_arg        = required_argument,
3796                         .flag           = 0,
3797                         .val            = 'n',
3798                 },
3799                 {
3800                         .name           = "idmap",
3801                         .has_arg        = required_argument,
3802                         .flag           = 0,
3803                         .val            = 'm',
3804                 },
3805                 {
3806                         .name           = "idtype",
3807                         .has_arg        = required_argument,
3808                         .flag           = 0,
3809                         .val            = 'i',
3810                 },
3811                 {
3812                         NULL
3813                 }
3814         };
3815
3816         while ((c = getopt_long(argc, argv, "n:m:i:",
3817                                 long_options, NULL)) != -1) {
3818                 switch (c) {
3819                 case 'n':
3820                         nodemap_name = optarg;
3821                         break;
3822                 case 'm':
3823                         idmap = optarg;
3824                         break;
3825                 case 'i':
3826                         idtype = optarg;
3827                         break;
3828                 }
3829         }
3830
3831         if (nodemap_name == NULL || idmap == NULL || idtype == NULL) {
3832                 fprintf(stderr, "usage: %s --name <name> --idtype [uid | gid]"
3833                         " --idmap <client id>:<filesystem id>\n", argv[0]);
3834                 return -1;
3835         }
3836
3837         if (strcmp("uid", idtype) == 0) {
3838                 cmd = LCFG_NODEMAP_ADD_UIDMAP;
3839         } else if (strcmp("gid", idtype) == 0) {
3840                 cmd = LCFG_NODEMAP_ADD_GIDMAP;
3841         } else {
3842                 fprintf(stderr, "usage: %s --name <name> --idtype [uid | gid]"
3843                         " --idmap <client id>:<filesystem id>\n", argv[0]);
3844                 return -1;
3845         }
3846
3847         rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, idmap, NULL);
3848         if (rc != 0) {
3849                 errno = -rc;
3850                 fprintf(stderr, "cannot add %smap '%s' to nodemap '%s'"
3851                         ": rc = %d\n", idtype, idmap, nodemap_name, rc);
3852         }
3853
3854         return rc;
3855 }
3856
3857 int jt_nodemap_del_idmap(int argc, char **argv)
3858 {
3859         int                     c;
3860         enum                    lcfg_command_type cmd = 0;
3861         char                    *nodemap_name = NULL;
3862         char                    *idmap = NULL;
3863         char                    *idtype = NULL;
3864         int                     rc = 0;
3865
3866         static struct option long_options[] = {
3867                 {
3868                         .name           = "name",
3869                         .has_arg        = required_argument,
3870                         .flag           = 0,
3871                         .val            = 'n',
3872                 },
3873                 {
3874                         .name           = "idmap",
3875                         .has_arg        = required_argument,
3876                         .flag           = 0,
3877                         .val            = 'm',
3878                 },
3879                 {
3880                         .name           = "idtype",
3881                         .has_arg        = required_argument,
3882                         .flag           = 0,
3883                         .val            = 'i',
3884                 },
3885                 {
3886                         NULL
3887                 }
3888         };
3889
3890         while ((c = getopt_long(argc, argv, "n:m:i:",
3891                                 long_options, NULL)) != -1) {
3892                 switch (c) {
3893                 case 'n':
3894                         nodemap_name = optarg;
3895                         break;
3896                 case 'm':
3897                         idmap = optarg;
3898                         break;
3899                 case 'i':
3900                         idtype = optarg;
3901                         break;
3902                 }
3903         }
3904
3905         if (nodemap_name == NULL || idmap == NULL || idtype == NULL) {
3906                 fprintf(stderr, "usage: %s --name <name> --idtype [uid | gid]"
3907                         " --idmap <client id>:<filesystem id>\n", argv[0]);
3908                 return -1;
3909         }
3910
3911         if (strcmp("uid", idtype) == 0)
3912                 cmd = LCFG_NODEMAP_DEL_UIDMAP;
3913         else
3914                 cmd = LCFG_NODEMAP_DEL_GIDMAP;
3915
3916         rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, idmap, NULL);
3917         if (rc != 0) {
3918                 errno = -rc;
3919                 fprintf(stderr, "cannot delete %smap '%s' from nodemap '%s'"
3920                         ": rc = %d\n", idtype, idmap, nodemap_name, rc);
3921         }
3922
3923         return rc;
3924 }
3925
3926 /*
3927  * this function tranforms a rule [start-end/step] into an array
3928  * of matching numbers
3929  * supported forms are:
3930  * [start]                : just this number
3931  * [start-end]            : all numbers from start to end
3932  * [start-end/step]       : numbers from start to end with increment of step
3933  * on return, format contains a printf format string which can be used
3934  * to generate all the strings
3935  */
3936 static int get_array_idx(char *rule, char *format, int **array)
3937 {
3938         char *start, *end, *ptr;
3939         unsigned int lo, hi, step;
3940         int array_sz = 0;
3941         int i, array_idx;
3942         int rc;
3943
3944         start = strchr(rule, '[');
3945         end = strchr(rule, ']');
3946         if ((start == NULL) || (end == NULL)) {
3947                 *array = malloc(sizeof(int));
3948                 if (*array == NULL)
3949                         return 0;
3950                 strcpy(format, rule);
3951                 array_sz = 1;
3952                 return array_sz;
3953         }
3954         *start = '\0';
3955         *end = '\0';
3956         end++;
3957         start++;
3958         /* put in format the printf format (the rule without the range) */
3959         sprintf(format, "%s%%.4x%s", rule, end);
3960
3961         array_idx = 0;
3962         array_sz = 0;
3963         *array = NULL;
3964         /* loop on , separator */
3965         do {
3966                 /* extract the 3 fields */
3967                 rc = sscanf(start, "%x-%x/%u", &lo, &hi, &step);
3968                 switch (rc) {
3969                 case 0: {
3970                         return 0;
3971                 }
3972                 case 1: {
3973                         array_sz++;
3974                         *array = realloc(*array, array_sz * sizeof(int));
3975                         if (*array == NULL)
3976                                 return 0;
3977                         (*array)[array_idx] = lo;
3978                         array_idx++;
3979                         break;
3980                 }
3981                 case 2: {
3982                         step = 1;
3983                         /* do not break to share code with case 3: */
3984                 }
3985                 case 3: {
3986                         if ((hi < lo) || (step == 0))
3987                                 return 0;
3988                         array_sz += (hi - lo) / step + 1;
3989                         *array = realloc(*array, sizeof(int) * array_sz);
3990                         if (*array == NULL)
3991                                 return 0;
3992                         for (i = lo; i <= hi; i+=step, array_idx++)
3993                                 (*array)[array_idx] = i;
3994                         break;
3995                 }
3996                 }
3997                 ptr = strchr(start, ',');
3998                 if (ptr != NULL)
3999                         start = ptr + 1;
4000
4001         } while (ptr != NULL);
4002         return array_sz;
4003 }
4004
4005 static int extract_fsname_poolname(char *arg, char *fsname, char *poolname)
4006 {
4007         char *ptr;
4008         int len;
4009         int rc;
4010
4011         strcpy(fsname, arg);
4012         ptr = strchr(fsname, '.');
4013         if (ptr == NULL) {
4014                 fprintf(stderr, ". is missing in %s\n", fsname);
4015                 rc = -EINVAL;
4016                 goto err;
4017         }
4018
4019         len = ptr - fsname;
4020         if (len == 0) {
4021                 fprintf(stderr, "fsname is empty\n");
4022                 rc = -EINVAL;
4023                 goto err;
4024         }
4025
4026         len = strlen(ptr + 1);
4027         if (len == 0) {
4028                 fprintf(stderr, "poolname is empty\n");
4029                 rc = -EINVAL;
4030                 goto err;
4031         }
4032         if (len > LOV_MAXPOOLNAME) {
4033                 fprintf(stderr,
4034                         "poolname %s is too long (length is %d max is %d)\n",
4035                         ptr + 1, len, LOV_MAXPOOLNAME);
4036                 rc = -ENAMETOOLONG;
4037                 goto err;
4038         }
4039         strncpy(poolname, ptr + 1, LOV_MAXPOOLNAME);
4040         poolname[LOV_MAXPOOLNAME] = '\0';
4041         *ptr = '\0';
4042         return 0;
4043
4044 err:
4045         fprintf(stderr, "argument %s must be <fsname>.<poolname>\n", arg);
4046         return rc;
4047 }
4048
4049 int jt_pool_cmd(int argc, char **argv)
4050 {
4051         enum lcfg_command_type cmd;
4052         char fsname[PATH_MAX + 1];
4053         char poolname[LOV_MAXPOOLNAME + 1];
4054         char *ostnames_buf = NULL;
4055         int i, rc;
4056         int *array = NULL, array_sz;
4057         struct {
4058                 int     rc;
4059                 char   *ostname;
4060         } *cmds = NULL;
4061
4062         switch (argc) {
4063         case 0:
4064         case 1: return CMD_HELP;
4065         case 2: {
4066                 if (strcmp("pool_new", argv[0]) == 0)
4067                         cmd = LCFG_POOL_NEW;
4068                 else if (strcmp("pool_destroy", argv[0]) == 0)
4069                         cmd = LCFG_POOL_DEL;
4070                 else if (strcmp("pool_list", argv[0]) == 0)
4071                          return llapi_poollist(argv[1]);
4072                 else return CMD_HELP;
4073
4074                 rc = extract_fsname_poolname(argv[1], fsname, poolname);
4075                 if (rc)
4076                         break;
4077
4078                 rc = pool_cmd(cmd, argv[0], argv[1], fsname, poolname, NULL);
4079                 if (rc)
4080                         break;
4081
4082                 check_pool_cmd_result(cmd, fsname, poolname, NULL);
4083                 break;
4084         }
4085         default: {
4086                 char format[2*MAX_OBD_NAME];
4087
4088                 if (strcmp("pool_remove", argv[0]) == 0) {
4089                         cmd = LCFG_POOL_REM;
4090                 } else if (strcmp("pool_add", argv[0]) == 0) {
4091                         cmd = LCFG_POOL_ADD;
4092                 } else {
4093                         return CMD_HELP;
4094                 }
4095
4096                 rc = extract_fsname_poolname(argv[1], fsname, poolname);
4097                 if (rc)
4098                         break;
4099
4100                 for (i = 2; i < argc; i++) {
4101                         int j;
4102
4103                         array_sz = get_array_idx(argv[i], format, &array);
4104                         if (array_sz == 0)
4105                                 return CMD_HELP;
4106
4107                         cmds = malloc(array_sz * sizeof(cmds[0]));
4108                         if (cmds != NULL) {
4109                                 ostnames_buf = malloc(array_sz *
4110                                                       (MAX_OBD_NAME + 1));
4111                         } else {
4112                                 free(array);
4113                                 rc = -ENOMEM;
4114                                 goto out;
4115                         }
4116
4117                         for (j = 0; j < array_sz; j++) {
4118                                 char ostname[MAX_OBD_NAME + 1];
4119
4120                                 snprintf(ostname, MAX_OBD_NAME, format,
4121                                          array[j]);
4122                                 ostname[MAX_OBD_NAME] = '\0';
4123
4124                                 rc = check_and_complete_ostname(fsname,ostname);
4125                                 if (rc) {
4126                                         free(array);
4127                                         free(cmds);
4128                                         if (ostnames_buf)
4129                                                 free(ostnames_buf);
4130                                         goto out;
4131                                 }
4132                                 if (ostnames_buf != NULL) {
4133                                         cmds[j].ostname =
4134                                           &ostnames_buf[(MAX_OBD_NAME + 1) * j];
4135                                         strcpy(cmds[j].ostname, ostname);
4136                                 } else {
4137                                         cmds[j].ostname = NULL;
4138                                 }
4139                                 cmds[j].rc = pool_cmd(cmd, argv[0], argv[1],
4140                                                       fsname, poolname,
4141                                                       ostname);
4142                                 /* Return an err if any of the add/dels fail */
4143                                 if (!rc)
4144                                         rc = cmds[j].rc;
4145                         }
4146                         for (j = 0; j < array_sz; j++) {
4147                                 if (!cmds[j].rc) {
4148                                         char ostname[MAX_OBD_NAME + 1];
4149
4150                                         if (!cmds[j].ostname) {
4151                                                 snprintf(ostname, MAX_OBD_NAME,
4152                                                          format, array[j]);
4153                                                 ostname[MAX_OBD_NAME] = '\0';
4154                                                 check_and_complete_ostname(
4155                                                         fsname, ostname);
4156                                         } else {
4157                                                 strcpy(ostname,
4158                                                        cmds[j].ostname);
4159                                         }
4160                                         check_pool_cmd_result(cmd, fsname,
4161                                                               poolname,ostname);
4162                                 }
4163                         }
4164                         if (array_sz > 0)
4165                                 free(array);
4166                         if (cmds)
4167                                 free(cmds);
4168                         if (ostnames_buf != NULL)
4169                                 free(ostnames_buf);
4170                 }
4171                 /* fall through */
4172         }
4173         } /* switch */
4174
4175 out:
4176         if (rc != 0) {
4177                 errno = -rc;
4178                 perror(argv[0]);
4179         }
4180
4181         return rc;
4182 }
4183
4184 int jt_get_obj_version(int argc, char **argv)
4185 {
4186         struct lu_fid fid;
4187         struct obd_ioctl_data data;
4188         __u64 version, id = ULLONG_MAX, group = ULLONG_MAX;
4189         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf, *fidstr;
4190         int rc, c;
4191
4192         while ((c = getopt(argc, argv, "i:g:")) != -1) {
4193                 switch (c) {
4194                 case 'i':
4195                         id = strtoull(optarg, NULL, 0);
4196                         break;
4197                 case 'g':
4198                         group = strtoull(optarg, NULL, 0);
4199                         break;
4200                 default:
4201                         return CMD_HELP;
4202                 }
4203         }
4204
4205         argc -= optind;
4206         argv += optind;
4207
4208         if (!(id != ULLONG_MAX && group != ULLONG_MAX && argc == 0) &&
4209             !(id == ULLONG_MAX && group == ULLONG_MAX && argc == 1))
4210                 return CMD_HELP;
4211
4212         memset(&data, 0, sizeof data);
4213         data.ioc_dev = cur_device;
4214         if (argc == 1) {
4215                 fidstr = *argv;
4216                 while (*fidstr == '[')
4217                         fidstr++;
4218                 sscanf(fidstr, SFID, RFID(&fid));
4219
4220                 data.ioc_inlbuf1 = (char *) &fid;
4221                 data.ioc_inllen1 = sizeof fid;
4222         } else {
4223                 data.ioc_inlbuf3 = (char *) &id;
4224                 data.ioc_inllen3 = sizeof id;
4225                 data.ioc_inlbuf4 = (char *) &group;
4226                 data.ioc_inllen4 = sizeof group;
4227         }
4228         data.ioc_inlbuf2 = (char *) &version;
4229         data.ioc_inllen2 = sizeof version;
4230
4231         memset(buf, 0, sizeof *buf);
4232         rc = obd_ioctl_pack(&data, &buf, sizeof rawbuf);
4233         if (rc) {
4234                 fprintf(stderr, "error: %s: packing ioctl arguments: %s\n",
4235                         jt_cmdname(argv[0]), strerror(-rc));
4236                 return rc;
4237         }
4238
4239         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_GET_OBJ_VERSION, buf);
4240         if (rc == -1) {
4241                 fprintf(stderr, "error: %s: ioctl: %s\n",
4242                         jt_cmdname(argv[0]), strerror(errno));
4243                 return -errno;
4244         }
4245
4246         obd_ioctl_unpack(&data, buf, sizeof rawbuf);
4247         printf(LPX64"\n", version);
4248         return 0;
4249 }
4250
4251 int jt_changelog_register(int argc, char **argv)
4252 {
4253         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
4254         struct obd_ioctl_data data;
4255         char devname[30];
4256         int rc;
4257
4258         if (argc > 2)
4259                 return CMD_HELP;
4260         else if (argc == 2 && strcmp(argv[1], "-n") != 0)
4261                 return CMD_HELP;
4262         if (cur_device < 0)
4263                 return CMD_HELP;
4264
4265         memset(&data, 0, sizeof(data));
4266         data.ioc_dev = cur_device;
4267         memset(buf, 0, sizeof(rawbuf));
4268         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
4269         if (rc) {
4270                 fprintf(stderr, "error: %s: invalid ioctl\n",
4271                         jt_cmdname(argv[0]));
4272                return rc;
4273         }
4274
4275         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_CHANGELOG_REG, buf);
4276         if (rc < 0) {
4277                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
4278                         strerror(rc = errno));
4279                 return rc;
4280         }
4281         obd_ioctl_unpack(&data, buf, sizeof(rawbuf));
4282
4283         if (data.ioc_u32_1 == 0) {
4284                 fprintf(stderr, "received invalid userid!\n");
4285                 return -EPROTO;
4286         }
4287
4288         if (lcfg_get_devname() != NULL) {
4289                 if (strlen(lcfg_get_devname()) > sizeof(devname)-1) {
4290                         fprintf(stderr, "Dev name too long\n");
4291                         return -E2BIG;
4292                 }
4293                 strncpy(devname, lcfg_get_devname(), sizeof(devname));
4294         } else {
4295                 if (snprintf(devname, sizeof(devname), "dev %d", cur_device) >=
4296                     sizeof(devname)) {
4297                         fprintf(stderr, "Dev name too long\n");
4298                         return -E2BIG;
4299                 }
4300         }
4301
4302         if (argc == 2)
4303                 /* -n means bare name */
4304                 printf(CHANGELOG_USER_PREFIX"%u\n", data.ioc_u32_1);
4305         else
4306                 printf("%s: Registered changelog userid '"CHANGELOG_USER_PREFIX
4307                        "%u'\n", devname, data.ioc_u32_1);
4308         return 0;
4309 }
4310
4311 int jt_changelog_deregister(int argc, char **argv)
4312 {
4313         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
4314         struct obd_ioctl_data data;
4315         char devname[30];
4316         int id, rc;
4317
4318         if (argc != 2 || cur_device < 0)
4319                 return CMD_HELP;
4320
4321         id = strtol(argv[1] + strlen(CHANGELOG_USER_PREFIX), NULL, 10);
4322         if ((id == 0) || (strncmp(argv[1], CHANGELOG_USER_PREFIX,
4323                                   strlen(CHANGELOG_USER_PREFIX)) != 0)) {
4324                 fprintf(stderr, "expecting id of the form '"
4325                         CHANGELOG_USER_PREFIX"<num>'; got '%s'\n", argv[1]);
4326                 return CMD_HELP;
4327         }
4328
4329         memset(&data, 0, sizeof(data));
4330         data.ioc_dev = cur_device;
4331         data.ioc_u32_1 = id;
4332         memset(buf, 0, sizeof(rawbuf));
4333         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
4334         if (rc) {
4335                 fprintf(stderr, "error: %s: invalid ioctl\n",
4336                         jt_cmdname(argv[0]));
4337                 return rc;
4338         }
4339
4340         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_CHANGELOG_DEREG, buf);
4341         if (rc < 0) {
4342                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
4343                         strerror(rc = errno));
4344                 return rc;
4345         }
4346         obd_ioctl_unpack(&data, buf, sizeof(rawbuf));
4347
4348         if (data.ioc_u32_1 != id) {
4349                 fprintf(stderr, "No changelog user '%s'.  Blocking user"
4350                         " is '"CHANGELOG_USER_PREFIX"%d'.\n", argv[1],
4351                         data.ioc_u32_1);
4352                 return -ENOENT;
4353         }
4354
4355         if (lcfg_get_devname() != NULL) {
4356                 if (strlen(lcfg_get_devname()) > sizeof(devname)-1) {
4357                         fprintf(stderr, "Dev name too long\n");
4358                         return -E2BIG;
4359                 }
4360                 strncpy(devname, lcfg_get_devname(), sizeof(devname));
4361         } else {
4362                 if (snprintf(devname, sizeof(devname), "dev %d", cur_device) >=
4363                     sizeof(devname)) {
4364                         fprintf(stderr, "Dev name too long\n");
4365                         return -E2BIG;
4366                 }
4367         }
4368
4369         printf("%s: Deregistered changelog user '"CHANGELOG_USER_PREFIX"%d'\n",
4370                devname, data.ioc_u32_1);
4371         return 0;
4372 }
4373
4374