Whamcloud - gitweb
Branch HEAD
[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  *  Copyright (C) 2002 Cluster File Systems, Inc.
5  *   Author: Peter J. Braam <braam@clusterfs.com>
6  *   Author: Phil Schwan <phil@clusterfs.com>
7  *   Author: Andreas Dilger <adilger@clusterfs.com>
8  *   Author: Robert Read <rread@clusterfs.com>
9  *
10  *   This file is part of Lustre, http://www.lustre.org.
11  *
12  *   Lustre is free software; you can redistribute it and/or
13  *   modify it under the terms of version 2 of the GNU General Public
14  *   License as published by the Free Software Foundation.
15  *
16  *   Lustre is distributed in the hope that it will be useful,
17  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *   GNU General Public License for more details.
20  *
21  *   You should have received a copy of the GNU General Public License
22  *   along with Lustre; if not, write to the Free Software
23  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  *
25  */
26
27 #include <stdlib.h>
28 #include <sys/ioctl.h>
29 #include <fcntl.h>
30 #include <sys/socket.h>
31 #include <sys/types.h>
32 #include <sys/wait.h>
33 #include <sys/stat.h>
34 #include <stdio.h>
35 #include <stdarg.h>
36 #include <signal.h>
37 #include <ctype.h>
38
39 #include "obdctl.h"
40
41 #include <obd.h>          /* for struct lov_stripe_md */
42 #include <lustre/lustre_build_version.h>
43
44 #include <unistd.h>
45 #include <sys/un.h>
46 #include <time.h>
47 #include <sys/time.h>
48 #include <errno.h>
49 #include <string.h>
50
51 #ifdef HAVE_ASM_PAGE_H
52 #include <asm/page.h>           /* needed for PAGE_SIZE - rread */
53 #endif
54
55 #include <obd_class.h>
56 #include <lnet/lnetctl.h>
57 #include "parser.h"
58 #include "platform.h"
59 #include <stdio.h>
60
61 #define MAX_STRING_SIZE 128
62 #define DEVICES_LIST "/proc/fs/lustre/devices"
63
64 #if HAVE_LIBPTHREAD
65 #include <sys/ipc.h>
66 #include <sys/shm.h>
67 #include <pthread.h>
68
69 #define MAX_THREADS 1024
70
71 struct shared_data {
72         __u64 counters[MAX_THREADS];
73         __u64 offsets[MAX_THREADS];
74         int   running;
75         int   barrier;
76         int   stop;
77         l_mutex_t mutex;
78         l_cond_t  cond;
79 };
80
81 static struct shared_data *shared_data;
82 static __u64 counter_snapshot[2][MAX_THREADS];
83 static int prev_valid;
84 static struct timeval prev_time;
85 static int thread;
86 static int nthreads;
87 #else
88 const int thread = 0;
89 const int nthreads = 1;
90 #endif
91
92 static char rawbuf[8192];
93 static char *buf = rawbuf;
94 static int max = sizeof(rawbuf);
95
96 static int cur_device = -1;
97
98 #define MAX_STRIPES     170
99 struct lov_oinfo lov_oinfos[MAX_STRIPES];
100
101 struct lsm_buffer {
102         struct lov_stripe_md lsm;
103         struct lov_oinfo *ptrs[MAX_STRIPES];
104 } lsm_buffer;
105
106 static int l2_ioctl(int dev_id, int opc, void *buf)
107 {
108         return l_ioctl(dev_id, opc, buf);
109 }
110
111 #define IOC_INIT(data)                                                  \
112 do {                                                                    \
113         memset(&data, 0, sizeof(data));                                 \
114         data.ioc_dev = cur_device;                                      \
115 } while (0)
116
117 #define IOC_PACK(func, data)                                            \
118 do {                                                                    \
119         memset(buf, 0, sizeof(rawbuf));                                 \
120         if (obd_ioctl_pack(&data, &buf, max)) {                         \
121                 fprintf(stderr, "error: %s: invalid ioctl\n",           \
122                         jt_cmdname(func));                                 \
123                 return -2;                                              \
124         }                                                               \
125 } while (0)
126
127 #define IOC_UNPACK(func, data)                                          \
128 do {                                                                    \
129         if (obd_ioctl_unpack(&data, buf, max)) {                        \
130                 fprintf(stderr, "error: %s: invalid reply\n",           \
131                         jt_cmdname(func));                                 \
132                 return -2;                                              \
133         }                                                               \
134 } while (0)
135
136 int lcfg_ioctl(char * func, int dev_id, struct lustre_cfg *lcfg)
137 {
138         struct obd_ioctl_data data;
139         int rc;
140
141         IOC_INIT(data);
142         data.ioc_type = LUSTRE_CFG_TYPE;
143         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
144                                         lcfg->lcfg_buflens);
145         data.ioc_pbuf1 = (void *)lcfg;
146         IOC_PACK(func, data);
147
148         rc =  l_ioctl(dev_id, OBD_IOC_PROCESS_CFG, buf);
149
150         return rc;
151 }
152
153 static int do_device(char *func, char *devname);
154
155 int lcfg_mgs_ioctl(char *func, int dev_id, struct lustre_cfg *lcfg)
156 {
157         struct obd_ioctl_data data;
158         static int mgs_device = -1;
159         char mgs[] = "$MGS";
160         int rc;
161
162         /* Always operates on MGS dev */
163         if (mgs_device == -1) {
164                 do_disconnect(NULL, 1);
165                 rc = do_device("mgsioc", mgs);
166                 if (rc) {
167                         errno = ENODEV;
168                         return -1;
169                 }
170                 mgs_device = cur_device;
171         }
172
173         IOC_INIT(data);
174         data.ioc_dev = mgs_device;
175         data.ioc_type = LUSTRE_CFG_TYPE;
176         data.ioc_plen1 = lustre_cfg_len(lcfg->lcfg_bufcount,
177                                         lcfg->lcfg_buflens);
178         data.ioc_pbuf1 = (void *)lcfg;
179         IOC_PACK(func, data);
180
181         rc =  l_ioctl(dev_id, OBD_IOC_PARAM, buf);
182
183         if (rc == ENODEV)
184                 fprintf(stderr, "Is the MGS running on this node?\n");
185         if (rc == ENOSYS)
186                 fprintf(stderr, "Make sure cfg_device is set first.\n");
187         if (rc == EINVAL)
188                 fprintf(stderr, "cfg_device should be of the form "
189                         "'lustre-MDT0000'\n");
190
191         return rc;
192 }
193
194 char *obdo_print(struct obdo *obd)
195 {
196         char buf[1024];
197
198         sprintf(buf, "id: "LPX64"\ngrp: "LPX64"\natime: "LPU64"\nmtime: "LPU64
199                 "\nctime: "LPU64"\nsize: "LPU64"\nblocks: "LPU64
200                 "\nblksize: %u\nmode: %o\nuid: %d\ngid: %d\nflags: %x\n"
201                 "misc: %x\nnlink: %d,\nvalid "LPX64"\n",
202                 obd->o_id, obd->o_gr, obd->o_atime, obd->o_mtime, obd->o_ctime,
203                 obd->o_size, obd->o_blocks, obd->o_blksize, obd->o_mode,
204                 obd->o_uid, obd->o_gid, obd->o_flags, obd->o_misc,
205                 obd->o_nlink, obd->o_valid);
206         return strdup(buf);
207 }
208
209
210 #define BAD_VERBOSE (-999999999)
211
212 #define N2D_OFF 0x100      /* So we can tell between error codes and devices */
213
214 static int do_name2dev(char *func, char *name)
215 {
216         struct obd_ioctl_data data;
217         int rc;
218
219         IOC_INIT(data);
220
221         data.ioc_inllen1 = strlen(name) + 1;
222         data.ioc_inlbuf1 = name;
223
224         IOC_PACK(func, data);
225         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_NAME2DEV, buf);
226         if (rc < 0)
227                 return errno;
228         IOC_UNPACK(func, data);
229
230         return data.ioc_dev + N2D_OFF;
231 }
232
233 /*
234  * resolve a device name to a device number.
235  * supports a number, $name or %uuid.
236  */
237 int parse_devname(char *func, char *name)
238 {
239         int rc;
240         int ret = -1;
241
242         if (!name)
243                 return ret;
244         if (isdigit(name[0])) {
245                 ret = strtoul(name, NULL, 0);
246         } else {
247                 if (name[0] == '$' || name[0] == '%')
248                         name++;
249                 rc = do_name2dev(func, name);
250                 if (rc >= N2D_OFF) {
251                         ret = rc - N2D_OFF;
252                         // printf("Name %s is device %d\n", name, ret);
253                 } else {
254                         fprintf(stderr, "No device found for name %s: %s\n",
255                                name, strerror(rc));
256                 }
257         }
258         return ret;
259 }
260
261 static void
262 reset_lsmb (struct lsm_buffer *lsmb)
263 {
264         memset (&lsmb->lsm, 0, sizeof (lsmb->lsm));
265         memset(lov_oinfos, 0, sizeof(lov_oinfos));
266         lsmb->lsm.lsm_magic = LOV_MAGIC;
267 }
268
269 static int
270 parse_lsm (struct lsm_buffer *lsmb, char *string)
271 {
272         struct lov_stripe_md *lsm = &lsmb->lsm;
273         char                 *end;
274         int                   i;
275
276         /*
277          * object_id[=size#count[@offset:id]*]
278          */
279
280         reset_lsmb (lsmb);
281
282         lsm->lsm_object_id = strtoull (string, &end, 0);
283         if (end == string)
284                 return (-1);
285         string = end;
286
287         if (*string == 0)
288                 return (0);
289
290         if (*string != '=')
291                 return (-1);
292         string++;
293
294         lsm->lsm_stripe_size = strtoul (string, &end, 0);
295         if (end == string)
296                 return (-1);
297         string = end;
298
299         if (*string != '#')
300                 return (-1);
301         string++;
302
303         lsm->lsm_stripe_count = strtoul (string, &end, 0);
304         if (end == string)
305                 return (-1);
306         string = end;
307
308         if (*string == 0)               /* don't have to specify obj ids */
309                 return (0);
310
311         for (i = 0; i < lsm->lsm_stripe_count; i++) {
312                 if (*string != '@')
313                         return (-1);
314                 string++;
315                 lsm->lsm_oinfo[i]->loi_ost_idx = strtoul(string, &end, 0);
316                 if (*end != ':')
317                         return (-1);
318                 string = end + 1;
319                 lsm->lsm_oinfo[i]->loi_id = strtoull(string, &end, 0);
320                 string = end;
321         }
322
323         if (*string != 0)
324                 return (-1);
325
326         return (0);
327 }
328
329 char *jt_cmdname(char *func)
330 {
331         static char buf[512];
332
333         if (thread) {
334                 sprintf(buf, "%s-%d", func, thread);
335                 return buf;
336         }
337
338         return func;
339 }
340
341 #define difftime(a, b)                                  \
342         ((a)->tv_sec - (b)->tv_sec +                    \
343          ((a)->tv_usec - (b)->tv_usec) / 1000000.0)
344
345 static int be_verbose(int verbose, struct timeval *next_time,
346                       __u64 num, __u64 *next_num, int num_total)
347 {
348         struct timeval now;
349
350         if (!verbose)
351                 return 0;
352
353         if (next_time != NULL)
354                 gettimeofday(&now, NULL);
355
356         /* A positive verbosity means to print every X iterations */
357         if (verbose > 0 && (num >= *next_num || num >= num_total)) {
358                 *next_num += verbose;
359                 if (next_time) {
360                         next_time->tv_sec = now.tv_sec - verbose;
361                         next_time->tv_usec = now.tv_usec;
362                 }
363                 return 1;
364         }
365
366         /* A negative verbosity means to print at most each X seconds */
367         if (verbose < 0 && next_time != NULL &&
368             difftime(&now, next_time) >= 0.0){
369                 next_time->tv_sec = now.tv_sec - verbose;
370                 next_time->tv_usec = now.tv_usec;
371                 *next_num = num;
372                 return 1;
373         }
374
375         return 0;
376 }
377
378 static int get_verbose(char *func, const char *arg)
379 {
380         int verbose;
381         char *end;
382
383         if (!arg || arg[0] == 'v')
384                 verbose = 1;
385         else if (arg[0] == 's' || arg[0] == 'q')
386                 verbose = 0;
387         else {
388                 verbose = (int)strtoul(arg, &end, 0);
389                 if (*end) {
390                         fprintf(stderr, "error: %s: bad verbose option '%s'\n",
391                                 jt_cmdname(func), arg);
392                         return BAD_VERBOSE;
393                 }
394         }
395
396         if (verbose < 0)
397                 printf("Print status every %d seconds\n", -verbose);
398         else if (verbose == 1)
399                 printf("Print status every operation\n");
400         else if (verbose > 1)
401                 printf("Print status every %d operations\n", verbose);
402
403         return verbose;
404 }
405
406 int do_disconnect(char *func, int verbose)
407 {
408         lcfg_set_devname(NULL);
409         cur_device = -1;
410         return 0;
411 }
412
413 #ifdef MAX_THREADS
414 static void shmem_setup(void)
415 {
416         /* Create new segment */
417         int shmid = shmget(IPC_PRIVATE, sizeof(*shared_data), 0600);
418
419         if (shmid == -1) {
420                 fprintf(stderr, "Can't create shared data: %s\n",
421                         strerror(errno));
422                 return;
423         }
424
425         /* Attatch to new segment */
426         shared_data = (struct shared_data *)shmat(shmid, NULL, 0);
427
428         if (shared_data == (struct shared_data *)(-1)) {
429                 fprintf(stderr, "Can't attach shared data: %s\n",
430                         strerror(errno));
431                 shared_data = NULL;
432                 return;
433         }
434
435         /* Mark segment as destroyed, so it will disappear when we exit.
436          * Forks will inherit attached segments, so we should be OK.
437          */
438         if (shmctl(shmid, IPC_RMID, NULL) == -1) {
439                 fprintf(stderr, "Can't destroy shared data: %s\n",
440                         strerror(errno));
441         }
442 }
443
444 static inline void shmem_lock(void)
445 {
446         l_mutex_lock(&shared_data->mutex);
447 }
448
449 static inline void shmem_unlock(void)
450 {
451         l_mutex_unlock(&shared_data->mutex);
452 }
453
454 static inline void shmem_reset(int total_threads)
455 {
456         if (shared_data == NULL)
457                 return;
458
459         memset(shared_data, 0, sizeof(*shared_data));
460         l_mutex_init(&shared_data->mutex);
461         l_cond_init(&shared_data->cond);
462         memset(counter_snapshot, 0, sizeof(counter_snapshot));
463         prev_valid = 0;
464         shared_data->barrier = total_threads;
465 }
466
467 static inline void shmem_bump(void)
468 {
469         static int bumped_running;
470
471         if (shared_data == NULL || thread <= 0 || thread > MAX_THREADS)
472                 return;
473
474         shmem_lock();
475         shared_data->counters[thread - 1]++;
476         if (!bumped_running)
477                 shared_data->running++;
478         shmem_unlock();
479         bumped_running = 1;
480 }
481
482 static void shmem_snap(int total_threads, int live_threads)
483 {
484         struct timeval this_time;
485         int non_zero = 0;
486         __u64 total = 0;
487         double secs;
488         int running;
489         int i;
490
491         if (shared_data == NULL || total_threads > MAX_THREADS)
492                 return;
493
494         shmem_lock();
495         memcpy(counter_snapshot[0], shared_data->counters,
496                total_threads * sizeof(counter_snapshot[0][0]));
497         running = shared_data->running;
498         shmem_unlock();
499
500         gettimeofday(&this_time, NULL);
501
502         for (i = 0; i < total_threads; i++) {
503                 long long this_count =
504                         counter_snapshot[0][i] - counter_snapshot[1][i];
505
506                 if (this_count != 0) {
507                         non_zero++;
508                         total += this_count;
509                 }
510         }
511
512         secs = (this_time.tv_sec + this_time.tv_usec / 1000000.0) -
513                (prev_time.tv_sec + prev_time.tv_usec / 1000000.0);
514
515         if (prev_valid &&
516             live_threads == total_threads &&
517             secs > 0.0)                    /* someone screwed with the time? */
518                 printf("%d/%d Total: %f/second\n", non_zero, total_threads, total / secs);
519
520         memcpy(counter_snapshot[1], counter_snapshot[0],
521                total_threads * sizeof(counter_snapshot[0][0]));
522         prev_time = this_time;
523         if (!prev_valid &&
524             running == total_threads)
525                 prev_valid = 1;
526 }
527
528 static void shmem_stop(void)
529 {
530         if (shared_data == NULL)
531                 return;
532
533         shared_data->stop = 1;
534 }
535
536 static int shmem_running(void)
537 {
538         return (shared_data == NULL ||
539                 !shared_data->stop);
540 }
541 #else
542 static void shmem_setup(void)
543 {
544 }
545
546 static inline void shmem_reset(int total_threads)
547 {
548 }
549
550 static inline void shmem_bump(void)
551 {
552 }
553
554 static void shmem_lock()
555 {
556 }
557
558 static void shmem_unlock()
559 {
560 }
561
562 static void shmem_stop(void)
563 {
564 }
565
566 static int shmem_running(void)
567 {
568         return 1;
569 }
570 #endif
571
572 extern command_t cmdlist[];
573
574 static int do_device(char *func, char *devname)
575 {
576         int dev;
577
578         dev = parse_devname(func, devname);
579         if (dev < 0)
580                 return -1;
581
582         lcfg_set_devname(devname);
583         cur_device = dev;
584         return 0;
585 }
586
587 int jt_obd_get_device()
588 {
589         return cur_device;
590 }
591
592 int jt_obd_device(int argc, char **argv)
593 {
594         int rc;
595
596         if (argc > 2)
597                 return CMD_HELP;
598
599         if (argc == 1) {
600                 printf("current device is %d - %s\n",
601                        cur_device, lcfg_get_devname() ? : "not set");
602                 return 0;
603         }
604         rc = do_device("device", argv[1]);
605         return rc;
606 }
607
608 int jt_opt_device(int argc, char **argv)
609 {
610         int ret;
611         int rc;
612
613         if (argc < 3)
614                 return CMD_HELP;
615
616         rc = do_device("device", argv[1]);
617
618         if (!rc)
619                 rc = Parser_execarg(argc - 2, argv + 2, cmdlist);
620
621         ret = do_disconnect(argv[0], 0);
622         if (!rc)
623                 rc = ret;
624
625         return rc;
626 }
627
628 #ifdef MAX_THREADS
629 static void parent_sighandler (int sig)
630 {
631         return;
632 }
633
634 int jt_opt_threads(int argc, char **argv)
635 {
636         static char      cmdstr[128];
637         sigset_t         saveset;
638         sigset_t         sigset;
639         struct sigaction sigact;
640         struct sigaction saveact1;
641         struct sigaction saveact2;
642         unsigned long    threads;
643         __u64            next_thread;
644         int verbose;
645         int rc = 0;
646         int report_count = -1;
647         char *end;
648         int i;
649
650         if (argc < 5)
651                 return CMD_HELP;
652
653         threads = strtoul(argv[1], &end, 0);
654
655         if (*end == '.')
656                 report_count = strtoul(end + 1, &end, 0);
657
658         if (*end || threads > MAX_THREADS) {
659                 fprintf(stderr, "error: %s: invalid thread count '%s'\n",
660                         jt_cmdname(argv[0]), argv[1]);
661                 return CMD_HELP;
662         }
663
664         verbose = get_verbose(argv[0], argv[2]);
665         if (verbose == BAD_VERBOSE)
666                 return CMD_HELP;
667
668         if (verbose != 0) {
669                 snprintf(cmdstr, sizeof(cmdstr), "%s", argv[4]);
670                 for (i = 5; i < argc; i++)
671                         snprintf(cmdstr + strlen(cmdstr), sizeof(cmdstr),
672                                  " %s", argv[i]);
673
674                 printf("%s: starting %ld threads on device %s running %s\n",
675                        argv[0], threads, argv[3], cmdstr);
676         }
677
678         shmem_reset(threads);
679
680         sigemptyset(&sigset);
681         sigaddset(&sigset, SIGALRM);
682         sigaddset(&sigset, SIGCHLD);
683         sigprocmask(SIG_BLOCK, &sigset, &saveset);
684
685         nthreads = threads;
686
687         for (i = 1, next_thread = verbose; i <= threads; i++) {
688                 rc = fork();
689                 if (rc < 0) {
690                         fprintf(stderr, "error: %s: #%d - %s\n", argv[0], i,
691                                 strerror(rc = errno));
692                         break;
693                 } else if (rc == 0) {
694                         sigprocmask(SIG_SETMASK, &saveset, NULL);
695
696                         thread = i;
697                         argv[2] = "--device";
698                         return jt_opt_device(argc - 2, argv + 2);
699                 } else if (be_verbose(verbose, NULL, i, &next_thread, threads))
700                         printf("%s: thread #%d (PID %d) started\n",
701                                argv[0], i, rc);
702                 rc = 0;
703         }
704
705         if (!thread) {          /* parent process */
706                 int live_threads = threads;
707
708                 sigemptyset(&sigset);
709                 sigemptyset(&sigact.sa_mask);
710                 sigact.sa_handler = parent_sighandler;
711                 sigact.sa_flags = 0;
712
713                 sigaction(SIGALRM, &sigact, &saveact1);
714                 sigaction(SIGCHLD, &sigact, &saveact2);
715
716                 while (live_threads > 0) {
717                         int status;
718                         pid_t ret;
719
720                         if (verbose < 0)        /* periodic stats */
721                                 alarm(-verbose);
722
723                         sigsuspend(&sigset);
724                         alarm(0);
725
726                         while (live_threads > 0) {
727                                 ret = waitpid(0, &status, WNOHANG);
728                                 if (ret == 0)
729                                         break;
730
731                                 if (ret < 0) {
732                                         fprintf(stderr, "error: %s: wait - %s\n",
733                                                 argv[0], strerror(errno));
734                                         if (!rc)
735                                                 rc = errno;
736                                         continue;
737                                 } else {
738                                         /*
739                                          * This is a hack.  We _should_ be able
740                                          * to use WIFEXITED(status) to see if
741                                          * there was an error, but it appears
742                                          * to be broken and it always returns 1
743                                          * (OK).  See wait(2).
744                                          */
745                                         int err = WEXITSTATUS(status);
746                                         if (err || WIFSIGNALED(status))
747                                                 fprintf(stderr,
748                                                         "%s: PID %d had rc=%d\n",
749                                                         argv[0], ret, err);
750                                         if (!rc)
751                                                 rc = err;
752
753                                         live_threads--;
754                                 }
755                         }
756
757                         /* Show stats while all threads running */
758                         if (verbose < 0) {
759                                 shmem_snap(threads, live_threads);
760                                 if (report_count > 0 && --report_count == 0)
761                                         shmem_stop();
762                         }
763                 }
764                 sigaction(SIGCHLD, &saveact2, NULL);
765                 sigaction(SIGALRM, &saveact1, NULL);
766         }
767
768         sigprocmask(SIG_SETMASK, &saveset, NULL);
769
770         return rc;
771 }
772 #else
773 int jt_opt_threads(int argc, char **argv)
774 {
775         fprintf(stderr, "%s not-supported in a single-threaded runtime\n",
776                 jt_cmdname(argv[0]));
777         return CMD_HELP;
778 }
779 #endif
780
781 int jt_opt_net(int argc, char **argv)
782 {
783         char *arg2[3];
784         int rc;
785
786         if (argc < 3)
787                 return CMD_HELP;
788
789         arg2[0] = argv[0];
790         arg2[1] = argv[1];
791         arg2[2] = NULL;
792         rc = jt_ptl_network (2, arg2);
793
794         if (!rc)
795                 rc = Parser_execarg(argc - 2, argv + 2, cmdlist);
796
797         return rc;
798 }
799
800 int jt_obd_no_transno(int argc, char **argv)
801 {
802         struct obd_ioctl_data data;
803         int rc;
804
805         IOC_INIT(data);
806
807         if (argc != 1)
808                 return CMD_HELP;
809
810         IOC_PACK(argv[0], data);
811         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_NO_TRANSNO, buf);
812         if (rc < 0)
813                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
814                         strerror(rc = errno));
815
816         return rc;
817 }
818
819 int jt_obd_set_readonly(int argc, char **argv)
820 {
821         struct obd_ioctl_data data;
822         int rc;
823
824         IOC_INIT(data);
825
826         if (argc != 1)
827                 return CMD_HELP;
828
829         IOC_PACK(argv[0], data);
830         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_SET_READONLY, buf);
831         if (rc < 0)
832                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
833                         strerror(rc = errno));
834
835         return rc;
836 }
837
838 int jt_obd_abort_recovery(int argc, char **argv)
839 {
840         struct obd_ioctl_data data;
841         int rc;
842
843         IOC_INIT(data);
844
845         if (argc != 1)
846                 return CMD_HELP;
847
848         IOC_PACK(argv[0], data);
849         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_ABORT_RECOVERY, buf);
850         if (rc < 0)
851                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
852                         strerror(rc = errno));
853
854         return rc;
855 }
856
857 int jt_get_version(int argc, char **argv)
858 {
859         int rc;
860         char buf[8192];
861         struct obd_ioctl_data *data = (struct obd_ioctl_data *)buf;
862
863         if (argc != 1)
864                 return CMD_HELP;
865
866         memset(buf, 0, sizeof(buf));
867         data->ioc_version = OBD_IOCTL_VERSION;
868         data->ioc_inllen1 = sizeof(buf) - size_round(sizeof(*data));
869         data->ioc_inlbuf1 = buf + size_round(sizeof(*data));
870         data->ioc_len = obd_ioctl_packlen(data);
871
872         rc = l2_ioctl(OBD_DEV_ID, OBD_GET_VERSION, buf);
873         if (rc < 0)
874                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
875                         strerror(rc = errno));
876         else {
877                 printf("Lustre version: %s\n", data->ioc_bulk);
878         }
879
880         printf("lctl   version: %s\n", BUILD_VERSION);
881         return rc;
882 }
883
884 /*
885  * Print an obd device line with the ost_conn_uuid inserted, if the obd
886  * is an osc.
887  */
888 static void print_obd_line(char *s)
889 {
890         char buf[MAX_STRING_SIZE];
891         char obd_name[MAX_OBD_NAME];
892         FILE *fp = NULL;
893         char *ptr;
894
895         if (sscanf(s, " %*d %*s osc %s %*s %*d ", obd_name) == 0)
896                 goto try_mdc;
897         snprintf(buf, sizeof(buf),
898                  "/proc/fs/lustre/osc/%s/ost_conn_uuid", obd_name);
899         if ((fp = fopen(buf, "r")) == NULL)
900                 goto try_mdc;
901         goto got_one;
902
903 try_mdc:
904         if (sscanf(s, " %*d %*s mdc %s %*s %*d ", obd_name) == 0)
905                 goto fail;
906         snprintf(buf, sizeof(buf),
907                  "/proc/fs/lustre/mdc/%s/mds_conn_uuid", obd_name);
908         if ((fp = fopen(buf, "r")) == NULL)
909                 goto fail;
910
911 got_one:
912         fgets(buf, sizeof(buf), fp);
913         fclose(fp);
914
915         /* trim trailing newlines */
916         ptr = strrchr(buf, '\n');
917         if (ptr) *ptr = '\0';
918         ptr = strrchr(s, '\n');
919         if (ptr) *ptr = '\0';
920
921         printf("%s %s\n", s, buf);
922         return;
923
924 fail:
925         printf("%s", s);
926         return;
927 }
928
929 /* get device list by ioctl */
930 int jt_obd_list_ioctl(int argc, char **argv)
931 {
932         int rc, index;
933         char buf[8192];
934         struct obd_ioctl_data *data = (struct obd_ioctl_data *)buf;
935
936         if (argc > 2)
937                 return CMD_HELP;
938         /* Just ignore a -t option.  Only supported with /proc. */
939         else if (argc == 2 && strcmp(argv[1], "-t") != 0)
940                 return CMD_HELP;
941
942         for (index = 0;; index++) {
943                 memset(buf, 0, sizeof(buf));
944                 data->ioc_version = OBD_IOCTL_VERSION;
945                 data->ioc_inllen1 = sizeof(buf) - size_round(sizeof(*data));
946                 data->ioc_inlbuf1 = buf + size_round(sizeof(*data));
947                 data->ioc_len = obd_ioctl_packlen(data);
948                 data->ioc_count = index;
949
950                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_GETDEVICE, buf);
951                 if (rc != 0)
952                         break;
953                 printf("%s\n", (char *)data->ioc_bulk);
954         }
955         if (rc != 0) {
956                 if (errno == ENOENT)
957                         /* no device or the last device */
958                         rc = 0;
959                 else
960                         fprintf(stderr, "Error getting device list: %s: "
961                                         "check dmesg.\n",
962                                         strerror(errno));
963         }
964         return rc;
965 }
966
967 int jt_obd_list(int argc, char **argv)
968 {
969         int rc;
970         char buf[MAX_STRING_SIZE];
971         FILE *fp = NULL;
972         int print_obd = 0;
973
974         if (argc > 2)
975                 return CMD_HELP;
976         else if (argc == 2) {
977                 if (strcmp(argv[1], "-t") == 0)
978                         print_obd = 1;
979                 else
980                         return CMD_HELP;
981         }
982
983         fp = fopen(DEVICES_LIST, "r");
984         if (fp == NULL) {
985                 fprintf(stderr, "error: %s: %s opening "DEVICES_LIST"\n",
986                         jt_cmdname(argv[0]), strerror(rc =  errno));
987                 return jt_obd_list_ioctl(argc, argv);
988         }
989
990         while (fgets(buf, sizeof(buf), fp) != NULL)
991                 if (print_obd)
992                         print_obd_line(buf);
993                 else
994                         printf("%s", buf);
995
996         fclose(fp);
997         return 0;
998 }
999
1000
1001
1002
1003 /* Create one or more objects, arg[4] may describe stripe meta-data.  If
1004  * not, defaults assumed.  This echo-client instance stashes the stripe
1005  * object ids.  Use get_stripe on this node to print full lsm and
1006  * set_stripe on another node to cut/paste between nodes.
1007  */
1008 /* create <count> [<file_create_mode>] [q|v|# verbosity] [striping] */
1009 int jt_obd_create(int argc, char **argv)
1010 {
1011         struct obd_ioctl_data data;
1012         struct timeval next_time;
1013         __u64 count = 1, next_count, base_id = 0;
1014         int verbose = 1, mode = 0100644, rc = 0, i, valid_lsm = 0;
1015         char *end;
1016
1017         IOC_INIT(data);
1018         if (argc < 2 || argc > 5)
1019                 return CMD_HELP;
1020
1021         count = strtoull(argv[1], &end, 0);
1022         if (*end) {
1023                 fprintf(stderr, "error: %s: invalid iteration count '%s'\n",
1024                         jt_cmdname(argv[0]), argv[1]);
1025                 return CMD_HELP;
1026         }
1027
1028         if (argc > 2) {
1029                 mode = strtoul(argv[2], &end, 0);
1030                 if (*end) {
1031                         fprintf(stderr, "error: %s: invalid mode '%s'\n",
1032                                 jt_cmdname(argv[0]), argv[2]);
1033                         return CMD_HELP;
1034                 }
1035                 if (!(mode & S_IFMT))
1036                         mode |= S_IFREG;
1037         }
1038
1039         if (argc > 3) {
1040                 verbose = get_verbose(argv[0], argv[3]);
1041                 if (verbose == BAD_VERBOSE)
1042                         return CMD_HELP;
1043         }
1044
1045         if (argc < 5)
1046                 reset_lsmb (&lsm_buffer);       /* will set default */
1047         else {
1048                 rc = parse_lsm (&lsm_buffer, argv[4]);
1049                 if (rc != 0) {
1050                         fprintf(stderr, "error: %s: invalid lsm '%s'\n",
1051                                 jt_cmdname(argv[0]), argv[4]);
1052                         return CMD_HELP;
1053                 }
1054                 base_id = lsm_buffer.lsm.lsm_object_id;
1055                 valid_lsm = 1;
1056         }
1057
1058         printf("%s: "LPD64" objects\n", jt_cmdname(argv[0]), count);
1059         gettimeofday(&next_time, NULL);
1060         next_time.tv_sec -= verbose;
1061
1062         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
1063                 data.ioc_obdo1.o_mode = mode;
1064                 data.ioc_obdo1.o_id = base_id;
1065                 data.ioc_obdo1.o_uid = 0;
1066                 data.ioc_obdo1.o_gid = 0;
1067                 data.ioc_obdo1.o_valid = OBD_MD_FLTYPE | OBD_MD_FLMODE |
1068                         OBD_MD_FLID | OBD_MD_FLUID | OBD_MD_FLGID;
1069
1070                 if (valid_lsm) {
1071                         data.ioc_plen1 = sizeof lsm_buffer;
1072                         data.ioc_pbuf1 = (char *)&lsm_buffer;
1073                 }
1074
1075                 IOC_PACK(argv[0], data);
1076                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_CREATE, buf);
1077                 IOC_UNPACK(argv[0], data);
1078                 shmem_bump();
1079                 if (rc < 0) {
1080                         fprintf(stderr, "error: %s: #%d - %s\n",
1081                                 jt_cmdname(argv[0]), i, strerror(rc = errno));
1082                         break;
1083                 }
1084                 if (!(data.ioc_obdo1.o_valid & OBD_MD_FLID)) {
1085                         fprintf(stderr,"error: %s: oid not valid #%d:"LPX64"\n",
1086                                 jt_cmdname(argv[0]), i, data.ioc_obdo1.o_valid);
1087                         rc = EINVAL;
1088                         break;
1089                 }
1090
1091                 if (be_verbose(verbose, &next_time, i, &next_count, count))
1092                         printf("%s: #%d is object id "LPX64"\n",
1093                                 jt_cmdname(argv[0]), i, data.ioc_obdo1.o_id);
1094         }
1095         return rc;
1096 }
1097
1098 int jt_obd_setattr(int argc, char **argv)
1099 {
1100         struct obd_ioctl_data data;
1101         char *end;
1102         int rc;
1103
1104         IOC_INIT(data);
1105         if (argc != 2)
1106                 return CMD_HELP;
1107
1108         data.ioc_obdo1.o_id = strtoull(argv[1], &end, 0);
1109         if (*end) {
1110                 fprintf(stderr, "error: %s: invalid objid '%s'\n",
1111                         jt_cmdname(argv[0]), argv[1]);
1112                 return CMD_HELP;
1113         }
1114         data.ioc_obdo1.o_mode = S_IFREG | strtoul(argv[2], &end, 0);
1115         if (*end) {
1116                 fprintf(stderr, "error: %s: invalid mode '%s'\n",
1117                         jt_cmdname(argv[0]), argv[2]);
1118                 return CMD_HELP;
1119         }
1120         data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE;
1121
1122         IOC_PACK(argv[0], data);
1123         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_SETATTR, buf);
1124         if (rc < 0)
1125                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
1126                         strerror(rc = errno));
1127
1128         return rc;
1129 }
1130
1131 int jt_obd_test_setattr(int argc, char **argv)
1132 {
1133         struct obd_ioctl_data data;
1134         struct timeval start, next_time;
1135         __u64 i, count, next_count;
1136         int verbose = 1;
1137         obd_id objid = 3;
1138         char *end;
1139         int rc = 0;
1140
1141         if (argc < 2 || argc > 4)
1142                 return CMD_HELP;
1143
1144         IOC_INIT(data);
1145         count = strtoull(argv[1], &end, 0);
1146         if (*end) {
1147                 fprintf(stderr, "error: %s: invalid iteration count '%s'\n",
1148                         jt_cmdname(argv[0]), argv[1]);
1149                 return CMD_HELP;
1150         }
1151
1152         if (argc >= 3) {
1153                 verbose = get_verbose(argv[0], argv[2]);
1154                 if (verbose == BAD_VERBOSE)
1155                         return CMD_HELP;
1156         }
1157
1158         if (argc >= 4) {
1159                 if (argv[3][0] == 't') {
1160                         objid = strtoull(argv[3] + 1, &end, 0);
1161                         if (thread)
1162                                 objid += thread - 1;
1163                 } else
1164                         objid = strtoull(argv[3], &end, 0);
1165                 if (*end) {
1166                         fprintf(stderr, "error: %s: invalid objid '%s'\n",
1167                                 jt_cmdname(argv[0]), argv[3]);
1168                         return CMD_HELP;
1169                 }
1170         }
1171
1172         gettimeofday(&start, NULL);
1173         next_time.tv_sec = start.tv_sec - verbose;
1174         next_time.tv_usec = start.tv_usec;
1175         if (verbose != 0)
1176                 printf("%s: setting "LPD64" attrs (objid "LPX64"): %s",
1177                        jt_cmdname(argv[0]), count, objid, ctime(&start.tv_sec));
1178
1179         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
1180                 data.ioc_obdo1.o_id = objid;
1181                 data.ioc_obdo1.o_mode = S_IFREG;
1182                 data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE;
1183                 IOC_PACK(argv[0], data);
1184                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_SETATTR, &data);
1185                 shmem_bump();
1186                 if (rc < 0) {
1187                         fprintf(stderr, "error: %s: #"LPD64" - %d:%s\n",
1188                                 jt_cmdname(argv[0]), i, errno, strerror(rc = errno));
1189                         break;
1190                 } else {
1191                         if (be_verbose
1192                             (verbose, &next_time, i, &next_count, count))
1193                                 printf("%s: set attr #"LPD64"\n",
1194                                        jt_cmdname(argv[0]), i);
1195                 }
1196         }
1197
1198         if (!rc) {
1199                 struct timeval end;
1200                 double diff;
1201
1202                 gettimeofday(&end, NULL);
1203
1204                 diff = difftime(&end, &start);
1205
1206                 --i;
1207                 if (verbose != 0)
1208                         printf("%s: "LPD64" attrs in %.3fs (%.3f attr/s): %s",
1209                                jt_cmdname(argv[0]), i, diff, i / diff,
1210                                ctime(&end.tv_sec));
1211         }
1212         return rc;
1213 }
1214
1215 int jt_obd_destroy(int argc, char **argv)
1216 {
1217         struct obd_ioctl_data data;
1218         struct timeval next_time;
1219         __u64 count = 1, next_count;
1220         int verbose = 1;
1221         __u64 id;
1222         char *end;
1223         int rc = 0, i;
1224
1225         IOC_INIT(data);
1226         if (argc < 2 || argc > 4)
1227                 return CMD_HELP;
1228
1229         id = strtoull(argv[1], &end, 0);
1230         if (*end || id == 0 || errno != 0) {
1231                 fprintf(stderr, "error: %s: invalid objid '%s'\n",
1232                         jt_cmdname(argv[0]), argv[1]);
1233                 return CMD_HELP;
1234         }
1235         if (argc > 2) {
1236                 count = strtoull(argv[2], &end, 0);
1237                 if (*end) {
1238                         fprintf(stderr,
1239                                 "error: %s: invalid iteration count '%s'\n",
1240                                 jt_cmdname(argv[0]), argv[2]);
1241                         return CMD_HELP;
1242                 }
1243         }
1244
1245         if (argc > 3) {
1246                 verbose = get_verbose(argv[0], argv[3]);
1247                 if (verbose == BAD_VERBOSE)
1248                         return CMD_HELP;
1249         }
1250
1251         printf("%s: "LPD64" objects\n", jt_cmdname(argv[0]), count);
1252         gettimeofday(&next_time, NULL);
1253         next_time.tv_sec -= verbose;
1254
1255         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++, id++) {
1256                 data.ioc_obdo1.o_id = id;
1257                 data.ioc_obdo1.o_mode = S_IFREG | 0644;
1258                 data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLMODE;
1259
1260                 IOC_PACK(argv[0], data);
1261                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_DESTROY, buf);
1262                 IOC_UNPACK(argv[0], data);
1263                 shmem_bump();
1264                 if (rc < 0) {
1265                         fprintf(stderr, "error: %s: objid "LPX64": %s\n",
1266                                 jt_cmdname(argv[0]), id, strerror(rc = errno));
1267                         break;
1268                 }
1269
1270                 if (be_verbose(verbose, &next_time, i, &next_count, count))
1271                         printf("%s: #%d is object id "LPX64"\n",
1272                                jt_cmdname(argv[0]), i, id);
1273         }
1274
1275         return rc;
1276 }
1277
1278 int jt_obd_getattr(int argc, char **argv)
1279 {
1280         struct obd_ioctl_data data;
1281         char *end;
1282         int rc;
1283
1284         if (argc != 2)
1285                 return CMD_HELP;
1286
1287         IOC_INIT(data);
1288         data.ioc_obdo1.o_id = strtoull(argv[1], &end, 0);
1289         if (*end) {
1290                 fprintf(stderr, "error: %s: invalid objid '%s'\n",
1291                         jt_cmdname(argv[0]), argv[1]);
1292                 return CMD_HELP;
1293         }
1294         /* to help obd filter */
1295         data.ioc_obdo1.o_mode = 0100644;
1296         data.ioc_obdo1.o_valid = 0xffffffff;
1297         printf("%s: object id "LPX64"\n", jt_cmdname(argv[0]),data.ioc_obdo1.o_id);
1298
1299         IOC_PACK(argv[0], data);
1300         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_GETATTR, buf);
1301         IOC_UNPACK(argv[0], data);
1302         if (rc) {
1303                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
1304                         strerror(rc = errno));
1305         } else {
1306                 printf("%s: object id "LPX64", mode %o\n", jt_cmdname(argv[0]),
1307                        data.ioc_obdo1.o_id, data.ioc_obdo1.o_mode);
1308         }
1309         return rc;
1310 }
1311
1312 int jt_obd_test_getattr(int argc, char **argv)
1313 {
1314         struct obd_ioctl_data data;
1315         struct timeval start, next_time;
1316         __u64 i, count, next_count;
1317         int verbose = 1;
1318         obd_id objid = 3;
1319         char *end;
1320         int rc = 0;
1321
1322         if (argc < 2 || argc > 4)
1323                 return CMD_HELP;
1324
1325         IOC_INIT(data);
1326         count = strtoull(argv[1], &end, 0);
1327         if (*end) {
1328                 fprintf(stderr, "error: %s: invalid iteration count '%s'\n",
1329                         jt_cmdname(argv[0]), argv[1]);
1330                 return CMD_HELP;
1331         }
1332
1333         if (argc >= 3) {
1334                 verbose = get_verbose(argv[0], argv[2]);
1335                 if (verbose == BAD_VERBOSE)
1336                         return CMD_HELP;
1337         }
1338
1339         if (argc >= 4) {
1340                 if (argv[3][0] == 't') {
1341                         objid = strtoull(argv[3] + 1, &end, 0);
1342                         if (thread)
1343                                 objid += thread - 1;
1344                 } else
1345                         objid = strtoull(argv[3], &end, 0);
1346                 if (*end) {
1347                         fprintf(stderr, "error: %s: invalid objid '%s'\n",
1348                                 jt_cmdname(argv[0]), argv[3]);
1349                         return CMD_HELP;
1350                 }
1351         }
1352
1353         gettimeofday(&start, NULL);
1354         next_time.tv_sec = start.tv_sec - verbose;
1355         next_time.tv_usec = start.tv_usec;
1356         if (verbose != 0)
1357                 printf("%s: getting "LPD64" attrs (objid "LPX64"): %s",
1358                        jt_cmdname(argv[0]), count, objid, ctime(&start.tv_sec));
1359
1360         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
1361                 data.ioc_obdo1.o_id = objid;
1362                 data.ioc_obdo1.o_mode = S_IFREG;
1363                 data.ioc_obdo1.o_valid = 0xffffffff;
1364                 IOC_PACK(argv[0], data);
1365                 rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_GETATTR, &data);
1366                 shmem_bump();
1367                 if (rc < 0) {
1368                         fprintf(stderr, "error: %s: #"LPD64" - %d:%s\n",
1369                                 jt_cmdname(argv[0]), i, errno, strerror(rc = errno));
1370                         break;
1371                 } else {
1372                         if (be_verbose
1373                             (verbose, &next_time, i, &next_count, count))
1374                                 printf("%s: got attr #"LPD64"\n",
1375                                        jt_cmdname(argv[0]), i);
1376                 }
1377         }
1378
1379         if (!rc) {
1380                 struct timeval end;
1381                 double diff;
1382
1383                 gettimeofday(&end, NULL);
1384
1385                 diff = difftime(&end, &start);
1386
1387                 --i;
1388                 if (verbose != 0)
1389                         printf("%s: "LPD64" attrs in %.3fs (%.3f attr/s): %s",
1390                                jt_cmdname(argv[0]), i, diff, i / diff,
1391                                ctime(&end.tv_sec));
1392         }
1393         return rc;
1394 }
1395
1396 /* test_brw <cnt>                                               count
1397         <r|w[r(repeat)x(noverify)]>                             mode
1398         <q|v|#(print interval)>                                 verbosity
1399         <npages[+offset]>                                       blocksize
1400         <[[<interleave_threads>]t(inc obj by thread#)]obj>      object
1401         [p|g<args>]                                             batch */
1402 int jt_obd_test_brw(int argc, char **argv)
1403 {
1404         struct obd_ioctl_data data;
1405         struct timeval start, next_time;
1406         __u64 count, next_count, len, stride, thr_offset = 0, objid = 3;
1407         int write = 0, verbose = 1, cmd, i, rc = 0, pages = 1;
1408         int offset_pages = 0;
1409         long n;
1410         int repeat_offset = 0;
1411         unsigned long long ull;
1412         int  nthr_per_obj = 0;
1413         int  verify = 1;
1414         int  obj_idx = 0;
1415         char *end;
1416
1417         if (argc < 2 || argc > 7) {
1418                 fprintf(stderr, "error: %s: bad number of arguments: %d\n",
1419                         jt_cmdname(argv[0]), argc);
1420                 return CMD_HELP;
1421         }
1422
1423         count = strtoull(argv[1], &end, 0);
1424         if (*end) {
1425                 fprintf(stderr, "error: %s: bad iteration count '%s'\n",
1426                         jt_cmdname(argv[0]), argv[1]);
1427                 return CMD_HELP;
1428         }
1429
1430         if (argc >= 3) {
1431                 if (argv[2][0] == 'w' || argv[2][0] == '1')
1432                         write = 1;
1433                 /* else it's a read */
1434
1435                 if (argv[2][0] != 0)
1436                         for (i = 1; argv[2][i] != 0; i++)
1437                                 switch (argv[2][i]) {
1438                                 case 'r':
1439                                         repeat_offset = 1;
1440                                         break;
1441
1442                                 case 'x':
1443                                         verify = 0;
1444                                         break;
1445
1446                                 default:
1447                                         fprintf (stderr, "Can't parse cmd '%s'\n",
1448                                                  argv[2]);
1449                                         return CMD_HELP;
1450                                 }
1451         }
1452
1453         if (argc >= 4) {
1454                 verbose = get_verbose(argv[0], argv[3]);
1455                 if (verbose == BAD_VERBOSE)
1456                         return CMD_HELP;
1457         }
1458
1459         if (argc >= 5) {
1460                 pages = strtoul(argv[4], &end, 0);
1461
1462                 if (*end == '+')
1463                         offset_pages = strtoul(end + 1, &end, 0);
1464
1465                 if (*end != 0 ||
1466                     offset_pages < 0 || offset_pages >= pages) {
1467                         fprintf(stderr, "error: %s: bad npages[+offset] parameter '%s'\n",
1468                                 jt_cmdname(argv[0]), argv[4]);
1469                         return CMD_HELP;
1470                 }
1471         }
1472
1473         if (argc >= 6) {
1474                 if (thread &&
1475                     (n = strtol(argv[5], &end, 0)) > 0 &&
1476                     *end == 't' &&
1477                     (ull = strtoull(end + 1, &end, 0)) > 0 &&
1478                     *end == 0) {
1479                         nthr_per_obj = n;
1480                         objid = ull;
1481                 } else if (thread &&
1482                            argv[5][0] == 't') {
1483                         nthr_per_obj = 1;
1484                         objid = strtoull(argv[5] + 1, &end, 0);
1485                 } else {
1486                         nthr_per_obj = 0;
1487                         objid = strtoull(argv[5], &end, 0);
1488                 }
1489                 if (*end) {
1490                         fprintf(stderr, "error: %s: bad objid '%s'\n",
1491                                 jt_cmdname(argv[0]), argv[5]);
1492                         return CMD_HELP;
1493                 }
1494         }
1495
1496         IOC_INIT(data);
1497
1498         /* communicate the 'type' of brw test and batching to echo_client.
1499          * don't start.  we'd love to refactor this lctl->echo_client
1500          * interface */
1501         data.ioc_pbuf1 = (void *)1;
1502         data.ioc_plen1 = 1;
1503
1504         if (argc >= 7) {
1505                 switch(argv[6][0]) {
1506                         case 'g': /* plug and unplug */
1507                                 data.ioc_pbuf1 = (void *)2;
1508                                 data.ioc_plen1 = strtoull(argv[6] + 1, &end,
1509                                                           0);
1510                                 break;
1511                         case 'p': /* prep and commit */
1512                                 data.ioc_pbuf1 = (void *)3;
1513                                 data.ioc_plen1 = strtoull(argv[6] + 1, &end,
1514                                                           0);
1515                                 break;
1516                         default:
1517                                 fprintf(stderr, "error: %s: batching '%s' "
1518                                         "needs to specify 'p' or 'g'\n",
1519                                         jt_cmdname(argv[0]), argv[6]);
1520                                 return CMD_HELP;
1521                 }
1522
1523                 if (*end) {
1524                         fprintf(stderr, "error: %s: bad batching '%s'\n",
1525                                 jt_cmdname(argv[0]), argv[6]);
1526                         return CMD_HELP;
1527                 }
1528                 data.ioc_plen1 *= getpagesize();
1529         }
1530
1531         len = pages * getpagesize();
1532         thr_offset = offset_pages * getpagesize();
1533         stride = len;
1534
1535 #ifdef MAX_THREADS
1536         if (thread) {
1537                 shmem_lock ();
1538                 if (nthr_per_obj != 0) {
1539                         /* threads interleave */
1540                         obj_idx = (thread - 1)/nthr_per_obj;
1541                         objid += obj_idx;
1542                         stride *= nthr_per_obj;
1543                         if (thread == 1)
1544                                 shared_data->offsets[obj_idx] = stride + thr_offset;
1545                         thr_offset += ((thread - 1) % nthr_per_obj) * len;
1546                 } else {
1547                         /* threads disjoint */
1548                         thr_offset += (thread - 1) * len;
1549                 }
1550
1551                 shared_data->barrier--;
1552                 if (shared_data->barrier == 0)
1553                         l_cond_broadcast(&shared_data->cond);
1554                 else
1555                         l_cond_wait(&shared_data->cond,
1556                                           &shared_data->mutex);
1557
1558                 shmem_unlock ();
1559         }
1560 #endif
1561
1562         data.ioc_obdo1.o_id = objid;
1563         data.ioc_obdo1.o_mode = S_IFREG;
1564         data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE | OBD_MD_FLFLAGS;
1565         data.ioc_obdo1.o_flags = (verify ? OBD_FL_DEBUG_CHECK : 0);
1566         data.ioc_count = len;
1567         data.ioc_offset = (repeat_offset ? 0 : thr_offset);
1568
1569         gettimeofday(&start, NULL);
1570         next_time.tv_sec = start.tv_sec - verbose;
1571         next_time.tv_usec = start.tv_usec;
1572
1573         if (verbose != 0)
1574                 printf("%s: %s "LPU64"x%d pages (obj "LPX64", off "LPU64"): %s",
1575                        jt_cmdname(argv[0]), write ? "writing" : "reading", count,
1576                        pages, objid, data.ioc_offset, ctime(&start.tv_sec));
1577
1578         cmd = write ? OBD_IOC_BRW_WRITE : OBD_IOC_BRW_READ;
1579         for (i = 1, next_count = verbose; i <= count && shmem_running(); i++) {
1580                 data.ioc_obdo1.o_valid &= ~(OBD_MD_FLBLOCKS|OBD_MD_FLGRANT);
1581                 IOC_PACK(argv[0], data);
1582                 rc = l2_ioctl(OBD_DEV_ID, cmd, buf);
1583                 shmem_bump();
1584                 if (rc) {
1585                         fprintf(stderr, "error: %s: #%d - %s on %s\n",
1586                                 jt_cmdname(argv[0]), i, strerror(rc = errno),
1587                                 write ? "write" : "read");
1588                         break;
1589                 } else if (be_verbose(verbose, &next_time,i, &next_count,count)) {
1590                         shmem_lock ();
1591                         printf("%s: %s number %d @ "LPD64":"LPU64" for %d\n",
1592                                jt_cmdname(argv[0]), write ? "write" : "read", i,
1593                                data.ioc_obdo1.o_id, data.ioc_offset,
1594                                (int)(pages * getpagesize()));
1595                         shmem_unlock ();
1596                 }
1597
1598                 if (!repeat_offset) {
1599 #ifdef MAX_THREADS
1600                         if (stride == len) {
1601                                 data.ioc_offset += stride;
1602                         } else if (i < count) {
1603                                 shmem_lock ();
1604                                 data.ioc_offset = shared_data->offsets[obj_idx];
1605                                 shared_data->offsets[obj_idx] += len;
1606                                 shmem_unlock ();
1607                         }
1608 #else
1609                         data.ioc_offset += len;
1610                         obj_idx = 0; /* avoids an unused var warning */
1611 #endif
1612                 }
1613         }
1614
1615         if (!rc) {
1616                 struct timeval end;
1617                 double diff;
1618
1619                 gettimeofday(&end, NULL);
1620
1621                 diff = difftime(&end, &start);
1622
1623                 --i;
1624                 if (verbose != 0)
1625                         printf("%s: %s %dx%d pages in %.3fs (%.3f MB/s): %s",
1626                                jt_cmdname(argv[0]), write ? "wrote" : "read",
1627                                i, pages, diff,
1628                                ((double)i * pages * getpagesize()) /
1629                                (diff * 1048576.0),
1630                                ctime(&end.tv_sec));
1631         }
1632
1633         return rc;
1634 }
1635
1636 int jt_obd_lov_getconfig(int argc, char **argv)
1637 {
1638         struct obd_ioctl_data data;
1639         struct lov_desc desc;
1640         struct obd_uuid *uuidarray;
1641         __u32 *obdgens;
1642         char *path;
1643         int rc, fd;
1644
1645         IOC_INIT(data);
1646
1647         if (argc != 2)
1648                 return CMD_HELP;
1649
1650         path = argv[1];
1651         fd = open(path, O_RDONLY);
1652         if (fd < 0) {
1653                 fprintf(stderr, "open \"%s\" failed: %s\n", path,
1654                         strerror(errno));
1655                 return -errno;
1656         }
1657
1658         memset(&desc, 0, sizeof(desc));
1659         obd_str2uuid(&desc.ld_uuid, argv[1]);
1660         desc.ld_tgt_count = ((OBD_MAX_IOCTL_BUFFER-sizeof(data)-sizeof(desc)) /
1661                              (sizeof(*uuidarray) + sizeof(*obdgens)));
1662
1663
1664 repeat:
1665         uuidarray = calloc(desc.ld_tgt_count, sizeof(*uuidarray));
1666         if (!uuidarray) {
1667                 fprintf(stderr, "error: %s: no memory for %d uuid's\n",
1668                         jt_cmdname(argv[0]), desc.ld_tgt_count);
1669                 rc = -ENOMEM;
1670                 goto out;
1671         }
1672         obdgens = calloc(desc.ld_tgt_count, sizeof(*obdgens));
1673         if (!obdgens) {
1674                 fprintf(stderr, "error: %s: no memory for %d generation #'s\n",
1675                         jt_cmdname(argv[0]), desc.ld_tgt_count);
1676                 rc = -ENOMEM;
1677                 goto out_uuidarray;
1678         }
1679
1680         data.ioc_inllen1 = sizeof(desc);
1681         data.ioc_inlbuf1 = (char *)&desc;
1682         data.ioc_inllen2 = desc.ld_tgt_count * sizeof(*uuidarray);
1683         data.ioc_inlbuf2 = (char *)uuidarray;
1684         data.ioc_inllen3 = desc.ld_tgt_count * sizeof(*obdgens);
1685         data.ioc_inlbuf3 = (char *)obdgens;
1686
1687         if (obd_ioctl_pack(&data, &buf, max)) {
1688                 fprintf(stderr, "error: %s: invalid ioctl\n",
1689                         jt_cmdname(argv[0]));
1690                 rc = -EINVAL;
1691                 goto out_obdgens;
1692         }
1693         rc = ioctl(fd, OBD_IOC_LOV_GET_CONFIG, buf);
1694         if (rc == -ENOSPC) {
1695                 free(uuidarray);
1696                 free(obdgens);
1697                 goto repeat;
1698         } else if (rc) {
1699                 fprintf(stderr, "error: %s: ioctl error: %s\n",
1700                         jt_cmdname(argv[0]), strerror(rc = errno));
1701         } else {
1702                 struct obd_uuid *uuidp;
1703                 __u32 *genp;
1704                 int i;
1705
1706                 if (obd_ioctl_unpack(&data, buf, max)) {
1707                         fprintf(stderr, "error: %s: invalid reply\n",
1708                                 jt_cmdname(argv[0]));
1709                         rc = -EINVAL;
1710                         goto out;
1711                 }
1712                 if (desc.ld_default_stripe_count == (__u32)-1)
1713                         printf("default_stripe_count: %d\n", -1);
1714                 else
1715                         printf("default_stripe_count: %u\n",
1716                                desc.ld_default_stripe_count);
1717                 printf("default_stripe_size: "LPU64"\n",
1718                        desc.ld_default_stripe_size);
1719                 printf("default_stripe_offset: "LPU64"\n",
1720                        desc.ld_default_stripe_offset);
1721                 printf("default_stripe_pattern: %u\n", desc.ld_pattern);
1722                 printf("obd_count: %u\n", desc.ld_tgt_count);
1723                 printf("OBDS:\tobdidx\t\tobdgen\t\t obduuid\n");
1724                 uuidp = uuidarray;
1725                 genp = obdgens;
1726                 for (i = 0; i < desc.ld_tgt_count; i++, uuidp++, genp++)
1727                         printf("\t%6u\t%14u\t\t %s\n", i, *genp, (char *)uuidp);
1728         }
1729 out_obdgens:
1730         free(obdgens);
1731 out_uuidarray:
1732         free(uuidarray);
1733 out:
1734         close(fd);
1735         return rc;
1736 }
1737
1738 int jt_obd_ldlm_regress_start(int argc, char **argv)
1739 {
1740         int rc;
1741         struct obd_ioctl_data data;
1742         char argstring[200];
1743         int i, count = sizeof(argstring) - 1;
1744
1745         IOC_INIT(data);
1746         if (argc > 5)
1747                 return CMD_HELP;
1748
1749         argstring[0] = '\0';
1750         for (i = 1; i < argc; i++) {
1751                 strncat(argstring, " ", count);
1752                 count--;
1753                 strncat(argstring, argv[i], count);
1754                 count -= strlen(argv[i]);
1755         }
1756
1757         if (strlen(argstring)) {
1758                 data.ioc_inlbuf1 = argstring;
1759                 data.ioc_inllen1 = strlen(argstring) + 1;
1760         }
1761
1762         IOC_PACK(argv[0], data);
1763         rc = l2_ioctl(OBD_DEV_ID, IOC_LDLM_REGRESS_START, buf);
1764         if (rc)
1765                 fprintf(stderr, "error: %s: test failed: %s\n",
1766                         jt_cmdname(argv[0]), strerror(rc = errno));
1767
1768         return rc;
1769 }
1770
1771 int jt_obd_ldlm_regress_stop(int argc, char **argv)
1772 {
1773         int rc;
1774         struct obd_ioctl_data data;
1775         IOC_INIT(data);
1776
1777         if (argc != 1)
1778                 return CMD_HELP;
1779
1780         IOC_PACK(argv[0], data);
1781         rc = l2_ioctl(OBD_DEV_ID, IOC_LDLM_REGRESS_STOP, buf);
1782
1783         if (rc)
1784                 fprintf(stderr, "error: %s: test failed: %s\n",
1785                         jt_cmdname(argv[0]), strerror(rc = errno));
1786         return rc;
1787 }
1788
1789 static int do_activate(int argc, char **argv, int flag)
1790 {
1791         struct obd_ioctl_data data;
1792         int rc;
1793
1794         IOC_INIT(data);
1795         if (argc != 1)
1796                 return CMD_HELP;
1797
1798         /* reuse offset for 'active' */
1799         data.ioc_offset = flag;
1800
1801         IOC_PACK(argv[0], data);
1802         rc = l2_ioctl(OBD_DEV_ID, IOC_OSC_SET_ACTIVE, buf);
1803         if (rc)
1804                 fprintf(stderr, "error: %s: failed: %s\n",
1805                         jt_cmdname(argv[0]), strerror(rc = errno));
1806
1807         return rc;
1808 }
1809
1810 int jt_obd_deactivate(int argc, char **argv)
1811 {
1812         return do_activate(argc, argv, 0);
1813 }
1814
1815 int jt_obd_activate(int argc, char **argv)
1816 {
1817         return do_activate(argc, argv, 1);
1818 }
1819
1820 int jt_obd_recover(int argc, char **argv)
1821 {
1822         int rc;
1823         struct obd_ioctl_data data;
1824
1825         IOC_INIT(data);
1826         if (argc > 2)
1827                 return CMD_HELP;
1828
1829         if (argc == 2) {
1830                 data.ioc_inllen1 = strlen(argv[1]) + 1;
1831                 data.ioc_inlbuf1 = argv[1];
1832         }
1833
1834         IOC_PACK(argv[0], data);
1835         rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_CLIENT_RECOVER, buf);
1836         if (rc < 0) {
1837                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
1838                         strerror(rc = errno));
1839         }
1840
1841         return rc;
1842 }
1843
1844 int jt_obd_mdc_lookup(int argc, char **argv)
1845 {
1846         struct obd_ioctl_data data;
1847         char *parent, *child;
1848         int rc, fd, verbose = 1;
1849
1850         if (argc < 3 || argc > 4)
1851                 return CMD_HELP;
1852
1853         parent = argv[1];
1854         child = argv[2];
1855         if (argc == 4)
1856                 verbose = get_verbose(argv[0], argv[3]);
1857
1858         IOC_INIT(data);
1859
1860         data.ioc_inllen1 = strlen(child) + 1;
1861         data.ioc_inlbuf1 = child;
1862
1863         IOC_PACK(argv[0], data);
1864
1865         fd = open(parent, O_RDONLY);
1866         if (fd < 0) {
1867                 fprintf(stderr, "open \"%s\" failed: %s\n", parent,
1868                         strerror(errno));
1869                 return -1;
1870         }
1871
1872         rc = ioctl(fd, IOC_MDC_LOOKUP, buf);
1873         if (rc < 0) {
1874                 fprintf(stderr, "error: %s: ioctl error: %s\n",
1875                         jt_cmdname(argv[0]), strerror(rc = errno));
1876         }
1877         close(fd);
1878
1879         if (verbose) {
1880                 IOC_UNPACK(argv[0], data);
1881                 printf("%s: mode %o uid %d gid %d\n", child,
1882                        data.ioc_obdo1.o_mode, data.ioc_obdo1.o_uid,
1883                        data.ioc_obdo1.o_gid);
1884         }
1885
1886         return rc;
1887 }
1888
1889 int jt_cfg_dump_log(int argc, char **argv)
1890 {
1891         struct obd_ioctl_data data;
1892         int rc;
1893
1894         IOC_INIT(data);
1895
1896         if (argc != 2)
1897                 return CMD_HELP;
1898
1899         data.ioc_inllen1 = strlen(argv[1]) + 1;
1900         data.ioc_inlbuf1 = argv[1];
1901
1902         IOC_PACK(argv[0], data);
1903         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_DUMP_LOG, buf);
1904         if (rc < 0)
1905                 fprintf(stderr, "OBD_IOC_DUMP_LOG failed: %s\n",
1906                         strerror(errno));
1907
1908         return rc;
1909 }
1910
1911 int jt_llog_catlist(int argc, char **argv)
1912 {
1913         struct obd_ioctl_data data;
1914         int rc;
1915
1916         if (argc != 1)
1917                 return CMD_HELP;
1918
1919         IOC_INIT(data);
1920         data.ioc_inllen1 = max - size_round(sizeof(data));
1921         IOC_PACK(argv[0], data);
1922
1923         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_CATLOGLIST, buf);
1924         if (rc == 0)
1925                 fprintf(stdout, "%s", ((struct obd_ioctl_data*)buf)->ioc_bulk);
1926         else
1927                 fprintf(stderr, "OBD_IOC_CATLOGLIST failed: %s\n",
1928                         strerror(errno));
1929
1930         return rc;
1931 }
1932
1933 int jt_llog_info(int argc, char **argv)
1934 {
1935         struct obd_ioctl_data data;
1936         int rc;
1937
1938         if (argc != 2)
1939                 return CMD_HELP;
1940
1941         IOC_INIT(data);
1942         data.ioc_inllen1 = strlen(argv[1]) + 1;
1943         data.ioc_inlbuf1 = argv[1];
1944         data.ioc_inllen2 = max - size_round(sizeof(data)) -
1945                 size_round(data.ioc_inllen1);
1946         IOC_PACK(argv[0], data);
1947
1948         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_INFO, buf);
1949         if (rc == 0)
1950                 fprintf(stdout, "%s", ((struct obd_ioctl_data*)buf)->ioc_bulk);
1951         else
1952                 fprintf(stderr, "OBD_IOC_LLOG_INFO failed: %s\n",
1953                         strerror(errno));
1954
1955         return rc;
1956 }
1957
1958 int jt_llog_print(int argc, char **argv)
1959 {
1960         struct obd_ioctl_data data;
1961         int rc;
1962
1963         if (argc != 2 && argc != 4)
1964                 return CMD_HELP;
1965
1966         IOC_INIT(data);
1967         data.ioc_inllen1 = strlen(argv[1]) + 1;
1968         data.ioc_inlbuf1 = argv[1];
1969         if (argc == 4) {
1970                 data.ioc_inllen2 = strlen(argv[2]) + 1;
1971                 data.ioc_inlbuf2 = argv[2];
1972                 data.ioc_inllen3 = strlen(argv[3]) + 1;
1973                 data.ioc_inlbuf3 = argv[3];
1974         } else {
1975                 char from[2] = "1", to[3] = "-1";
1976                 data.ioc_inllen2 = strlen(from) + 1;
1977                 data.ioc_inlbuf2 = from;
1978                 data.ioc_inllen3 = strlen(to) + 1;
1979                 data.ioc_inlbuf3 = to;
1980         }
1981         data.ioc_inllen4 = max - size_round(sizeof(data)) -
1982                 size_round(data.ioc_inllen1) -
1983                 size_round(data.ioc_inllen2) -
1984                 size_round(data.ioc_inllen3);
1985         IOC_PACK(argv[0], data);
1986
1987         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_PRINT, buf);
1988         if (rc == 0)
1989                 fprintf(stdout, "%s", ((struct obd_ioctl_data*)buf)->ioc_bulk);
1990         else
1991                 fprintf(stderr, "OBD_IOC_LLOG_PRINT failed: %s\n",
1992                         strerror(errno));
1993
1994         return rc;
1995 }
1996
1997 int jt_llog_cancel(int argc, char **argv)
1998 {
1999         struct obd_ioctl_data data;
2000         int rc;
2001
2002         if (argc != 4)
2003                 return CMD_HELP;
2004
2005         IOC_INIT(data);
2006         data.ioc_inllen1 = strlen(argv[1]) + 1;
2007         data.ioc_inlbuf1 = argv[1];
2008         data.ioc_inllen2 = strlen(argv[2]) + 1;
2009         data.ioc_inlbuf2 = argv[2];
2010         data.ioc_inllen3 = strlen(argv[3]) + 1;
2011         data.ioc_inlbuf3 = argv[3];
2012         IOC_PACK(argv[0], data);
2013
2014         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_CANCEL, buf);
2015         if (rc == 0)
2016                 fprintf(stdout, "index %s be canceled.\n", argv[3]);
2017         else
2018                 fprintf(stderr, "OBD_IOC_LLOG_CANCEL failed: %s\n",
2019                         strerror(errno));
2020
2021         return rc;
2022
2023 }
2024 int jt_llog_check(int argc, char **argv)
2025 {
2026         struct obd_ioctl_data data;
2027         int rc;
2028
2029         if (argc != 2 && argc != 4)
2030                 return CMD_HELP;
2031
2032         IOC_INIT(data);
2033         data.ioc_inllen1 = strlen(argv[1]) + 1;
2034         data.ioc_inlbuf1 = argv[1];
2035         if (argc == 4) {
2036                 data.ioc_inllen2 = strlen(argv[2]) + 1;
2037                 data.ioc_inlbuf2 = argv[2];
2038                 data.ioc_inllen3 = strlen(argv[3]) + 1;
2039                 data.ioc_inlbuf3 = argv[3];
2040         } else {
2041                 char from[2] = "1", to[3] = "-1";
2042                 data.ioc_inllen2 = strlen(from) + 1;
2043                 data.ioc_inlbuf2 = from;
2044                 data.ioc_inllen3 = strlen(to) + 1;
2045                 data.ioc_inlbuf3 = to;
2046         }
2047         data.ioc_inllen4 = max - size_round(sizeof(data)) -
2048                 size_round(data.ioc_inllen1) -
2049                 size_round(data.ioc_inllen2) -
2050                 size_round(data.ioc_inllen3);
2051         IOC_PACK(argv[0], data);
2052
2053         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_CHECK, buf);
2054         if (rc == 0)
2055                 fprintf(stdout, "%s", ((struct obd_ioctl_data*)buf)->ioc_bulk);
2056         else
2057                 fprintf(stderr, "OBD_IOC_LLOG_CHECK failed: %s\n",
2058                         strerror(errno));
2059         return rc;
2060 }
2061
2062 int jt_llog_remove(int argc, char **argv)
2063 {
2064         struct obd_ioctl_data data;
2065         int rc;
2066
2067         if (argc != 3 && argc != 2)
2068                 return CMD_HELP;
2069
2070         IOC_INIT(data);
2071         data.ioc_inllen1 = strlen(argv[1]) + 1;
2072         data.ioc_inlbuf1 = argv[1];
2073         if (argc == 3){
2074                 data.ioc_inllen2 = strlen(argv[2]) + 1;
2075                 data.ioc_inlbuf2 = argv[2];
2076         }
2077         IOC_PACK(argv[0], data);
2078
2079         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_LLOG_REMOVE, buf);
2080         if (rc == 0) {
2081                 if (argc == 3)
2082                         fprintf(stdout, "log %s are removed.\n", argv[2]);
2083                 else
2084                         fprintf(stdout, "the log in catalog %s are removed. \n", argv[1]);
2085         } else
2086                 fprintf(stderr, "OBD_IOC_LLOG_REMOVE failed: %s\n",
2087                         strerror(errno));
2088
2089         return rc;
2090 }
2091
2092 /* attach a regular file to virtual block device.
2093  * return vaule:
2094  *  -1: fatal error
2095  *  1: error, it always means the command run failed
2096  *  0: success
2097  */
2098 static int jt_blockdev_run_process(const char *file, char *argv[])
2099 {
2100         pid_t pid;
2101         int rc;
2102
2103         pid = vfork();
2104         if (pid == 0) { /* child process */
2105                 /* don't print error messages */
2106                 close(1), close(2);
2107                 (void)execvp(file, argv);
2108                 exit(-1);
2109         } else if (pid > 0) {
2110                 int status;
2111
2112                 rc = waitpid(pid, &status, 0);
2113                 if (rc < 0 || !WIFEXITED(status))
2114                         return -1;
2115
2116                 return WEXITSTATUS(status);
2117         }
2118
2119         return -1;
2120 }
2121
2122 static int jt_blockdev_find_module(const char *module)
2123 {
2124         FILE *fp;
2125         int found = 0;
2126         char modname[256];
2127
2128         fp = fopen("/proc/modules", "r");
2129         if (fp == NULL)
2130                 return -1;
2131
2132         while (fscanf(fp, "%s %*s %*s %*s %*s %*s", modname) == 1) {
2133                 if (strcmp(module, modname) == 0) {
2134                         found = 1;
2135                         break;
2136                 }
2137         }
2138         fclose(fp);
2139
2140         return found;
2141 }
2142
2143 static int jt_blockdev_probe_module(const char *module)
2144 {
2145         char buf[1024];
2146         char *argv[10];
2147         int c, rc;
2148
2149         if (jt_blockdev_find_module(module) == 1)
2150                 return 0;
2151
2152         /* run modprobe first */
2153         c = 0;
2154         argv[c++] = "/sbin/modprobe";
2155         argv[c++] = "-q";
2156         argv[c++] = (char *)module;
2157         argv[c++] = NULL;
2158         rc = jt_blockdev_run_process("modprobe", argv);
2159         if (rc != 1)
2160                 return rc;
2161
2162         /* cannot find the module in default directory ... */
2163         sprintf(buf, "../llite/%s.ko", module);
2164         c = 0;
2165         argv[c++] = "/sbin/insmod";
2166         argv[c++] = buf;
2167         argv[c++] = NULL;
2168         rc = jt_blockdev_run_process("insmod", argv);
2169         return rc ? -1 : 0;
2170 }
2171
2172 int jt_blockdev_attach(int argc, char **argv)
2173 {
2174         int rc, fd;
2175         struct stat st;
2176         char *filename, *devname;
2177         unsigned long dev;
2178
2179         if (argc != 3)
2180                 return CMD_HELP;
2181
2182         if (jt_blockdev_probe_module("llite_lloop") < 0) {
2183                 fprintf(stderr, "error: cannot find module llite_lloop.(k)o\n");
2184                 return ENOENT;
2185         }
2186
2187         filename = argv[1];
2188         devname = argv[2];
2189
2190         fd = open(filename, O_RDWR);
2191         if (fd < 0) {
2192                 fprintf(stderr, "file %s can't be opened(%s)\n\n",
2193                         filename, strerror(errno));
2194                 return CMD_HELP;
2195         }
2196
2197         rc = ioctl(fd, LL_IOC_LLOOP_ATTACH, &dev);
2198         if (rc < 0) {
2199                 rc = errno;
2200                 fprintf(stderr, "attach error(%s)\n", strerror(rc));
2201                 goto out;
2202         }
2203
2204         rc = stat(devname, &st);
2205         if (rc == 0 && (!S_ISBLK(st.st_mode) || st.st_rdev != dev)) {
2206                 rc = EEXIST;
2207         } else if (rc < 0) {
2208                 if (errno == ENOENT &&
2209                     !mknod(devname, S_IFBLK|S_IRUSR|S_IWUSR, dev))
2210                         rc = 0;
2211                 else
2212                         rc = errno;
2213         }
2214
2215         if (rc) {
2216                 fprintf(stderr, "error: the file %s could be attached to block "
2217                                 "device %X but creating %s failed: %s\n"
2218                                 "now detaching the block device..",
2219                         filename, (int)dev, devname, strerror(rc));
2220
2221                 (void)ioctl(fd, LL_IOC_LLOOP_DETACH_BYDEV, dev);
2222                 fprintf(stderr, "%s\n", strerror(errno));
2223         }
2224 out:
2225         close(fd);
2226         return -rc;
2227 }
2228
2229 int jt_blockdev_detach(int argc, char **argv)
2230 {
2231         char *filename;
2232         int rc, fd;
2233
2234         if (argc != 2)
2235                 return CMD_HELP;
2236
2237         filename = argv[1];
2238         fd = open(filename, O_RDONLY);
2239         if (fd < 0) {
2240                 fprintf(stderr, "cannot open file %s error %s\n",
2241                         filename, strerror(errno));
2242                 return CMD_HELP;
2243         }
2244
2245         rc = ioctl(fd, LL_IOC_LLOOP_DETACH, 0);
2246         if (rc < 0) {
2247                 rc = errno;
2248                 fprintf(stderr, "detach error(%s)\n", strerror(rc));
2249         } else {
2250                 (void)unlink(filename);
2251         }
2252
2253         close(fd);
2254         return -rc;
2255 }
2256
2257 int jt_blockdev_info(int argc, char **argv)
2258 {
2259         char *filename;
2260         int rc, fd;
2261         __u64  ino;
2262
2263         if (argc != 2)
2264                 return CMD_HELP;
2265
2266         filename = argv[1];
2267         fd = open(filename, O_RDONLY);
2268         if (fd < 0) {
2269                 fprintf(stderr, "cannot open file %s error: %s\n",
2270                         filename, strerror(errno));
2271                 return CMD_HELP;
2272         }
2273
2274         rc = ioctl(fd, LL_IOC_LLOOP_INFO, &ino);
2275         if (rc < 0) {
2276                 rc = errno;
2277                 fprintf(stderr, "error: %s\n", strerror(errno));
2278                 goto out;
2279         }
2280         fprintf(stdout, "lloop device info: ");
2281         if (ino == 0ULL)
2282                 fprintf(stdout, "Not attached\n");
2283         else
2284                 fprintf(stdout, "attached to inode "LPU64"\n", ino);
2285 out:
2286         close(fd);
2287         return -rc;
2288 }
2289
2290 static void signal_server(int sig)
2291 {
2292         if (sig == SIGINT) {
2293                 do_disconnect("sigint", 1);
2294                 exit(1);
2295         } else
2296                 fprintf(stderr, "%s: got signal %d\n", jt_cmdname("sigint"), sig);
2297 }
2298
2299 int obd_initialize(int argc, char **argv)
2300 {
2301         int i;
2302
2303         for (i = 0; i < MAX_STRIPES; i++)
2304                 lsm_buffer.lsm.lsm_oinfo[i] = lov_oinfos + i;
2305
2306         shmem_setup();
2307         register_ioc_dev(OBD_DEV_ID, OBD_DEV_PATH,
2308                          OBD_DEV_MAJOR, OBD_DEV_MINOR);
2309
2310         return 0;
2311 }
2312
2313 void obd_finalize(int argc, char **argv)
2314 {
2315         struct sigaction sigact;
2316
2317         sigact.sa_handler = signal_server;
2318         sigfillset(&sigact.sa_mask);
2319         sigact.sa_flags = SA_RESTART;
2320         sigaction(SIGINT, &sigact, NULL);
2321
2322         shmem_stop();
2323         do_disconnect(argv[0], 1);
2324 }