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