Whamcloud - gitweb
Make obdctl return the error code from the most recently executed command
[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 int rc = 0;
62
63 #define IOCINIT(data)                                                   \
64 do {                                                                    \
65         memset(&data, 0, sizeof(data));                                 \
66         data.ioc_version = OBD_IOCTL_VERSION;                           \
67         data.ioc_conn1 = connid;                                        \
68         data.ioc_len = sizeof(data);                                    \
69         if (fd < 0) {                                                   \
70                 fprintf(stderr, "No device open, use device\n");        \
71                 return 1;                                               \
72         }                                                               \
73 } while (0)
74
75 /*
76     pack "LL LL LL LL LL LL LL L L L L L L L L L a60 a60 L L L",
77     $obdo->{id}, 0,
78     $obdo->{gr}, 0,
79     $obdo->{atime}, 0,
80     $obdo->{mtime}, 0 ,
81     $obdo->{ctime}, 0,
82     $obdo->{size}, 0,
83     $obdo->{blocks}, 0,
84     $obdo->{blksize},
85     $obdo->{mode},
86     $obdo->{uid},
87     $obdo->{gid},
88     $obdo->{flags},
89     $obdo->{obdflags},
90     $obdo->{nlink},
91     $obdo->{generation},
92     $obdo->{valid},
93     $obdo->{inline},
94     $obdo->{obdmd},
95     0, 0, # struct list_head
96     0;  #  struct obd_ops
97 }
98
99 */
100
101 char * obdo_print(struct obdo *obd)
102 {
103         char buf[1024];
104
105         sprintf(buf, "id: %Ld\ngrp: %Ld\natime: %Ld\nmtime: %Ld\nctime: %Ld\n"
106                 "size: %Ld\nblocks: %Ld\nblksize: %d\nmode: %o\nuid: %d\n"
107                 "gid: %d\nflags: %x\nobdflags: %x\nnlink: %d,\nvalid %x\n",
108                 obd->o_id,
109                 obd->o_gr,
110                 obd->o_atime,
111                 obd->o_mtime,
112                 obd->o_ctime,
113                 obd->o_size,
114                 obd->o_blocks,
115                 obd->o_blksize,
116                 obd->o_mode,
117                 obd->o_uid,
118                 obd->o_gid,
119                 obd->o_flags,
120                 obd->o_obdflags,
121                 obd->o_nlink,
122                 obd->o_valid);
123         return strdup(buf);
124 }
125
126 static char *cmdname(char *func)
127 {
128         static char buf[512];
129
130         if (thread) {
131                 sprintf(buf, "%s-%d", func, thread);
132                 return buf;
133         }
134
135         return func;
136 }
137
138 int getfd(char *func)
139 {
140         if (fd == -1)
141                 fd = open("/dev/obd", O_RDWR);
142         if (fd == -1) {
143                 fprintf(stderr, "error: %s: opening /dev/obd: %s\n",
144                         cmdname(func), strerror(errno));
145                 return -1;
146         }
147         return 0;
148 }
149
150 /*
151 #define difftime(a, b)                                          \
152         ((double)(a)->tv_sec - (b)->tv_sec +                    \
153          ((double)((a)->tv_usec - (b)->tv_usec) / 1000000))
154 */
155
156 #define difftime(a, b)  (((a)->tv_sec - (b)->tv_sec) + \
157                         (((a)->tv_usec - (b)->tv_usec) / 1000000))
158
159 static int be_verbose(int verbose, struct timeval *next_time,
160                       int num, int *next_num, int num_total)
161 {
162         struct timeval now;
163
164         if (!verbose)
165                 return 0;
166
167         if (next_time != NULL)
168                 gettimeofday(&now, NULL);
169
170         /* A positive verbosity means to print every X iterations */
171         if (verbose > 0 &&
172             (next_num == NULL || num >= *next_num || num >= num_total)) {
173                 *next_num += verbose;
174                 if (next_time) {
175                         next_time->tv_sec = now.tv_sec - verbose;
176                         next_time->tv_usec = now.tv_usec;
177                 }
178                 return 1;
179         }
180
181         /* A negative verbosity means to print at most each X seconds */
182         if (verbose < 0 && next_time != NULL && difftime(&now, next_time) >= 0){
183                 next_time->tv_sec = now.tv_sec - verbose;
184                 next_time->tv_usec = now.tv_usec;
185                 if (next_num)
186                         *next_num = num;
187                 return 1;
188         }
189
190         return 0;
191 }
192
193 static int get_verbose(const char *arg)
194 {
195         int verbose;
196
197         if (!arg || arg[0] == 'v')
198                 verbose = 1;
199         else if (arg[0] == 's' || arg[0] == 'q')
200                 verbose = 0;
201         else
202                 verbose = (int) strtoul(arg, NULL, 0);
203
204         if (verbose < 0)
205                 printf("Print status every %d seconds\n", -verbose);
206         else if (verbose == 1)
207                 printf("Print status every operation\n");
208         else if (verbose > 1)
209                 printf("Print status every %d operations\n", verbose);
210
211         return verbose;
212 }
213
214 static int do_disconnect(char *func, int verbose)
215 {
216         struct obd_ioctl_data data;
217
218         if (connid == -1)
219                 return 0;
220
221         IOCINIT(data);
222
223         rc = ioctl(fd, OBD_IOC_DISCONNECT , &data);
224         if (rc < 0) {
225                 fprintf(stderr, "error: %s: %x %s\n", cmdname(func),
226                         OBD_IOC_DISCONNECT, strerror(errno));
227         } else {
228                 if (verbose)
229                         printf("%s: disconnected connid %d\n", cmdname(func),
230                                connid);
231                 connid = -1;
232         }
233
234         return rc;
235 }
236
237 extern command_t cmdlist[];
238
239 static int do_device(char *func, int dev)
240 {
241         struct obd_ioctl_data data;
242
243         memset(&data, 0, sizeof(data));
244
245         data.ioc_dev = dev;
246
247         if (getfd(func))
248                 return -1;
249
250         if (obd_ioctl_pack(&data, &buf, max)) {
251                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(func));
252                 return -2;
253         }
254
255         return ioctl(fd, OBD_IOC_DEVICE , buf);
256 }
257
258 static int jt_device(int argc, char **argv)
259 {
260         do_disconnect(argv[0], 1);
261
262         if (argc != 2) {
263                 fprintf(stderr, "usage: %s devno\n", cmdname(argv[0]));
264                 return -1;
265         }
266
267         rc = do_device(argv[0], strtoul(argv[1], NULL, 0));
268
269         if (rc < 0)
270                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
271                         strerror(rc = errno));
272
273         return rc;
274 }
275
276 static int jt_connect(int argc, char **argv)
277 {
278         struct obd_ioctl_data data;
279
280         IOCINIT(data);
281
282         do_disconnect(argv[0], 1);
283
284         if (argc != 1) {
285                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
286                 return -1;
287         }
288
289         rc = ioctl(fd, OBD_IOC_CONNECT , &data);
290         if (rc < 0)
291                 fprintf(stderr, "error: %s: %x %s\n", cmdname(argv[0]),
292                         OBD_IOC_CONNECT, strerror(rc = errno));
293         else
294                 connid = data.ioc_conn1;
295
296         return rc;
297 }
298
299 static int jt_disconnect(int argc, char **argv)
300 {
301         if (argc != 1) {
302                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
303                 return -1;
304         }
305
306         return do_disconnect(argv[0], 0);
307 }
308
309 static int jt__device(int argc, char **argv)
310 {
311         char *arg2[3];
312         int ret;
313
314         if (argc < 3) {
315                 fprintf(stderr, "usage: %s devno <command [args ...]>\n",
316                         cmdname(argv[0]));
317                 return -1;
318         }
319
320         rc = do_device("device", strtoul(argv[1], NULL, 0));
321
322         if (!rc) {
323                 arg2[0] = "connect";
324                 arg2[1] = NULL;
325                 rc = jt_connect(1, arg2);
326         }
327
328         if (!rc)
329                 rc = Parser_execarg(argc - 2, argv + 2, cmdlist);
330
331         ret = do_disconnect(argv[0], 0);
332         if (!rc)
333                 rc = ret;
334
335         return rc;
336 }
337
338 static int jt__threads(int argc, char **argv)
339 {
340         int threads, next_thread;
341         int verbose;
342         int i, j;
343
344         if (argc < 5) {
345                 fprintf(stderr,
346                         "usage: %s numthreads verbose devno <cmd [args ...]>\n",
347                         argv[0]);
348                 return -1;
349         }
350
351         threads = strtoul(argv[1], NULL, 0);
352
353         verbose = get_verbose(argv[2]);
354
355         printf("%s: starting %d threads on device %s running %s\n",
356                argv[0], threads, argv[3], argv[4]);
357
358         for (i = 1, next_thread = verbose; i <= threads; i++) {
359                 rc = fork();
360                 if (rc < 0) {
361                         fprintf(stderr, "error: %s: #%d - %s\n", argv[0], i,
362                                 strerror(rc = errno));
363                         break;
364                 } else if (rc == 0) {
365                         thread = i;
366                         argv[2] = "--device";
367                         return jt__device(argc - 2, argv + 2);
368                 } else if (be_verbose(verbose, NULL, i, &next_thread, threads))
369                         printf("%s: thread #%d (PID %d) started\n",
370                                argv[0], i, rc);
371                 rc = 0;
372         }
373
374         if (!thread) { /* parent process */
375                 if (!verbose)
376                         printf("%s: started %d threads\n\n", argv[0], i - 1);
377                 else
378                         printf("\n");
379
380                 for (j = 1; j < i; j++) {
381                         int status;
382                         int ret = wait(&status);
383
384                         if (ret < 0) {
385                                 fprintf(stderr, "error: %s: wait - %s\n",
386                                         argv[0], strerror(errno));
387                                 if (!rc)
388                                         rc = errno;
389                         } else {
390                                 /*
391                                  * This is a hack.  We _should_ be able to use
392                                  * WIFEXITED(status) to see if there was an
393                                  * error, but it appears to be broken and it
394                                  * always returns 1 (OK).  See wait(2).
395                                  */
396                                 int err = WEXITSTATUS(status);
397                                 if (err)
398                                         fprintf(stderr,
399                                                 "%s: PID %d had rc=%d\n",
400                                                 argv[0], ret, err);
401                                 if (!rc)
402                                         rc = err;
403                         }
404                 }
405         }
406
407         return rc;
408 }
409
410 static int jt_detach(int argc, char **argv)
411 {
412         struct obd_ioctl_data data;
413
414         IOCINIT(data);
415
416         if (argc != 1) {
417                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
418                 return -1;
419         }
420
421         if (obd_ioctl_pack(&data, &buf, max)) {
422                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
423                 return -2;
424         }
425
426         rc = ioctl(fd, OBD_IOC_DETACH , buf);
427         if (rc < 0)
428                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
429                         strerror(rc=errno));
430
431         return rc;
432 }
433
434 static int jt_cleanup(int argc, char **argv)
435 {
436         struct obd_ioctl_data data;
437
438         IOCINIT(data);
439
440         if (argc != 1) {
441                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
442                 return -1;
443         }
444
445         rc = ioctl(fd, OBD_IOC_CLEANUP , &data);
446         if (rc < 0)
447                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
448                         strerror(rc=errno));
449
450         return rc;
451 }
452
453 static int jt_newdev(int argc, char **argv)
454 {
455         struct obd_ioctl_data data;
456
457         if (getfd(argv[0]))
458                 return -1;
459
460         IOCINIT(data);
461
462         if (argc != 1) {
463                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
464                 return -1;
465         }
466
467         rc = ioctl(fd, OBD_IOC_NEWDEV , &data);
468         if (rc < 0)
469                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
470                         strerror(rc=errno));
471         else {
472                 printf("Current device set to %d\n", data.ioc_dev);
473         }
474
475         return rc;
476 }
477
478 static int jt_attach(int argc, char **argv)
479 {
480         struct obd_ioctl_data data;
481
482         IOCINIT(data);
483
484         if (argc != 2 && argc != 3) {
485                 fprintf(stderr, "usage: %s type [name [uuid]]\n",
486                         cmdname(argv[0]));
487                 return -1;
488         }
489
490         data.ioc_inllen1 =  strlen(argv[1]) + 1;
491         data.ioc_inlbuf1 = argv[1];
492         if (argc == 3) {
493                 data.ioc_inllen2 = strlen(argv[2]) + 1;
494                 data.ioc_inlbuf2 = argv[2];
495         }
496
497         if (obd_ioctl_pack(&data, &buf, max)) {
498                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
499                 return -2;
500         }
501
502         rc = ioctl(fd, OBD_IOC_ATTACH , buf);
503         if (rc < 0)
504                 fprintf(stderr, "error: %s: %x %s\n", cmdname(argv[0]),
505                         OBD_IOC_ATTACH, strerror(rc = errno));
506         else if (argc == 3) {
507                 char name[1024];
508                 if (strlen(argv[2]) > 128) {
509                         printf("Name too long to set environment\n");
510                         return -EINVAL;
511                 }
512                 snprintf(name, 512, "LUSTRE_DEV_%s", argv[2]);
513                 rc = setenv(name, argv[1], 1);
514                 if (rc) {
515                         printf("error setting env variable %s\n", name);
516                 }
517         }
518
519         return rc;
520 }
521
522 #define N2D_OFF 0x100    /* So we can tell between error codes and devices */
523
524 static int do_name2dev(char *func, char *name)
525 {
526         struct obd_ioctl_data data;
527
528         if (getfd(func))
529                 return -1;
530
531         IOCINIT(data);
532
533         data.ioc_inllen1 = strlen(name) + 1;
534         data.ioc_inlbuf1 = name;
535
536         if (obd_ioctl_pack(&data, &buf, max)) {
537                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(func));
538                 return -2;
539         }
540         rc = ioctl(fd, OBD_IOC_NAME2DEV , buf);
541         if (rc < 0) {
542                 fprintf(stderr, "error: %s: %s - %s\n", cmdname(func),
543                         name, strerror(rc = errno));
544                 return rc;
545         }
546
547         memcpy((char *)(&data), buf, sizeof(data));
548
549         return data.ioc_dev + N2D_OFF;
550 }
551
552 static int jt_name2dev(int argc, char **argv)
553 {
554         if (argc != 2) {
555                 fprintf(stderr, "usage: %s name\n", cmdname(argv[0]));
556                 return -1;
557         }
558
559         rc = do_name2dev(argv[0], argv[1]);
560         if (rc >= N2D_OFF) {
561                 int dev = rc - N2D_OFF;
562                 rc = do_device(argv[0], dev);
563                 if (rc == 0)
564                         printf("%d\n", dev);
565         }
566         return rc;
567 }
568
569 static int jt_setup(int argc, char **argv)
570 {
571         struct obd_ioctl_data data;
572
573         IOCINIT(data);
574
575         if ( argc > 3) {
576                 fprintf(stderr, "usage: %s [device] [fstype]\n",
577                         cmdname(argv[0]));
578                 return -1;
579         }
580
581         data.ioc_dev = -1;
582         if (argc > 1) {
583                 if (argv[1][0] == '$') {
584                         rc = do_name2dev(argv[0], argv[1] + 1);
585                         if (rc >= N2D_OFF) {
586                                 printf("%s is device %d\n", argv[1],
587                                        rc - N2D_OFF);
588                                 data.ioc_dev = rc - N2D_OFF;
589                         }
590                 } else
591                         data.ioc_dev = strtoul(argv[1], NULL, 0);
592                 data.ioc_inllen1 = strlen(argv[1]) + 1;
593                 data.ioc_inlbuf1 = argv[1];
594         }
595         if ( argc == 3 ) {
596                 data.ioc_inllen2 = strlen(argv[2]) + 1;
597                 data.ioc_inlbuf2 = argv[2];
598         }
599
600         if (obd_ioctl_pack(&data, &buf, max)) {
601                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
602                 return -2;
603         }
604         rc = ioctl(fd, OBD_IOC_SETUP , buf);
605         if (rc < 0)
606                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
607                         strerror(rc = errno));
608
609         return rc;
610 }
611
612
613 static int jt_create(int argc, char **argv)
614 {
615         struct obd_ioctl_data data;
616         struct timeval next_time;
617         int count = 1, next_count;
618         int verbose;
619         int i;
620
621         IOCINIT(data);
622         if (argc < 2 || argc > 4) {
623                 fprintf(stderr, "usage: %s num [mode] [verbose]\n",
624                         cmdname(argv[0]));
625                 return -1;
626         }
627         count = strtoul(argv[1], NULL, 0);
628
629         if (argc > 2)
630                 data.ioc_obdo1.o_mode = strtoul(argv[2], NULL, 0);
631         else
632                 data.ioc_obdo1.o_mode = 0100644;
633         data.ioc_obdo1.o_valid = OBD_MD_FLMODE;
634
635         verbose = get_verbose(argv[3]);
636
637         printf("%s: %d obdos\n", cmdname(argv[0]), count);
638         gettimeofday(&next_time, NULL);
639         next_time.tv_sec -= verbose;
640
641         for (i = 1, next_count = verbose; i <= count ; i++) {
642                 rc = ioctl(fd, OBD_IOC_CREATE , &data);
643                 if (rc < 0) {
644                         fprintf(stderr, "error: %s: #%d - %s\n",
645                                 cmdname(argv[0]), i, strerror(rc = errno));
646                         break;
647                 }
648                 if (be_verbose(verbose, &next_time, i, &next_count, count))
649                         printf("%s: #%d is object id %Ld\n", cmdname(argv[0]),
650                                i, data.ioc_obdo1.o_id);
651         }
652         return rc;
653 }
654
655 static int jt_setattr(int argc, char **argv)
656 {
657         struct obd_ioctl_data data;
658
659         IOCINIT(data);
660         if (argc != 2) {
661                 fprintf(stderr, "usage: %s id mode\n", cmdname(argv[0]));
662                 return -1;
663         }
664
665         data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
666         data.ioc_obdo1.o_mode = S_IFREG | strtoul(argv[2], NULL, 0);
667         data.ioc_obdo1.o_valid = OBD_MD_FLMODE;
668
669         rc = ioctl(fd, OBD_IOC_SETATTR , &data);
670         if (rc < 0)
671                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
672                         strerror(rc = errno));
673
674         return rc;
675 }
676
677 static int jt_destroy(int argc, char **argv)
678 {
679         struct obd_ioctl_data data;
680
681         IOCINIT(data);
682         if (argc != 2) {
683                 fprintf(stderr, "usage: %s id\n", cmdname(argv[0]));
684                 return -1;
685         }
686
687         data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
688         data.ioc_obdo1.o_mode = S_IFREG|0644;
689
690         rc = ioctl(fd, OBD_IOC_DESTROY , &data);
691         if (rc < 0)
692                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
693                         strerror(rc = errno));
694
695         return rc;
696 }
697
698 static int jt_getattr(int argc, char **argv)
699 {
700         struct obd_ioctl_data data;
701
702         if (argc != 2) {
703                 fprintf(stderr, "usage: %s id\n", cmdname(argv[0]));
704                 return -1;
705         }
706
707         IOCINIT(data);
708         data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
709         /* to help obd filter */
710         data.ioc_obdo1.o_mode = 0100644;
711         data.ioc_obdo1.o_valid = 0xffffffff;
712         printf("%s: object id %Ld\n", cmdname(argv[0]), data.ioc_obdo1.o_id);
713
714         rc = ioctl(fd, OBD_IOC_GETATTR , &data);
715         if (rc) {
716                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
717                         strerror(rc=errno));
718         } else {
719                 printf("%s: object id %Ld, mode %o\n", cmdname(argv[0]),
720                        data.ioc_obdo1.o_id, data.ioc_obdo1.o_mode);
721         }
722         return rc;
723 }
724
725 static int jt_test_getattr(int argc, char **argv)
726 {
727         struct obd_ioctl_data data;
728         struct timeval start, next_time;
729         int i, count, next_count;
730         int verbose;
731
732         if (argc != 2 && argc != 3) {
733                 fprintf(stderr, "usage: %s count [verbose]\n",cmdname(argv[0]));
734                 return -1;
735         }
736
737         IOCINIT(data);
738         count = strtoul(argv[1], NULL, 0);
739
740         if (argc == 3)
741                 verbose = get_verbose(argv[2]);
742         else
743                 verbose = 1;
744
745         data.ioc_obdo1.o_valid = 0xffffffff;
746         data.ioc_obdo1.o_id = 2;
747         gettimeofday(&start, NULL);
748         next_time.tv_sec = start.tv_sec - verbose;
749         next_time.tv_usec = start.tv_usec;
750         printf("%s: getting %d attrs (testing only): %s", cmdname(argv[0]),
751                count, ctime(&start.tv_sec));
752
753         for (i = 1, next_count = verbose; i <= count; i++) {
754                 rc = ioctl(fd, OBD_IOC_GETATTR , &data);
755                 if (rc < 0) {
756                         fprintf(stderr, "error: %s: #%d - %s\n",
757                                 cmdname(argv[0]), i, strerror(rc = errno));
758                         break;
759                 } else {
760                         if (be_verbose(verbose, &next_time, i,&next_count,count))
761                         printf("%s: got attr #%d\n", cmdname(argv[0]), i);
762                 }
763         }
764
765         if (!rc) {
766                 struct timeval end;
767                 double diff;
768
769                 gettimeofday(&end, NULL);
770
771                 diff = difftime(&end, &start);
772
773                 --i;
774                 printf("%s: %d attrs in %.4gs (%.4g attr/s): %s",
775                        cmdname(argv[0]), i, diff, (double)i / diff,
776                        ctime(&end.tv_sec));
777         }
778         return rc;
779 }
780
781 static int jt_test_brw(int argc, char **argv)
782 {
783         struct obd_ioctl_data data;
784         struct timeval start, next_time;
785         char *bulk, *b;
786         int pages = 1, obdos = 1, count, next_count;
787         int verbose = 1, write = 0, rw;
788         int i, o, p;
789         int len;
790
791         if (argc < 2 || argc > 6) {
792                 fprintf(stderr,
793                         "usage: %s count [write [verbose [pages [obdos]]]]\n",
794                         cmdname(argv[0]));
795                 return -1;
796         }
797
798         count = strtoul(argv[1], NULL, 0);
799
800         if (argc >= 3) {
801                 if (argv[2][0] == 'w' || argv[2][0] == '1')
802                         write = 1;
803                 else if (argv[2][0] == 'r' || argv[2][0] == '0')
804                         write = 0;
805
806                 verbose = get_verbose(argv[3]);
807         }
808
809         if (argc >= 5)
810                 pages = strtoul(argv[4], NULL, 0);
811         if (argc >= 6)
812                 obdos = strtoul(argv[5], NULL, 0);
813
814         if (obdos != 1 && obdos != 2) {
815                 fprintf(stderr, "error: %s: only 1 or 2 obdos supported\n",
816                         cmdname(argv[0]));
817                 return -2;
818         }
819
820         len = pages * PAGE_SIZE;
821
822         bulk = calloc(obdos, len);
823         if (!bulk) {
824                 fprintf(stderr, "error: %s: no memory allocating %dx%d pages\n",
825                         cmdname(argv[0]), obdos, pages);
826                 return -2;
827         }
828         IOCINIT(data);
829         data.ioc_conn2 = connid;
830         data.ioc_obdo1.o_id = 2;
831         data.ioc_count = len;
832         data.ioc_offset = 0;
833         data.ioc_plen1 = len;
834         data.ioc_pbuf1 = bulk;
835         if (obdos > 1) {
836                 data.ioc_obdo2.o_id = 3;
837                 data.ioc_plen2 = len;
838                 data.ioc_pbuf2 = bulk + len;
839         }
840
841         gettimeofday(&start, NULL);
842         next_time.tv_sec = start.tv_sec - verbose;
843         next_time.tv_usec = start.tv_usec;
844
845         printf("%s: %s %d (%dx%d pages) (testing only): %s",
846                cmdname(argv[0]), write ? "writing" : "reading",
847                count, obdos, pages, ctime(&start.tv_sec));
848
849         /*
850          * We will put in the start time (and loop count inside the loop)
851          * at the beginning of each page so that we will be able to validate
852          * (at some later time) whether the data actually made it or not.
853          *
854          * XXX we do not currently use any of this memory in OBD_IOC_BRW_*
855          *     just to avoid the overhead of the copy_{to,from}_user.  It
856          *     can be fixed if we ever need to send real data around.
857          */
858         for (o = 0, b = bulk; o < obdos; o++)
859                 for (p = 0; p < pages; p++, b += PAGE_SIZE)
860                         memcpy(b, &start, sizeof(start));
861
862         rw = write ? OBD_IOC_BRW_WRITE : OBD_IOC_BRW_READ;
863         for (i = 1, next_count = verbose; i <= count; i++) {
864                 if (write) {
865                         b = bulk + sizeof(struct timeval);
866                         for (o = 0; o < obdos; o++)
867                                 for (p = 0; p < pages; p++, b += PAGE_SIZE)
868                                         memcpy(b, &count, sizeof(count));
869                 }
870
871                 rc = ioctl(fd, rw, &data);
872                 if (rc) {
873                         fprintf(stderr, "error: %s: #%d - %s on %s\n",
874                                 cmdname(argv[0]), i, strerror(rc = errno),
875                                 write ? "write" : "read");
876                         break;
877                 } else if (be_verbose(verbose, &next_time, i,&next_count,count))
878                         printf("%s: %s number %d\n", cmdname(argv[0]),
879                                write ? "write" : "read", i);
880         }
881
882         free(bulk);
883
884         if (!rc) {
885                 struct timeval end;
886                 double diff;
887
888                 gettimeofday(&end, NULL);
889
890                 diff = difftime(&end, &start);
891
892                 --i;
893                 printf("%s: %s %dx%dx%d pages in %.4gs (%.4g pg/s): %s",
894                        cmdname(argv[0]), write ? "wrote" : "read", obdos,
895                        pages, i, diff, (double)obdos * i * pages / diff,
896                        ctime(&end.tv_sec));
897         }
898         return rc;
899 }
900
901 static int jt_test_ldlm(int argc, char **argv)
902 {
903         struct obd_ioctl_data data;
904
905         IOCINIT(data);
906         if (argc != 1) {
907                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
908                 return 1;
909         }
910
911         rc = ioctl(fd, IOC_LDLM_TEST, &data);
912         if (rc)
913                 fprintf(stderr, "error: %s: test failed: %s\n",
914                         cmdname(argv[0]), strerror(rc = errno));
915         return rc;
916 }
917
918 static int jt_newconn(int argc, char **argv)
919 {
920         struct obd_ioctl_data data;
921
922         IOCINIT(data);
923         if (argc != 1) {
924                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
925                 return -1;
926         }
927
928         rc = ioctl(fd, OBD_IOC_RECOVD_NEWCONN , &data);
929         if (rc < 0)
930                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
931                         strerror(rc = errno));
932
933         return rc;
934 }
935
936 static int jt_quit(int argc, char **argv)
937 {
938         Parser_quit(argc, argv);
939
940         return rc;
941 }
942
943 command_t cmdlist[] = {
944         /* Metacommands */
945         {"--device", jt__device, 0, "--device <devno> <command [args ...]>"},
946         {"--threads", jt__threads, 0,
947                 "--threads <threads> <devno> <command [args ...]>"},
948
949         /* Device configuration commands */
950         {"newdev", jt_newdev, 0, "set device to a new unused obd (no args)"},
951         {"device", jt_device, 0, "set current device (args device_no name)"},
952         {"name2dev", jt_name2dev, 0, "set device by name (args name)"},
953         {"attach", jt_attach, 0, "name the type of device (args: type data"},
954         {"setup", jt_setup, 0, "setup device (args: <blkdev> [data]"},
955         {"detach", jt_detach, 0, "detach the current device (arg: )"},
956         {"cleanup", jt_cleanup, 0, "cleanup the current device (arg: )"},
957
958         /* Session commands */
959         {"connect", jt_connect, 0, "connect - get a connection to device"},
960         {"disconnect", jt_disconnect, 0,
961                 "disconnect - break connection to device"},
962
963         /* Session operations */
964         {"create", jt_create, 0, "create [count [mode [verbose]]]"},
965         {"destroy", jt_destroy, 0, "destroy <id>"},
966         {"getattr", jt_getattr, 0, "getattr <id>"},
967         {"setattr", jt_setattr, 0, "setattr <id> <mode>"},
968         {"newconn", jt_newconn, 0, "newconn [newuuid]"},
969         {"test_getattr", jt_test_getattr, 0, "test_getattr <count> [verbose]"},
970         {"test_brw", jt_test_brw, 0, "test_brw <count> [write [verbose]]"},
971         {"test_ldlm", jt_test_ldlm, 0, "test lock manager (no args)"},
972
973         /* User interface commands */
974         {"help", Parser_help, 0, "help"},
975         {"exit", jt_quit, 0, "quit"},
976         {"quit", jt_quit, 0, "quit"},
977         { 0, 0, 0, NULL }
978 };
979
980
981 static void signal_server(int sig)
982 {
983         if (sig == SIGINT) {
984                 do_disconnect("sigint", 1);
985                 exit(1);
986         } else {
987                 fprintf(stderr, "%s: got signal %d\n", cmdname("sigint"), sig);
988         }
989 }
990
991 int main(int argc, char **argv)
992 {
993         struct sigaction sigact;
994
995         sigact.sa_handler = signal_server;
996         sigfillset(&sigact.sa_mask);
997         sigact.sa_flags = SA_RESTART;
998         sigaction(SIGINT, &sigact, NULL);
999
1000
1001         if (argc > 1) {
1002                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
1003         } else {
1004                 Parser_init("obdctl > ", cmdlist);
1005                 rc = Parser_commands();
1006         }
1007
1008         do_disconnect(argv[0], 1);
1009         return rc;
1010 }
1011