Annotation of qemu/qemu-io.c, revision 1.1.1.5

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

unix.superglobalmegacorp.com