Whamcloud - gitweb
Consolidate verbose flag parsing.
[fs/lustre-release.git] / lustre / utils / obdctl.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  *
8  *   This file is part of Lustre, http://www.lustre.org.
9  *
10  *   Lustre is free software; you can redistribute it and/or
11  *   modify it under the terms of version 2 of the GNU General Public
12  *   License as published by the Free Software Foundation.
13  *
14  *   Lustre is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *   GNU General Public License for more details.
18  *
19  *   You should have received a copy of the GNU General Public License
20  *   along with Lustre; if not, write to the Free Software
21  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  */
24
25 #include <stdlib.h>
26 #include <sys/ioctl.h>
27 #include <fcntl.h>
28 #include <sys/socket.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31 #include <sys/stat.h>
32 #include <stdio.h>
33 #include <signal.h>
34 #define printk printf
35
36 #include <linux/lustre_lib.h>
37 #include <linux/lustre_idl.h>
38 #include <linux/lustre_dlm.h>
39
40 #include <unistd.h>
41 #include <sys/un.h>
42 #include <time.h>
43 #include <sys/time.h>
44 #include <netinet/in.h>
45 #include <errno.h>
46 #include <string.h>
47
48 #define __KERNEL__
49 #include <linux/list.h>
50 #undef __KERNEL__
51
52 #include "parser.h"
53 #include <stdio.h>
54
55 int fd = -1;
56 int connid = -1;
57 char rawbuf[8192];
58 char *buf = rawbuf;
59 int max = 8192;
60 int thread;
61
62 #define IOCINIT(data)                                                   \
63 do {                                                                    \
64         memset(&data, 0, sizeof(data));                                 \
65         data.ioc_version = OBD_IOCTL_VERSION;                           \
66         data.ioc_conn1 = connid;                                        \
67         data.ioc_len = sizeof(data);                                    \
68         if (fd < 0) {                                                   \
69                 fprintf(stderr, "No device open, use device\n");        \
70                 return 1;                                               \
71         }                                                               \
72 } while (0)
73
74 /*
75     pack "LL LL LL LL LL LL LL L L L L L L L L L a60 a60 L L L",
76     $obdo->{id}, 0,
77     $obdo->{gr}, 0,
78     $obdo->{atime}, 0,
79     $obdo->{mtime}, 0 ,
80     $obdo->{ctime}, 0,
81     $obdo->{size}, 0,
82     $obdo->{blocks}, 0,
83     $obdo->{blksize},
84     $obdo->{mode},
85     $obdo->{uid},
86     $obdo->{gid},
87     $obdo->{flags},
88     $obdo->{obdflags},
89     $obdo->{nlink},
90     $obdo->{generation},
91     $obdo->{valid},
92     $obdo->{inline},
93     $obdo->{obdmd},
94     0, 0, # struct list_head
95     0;  #  struct obd_ops
96 }
97
98 */
99
100 char * obdo_print(struct obdo *obd)
101 {
102         char buf[1024];
103
104         sprintf(buf, "id: %Ld\ngrp: %Ld\natime: %Ld\nmtime: %Ld\nctime: %Ld\n"
105                 "size: %Ld\nblocks: %Ld\nblksize: %d\nmode: %o\nuid: %d\n"
106                 "gid: %d\nflags: %x\nobdflags: %x\nnlink: %d,\nvalid %x\n",
107                 obd->o_id,
108                 obd->o_gr,
109                 obd->o_atime,
110                 obd->o_mtime,
111                 obd->o_ctime,
112                 obd->o_size,
113                 obd->o_blocks,
114                 obd->o_blksize,
115                 obd->o_mode,
116                 obd->o_uid,
117                 obd->o_gid,
118                 obd->o_flags,
119                 obd->o_obdflags,
120                 obd->o_nlink,
121                 obd->o_valid);
122         return strdup(buf);
123 }
124
125 static char *cmdname(char *func)
126 {
127         static char buf[512];
128
129         if (thread) {
130                 sprintf(buf, "%s-%d", func, thread);
131                 return buf;
132         }
133
134         return func;
135 }
136
137 #define difftime(a, b)                                          \
138         ((double)(a)->tv_sec - (b)->tv_sec +                    \
139          ((double)((a)->tv_usec - (b)->tv_usec) / 1000000))
140
141 static int be_verbose(int verbose, struct timeval *next_time,
142                       int num, int *next_num, int num_total)
143 {
144         struct timeval now;
145
146         if (!verbose)
147                 return 0;
148
149         /* A positive verbosity means to print every X iterations */
150         if (verbose > 0 &&
151             (next_num == NULL || num >= *next_num || num >= num_total)) {
152                 *next_num += verbose;
153                 return 1;
154         }
155
156         if (verbose < 0 && next_time != NULL) {
157                 /* A negative verbosity means to print at most each X seconds */
158                 gettimeofday(&now, NULL);
159                 if (difftime(&now, next_time) >= 0) {
160                         next_time->tv_sec = now.tv_sec - verbose;
161                         next_time->tv_usec = now.tv_usec;
162                         return 1;
163                 }
164         }
165
166         return 0;
167 }
168
169 static int get_verbose(const char *arg)
170 {
171         int verbose;
172
173         if (!arg || arg[0] == 'v')
174                 verbose = 1;
175         else if (arg[0] == 's' || arg[0] == 'q')
176                 verbose = 0;
177         else
178                 verbose = strtoul(arg, NULL, 0);
179
180         return verbose;
181 }
182
183 static int do_disconnect(char *func, int verbose)
184 {
185         struct obd_ioctl_data data;
186         int rc;
187
188         if (connid == -1)
189                 return 0;
190
191         IOCINIT(data);
192
193         rc = ioctl(fd, OBD_IOC_DISCONNECT , &data);
194         if (rc < 0) {
195                 fprintf(stderr, "error: %s: %x %s\n", cmdname(func),
196                         OBD_IOC_DISCONNECT, strerror(errno));
197         } else {
198                 if (verbose)
199                         printf("%s: disconnected connid %d\n", cmdname(func),
200                                connid);
201                 connid = -1;
202         }
203
204         return rc;
205 }
206
207 extern command_t cmdlist[];
208
209 static int jt_device(int argc, char **argv)
210 {
211         struct obd_ioctl_data data;
212         int rc;
213
214         do_disconnect(argv[0], 1);
215
216         memset(&data, 0, sizeof(data));
217         if ( argc != 2 ) {
218                 fprintf(stderr, "usage: %s devno\n", cmdname(argv[0]));
219                 return -1;
220         }
221
222         data.ioc_dev = strtoul(argv[1], NULL, 0);
223
224         if (obd_ioctl_pack(&data, &buf, max)) {
225                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
226                 return -2;
227         }
228
229         if (fd == -1)
230                 fd = open("/dev/obd", O_RDWR);
231         if (fd == -1) {
232                 fprintf(stderr, "error: %s: opening /dev/obd: %s\n",
233                         cmdname(argv[0]), strerror(errno));
234                 return errno;
235         }
236
237         rc = ioctl(fd, OBD_IOC_DEVICE , buf);
238         if (rc < 0)
239                 fprintf(stderr, "error: %s: %x %s\n", cmdname(argv[0]),
240                         OBD_IOC_DEVICE, strerror(rc = errno));
241
242         return rc;
243 }
244
245 static int jt_connect(int argc, char **argv)
246 {
247         struct obd_ioctl_data data;
248         int rc;
249
250         IOCINIT(data);
251
252         do_disconnect(argv[0], 1);
253
254         if (argc != 1) {
255                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
256                 return -1;
257         }
258
259         rc = ioctl(fd, OBD_IOC_CONNECT , &data);
260         if (rc < 0)
261                 fprintf(stderr, "error: %s: %x %s\n", cmdname(argv[0]),
262                         OBD_IOC_CONNECT, strerror(rc = errno));
263         else
264                 connid = data.ioc_conn1;
265
266         return rc;
267 }
268
269 static int jt_disconnect(int argc, char **argv)
270 {
271         if (argc != 1) {
272                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
273                 return -1;
274         }
275
276         return do_disconnect(argv[0], 0);
277 }
278
279 static int jt__device(int argc, char **argv)
280 {
281         char *arg2[3];
282         int rc, ret;
283
284         if (argc < 3) {
285                 fprintf(stderr, "usage: %s devno <command [args ...]>\n",
286                         cmdname(argv[0]));
287                 return -1;
288         }
289
290         arg2[0] = "device";
291         arg2[1] = argv[1];
292         arg2[2] = NULL;
293         rc = jt_device(2, arg2);
294
295         if (!rc) {
296                 arg2[0] = "connect";
297                 arg2[1] = NULL;
298                 rc = jt_connect(1, arg2);
299         }
300
301         if (!rc)
302                 rc = Parser_execarg(argc - 2, argv + 2, cmdlist);
303
304         ret = do_disconnect(argv[0], 0);
305         if (!rc)
306                 rc = ret;
307
308         return rc;
309 }
310
311 static int jt__threads(int argc, char **argv)
312 {
313         int threads, next_thread;
314         int verbose;
315         int i, j;
316         int rc;
317
318         if (argc < 5) {
319                 fprintf(stderr,
320                         "usage: %s numthreads verbose devno <cmd [args ...]>\n",
321                         argv[0]);
322                 return -1;
323         }
324
325         threads = strtoul(argv[1], NULL, 0);
326
327         verbose = get_verbose(argv[2]);
328
329         printf("%s: starting %d threads on device %s running %s\n",
330                argv[0], threads, argv[3], argv[4]);
331
332         for (i = 1, next_thread = verbose; i <= threads; i++) {
333                 rc = fork();
334                 if (rc < 0) {
335                         fprintf(stderr, "error: %s: #%d - %s\n", argv[0], i,
336                                 strerror(rc = errno));
337                         break;
338                 } else if (rc == 0) {
339                         thread = i;
340                         argv[2] = "--device";
341                         return jt__device(argc - 2, argv + 2);
342                 } else if (be_verbose(verbose, NULL, i, &next_thread, threads))
343                         printf("%s: thread #%d (PID %d) started\n",
344                                argv[0], i, rc);
345                 rc = 0;
346         }
347
348         if (!thread) { /* parent process */
349                 if (!verbose)
350                         printf("%s: started %d threads\n\n", argv[0], i - 1);
351                 else
352                         printf("\n");
353
354                 for (j = 1; j < i; j++) {
355                         int status;
356                         int ret = wait(&status);
357
358                         if (ret < 0) {
359                                 fprintf(stderr, "error: %s: wait - %s\n",
360                                         argv[0], strerror(errno));
361                                 if (rc == 0)
362                                         rc = errno;
363                         } else if (WIFEXITED(status) == 0) {
364                                 fprintf(stderr, "%s: PID %d had rc=%d\n",
365                                         argv[0], ret, WEXITSTATUS(status));
366                                 if (rc == 0)
367                                         rc = WEXITSTATUS(status);
368                         }
369                 }
370         }
371
372         return rc;
373 }
374
375 static int jt_detach(int argc, char **argv)
376 {
377         struct obd_ioctl_data data;
378         int rc;
379
380         IOCINIT(data);
381
382         if (argc != 1) {
383                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
384                 return -1;
385         }
386
387         if (obd_ioctl_pack(&data, &buf, max)) {
388                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
389                 return -2;
390         }
391
392         rc = ioctl(fd, OBD_IOC_DETACH , buf);
393         if (rc < 0)
394                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
395                         strerror(rc=errno));
396
397         return rc;
398 }
399
400 static int jt_cleanup(int argc, char **argv)
401 {
402         struct obd_ioctl_data data;
403         int rc;
404
405         IOCINIT(data);
406
407         if (argc != 1) {
408                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
409                 return -1;
410         }
411
412         rc = ioctl(fd, OBD_IOC_CLEANUP , &data);
413         if (rc < 0)
414                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
415                         strerror(rc=errno));
416
417         return rc;
418 }
419
420 static int jt_attach(int argc, char **argv)
421 {
422         struct obd_ioctl_data data;
423         int rc;
424
425         IOCINIT(data);
426
427         if (argc != 2 && argc != 3) {
428                 fprintf(stderr, "usage: %s type [data]\n", cmdname(argv[0]));
429                 return -1;
430         }
431
432         data.ioc_inllen1 =  strlen(argv[1]) + 1;
433         data.ioc_inlbuf1 = argv[1];
434         if (argc == 3) {
435                 data.ioc_inllen2 = strlen(argv[2]) + 1;
436                 data.ioc_inlbuf2 = argv[2];
437         }
438
439         printf("%s: len %d addr %p type %s data %s\n",
440                cmdname(argv[0]), data.ioc_len, buf,
441                MKSTR(data.ioc_inlbuf1), MKSTR(data.ioc_inlbuf2));
442
443         if (obd_ioctl_pack(&data, &buf, max)) {
444                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
445                 return -2;
446         }
447         printf("%s: len %d addr %p raw %p type %s data %s and %s\n",
448                cmdname(argv[0]), data.ioc_len, buf, rawbuf,
449                MKSTR(data.ioc_inlbuf1), MKSTR(data.ioc_inlbuf2), &buf[516]);
450
451         rc = ioctl(fd, OBD_IOC_ATTACH , buf);
452         if (rc < 0)
453                 fprintf(stderr, "error: %s: %x %s\n", cmdname(argv[0]),
454                         OBD_IOC_ATTACH, strerror(rc = errno));
455
456         return rc;
457 }
458
459 static int jt_setup(int argc, char **argv)
460 {
461         struct obd_ioctl_data data;
462         int rc;
463
464         IOCINIT(data);
465
466         if ( argc > 3) {
467                 fprintf(stderr, "usage: %s [device] [fstype]\n",
468                         cmdname(argv[0]));
469                 return -1;
470         }
471
472         if (argc > 1) {
473                 data.ioc_inllen1 =  strlen(argv[1]) + 1;
474                 data.ioc_inlbuf1 = argv[1];
475                 data.ioc_dev = strtoul(argv[1], NULL, 0);
476         } else {
477                 data.ioc_dev = -1;
478         }
479         if ( argc == 3 ) {
480                 data.ioc_inllen2 = strlen(argv[2]) + 1;
481                 data.ioc_inlbuf2 = argv[2];
482         }
483
484         printf("%s: len %d addr %p device %s type %s\n",
485                cmdname(argv[0]), data.ioc_len, buf,
486                MKSTR(data.ioc_inlbuf1), MKSTR(data.ioc_inlbuf2));
487
488         if (obd_ioctl_pack(&data, &buf, max)) {
489                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
490                 return -2;
491         }
492         printf("%s: len %d addr %p raw %p device %s type %s\n",
493                cmdname(argv[0]), data.ioc_len, buf, rawbuf,
494                MKSTR(data.ioc_inlbuf1), MKSTR(data.ioc_inlbuf2));
495
496         rc = ioctl(fd, OBD_IOC_SETUP , buf);
497         if (rc < 0)
498                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
499                         strerror(rc = errno));
500
501         return rc;
502 }
503
504
505 static int jt_create(int argc, char **argv)
506 {
507         struct obd_ioctl_data data;
508         struct timeval next_time;
509         int count = 1, next_count;
510         int verbose;
511         int i;
512         int rc;
513
514         IOCINIT(data);
515         if (argc < 2 || argc > 4) {
516                 fprintf(stderr, "usage: %s num [mode] [verbose]\n",
517                         cmdname(argv[0]));
518                 return -1;
519         }
520         count = strtoul(argv[1], NULL, 0);
521
522         if (argc > 2)
523                 data.ioc_obdo1.o_mode = strtoul(argv[2], NULL, 0);
524         else
525                 data.ioc_obdo1.o_mode = 0100644;
526         data.ioc_obdo1.o_valid = OBD_MD_FLMODE;
527
528         verbose = get_verbose(argv[3]);
529
530         printf("%s: %d obdos\n", cmdname(argv[0]), count);
531         gettimeofday(&next_time, NULL);
532         next_time.tv_sec -= verbose;
533
534         for (i = 1, next_count = verbose; i <= count ; i++) {
535                 rc = ioctl(fd, OBD_IOC_CREATE , &data);
536                 if (rc < 0) {
537                         fprintf(stderr, "error: %s: #%d - %s\n",
538                                 cmdname(argv[0]), i, strerror(rc = errno));
539                         break;
540                 }
541                 if (be_verbose(verbose, &next_time, i, &next_count, count))
542                         printf("%s: #%d is object id %Ld\n", cmdname(argv[0]),
543                                i, data.ioc_obdo1.o_id);
544         }
545         return rc;
546 }
547
548 static int jt_setattr(int argc, char **argv)
549 {
550         struct obd_ioctl_data data;
551         int rc;
552
553         IOCINIT(data);
554         if (argc != 2) {
555                 fprintf(stderr, "usage: %s id mode\n", cmdname(argv[0]));
556                 return -1;
557         }
558
559         data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
560         data.ioc_obdo1.o_mode = S_IFREG | strtoul(argv[2], NULL, 0);
561         data.ioc_obdo1.o_valid = OBD_MD_FLMODE; 
562
563         rc = ioctl(fd, OBD_IOC_SETATTR , &data);
564         if (rc < 0)
565                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
566                         strerror(rc = errno));
567
568         return rc;
569 }
570
571 static int jt_destroy(int argc, char **argv)
572 {
573         struct obd_ioctl_data data;
574         int rc;
575
576         IOCINIT(data);
577         if (argc != 2) {
578                 fprintf(stderr, "usage: %s id\n", cmdname(argv[0]));
579                 return -1;
580         }
581
582         data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
583         data.ioc_obdo1.o_mode = S_IFREG|0644;
584
585         rc = ioctl(fd, OBD_IOC_DESTROY , &data);
586         if (rc < 0)
587                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
588                         strerror(rc = errno));
589
590         return rc;
591 }
592
593 static int jt_getattr(int argc, char **argv)
594 {
595         struct obd_ioctl_data data;
596         int rc;
597
598         if (argc != 2) {
599                 fprintf(stderr, "usage: %s id\n", cmdname(argv[0]));
600                 return -1;
601         }
602
603         IOCINIT(data);
604         data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
605         /* to help obd filter */ 
606         data.ioc_obdo1.o_mode = 0100644;
607         data.ioc_obdo1.o_valid = 0xffffffff;
608         printf("%s: object id %Ld\n", cmdname(argv[0]), data.ioc_obdo1.o_id);
609
610         rc = ioctl(fd, OBD_IOC_GETATTR , &data);
611         if (rc) {
612                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
613                         strerror(rc=errno));
614         } else {
615                 printf("%s: object id %Ld, mode %o\n", cmdname(argv[0]),
616                        data.ioc_obdo1.o_id, data.ioc_obdo1.o_mode);
617         }
618         return rc;
619 }
620
621 static int jt_test_getattr(int argc, char **argv)
622 {
623         struct obd_ioctl_data data;
624         struct timeval start, next_time;
625         int i, count, next_count;
626         int verbose;
627         int rc;
628
629         if (argc != 2 && argc != 3) {
630                 fprintf(stderr, "usage: %s count [verbose]\n",cmdname(argv[0]));
631                 return -1;
632         }
633
634         IOCINIT(data);
635         count = strtoul(argv[1], NULL, 0);
636
637         verbose = get_verbose(argv[2]);
638
639         data.ioc_obdo1.o_valid = 0xffffffff;
640         data.ioc_obdo1.o_id = 2;
641         gettimeofday(&start, NULL);
642         next_time.tv_sec = start.tv_sec - verbose;
643         next_time.tv_usec = start.tv_usec;
644         printf("%s: getting %d attrs (testing only): %s", cmdname(argv[0]),
645                count, ctime(&start.tv_sec));
646
647         for (i = 1, next_count = verbose; i <= count; i++) {
648                 rc = ioctl(fd, OBD_IOC_GETATTR , &data);
649                 if (rc) {
650                         fprintf(stderr, "error: %s: #%d - %s\n",
651                                 cmdname(argv[0]), i, strerror(rc = errno));
652                         break;
653                 } else if (be_verbose(verbose, &next_time, i,&next_count,count))
654                         printf("%s: got attr #%d\n", cmdname(argv[0]), i);
655         }
656
657         if (!rc) {
658                 struct timeval end;
659                 double diff;
660
661                 gettimeofday(&end, NULL);
662
663                 diff = difftime(&end, &start);
664
665                 --i;
666                 printf("%s: %d attrs in %.4gs (%.4g attr/s): %s",
667                        cmdname(argv[0]), i, diff, (double)i / diff,
668                        ctime(&end.tv_sec));
669         }
670         return rc;
671 }
672
673 static int jt_test_brw(int argc, char **argv)
674 {
675         struct obd_ioctl_data data;
676         struct timeval start, next_time;
677         char *bulk, *b;
678         int pages = 1, obdos = 1, count, next_count;
679         int verbose = 1, write = 0, rw;
680         int i, o, p;
681         int len;
682         int rc;
683
684         if (argc < 2 || argc > 6) {
685                 fprintf(stderr,
686                         "usage: %s count [write [verbose [pages [obdos]]]]\n",
687                         cmdname(argv[0]));
688                 return -1;
689         }
690
691         count = strtoul(argv[1], NULL, 0);
692
693         if (argc >= 3) {
694                 if (argv[2][0] == 'w' || argv[2][0] == '1')
695                         write = 1;
696                 else if (argv[2][0] == 'r' || argv[2][0] == '0')
697                         write = 0;
698
699                 verbose = get_verbose(argv[3]);
700         }
701
702         if (argc >= 5)
703                 pages = strtoul(argv[4], NULL, 0);
704         if (argc >= 6)
705                 obdos = strtoul(argv[5], NULL, 0);
706
707         if (obdos != 1 && obdos != 2) {
708                 fprintf(stderr, "error: %s: only 1 or 2 obdos supported\n",
709                         cmdname(argv[0]));
710                 return -2;
711         }
712
713         len = pages * PAGE_SIZE;
714
715         bulk = calloc(obdos, len);
716         if (!bulk) {
717                 fprintf(stderr, "error: %s: no memory allocating %dx%d pages\n",
718                         cmdname(argv[0]), obdos, pages);
719                 return -2;
720         }
721         IOCINIT(data);
722         data.ioc_conn2 = connid;
723         data.ioc_obdo1.o_id = 2;
724         data.ioc_count = len;
725         data.ioc_offset = 0;
726         data.ioc_plen1 = len;
727         data.ioc_pbuf1 = bulk;
728         if (obdos > 1) {
729                 data.ioc_obdo2.o_id = 2;
730                 data.ioc_plen2 = len;
731                 data.ioc_pbuf2 = bulk + len;
732         }
733
734         gettimeofday(&start, NULL);
735         next_time.tv_sec = start.tv_sec - verbose;
736         next_time.tv_usec = start.tv_usec;
737
738         printf("%s: %s %d (%dx%d pages) (testing only): %s",
739                cmdname(argv[0]), write ? "writing" : "reading",
740                count, obdos, pages, ctime(&start.tv_sec));
741
742         /*
743          * We will put in the start time (and loop count inside the loop)
744          * at the beginning of each page so that we will be able to validate
745          * (at some later time) whether the data actually made it or not.
746          */
747         for (o = 0, b = bulk; o < obdos; o++)
748                 for (p = 0; p < pages; p++, b += PAGE_SIZE)
749                         memcpy(b, &start, sizeof(start));
750
751         rw = write ? OBD_IOC_BRW_WRITE : OBD_IOC_BRW_READ;
752         for (i = 1, next_count = verbose; i <= count; i++) {
753                 if (write) {
754                         b = bulk + sizeof(struct timeval);
755                         for (o = 0; o < obdos; o++)
756                                 for (p = 0; p < pages; p++, b += PAGE_SIZE)
757                                         memcpy(b, &count, sizeof(count));
758                 }
759
760                 rc = ioctl(fd, rw, &data);
761                 if (rc) {
762                         fprintf(stderr, "error: %s: #%d - %s on %s\n",
763                                 cmdname(argv[0]), i, strerror(rc = errno),
764                                 write ? "write" : "read");
765                         break;
766                 } else if (be_verbose(verbose, &next_time, i,&next_count,count))
767                         printf("%s: %s number %d\n", cmdname(argv[0]),
768                                write ? "write" : "read", i);
769         }
770
771         free(bulk);
772
773         if (!rc) {
774                 struct timeval end;
775                 double diff;
776
777                 gettimeofday(&end, NULL);
778
779                 diff = difftime(&end, &start);
780
781                 --i;
782                 printf("%s: %s %dx%dx%d pages in %.4gs (%.4g pg/s): %s",
783                        cmdname(argv[0]), write ? "wrote" : "read", obdos,
784                        pages, i, diff, (double)obdos * i * pages / diff,
785                        ctime(&end.tv_sec));
786         }
787         return rc;
788 }
789
790 static int jt_test_ldlm(int argc, char **argv)
791 {
792         struct obd_ioctl_data data;
793         int rc;
794
795         IOCINIT(data);
796         if (argc != 1) {
797                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
798                 return 1;
799         }
800
801         rc = ioctl(fd, IOC_LDLM_TEST, &data);
802         if (rc)
803                 fprintf(stderr, "error: %s: test failed: %s\n",
804                         cmdname(argv[0]), strerror(rc = errno));
805         return rc;
806 }
807
808 command_t cmdlist[] = {
809         /* Metacommands */
810         {"--device", jt__device, 0, "--device <devno> <command [args ...]>"},
811         {"--threads", jt__threads, 0,
812                 "--threads <threads> <devno> <command [args ...]>"},
813
814         /* Device configuration commands */
815         {"device", jt_device, 0, "set current device (args device no)"},
816         {"attach", jt_attach, 0, "name the type of device (args: type data"},
817         {"setup", jt_setup, 0, "setup device (args: <blkdev> [data]"},
818         {"detach", jt_detach, 0, "detach the current device (arg: )"},
819         {"cleanup", jt_cleanup, 0, "cleanup the current device (arg: )"},
820
821         /* Session commands */
822         {"connect", jt_connect, 0, "connect - get a connection to device"},
823         {"disconnect", jt_disconnect, 0,
824                 "disconnect - break connection to device"},
825
826         /* Session operations */
827         {"create", jt_create, 0, "create [count [mode [verbose]]]"},
828         {"destroy", jt_destroy, 0, "destroy <id>"},
829         {"getattr", jt_getattr, 0, "getattr <id>"},
830         {"setattr", jt_setattr, 0, "setattr <id> <mode>"},
831         {"test_getattr", jt_test_getattr, 0, "test_getattr <count> [verbose]"},
832         {"test_brw", jt_test_brw, 0, "test_brw <count> [write [verbose]]"},
833         {"test_ldlm", jt_test_ldlm, 0, "test lock manager (no args)"},
834
835         /* User interface commands */
836         {"help", Parser_help, 0, "help"},
837         {"exit", Parser_quit, 0, "quit"},
838         {"quit", Parser_quit, 0, "quit"},
839         { 0, 0, 0, NULL }
840 };
841
842
843 static void signal_server(int sig)
844 {
845         if (sig == SIGINT) { 
846                 do_disconnect("sigint", 1);
847                 exit(1);
848         } else {
849                 fprintf(stderr, "%s: got signal %d\n", cmdname("sigint"), sig);
850         }
851 }
852
853 int main(int argc, char **argv)
854 {
855         struct sigaction sigact;
856         int rc = 0;
857
858         sigact.sa_handler = signal_server;
859         sigfillset(&sigact.sa_mask);
860         sigact.sa_flags = SA_RESTART;
861         sigaction(SIGINT, &sigact, NULL);
862
863
864         if (argc > 1) {
865                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
866         } else {
867                 Parser_init("obdctl > ", cmdlist);
868                 Parser_commands();
869         }
870
871         do_disconnect(argv[0], 1);
872         return rc;
873 }
874