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