Annotation of qemu/qemu-io.c, revision 1.1.1.3
1.1 root 1: /*
2: * Command line utility to exercise the QEMU I/O path.
3: *
4: * Copyright (C) 2009 Red Hat, Inc.
5: * Copyright (c) 2003-2005 Silicon Graphics, Inc.
6: *
7: * This work is licensed under the terms of the GNU GPL, version 2 or later.
8: * See the COPYING file in the top-level directory.
9: */
10: #include <sys/time.h>
11: #include <sys/types.h>
12: #include <stdarg.h>
13: #include <stdio.h>
14: #include <getopt.h>
15: #include <libgen.h>
16:
17: #include "qemu-common.h"
18: #include "block_int.h"
19: #include "cmd.h"
20:
21: #define VERSION "0.0.1"
22:
23: #define CMD_NOFILE_OK 0x01
24:
25: char *progname;
26: static BlockDriverState *bs;
27:
28: static int misalign;
29:
30: /*
1.1.1.2 root 31: * Parse the pattern argument to various sub-commands.
32: *
33: * Because the pattern is used as an argument to memset it must evaluate
34: * to an unsigned integer that fits into a single byte.
35: */
36: static int parse_pattern(const char *arg)
37: {
38: char *endptr = NULL;
39: long pattern;
40:
41: pattern = strtol(arg, &endptr, 0);
42: if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') {
43: printf("%s is not a valid pattern byte\n", arg);
44: return -1;
45: }
46:
47: return pattern;
48: }
49:
50: /*
1.1 root 51: * Memory allocation helpers.
52: *
53: * Make sure memory is aligned by default, or purposefully misaligned if
54: * that is specified on the command line.
55: */
56:
57: #define MISALIGN_OFFSET 16
58: static void *qemu_io_alloc(size_t len, int pattern)
59: {
60: void *buf;
61:
62: if (misalign)
63: len += MISALIGN_OFFSET;
64: buf = qemu_memalign(512, len);
65: memset(buf, pattern, len);
66: if (misalign)
67: buf += MISALIGN_OFFSET;
68: return buf;
69: }
70:
71: static void qemu_io_free(void *p)
72: {
73: if (misalign)
74: p -= MISALIGN_OFFSET;
75: qemu_vfree(p);
76: }
77:
78: static void
79: dump_buffer(const void *buffer, int64_t offset, int len)
80: {
81: int i, j;
82: const uint8_t *p;
83:
84: for (i = 0, p = buffer; i < len; i += 16) {
85: const uint8_t *s = p;
86:
1.1.1.3 ! root 87: printf("%08" PRIx64 ": ", offset + i);
1.1 root 88: for (j = 0; j < 16 && i + j < len; j++, p++)
89: printf("%02x ", *p);
90: printf(" ");
91: for (j = 0; j < 16 && i + j < len; j++, s++) {
92: if (isalnum(*s))
93: printf("%c", *s);
94: else
95: printf(".");
96: }
97: printf("\n");
98: }
99: }
100:
101: static void
102: print_report(const char *op, struct timeval *t, int64_t offset,
103: int count, int total, int cnt, int Cflag)
104: {
105: char s1[64], s2[64], ts[64];
106:
107: timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0);
108: if (!Cflag) {
109: cvtstr((double)total, s1, sizeof(s1));
110: cvtstr(tdiv((double)total, *t), s2, sizeof(s2));
1.1.1.3 ! root 111: printf("%s %d/%d bytes at offset %" PRId64 "\n",
! 112: op, total, count, offset);
1.1 root 113: printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n",
114: s1, cnt, ts, s2, tdiv((double)cnt, *t));
115: } else {/* bytes,ops,time,bytes/sec,ops/sec */
116: printf("%d,%d,%s,%.3f,%.3f\n",
117: total, cnt, ts,
118: tdiv((double)total, *t),
119: tdiv((double)cnt, *t));
120: }
121: }
122:
123: /*
124: * Parse multiple length statements for vectored I/O, and construct an I/O
125: * vector matching it.
126: */
127: static void *
128: create_iovec(QEMUIOVector *qiov, char **argv, int nr_iov, int pattern)
129: {
130: size_t *sizes = calloc(nr_iov, sizeof(size_t));
131: size_t count = 0;
1.1.1.2 root 132: void *buf = NULL;
133: void *p;
1.1 root 134: int i;
135:
136: for (i = 0; i < nr_iov; i++) {
137: char *arg = argv[i];
1.1.1.3 ! root 138: uint64_t len;
1.1 root 139:
140: len = cvtnum(arg);
141: if (len < 0) {
142: printf("non-numeric length argument -- %s\n", arg);
1.1.1.2 root 143: goto fail;
1.1 root 144: }
145:
146: /* should be SIZE_T_MAX, but that doesn't exist */
147: if (len > UINT_MAX) {
148: printf("too large length argument -- %s\n", arg);
1.1.1.2 root 149: goto fail;
1.1 root 150: }
151:
152: if (len & 0x1ff) {
1.1.1.3 ! root 153: printf("length argument %" PRId64
! 154: " is not sector aligned\n", len);
1.1.1.2 root 155: goto fail;
1.1 root 156: }
157:
158: sizes[i] = len;
159: count += len;
160: }
161:
162: qemu_iovec_init(qiov, nr_iov);
163:
164: buf = p = qemu_io_alloc(count, pattern);
165:
166: for (i = 0; i < nr_iov; i++) {
167: qemu_iovec_add(qiov, p, sizes[i]);
168: p += sizes[i];
169: }
170:
1.1.1.2 root 171: fail:
1.1 root 172: free(sizes);
173: return buf;
174: }
175:
176: static int do_read(char *buf, int64_t offset, int count, int *total)
177: {
178: int ret;
179:
180: ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9);
181: if (ret < 0)
182: return ret;
183: *total = count;
184: return 1;
185: }
186:
187: static int do_write(char *buf, int64_t offset, int count, int *total)
188: {
189: int ret;
190:
191: ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9);
192: if (ret < 0)
193: return ret;
194: *total = count;
195: return 1;
196: }
197:
198: static int do_pread(char *buf, int64_t offset, int count, int *total)
199: {
200: *total = bdrv_pread(bs, offset, (uint8_t *)buf, count);
201: if (*total < 0)
202: return *total;
203: return 1;
204: }
205:
206: static int do_pwrite(char *buf, int64_t offset, int count, int *total)
207: {
208: *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count);
209: if (*total < 0)
210: return *total;
211: return 1;
212: }
213:
214: static int do_load_vmstate(char *buf, int64_t offset, int count, int *total)
215: {
216: *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count);
217: if (*total < 0)
218: return *total;
219: return 1;
220: }
221:
222: static int do_save_vmstate(char *buf, int64_t offset, int count, int *total)
223: {
224: *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count);
225: if (*total < 0)
226: return *total;
227: return 1;
228: }
229:
230: #define NOT_DONE 0x7fffffff
231: static void aio_rw_done(void *opaque, int ret)
232: {
233: *(int *)opaque = ret;
234: }
235:
236: static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total)
237: {
238: BlockDriverAIOCB *acb;
239: int async_ret = NOT_DONE;
240:
241: acb = bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
242: aio_rw_done, &async_ret);
243: if (!acb)
244: return -EIO;
245:
246: while (async_ret == NOT_DONE)
247: qemu_aio_wait();
248:
249: *total = qiov->size;
250: return async_ret < 0 ? async_ret : 1;
251: }
252:
253: static int do_aio_writev(QEMUIOVector *qiov, int64_t offset, int *total)
254: {
255: BlockDriverAIOCB *acb;
256: int async_ret = NOT_DONE;
257:
258: acb = bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
259: aio_rw_done, &async_ret);
260: if (!acb)
261: return -EIO;
262:
263: while (async_ret == NOT_DONE)
264: qemu_aio_wait();
265:
266: *total = qiov->size;
267: return async_ret < 0 ? async_ret : 1;
268: }
269:
1.1.1.3 ! root 270: struct multiwrite_async_ret {
! 271: int num_done;
! 272: int error;
! 273: };
! 274:
! 275: static void multiwrite_cb(void *opaque, int ret)
! 276: {
! 277: struct multiwrite_async_ret *async_ret = opaque;
! 278:
! 279: async_ret->num_done++;
! 280: if (ret < 0) {
! 281: async_ret->error = ret;
! 282: }
! 283: }
! 284:
! 285: static int do_aio_multiwrite(BlockRequest* reqs, int num_reqs, int *total)
! 286: {
! 287: int i, ret;
! 288: struct multiwrite_async_ret async_ret = {
! 289: .num_done = 0,
! 290: .error = 0,
! 291: };
! 292:
! 293: *total = 0;
! 294: for (i = 0; i < num_reqs; i++) {
! 295: reqs[i].cb = multiwrite_cb;
! 296: reqs[i].opaque = &async_ret;
! 297: *total += reqs[i].qiov->size;
! 298: }
! 299:
! 300: ret = bdrv_aio_multiwrite(bs, reqs, num_reqs);
! 301: if (ret < 0) {
! 302: return ret;
! 303: }
! 304:
! 305: while (async_ret.num_done < num_reqs) {
! 306: qemu_aio_wait();
! 307: }
! 308:
! 309: return async_ret.error < 0 ? async_ret.error : 1;
! 310: }
1.1 root 311:
312: static void
313: read_help(void)
314: {
315: printf(
316: "\n"
317: " reads a range of bytes from the given offset\n"
318: "\n"
319: " Example:\n"
320: " 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n"
321: "\n"
322: " Reads a segment of the currently open file, optionally dumping it to the\n"
323: " standard output stream (with -v option) for subsequent inspection.\n"
324: " -b, -- read from the VM state rather than the virtual disk\n"
325: " -C, -- report statistics in a machine parsable format\n"
326: " -l, -- length for pattern verification (only with -P)\n"
327: " -p, -- use bdrv_pread to read the file\n"
328: " -P, -- use a pattern to verify read data\n"
329: " -q, -- quite mode, do not show I/O statistics\n"
330: " -s, -- start offset for pattern verification (only with -P)\n"
331: " -v, -- dump buffer to standard output\n"
332: "\n");
333: }
334:
1.1.1.2 root 335: static int read_f(int argc, char **argv);
336:
337: static const cmdinfo_t read_cmd = {
338: .name = "read",
339: .altname = "r",
340: .cfunc = read_f,
341: .argmin = 2,
342: .argmax = -1,
343: .args = "[-abCpqv] [-P pattern [-s off] [-l len]] off len",
344: .oneline = "reads a number of bytes at a specified offset",
345: .help = read_help,
346: };
347:
1.1 root 348: static int
349: read_f(int argc, char **argv)
350: {
351: struct timeval t1, t2;
352: int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
353: int Pflag = 0, sflag = 0, lflag = 0, bflag = 0;
354: int c, cnt;
355: char *buf;
356: int64_t offset;
357: int count;
358: /* Some compilers get confused and warn if this is not initialized. */
359: int total = 0;
360: int pattern = 0, pattern_offset = 0, pattern_count = 0;
361:
362: while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != EOF) {
363: switch (c) {
364: case 'b':
365: bflag = 1;
366: break;
367: case 'C':
368: Cflag = 1;
369: break;
370: case 'l':
371: lflag = 1;
372: pattern_count = cvtnum(optarg);
373: if (pattern_count < 0) {
374: printf("non-numeric length argument -- %s\n", optarg);
375: return 0;
376: }
377: break;
378: case 'p':
379: pflag = 1;
380: break;
381: case 'P':
382: Pflag = 1;
1.1.1.2 root 383: pattern = parse_pattern(optarg);
384: if (pattern < 0)
385: return 0;
1.1 root 386: break;
387: case 'q':
388: qflag = 1;
389: break;
390: case 's':
391: sflag = 1;
392: pattern_offset = cvtnum(optarg);
393: if (pattern_offset < 0) {
394: printf("non-numeric length argument -- %s\n", optarg);
395: return 0;
396: }
397: break;
398: case 'v':
399: vflag = 1;
400: break;
401: default:
402: return command_usage(&read_cmd);
403: }
404: }
405:
406: if (optind != argc - 2)
407: return command_usage(&read_cmd);
408:
409: if (bflag && pflag) {
410: printf("-b and -p cannot be specified at the same time\n");
411: return 0;
412: }
413:
414: offset = cvtnum(argv[optind]);
415: if (offset < 0) {
416: printf("non-numeric length argument -- %s\n", argv[optind]);
417: return 0;
418: }
419:
420: optind++;
421: count = cvtnum(argv[optind]);
422: if (count < 0) {
423: printf("non-numeric length argument -- %s\n", argv[optind]);
424: return 0;
425: }
426:
427: if (!Pflag && (lflag || sflag)) {
428: return command_usage(&read_cmd);
429: }
430:
431: if (!lflag) {
432: pattern_count = count - pattern_offset;
433: }
434:
435: if ((pattern_count < 0) || (pattern_count + pattern_offset > count)) {
436: printf("pattern verfication range exceeds end of read data\n");
437: return 0;
438: }
439:
440: if (!pflag)
441: if (offset & 0x1ff) {
1.1.1.3 ! root 442: printf("offset %" PRId64 " is not sector aligned\n",
! 443: offset);
1.1 root 444: return 0;
445:
446: if (count & 0x1ff) {
447: printf("count %d is not sector aligned\n",
448: count);
449: return 0;
450: }
451: }
452:
453: buf = qemu_io_alloc(count, 0xab);
454:
455: gettimeofday(&t1, NULL);
456: if (pflag)
457: cnt = do_pread(buf, offset, count, &total);
458: else if (bflag)
459: cnt = do_load_vmstate(buf, offset, count, &total);
460: else
461: cnt = do_read(buf, offset, count, &total);
462: gettimeofday(&t2, NULL);
463:
464: if (cnt < 0) {
465: printf("read failed: %s\n", strerror(-cnt));
466: goto out;
467: }
468:
469: if (Pflag) {
470: void* cmp_buf = malloc(pattern_count);
471: memset(cmp_buf, pattern, pattern_count);
472: if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
1.1.1.3 ! root 473: printf("Pattern verification failed at offset %"
! 474: PRId64 ", %d bytes\n",
! 475: offset + pattern_offset, pattern_count);
1.1 root 476: }
477: free(cmp_buf);
478: }
479:
480: if (qflag)
481: goto out;
482:
483: if (vflag)
484: dump_buffer(buf, offset, count);
485:
486: /* Finally, report back -- -C gives a parsable format */
487: t2 = tsub(t2, t1);
488: print_report("read", &t2, offset, count, total, cnt, Cflag);
489:
490: out:
491: qemu_io_free(buf);
492:
493: return 0;
494: }
495:
496: static void
497: readv_help(void)
498: {
499: printf(
500: "\n"
501: " reads a range of bytes from the given offset into multiple buffers\n"
502: "\n"
503: " Example:\n"
504: " 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
505: "\n"
506: " Reads a segment of the currently open file, optionally dumping it to the\n"
507: " standard output stream (with -v option) for subsequent inspection.\n"
508: " Uses multiple iovec buffers if more than one byte range is specified.\n"
509: " -C, -- report statistics in a machine parsable format\n"
510: " -P, -- use a pattern to verify read data\n"
511: " -v, -- dump buffer to standard output\n"
512: " -q, -- quite mode, do not show I/O statistics\n"
513: "\n");
514: }
515:
1.1.1.2 root 516: static int readv_f(int argc, char **argv);
517:
518: static const cmdinfo_t readv_cmd = {
519: .name = "readv",
520: .cfunc = readv_f,
521: .argmin = 2,
522: .argmax = -1,
523: .args = "[-Cqv] [-P pattern ] off len [len..]",
524: .oneline = "reads a number of bytes at a specified offset",
525: .help = readv_help,
526: };
527:
1.1 root 528: static int
529: readv_f(int argc, char **argv)
530: {
531: struct timeval t1, t2;
532: int Cflag = 0, qflag = 0, vflag = 0;
533: int c, cnt;
534: char *buf;
535: int64_t offset;
1.1.1.3 ! root 536: /* Some compilers get confused and warn if this is not initialized. */
! 537: int total = 0;
1.1 root 538: int nr_iov;
539: QEMUIOVector qiov;
540: int pattern = 0;
541: int Pflag = 0;
542:
543: while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
544: switch (c) {
545: case 'C':
546: Cflag = 1;
547: break;
548: case 'P':
549: Pflag = 1;
1.1.1.2 root 550: pattern = parse_pattern(optarg);
551: if (pattern < 0)
552: return 0;
1.1 root 553: break;
554: case 'q':
555: qflag = 1;
556: break;
557: case 'v':
558: vflag = 1;
559: break;
560: default:
561: return command_usage(&readv_cmd);
562: }
563: }
564:
565: if (optind > argc - 2)
566: return command_usage(&readv_cmd);
567:
568:
569: offset = cvtnum(argv[optind]);
570: if (offset < 0) {
571: printf("non-numeric length argument -- %s\n", argv[optind]);
572: return 0;
573: }
574: optind++;
575:
576: if (offset & 0x1ff) {
1.1.1.3 ! root 577: printf("offset %" PRId64 " is not sector aligned\n",
! 578: offset);
1.1 root 579: return 0;
580: }
581:
582: nr_iov = argc - optind;
583: buf = create_iovec(&qiov, &argv[optind], nr_iov, 0xab);
584:
585: gettimeofday(&t1, NULL);
586: cnt = do_aio_readv(&qiov, offset, &total);
587: gettimeofday(&t2, NULL);
588:
589: if (cnt < 0) {
590: printf("readv failed: %s\n", strerror(-cnt));
591: goto out;
592: }
593:
594: if (Pflag) {
595: void* cmp_buf = malloc(qiov.size);
596: memset(cmp_buf, pattern, qiov.size);
597: if (memcmp(buf, cmp_buf, qiov.size)) {
1.1.1.3 ! root 598: printf("Pattern verification failed at offset %"
! 599: PRId64 ", %zd bytes\n",
! 600: offset, qiov.size);
1.1 root 601: }
602: free(cmp_buf);
603: }
604:
605: if (qflag)
606: goto out;
607:
608: if (vflag)
609: dump_buffer(buf, offset, qiov.size);
610:
611: /* Finally, report back -- -C gives a parsable format */
612: t2 = tsub(t2, t1);
613: print_report("read", &t2, offset, qiov.size, total, cnt, Cflag);
614:
615: out:
616: qemu_io_free(buf);
617: return 0;
618: }
619:
620: static void
621: write_help(void)
622: {
623: printf(
624: "\n"
625: " writes a range of bytes from the given offset\n"
626: "\n"
627: " Example:\n"
628: " 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n"
629: "\n"
630: " Writes into a segment of the currently open file, using a buffer\n"
631: " filled with a set pattern (0xcdcdcdcd).\n"
632: " -b, -- write to the VM state rather than the virtual disk\n"
633: " -p, -- use bdrv_pwrite to write the file\n"
634: " -P, -- use different pattern to fill file\n"
635: " -C, -- report statistics in a machine parsable format\n"
636: " -q, -- quite mode, do not show I/O statistics\n"
637: "\n");
638: }
639:
1.1.1.2 root 640: static int write_f(int argc, char **argv);
641:
642: static const cmdinfo_t write_cmd = {
643: .name = "write",
644: .altname = "w",
645: .cfunc = write_f,
646: .argmin = 2,
647: .argmax = -1,
648: .args = "[-abCpq] [-P pattern ] off len",
649: .oneline = "writes a number of bytes at a specified offset",
650: .help = write_help,
651: };
652:
1.1 root 653: static int
654: write_f(int argc, char **argv)
655: {
656: struct timeval t1, t2;
657: int Cflag = 0, pflag = 0, qflag = 0, bflag = 0;
658: int c, cnt;
659: char *buf;
660: int64_t offset;
661: int count;
662: /* Some compilers get confused and warn if this is not initialized. */
663: int total = 0;
664: int pattern = 0xcd;
665:
666: while ((c = getopt(argc, argv, "bCpP:q")) != EOF) {
667: switch (c) {
668: case 'b':
669: bflag = 1;
670: break;
671: case 'C':
672: Cflag = 1;
673: break;
674: case 'p':
675: pflag = 1;
676: break;
677: case 'P':
1.1.1.2 root 678: pattern = parse_pattern(optarg);
679: if (pattern < 0)
680: return 0;
1.1 root 681: break;
682: case 'q':
683: qflag = 1;
684: break;
685: default:
686: return command_usage(&write_cmd);
687: }
688: }
689:
690: if (optind != argc - 2)
691: return command_usage(&write_cmd);
692:
693: if (bflag && pflag) {
694: printf("-b and -p cannot be specified at the same time\n");
695: return 0;
696: }
697:
698: offset = cvtnum(argv[optind]);
699: if (offset < 0) {
700: printf("non-numeric length argument -- %s\n", argv[optind]);
701: return 0;
702: }
703:
704: optind++;
705: count = cvtnum(argv[optind]);
706: if (count < 0) {
707: printf("non-numeric length argument -- %s\n", argv[optind]);
708: return 0;
709: }
710:
711: if (!pflag) {
712: if (offset & 0x1ff) {
1.1.1.3 ! root 713: printf("offset %" PRId64 " is not sector aligned\n",
! 714: offset);
1.1 root 715: return 0;
716: }
717:
718: if (count & 0x1ff) {
719: printf("count %d is not sector aligned\n",
720: count);
721: return 0;
722: }
723: }
724:
725: buf = qemu_io_alloc(count, pattern);
726:
727: gettimeofday(&t1, NULL);
728: if (pflag)
729: cnt = do_pwrite(buf, offset, count, &total);
730: else if (bflag)
731: cnt = do_save_vmstate(buf, offset, count, &total);
732: else
733: cnt = do_write(buf, offset, count, &total);
734: gettimeofday(&t2, NULL);
735:
736: if (cnt < 0) {
737: printf("write failed: %s\n", strerror(-cnt));
738: goto out;
739: }
740:
741: if (qflag)
742: goto out;
743:
744: /* Finally, report back -- -C gives a parsable format */
745: t2 = tsub(t2, t1);
746: print_report("wrote", &t2, offset, count, total, cnt, Cflag);
747:
748: out:
749: qemu_io_free(buf);
750:
751: return 0;
752: }
753:
754: static void
755: writev_help(void)
756: {
757: printf(
758: "\n"
759: " writes a range of bytes from the given offset source from multiple buffers\n"
760: "\n"
761: " Example:\n"
762: " 'write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
763: "\n"
764: " Writes into a segment of the currently open file, using a buffer\n"
765: " filled with a set pattern (0xcdcdcdcd).\n"
766: " -P, -- use different pattern to fill file\n"
767: " -C, -- report statistics in a machine parsable format\n"
768: " -q, -- quite mode, do not show I/O statistics\n"
769: "\n");
770: }
771:
1.1.1.2 root 772: static int writev_f(int argc, char **argv);
773:
774: static const cmdinfo_t writev_cmd = {
775: .name = "writev",
776: .cfunc = writev_f,
777: .argmin = 2,
778: .argmax = -1,
779: .args = "[-Cq] [-P pattern ] off len [len..]",
780: .oneline = "writes a number of bytes at a specified offset",
781: .help = writev_help,
782: };
783:
1.1 root 784: static int
785: writev_f(int argc, char **argv)
786: {
787: struct timeval t1, t2;
788: int Cflag = 0, qflag = 0;
789: int c, cnt;
790: char *buf;
791: int64_t offset;
1.1.1.3 ! root 792: /* Some compilers get confused and warn if this is not initialized. */
! 793: int total = 0;
1.1 root 794: int nr_iov;
795: int pattern = 0xcd;
796: QEMUIOVector qiov;
797:
798: while ((c = getopt(argc, argv, "CqP:")) != EOF) {
799: switch (c) {
800: case 'C':
801: Cflag = 1;
802: break;
803: case 'q':
804: qflag = 1;
805: break;
806: case 'P':
1.1.1.2 root 807: pattern = parse_pattern(optarg);
808: if (pattern < 0)
809: return 0;
1.1 root 810: break;
811: default:
812: return command_usage(&writev_cmd);
813: }
814: }
815:
816: if (optind > argc - 2)
817: return command_usage(&writev_cmd);
818:
819: offset = cvtnum(argv[optind]);
820: if (offset < 0) {
821: printf("non-numeric length argument -- %s\n", argv[optind]);
822: return 0;
823: }
824: optind++;
825:
826: if (offset & 0x1ff) {
1.1.1.3 ! root 827: printf("offset %" PRId64 " is not sector aligned\n",
! 828: offset);
1.1 root 829: return 0;
830: }
831:
832: nr_iov = argc - optind;
833: buf = create_iovec(&qiov, &argv[optind], nr_iov, pattern);
834:
835: gettimeofday(&t1, NULL);
836: cnt = do_aio_writev(&qiov, offset, &total);
837: gettimeofday(&t2, NULL);
838:
839: if (cnt < 0) {
840: printf("writev failed: %s\n", strerror(-cnt));
841: goto out;
842: }
843:
844: if (qflag)
845: goto out;
846:
847: /* Finally, report back -- -C gives a parsable format */
848: t2 = tsub(t2, t1);
849: print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag);
850: out:
851: qemu_io_free(buf);
852: return 0;
853: }
854:
1.1.1.3 ! root 855: static void
! 856: multiwrite_help(void)
! 857: {
! 858: printf(
! 859: "\n"
! 860: " writes a range of bytes from the given offset source from multiple buffers,\n"
! 861: " in a batch of requests that may be merged by qemu\n"
! 862: "\n"
! 863: " Example:\n"
! 864: " 'multiwrite 512 1k 1k ; 4k 1k' \n"
! 865: " writes 2 kB at 512 bytes and 1 kB at 4 kB into the open file\n"
! 866: "\n"
! 867: " Writes into a segment of the currently open file, using a buffer\n"
! 868: " filled with a set pattern (0xcdcdcdcd). The pattern byte is increased\n"
! 869: " by one for each request contained in the multiwrite command.\n"
! 870: " -P, -- use different pattern to fill file\n"
! 871: " -C, -- report statistics in a machine parsable format\n"
! 872: " -q, -- quiet mode, do not show I/O statistics\n"
! 873: "\n");
! 874: }
! 875:
! 876: static int multiwrite_f(int argc, char **argv);
! 877:
! 878: static const cmdinfo_t multiwrite_cmd = {
! 879: .name = "multiwrite",
! 880: .cfunc = multiwrite_f,
! 881: .argmin = 2,
! 882: .argmax = -1,
! 883: .args = "[-Cq] [-P pattern ] off len [len..] [; off len [len..]..]",
! 884: .oneline = "issues multiple write requests at once",
! 885: .help = multiwrite_help,
! 886: };
! 887:
! 888: static int
! 889: multiwrite_f(int argc, char **argv)
! 890: {
! 891: struct timeval t1, t2;
! 892: int Cflag = 0, qflag = 0;
! 893: int c, cnt;
! 894: char **buf;
! 895: int64_t offset, first_offset = 0;
! 896: /* Some compilers get confused and warn if this is not initialized. */
! 897: int total = 0;
! 898: int nr_iov;
! 899: int nr_reqs;
! 900: int pattern = 0xcd;
! 901: QEMUIOVector *qiovs;
! 902: int i;
! 903: BlockRequest *reqs;
! 904:
! 905: while ((c = getopt(argc, argv, "CqP:")) != EOF) {
! 906: switch (c) {
! 907: case 'C':
! 908: Cflag = 1;
! 909: break;
! 910: case 'q':
! 911: qflag = 1;
! 912: break;
! 913: case 'P':
! 914: pattern = parse_pattern(optarg);
! 915: if (pattern < 0)
! 916: return 0;
! 917: break;
! 918: default:
! 919: return command_usage(&writev_cmd);
! 920: }
! 921: }
! 922:
! 923: if (optind > argc - 2)
! 924: return command_usage(&writev_cmd);
! 925:
! 926: nr_reqs = 1;
! 927: for (i = optind; i < argc; i++) {
! 928: if (!strcmp(argv[i], ";")) {
! 929: nr_reqs++;
! 930: }
! 931: }
! 932:
! 933: reqs = qemu_malloc(nr_reqs * sizeof(*reqs));
! 934: buf = qemu_malloc(nr_reqs * sizeof(*buf));
! 935: qiovs = qemu_malloc(nr_reqs * sizeof(*qiovs));
! 936:
! 937: for (i = 0; i < nr_reqs; i++) {
! 938: int j;
! 939:
! 940: /* Read the offset of the request */
! 941: offset = cvtnum(argv[optind]);
! 942: if (offset < 0) {
! 943: printf("non-numeric offset argument -- %s\n", argv[optind]);
! 944: return 0;
! 945: }
! 946: optind++;
! 947:
! 948: if (offset & 0x1ff) {
! 949: printf("offset %lld is not sector aligned\n",
! 950: (long long)offset);
! 951: return 0;
! 952: }
! 953:
! 954: if (i == 0) {
! 955: first_offset = offset;
! 956: }
! 957:
! 958: /* Read lengths for qiov entries */
! 959: for (j = optind; j < argc; j++) {
! 960: if (!strcmp(argv[j], ";")) {
! 961: break;
! 962: }
! 963: }
! 964:
! 965: nr_iov = j - optind;
! 966:
! 967: /* Build request */
! 968: reqs[i].qiov = &qiovs[i];
! 969: buf[i] = create_iovec(reqs[i].qiov, &argv[optind], nr_iov, pattern);
! 970: reqs[i].sector = offset >> 9;
! 971: reqs[i].nb_sectors = reqs[i].qiov->size >> 9;
! 972:
! 973: optind = j + 1;
! 974:
! 975: offset += reqs[i].qiov->size;
! 976: pattern++;
! 977: }
! 978:
! 979: gettimeofday(&t1, NULL);
! 980: cnt = do_aio_multiwrite(reqs, nr_reqs, &total);
! 981: gettimeofday(&t2, NULL);
! 982:
! 983: if (cnt < 0) {
! 984: printf("aio_multiwrite failed: %s\n", strerror(-cnt));
! 985: goto out;
! 986: }
! 987:
! 988: if (qflag)
! 989: goto out;
! 990:
! 991: /* Finally, report back -- -C gives a parsable format */
! 992: t2 = tsub(t2, t1);
! 993: print_report("wrote", &t2, first_offset, total, total, cnt, Cflag);
! 994: out:
! 995: for (i = 0; i < nr_reqs; i++) {
! 996: qemu_io_free(buf[i]);
! 997: qemu_iovec_destroy(&qiovs[i]);
! 998: }
! 999: qemu_free(buf);
! 1000: qemu_free(reqs);
! 1001: qemu_free(qiovs);
! 1002: return 0;
! 1003: }
! 1004:
1.1 root 1005: struct aio_ctx {
1006: QEMUIOVector qiov;
1007: int64_t offset;
1008: char *buf;
1009: int qflag;
1010: int vflag;
1011: int Cflag;
1012: int Pflag;
1013: int pattern;
1014: struct timeval t1;
1015: };
1016:
1017: static void
1018: aio_write_done(void *opaque, int ret)
1019: {
1020: struct aio_ctx *ctx = opaque;
1021: struct timeval t2;
1022:
1023: gettimeofday(&t2, NULL);
1024:
1025:
1026: if (ret < 0) {
1027: printf("aio_write failed: %s\n", strerror(-ret));
1028: goto out;
1029: }
1030:
1031: if (ctx->qflag) {
1032: goto out;
1033: }
1034:
1035: /* Finally, report back -- -C gives a parsable format */
1036: t2 = tsub(t2, ctx->t1);
1037: print_report("wrote", &t2, ctx->offset, ctx->qiov.size,
1038: ctx->qiov.size, 1, ctx->Cflag);
1039: out:
1040: qemu_io_free(ctx->buf);
1041: free(ctx);
1042: }
1043:
1044: static void
1045: aio_read_done(void *opaque, int ret)
1046: {
1047: struct aio_ctx *ctx = opaque;
1048: struct timeval t2;
1049:
1050: gettimeofday(&t2, NULL);
1051:
1052: if (ret < 0) {
1053: printf("readv failed: %s\n", strerror(-ret));
1054: goto out;
1055: }
1056:
1057: if (ctx->Pflag) {
1058: void *cmp_buf = malloc(ctx->qiov.size);
1059:
1060: memset(cmp_buf, ctx->pattern, ctx->qiov.size);
1061: if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
1.1.1.3 ! root 1062: printf("Pattern verification failed at offset %"
! 1063: PRId64 ", %zd bytes\n",
! 1064: ctx->offset, ctx->qiov.size);
1.1 root 1065: }
1066: free(cmp_buf);
1067: }
1068:
1069: if (ctx->qflag) {
1070: goto out;
1071: }
1072:
1073: if (ctx->vflag) {
1074: dump_buffer(ctx->buf, ctx->offset, ctx->qiov.size);
1075: }
1076:
1077: /* Finally, report back -- -C gives a parsable format */
1078: t2 = tsub(t2, ctx->t1);
1079: print_report("read", &t2, ctx->offset, ctx->qiov.size,
1080: ctx->qiov.size, 1, ctx->Cflag);
1081: out:
1082: qemu_io_free(ctx->buf);
1083: free(ctx);
1084: }
1085:
1086: static void
1087: aio_read_help(void)
1088: {
1089: printf(
1090: "\n"
1091: " asynchronously reads a range of bytes from the given offset\n"
1092: "\n"
1093: " Example:\n"
1094: " 'aio_read -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
1095: "\n"
1096: " Reads a segment of the currently open file, optionally dumping it to the\n"
1097: " standard output stream (with -v option) for subsequent inspection.\n"
1.1.1.3 ! root 1098: " The read is performed asynchronously and the aio_flush command must be\n"
! 1099: " used to ensure all outstanding aio requests have been completed\n"
1.1 root 1100: " -C, -- report statistics in a machine parsable format\n"
1101: " -P, -- use a pattern to verify read data\n"
1102: " -v, -- dump buffer to standard output\n"
1103: " -q, -- quite mode, do not show I/O statistics\n"
1104: "\n");
1105: }
1106:
1.1.1.2 root 1107: static int aio_read_f(int argc, char **argv);
1108:
1109: static const cmdinfo_t aio_read_cmd = {
1110: .name = "aio_read",
1111: .cfunc = aio_read_f,
1112: .argmin = 2,
1113: .argmax = -1,
1114: .args = "[-Cqv] [-P pattern ] off len [len..]",
1115: .oneline = "asynchronously reads a number of bytes",
1116: .help = aio_read_help,
1117: };
1118:
1.1 root 1119: static int
1120: aio_read_f(int argc, char **argv)
1121: {
1122: int nr_iov, c;
1123: struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
1124: BlockDriverAIOCB *acb;
1125:
1126: while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
1127: switch (c) {
1128: case 'C':
1129: ctx->Cflag = 1;
1130: break;
1131: case 'P':
1132: ctx->Pflag = 1;
1.1.1.2 root 1133: ctx->pattern = parse_pattern(optarg);
1134: if (ctx->pattern < 0)
1135: return 0;
1.1 root 1136: break;
1137: case 'q':
1138: ctx->qflag = 1;
1139: break;
1140: case 'v':
1141: ctx->vflag = 1;
1142: break;
1143: default:
1144: free(ctx);
1145: return command_usage(&aio_read_cmd);
1146: }
1147: }
1148:
1149: if (optind > argc - 2) {
1150: free(ctx);
1151: return command_usage(&aio_read_cmd);
1152: }
1153:
1154: ctx->offset = cvtnum(argv[optind]);
1155: if (ctx->offset < 0) {
1156: printf("non-numeric length argument -- %s\n", argv[optind]);
1157: free(ctx);
1158: return 0;
1159: }
1160: optind++;
1161:
1162: if (ctx->offset & 0x1ff) {
1.1.1.3 ! root 1163: printf("offset %" PRId64 " is not sector aligned\n",
! 1164: ctx->offset);
1.1 root 1165: free(ctx);
1166: return 0;
1167: }
1168:
1169: nr_iov = argc - optind;
1170: ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, 0xab);
1171:
1172: gettimeofday(&ctx->t1, NULL);
1173: acb = bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov,
1174: ctx->qiov.size >> 9, aio_read_done, ctx);
1175: if (!acb) {
1176: free(ctx->buf);
1177: free(ctx);
1178: return -EIO;
1179: }
1180:
1181: return 0;
1182: }
1183:
1184: static void
1185: aio_write_help(void)
1186: {
1187: printf(
1188: "\n"
1189: " asynchronously writes a range of bytes from the given offset source \n"
1190: " from multiple buffers\n"
1191: "\n"
1192: " Example:\n"
1193: " 'aio_write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
1194: "\n"
1195: " Writes into a segment of the currently open file, using a buffer\n"
1196: " filled with a set pattern (0xcdcdcdcd).\n"
1.1.1.3 ! root 1197: " The write is performed asynchronously and the aio_flush command must be\n"
! 1198: " used to ensure all outstanding aio requests have been completed\n"
1.1 root 1199: " -P, -- use different pattern to fill file\n"
1200: " -C, -- report statistics in a machine parsable format\n"
1201: " -q, -- quite mode, do not show I/O statistics\n"
1202: "\n");
1203: }
1204:
1.1.1.2 root 1205: static int aio_write_f(int argc, char **argv);
1206:
1207: static const cmdinfo_t aio_write_cmd = {
1208: .name = "aio_write",
1209: .cfunc = aio_write_f,
1210: .argmin = 2,
1211: .argmax = -1,
1212: .args = "[-Cq] [-P pattern ] off len [len..]",
1213: .oneline = "asynchronously writes a number of bytes",
1214: .help = aio_write_help,
1215: };
1.1 root 1216:
1217: static int
1218: aio_write_f(int argc, char **argv)
1219: {
1220: int nr_iov, c;
1221: int pattern = 0xcd;
1222: struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
1223: BlockDriverAIOCB *acb;
1224:
1225: while ((c = getopt(argc, argv, "CqP:")) != EOF) {
1226: switch (c) {
1227: case 'C':
1228: ctx->Cflag = 1;
1229: break;
1230: case 'q':
1231: ctx->qflag = 1;
1232: break;
1233: case 'P':
1.1.1.2 root 1234: pattern = parse_pattern(optarg);
1235: if (pattern < 0)
1236: return 0;
1.1 root 1237: break;
1238: default:
1239: free(ctx);
1240: return command_usage(&aio_write_cmd);
1241: }
1242: }
1243:
1244: if (optind > argc - 2) {
1245: free(ctx);
1246: return command_usage(&aio_write_cmd);
1247: }
1248:
1249: ctx->offset = cvtnum(argv[optind]);
1250: if (ctx->offset < 0) {
1251: printf("non-numeric length argument -- %s\n", argv[optind]);
1252: free(ctx);
1253: return 0;
1254: }
1255: optind++;
1256:
1257: if (ctx->offset & 0x1ff) {
1.1.1.3 ! root 1258: printf("offset %" PRId64 " is not sector aligned\n",
! 1259: ctx->offset);
1.1 root 1260: free(ctx);
1261: return 0;
1262: }
1263:
1264: nr_iov = argc - optind;
1265: ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, pattern);
1266:
1267: gettimeofday(&ctx->t1, NULL);
1268: acb = bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov,
1269: ctx->qiov.size >> 9, aio_write_done, ctx);
1270: if (!acb) {
1271: free(ctx->buf);
1272: free(ctx);
1273: return -EIO;
1274: }
1275:
1276: return 0;
1277: }
1278:
1279: static int
1280: aio_flush_f(int argc, char **argv)
1281: {
1282: qemu_aio_flush();
1283: return 0;
1284: }
1285:
1286: static const cmdinfo_t aio_flush_cmd = {
1287: .name = "aio_flush",
1288: .cfunc = aio_flush_f,
1.1.1.3 ! root 1289: .oneline = "completes all outstanding aio requests"
1.1 root 1290: };
1291:
1292: static int
1293: flush_f(int argc, char **argv)
1294: {
1295: bdrv_flush(bs);
1296: return 0;
1297: }
1298:
1299: static const cmdinfo_t flush_cmd = {
1300: .name = "flush",
1301: .altname = "f",
1302: .cfunc = flush_f,
1303: .oneline = "flush all in-core file state to disk",
1304: };
1305:
1306: static int
1307: truncate_f(int argc, char **argv)
1308: {
1309: int64_t offset;
1310: int ret;
1311:
1312: offset = cvtnum(argv[1]);
1313: if (offset < 0) {
1314: printf("non-numeric truncate argument -- %s\n", argv[1]);
1315: return 0;
1316: }
1317:
1318: ret = bdrv_truncate(bs, offset);
1319: if (ret < 0) {
1.1.1.3 ! root 1320: printf("truncate: %s\n", strerror(-ret));
1.1 root 1321: return 0;
1322: }
1323:
1324: return 0;
1325: }
1326:
1327: static const cmdinfo_t truncate_cmd = {
1328: .name = "truncate",
1329: .altname = "t",
1330: .cfunc = truncate_f,
1331: .argmin = 1,
1332: .argmax = 1,
1333: .args = "off",
1334: .oneline = "truncates the current file at the given offset",
1335: };
1336:
1337: static int
1338: length_f(int argc, char **argv)
1339: {
1340: int64_t size;
1341: char s1[64];
1342:
1343: size = bdrv_getlength(bs);
1344: if (size < 0) {
1.1.1.3 ! root 1345: printf("getlength: %s\n", strerror(-size));
1.1 root 1346: return 0;
1347: }
1348:
1349: cvtstr(size, s1, sizeof(s1));
1350: printf("%s\n", s1);
1351: return 0;
1352: }
1353:
1354:
1355: static const cmdinfo_t length_cmd = {
1356: .name = "length",
1357: .altname = "l",
1358: .cfunc = length_f,
1359: .oneline = "gets the length of the current file",
1360: };
1361:
1362:
1363: static int
1364: info_f(int argc, char **argv)
1365: {
1366: BlockDriverInfo bdi;
1367: char s1[64], s2[64];
1368: int ret;
1369:
1370: if (bs->drv && bs->drv->format_name)
1371: printf("format name: %s\n", bs->drv->format_name);
1372: if (bs->drv && bs->drv->protocol_name)
1373: printf("format name: %s\n", bs->drv->protocol_name);
1374:
1375: ret = bdrv_get_info(bs, &bdi);
1376: if (ret)
1377: return 0;
1378:
1379: cvtstr(bdi.cluster_size, s1, sizeof(s1));
1380: cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
1381:
1382: printf("cluster size: %s\n", s1);
1383: printf("vm state offset: %s\n", s2);
1384:
1385: return 0;
1386: }
1387:
1388:
1389:
1390: static const cmdinfo_t info_cmd = {
1391: .name = "info",
1392: .altname = "i",
1393: .cfunc = info_f,
1394: .oneline = "prints information about the current file",
1395: };
1396:
1397: static int
1398: alloc_f(int argc, char **argv)
1399: {
1400: int64_t offset;
1.1.1.2 root 1401: int nb_sectors, remaining;
1.1 root 1402: char s1[64];
1.1.1.2 root 1403: int num, sum_alloc;
1.1 root 1404: int ret;
1405:
1406: offset = cvtnum(argv[1]);
1407: if (offset & 0x1ff) {
1.1.1.3 ! root 1408: printf("offset %" PRId64 " is not sector aligned\n",
! 1409: offset);
1.1 root 1410: return 0;
1411: }
1412:
1413: if (argc == 3)
1414: nb_sectors = cvtnum(argv[2]);
1415: else
1416: nb_sectors = 1;
1417:
1.1.1.2 root 1418: remaining = nb_sectors;
1419: sum_alloc = 0;
1420: while (remaining) {
1421: ret = bdrv_is_allocated(bs, offset >> 9, nb_sectors, &num);
1422: remaining -= num;
1423: if (ret) {
1424: sum_alloc += num;
1425: }
1426: }
1.1 root 1427:
1428: cvtstr(offset, s1, sizeof(s1));
1429:
1430: if (nb_sectors == 1)
1.1.1.2 root 1431: printf("sector allocated at offset %s\n", s1);
1.1 root 1432: else
1.1.1.2 root 1433: printf("%d/%d sectors allocated at offset %s\n",
1434: sum_alloc, nb_sectors, s1);
1.1 root 1435: return 0;
1436: }
1437:
1438: static const cmdinfo_t alloc_cmd = {
1439: .name = "alloc",
1440: .altname = "a",
1441: .argmin = 1,
1442: .argmax = 2,
1443: .cfunc = alloc_f,
1444: .args = "off [sectors]",
1445: .oneline = "checks if a sector is present in the file",
1446: };
1447:
1448: static int
1449: close_f(int argc, char **argv)
1450: {
1451: bdrv_close(bs);
1452: bs = NULL;
1453: return 0;
1454: }
1455:
1456: static const cmdinfo_t close_cmd = {
1457: .name = "close",
1458: .altname = "c",
1459: .cfunc = close_f,
1460: .oneline = "close the current open file",
1461: };
1462:
1463: static int openfile(char *name, int flags, int growable)
1464: {
1465: if (bs) {
1466: fprintf(stderr, "file open already, try 'help close'\n");
1467: return 1;
1468: }
1469:
1470: if (growable) {
1.1.1.3 ! root 1471: if (bdrv_file_open(&bs, name, flags)) {
! 1472: fprintf(stderr, "%s: can't open device %s\n", progname, name);
! 1473: return 1;
! 1474: }
! 1475: } else {
! 1476: bs = bdrv_new("hda");
! 1477: if (!bs)
! 1478: return 1;
! 1479:
! 1480: if (bdrv_open(bs, name, flags, NULL) < 0) {
! 1481: fprintf(stderr, "%s: can't open device %s\n", progname, name);
! 1482: bs = NULL;
! 1483: return 1;
! 1484: }
1.1 root 1485: }
1486:
1487: return 0;
1488: }
1489:
1490: static void
1491: open_help(void)
1492: {
1493: printf(
1494: "\n"
1495: " opens a new file in the requested mode\n"
1496: "\n"
1497: " Example:\n"
1498: " 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n"
1499: "\n"
1500: " Opens a file for subsequent use by all of the other qemu-io commands.\n"
1501: " -r, -- open file read-only\n"
1502: " -s, -- use snapshot file\n"
1503: " -n, -- disable host cache\n"
1504: " -g, -- allow file to grow (only applies to protocols)"
1505: "\n");
1506: }
1507:
1.1.1.2 root 1508: static int open_f(int argc, char **argv);
1509:
1510: static const cmdinfo_t open_cmd = {
1511: .name = "open",
1512: .altname = "o",
1513: .cfunc = open_f,
1514: .argmin = 1,
1515: .argmax = -1,
1516: .flags = CMD_NOFILE_OK,
1517: .args = "[-Crsn] [path]",
1518: .oneline = "open the file specified by path",
1519: .help = open_help,
1520: };
1.1 root 1521:
1522: static int
1523: open_f(int argc, char **argv)
1524: {
1525: int flags = 0;
1526: int readonly = 0;
1527: int growable = 0;
1528: int c;
1529:
1.1.1.3 ! root 1530: while ((c = getopt(argc, argv, "snrg")) != EOF) {
1.1 root 1531: switch (c) {
1532: case 's':
1533: flags |= BDRV_O_SNAPSHOT;
1534: break;
1535: case 'n':
1536: flags |= BDRV_O_NOCACHE;
1537: break;
1538: case 'r':
1539: readonly = 1;
1540: break;
1541: case 'g':
1542: growable = 1;
1543: break;
1544: default:
1545: return command_usage(&open_cmd);
1546: }
1547: }
1548:
1.1.1.3 ! root 1549: if (!readonly) {
! 1550: flags |= BDRV_O_RDWR;
! 1551: }
1.1 root 1552:
1553: if (optind != argc - 1)
1554: return command_usage(&open_cmd);
1555:
1556: return openfile(argv[optind], flags, growable);
1557: }
1558:
1559: static int
1560: init_args_command(
1561: int index)
1562: {
1563: /* only one device allowed so far */
1564: if (index >= 1)
1565: return 0;
1566: return ++index;
1567: }
1568:
1569: static int
1570: init_check_command(
1571: const cmdinfo_t *ct)
1572: {
1573: if (ct->flags & CMD_FLAG_GLOBAL)
1574: return 1;
1575: if (!(ct->flags & CMD_NOFILE_OK) && !bs) {
1576: fprintf(stderr, "no file open, try 'help open'\n");
1577: return 0;
1578: }
1579: return 1;
1580: }
1581:
1582: static void usage(const char *name)
1583: {
1584: printf(
1.1.1.3 ! root 1585: "Usage: %s [-h] [-V] [-rsnm] [-c cmd] ... [file]\n"
1.1 root 1586: "QEMU Disk exerciser\n"
1587: "\n"
1588: " -c, --cmd command to execute\n"
1589: " -r, --read-only export read-only\n"
1590: " -s, --snapshot use snapshot file\n"
1591: " -n, --nocache disable host cache\n"
1592: " -g, --growable allow file to grow (only applies to protocols)\n"
1593: " -m, --misalign misalign allocations for O_DIRECT\n"
1.1.1.2 root 1594: " -k, --native-aio use kernel AIO implementation (on Linux only)\n"
1.1 root 1595: " -h, --help display this help and exit\n"
1596: " -V, --version output version information and exit\n"
1597: "\n",
1598: name);
1599: }
1600:
1601:
1602: int main(int argc, char **argv)
1603: {
1604: int readonly = 0;
1605: int growable = 0;
1.1.1.3 ! root 1606: const char *sopt = "hVc:rsnmgk";
! 1607: const struct option lopt[] = {
1.1 root 1608: { "help", 0, NULL, 'h' },
1609: { "version", 0, NULL, 'V' },
1610: { "offset", 1, NULL, 'o' },
1611: { "cmd", 1, NULL, 'c' },
1612: { "read-only", 0, NULL, 'r' },
1613: { "snapshot", 0, NULL, 's' },
1614: { "nocache", 0, NULL, 'n' },
1615: { "misalign", 0, NULL, 'm' },
1616: { "growable", 0, NULL, 'g' },
1.1.1.2 root 1617: { "native-aio", 0, NULL, 'k' },
1.1 root 1618: { NULL, 0, NULL, 0 }
1619: };
1620: int c;
1621: int opt_index = 0;
1622: int flags = 0;
1623:
1624: progname = basename(argv[0]);
1625:
1626: while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
1627: switch (c) {
1628: case 's':
1629: flags |= BDRV_O_SNAPSHOT;
1630: break;
1631: case 'n':
1632: flags |= BDRV_O_NOCACHE;
1633: break;
1634: case 'c':
1635: add_user_command(optarg);
1636: break;
1637: case 'r':
1638: readonly = 1;
1639: break;
1640: case 'm':
1641: misalign = 1;
1642: break;
1643: case 'g':
1644: growable = 1;
1645: break;
1.1.1.2 root 1646: case 'k':
1647: flags |= BDRV_O_NATIVE_AIO;
1648: break;
1.1 root 1649: case 'V':
1650: printf("%s version %s\n", progname, VERSION);
1651: exit(0);
1652: case 'h':
1653: usage(progname);
1654: exit(0);
1655: default:
1656: usage(progname);
1657: exit(1);
1658: }
1659: }
1660:
1661: if ((argc - optind) > 1) {
1662: usage(progname);
1663: exit(1);
1664: }
1665:
1666: bdrv_init();
1667:
1668: /* initialize commands */
1669: quit_init();
1670: help_init();
1671: add_command(&open_cmd);
1672: add_command(&close_cmd);
1673: add_command(&read_cmd);
1674: add_command(&readv_cmd);
1675: add_command(&write_cmd);
1676: add_command(&writev_cmd);
1.1.1.3 ! root 1677: add_command(&multiwrite_cmd);
1.1 root 1678: add_command(&aio_read_cmd);
1679: add_command(&aio_write_cmd);
1680: add_command(&aio_flush_cmd);
1681: add_command(&flush_cmd);
1682: add_command(&truncate_cmd);
1683: add_command(&length_cmd);
1684: add_command(&info_cmd);
1685: add_command(&alloc_cmd);
1686:
1687: add_args_command(init_args_command);
1688: add_check_command(init_check_command);
1689:
1690: /* open the device */
1.1.1.3 ! root 1691: if (!readonly) {
! 1692: flags |= BDRV_O_RDWR;
! 1693: }
1.1 root 1694:
1695: if ((argc - optind) == 1)
1696: openfile(argv[optind], flags, growable);
1697: command_loop();
1698:
1699: /*
1700: * Make sure all outstanding requests get flushed the program exits.
1701: */
1702: qemu_aio_flush();
1703:
1704: if (bs)
1705: bdrv_close(bs);
1706: return 0;
1707: }
unix.superglobalmegacorp.com