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