Whamcloud - gitweb
Land b1_8_gate onto b1_8 (20081218_1708)
[fs/lustre-release.git] / lustre / utils / obd.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
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 <stdlib.h>
45 #include <sys/ioctl.h>
46 #include <fcntl.h>
47 #include <sys/socket.h>
48 #include <sys/types.h>
49 #include <sys/wait.h>
50 #include <sys/stat.h>
51 #include <sys/param.h>
52 #include <stdio.h>
53 #include <stdarg.h>
54 #include <signal.h>
55 #include <glob.h>
56
57 #include "obdctl.h"
58
59 #include <obd.h>          /* for struct lov_stripe_md */
60 #include <lustre/lustre_build_version.h>
61
62 #include <unistd.h>
63 #include <sys/un.h>
64 #include <time.h>
65 #include <sys/time.h>
66 #include <errno.h>
67 #include <string.h>
68 #include <ctype.h>
69 #include <lustre/liblustreapi.h>
70
71 #ifdef HAVE_ASM_PAGE_H
72 #include <asm/page.h>           /* needed for PAGE_SIZE - rread */
73 #endif
74
75 #include <obd_class.h>
76 #include <lnet/lnetctl.h>
77 #include "parser.h"
78 #include "platform.h"
79 #include <stdio.h>
80
81 #define MAX_STRING_SIZE 128
82 #define DEVICES_LIST "/proc/fs/lustre/devices"
83
84 #if HAVE_LIBPTHREAD
85 #include <sys/ipc.h>
86 #include <sys/shm.h>
87 #include <pthread.h>
88
89 #define MAX_THREADS 1024
90
91 struct shared_data {
92         __u64 counters[MAX_THREADS];
93         __u64 offsets[MAX_THREADS];
94         int   running;
95         int   barrier;
96         int   stop;
97         l_mutex_t mutex;
98         l_cond_t  cond;
99 };
100
101 static struct shared_data *shared_data;
102 static __u64 counter_snapshot[2][MAX_THREADS];
103 static int prev_valid;
104 static struct timeval prev_time;
105 static int thread;
106 static int nthreads;
107 #else
108 const int thread = 0;
109 const int nthreads = 1;
110 #endif
111
112 static char rawbuf[8192];
113 static char *buf = rawbuf;
114 static int max = sizeof(rawbuf);
115
116 static int cur_device = -1;
117
118
119 #define MAX_STRIPES     170
120 struct lov_oinfo lov_oinfos[MAX_STRIPES];
121
122 struct lsm_buffer {
123         struct lov_stripe_md lsm;
124         struct lov_oinfo *ptrs[MAX_STRIPES];
125 } lsm_buffer;
126
127 static int l2_ioctl(int dev_id, unsigned int opc, void *buf)
128 {
129         return l_ioctl(dev_id, opc, buf);
130 }
131
132 #define IOC_INIT(data)                                                  \
133 do {                                                                    \
134         memset(&data, 0, sizeof(data));                                 \
135         data.ioc_dev = cur_device;                                      \
136 } while (0)
137
138 #define IOC_PACK(func, data)                                            \
139 do {                                                                    \
140         memset(buf, 0, sizeof(rawbuf));                                 \
141         if (obd_ioctl_pack(&data, &buf, max)) {                         \
142                 fprintf(stderr, "error: %s: invalid ioctl\n",           \
143                         jt_cmdname(func));                                 \
144                 return -2;                                              \
145         }                                                               \
146 } while (0)
147
148 #define IOC_UNPACK(func, data)                                          \
149 do {                                                                    \
150         if (obd_ioctl_unpack(&data, buf, max)) {                        \
151                 fprintf(stderr, "error: %s: invalid reply\n",           \
152                         jt_cmdname(func));                                 \
153                 return -2;                                              \
154         }                                                               \
155 } while (0)
156
157 int lcfg_ioctl(char * func, int dev_id, struct lustre_cfg *lcfg)
158 {
159         struct obd_ioctl_data data;
160         int rc;
161
162         IOC_INIT(data);
163         data.ioc_type = LUSTRE_CFG_TYPE;
164         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
165                                         lcfg->lcfg_buflens);
166         data.ioc_pbuf1 = (void *)lcfg;
167         IOC_PACK(func, data);
168
169         rc =  l_ioctl(dev_id, OBD_IOC_PROCESS_CFG, buf);
170
171         return rc;
172 }
173
174 static int do_device(char *func, char *devname);
175
176 static int get_mgs_device()
177 {
178         char mgs[] = "$MGS";
179         static int mgs_device = -1;
180
181         if (mgs_device == -1) {
182                 int rc;
183                 do_disconnect(NULL, 1);
184                 rc = do_device("mgsioc", mgs);
185                 if (rc) {
186                         fprintf(stderr, 
187                                 "This command must be run on the MGS.\n");
188                         errno = ENODEV;
189                         return -1;
190                 }
191                 mgs_device = cur_device;
192         }
193         return mgs_device;
194 }
195
196 /* Returns -1 on error with errno set */
197 int lcfg_mgs_ioctl(char *func, int dev_id, struct lustre_cfg *lcfg)
198 {
199         struct obd_ioctl_data data;
200         int rc;
201         
202         IOC_INIT(data);
203         rc = data.ioc_dev = get_mgs_device();
204         if (rc < 0)
205                 goto out;
206         data.ioc_type = LUSTRE_CFG_TYPE;
207         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
208                                         lcfg->lcfg_buflens);
209         data.ioc_pbuf1 = (void *)lcfg;
210         IOC_PACK(func, data);
211
212         rc = l_ioctl(dev_id, OBD_IOC_PARAM, buf);
213 out:
214         if (rc) {
215                 if (errno == ENOSYS)
216                         fprintf(stderr, "Make sure cfg_device is set first.\n");
217                 if (errno == EINVAL)
218                         fprintf(stderr, "cfg_device should be of the form "
219                                 "'lustre-MDT0000'\n");
220         }
221         return rc;
222 }
223
224 char *obdo_print(struct obdo *obd)
225 {
226         char buf[1024];
227
228         sprintf(buf, "id: "LPX64"\ngrp: "LPX64"\natime: "LPU64"\nmtime: "LPU64
229                 "\nctime: "LPU64"\nsize: "LPU64"\nblocks: "LPU64
230                 "\nblksize: %u\nmode: %o\nuid: %d\ngid: %d\nflags: %x\n"
231                 "misc: %x\nnlink: %d,\nvalid "LPX64"\n",
232                 obd->o_id, obd->o_gr, obd->o_atime, obd->o_mtime, obd->o_ctime,
233                 obd->o_size, obd->o_blocks, obd->o_blksize, obd->o_mode,
234                 obd->o_uid, obd->o_gid, obd->o_flags, obd->o_misc,
235                 obd->o_nlink, obd->o_valid);
236         return strdup(buf);
237 }
238
239
240 #define BAD_VERBOSE (-999999999)
241
242 #define N2D_OFF 0x100      /* So we can tell between error codes and devices */
243
244 static int do_name2dev(char *func, char *name)
245 {
246         struct obd_ioctl_data data;
247         int rc;
248
249         IOC_INIT(data);
250
251         data.ioc_inllen1 = strlen(name) + 1;
252         data.ioc_inlbuf1 = name;
253
254         IOC_PACK(func, data);
255         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_NAME2DEV, buf);
256         if (rc < 0)
257                 return errno;
258         IOC_UNPACK(func, data);
259
260         return data.ioc_dev + N2D_OFF;
261 }
262
263 /*
264  * resolve a device name to a device number.
265  * supports a number, $name or %uuid.
266  */
267 int parse_devname(char *func, char *name)
268 {
269         int rc;
270         int ret = -1;
271
272         if (!name)
273                 return ret;
274         if (isdigit(name[0])) {
275                 ret = strtoul(name, NULL, 0);
276         } else {
277                 if (name[0] == '$' || name[0] == '%')
278                         name++;
279                 rc = do_name2dev(func, name);
280                 if (rc >= N2D_OFF) {
281                         ret = rc - N2D_OFF;
282                         // printf("Name %s is device %d\n", name, ret);
283                 } else {
284                         fprintf(stderr, "No device found for name %s: %s\n",
285                                name, strerror(rc));
286                 }
287         }
288         return ret;
289 }
290
291 static void
292 reset_lsmb (struct lsm_buffer *lsmb)
293 {
294         memset (&lsmb->lsm, 0, sizeof (lsmb->lsm));
295         memset(lov_oinfos, 0, sizeof(lov_oinfos));
296         lsmb->lsm.lsm_magic = LOV_MAGIC;
297 }
298
299 static int
300 parse_lsm (struct lsm_buffer *lsmb, char *string)
301 {
302         struct lov_stripe_md *lsm = &lsmb->lsm;
303         char                 *end;
304         int                   i;
305
306         /*
307          * object_id[=size#count[@offset:id]*]
308          */
309
310         reset_lsmb (lsmb);
311
312         lsm->lsm_object_id = strtoull (string, &end, 0);
313         if (end == string)
314                 return (-1);
315         string = end;
316
317         if (*string == 0)
318                 return (0);
319
320         if (*string != '=')
321                 return (-1);
322         string++;
323
324         lsm->lsm_stripe_size = strtoul (string, &end, 0);
325         if (end == string)
326                 return (-1);
327         string = end;
328
329         if (*string != '#')
330                 return (-1);
331         string++;
332
333         lsm->lsm_stripe_count = strtoul (string, &end, 0);
334         if (end == string)
335                 return (-1);
336         string = end;
337
338         if (*string == 0)               /* don't have to specify obj ids */
339                 return (0);
340
341         for (i = 0; i < lsm->lsm_stripe_count; i++) {
342                 if (*string != '@')
343                         return (-1);
344                 string++;
345                 lsm->lsm_oinfo[i]->loi_ost_idx = strtoul(string, &end, 0);
346                 if (*end != ':')
347                         return (-1);
348                 string = end + 1;
349                 lsm->lsm_oinfo[i]->loi_id = strtoull(string, &end, 0);
350                 string = end;
351         }
352
353         if (*string != 0)
354                 return (-1);
355
356         return (0);
357 }
358
359 char *jt_cmdname(char *func)
360 {
361         static char buf[512];
362
363         if (thread) {
364                 sprintf(buf, "%s-%d", func, thread);
365                 return buf;
366         }
367
368         return func;
369 }
370
371 #define difftime(a, b)                                  \
372         ((a)->tv_sec - (b)->tv_sec +                    \
373          ((a)->tv_usec - (b)->tv_usec) / 1000000.0)
374
375 static int be_verbose(int verbose, struct timeval *next_time,
376                       __u64 num, __u64 *next_num, int num_total)
377 {
378         struct timeval now;
379
380         if (!verbose)
381                 return 0;
382
383         if (next_time != NULL)
384                 gettimeofday(&now, NULL);
385
386         /* A positive verbosity means to print every X iterations */
387         if (verbose > 0 && (num >= *next_num || num >= num_total)) {
388                 *next_num += verbose;
389                 if (next_time) {
390                         next_time->tv_sec = now.tv_sec - verbose;
391                         next_time->tv_usec = now.tv_usec;
392                 }
393                 return 1;
394         }
395
396         /* A negative verbosity means to print at most each X seconds */
397         if (verbose < 0 && next_time != NULL &&
398             difftime(&now, next_time) >= 0.0){
399                 next_time->tv_sec = now.tv_sec - verbose;
400                 next_time->tv_usec = now.tv_usec;
401                 *next_num = num;
402                 return 1;
403         }
404
405         return 0;
406 }
407
408 static int get_verbose(char *func, const char *arg)
409 {
410         int verbose;
411         char *end;
412
413         if (!arg || arg[0] == 'v')
414                 verbose = 1;
415         else if (arg[0] == 's' || arg[0] == 'q')
416                 verbose = 0;
417         else {
418                 verbose = (int)strtoul(arg, &end, 0);
419                 if (*end) {
420                         fprintf(stderr, "error: %s: bad verbose option '%s'\n",
421                                 jt_cmdname(func), arg);
422                         return BAD_VERBOSE;
423                 }
424         }
425
426         if (verbose < 0)
427                 printf("Print status every %d seconds\n", -verbose);
428         else if (verbose == 1)
429                 printf("Print status every operation\n");
430         else if (verbose > 1)
431                 printf("Print status every %d operations\n", verbose);
432
433         return verbose;
434 }
435
436 int do_disconnect(char *func, int verbose)
437 {
438         lcfg_set_devname(NULL);
439         cur_device = -1;
440         return 0;
441 }
442
443 #ifdef MAX_THREADS
444 static void shmem_setup(void)
445 {
446         /* Create new segment */
447         int shmid = shmget(IPC_PRIVATE, sizeof(*shared_data), 0600);
448
449         if (shmid == -1) {
450                 fprintf(stderr, "Can't create shared data: %s\n",
451                         strerror(errno));
452                 return;
453         }
454
455         /* Attatch to new segment */
456         shared_data = (struct shared_data *)shmat(shmid, NULL, 0);
457
458         if (shared_data == (struct shared_data *)(-1)) {
459                 fprintf(stderr, "Can't attach shared data: %s\n",
460                         strerror(errno));
461                 shared_data = NULL;
462                 return;
463         }
464
465         /* Mark segment as destroyed, so it will disappear when we exit.
466          * Forks will inherit attached segments, so we should be OK.
467          */
468         if (shmctl(shmid, IPC_RMID, NULL) == -1) {
469                 fprintf(stderr, "Can't destroy shared data: %s\n",
470                         strerror(errno));
471         }
472 }
473
474 static inline void shmem_lock(void)
475 {
476         l_mutex_lock(&shared_data->mutex);
477 }
478
479 static inline void shmem_unlock(void)
480 {
481         l_mutex_unlock(&shared_data->mutex);
482 }
483
484 static inline void shmem_reset(int total_threads)
485 {
486         if (shared_data == NULL)
487                 return;
488
489         memset(shared_data, 0, sizeof(*shared_data));
490         l_mutex_init(&shared_data->mutex);
491         l_cond_init(&shared_data->cond);
492         memset(counter_snapshot, 0, sizeof(counter_snapshot));
493         prev_valid = 0;
494         shared_data->barrier = total_threads;
495 }
496
497 static inline void shmem_bump(void)
498 {
499         static int bumped_running;
500
501         if (shared_data == NULL || thread <= 0 || thread > MAX_THREADS)
502                 return;
503
504         shmem_lock();
505         shared_data->counters[thread - 1]++;
506         if (!bumped_running)
507                 shared_data->running++;
508         shmem_unlock();
509         bumped_running = 1;
510 }
511
512 static void shmem_snap(int total_threads, int live_threads)
513 {
514         struct timeval this_time;
515         int non_zero = 0;
516         __u64 total = 0;
517         double secs;
518         int running;
519         int i;
520
521         if (shared_data == NULL || total_threads > MAX_THREADS)
522                 return;
523
524         shmem_lock();
525         memcpy(counter_snapshot[0], shared_data->counters,
526                total_threads * sizeof(counter_snapshot[0][0]));
527         running = shared_data->running;
528         shmem_unlock();
529
530         gettimeofday(&this_time, NULL);
531
532         for (i = 0; i < total_threads; i++) {
533                 long long this_count =
534                         counter_snapshot[0][i] - counter_snapshot[1][i];
535
536                 if (this_count != 0) {
537                         non_zero++;
538                         total += this_count;
539                 }
540         }
541
542         secs = (this_time.tv_sec + this_time.tv_usec / 1000000.0) -
543                (prev_time.tv_sec + prev_time.tv_usec / 1000000.0);
544
545         if (prev_valid &&
546             live_threads == total_threads &&
547             secs > 0.0)                    /* someone screwed with the time? */
548                 printf("%d/%d Total: %f/second\n", non_zero, total_threads, total / secs);
549
550         memcpy(counter_snapshot[1], counter_snapshot[0],
551                total_threads * sizeof(counter_snapshot[0][0]));
552         prev_time = this_time;
553         if (!prev_valid &&
554             running == total_threads)
555                 prev_valid = 1;
556 }
557
558 static void shmem_stop(void)
559 {
560         if (shared_data == NULL)
561                 return;
562
563         shared_data->stop = 1;
564 }
565
566 static int shmem_running(void)
567 {
568         return (shared_data == NULL ||
569                 !shared_data->stop);
570 }
571 #else
572 static void shmem_setup(void)
573 {
574 }
575
576 static inline void shmem_reset(int total_threads)
577 {
578 }
579
580 static inline void shmem_bump(void)
581 {
582 }
583
584 static void shmem_lock()
585 {
586 }
587
588 static void shmem_unlock()
589 {
590 }
591
592 static void shmem_stop(void)
593 {
594 }
595
596 static int shmem_running(void)
597 {
598         return 1;
599 }
600 #endif
601
602 extern command_t cmdlist[];
603
604 static int do_device(char *func, char *devname)
605 {
606         int dev;
607
608         dev = parse_devname(func, devname);
609         if (dev < 0)
610                 return -1;
611
612         lcfg_set_devname(devname);
613         cur_device = dev;
614         return 0;
615 }
616
617 int jt_obd_get_device()
618 {
619         return cur_device;
620 }
621
622 int jt_obd_device(int argc, char **argv)
623 {
624         int rc;
625
626         if (argc > 2)
627                 return CMD_HELP;
628
629         if (argc == 1) {
630                 printf("current device is %d - %s\n",
631                        cur_device, lcfg_get_devname() ? : "not set");
632                 return 0;
633         }
634         rc = do_device("device", argv[1]);
635         return rc;
636 }
637
638 int jt_opt_device(int argc, char **argv)
639 {
640         int ret;
641         int rc;
642
643         if (argc < 3)
644                 return CMD_HELP;
645
646         rc = do_device("device", argv[1]);
647
648         if (!rc)
649                 rc = Parser_execarg(argc - 2, argv + 2, cmdlist);
650
651         ret = do_disconnect(argv[0], 0);
652         if (!rc)
653                 rc = ret;
654
655         return rc;
656 }
657
658 #ifdef MAX_THREADS
659 static void parent_sighandler (int sig)
660 {
661         return;
662 }
663
664 int jt_opt_threads(int argc, char **argv)
665 {
666         static char      cmdstr[128];
667         sigset_t         saveset;
668         sigset_t         sigset;
669         struct sigaction sigact;
670         struct sigaction saveact1;
671         struct sigaction saveact2;
672         unsigned long    threads;
673         __u64            next_thread;
674         int verbose;
675         int rc = 0;
676         int report_count = -1;
677         char *end;
678         int i;
679
680         if (argc < 5)
681                 return CMD_HELP;
682
683         threads = strtoul(argv[1], &end, 0);
684
685         if (*end == '.')
686                 report_count = strtoul(end + 1, &end, 0);
687
688         if (*end || threads > MAX_THREADS) {
689                 fprintf(stderr, "error: %s: invalid thread count '%s'\n",
690                         jt_cmdname(argv[0]), argv[1]);
691                 return CMD_HELP;
692         }
693
694         verbose = get_verbose(argv[0], argv[2]);
695         if (verbose == BAD_VERBOSE)
696                 return CMD_HELP;
697
698         if (verbose != 0) {
699                 snprintf(cmdstr, sizeof(cmdstr), "%s", argv[4]);
700                 for (i = 5; i < argc; i++)
701                         snprintf(cmdstr + strlen(cmdstr), sizeof(cmdstr),
702                                  " %s", argv[i]);
703
704                 printf("%s: starting %ld threads on device %s running %s\n",
705                        argv[0], threads, argv[3], cmdstr);
706         }
707
708         shmem_reset(threads);
709
710         sigemptyset(&sigset);
711         sigaddset(&sigset, SIGALRM);
712         sigaddset(&sigset, SIGCHLD);
713         sigprocmask(SIG_BLOCK, &sigset, &saveset);
714
715         nthreads = threads;
716
717         for (i = 1, next_thread = verbose; i <= threads; i++) {
718                 rc = fork();
719                 if (rc < 0) {
720                         fprintf(stderr, "error: %s: #%d - %s\n", argv[0], i,
721                                 strerror(rc = errno));
722                         break;
723                 } else if (rc == 0) {
724                         sigprocmask(SIG_SETMASK, &saveset, NULL);
725
726                         thread = i;
727                         argv[2] = "--device";
728                         return jt_opt_device(argc - 2, argv + 2);
729                 } else if (be_verbose(verbose, NULL, i, &next_thread, threads))
730                         printf("%s: thread #%d (PID %d) started\n",
731                                argv[0], i, rc);
732                 rc = 0;
733         }
734
735         if (!thread) {          /* parent process */
736                 int live_threads = threads;
737
738                 sigemptyset(&sigset);
739                 sigemptyset(&sigact.sa_mask);
740                 sigact.sa_handler = parent_sighandler;
741                 sigact.sa_flags = 0;
742
743                 sigaction(SIGALRM, &sigact, &saveact1);
744                 sigaction(SIGCHLD, &sigact, &saveact2);
745
746                 while (live_threads > 0) {
747                         int status;
748                         pid_t ret;
749
750                         if (verbose < 0)        /* periodic stats */
751                                 alarm(-verbose);
752
753                         sigsuspend(&sigset);
754                         alarm(0);
755
756                         while (live_threads > 0) {
757                                 ret = waitpid(0, &status, WNOHANG);
758                                 if (ret == 0)
759                                         break;
760
761                                 if (ret < 0) {
762                                         fprintf(stderr, "error: %s: wait - %s\n",
763                                                 argv[0], strerror(errno));
764                                         if (!rc)
765                                                 rc = errno;
766                                         continue;
767                                 } else {
768                                         /*
769                                          * This is a hack.  We _should_ be able
770                                          * to use WIFEXITED(status) to see if
771                                          * there was an error, but it appears
772                                          * to be broken and it always returns 1
773                                          * (OK).  See wait(2).
774                                          */
775                                         int err = WEXITSTATUS(status);
776                                         if (err || WIFSIGNALED(status))
777                                                 fprintf(stderr,
778                                                         "%s: PID %d had rc=%d\n",
779                                                         argv[0], ret, err);
780                                         if (!rc)
781                                                 rc = err;
782
783                                         live_threads--;
784                                 }
785                         }
786
787                         /* Show stats while all threads running */
788                         if (verbose < 0) {
789                                 shmem_snap(threads, live_threads);
790                                 if (report_count > 0 && --report_count == 0)
791                                         shmem_stop();
792                         }
793                 }
794                 sigaction(SIGCHLD, &saveact2, NULL);
795                 sigaction(SIGALRM, &saveact1, NULL);
796         }
797
798         sigprocmask(SIG_SETMASK, &saveset, NULL);
799
800         return rc;
801 }
802 #else
803 int jt_opt_threads(int argc, char **argv)
804 {
805         fprintf(stderr, "%s not-supported in a single-threaded runtime\n",
806                 jt_cmdname(argv[0]));
807         return CMD_HELP;
808 }
809 #endif
810
811 int jt_opt_net(int argc, char **argv)
812 {
813         char *arg2[3];
814         int rc;
815
816         if (argc < 3)
817                 return CMD_HELP;
818
819         arg2[0] = argv[0];
820         arg2[1] = argv[1];
821         arg2[2] = NULL;
822         rc = jt_ptl_network (2, arg2);
823
824         if (!rc)
825                 rc = Parser_execarg(argc - 2, argv + 2, cmdlist);
826
827         return rc;
828 }
829
830 int jt_obd_no_transno(int argc, char **argv)
831 {
832         struct obd_ioctl_data data;
833         int rc;
834
835         IOC_INIT(data);
836
837         if (argc != 1)
838                 return CMD_HELP;
839
840         IOC_PACK(argv[0], data);
841         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_NO_TRANSNO, buf);
842         if (rc < 0)
843                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
844                         strerror(rc = errno));
845
846         return rc;
847 }
848
849 int jt_obd_set_readonly(int argc, char **argv)
850 {
851         struct obd_ioctl_data data;
852         int rc;
853
854         IOC_INIT(data);
855
856         if (argc != 1)
857                 return CMD_HELP;
858
859         IOC_PACK(argv[0], data);
860         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_SET_READONLY, buf);
861         if (rc < 0)
862                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
863                         strerror(rc = errno));
864
865         return rc;
866 }
867
868 int jt_obd_abort_recovery(int argc, char **argv)
869 {
870         struct obd_ioctl_data data;
871         int rc;
872
873         IOC_INIT(data);
874
875         if (argc != 1)
876                 return CMD_HELP;
877
878         IOC_PACK(argv[0], data);
879         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_ABORT_RECOVERY, buf);
880         if (rc < 0)
881                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
882                         strerror(rc = errno));
883
884         return rc;
885 }
886
887 int jt_get_version(int argc, char **argv)
888 {
889         int rc;
890         char buf[8192];
891         struct obd_ioctl_data *data = (struct obd_ioctl_data *)buf;
892
893         if (argc != 1)
894                 return CMD_HELP;
895
896         memset(buf, 0, sizeof(buf));
897         data->ioc_version = OBD_IOCTL_VERSION;
898         data->ioc_inllen1 = sizeof(buf) - size_round(sizeof(*data));
899         data->ioc_inlbuf1 = buf + size_round(sizeof(*data));
900         data->ioc_len = obd_ioctl_packlen(data);
901
902         rc = l2_ioctl(OBD_DEV_ID, OBD_GET_VERSION, buf);
903         if (rc < 0)
904                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
905                         strerror(rc = errno));
906         else {
907                 printf("Lustre version: %s\n", data->ioc_bulk);
908         }
909
910         printf("lctl   version: %s\n", BUILD_VERSION);
911         return rc;
912 }
913
914 /*
915  * Print an obd device line with the ost_conn_uuid inserted, if the obd
916  * is an osc.
917  */
918 static void print_obd_line(char *s)
919 {
920         char buf[MAX_STRING_SIZE];
921         char obd_name[MAX_OBD_NAME];
922         FILE *fp = NULL;
923         char *ptr;
924
925         if (sscanf(s, " %*d %*s osc %s %*s %*d ", obd_name) == 0)
926                 goto try_mdc;
927         snprintf(buf, sizeof(buf),
928                  "/proc/fs/lustre/osc/%s/ost_conn_uuid", obd_name);
929         if ((fp = fopen(buf, "r")) == NULL)
930                 goto try_mdc;
931         goto got_one;
932
933 try_mdc:
934         if (sscanf(s, " %*d %*s mdc %s %*s %*d ", obd_name) == 0)
935                 goto fail;
936         snprintf(buf, sizeof(buf),
937                  "/proc/fs/lustre/mdc/%s/mds_conn_uuid", obd_name);
938         if ((fp = fopen(buf, "r")) == NULL)
939                 goto fail;
940
941 got_one:
942         fgets(buf, sizeof(buf), fp);
943         fclose(fp);
944
945         /* trim trailing newlines */
946         ptr = strrchr(buf, '\n');
947         if (ptr) *ptr = '\0';
948         ptr = strrchr(s, '\n');
949         if (ptr) *ptr = '\0';
950
951         printf("%s %s\n", s, buf);
952         return;
953
954 fail:
955         printf("%s", s);
956         return;
957 }
958
959 /* get device list by ioctl */
960 int jt_obd_list_ioctl(int argc, char **argv)
961 {
962         int rc, index;
963         char buf[8192];
964         struct obd_ioctl_data *data = (struct obd_ioctl_data *)buf;
965
966         if (argc > 2)
967                 return CMD_HELP;
968         /* Just ignore a -t option.  Only supported with /proc. */
969         else if (argc == 2 && strcmp(argv[1], "-t") != 0)
970                 return CMD_HELP;
971
972         for (index = 0;; index++) {
973                 memset(buf, 0, sizeof(buf));
974                 data->ioc_version = OBD_IOCTL_VERSION;
975                 data->ioc_inllen1 = sizeof(buf) - size_round(sizeof(*data));
976                 data->ioc_inlbuf1 = buf + size_round(sizeof(*data));
977                 data->ioc_len = obd_ioctl_packlen(data);
978                 data->ioc_count = index;
979
980                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_GETDEVICE, buf);
981                 if (rc != 0)
982                         break;
983                 printf("%s\n", (char *)data->ioc_bulk);
984         }
985         if (rc != 0) {
986                 if (errno == ENOENT)
987                         /* no device or the last device */
988                         rc = 0;
989                 else
990                         fprintf(stderr, "Error getting device list: %s: "
991                                         "check dmesg.\n",
992                                         strerror(errno));
993         }
994         return rc;
995 }
996
997 int jt_obd_list(int argc, char **argv)
998 {
999         int rc;
1000         char buf[MAX_STRING_SIZE];
1001         FILE *fp = NULL;
1002         int print_obd = 0;
1003
1004         if (argc > 2)
1005                 return CMD_HELP;
1006         else if (argc == 2) {
1007                 if (strcmp(argv[1], "-t") == 0)
1008                         print_obd = 1;
1009                 else
1010                         return CMD_HELP;
1011         }
1012
1013         fp = fopen(DEVICES_LIST, "r");
1014         if (fp == NULL) {
1015                 fprintf(stderr, "error: %s: %s opening "DEVICES_LIST"\n",
1016                         jt_cmdname(argv[0]), strerror(rc =  errno));
1017                 return jt_obd_list_ioctl(argc, argv);
1018         }
1019
1020         while (fgets(buf, sizeof(buf), fp) != NULL)
1021                 if (print_obd)
1022                         print_obd_line(buf);
1023                 else
1024                         printf("%s", buf);
1025
1026         fclose(fp);
1027         return 0;
1028 }
1029
1030
1031
1032
1033 /* Create one or more objects, arg[4] may describe stripe meta-data.  If
1034  * not, defaults assumed.  This echo-client instance stashes the stripe
1035  * object ids.  Use get_stripe on this node to print full lsm and
1036  * set_stripe on another node to cut/paste between nodes.
1037  */
1038 /* create <count> [<file_create_mode>] [q|v|# verbosity] [striping] */
1039 int jt_obd_create(int argc, char **argv)
1040 {
1041         struct obd_ioctl_data data;
1042         struct timeval next_time;
1043         __u64 count = 1, next_count, base_id = 0;
1044         int verbose = 1, mode = 0100644, rc = 0, i, valid_lsm = 0;
1045         char *end;
1046
1047         IOC_INIT(data);
1048         if (argc < 2 || argc > 5)
1049                 return CMD_HELP;
1050
1051         count = strtoull(argv[1], &end, 0);
1052         if (*end) {
1053                 fprintf(stderr, "error: %s: invalid iteration count '%s'\n",
1054                         jt_cmdname(argv[0]), argv[1]);
1055                 return CMD_HELP;
1056         }
1057
1058         if (argc > 2) {
1059                 mode = strtoul(argv[2], &end, 0);
1060                 if (*end) {
1061                         fprintf(stderr, "error: %s: invalid mode '%s'\n",
1062                                 jt_cmdname(argv[0]), argv[2]);
1063                         return CMD_HELP;
1064                 }
1065                 if (!(mode & S_IFMT))
1066                         mode |= S_IFREG;
1067         }
1068
1069         if (argc > 3) {
1070                 verbose = get_verbose(argv[0], argv[3]);
1071                 if (verbose == BAD_VERBOSE)
1072                         return CMD_HELP;
1073         }
1074
1075         if (argc < 5)
1076                 reset_lsmb (&lsm_buffer);       /* will set default */
1077         else {
1078                 rc = parse_lsm (&lsm_buffer, argv[4]);
1079                 if (rc != 0) {
1080                         fprintf(stderr, "error: %s: invalid lsm '%s'\n",
1081                                 jt_cmdname(argv[0]), argv[4]);
1082                         return CMD_HELP;
1083                 }
1084                 base_id = lsm_buffer.lsm.lsm_object_id;
1085                 valid_lsm = 1;
1086         }
1087
1088         printf("%s: "LPD64" objects\n", jt_cmdname(argv[0]), count);
1089         gettimeofday(&next_time, NULL);
1090         next_time.tv_sec -= verbose;
1091
1092         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
1093                 data.ioc_obdo1.o_mode = mode;
1094                 data.ioc_obdo1.o_id = base_id;
1095                 data.ioc_obdo1.o_uid = 0;
1096                 data.ioc_obdo1.o_gid = 0;
1097                 data.ioc_obdo1.o_valid = OBD_MD_FLTYPE | OBD_MD_FLMODE |
1098                         OBD_MD_FLID | OBD_MD_FLUID | OBD_MD_FLGID;
1099
1100                 if (valid_lsm) {
1101                         data.ioc_plen1 = sizeof lsm_buffer;
1102                         data.ioc_pbuf1 = (char *)&lsm_buffer;
1103                 }
1104
1105                 IOC_PACK(argv[0], data);
1106                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_CREATE, buf);
1107                 IOC_UNPACK(argv[0], data);
1108                 shmem_bump();
1109                 if (rc < 0) {
1110                         fprintf(stderr, "error: %s: #%d - %s\n",
1111                                 jt_cmdname(argv[0]), i, strerror(rc = errno));
1112                         break;
1113                 }
1114                 if (!(data.ioc_obdo1.o_valid & OBD_MD_FLID)) {
1115                         fprintf(stderr,"error: %s: oid not valid #%d:"LPX64"\n",
1116                                 jt_cmdname(argv[0]), i, data.ioc_obdo1.o_valid);
1117                         rc = EINVAL;
1118                         break;
1119                 }
1120
1121                 if (be_verbose(verbose, &next_time, i, &next_count, count))
1122                         printf("%s: #%d is object id "LPX64"\n",
1123                                 jt_cmdname(argv[0]), i, data.ioc_obdo1.o_id);
1124         }
1125         return rc;
1126 }
1127
1128 int jt_obd_setattr(int argc, char **argv)
1129 {
1130         struct obd_ioctl_data data;
1131         char *end;
1132         int rc;
1133
1134         IOC_INIT(data);
1135         if (argc != 2)
1136                 return CMD_HELP;
1137
1138         data.ioc_obdo1.o_id = strtoull(argv[1], &end, 0);
1139         if (*end) {
1140                 fprintf(stderr, "error: %s: invalid objid '%s'\n",
1141                         jt_cmdname(argv[0]), argv[1]);
1142                 return CMD_HELP;
1143         }
1144         data.ioc_obdo1.o_mode = S_IFREG | strtoul(argv[2], &end, 0);
1145         if (*end) {
1146                 fprintf(stderr, "error: %s: invalid mode '%s'\n",
1147                         jt_cmdname(argv[0]), argv[2]);
1148                 return CMD_HELP;
1149         }
1150         data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE;
1151
1152         IOC_PACK(argv[0], data);
1153         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_SETATTR, buf);
1154         if (rc < 0)
1155                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
1156                         strerror(rc = errno));
1157
1158         return rc;
1159 }
1160
1161 int jt_obd_test_setattr(int argc, char **argv)
1162 {
1163         struct obd_ioctl_data data;
1164         struct timeval start, next_time;
1165         __u64 i, count, next_count;
1166         int verbose = 1;
1167         obd_id objid = 3;
1168         char *end;
1169         int rc = 0;
1170
1171         if (argc < 2 || argc > 4)
1172                 return CMD_HELP;
1173
1174         IOC_INIT(data);
1175         count = strtoull(argv[1], &end, 0);
1176         if (*end) {
1177                 fprintf(stderr, "error: %s: invalid iteration count '%s'\n",
1178                         jt_cmdname(argv[0]), argv[1]);
1179                 return CMD_HELP;
1180         }
1181
1182         if (argc >= 3) {
1183                 verbose = get_verbose(argv[0], argv[2]);
1184                 if (verbose == BAD_VERBOSE)
1185                         return CMD_HELP;
1186         }
1187
1188         if (argc >= 4) {
1189                 if (argv[3][0] == 't') {
1190                         objid = strtoull(argv[3] + 1, &end, 0);
1191                         if (thread)
1192                                 objid += thread - 1;
1193                 } else
1194                         objid = strtoull(argv[3], &end, 0);
1195                 if (*end) {
1196                         fprintf(stderr, "error: %s: invalid objid '%s'\n",
1197                                 jt_cmdname(argv[0]), argv[3]);
1198                         return CMD_HELP;
1199                 }
1200         }
1201
1202         gettimeofday(&start, NULL);
1203         next_time.tv_sec = start.tv_sec - verbose;
1204         next_time.tv_usec = start.tv_usec;
1205         if (verbose != 0)
1206                 printf("%s: setting "LPD64" attrs (objid "LPX64"): %s",
1207                        jt_cmdname(argv[0]), count, objid, ctime(&start.tv_sec));
1208
1209         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
1210                 data.ioc_obdo1.o_id = objid;
1211                 data.ioc_obdo1.o_mode = S_IFREG;
1212                 data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE;
1213                 IOC_PACK(argv[0], data);
1214                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_SETATTR, &data);
1215                 shmem_bump();
1216                 if (rc < 0) {
1217                         fprintf(stderr, "error: %s: #"LPD64" - %d:%s\n",
1218                                 jt_cmdname(argv[0]), i, errno, strerror(rc = errno));
1219                         break;
1220                 } else {
1221                         if (be_verbose
1222                             (verbose, &next_time, i, &next_count, count))
1223                                 printf("%s: set attr #"LPD64"\n",
1224                                        jt_cmdname(argv[0]), i);
1225                 }
1226         }
1227
1228         if (!rc) {
1229                 struct timeval end;
1230                 double diff;
1231
1232                 gettimeofday(&end, NULL);
1233
1234                 diff = difftime(&end, &start);
1235
1236                 --i;
1237                 if (verbose != 0)
1238                         printf("%s: "LPD64" attrs in %.3fs (%.3f attr/s): %s",
1239                                jt_cmdname(argv[0]), i, diff, i / diff,
1240                                ctime(&end.tv_sec));
1241         }
1242         return rc;
1243 }
1244
1245 int jt_obd_destroy(int argc, char **argv)
1246 {
1247         struct obd_ioctl_data data;
1248         struct timeval next_time;
1249         __u64 count = 1, next_count;
1250         int verbose = 1;
1251         __u64 id;
1252         char *end;
1253         int rc = 0, i;
1254
1255         IOC_INIT(data);
1256         if (argc < 2 || argc > 4)
1257                 return CMD_HELP;
1258
1259         id = strtoull(argv[1], &end, 0);
1260         if (*end || id == 0 || errno != 0) {
1261                 fprintf(stderr, "error: %s: invalid objid '%s'\n",
1262                         jt_cmdname(argv[0]), argv[1]);
1263                 return CMD_HELP;
1264         }
1265         if (argc > 2) {
1266                 count = strtoull(argv[2], &end, 0);
1267                 if (*end) {
1268                         fprintf(stderr,
1269                                 "error: %s: invalid iteration count '%s'\n",
1270                                 jt_cmdname(argv[0]), argv[2]);
1271                         return CMD_HELP;
1272                 }
1273         }
1274
1275         if (argc > 3) {
1276                 verbose = get_verbose(argv[0], argv[3]);
1277                 if (verbose == BAD_VERBOSE)
1278                         return CMD_HELP;
1279         }
1280
1281         printf("%s: "LPD64" objects\n", jt_cmdname(argv[0]), count);
1282         gettimeofday(&next_time, NULL);
1283         next_time.tv_sec -= verbose;
1284
1285         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++, id++) {
1286                 data.ioc_obdo1.o_id = id;
1287                 data.ioc_obdo1.o_mode = S_IFREG | 0644;
1288                 data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLMODE;
1289
1290                 IOC_PACK(argv[0], data);
1291                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_DESTROY, buf);
1292                 IOC_UNPACK(argv[0], data);
1293                 shmem_bump();
1294                 if (rc < 0) {
1295                         fprintf(stderr, "error: %s: objid "LPX64": %s\n",
1296                                 jt_cmdname(argv[0]), id, strerror(rc = errno));
1297                         break;
1298                 }
1299
1300                 if (be_verbose(verbose, &next_time, i, &next_count, count))
1301                         printf("%s: #%d is object id "LPX64"\n",
1302                                jt_cmdname(argv[0]), i, id);
1303         }
1304
1305         return rc;
1306 }
1307
1308 int jt_obd_getattr(int argc, char **argv)
1309 {
1310         struct obd_ioctl_data data;
1311         char *end;
1312         int rc;
1313
1314         if (argc != 2)
1315                 return CMD_HELP;
1316
1317         IOC_INIT(data);
1318         data.ioc_obdo1.o_id = strtoull(argv[1], &end, 0);
1319         if (*end) {
1320                 fprintf(stderr, "error: %s: invalid objid '%s'\n",
1321                         jt_cmdname(argv[0]), argv[1]);
1322                 return CMD_HELP;
1323         }
1324         /* to help obd filter */
1325         data.ioc_obdo1.o_mode = 0100644;
1326         data.ioc_obdo1.o_valid = 0xffffffff;
1327         printf("%s: object id "LPX64"\n", jt_cmdname(argv[0]),data.ioc_obdo1.o_id);
1328
1329         IOC_PACK(argv[0], data);
1330         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_GETATTR, buf);
1331         IOC_UNPACK(argv[0], data);
1332         if (rc) {
1333                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
1334                         strerror(rc = errno));
1335         } else {
1336                 printf("%s: object id "LPX64", mode %o\n", jt_cmdname(argv[0]),
1337                        data.ioc_obdo1.o_id, data.ioc_obdo1.o_mode);
1338         }
1339         return rc;
1340 }
1341
1342 int jt_obd_test_getattr(int argc, char **argv)
1343 {
1344         struct obd_ioctl_data data;
1345         struct timeval start, next_time;
1346         __u64 i, count, next_count;
1347         int verbose = 1;
1348         obd_id objid = 3;
1349         char *end;
1350         int rc = 0;
1351
1352         if (argc < 2 || argc > 4)
1353                 return CMD_HELP;
1354
1355         IOC_INIT(data);
1356         count = strtoull(argv[1], &end, 0);
1357         if (*end) {
1358                 fprintf(stderr, "error: %s: invalid iteration count '%s'\n",
1359                         jt_cmdname(argv[0]), argv[1]);
1360                 return CMD_HELP;
1361         }
1362
1363         if (argc >= 3) {
1364                 verbose = get_verbose(argv[0], argv[2]);
1365                 if (verbose == BAD_VERBOSE)
1366                         return CMD_HELP;
1367         }
1368
1369         if (argc >= 4) {
1370                 if (argv[3][0] == 't') {
1371                         objid = strtoull(argv[3] + 1, &end, 0);
1372                         if (thread)
1373                                 objid += thread - 1;
1374                 } else
1375                         objid = strtoull(argv[3], &end, 0);
1376                 if (*end) {
1377                         fprintf(stderr, "error: %s: invalid objid '%s'\n",
1378                                 jt_cmdname(argv[0]), argv[3]);
1379                         return CMD_HELP;
1380                 }
1381         }
1382
1383         gettimeofday(&start, NULL);
1384         next_time.tv_sec = start.tv_sec - verbose;
1385         next_time.tv_usec = start.tv_usec;
1386         if (verbose != 0)
1387                 printf("%s: getting "LPD64" attrs (objid "LPX64"): %s",
1388                        jt_cmdname(argv[0]), count, objid, ctime(&start.tv_sec));
1389
1390         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
1391                 data.ioc_obdo1.o_id = objid;
1392                 data.ioc_obdo1.o_mode = S_IFREG;
1393                 data.ioc_obdo1.o_valid = 0xffffffff;
1394                 IOC_PACK(argv[0], data);
1395                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_GETATTR, &data);
1396                 shmem_bump();
1397                 if (rc < 0) {
1398                         fprintf(stderr, "error: %s: #"LPD64" - %d:%s\n",
1399                                 jt_cmdname(argv[0]), i, errno, strerror(rc = errno));
1400                         break;
1401                 } else {
1402                         if (be_verbose
1403                             (verbose, &next_time, i, &next_count, count))
1404                                 printf("%s: got attr #"LPD64"\n",
1405                                        jt_cmdname(argv[0]), i);
1406                 }
1407         }
1408
1409         if (!rc) {
1410                 struct timeval end;
1411                 double diff;
1412
1413                 gettimeofday(&end, NULL);
1414
1415                 diff = difftime(&end, &start);
1416
1417                 --i;
1418                 if (verbose != 0)
1419                         printf("%s: "LPD64" attrs in %.3fs (%.3f attr/s): %s",
1420                                jt_cmdname(argv[0]), i, diff, i / diff,
1421                                ctime(&end.tv_sec));
1422         }
1423         return rc;
1424 }
1425
1426 /* test_brw <cnt>                                               count
1427         <r|w[r(repeat)x(noverify)]>                             mode
1428         <q|v|#(print interval)>                                 verbosity
1429         <npages[+offset]>                                       blocksize
1430         <[[<interleave_threads>]t(inc obj by thread#)]obj>      object
1431         [p|g<args>]                                             batch */
1432 int jt_obd_test_brw(int argc, char **argv)
1433 {
1434         struct obd_ioctl_data data;
1435         struct timeval start, next_time;
1436         __u64 count, next_count, len, stride, thr_offset = 0, objid = 3;
1437         int write = 0, verbose = 1, cmd, i, rc = 0, pages = 1;
1438         int offset_pages = 0;
1439         long n;
1440         int repeat_offset = 0;
1441         unsigned long long ull;
1442         int  nthr_per_obj = 0;
1443         int  verify = 1;
1444         int  obj_idx = 0;
1445         char *end;
1446
1447         if (argc < 2 || argc > 7) {
1448                 fprintf(stderr, "error: %s: bad number of arguments: %d\n",
1449                         jt_cmdname(argv[0]), argc);
1450                 return CMD_HELP;
1451         }
1452
1453         count = strtoull(argv[1], &end, 0);
1454         if (*end) {
1455                 fprintf(stderr, "error: %s: bad iteration count '%s'\n",
1456                         jt_cmdname(argv[0]), argv[1]);
1457                 return CMD_HELP;
1458         }
1459
1460         if (argc >= 3) {
1461                 if (argv[2][0] == 'w' || argv[2][0] == '1')
1462                         write = 1;
1463                 /* else it's a read */
1464
1465                 if (argv[2][0] != 0)
1466                         for (i = 1; argv[2][i] != 0; i++)
1467                                 switch (argv[2][i]) {
1468                                 case 'r':
1469                                         repeat_offset = 1;
1470                                         break;
1471
1472                                 case 'x':
1473                                         verify = 0;
1474                                         break;
1475
1476                                 default:
1477                                         fprintf (stderr, "Can't parse cmd '%s'\n",
1478                                                  argv[2]);
1479                                         return CMD_HELP;
1480                                 }
1481         }
1482
1483         if (argc >= 4) {
1484                 verbose = get_verbose(argv[0], argv[3]);
1485                 if (verbose == BAD_VERBOSE)
1486                         return CMD_HELP;
1487         }
1488
1489         if (argc >= 5) {
1490                 pages = strtoul(argv[4], &end, 0);
1491
1492                 if (*end == '+')
1493                         offset_pages = strtoul(end + 1, &end, 0);
1494
1495                 if (*end != 0 ||
1496                     offset_pages < 0 || offset_pages >= pages) {
1497                         fprintf(stderr, "error: %s: bad npages[+offset] parameter '%s'\n",
1498                                 jt_cmdname(argv[0]), argv[4]);
1499                         return CMD_HELP;
1500                 }
1501         }
1502
1503         if (argc >= 6) {
1504                 if (thread &&
1505                     (n = strtol(argv[5], &end, 0)) > 0 &&
1506                     *end == 't' &&
1507                     (ull = strtoull(end + 1, &end, 0)) > 0 &&
1508                     *end == 0) {
1509                         nthr_per_obj = n;
1510                         objid = ull;
1511                 } else if (thread &&
1512                            argv[5][0] == 't') {
1513                         nthr_per_obj = 1;
1514                         objid = strtoull(argv[5] + 1, &end, 0);
1515                 } else {
1516                         nthr_per_obj = 0;
1517                         objid = strtoull(argv[5], &end, 0);
1518                 }
1519                 if (*end) {
1520                         fprintf(stderr, "error: %s: bad objid '%s'\n",
1521                                 jt_cmdname(argv[0]), argv[5]);
1522                         return CMD_HELP;
1523                 }
1524         }
1525
1526         IOC_INIT(data);
1527
1528         /* communicate the 'type' of brw test and batching to echo_client.
1529          * don't start.  we'd love to refactor this lctl->echo_client
1530          * interface */
1531         data.ioc_pbuf1 = (void *)1;
1532         data.ioc_plen1 = 1;
1533
1534         if (argc >= 7) {
1535                 switch(argv[6][0]) {
1536                         case 'g': /* plug and unplug */
1537                                 data.ioc_pbuf1 = (void *)2;
1538                                 data.ioc_plen1 = strtoull(argv[6] + 1, &end,
1539                                                           0);
1540                                 break;
1541                         case 'p': /* prep and commit */
1542                                 data.ioc_pbuf1 = (void *)3;
1543                                 data.ioc_plen1 = strtoull(argv[6] + 1, &end,
1544                                                           0);
1545                                 break;
1546                         default:
1547                                 fprintf(stderr, "error: %s: batching '%s' "
1548                                         "needs to specify 'p' or 'g'\n",
1549                                         jt_cmdname(argv[0]), argv[6]);
1550                                 return CMD_HELP;
1551                 }
1552
1553                 if (*end) {
1554                         fprintf(stderr, "error: %s: bad batching '%s'\n",
1555                                 jt_cmdname(argv[0]), argv[6]);
1556                         return CMD_HELP;
1557                 }
1558                 data.ioc_plen1 *= getpagesize();
1559         }
1560
1561         len = pages * getpagesize();
1562         thr_offset = offset_pages * getpagesize();
1563         stride = len;
1564
1565 #ifdef MAX_THREADS
1566         if (thread) {
1567                 shmem_lock ();
1568                 if (nthr_per_obj != 0) {
1569                         /* threads interleave */
1570                         obj_idx = (thread - 1)/nthr_per_obj;
1571                         objid += obj_idx;
1572                         stride *= nthr_per_obj;
1573                         if (thread == 1)
1574                                 shared_data->offsets[obj_idx] = stride + thr_offset;
1575                         thr_offset += ((thread - 1) % nthr_per_obj) * len;
1576                 } else {
1577                         /* threads disjoint */
1578                         thr_offset += (thread - 1) * len;
1579                 }
1580
1581                 shared_data->barrier--;
1582                 if (shared_data->barrier == 0)
1583                         l_cond_broadcast(&shared_data->cond);
1584                 else
1585                         l_cond_wait(&shared_data->cond,
1586                                           &shared_data->mutex);
1587
1588                 shmem_unlock ();
1589         }
1590 #endif
1591
1592         data.ioc_obdo1.o_id = objid;
1593         data.ioc_obdo1.o_mode = S_IFREG;
1594         data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE | OBD_MD_FLFLAGS;
1595         data.ioc_obdo1.o_flags = (verify ? OBD_FL_DEBUG_CHECK : 0);
1596         data.ioc_count = len;
1597         data.ioc_offset = (repeat_offset ? 0 : thr_offset);
1598
1599         gettimeofday(&start, NULL);
1600         next_time.tv_sec = start.tv_sec - verbose;
1601         next_time.tv_usec = start.tv_usec;
1602
1603         if (verbose != 0)
1604                 printf("%s: %s "LPU64"x%d pages (obj "LPX64", off "LPU64"): %s",
1605                        jt_cmdname(argv[0]), write ? "writing" : "reading", count,
1606                        pages, objid, data.ioc_offset, ctime(&start.tv_sec));
1607
1608         cmd = write ? OBD_IOC_BRW_WRITE : OBD_IOC_BRW_READ;
1609         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
1610                 data.ioc_obdo1.o_valid &= ~(OBD_MD_FLBLOCKS|OBD_MD_FLGRANT);
1611                 IOC_PACK(argv[0], data);
1612                 rc = l2_ioctl(OBD_DEV_ID, cmd, buf);
1613                 shmem_bump();
1614                 if (rc) {
1615                         fprintf(stderr, "error: %s: #%d - %s on %s\n",
1616                                 jt_cmdname(argv[0]), i, strerror(rc = errno),
1617                                 write ? "write" : "read");
1618                         break;
1619                 } else if (be_verbose(verbose, &next_time,i, &next_count,count)) {
1620                         shmem_lock ();
1621                         printf("%s: %s number %d @ "LPD64":"LPU64" for %d\n",
1622                                jt_cmdname(argv[0]), write ? "write" : "read", i,
1623                                data.ioc_obdo1.o_id, data.ioc_offset,
1624                                (int)(pages * getpagesize()));
1625                         shmem_unlock ();
1626                 }
1627
1628                 if (!repeat_offset) {
1629 #ifdef MAX_THREADS
1630                         if (stride == len) {
1631                                 data.ioc_offset += stride;
1632                         } else if (i < count) {
1633                                 shmem_lock ();
1634                                 data.ioc_offset = shared_data->offsets[obj_idx];
1635                                 shared_data->offsets[obj_idx] += len;
1636                                 shmem_unlock ();
1637                         }
1638 #else
1639                         data.ioc_offset += len;
1640                         obj_idx = 0; /* avoids an unused var warning */
1641 #endif
1642                 }
1643         }
1644
1645         if (!rc) {
1646                 struct timeval end;
1647                 double diff;
1648
1649                 gettimeofday(&end, NULL);
1650
1651                 diff = difftime(&end, &start);
1652
1653                 --i;
1654                 if (verbose != 0)
1655                         printf("%s: %s %dx%d pages in %.3fs (%.3f MB/s): %s",
1656                                jt_cmdname(argv[0]), write ? "wrote" : "read",
1657                                i, pages, diff,
1658                                ((double)i * pages * getpagesize()) /
1659                                (diff * 1048576.0),
1660                                ctime(&end.tv_sec));
1661         }
1662
1663         return rc;
1664 }
1665
1666 int jt_obd_lov_getconfig(int argc, char **argv)
1667 {
1668         struct obd_ioctl_data data;
1669         struct lov_desc desc;
1670         struct obd_uuid *uuidarray;
1671         __u32 *obdgens;
1672         char *path;
1673         int rc, fd;
1674
1675         IOC_INIT(data);
1676
1677         if (argc != 2)
1678                 return CMD_HELP;
1679
1680         path = argv[1];
1681         fd = open(path, O_RDONLY);
1682         if (fd < 0) {
1683                 fprintf(stderr, "open \"%s\" failed: %s\n", path,
1684                         strerror(errno));
1685                 return -errno;
1686         }
1687
1688         memset(&desc, 0, sizeof(desc));
1689         obd_str2uuid(&desc.ld_uuid, argv[1]);
1690         desc.ld_tgt_count = ((OBD_MAX_IOCTL_BUFFER-sizeof(data)-sizeof(desc)) /
1691                              (sizeof(*uuidarray) + sizeof(*obdgens)));
1692
1693
1694 repeat:
1695         uuidarray = calloc(desc.ld_tgt_count, sizeof(*uuidarray));
1696         if (!uuidarray) {
1697                 fprintf(stderr, "error: %s: no memory for %d uuid's\n",
1698                         jt_cmdname(argv[0]), desc.ld_tgt_count);
1699                 rc = -ENOMEM;
1700                 goto out;
1701         }
1702         obdgens = calloc(desc.ld_tgt_count, sizeof(*obdgens));
1703         if (!obdgens) {
1704                 fprintf(stderr, "error: %s: no memory for %d generation #'s\n",
1705                         jt_cmdname(argv[0]), desc.ld_tgt_count);
1706                 rc = -ENOMEM;
1707                 goto out_uuidarray;
1708         }
1709
1710         data.ioc_inllen1 = sizeof(desc);
1711         data.ioc_inlbuf1 = (char *)&desc;
1712         data.ioc_inllen2 = desc.ld_tgt_count * sizeof(*uuidarray);
1713         data.ioc_inlbuf2 = (char *)uuidarray;
1714         data.ioc_inllen3 = desc.ld_tgt_count * sizeof(*obdgens);
1715         data.ioc_inlbuf3 = (char *)obdgens;
1716
1717         if (obd_ioctl_pack(&data, &buf, max)) {
1718                 fprintf(stderr, "error: %s: invalid ioctl\n",
1719                         jt_cmdname(argv[0]));
1720                 rc = -EINVAL;
1721                 goto out_obdgens;
1722         }
1723         rc = ioctl(fd, OBD_IOC_LOV_GET_CONFIG, buf);
1724         if (rc == -ENOSPC) {
1725                 free(uuidarray);
1726                 free(obdgens);
1727                 goto repeat;
1728         } else if (rc) {
1729                 fprintf(stderr, "error: %s: ioctl error: %s\n",
1730                         jt_cmdname(argv[0]), strerror(rc = errno));
1731         } else {
1732                 struct obd_uuid *uuidp;
1733                 __u32 *genp;
1734                 int i;
1735
1736                 if (obd_ioctl_unpack(&data, buf, max)) {
1737                         fprintf(stderr, "error: %s: invalid reply\n",
1738                                 jt_cmdname(argv[0]));
1739                         rc = -EINVAL;
1740                         goto out;
1741                 }
1742                 if (desc.ld_default_stripe_count == (__u16)-1)
1743                         printf("default_stripe_count: %d\n", -1);
1744                 else
1745                         printf("default_stripe_count: %u\n",
1746                                desc.ld_default_stripe_count);
1747                 printf("default_stripe_size: "LPU64"\n",
1748                        desc.ld_default_stripe_size);
1749                 printf("default_stripe_offset: "LPU64"\n",
1750                        desc.ld_default_stripe_offset);
1751                 printf("default_stripe_pattern: %u\n", desc.ld_pattern);
1752                 printf("obd_count: %u\n", desc.ld_tgt_count);
1753                 printf("OBDS:\tobdidx\t\tobdgen\t\t obduuid\n");
1754                 uuidp = uuidarray;
1755                 genp = obdgens;
1756                 for (i = 0; i < desc.ld_tgt_count; i++, uuidp++, genp++)
1757                         printf("\t%6u\t%14u\t\t %s\n", i, *genp, (char *)uuidp);
1758         }
1759 out_obdgens:
1760         free(obdgens);
1761 out_uuidarray:
1762         free(uuidarray);
1763 out:
1764         close(fd);
1765         return rc;
1766 }
1767
1768 int jt_obd_ldlm_regress_start(int argc, char **argv)
1769 {
1770         int rc;
1771         struct obd_ioctl_data data;
1772         char argstring[200];
1773         int i, count = sizeof(argstring) - 1;
1774
1775         IOC_INIT(data);
1776         if (argc > 5)
1777                 return CMD_HELP;
1778
1779         argstring[0] = '\0';
1780         for (i = 1; i < argc; i++) {
1781                 strncat(argstring, " ", count);
1782                 count--;
1783                 strncat(argstring, argv[i], count);
1784                 count -= strlen(argv[i]);
1785         }
1786
1787         if (strlen(argstring)) {
1788                 data.ioc_inlbuf1 = argstring;
1789                 data.ioc_inllen1 = strlen(argstring) + 1;
1790         }
1791
1792         IOC_PACK(argv[0], data);
1793         rc = l2_ioctl(OBD_DEV_ID, IOC_LDLM_REGRESS_START, buf);
1794         if (rc)
1795                 fprintf(stderr, "error: %s: test failed: %s\n",
1796                         jt_cmdname(argv[0]), strerror(rc = errno));
1797
1798         return rc;
1799 }
1800
1801 int jt_obd_ldlm_regress_stop(int argc, char **argv)
1802 {
1803         int rc;
1804         struct obd_ioctl_data data;
1805         IOC_INIT(data);
1806
1807         if (argc != 1)
1808                 return CMD_HELP;
1809
1810         IOC_PACK(argv[0], data);
1811         rc = l2_ioctl(OBD_DEV_ID, IOC_LDLM_REGRESS_STOP, buf);
1812
1813         if (rc)
1814                 fprintf(stderr, "error: %s: test failed: %s\n",
1815                         jt_cmdname(argv[0]), strerror(rc = errno));
1816         return rc;
1817 }
1818
1819 static int do_activate(int argc, char **argv, int flag)
1820 {
1821         struct obd_ioctl_data data;
1822         int rc;
1823
1824         IOC_INIT(data);
1825         if (argc != 1)
1826                 return CMD_HELP;
1827
1828         /* reuse offset for 'active' */
1829         data.ioc_offset = flag;
1830
1831         IOC_PACK(argv[0], data);
1832         rc = l2_ioctl(OBD_DEV_ID, IOC_OSC_SET_ACTIVE, buf);
1833         if (rc)
1834                 fprintf(stderr, "error: %s: failed: %s\n",
1835                         jt_cmdname(argv[0]), strerror(rc = errno));
1836
1837         return rc;
1838 }
1839
1840 int jt_obd_deactivate(int argc, char **argv)
1841 {
1842         return do_activate(argc, argv, 0);
1843 }
1844
1845 int jt_obd_activate(int argc, char **argv)
1846 {
1847         return do_activate(argc, argv, 1);
1848 }
1849
1850 int jt_obd_recover(int argc, char **argv)
1851 {
1852         int rc;
1853         struct obd_ioctl_data data;
1854
1855         IOC_INIT(data);
1856         if (argc > 2)
1857                 return CMD_HELP;
1858
1859         if (argc == 2) {
1860                 data.ioc_inllen1 = strlen(argv[1]) + 1;
1861                 data.ioc_inlbuf1 = argv[1];
1862         }
1863
1864         IOC_PACK(argv[0], data);
1865         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_CLIENT_RECOVER, buf);
1866         if (rc < 0) {
1867                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
1868                         strerror(rc = errno));
1869         }
1870
1871         return rc;
1872 }
1873
1874 int jt_obd_mdc_lookup(int argc, char **argv)
1875 {
1876         struct obd_ioctl_data data;
1877         char *parent, *child;
1878         int rc, fd, verbose = 1;
1879
1880         if (argc < 3 || argc > 4)
1881                 return CMD_HELP;
1882
1883         parent = argv[1];
1884         child = argv[2];
1885         if (argc == 4)
1886                 verbose = get_verbose(argv[0], argv[3]);
1887
1888         IOC_INIT(data);
1889
1890         data.ioc_inllen1 = strlen(child) + 1;
1891         data.ioc_inlbuf1 = child;
1892
1893         IOC_PACK(argv[0], data);
1894
1895         fd = open(parent, O_RDONLY);
1896         if (fd < 0) {
1897                 fprintf(stderr, "open \"%s\" failed: %s\n", parent,
1898                         strerror(errno));
1899                 return -1;
1900         }
1901
1902         rc = ioctl(fd, IOC_MDC_LOOKUP, buf);
1903         if (rc < 0) {
1904                 fprintf(stderr, "error: %s: ioctl error: %s\n",
1905                         jt_cmdname(argv[0]), strerror(rc = errno));
1906         }
1907         close(fd);
1908
1909         if (verbose) {
1910                 IOC_UNPACK(argv[0], data);
1911                 printf("%s: mode %o uid %d gid %d\n", child,
1912                        data.ioc_obdo1.o_mode, data.ioc_obdo1.o_uid,
1913                        data.ioc_obdo1.o_gid);
1914         }
1915
1916         return rc;
1917 }
1918
1919 int jt_cfg_dump_log(int argc, char **argv)
1920 {
1921         struct obd_ioctl_data data;
1922         int rc;
1923
1924         IOC_INIT(data);
1925
1926         if (argc != 2)
1927                 return CMD_HELP;
1928
1929         data.ioc_inllen1 = strlen(argv[1]) + 1;
1930         data.ioc_inlbuf1 = argv[1];
1931
1932         IOC_PACK(argv[0], data);
1933         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_DUMP_LOG, buf);
1934         if (rc < 0)
1935                 fprintf(stderr, "OBD_IOC_DUMP_LOG failed: %s\n",
1936                         strerror(errno));
1937
1938         return rc;
1939 }
1940
1941 int jt_llog_catlist(int argc, char **argv)
1942 {
1943         struct obd_ioctl_data data;
1944         int rc;
1945
1946         if (argc != 1)
1947                 return CMD_HELP;
1948
1949         IOC_INIT(data);
1950         data.ioc_inllen1 = max - size_round(sizeof(data));
1951         IOC_PACK(argv[0], data);
1952
1953         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_CATLOGLIST, buf);
1954         if (rc == 0)
1955                 fprintf(stdout, "%s", ((struct obd_ioctl_data*)buf)->ioc_bulk);
1956         else
1957                 fprintf(stderr, "OBD_IOC_CATLOGLIST failed: %s\n",
1958                         strerror(errno));
1959
1960         return rc;
1961 }
1962
1963 int jt_llog_info(int argc, char **argv)
1964 {
1965         struct obd_ioctl_data data;
1966         int rc;
1967
1968         if (argc != 2)
1969                 return CMD_HELP;
1970
1971         IOC_INIT(data);
1972         data.ioc_inllen1 = strlen(argv[1]) + 1;
1973         data.ioc_inlbuf1 = argv[1];
1974         data.ioc_inllen2 = max - size_round(sizeof(data)) -
1975                 size_round(data.ioc_inllen1);
1976         IOC_PACK(argv[0], data);
1977
1978         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_INFO, buf);
1979         if (rc == 0)
1980                 fprintf(stdout, "%s", ((struct obd_ioctl_data*)buf)->ioc_bulk);
1981         else
1982                 fprintf(stderr, "OBD_IOC_LLOG_INFO failed: %s\n",
1983                         strerror(errno));
1984
1985         return rc;
1986 }
1987
1988 int jt_llog_print(int argc, char **argv)
1989 {
1990         struct obd_ioctl_data data;
1991         int rc;
1992
1993         if (argc != 2 && argc != 4)
1994                 return CMD_HELP;
1995
1996         IOC_INIT(data);
1997         data.ioc_inllen1 = strlen(argv[1]) + 1;
1998         data.ioc_inlbuf1 = argv[1];
1999         if (argc == 4) {
2000                 data.ioc_inllen2 = strlen(argv[2]) + 1;
2001                 data.ioc_inlbuf2 = argv[2];
2002                 data.ioc_inllen3 = strlen(argv[3]) + 1;
2003                 data.ioc_inlbuf3 = argv[3];
2004         } else {
2005                 char from[2] = "1", to[3] = "-1";
2006                 data.ioc_inllen2 = strlen(from) + 1;
2007                 data.ioc_inlbuf2 = from;
2008                 data.ioc_inllen3 = strlen(to) + 1;
2009                 data.ioc_inlbuf3 = to;
2010         }
2011         data.ioc_inllen4 = max - size_round(sizeof(data)) -
2012                 size_round(data.ioc_inllen1) -
2013                 size_round(data.ioc_inllen2) -
2014                 size_round(data.ioc_inllen3);
2015         IOC_PACK(argv[0], data);
2016
2017         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_PRINT, buf);
2018         if (rc == 0)
2019                 fprintf(stdout, "%s", ((struct obd_ioctl_data*)buf)->ioc_bulk);
2020         else
2021                 fprintf(stderr, "OBD_IOC_LLOG_PRINT failed: %s\n",
2022                         strerror(errno));
2023
2024         return rc;
2025 }
2026
2027 int jt_llog_cancel(int argc, char **argv)
2028 {
2029         struct obd_ioctl_data data;
2030         int rc;
2031
2032         if (argc != 4)
2033                 return CMD_HELP;
2034
2035         IOC_INIT(data);
2036         data.ioc_inllen1 = strlen(argv[1]) + 1;
2037         data.ioc_inlbuf1 = argv[1];
2038         data.ioc_inllen2 = strlen(argv[2]) + 1;
2039         data.ioc_inlbuf2 = argv[2];
2040         data.ioc_inllen3 = strlen(argv[3]) + 1;
2041         data.ioc_inlbuf3 = argv[3];
2042         IOC_PACK(argv[0], data);
2043
2044         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_CANCEL, buf);
2045         if (rc == 0)
2046                 fprintf(stdout, "index %s be canceled.\n", argv[3]);
2047         else
2048                 fprintf(stderr, "OBD_IOC_LLOG_CANCEL failed: %s\n",
2049                         strerror(errno));
2050
2051         return rc;
2052
2053 }
2054 int jt_llog_check(int argc, char **argv)
2055 {
2056         struct obd_ioctl_data data;
2057         int rc;
2058
2059         if (argc != 2 && argc != 4)
2060                 return CMD_HELP;
2061
2062         IOC_INIT(data);
2063         data.ioc_inllen1 = strlen(argv[1]) + 1;
2064         data.ioc_inlbuf1 = argv[1];
2065         if (argc == 4) {
2066                 data.ioc_inllen2 = strlen(argv[2]) + 1;
2067                 data.ioc_inlbuf2 = argv[2];
2068                 data.ioc_inllen3 = strlen(argv[3]) + 1;
2069                 data.ioc_inlbuf3 = argv[3];
2070         } else {
2071                 char from[2] = "1", to[3] = "-1";
2072                 data.ioc_inllen2 = strlen(from) + 1;
2073                 data.ioc_inlbuf2 = from;
2074                 data.ioc_inllen3 = strlen(to) + 1;
2075                 data.ioc_inlbuf3 = to;
2076         }
2077         data.ioc_inllen4 = max - size_round(sizeof(data)) -
2078                 size_round(data.ioc_inllen1) -
2079                 size_round(data.ioc_inllen2) -
2080                 size_round(data.ioc_inllen3);
2081         IOC_PACK(argv[0], data);
2082
2083         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_CHECK, buf);
2084         if (rc == 0)
2085                 fprintf(stdout, "%s", ((struct obd_ioctl_data*)buf)->ioc_bulk);
2086         else
2087                 fprintf(stderr, "OBD_IOC_LLOG_CHECK failed: %s\n",
2088                         strerror(errno));
2089         return rc;
2090 }
2091
2092 int jt_llog_remove(int argc, char **argv)
2093 {
2094         struct obd_ioctl_data data;
2095         int rc;
2096
2097         if (argc != 3 && argc != 2)
2098                 return CMD_HELP;
2099
2100         IOC_INIT(data);
2101         data.ioc_inllen1 = strlen(argv[1]) + 1;
2102         data.ioc_inlbuf1 = argv[1];
2103         if (argc == 3){
2104                 data.ioc_inllen2 = strlen(argv[2]) + 1;
2105                 data.ioc_inlbuf2 = argv[2];
2106         }
2107         IOC_PACK(argv[0], data);
2108
2109         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_REMOVE, buf);
2110         if (rc == 0) {
2111                 if (argc == 3)
2112                         fprintf(stdout, "log %s are removed.\n", argv[2]);
2113                 else
2114                         fprintf(stdout, "the log in catalog %s are removed. \n", argv[1]);
2115         } else
2116                 fprintf(stderr, "OBD_IOC_LLOG_REMOVE failed: %s\n",
2117                         strerror(errno));
2118
2119         return rc;
2120 }
2121
2122 /* attach a regular file to virtual block device.
2123  * return vaule:
2124  *  -1: fatal error
2125  *  1: error, it always means the command run failed
2126  *  0: success
2127  */
2128 static int jt_blockdev_run_process(const char *file, char *argv[])
2129 {
2130         pid_t pid;
2131         int rc;
2132
2133         pid = vfork();
2134         if (pid == 0) { /* child process */
2135                 /* don't print error messages */
2136                 close(1), close(2);
2137                 (void)execvp(file, argv);
2138                 exit(-1);
2139         } else if (pid > 0) {
2140                 int status;
2141
2142                 rc = waitpid(pid, &status, 0);
2143                 if (rc < 0 || !WIFEXITED(status))
2144                         return -1;
2145
2146                 return WEXITSTATUS(status);
2147         }
2148
2149         return -1;
2150 }
2151
2152 static int jt_blockdev_find_module(const char *module)
2153 {
2154         FILE *fp;
2155         int found = 0;
2156         char modname[256];
2157
2158         fp = fopen("/proc/modules", "r");
2159         if (fp == NULL)
2160                 return -1;
2161
2162         while (fscanf(fp, "%s %*s %*s %*s %*s %*s", modname) == 1) {
2163                 if (strcmp(module, modname) == 0) {
2164                         found = 1;
2165                         break;
2166                 }
2167         }
2168         fclose(fp);
2169
2170         return found;
2171 }
2172
2173 static int jt_blockdev_probe_module(const char *module)
2174 {
2175         char buf[1024];
2176         char *argv[10];
2177         int c, rc;
2178
2179         if (jt_blockdev_find_module(module) == 1)
2180                 return 0;
2181
2182         /* run modprobe first */
2183         c = 0;
2184         argv[c++] = "/sbin/modprobe";
2185         argv[c++] = "-q";
2186         argv[c++] = (char *)module;
2187         argv[c++] = NULL;
2188         rc = jt_blockdev_run_process("modprobe", argv);
2189         if (rc != 1)
2190                 return rc;
2191
2192         /* cannot find the module in default directory ... */
2193         sprintf(buf, "../llite/%s.ko", module);
2194         c = 0;
2195         argv[c++] = "/sbin/insmod";
2196         argv[c++] = buf;
2197         argv[c++] = NULL;
2198         rc = jt_blockdev_run_process("insmod", argv);
2199         return rc ? -1 : 0;
2200 }
2201
2202 int jt_blockdev_attach(int argc, char **argv)
2203 {
2204         int rc, fd;
2205         struct stat st;
2206         char *filename, *devname;
2207         unsigned long dev;
2208
2209         if (argc != 3)
2210                 return CMD_HELP;
2211
2212         if (jt_blockdev_probe_module("llite_lloop") < 0) {
2213                 fprintf(stderr, "error: cannot find module llite_lloop.(k)o\n");
2214                 return ENOENT;
2215         }
2216
2217         filename = argv[1];
2218         devname = argv[2];
2219
2220         fd = open(filename, O_RDWR);
2221         if (fd < 0) {
2222                 fprintf(stderr, "file %s can't be opened(%s)\n\n",
2223                         filename, strerror(errno));
2224                 return CMD_HELP;
2225         }
2226
2227         rc = ioctl(fd, LL_IOC_LLOOP_ATTACH, &dev);
2228         if (rc < 0) {
2229                 rc = errno;
2230                 fprintf(stderr, "attach error(%s)\n", strerror(rc));
2231                 goto out;
2232         }
2233
2234         rc = stat(devname, &st);
2235         if (rc == 0 && (!S_ISBLK(st.st_mode) || st.st_rdev != dev)) {
2236                 rc = EEXIST;
2237         } else if (rc < 0) {
2238                 if (errno == ENOENT &&
2239                     !mknod(devname, S_IFBLK|S_IRUSR|S_IWUSR, dev))
2240                         rc = 0;
2241                 else
2242                         rc = errno;
2243         }
2244
2245         if (rc) {
2246                 fprintf(stderr, "error: the file %s could be attached to block "
2247                                 "device %X but creating %s failed: %s\n"
2248                                 "now detaching the block device..",
2249                         filename, (int)dev, devname, strerror(rc));
2250
2251                 (void)ioctl(fd, LL_IOC_LLOOP_DETACH_BYDEV, dev);
2252                 fprintf(stderr, "%s\n", strerror(errno));
2253         }
2254 out:
2255         close(fd);
2256         return -rc;
2257 }
2258
2259 int jt_blockdev_detach(int argc, char **argv)
2260 {
2261         char *filename;
2262         int rc, fd;
2263
2264         if (argc != 2)
2265                 return CMD_HELP;
2266
2267         filename = argv[1];
2268         fd = open(filename, O_RDONLY);
2269         if (fd < 0) {
2270                 fprintf(stderr, "cannot open file %s error %s\n",
2271                         filename, strerror(errno));
2272                 return CMD_HELP;
2273         }
2274
2275         rc = ioctl(fd, LL_IOC_LLOOP_DETACH, 0);
2276         if (rc < 0) {
2277                 rc = errno;
2278                 fprintf(stderr, "detach error(%s)\n", strerror(rc));
2279         } else {
2280                 (void)unlink(filename);
2281         }
2282
2283         close(fd);
2284         return -rc;
2285 }
2286
2287 int jt_blockdev_info(int argc, char **argv)
2288 {
2289         char *filename;
2290         int rc, fd;
2291         __u64  ino;
2292
2293         if (argc != 2)
2294                 return CMD_HELP;
2295
2296         filename = argv[1];
2297         fd = open(filename, O_RDONLY);
2298         if (fd < 0) {
2299                 fprintf(stderr, "cannot open file %s error: %s\n",
2300                         filename, strerror(errno));
2301                 return CMD_HELP;
2302         }
2303
2304         rc = ioctl(fd, LL_IOC_LLOOP_INFO, &ino);
2305         if (rc < 0) {
2306                 rc = errno;
2307                 fprintf(stderr, "error: %s\n", strerror(errno));
2308                 goto out;
2309         }
2310         fprintf(stdout, "lloop device info: ");
2311         if (ino == 0ULL)
2312                 fprintf(stdout, "Not attached\n");
2313         else
2314                 fprintf(stdout, "attached to inode "LPU64"\n", ino);
2315 out:
2316         close(fd);
2317         return -rc;
2318 }
2319
2320 static void signal_server(int sig)
2321 {
2322         if (sig == SIGINT) {
2323                 do_disconnect("sigint", 1);
2324                 exit(1);
2325         } else
2326                 fprintf(stderr, "%s: got signal %d\n", jt_cmdname("sigint"), sig);
2327 }
2328
2329 int obd_initialize(int argc, char **argv)
2330 {
2331         int i;
2332
2333         for (i = 0; i < MAX_STRIPES; i++)
2334                 lsm_buffer.lsm.lsm_oinfo[i] = lov_oinfos + i;
2335
2336         shmem_setup();
2337         register_ioc_dev(OBD_DEV_ID, OBD_DEV_PATH,
2338                          OBD_DEV_MAJOR, OBD_DEV_MINOR);
2339
2340         return 0;
2341 }
2342
2343 void obd_finalize(int argc, char **argv)
2344 {
2345         struct sigaction sigact;
2346
2347         sigact.sa_handler = signal_server;
2348         sigfillset(&sigact.sa_mask);
2349         sigact.sa_flags = SA_RESTART;
2350         sigaction(SIGINT, &sigact, NULL);
2351
2352         shmem_stop();
2353         do_disconnect(argv[0], 1);
2354 }
2355
2356 static int find_target_obdpath(char *fsname, char *path)
2357 {
2358         glob_t glob_info;
2359         char pattern[MAXPATHLEN + 1];
2360         int rc;
2361
2362         snprintf(pattern, MAXPATHLEN,
2363                  "/proc/fs/lustre/lov/%s-*/target_obd",
2364                  fsname);
2365         rc = glob(pattern, GLOB_BRACE, NULL, &glob_info);
2366         if (rc)
2367                 return -EINVAL;
2368
2369         if (glob_info.gl_pathc == 0) {
2370                 globfree(&glob_info);
2371                 return -EINVAL;
2372         }
2373
2374         strcpy(path, glob_info.gl_pathv[0]);
2375         return 0;
2376 }
2377
2378 static int find_poolpath(char *fsname, char *poolname, char *poolpath)
2379 {
2380         glob_t glob_info;
2381         char pattern[MAXPATHLEN + 1];
2382         int rc;
2383
2384         snprintf(pattern, MAXPATHLEN,
2385                  "/proc/fs/lustre/lov/%s-*/pools/%s",
2386                  fsname, poolname);
2387         rc = glob(pattern, GLOB_BRACE, NULL, &glob_info);
2388         if (rc)
2389                 return -EINVAL;
2390
2391         if (glob_info.gl_pathc == 0) {
2392                 globfree(&glob_info);
2393                 return -EINVAL;
2394         }
2395
2396         strcpy(poolpath, glob_info.gl_pathv[0]);
2397         return 0;
2398 }
2399
2400 /*
2401  * if pool is NULL, search ostname in target_obd
2402  * if pool is no NULL
2403  *  if pool not found returns < 0
2404  *  if ostname is NULL, returns 1 if pool is not empty and 0 if pool empty
2405  *  if ostname is not NULL, returns 1 if OST is in pool and 0 if not
2406  */
2407 static int search_ost(char *fsname, char *poolname, char *ostname)
2408 {
2409         FILE *fd;
2410         char buffer[MAXPATHLEN + 1];
2411         int len = 0, rc;
2412
2413         if (ostname != NULL)
2414                 len = strlen(ostname);
2415
2416         if (poolname == NULL)
2417                 rc = find_target_obdpath(fsname, buffer);
2418         else
2419                 rc = find_poolpath(fsname, poolname, buffer);
2420         if (rc)
2421                 return rc;
2422
2423         if ((fd = fopen(buffer, "r")) == NULL)
2424                 return -EINVAL;
2425
2426         while (fgets(buffer, sizeof(buffer), fd) != NULL) {
2427                 if (poolname == NULL) {
2428                         /* we search ostname in target_obd */
2429                         if (strncmp(buffer + 3, ostname, len) == 0) {
2430                                 fclose(fd);
2431                                 return 1;
2432                         }
2433                 } else {
2434                         /* we search a non empty pool or
2435                            an ostname in a pool */
2436                         if ((ostname == NULL) ||
2437                             (strncmp(buffer, ostname, len) == 0)) {
2438                                 fclose(fd);
2439                                 return 1;
2440                         }
2441                 }
2442         }
2443         fclose(fd);
2444         return 0;
2445 }
2446
2447 static int check_pool_cmd(enum lcfg_command_type cmd,
2448                           char *fsname, char *poolname,
2449                           char *ostname)
2450 {
2451         int rc = 0;
2452
2453         switch (cmd) {
2454         case LCFG_POOL_NEW: {
2455                 if (search_ost(fsname, poolname, NULL) >= 0) {
2456                         fprintf(stderr, "Pool %s.%s already exists\n",
2457                                 fsname, poolname);
2458                         return -EEXIST;
2459                 }
2460                 return 0;
2461         }
2462         case LCFG_POOL_DEL: {
2463                 rc = search_ost(fsname, poolname, NULL);
2464                 if (rc < 0) {
2465                         fprintf(stderr, "Pool %s.%s not found\n",
2466                                 fsname, poolname);
2467                         return -ENOENT;
2468                 }
2469                 if (rc == 1) {
2470                         fprintf(stderr, "Pool %s.%s not empty, "
2471                                 "please remove all members\n",
2472                                 fsname, poolname);
2473                         return -ENOTEMPTY;
2474                 }
2475                 return 0;
2476         }
2477         case LCFG_POOL_ADD: {
2478                 rc = search_ost(fsname, NULL, ostname);
2479                 if (rc == 0) {
2480                         fprintf(stderr, "OST %s not found in lov of %s\n",
2481                                 ostname, fsname);
2482                         return -ENOENT;
2483                 }
2484                 rc = search_ost(fsname, poolname, ostname);
2485                 if (rc < 0) {
2486                         fprintf(stderr, "Pool %s.%s not found\n",
2487                                 fsname, poolname);
2488                         return -ENOENT;
2489                 }
2490                 if (rc == 1) {
2491                         fprintf(stderr, "OST %s already in pool %s.%s\n",
2492                                 ostname, fsname, poolname);
2493                         return -EEXIST;
2494                 }
2495                 return 0;
2496         }
2497         case LCFG_POOL_REM: {
2498                 rc = search_ost(fsname, poolname, ostname);
2499                 if (rc < 0) {
2500                         fprintf(stderr, "Pool %s.%s not found\n",
2501                                 fsname, poolname);
2502                         return -ENOENT;
2503                 }
2504                 if (rc == 0) {
2505                         fprintf(stderr, "OST %s not found in pool %s.%s\n",
2506                                 ostname, fsname, poolname);
2507                         return -ENOENT;
2508                 }
2509                 return 0;
2510         }
2511         default: {
2512         }
2513         }
2514         return 0;
2515 }
2516
2517 static void check_pool_cmd_result(enum lcfg_command_type cmd,
2518                                   char *fsname, char *poolname,
2519                                   char *ostname)
2520 {
2521         int cpt, rc = 0;
2522
2523         cpt = 10;
2524         switch (cmd) {
2525         case LCFG_POOL_NEW: {
2526                 do {
2527                         rc = search_ost(fsname, poolname, NULL);
2528                         if (rc < 0)
2529                                 sleep(2);
2530                         cpt--;
2531                 } while ((rc < 0) && (cpt > 0));
2532                 if (rc >= 0)
2533                         fprintf(stderr, "Pool %s.%s created\n",
2534                                 fsname, poolname);
2535                 else
2536                         fprintf(stderr, "Warning, pool %s.%s not found\n",
2537                                 fsname, poolname);
2538                 return;
2539         }
2540         case LCFG_POOL_DEL: {
2541                 do {
2542                          rc = search_ost(fsname, poolname, NULL);
2543                          if (rc >= 0)
2544                                 sleep(2);
2545                          cpt--;
2546                 } while ((rc >= 0) && (cpt > 0));
2547                 if (rc < 0)
2548                         fprintf(stderr, "Pool %s.%s destroyed\n",
2549                                 fsname, poolname);
2550                 else
2551                         fprintf(stderr, "Warning, pool %s.%s still found\n",
2552                                 fsname, poolname);
2553                 return;
2554         }
2555         case LCFG_POOL_ADD: {
2556                 do {
2557                         rc = search_ost(fsname, poolname, ostname);
2558                         if (rc != 1)
2559                                 sleep(2);
2560                         cpt--;
2561                 } while ((rc != 1) && (cpt > 0));
2562                 if (rc == 1)
2563                         fprintf(stderr, "OST %s added to pool %s.%s\n",
2564                                 ostname, fsname, poolname);
2565                 else
2566                         fprintf(stderr, "Warning, OST %s not found in pool %s.%s\n",
2567                                 ostname, fsname, poolname);
2568                 return;
2569         }
2570         case LCFG_POOL_REM: {
2571                 do {
2572                         rc = search_ost(fsname, poolname, ostname);
2573                         if (rc == 1)
2574                                 sleep(2);
2575                         cpt--;
2576                 } while ((rc == 1) && (cpt > 0));
2577                 if (rc != 1)
2578                         fprintf(stderr, "OST %s removed from pool %s.%s\n",
2579                                 ostname, fsname, poolname);
2580                 else
2581                         fprintf(stderr, "Warning, OST %s still found in pool %s.%s\n",
2582                                 ostname, fsname, poolname);
2583                 return;
2584         }
2585         default: {
2586         }
2587         }
2588 }
2589
2590 static int check_and_complete_ostname(char *fsname, char *ostname)
2591 {
2592         char *ptr;
2593         char real_ostname[MAX_OBD_NAME + 1];
2594         char i;
2595
2596         /* if OST name does not start with fsname, we add it */
2597         /* if not check if the fsname is the right one */
2598         ptr = strchr(ostname, '-');
2599         if (ptr == NULL) {
2600                 sprintf(real_ostname, "%s-%s", fsname, ostname);
2601         } else if (strncmp(ostname, fsname, strlen(fsname)) != 0) {
2602                 fprintf(stderr, "%s does not start with fsname %s\n",
2603                         ostname, fsname);
2604                 return -EINVAL;
2605         } else {
2606              strcpy(real_ostname, ostname);
2607         }
2608         /* real_ostname is fsname-????? */
2609         ptr = real_ostname + strlen(fsname) + 1;
2610         if (strncmp(ptr, "OST", 3) != 0) {
2611                 fprintf(stderr, "%s does not start by %s-OST nor OST\n",
2612                         ostname, fsname);
2613                 return -EINVAL;
2614         }
2615         /* real_ostname is fsname-OST????? */
2616         ptr += 3;
2617         for (i = 0; i < 4; i++) {
2618                 if (!isxdigit(*ptr)) {
2619                         fprintf(stderr,
2620                                 "ost's index in %s is not an hexa number\n",
2621                                 ostname);
2622                         return -EINVAL;
2623                 }
2624                 ptr++;
2625         }
2626         /* real_ostname is fsname-OSTXXXX????? */
2627         /* if OST name does not end with _UUID, we add it */
2628         if (*ptr == '\0') {
2629                 strcat(real_ostname, "_UUID");
2630         } else if (strcmp(ptr, "_UUID") != 0) {
2631                 fprintf(stderr,
2632                         "ostname %s does not end with _UUID\n", ostname);
2633                 return -EINVAL;
2634         }
2635         /* real_ostname is fsname-OSTXXXX_UUID */
2636         strcpy(ostname, real_ostname);
2637         return 0;
2638 }
2639
2640 /* returns 0 or -errno */
2641 static int pool_cmd(enum lcfg_command_type cmd,
2642                     char *cmdname, char *fullpoolname,
2643                     char *fsname, char *poolname, char *ostname)
2644 {
2645         int rc = 0;
2646         struct obd_ioctl_data data;
2647         struct lustre_cfg_bufs bufs;
2648         struct lustre_cfg *lcfg;
2649
2650         rc = check_pool_cmd(cmd, fsname, poolname, ostname);
2651         if (rc)
2652                 return rc;
2653
2654         lustre_cfg_bufs_reset(&bufs, NULL);
2655         lustre_cfg_bufs_set_string(&bufs, 0, cmdname);
2656         lustre_cfg_bufs_set_string(&bufs, 1, fullpoolname);
2657         if (ostname != NULL)
2658                 lustre_cfg_bufs_set_string(&bufs, 2, ostname);
2659
2660         lcfg = lustre_cfg_new(cmd, &bufs);
2661         if (IS_ERR(lcfg)) {
2662                 rc = PTR_ERR(lcfg);
2663                 return rc;
2664         }
2665
2666         IOC_INIT(data);
2667         rc = data.ioc_dev = get_mgs_device();
2668         if (rc < 0)
2669                 goto out;
2670
2671         data.ioc_type = LUSTRE_CFG_TYPE;
2672         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
2673                                         lcfg->lcfg_buflens);
2674         data.ioc_pbuf1 = (void *)lcfg;
2675         IOC_PACK(cmdname, data);
2676
2677         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_POOL, buf);
2678 out:
2679         if (rc)
2680                 rc = -errno;
2681         lustre_cfg_free(lcfg);
2682         return rc;
2683 }
2684
2685 /*
2686  * this function tranforms a rule [start-end/step] into an array
2687  * of matching numbers
2688  * supported forms are:
2689  * [start]                : just this number
2690  * [start-end]            : all numbers from start to end
2691  * [start-end/step]       : numbers from start to end with increment of step
2692  * on return, format contains a printf format string which can be used
2693  * to generate all the strings
2694  */
2695 static int get_array_idx(char *rule, char *format, int **array)
2696 {
2697         char *start, *end, *ptr;
2698         unsigned int lo, hi, step;
2699         int array_sz = 0;
2700         int i, array_idx;
2701         int rc;
2702
2703         start = strchr(rule, '[');
2704         end = strchr(rule, ']');
2705         if ((start == NULL) || (end == NULL)) {
2706                 *array = malloc(sizeof(int));
2707                 if (*array == NULL)
2708                         return 0;
2709                 strcpy(format, rule);
2710                 array_sz = 1;
2711                 return array_sz;
2712         }
2713         *start = '\0';
2714         *end = '\0';
2715         end++;
2716         start++;
2717         /* put in format the printf format (the rule without the range) */
2718         sprintf(format, "%s%%.4d%s", rule, end);
2719
2720         array_idx = 0;
2721         array_sz = 0;
2722         *array = NULL;
2723         /* loop on , separator */
2724         do {
2725                 /* extract the 3 fields */
2726                 rc = sscanf(start, "%u-%u/%u", &lo, &hi, &step);
2727                 switch (rc) {
2728                 case 0: {
2729                         return 0;
2730                 }
2731                 case 1: {
2732                         array_sz++;
2733                         *array = realloc(*array, array_sz * sizeof(int));
2734                         if (*array == NULL)
2735                                 return 0;
2736                         (*array)[array_idx] = lo;
2737                         array_idx++;
2738                         break;
2739                 }
2740                 case 2: {
2741                         step = 1;
2742                         /* do not break to share code with case 3: */
2743                 }
2744                 case 3: {
2745                         if ((hi < lo) || (step == 0))
2746                                 return 0;
2747                         array_sz += (hi - lo) / step + 1;
2748                         *array = realloc(*array, sizeof(int) * array_sz);
2749                         if (*array == NULL)
2750                                 return 0;
2751                         for (i = lo; i <= hi; i+=step, array_idx++)
2752                                 (*array)[array_idx] = i;
2753                         break;
2754                 }
2755                 }
2756                 ptr = strchr(start, ',');
2757                 if (ptr != NULL)
2758                         start = ptr + 1;
2759
2760         } while (ptr != NULL);
2761         return array_sz;
2762 }
2763
2764 static int extract_fsname_poolname(char *arg, char *fsname, char *poolname)
2765 {
2766         char *ptr;
2767         int len;
2768         int rc;
2769
2770         strcpy(fsname, arg);
2771         ptr = strchr(fsname, '.');
2772         if (ptr == NULL) {
2773                 fprintf(stderr, ". is missing in %s\n", fsname);
2774                 rc = -EINVAL;
2775                 goto err;
2776         }
2777
2778         len = ptr - fsname;
2779         if (len == 0) {
2780                 fprintf(stderr, "fsname is empty\n");
2781                 rc = -EINVAL;
2782                 goto err;
2783         }
2784
2785         len = strlen(ptr + 1);
2786         if (len == 0) {
2787                 fprintf(stderr, "poolname is empty\n");
2788                 rc = -EINVAL;
2789                 goto err;
2790         }
2791         if (len > LOV_MAXPOOLNAME) {
2792                 fprintf(stderr,
2793                         "poolname %s is too long (length is %d max is %d)\n",
2794                         ptr + 1, len, LOV_MAXPOOLNAME);
2795                 rc = -ENAMETOOLONG;
2796                 goto err;
2797         }
2798         strncpy(poolname, ptr + 1, LOV_MAXPOOLNAME);
2799         poolname[LOV_MAXPOOLNAME] = '\0';
2800         *ptr = '\0';
2801         return 0;
2802
2803 err:
2804         fprintf(stderr, "argument %s must be <fsname>.<poolname>\n", arg);
2805         return rc;
2806 }
2807
2808 int jt_pool_cmd(int argc, char **argv)
2809 {
2810         enum lcfg_command_type cmd;
2811         char fsname[MAXPATHLEN + 1];
2812         char poolname[LOV_MAXPOOLNAME + 1];
2813         char *ostnames_buf = NULL;
2814         int i, rc;
2815         int *array = NULL, array_sz;
2816         struct {
2817                 int     rc;
2818                 char   *ostname;
2819         } *cmds = NULL;
2820
2821         switch (argc) {
2822         case 0:
2823         case 1: return CMD_HELP;
2824         case 2: {
2825                 if (strcmp("pool_new", argv[0]) == 0)
2826                         cmd = LCFG_POOL_NEW;
2827                 else if (strcmp("pool_destroy", argv[0]) == 0)
2828                         cmd = LCFG_POOL_DEL;
2829                 else if (strcmp("pool_list", argv[0]) == 0)
2830                          return llapi_poollist(argv[1]);
2831                 else return CMD_HELP;
2832
2833                 rc = extract_fsname_poolname(argv[1], fsname, poolname);
2834                 if (rc)
2835                         break;
2836
2837                 rc = pool_cmd(cmd, argv[0], argv[1],
2838                               fsname, poolname, NULL);
2839                 if (rc)
2840                         break;
2841
2842                 check_pool_cmd_result(cmd, fsname, poolname, NULL);
2843                 break;
2844         }
2845         default: {
2846                 char format[2*MAX_OBD_NAME];
2847
2848                 if (strcmp("pool_remove", argv[0]) == 0) {
2849                         cmd = LCFG_POOL_REM;
2850                 } else if (strcmp("pool_add", argv[0]) == 0) {
2851                         cmd = LCFG_POOL_ADD;
2852                 } else {
2853                         return CMD_HELP;
2854                 }
2855
2856                 rc = extract_fsname_poolname(argv[1], fsname, poolname);
2857                 if (rc)
2858                         break;
2859
2860                 for (i = 2; i < argc; i++) {
2861                         int j;
2862
2863                         array_sz = get_array_idx(argv[i], format, &array);
2864                         if (array_sz == 0)
2865                                 return CMD_HELP;
2866
2867                         cmds = malloc(array_sz * sizeof(cmds[0]));
2868                         if (cmds != NULL) {
2869                                 ostnames_buf = malloc(array_sz *
2870                                                       (MAX_OBD_NAME + 1));
2871                         } else {
2872                                 free(array);
2873                                 rc = -ENOMEM;
2874                                 goto out;
2875                         }
2876
2877                         for (j = 0; j < array_sz; j++) {
2878                                 char ostname[MAX_OBD_NAME + 1];
2879
2880                                 snprintf(ostname, MAX_OBD_NAME, format,
2881                                          array[j]);
2882                                 ostname[MAX_OBD_NAME] = '\0';
2883
2884                                 rc = check_and_complete_ostname(fsname,ostname);
2885                                 if (rc) {
2886                                         free(array);
2887                                         free(cmds);
2888                                         if (ostnames_buf)
2889                                                 free(ostnames_buf);
2890                                         goto out;
2891                                 }
2892                                 if (ostnames_buf != NULL) {
2893                                         cmds[j].ostname =
2894                                           &ostnames_buf[(MAX_OBD_NAME + 1) * j];
2895                                         strcpy(cmds[j].ostname, ostname);
2896                                 } else {
2897                                         cmds[j].ostname = NULL;
2898                                 }
2899                                 cmds[j].rc = pool_cmd(cmd, argv[0], argv[1],
2900                                                       fsname, poolname,
2901                                                       ostname);
2902                         }
2903                         for (j = 0; j < array_sz; j++) {
2904                                 if (!cmds[j].rc) {
2905                                         char ostname[MAX_OBD_NAME + 1];
2906
2907                                         if (!cmds[j].ostname) {
2908                                                 snprintf(ostname, MAX_OBD_NAME,
2909                                                          format, array[j]);
2910                                                 ostname[MAX_OBD_NAME] = '\0';
2911                                                 check_and_complete_ostname(
2912                                                         fsname, ostname);
2913                                         } else {
2914                                                 strcpy(ostname,
2915                                                        cmds[j].ostname);
2916                                         }
2917                                         check_pool_cmd_result(cmd, fsname,
2918                                                               poolname,ostname);
2919                                 }
2920                         }
2921                         if (array_sz > 0)
2922                                 free(array);
2923                         if (cmds)
2924                                 free(cmds);
2925                         if (ostnames_buf);
2926                                 free(ostnames_buf);
2927                 }
2928                 return 0;
2929         }
2930         }
2931
2932
2933 out:
2934         if ((rc == -EINVAL) || (rc == -ENOENT))
2935                 fprintf(stderr, "Does the fs, pool or ost exist?\n");
2936         if (rc != 0) {
2937                 errno = -rc;
2938                 perror(argv[0]);
2939         }
2940
2941         return rc;
2942 }
2943
2944 void  llapi_ping_target(char *obd_type, char *obd_name,
2945                         char *obd_uuid, void *args)
2946 {
2947         int  rc;
2948         struct obd_ioctl_data data;
2949
2950         memset(&data, 0, sizeof(data));
2951         data.ioc_inlbuf4 = obd_name;
2952         data.ioc_inllen4 = strlen(obd_name) + 1;
2953         data.ioc_dev = OBD_DEV_BY_DEVNAME;
2954         memset(buf, 0, sizeof(rawbuf));
2955         if (obd_ioctl_pack(&data, &buf, max)) {
2956                 fprintf(stderr, "error: invalid ioctl\n");
2957                 return;
2958         }
2959         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_PING_TARGET, buf);
2960         if (rc)
2961                 rc = errno;
2962         if (rc == ENOTCONN || rc == ESHUTDOWN) {
2963                 printf("%s inactive.\n", obd_name);
2964         } else if (rc) {
2965                 fprintf(stderr, "error: check '%s' %s\n",
2966                         obd_name, strerror(errno));
2967         } else {
2968                 printf("%s active.\n", obd_name);
2969         }
2970
2971 }