Whamcloud - gitweb
b43a7d679cfce5dd5a4d5ed59696052981d0ca7c
[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 static int do_disconnect(char *func)
138 {
139         struct obd_ioctl_data data;
140         int rc;
141
142         if (connid == -1)
143                 return 0;
144
145         IOCINIT(data);
146
147         rc = ioctl(fd, OBD_IOC_DISCONNECT , &data);
148         if (rc < 0) {
149                 fprintf(stderr, "error: %s: %x %s\n", cmdname(func),
150                         OBD_IOC_DISCONNECT, strerror(errno));
151         } else {
152                 printf("%s: disconnected connid %d\n", cmdname(func), connid);
153                 connid = -1;
154         }
155
156         return rc;
157 }
158
159 extern command_t cmdlist[];
160
161 static int jt_device(int argc, char **argv)
162 {
163         struct obd_ioctl_data data;
164         int rc;
165
166         do_disconnect(argv[0]);
167
168         memset(&data, 0, sizeof(data));
169         if ( argc != 2 ) {
170                 fprintf(stderr, "usage: %s devno\n", cmdname(argv[0]));
171                 return -1;
172         }
173
174         data.ioc_dev = atoi(argv[1]);
175
176         if (obd_ioctl_pack(&data, &buf, max)) {
177                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
178                 return -2;
179         }
180
181         if (fd == -1)
182                 fd = open("/dev/obd", O_RDWR);
183         if (fd == -1) {
184                 fprintf(stderr, "error: %s: opening /dev/obd: %s\n",
185                         cmdname(argv[0]), strerror(errno));
186                 return errno;
187         }
188
189         rc = ioctl(fd, OBD_IOC_DEVICE , buf);
190         if (rc < 0)
191                 fprintf(stderr, "error: %s: %x %s\n", cmdname(argv[0]),
192                         OBD_IOC_DEVICE, strerror(rc = errno));
193
194         return rc;
195 }
196
197 static int jt_connect(int argc, char **argv)
198 {
199         struct obd_ioctl_data data;
200         int rc;
201
202         IOCINIT(data);
203
204         do_disconnect(argv[0]);
205
206         if (argc != 1) {
207                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
208                 return -1;
209         }
210
211         rc = ioctl(fd, OBD_IOC_CONNECT , &data);
212         if (rc < 0)
213                 fprintf(stderr, "error: %s: %x %s\n", cmdname(argv[0]),
214                         OBD_IOC_CONNECT, strerror(rc = errno));
215         else
216                 connid = data.ioc_conn1;
217
218         return rc;
219 }
220
221 static int jt_disconnect(int argc, char **argv)
222 {
223         struct obd_ioctl_data data;
224         int rc;
225
226         IOCINIT(data);
227
228         if (argc != 1) {
229                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
230                 return -1;
231         }
232
233         rc = ioctl(fd, OBD_IOC_DISCONNECT , &data);
234         if (rc < 0)
235                 fprintf(stderr, "error: %s: %x %s\n", cmdname(argv[0]),
236                         OBD_IOC_DISCONNECT, strerror(rc = errno));
237         else
238                 connid = -1;
239
240         return rc;
241 }
242
243 static int jt__device(int argc, char **argv)
244 {
245         char *arg2[3];
246         int rc;
247
248         if (argc < 3) {
249                 fprintf(stderr, "usage: %s devno <command [args ...]>\n",
250                         cmdname(argv[0]));
251                 return -1;
252         }
253
254         arg2[0] = "device";
255         arg2[1] = argv[1];
256         arg2[2] = NULL;
257         rc = jt_device(2, arg2);
258
259         if (!rc) {
260                 arg2[0] = "connect";
261                 arg2[1] = NULL;
262                 rc = jt_connect(1, arg2);
263         }
264
265         if (!rc)
266                 rc = Parser_execarg(argc - 2, argv + 2, cmdlist);
267
268         if (!rc) {
269                 arg2[0] = "disconnect";
270                 arg2[1] = NULL;
271                 rc = jt_disconnect(1, arg2);
272         }
273
274         return rc;
275 }
276
277 static int jt__threads(int argc, char **argv)
278 {
279         int threads;
280         int i, j;
281         int rc;
282
283         if (argc < 4) {
284                 fprintf(stderr,
285                         "usage: %s numthreads devno <command [args ...]>\n",
286                         argv[0]);
287                 return -1;
288         }
289
290         threads = atoi(argv[1]);
291         printf("%s: starting %d threads on device %s running %s\n",
292                argv[0], threads, argv[2], argv[3]);
293
294         for (i = 1; i <= threads; i++) {
295                 rc = fork();
296                 if (rc < 0) {
297                         fprintf(stderr, "error: %s: #%d - %s\n", argv[0], i,
298                                 strerror(rc = errno));
299                         break;
300                 } else if (rc == 0) {
301                         thread = i;
302                         argv[1] = "--device";
303                         return jt__device(argc - 1, argv + 1);
304                 } else {
305                         printf("%s: thread %d (PID %d) started\n",
306                                argv[0], i, rc);
307                         rc = 0;
308                 }
309         }
310
311         if (!thread) {
312                 printf("\n");
313                 for (j = 1; j < i; j++) {
314                         int status;
315                         int ret = wait(&status);
316
317                         if (ret < 0) {
318                                 fprintf(stderr, "error: %s: wait - %s\n",
319                                         argv[0], strerror(errno));
320                                 if (rc == 0)
321                                         rc = errno;
322                         } else if (WIFEXITED(status) == 0) {
323                                 fprintf(stderr, "%s: PID %d had rc=%d\n",
324                                         argv[0], ret, WEXITSTATUS(status));
325                                 if (rc == 0)
326                                         rc = WEXITSTATUS(status);
327                         }
328                 }
329         }
330
331         return rc;
332 }
333
334 static int jt_detach(int argc, char **argv)
335 {
336         struct obd_ioctl_data data;
337         int rc;
338
339         IOCINIT(data);
340
341         if (argc != 1) {
342                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
343                 return -1;
344         }
345
346         if (obd_ioctl_pack(&data, &buf, max)) {
347                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
348                 return -2;
349         }
350
351         rc = ioctl(fd, OBD_IOC_DETACH , buf);
352         if (rc < 0)
353                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
354                         strerror(rc=errno));
355
356         return rc;
357 }
358
359 static int jt_cleanup(int argc, char **argv)
360 {
361         struct obd_ioctl_data data;
362         int rc;
363
364         IOCINIT(data);
365
366         if (argc != 1) {
367                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
368                 return -1;
369         }
370
371         rc = ioctl(fd, OBD_IOC_CLEANUP , &data);
372         if (rc < 0)
373                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
374                         strerror(rc=errno));
375
376         return rc;
377 }
378
379 static int jt_attach(int argc, char **argv)
380 {
381         struct obd_ioctl_data data;
382         int rc;
383
384         IOCINIT(data);
385
386         if (argc != 2 && argc != 3) {
387                 fprintf(stderr, "usage: %s type [data]\n", cmdname(argv[0]));
388                 return -1;
389         }
390
391         data.ioc_inllen1 =  strlen(argv[1]) + 1;
392         data.ioc_inlbuf1 = argv[1];
393         if (argc == 3) {
394                 data.ioc_inllen2 = strlen(argv[2]) + 1;
395                 data.ioc_inlbuf2 = argv[2];
396         }
397
398         printf("%s: len %d addr %p type %s data %s\n",
399                cmdname(argv[0]), data.ioc_len, buf,
400                MKSTR(data.ioc_inlbuf1), MKSTR(data.ioc_inlbuf2));
401
402         if (obd_ioctl_pack(&data, &buf, max)) {
403                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
404                 return -2;
405         }
406         printf("%s: len %d addr %p raw %p type %s data %s and %s\n",
407                cmdname(argv[0]), data.ioc_len, buf, rawbuf,
408                MKSTR(data.ioc_inlbuf1), MKSTR(data.ioc_inlbuf2), &buf[516]);
409
410         rc = ioctl(fd, OBD_IOC_ATTACH , buf);
411         if (rc < 0)
412                 fprintf(stderr, "error: %s: %x %s\n", cmdname(argv[0]),
413                         OBD_IOC_ATTACH, strerror(rc = errno));
414
415         return rc;
416 }
417
418 static int jt_setup(int argc, char **argv)
419 {
420         struct obd_ioctl_data data;
421         int rc;
422
423         IOCINIT(data);
424
425         if ( argc > 3) {
426                 fprintf(stderr, "usage: %s [device] [fstype]\n",
427                         cmdname(argv[0]));
428                 return -1;
429         }
430
431         if (argc > 1) {
432                 data.ioc_inllen1 =  strlen(argv[1]) + 1;
433                 data.ioc_inlbuf1 = argv[1];
434                 data.ioc_dev = strtoul(argv[1], NULL, 0);
435         } else {
436                 data.ioc_dev = -1;
437         }
438         if ( argc == 3 ) {
439                 data.ioc_inllen2 = strlen(argv[2]) + 1;
440                 data.ioc_inlbuf2 = argv[2];
441         }
442
443         printf("%s: len %d addr %p device %s type %s\n",
444                cmdname(argv[0]), data.ioc_len, buf,
445                MKSTR(data.ioc_inlbuf1), MKSTR(data.ioc_inlbuf2));
446
447         if (obd_ioctl_pack(&data, &buf, max)) {
448                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
449                 return -2;
450         }
451         printf("%s: len %d addr %p raw %p device %s type %s\n",
452                cmdname(argv[0]), data.ioc_len, buf, rawbuf,
453                MKSTR(data.ioc_inlbuf1), MKSTR(data.ioc_inlbuf2));
454
455         rc = ioctl(fd, OBD_IOC_SETUP , buf);
456         if (rc < 0)
457                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
458                         strerror(rc = errno));
459
460         return rc;
461 }
462
463
464 static int jt_create(int argc, char **argv)
465 {
466         struct obd_ioctl_data data;
467         int num = 1;
468         int silent = 0;
469         int i;
470         int rc;
471
472         IOCINIT(data);
473         if (argc < 2 || argc > 4) {
474                 fprintf(stderr, "usage: %s num [mode] [silent]\n",
475                         cmdname(argv[0]));
476                 return -1;
477         }
478         num = strtoul(argv[1], NULL, 0);
479
480         if (argc > 2)
481                 data.ioc_obdo1.o_mode = strtoul(argv[2], NULL, 0);
482         else
483                 data.ioc_obdo1.o_mode = 0100644;
484         data.ioc_obdo1.o_valid = OBD_MD_FLMODE;
485
486         if (argc > 3)
487                 silent = strtoul(argv[3], NULL, 0);
488
489         printf("%s: %d obdos\n", cmdname(argv[0]), num);
490
491         for (i = 0 ; i < num ; i++) {
492                 rc = ioctl(fd, OBD_IOC_CREATE , &data);
493                 if (rc < 0) {
494                         fprintf(stderr, "error: %s: #%d - %s\n",
495                                 cmdname(argv[0]), i, strerror(rc = errno));
496                         break;
497                 }
498                 if (!silent)
499                         printf("%s: #%Ld succeeded\n", cmdname(argv[0]),
500                                data.ioc_obdo1.o_id);
501         }
502         return rc;
503 }
504
505 static int jt_setattr(int argc, char **argv)
506 {
507         struct obd_ioctl_data data;
508         int rc;
509
510         IOCINIT(data);
511         if (argc != 2) {
512                 fprintf(stderr, "usage: %s id mode\n", cmdname(argv[0]));
513                 return -1;
514         }
515
516         data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
517         data.ioc_obdo1.o_mode = S_IFREG | strtoul(argv[2], NULL, 0);
518         data.ioc_obdo1.o_valid = OBD_MD_FLMODE; 
519
520         rc = ioctl(fd, OBD_IOC_SETATTR , &data);
521         if (rc < 0)
522                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
523                         strerror(rc = errno));
524
525         return rc;
526 }
527
528 static int jt_destroy(int argc, char **argv)
529 {
530         struct obd_ioctl_data data;
531         int rc;
532
533         IOCINIT(data);
534         if (argc != 2) {
535                 fprintf(stderr, "usage: %s id\n", cmdname(argv[0]));
536                 return -1;
537         }
538
539         data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
540         data.ioc_obdo1.o_mode = S_IFREG|0644;
541
542         rc = ioctl(fd, OBD_IOC_DESTROY , &data);
543         if (rc < 0)
544                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
545                         strerror(rc = errno));
546
547         return rc;
548 }
549
550 static int jt_getattr(int argc, char **argv)
551 {
552         struct obd_ioctl_data data;
553         int rc;
554
555         if (argc != 2) {
556                 fprintf(stderr, "usage: %s id\n", cmdname(argv[0]));
557                 return -1;
558         }
559
560         IOCINIT(data);
561         data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
562         /* to help obd filter */ 
563         data.ioc_obdo1.o_mode = 0100644;
564         data.ioc_obdo1.o_valid = 0xffffffff;
565         printf("%s: object id %Ld\n", cmdname(argv[0]), data.ioc_obdo1.o_id);
566
567         rc = ioctl(fd, OBD_IOC_GETATTR , &data);
568         if (rc) {
569                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
570                         strerror(rc=errno));
571         } else {
572                 printf("%s: object id %Ld, mode %o\n", cmdname(argv[0]),
573                        data.ioc_obdo1.o_id, data.ioc_obdo1.o_mode);
574         }
575         return rc;
576 }
577
578 static int jt_test_getattr(int argc, char **argv)
579 {
580         struct obd_ioctl_data data;
581         struct timeval start;
582         int count, i;
583         int silent = 0;
584         int rc;
585
586         if (argc != 2 && argc != 3) {
587                 fprintf(stderr, "usage: %s count [silent]\n", cmdname(argv[0]));
588                 return -1;
589         }
590
591         IOCINIT(data);
592         count = strtoul(argv[1], NULL, 0);
593
594         if (argc == 3) {
595                 if (argv[2][0] == 's' || argv[2][0] == 'q')
596                         silent = 1;
597                 else
598                         silent = strtoul(argv[2], NULL, 0);
599         }
600         data.ioc_obdo1.o_valid = 0xffffffff;
601         data.ioc_obdo1.o_id = 2;
602         gettimeofday(&start, NULL);
603         printf("%s: %d attrs (testing only): %s", cmdname(argv[0]), count,
604                ctime(&start.tv_sec));
605
606         for (i = 0 ; i < count; i++) {
607                 rc = ioctl(fd, OBD_IOC_GETATTR , &data);
608                 if (rc) {
609                         fprintf(stderr, "error: %s: #%d - %s\n",
610                                 cmdname(argv[0]), i, strerror(rc = errno));
611                         break;
612                 } else if (!silent) {
613                         printf("%s: got attr #%d\n", cmdname(argv[0]), i);
614                 }
615         }
616         if (!rc) {
617                 struct timeval end;
618                 double diff;
619
620                 gettimeofday(&end, NULL);
621
622                 diff = ((double)(end.tv_sec - start.tv_sec) +
623                         (double)(end.tv_usec - start.tv_usec) / 1000000);
624
625                 printf("%s: %d attrs in %.4gs (%.4g attr/s): %s",
626                        cmdname(argv[0]), i, diff, (double)i / diff,
627                        ctime(&end.tv_sec));
628         }
629         return rc;
630 }
631
632 static int jt_test_brw(int argc, char **argv)
633 {
634         struct obd_ioctl_data data;
635         struct timeval start;
636         char *bulk, *b;
637         int pages = 1, obdos = 1, count;
638         int silent = 0, write = 0, rw;
639         int i, o, p;
640         int len;
641         int rc;
642
643         if (argc < 2 || argc > 6) {
644                 fprintf(stderr,
645                         "usage: %s count [write [silent [pages [obdos]]]]\n",
646                         cmdname(argv[0]));
647                 return -1;
648         }
649
650         count = strtoul(argv[1], NULL, 0);
651
652         if (argc >= 3) {
653                 if (argv[2][0] == 'w')
654                         write = 1;
655                 else if (argv[2][0] == 'r')
656                         write = 0;
657                 else
658                         write = strtoul(argv[2], NULL, 0);
659         }
660         if (argc >= 4) {
661                 if (argv[3][0] == 's' || argv[3][0] == 'q')
662                         silent = 1;
663                 else
664                         silent = strtoul(argv[3], NULL, 0);
665         }
666         if (argc >= 5)
667                 pages = strtoul(argv[4], NULL, 0);
668         if (argc >= 6)
669                 obdos = strtoul(argv[5], NULL, 0);
670
671         if (obdos != 1 && obdos != 2) {
672                 fprintf(stderr, "error: %s: only 1 or 2 obdos supported\n",
673                         cmdname(argv[0]));
674                 return -2;
675         }
676
677         len = pages * PAGE_SIZE;
678
679         bulk = calloc(obdos, len);
680         if (!bulk) {
681                 fprintf(stderr, "error: %s: no memory allocating %dx%d pages\n",
682                         cmdname(argv[0]), obdos, pages);
683                 return -2;
684         }
685         IOCINIT(data);
686         data.ioc_conn2 = connid;
687         data.ioc_obdo1.o_id = 2;
688         data.ioc_count = len;
689         data.ioc_offset = 0;
690         data.ioc_plen1 = len;
691         data.ioc_pbuf1 = bulk;
692         if (obdos > 1) {
693                 data.ioc_obdo2.o_id = 2;
694                 data.ioc_plen2 = len;
695                 data.ioc_pbuf2 = bulk + len;
696         }
697
698         gettimeofday(&start, NULL);
699         printf("%s: %s %d (%dx%d pages) (testing only): %s",
700                cmdname(argv[0]), write ? "writing" : "reading",
701                count, obdos, pages, ctime(&start.tv_sec));
702
703         /*
704          * We will put in the start time (and loop count inside the loop)
705          * at the beginning of each page so that we will be able to validate
706          * (at some later time) whether the data actually made it or not.
707          */
708         for (o = 0, b = bulk; o < obdos; o++)
709                 for (p = 0; p < pages; p++, b += PAGE_SIZE)
710                         memcpy(b, &start, sizeof(start));
711
712         rw = write ? OBD_IOC_BRW_WRITE : OBD_IOC_BRW_READ;
713         for (i = 0 ; i < count; i++) {
714                 if (write) {
715                         b = bulk + sizeof(struct timeval);
716                         for (o = 0; o < obdos; o++)
717                                 for (p = 0; p < pages; p++, b += PAGE_SIZE)
718                                         memcpy(b, &count, sizeof(count));
719                 }
720
721                 rc = ioctl(fd, rw, &data);
722                 if (rc) {
723                         fprintf(stderr, "error: %s: #%d - %s on %s\n",
724                                 cmdname(argv[0]), i, strerror(rc = errno),
725                                 write ? "write" : "read");
726                         break;
727                 } else if (!silent)
728                         printf("%s: %s number %d\n", cmdname(argv[0]),
729                                write ? "write" : "read", i);
730         }
731
732         free(bulk);
733
734         if (!rc) {
735                 struct timeval end;
736                 double diff;
737
738                 gettimeofday(&end, NULL);
739
740                 diff = ((double)(end.tv_sec - start.tv_sec) +
741                         (double)(end.tv_usec - start.tv_usec) / 1000000);
742
743                 printf("%s: %s %dx%dx%d pages in %.4gs (%.4g pg/s): %s",
744                        cmdname(argv[0]), write ? "wrote" : "read", obdos,
745                        pages, i, diff, (double)obdos * i * pages / diff,
746                        ctime(&end.tv_sec));
747         }
748         return rc;
749 }
750
751 static int jt_test_ldlm(int argc, char **argv)
752 {
753         struct obd_ioctl_data data;
754         int rc;
755
756         IOCINIT(data);
757         if (argc != 1) {
758                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
759                 return 1;
760         }
761
762         rc = ioctl(fd, IOC_LDLM_TEST, &data);
763         if (rc)
764                 fprintf(stderr, "error: %s: test failed: %s\n",
765                         cmdname(argv[0]), strerror(rc = errno));
766         return rc;
767 }
768
769 command_t cmdlist[] = {
770         {"--device", jt__device, 0, "--device <devno> <command [args ...]>"},
771         {"--threads", jt__threads, 0,
772                 "--threads <threads> <devno> <command [args ...]>"},
773         {"device", jt_device, 0, "set current device (args device no)"},
774         {"attach", jt_attach, 0, "name the type of device (args: type data"},
775         {"setup", jt_setup, 0, "setup device (args: <blkdev> [data]"},
776         {"detach", jt_detach, 0, "detach the current device (arg: )"},
777         {"cleanup", jt_cleanup, 0, "cleanup the current device (arg: )"},
778         {"create", jt_create, 0, "create [count [mode [silent]]]"},
779         {"destroy", jt_destroy, 0, "destroy <id>"},
780         {"getattr", jt_getattr, 0, "getattr <id>"},
781         {"setattr", jt_setattr, 0, "setattr <id> <mode>"},
782         {"connect", jt_connect, 0, "connect - get a connection to device"},
783         {"disconnect", jt_disconnect, 0,
784                 "disconnect - break connection to device"},
785         {"test_getattr", jt_test_getattr, 0, "test_getattr <count> [silent]"},
786         {"test_brw", jt_test_brw, 0, "test_brw <count> [write [silent]]"},
787         {"test_ldlm", jt_test_ldlm, 0, "test lock manager (no args)"},
788         {"help", Parser_help, 0, "help"},
789         {"exit", Parser_quit, 0, "quit"},
790         {"quit", Parser_quit, 0, "quit"},
791         { 0, 0, 0, NULL }
792 };
793
794
795 static void signal_server(int sig)
796 {
797         if (sig == SIGINT) { 
798                 do_disconnect("sigint");
799                 exit(1);
800         }
801 }
802
803 int main(int argc, char **argv)
804 {
805         struct sigaction sigact;
806         int rc = 0;
807
808         sigact.sa_handler = signal_server;
809         sigfillset(&sigact.sa_mask);
810         sigact.sa_flags = SA_RESTART;
811         sigaction(SIGINT, &sigact, NULL);
812
813
814         if (argc > 1) {
815                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
816         } else {
817                 Parser_init("obdctl > ", cmdlist);
818                 Parser_commands();
819         }
820
821         do_disconnect(argv[0]);
822         return rc;
823 }
824