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