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 11 #include "qemu-io.h" 12 #include "sysemu/block-backend.h" 13 #include "block/block.h" 14 #include "block/block_int.h" /* for info_f() */ 15 #include "block/qapi.h" 16 #include "qemu/main-loop.h" 17 #include "qemu/timer.h" 18 #include "sysemu/block-backend.h" 19 20 #define CMD_NOFILE_OK 0x01 21 22 bool qemuio_misalign; 23 24 static cmdinfo_t *cmdtab; 25 static int ncmds; 26 27 static int compare_cmdname(const void *a, const void *b) 28 { 29 return strcmp(((const cmdinfo_t *)a)->name, 30 ((const cmdinfo_t *)b)->name); 31 } 32 33 void qemuio_add_command(const cmdinfo_t *ci) 34 { 35 cmdtab = g_renew(cmdinfo_t, cmdtab, ++ncmds); 36 cmdtab[ncmds - 1] = *ci; 37 qsort(cmdtab, ncmds, sizeof(*cmdtab), compare_cmdname); 38 } 39 40 int qemuio_command_usage(const cmdinfo_t *ci) 41 { 42 printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline); 43 return 0; 44 } 45 46 static int init_check_command(BlockBackend *blk, const cmdinfo_t *ct) 47 { 48 if (ct->flags & CMD_FLAG_GLOBAL) { 49 return 1; 50 } 51 if (!(ct->flags & CMD_NOFILE_OK) && !blk) { 52 fprintf(stderr, "no file open, try 'help open'\n"); 53 return 0; 54 } 55 return 1; 56 } 57 58 static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc, 59 char **argv) 60 { 61 char *cmd = argv[0]; 62 63 if (!init_check_command(blk, ct)) { 64 return 0; 65 } 66 67 if (argc - 1 < ct->argmin || (ct->argmax != -1 && argc - 1 > ct->argmax)) { 68 if (ct->argmax == -1) { 69 fprintf(stderr, 70 "bad argument count %d to %s, expected at least %d arguments\n", 71 argc-1, cmd, ct->argmin); 72 } else if (ct->argmin == ct->argmax) { 73 fprintf(stderr, 74 "bad argument count %d to %s, expected %d arguments\n", 75 argc-1, cmd, ct->argmin); 76 } else { 77 fprintf(stderr, 78 "bad argument count %d to %s, expected between %d and %d arguments\n", 79 argc-1, cmd, ct->argmin, ct->argmax); 80 } 81 return 0; 82 } 83 optind = 0; 84 return ct->cfunc(blk, argc, argv); 85 } 86 87 static const cmdinfo_t *find_command(const char *cmd) 88 { 89 cmdinfo_t *ct; 90 91 for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) { 92 if (strcmp(ct->name, cmd) == 0 || 93 (ct->altname && strcmp(ct->altname, cmd) == 0)) 94 { 95 return (const cmdinfo_t *)ct; 96 } 97 } 98 return NULL; 99 } 100 101 /* Invoke fn() for commands with a matching prefix */ 102 void qemuio_complete_command(const char *input, 103 void (*fn)(const char *cmd, void *opaque), 104 void *opaque) 105 { 106 cmdinfo_t *ct; 107 size_t input_len = strlen(input); 108 109 for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) { 110 if (strncmp(input, ct->name, input_len) == 0) { 111 fn(ct->name, opaque); 112 } 113 } 114 } 115 116 static char **breakline(char *input, int *count) 117 { 118 int c = 0; 119 char *p; 120 char **rval = g_new0(char *, 1); 121 122 while (rval && (p = qemu_strsep(&input, " ")) != NULL) { 123 if (!*p) { 124 continue; 125 } 126 c++; 127 rval = g_renew(char *, rval, (c + 1)); 128 rval[c - 1] = p; 129 rval[c] = NULL; 130 } 131 *count = c; 132 return rval; 133 } 134 135 static int64_t cvtnum(const char *s) 136 { 137 char *end; 138 return strtosz_suffix(s, &end, STRTOSZ_DEFSUFFIX_B); 139 } 140 141 #define EXABYTES(x) ((long long)(x) << 60) 142 #define PETABYTES(x) ((long long)(x) << 50) 143 #define TERABYTES(x) ((long long)(x) << 40) 144 #define GIGABYTES(x) ((long long)(x) << 30) 145 #define MEGABYTES(x) ((long long)(x) << 20) 146 #define KILOBYTES(x) ((long long)(x) << 10) 147 148 #define TO_EXABYTES(x) ((x) / EXABYTES(1)) 149 #define TO_PETABYTES(x) ((x) / PETABYTES(1)) 150 #define TO_TERABYTES(x) ((x) / TERABYTES(1)) 151 #define TO_GIGABYTES(x) ((x) / GIGABYTES(1)) 152 #define TO_MEGABYTES(x) ((x) / MEGABYTES(1)) 153 #define TO_KILOBYTES(x) ((x) / KILOBYTES(1)) 154 155 static void cvtstr(double value, char *str, size_t size) 156 { 157 char *trim; 158 const char *suffix; 159 160 if (value >= EXABYTES(1)) { 161 suffix = " EiB"; 162 snprintf(str, size - 4, "%.3f", TO_EXABYTES(value)); 163 } else if (value >= PETABYTES(1)) { 164 suffix = " PiB"; 165 snprintf(str, size - 4, "%.3f", TO_PETABYTES(value)); 166 } else if (value >= TERABYTES(1)) { 167 suffix = " TiB"; 168 snprintf(str, size - 4, "%.3f", TO_TERABYTES(value)); 169 } else if (value >= GIGABYTES(1)) { 170 suffix = " GiB"; 171 snprintf(str, size - 4, "%.3f", TO_GIGABYTES(value)); 172 } else if (value >= MEGABYTES(1)) { 173 suffix = " MiB"; 174 snprintf(str, size - 4, "%.3f", TO_MEGABYTES(value)); 175 } else if (value >= KILOBYTES(1)) { 176 suffix = " KiB"; 177 snprintf(str, size - 4, "%.3f", TO_KILOBYTES(value)); 178 } else { 179 suffix = " bytes"; 180 snprintf(str, size - 6, "%f", value); 181 } 182 183 trim = strstr(str, ".000"); 184 if (trim) { 185 strcpy(trim, suffix); 186 } else { 187 strcat(str, suffix); 188 } 189 } 190 191 192 193 static struct timeval tsub(struct timeval t1, struct timeval t2) 194 { 195 t1.tv_usec -= t2.tv_usec; 196 if (t1.tv_usec < 0) { 197 t1.tv_usec += 1000000; 198 t1.tv_sec--; 199 } 200 t1.tv_sec -= t2.tv_sec; 201 return t1; 202 } 203 204 static double tdiv(double value, struct timeval tv) 205 { 206 return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0)); 207 } 208 209 #define HOURS(sec) ((sec) / (60 * 60)) 210 #define MINUTES(sec) (((sec) % (60 * 60)) / 60) 211 #define SECONDS(sec) ((sec) % 60) 212 213 enum { 214 DEFAULT_TIME = 0x0, 215 TERSE_FIXED_TIME = 0x1, 216 VERBOSE_FIXED_TIME = 0x2, 217 }; 218 219 static void timestr(struct timeval *tv, char *ts, size_t size, int format) 220 { 221 double usec = (double)tv->tv_usec / 1000000.0; 222 223 if (format & TERSE_FIXED_TIME) { 224 if (!HOURS(tv->tv_sec)) { 225 snprintf(ts, size, "%u:%02u.%02u", 226 (unsigned int) MINUTES(tv->tv_sec), 227 (unsigned int) SECONDS(tv->tv_sec), 228 (unsigned int) (usec * 100)); 229 return; 230 } 231 format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */ 232 } 233 234 if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) { 235 snprintf(ts, size, "%u:%02u:%02u.%02u", 236 (unsigned int) HOURS(tv->tv_sec), 237 (unsigned int) MINUTES(tv->tv_sec), 238 (unsigned int) SECONDS(tv->tv_sec), 239 (unsigned int) (usec * 100)); 240 } else { 241 snprintf(ts, size, "0.%04u sec", (unsigned int) (usec * 10000)); 242 } 243 } 244 245 /* 246 * Parse the pattern argument to various sub-commands. 247 * 248 * Because the pattern is used as an argument to memset it must evaluate 249 * to an unsigned integer that fits into a single byte. 250 */ 251 static int parse_pattern(const char *arg) 252 { 253 char *endptr = NULL; 254 long pattern; 255 256 pattern = strtol(arg, &endptr, 0); 257 if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') { 258 printf("%s is not a valid pattern byte\n", arg); 259 return -1; 260 } 261 262 return pattern; 263 } 264 265 /* 266 * Memory allocation helpers. 267 * 268 * Make sure memory is aligned by default, or purposefully misaligned if 269 * that is specified on the command line. 270 */ 271 272 #define MISALIGN_OFFSET 16 273 static void *qemu_io_alloc(BlockBackend *blk, size_t len, int pattern) 274 { 275 void *buf; 276 277 if (qemuio_misalign) { 278 len += MISALIGN_OFFSET; 279 } 280 buf = blk_blockalign(blk, len); 281 memset(buf, pattern, len); 282 if (qemuio_misalign) { 283 buf += MISALIGN_OFFSET; 284 } 285 return buf; 286 } 287 288 static void qemu_io_free(void *p) 289 { 290 if (qemuio_misalign) { 291 p -= MISALIGN_OFFSET; 292 } 293 qemu_vfree(p); 294 } 295 296 static void dump_buffer(const void *buffer, int64_t offset, int len) 297 { 298 int i, j; 299 const uint8_t *p; 300 301 for (i = 0, p = buffer; i < len; i += 16) { 302 const uint8_t *s = p; 303 304 printf("%08" PRIx64 ": ", offset + i); 305 for (j = 0; j < 16 && i + j < len; j++, p++) { 306 printf("%02x ", *p); 307 } 308 printf(" "); 309 for (j = 0; j < 16 && i + j < len; j++, s++) { 310 if (isalnum(*s)) { 311 printf("%c", *s); 312 } else { 313 printf("."); 314 } 315 } 316 printf("\n"); 317 } 318 } 319 320 static void print_report(const char *op, struct timeval *t, int64_t offset, 321 int count, int total, int cnt, int Cflag) 322 { 323 char s1[64], s2[64], ts[64]; 324 325 timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0); 326 if (!Cflag) { 327 cvtstr((double)total, s1, sizeof(s1)); 328 cvtstr(tdiv((double)total, *t), s2, sizeof(s2)); 329 printf("%s %d/%d bytes at offset %" PRId64 "\n", 330 op, total, count, offset); 331 printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n", 332 s1, cnt, ts, s2, tdiv((double)cnt, *t)); 333 } else {/* bytes,ops,time,bytes/sec,ops/sec */ 334 printf("%d,%d,%s,%.3f,%.3f\n", 335 total, cnt, ts, 336 tdiv((double)total, *t), 337 tdiv((double)cnt, *t)); 338 } 339 } 340 341 /* 342 * Parse multiple length statements for vectored I/O, and construct an I/O 343 * vector matching it. 344 */ 345 static void * 346 create_iovec(BlockBackend *blk, QEMUIOVector *qiov, char **argv, int nr_iov, 347 int pattern) 348 { 349 size_t *sizes = g_new0(size_t, nr_iov); 350 size_t count = 0; 351 void *buf = NULL; 352 void *p; 353 int i; 354 355 for (i = 0; i < nr_iov; i++) { 356 char *arg = argv[i]; 357 int64_t len; 358 359 len = cvtnum(arg); 360 if (len < 0) { 361 printf("non-numeric length argument -- %s\n", arg); 362 goto fail; 363 } 364 365 /* should be SIZE_T_MAX, but that doesn't exist */ 366 if (len > INT_MAX) { 367 printf("too large length argument -- %s\n", arg); 368 goto fail; 369 } 370 371 if (len & 0x1ff) { 372 printf("length argument %" PRId64 373 " is not sector aligned\n", len); 374 goto fail; 375 } 376 377 sizes[i] = len; 378 count += len; 379 } 380 381 qemu_iovec_init(qiov, nr_iov); 382 383 buf = p = qemu_io_alloc(blk, count, pattern); 384 385 for (i = 0; i < nr_iov; i++) { 386 qemu_iovec_add(qiov, p, sizes[i]); 387 p += sizes[i]; 388 } 389 390 fail: 391 g_free(sizes); 392 return buf; 393 } 394 395 static int do_read(BlockBackend *blk, char *buf, int64_t offset, int count, 396 int *total) 397 { 398 int ret; 399 400 ret = blk_read(blk, offset >> 9, (uint8_t *)buf, count >> 9); 401 if (ret < 0) { 402 return ret; 403 } 404 *total = count; 405 return 1; 406 } 407 408 static int do_write(BlockBackend *blk, char *buf, int64_t offset, int count, 409 int *total) 410 { 411 int ret; 412 413 ret = blk_write(blk, offset >> 9, (uint8_t *)buf, count >> 9); 414 if (ret < 0) { 415 return ret; 416 } 417 *total = count; 418 return 1; 419 } 420 421 static int do_pread(BlockBackend *blk, char *buf, int64_t offset, int count, 422 int *total) 423 { 424 *total = blk_pread(blk, offset, (uint8_t *)buf, count); 425 if (*total < 0) { 426 return *total; 427 } 428 return 1; 429 } 430 431 static int do_pwrite(BlockBackend *blk, char *buf, int64_t offset, int count, 432 int *total) 433 { 434 *total = blk_pwrite(blk, offset, (uint8_t *)buf, count); 435 if (*total < 0) { 436 return *total; 437 } 438 return 1; 439 } 440 441 typedef struct { 442 BlockBackend *blk; 443 int64_t offset; 444 int count; 445 int *total; 446 int ret; 447 bool done; 448 } CoWriteZeroes; 449 450 static void coroutine_fn co_write_zeroes_entry(void *opaque) 451 { 452 CoWriteZeroes *data = opaque; 453 454 data->ret = blk_co_write_zeroes(data->blk, data->offset / BDRV_SECTOR_SIZE, 455 data->count / BDRV_SECTOR_SIZE, 0); 456 data->done = true; 457 if (data->ret < 0) { 458 *data->total = data->ret; 459 return; 460 } 461 462 *data->total = data->count; 463 } 464 465 static int do_co_write_zeroes(BlockBackend *blk, int64_t offset, int count, 466 int *total) 467 { 468 Coroutine *co; 469 CoWriteZeroes data = { 470 .blk = blk, 471 .offset = offset, 472 .count = count, 473 .total = total, 474 .done = false, 475 }; 476 477 co = qemu_coroutine_create(co_write_zeroes_entry); 478 qemu_coroutine_enter(co, &data); 479 while (!data.done) { 480 aio_poll(blk_get_aio_context(blk), true); 481 } 482 if (data.ret < 0) { 483 return data.ret; 484 } else { 485 return 1; 486 } 487 } 488 489 static int do_write_compressed(BlockBackend *blk, char *buf, int64_t offset, 490 int count, int *total) 491 { 492 int ret; 493 494 ret = blk_write_compressed(blk, offset >> 9, (uint8_t *)buf, count >> 9); 495 if (ret < 0) { 496 return ret; 497 } 498 *total = count; 499 return 1; 500 } 501 502 static int do_load_vmstate(BlockBackend *blk, char *buf, int64_t offset, 503 int count, int *total) 504 { 505 *total = blk_load_vmstate(blk, (uint8_t *)buf, offset, count); 506 if (*total < 0) { 507 return *total; 508 } 509 return 1; 510 } 511 512 static int do_save_vmstate(BlockBackend *blk, char *buf, int64_t offset, 513 int count, int *total) 514 { 515 *total = blk_save_vmstate(blk, (uint8_t *)buf, offset, count); 516 if (*total < 0) { 517 return *total; 518 } 519 return 1; 520 } 521 522 #define NOT_DONE 0x7fffffff 523 static void aio_rw_done(void *opaque, int ret) 524 { 525 *(int *)opaque = ret; 526 } 527 528 static int do_aio_readv(BlockBackend *blk, QEMUIOVector *qiov, 529 int64_t offset, int *total) 530 { 531 int async_ret = NOT_DONE; 532 533 blk_aio_readv(blk, offset >> 9, qiov, qiov->size >> 9, 534 aio_rw_done, &async_ret); 535 while (async_ret == NOT_DONE) { 536 main_loop_wait(false); 537 } 538 539 *total = qiov->size; 540 return async_ret < 0 ? async_ret : 1; 541 } 542 543 static int do_aio_writev(BlockBackend *blk, QEMUIOVector *qiov, 544 int64_t offset, int *total) 545 { 546 int async_ret = NOT_DONE; 547 548 blk_aio_writev(blk, offset >> 9, qiov, qiov->size >> 9, 549 aio_rw_done, &async_ret); 550 while (async_ret == NOT_DONE) { 551 main_loop_wait(false); 552 } 553 554 *total = qiov->size; 555 return async_ret < 0 ? async_ret : 1; 556 } 557 558 struct multiwrite_async_ret { 559 int num_done; 560 int error; 561 }; 562 563 static void multiwrite_cb(void *opaque, int ret) 564 { 565 struct multiwrite_async_ret *async_ret = opaque; 566 567 async_ret->num_done++; 568 if (ret < 0) { 569 async_ret->error = ret; 570 } 571 } 572 573 static int do_aio_multiwrite(BlockBackend *blk, BlockRequest* reqs, 574 int num_reqs, int *total) 575 { 576 int i, ret; 577 struct multiwrite_async_ret async_ret = { 578 .num_done = 0, 579 .error = 0, 580 }; 581 582 *total = 0; 583 for (i = 0; i < num_reqs; i++) { 584 reqs[i].cb = multiwrite_cb; 585 reqs[i].opaque = &async_ret; 586 *total += reqs[i].qiov->size; 587 } 588 589 ret = blk_aio_multiwrite(blk, reqs, num_reqs); 590 if (ret < 0) { 591 return ret; 592 } 593 594 while (async_ret.num_done < num_reqs) { 595 main_loop_wait(false); 596 } 597 598 return async_ret.error < 0 ? async_ret.error : 1; 599 } 600 601 static void read_help(void) 602 { 603 printf( 604 "\n" 605 " reads a range of bytes from the given offset\n" 606 "\n" 607 " Example:\n" 608 " 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n" 609 "\n" 610 " Reads a segment of the currently open file, optionally dumping it to the\n" 611 " standard output stream (with -v option) for subsequent inspection.\n" 612 " -b, -- read from the VM state rather than the virtual disk\n" 613 " -C, -- report statistics in a machine parsable format\n" 614 " -l, -- length for pattern verification (only with -P)\n" 615 " -p, -- use blk_pread to read the file\n" 616 " -P, -- use a pattern to verify read data\n" 617 " -q, -- quiet mode, do not show I/O statistics\n" 618 " -s, -- start offset for pattern verification (only with -P)\n" 619 " -v, -- dump buffer to standard output\n" 620 "\n"); 621 } 622 623 static int read_f(BlockBackend *blk, int argc, char **argv); 624 625 static const cmdinfo_t read_cmd = { 626 .name = "read", 627 .altname = "r", 628 .cfunc = read_f, 629 .argmin = 2, 630 .argmax = -1, 631 .args = "[-abCpqv] [-P pattern [-s off] [-l len]] off len", 632 .oneline = "reads a number of bytes at a specified offset", 633 .help = read_help, 634 }; 635 636 static int read_f(BlockBackend *blk, int argc, char **argv) 637 { 638 struct timeval t1, t2; 639 int Cflag = 0, pflag = 0, qflag = 0, vflag = 0; 640 int Pflag = 0, sflag = 0, lflag = 0, bflag = 0; 641 int c, cnt; 642 char *buf; 643 int64_t offset; 644 int count; 645 /* Some compilers get confused and warn if this is not initialized. */ 646 int total = 0; 647 int pattern = 0, pattern_offset = 0, pattern_count = 0; 648 649 while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != -1) { 650 switch (c) { 651 case 'b': 652 bflag = 1; 653 break; 654 case 'C': 655 Cflag = 1; 656 break; 657 case 'l': 658 lflag = 1; 659 pattern_count = cvtnum(optarg); 660 if (pattern_count < 0) { 661 printf("non-numeric length argument -- %s\n", optarg); 662 return 0; 663 } 664 break; 665 case 'p': 666 pflag = 1; 667 break; 668 case 'P': 669 Pflag = 1; 670 pattern = parse_pattern(optarg); 671 if (pattern < 0) { 672 return 0; 673 } 674 break; 675 case 'q': 676 qflag = 1; 677 break; 678 case 's': 679 sflag = 1; 680 pattern_offset = cvtnum(optarg); 681 if (pattern_offset < 0) { 682 printf("non-numeric length argument -- %s\n", optarg); 683 return 0; 684 } 685 break; 686 case 'v': 687 vflag = 1; 688 break; 689 default: 690 return qemuio_command_usage(&read_cmd); 691 } 692 } 693 694 if (optind != argc - 2) { 695 return qemuio_command_usage(&read_cmd); 696 } 697 698 if (bflag && pflag) { 699 printf("-b and -p cannot be specified at the same time\n"); 700 return 0; 701 } 702 703 offset = cvtnum(argv[optind]); 704 if (offset < 0) { 705 printf("non-numeric length argument -- %s\n", argv[optind]); 706 return 0; 707 } 708 709 optind++; 710 count = cvtnum(argv[optind]); 711 if (count < 0) { 712 printf("non-numeric length argument -- %s\n", argv[optind]); 713 return 0; 714 } 715 716 if (!Pflag && (lflag || sflag)) { 717 return qemuio_command_usage(&read_cmd); 718 } 719 720 if (!lflag) { 721 pattern_count = count - pattern_offset; 722 } 723 724 if ((pattern_count < 0) || (pattern_count + pattern_offset > count)) { 725 printf("pattern verification range exceeds end of read data\n"); 726 return 0; 727 } 728 729 if (!pflag) { 730 if (offset & 0x1ff) { 731 printf("offset %" PRId64 " is not sector aligned\n", 732 offset); 733 return 0; 734 } 735 if (count & 0x1ff) { 736 printf("count %d is not sector aligned\n", 737 count); 738 return 0; 739 } 740 } 741 742 buf = qemu_io_alloc(blk, count, 0xab); 743 744 gettimeofday(&t1, NULL); 745 if (pflag) { 746 cnt = do_pread(blk, buf, offset, count, &total); 747 } else if (bflag) { 748 cnt = do_load_vmstate(blk, buf, offset, count, &total); 749 } else { 750 cnt = do_read(blk, buf, offset, count, &total); 751 } 752 gettimeofday(&t2, NULL); 753 754 if (cnt < 0) { 755 printf("read failed: %s\n", strerror(-cnt)); 756 goto out; 757 } 758 759 if (Pflag) { 760 void *cmp_buf = g_malloc(pattern_count); 761 memset(cmp_buf, pattern, pattern_count); 762 if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) { 763 printf("Pattern verification failed at offset %" 764 PRId64 ", %d bytes\n", 765 offset + pattern_offset, pattern_count); 766 } 767 g_free(cmp_buf); 768 } 769 770 if (qflag) { 771 goto out; 772 } 773 774 if (vflag) { 775 dump_buffer(buf, offset, count); 776 } 777 778 /* Finally, report back -- -C gives a parsable format */ 779 t2 = tsub(t2, t1); 780 print_report("read", &t2, offset, count, total, cnt, Cflag); 781 782 out: 783 qemu_io_free(buf); 784 785 return 0; 786 } 787 788 static void readv_help(void) 789 { 790 printf( 791 "\n" 792 " reads a range of bytes from the given offset into multiple buffers\n" 793 "\n" 794 " Example:\n" 795 " 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n" 796 "\n" 797 " Reads a segment of the currently open file, optionally dumping it to the\n" 798 " standard output stream (with -v option) for subsequent inspection.\n" 799 " Uses multiple iovec buffers if more than one byte range is specified.\n" 800 " -C, -- report statistics in a machine parsable format\n" 801 " -P, -- use a pattern to verify read data\n" 802 " -v, -- dump buffer to standard output\n" 803 " -q, -- quiet mode, do not show I/O statistics\n" 804 "\n"); 805 } 806 807 static int readv_f(BlockBackend *blk, int argc, char **argv); 808 809 static const cmdinfo_t readv_cmd = { 810 .name = "readv", 811 .cfunc = readv_f, 812 .argmin = 2, 813 .argmax = -1, 814 .args = "[-Cqv] [-P pattern ] off len [len..]", 815 .oneline = "reads a number of bytes at a specified offset", 816 .help = readv_help, 817 }; 818 819 static int readv_f(BlockBackend *blk, int argc, char **argv) 820 { 821 struct timeval t1, t2; 822 int Cflag = 0, qflag = 0, vflag = 0; 823 int c, cnt; 824 char *buf; 825 int64_t offset; 826 /* Some compilers get confused and warn if this is not initialized. */ 827 int total = 0; 828 int nr_iov; 829 QEMUIOVector qiov; 830 int pattern = 0; 831 int Pflag = 0; 832 833 while ((c = getopt(argc, argv, "CP:qv")) != -1) { 834 switch (c) { 835 case 'C': 836 Cflag = 1; 837 break; 838 case 'P': 839 Pflag = 1; 840 pattern = parse_pattern(optarg); 841 if (pattern < 0) { 842 return 0; 843 } 844 break; 845 case 'q': 846 qflag = 1; 847 break; 848 case 'v': 849 vflag = 1; 850 break; 851 default: 852 return qemuio_command_usage(&readv_cmd); 853 } 854 } 855 856 if (optind > argc - 2) { 857 return qemuio_command_usage(&readv_cmd); 858 } 859 860 861 offset = cvtnum(argv[optind]); 862 if (offset < 0) { 863 printf("non-numeric length argument -- %s\n", argv[optind]); 864 return 0; 865 } 866 optind++; 867 868 if (offset & 0x1ff) { 869 printf("offset %" PRId64 " is not sector aligned\n", 870 offset); 871 return 0; 872 } 873 874 nr_iov = argc - optind; 875 buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, 0xab); 876 if (buf == NULL) { 877 return 0; 878 } 879 880 gettimeofday(&t1, NULL); 881 cnt = do_aio_readv(blk, &qiov, offset, &total); 882 gettimeofday(&t2, NULL); 883 884 if (cnt < 0) { 885 printf("readv failed: %s\n", strerror(-cnt)); 886 goto out; 887 } 888 889 if (Pflag) { 890 void *cmp_buf = g_malloc(qiov.size); 891 memset(cmp_buf, pattern, qiov.size); 892 if (memcmp(buf, cmp_buf, qiov.size)) { 893 printf("Pattern verification failed at offset %" 894 PRId64 ", %zd bytes\n", offset, qiov.size); 895 } 896 g_free(cmp_buf); 897 } 898 899 if (qflag) { 900 goto out; 901 } 902 903 if (vflag) { 904 dump_buffer(buf, offset, qiov.size); 905 } 906 907 /* Finally, report back -- -C gives a parsable format */ 908 t2 = tsub(t2, t1); 909 print_report("read", &t2, offset, qiov.size, total, cnt, Cflag); 910 911 out: 912 qemu_iovec_destroy(&qiov); 913 qemu_io_free(buf); 914 return 0; 915 } 916 917 static void write_help(void) 918 { 919 printf( 920 "\n" 921 " writes a range of bytes from the given offset\n" 922 "\n" 923 " Example:\n" 924 " 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n" 925 "\n" 926 " Writes into a segment of the currently open file, using a buffer\n" 927 " filled with a set pattern (0xcdcdcdcd).\n" 928 " -b, -- write to the VM state rather than the virtual disk\n" 929 " -c, -- write compressed data with blk_write_compressed\n" 930 " -p, -- use blk_pwrite to write the file\n" 931 " -P, -- use different pattern to fill file\n" 932 " -C, -- report statistics in a machine parsable format\n" 933 " -q, -- quiet mode, do not show I/O statistics\n" 934 " -z, -- write zeroes using blk_co_write_zeroes\n" 935 "\n"); 936 } 937 938 static int write_f(BlockBackend *blk, int argc, char **argv); 939 940 static const cmdinfo_t write_cmd = { 941 .name = "write", 942 .altname = "w", 943 .cfunc = write_f, 944 .argmin = 2, 945 .argmax = -1, 946 .args = "[-bcCpqz] [-P pattern ] off len", 947 .oneline = "writes a number of bytes at a specified offset", 948 .help = write_help, 949 }; 950 951 static int write_f(BlockBackend *blk, int argc, char **argv) 952 { 953 struct timeval t1, t2; 954 int Cflag = 0, pflag = 0, qflag = 0, bflag = 0, Pflag = 0, zflag = 0; 955 int cflag = 0; 956 int c, cnt; 957 char *buf = NULL; 958 int64_t offset; 959 int count; 960 /* Some compilers get confused and warn if this is not initialized. */ 961 int total = 0; 962 int pattern = 0xcd; 963 964 while ((c = getopt(argc, argv, "bcCpP:qz")) != -1) { 965 switch (c) { 966 case 'b': 967 bflag = 1; 968 break; 969 case 'c': 970 cflag = 1; 971 break; 972 case 'C': 973 Cflag = 1; 974 break; 975 case 'p': 976 pflag = 1; 977 break; 978 case 'P': 979 Pflag = 1; 980 pattern = parse_pattern(optarg); 981 if (pattern < 0) { 982 return 0; 983 } 984 break; 985 case 'q': 986 qflag = 1; 987 break; 988 case 'z': 989 zflag = 1; 990 break; 991 default: 992 return qemuio_command_usage(&write_cmd); 993 } 994 } 995 996 if (optind != argc - 2) { 997 return qemuio_command_usage(&write_cmd); 998 } 999 1000 if (bflag + pflag + zflag > 1) { 1001 printf("-b, -p, or -z cannot be specified at the same time\n"); 1002 return 0; 1003 } 1004 1005 if (zflag && Pflag) { 1006 printf("-z and -P cannot be specified at the same time\n"); 1007 return 0; 1008 } 1009 1010 offset = cvtnum(argv[optind]); 1011 if (offset < 0) { 1012 printf("non-numeric length argument -- %s\n", argv[optind]); 1013 return 0; 1014 } 1015 1016 optind++; 1017 count = cvtnum(argv[optind]); 1018 if (count < 0) { 1019 printf("non-numeric length argument -- %s\n", argv[optind]); 1020 return 0; 1021 } 1022 1023 if (!pflag) { 1024 if (offset & 0x1ff) { 1025 printf("offset %" PRId64 " is not sector aligned\n", 1026 offset); 1027 return 0; 1028 } 1029 1030 if (count & 0x1ff) { 1031 printf("count %d is not sector aligned\n", 1032 count); 1033 return 0; 1034 } 1035 } 1036 1037 if (!zflag) { 1038 buf = qemu_io_alloc(blk, count, pattern); 1039 } 1040 1041 gettimeofday(&t1, NULL); 1042 if (pflag) { 1043 cnt = do_pwrite(blk, buf, offset, count, &total); 1044 } else if (bflag) { 1045 cnt = do_save_vmstate(blk, buf, offset, count, &total); 1046 } else if (zflag) { 1047 cnt = do_co_write_zeroes(blk, offset, count, &total); 1048 } else if (cflag) { 1049 cnt = do_write_compressed(blk, buf, offset, count, &total); 1050 } else { 1051 cnt = do_write(blk, buf, offset, count, &total); 1052 } 1053 gettimeofday(&t2, NULL); 1054 1055 if (cnt < 0) { 1056 printf("write failed: %s\n", strerror(-cnt)); 1057 goto out; 1058 } 1059 1060 if (qflag) { 1061 goto out; 1062 } 1063 1064 /* Finally, report back -- -C gives a parsable format */ 1065 t2 = tsub(t2, t1); 1066 print_report("wrote", &t2, offset, count, total, cnt, Cflag); 1067 1068 out: 1069 if (!zflag) { 1070 qemu_io_free(buf); 1071 } 1072 1073 return 0; 1074 } 1075 1076 static void 1077 writev_help(void) 1078 { 1079 printf( 1080 "\n" 1081 " writes a range of bytes from the given offset source from multiple buffers\n" 1082 "\n" 1083 " Example:\n" 1084 " 'writev 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n" 1085 "\n" 1086 " Writes into a segment of the currently open file, using a buffer\n" 1087 " filled with a set pattern (0xcdcdcdcd).\n" 1088 " -P, -- use different pattern to fill file\n" 1089 " -C, -- report statistics in a machine parsable format\n" 1090 " -q, -- quiet mode, do not show I/O statistics\n" 1091 "\n"); 1092 } 1093 1094 static int writev_f(BlockBackend *blk, int argc, char **argv); 1095 1096 static const cmdinfo_t writev_cmd = { 1097 .name = "writev", 1098 .cfunc = writev_f, 1099 .argmin = 2, 1100 .argmax = -1, 1101 .args = "[-Cq] [-P pattern ] off len [len..]", 1102 .oneline = "writes a number of bytes at a specified offset", 1103 .help = writev_help, 1104 }; 1105 1106 static int writev_f(BlockBackend *blk, int argc, char **argv) 1107 { 1108 struct timeval t1, t2; 1109 int Cflag = 0, qflag = 0; 1110 int c, cnt; 1111 char *buf; 1112 int64_t offset; 1113 /* Some compilers get confused and warn if this is not initialized. */ 1114 int total = 0; 1115 int nr_iov; 1116 int pattern = 0xcd; 1117 QEMUIOVector qiov; 1118 1119 while ((c = getopt(argc, argv, "CqP:")) != -1) { 1120 switch (c) { 1121 case 'C': 1122 Cflag = 1; 1123 break; 1124 case 'q': 1125 qflag = 1; 1126 break; 1127 case 'P': 1128 pattern = parse_pattern(optarg); 1129 if (pattern < 0) { 1130 return 0; 1131 } 1132 break; 1133 default: 1134 return qemuio_command_usage(&writev_cmd); 1135 } 1136 } 1137 1138 if (optind > argc - 2) { 1139 return qemuio_command_usage(&writev_cmd); 1140 } 1141 1142 offset = cvtnum(argv[optind]); 1143 if (offset < 0) { 1144 printf("non-numeric length argument -- %s\n", argv[optind]); 1145 return 0; 1146 } 1147 optind++; 1148 1149 if (offset & 0x1ff) { 1150 printf("offset %" PRId64 " is not sector aligned\n", 1151 offset); 1152 return 0; 1153 } 1154 1155 nr_iov = argc - optind; 1156 buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern); 1157 if (buf == NULL) { 1158 return 0; 1159 } 1160 1161 gettimeofday(&t1, NULL); 1162 cnt = do_aio_writev(blk, &qiov, offset, &total); 1163 gettimeofday(&t2, NULL); 1164 1165 if (cnt < 0) { 1166 printf("writev failed: %s\n", strerror(-cnt)); 1167 goto out; 1168 } 1169 1170 if (qflag) { 1171 goto out; 1172 } 1173 1174 /* Finally, report back -- -C gives a parsable format */ 1175 t2 = tsub(t2, t1); 1176 print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag); 1177 out: 1178 qemu_iovec_destroy(&qiov); 1179 qemu_io_free(buf); 1180 return 0; 1181 } 1182 1183 static void multiwrite_help(void) 1184 { 1185 printf( 1186 "\n" 1187 " writes a range of bytes from the given offset source from multiple buffers,\n" 1188 " in a batch of requests that may be merged by qemu\n" 1189 "\n" 1190 " Example:\n" 1191 " 'multiwrite 512 1k 1k ; 4k 1k'\n" 1192 " writes 2 kB at 512 bytes and 1 kB at 4 kB into the open file\n" 1193 "\n" 1194 " Writes into a segment of the currently open file, using a buffer\n" 1195 " filled with a set pattern (0xcdcdcdcd). The pattern byte is increased\n" 1196 " by one for each request contained in the multiwrite command.\n" 1197 " -P, -- use different pattern to fill file\n" 1198 " -C, -- report statistics in a machine parsable format\n" 1199 " -q, -- quiet mode, do not show I/O statistics\n" 1200 "\n"); 1201 } 1202 1203 static int multiwrite_f(BlockBackend *blk, int argc, char **argv); 1204 1205 static const cmdinfo_t multiwrite_cmd = { 1206 .name = "multiwrite", 1207 .cfunc = multiwrite_f, 1208 .argmin = 2, 1209 .argmax = -1, 1210 .args = "[-Cq] [-P pattern ] off len [len..] [; off len [len..]..]", 1211 .oneline = "issues multiple write requests at once", 1212 .help = multiwrite_help, 1213 }; 1214 1215 static int multiwrite_f(BlockBackend *blk, int argc, char **argv) 1216 { 1217 struct timeval t1, t2; 1218 int Cflag = 0, qflag = 0; 1219 int c, cnt; 1220 char **buf; 1221 int64_t offset, first_offset = 0; 1222 /* Some compilers get confused and warn if this is not initialized. */ 1223 int total = 0; 1224 int nr_iov; 1225 int nr_reqs; 1226 int pattern = 0xcd; 1227 QEMUIOVector *qiovs; 1228 int i; 1229 BlockRequest *reqs; 1230 1231 while ((c = getopt(argc, argv, "CqP:")) != -1) { 1232 switch (c) { 1233 case 'C': 1234 Cflag = 1; 1235 break; 1236 case 'q': 1237 qflag = 1; 1238 break; 1239 case 'P': 1240 pattern = parse_pattern(optarg); 1241 if (pattern < 0) { 1242 return 0; 1243 } 1244 break; 1245 default: 1246 return qemuio_command_usage(&writev_cmd); 1247 } 1248 } 1249 1250 if (optind > argc - 2) { 1251 return qemuio_command_usage(&writev_cmd); 1252 } 1253 1254 nr_reqs = 1; 1255 for (i = optind; i < argc; i++) { 1256 if (!strcmp(argv[i], ";")) { 1257 nr_reqs++; 1258 } 1259 } 1260 1261 reqs = g_new0(BlockRequest, nr_reqs); 1262 buf = g_new0(char *, nr_reqs); 1263 qiovs = g_new(QEMUIOVector, nr_reqs); 1264 1265 for (i = 0; i < nr_reqs && optind < argc; i++) { 1266 int j; 1267 1268 /* Read the offset of the request */ 1269 offset = cvtnum(argv[optind]); 1270 if (offset < 0) { 1271 printf("non-numeric offset argument -- %s\n", argv[optind]); 1272 goto out; 1273 } 1274 optind++; 1275 1276 if (offset & 0x1ff) { 1277 printf("offset %lld is not sector aligned\n", 1278 (long long)offset); 1279 goto out; 1280 } 1281 1282 if (i == 0) { 1283 first_offset = offset; 1284 } 1285 1286 /* Read lengths for qiov entries */ 1287 for (j = optind; j < argc; j++) { 1288 if (!strcmp(argv[j], ";")) { 1289 break; 1290 } 1291 } 1292 1293 nr_iov = j - optind; 1294 1295 /* Build request */ 1296 buf[i] = create_iovec(blk, &qiovs[i], &argv[optind], nr_iov, pattern); 1297 if (buf[i] == NULL) { 1298 goto out; 1299 } 1300 1301 reqs[i].qiov = &qiovs[i]; 1302 reqs[i].sector = offset >> 9; 1303 reqs[i].nb_sectors = reqs[i].qiov->size >> 9; 1304 1305 optind = j + 1; 1306 1307 pattern++; 1308 } 1309 1310 /* If there were empty requests at the end, ignore them */ 1311 nr_reqs = i; 1312 1313 gettimeofday(&t1, NULL); 1314 cnt = do_aio_multiwrite(blk, reqs, nr_reqs, &total); 1315 gettimeofday(&t2, NULL); 1316 1317 if (cnt < 0) { 1318 printf("aio_multiwrite failed: %s\n", strerror(-cnt)); 1319 goto out; 1320 } 1321 1322 if (qflag) { 1323 goto out; 1324 } 1325 1326 /* Finally, report back -- -C gives a parsable format */ 1327 t2 = tsub(t2, t1); 1328 print_report("wrote", &t2, first_offset, total, total, cnt, Cflag); 1329 out: 1330 for (i = 0; i < nr_reqs; i++) { 1331 qemu_io_free(buf[i]); 1332 if (reqs[i].qiov != NULL) { 1333 qemu_iovec_destroy(&qiovs[i]); 1334 } 1335 } 1336 g_free(buf); 1337 g_free(reqs); 1338 g_free(qiovs); 1339 return 0; 1340 } 1341 1342 struct aio_ctx { 1343 BlockBackend *blk; 1344 QEMUIOVector qiov; 1345 int64_t offset; 1346 char *buf; 1347 int qflag; 1348 int vflag; 1349 int Cflag; 1350 int Pflag; 1351 BlockAcctCookie acct; 1352 int pattern; 1353 struct timeval t1; 1354 }; 1355 1356 static void aio_write_done(void *opaque, int ret) 1357 { 1358 struct aio_ctx *ctx = opaque; 1359 struct timeval t2; 1360 1361 gettimeofday(&t2, NULL); 1362 1363 1364 if (ret < 0) { 1365 printf("aio_write failed: %s\n", strerror(-ret)); 1366 goto out; 1367 } 1368 1369 block_acct_done(blk_get_stats(ctx->blk), &ctx->acct); 1370 1371 if (ctx->qflag) { 1372 goto out; 1373 } 1374 1375 /* Finally, report back -- -C gives a parsable format */ 1376 t2 = tsub(t2, ctx->t1); 1377 print_report("wrote", &t2, ctx->offset, ctx->qiov.size, 1378 ctx->qiov.size, 1, ctx->Cflag); 1379 out: 1380 qemu_io_free(ctx->buf); 1381 qemu_iovec_destroy(&ctx->qiov); 1382 g_free(ctx); 1383 } 1384 1385 static void aio_read_done(void *opaque, int ret) 1386 { 1387 struct aio_ctx *ctx = opaque; 1388 struct timeval t2; 1389 1390 gettimeofday(&t2, NULL); 1391 1392 if (ret < 0) { 1393 printf("readv failed: %s\n", strerror(-ret)); 1394 goto out; 1395 } 1396 1397 if (ctx->Pflag) { 1398 void *cmp_buf = g_malloc(ctx->qiov.size); 1399 1400 memset(cmp_buf, ctx->pattern, ctx->qiov.size); 1401 if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) { 1402 printf("Pattern verification failed at offset %" 1403 PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size); 1404 } 1405 g_free(cmp_buf); 1406 } 1407 1408 block_acct_done(blk_get_stats(ctx->blk), &ctx->acct); 1409 1410 if (ctx->qflag) { 1411 goto out; 1412 } 1413 1414 if (ctx->vflag) { 1415 dump_buffer(ctx->buf, ctx->offset, ctx->qiov.size); 1416 } 1417 1418 /* Finally, report back -- -C gives a parsable format */ 1419 t2 = tsub(t2, ctx->t1); 1420 print_report("read", &t2, ctx->offset, ctx->qiov.size, 1421 ctx->qiov.size, 1, ctx->Cflag); 1422 out: 1423 qemu_io_free(ctx->buf); 1424 qemu_iovec_destroy(&ctx->qiov); 1425 g_free(ctx); 1426 } 1427 1428 static void aio_read_help(void) 1429 { 1430 printf( 1431 "\n" 1432 " asynchronously reads a range of bytes from the given offset\n" 1433 "\n" 1434 " Example:\n" 1435 " 'aio_read -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n" 1436 "\n" 1437 " Reads a segment of the currently open file, optionally dumping it to the\n" 1438 " standard output stream (with -v option) for subsequent inspection.\n" 1439 " The read is performed asynchronously and the aio_flush command must be\n" 1440 " used to ensure all outstanding aio requests have been completed.\n" 1441 " -C, -- report statistics in a machine parsable format\n" 1442 " -P, -- use a pattern to verify read data\n" 1443 " -v, -- dump buffer to standard output\n" 1444 " -q, -- quiet mode, do not show I/O statistics\n" 1445 "\n"); 1446 } 1447 1448 static int aio_read_f(BlockBackend *blk, int argc, char **argv); 1449 1450 static const cmdinfo_t aio_read_cmd = { 1451 .name = "aio_read", 1452 .cfunc = aio_read_f, 1453 .argmin = 2, 1454 .argmax = -1, 1455 .args = "[-Cqv] [-P pattern ] off len [len..]", 1456 .oneline = "asynchronously reads a number of bytes", 1457 .help = aio_read_help, 1458 }; 1459 1460 static int aio_read_f(BlockBackend *blk, int argc, char **argv) 1461 { 1462 int nr_iov, c; 1463 struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); 1464 1465 ctx->blk = blk; 1466 while ((c = getopt(argc, argv, "CP:qv")) != -1) { 1467 switch (c) { 1468 case 'C': 1469 ctx->Cflag = 1; 1470 break; 1471 case 'P': 1472 ctx->Pflag = 1; 1473 ctx->pattern = parse_pattern(optarg); 1474 if (ctx->pattern < 0) { 1475 g_free(ctx); 1476 return 0; 1477 } 1478 break; 1479 case 'q': 1480 ctx->qflag = 1; 1481 break; 1482 case 'v': 1483 ctx->vflag = 1; 1484 break; 1485 default: 1486 g_free(ctx); 1487 return qemuio_command_usage(&aio_read_cmd); 1488 } 1489 } 1490 1491 if (optind > argc - 2) { 1492 g_free(ctx); 1493 return qemuio_command_usage(&aio_read_cmd); 1494 } 1495 1496 ctx->offset = cvtnum(argv[optind]); 1497 if (ctx->offset < 0) { 1498 printf("non-numeric length argument -- %s\n", argv[optind]); 1499 g_free(ctx); 1500 return 0; 1501 } 1502 optind++; 1503 1504 if (ctx->offset & 0x1ff) { 1505 printf("offset %" PRId64 " is not sector aligned\n", 1506 ctx->offset); 1507 g_free(ctx); 1508 return 0; 1509 } 1510 1511 nr_iov = argc - optind; 1512 ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, 0xab); 1513 if (ctx->buf == NULL) { 1514 g_free(ctx); 1515 return 0; 1516 } 1517 1518 gettimeofday(&ctx->t1, NULL); 1519 block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size, 1520 BLOCK_ACCT_READ); 1521 blk_aio_readv(blk, ctx->offset >> 9, &ctx->qiov, 1522 ctx->qiov.size >> 9, aio_read_done, ctx); 1523 return 0; 1524 } 1525 1526 static void aio_write_help(void) 1527 { 1528 printf( 1529 "\n" 1530 " asynchronously writes a range of bytes from the given offset source\n" 1531 " from multiple buffers\n" 1532 "\n" 1533 " Example:\n" 1534 " 'aio_write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n" 1535 "\n" 1536 " Writes into a segment of the currently open file, using a buffer\n" 1537 " filled with a set pattern (0xcdcdcdcd).\n" 1538 " The write is performed asynchronously and the aio_flush command must be\n" 1539 " used to ensure all outstanding aio requests have been completed.\n" 1540 " -P, -- use different pattern to fill file\n" 1541 " -C, -- report statistics in a machine parsable format\n" 1542 " -q, -- quiet mode, do not show I/O statistics\n" 1543 "\n"); 1544 } 1545 1546 static int aio_write_f(BlockBackend *blk, int argc, char **argv); 1547 1548 static const cmdinfo_t aio_write_cmd = { 1549 .name = "aio_write", 1550 .cfunc = aio_write_f, 1551 .argmin = 2, 1552 .argmax = -1, 1553 .args = "[-Cq] [-P pattern ] off len [len..]", 1554 .oneline = "asynchronously writes a number of bytes", 1555 .help = aio_write_help, 1556 }; 1557 1558 static int aio_write_f(BlockBackend *blk, int argc, char **argv) 1559 { 1560 int nr_iov, c; 1561 int pattern = 0xcd; 1562 struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); 1563 1564 ctx->blk = blk; 1565 while ((c = getopt(argc, argv, "CqP:")) != -1) { 1566 switch (c) { 1567 case 'C': 1568 ctx->Cflag = 1; 1569 break; 1570 case 'q': 1571 ctx->qflag = 1; 1572 break; 1573 case 'P': 1574 pattern = parse_pattern(optarg); 1575 if (pattern < 0) { 1576 g_free(ctx); 1577 return 0; 1578 } 1579 break; 1580 default: 1581 g_free(ctx); 1582 return qemuio_command_usage(&aio_write_cmd); 1583 } 1584 } 1585 1586 if (optind > argc - 2) { 1587 g_free(ctx); 1588 return qemuio_command_usage(&aio_write_cmd); 1589 } 1590 1591 ctx->offset = cvtnum(argv[optind]); 1592 if (ctx->offset < 0) { 1593 printf("non-numeric length argument -- %s\n", argv[optind]); 1594 g_free(ctx); 1595 return 0; 1596 } 1597 optind++; 1598 1599 if (ctx->offset & 0x1ff) { 1600 printf("offset %" PRId64 " is not sector aligned\n", 1601 ctx->offset); 1602 g_free(ctx); 1603 return 0; 1604 } 1605 1606 nr_iov = argc - optind; 1607 ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, pattern); 1608 if (ctx->buf == NULL) { 1609 g_free(ctx); 1610 return 0; 1611 } 1612 1613 gettimeofday(&ctx->t1, NULL); 1614 block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size, 1615 BLOCK_ACCT_WRITE); 1616 blk_aio_writev(blk, ctx->offset >> 9, &ctx->qiov, 1617 ctx->qiov.size >> 9, aio_write_done, ctx); 1618 return 0; 1619 } 1620 1621 static int aio_flush_f(BlockBackend *blk, int argc, char **argv) 1622 { 1623 blk_drain_all(); 1624 return 0; 1625 } 1626 1627 static const cmdinfo_t aio_flush_cmd = { 1628 .name = "aio_flush", 1629 .cfunc = aio_flush_f, 1630 .oneline = "completes all outstanding aio requests" 1631 }; 1632 1633 static int flush_f(BlockBackend *blk, int argc, char **argv) 1634 { 1635 blk_flush(blk); 1636 return 0; 1637 } 1638 1639 static const cmdinfo_t flush_cmd = { 1640 .name = "flush", 1641 .altname = "f", 1642 .cfunc = flush_f, 1643 .oneline = "flush all in-core file state to disk", 1644 }; 1645 1646 static int truncate_f(BlockBackend *blk, int argc, char **argv) 1647 { 1648 int64_t offset; 1649 int ret; 1650 1651 offset = cvtnum(argv[1]); 1652 if (offset < 0) { 1653 printf("non-numeric truncate argument -- %s\n", argv[1]); 1654 return 0; 1655 } 1656 1657 ret = blk_truncate(blk, offset); 1658 if (ret < 0) { 1659 printf("truncate: %s\n", strerror(-ret)); 1660 return 0; 1661 } 1662 1663 return 0; 1664 } 1665 1666 static const cmdinfo_t truncate_cmd = { 1667 .name = "truncate", 1668 .altname = "t", 1669 .cfunc = truncate_f, 1670 .argmin = 1, 1671 .argmax = 1, 1672 .args = "off", 1673 .oneline = "truncates the current file at the given offset", 1674 }; 1675 1676 static int length_f(BlockBackend *blk, int argc, char **argv) 1677 { 1678 int64_t size; 1679 char s1[64]; 1680 1681 size = blk_getlength(blk); 1682 if (size < 0) { 1683 printf("getlength: %s\n", strerror(-size)); 1684 return 0; 1685 } 1686 1687 cvtstr(size, s1, sizeof(s1)); 1688 printf("%s\n", s1); 1689 return 0; 1690 } 1691 1692 1693 static const cmdinfo_t length_cmd = { 1694 .name = "length", 1695 .altname = "l", 1696 .cfunc = length_f, 1697 .oneline = "gets the length of the current file", 1698 }; 1699 1700 1701 static int info_f(BlockBackend *blk, int argc, char **argv) 1702 { 1703 BlockDriverState *bs = blk_bs(blk); 1704 BlockDriverInfo bdi; 1705 ImageInfoSpecific *spec_info; 1706 char s1[64], s2[64]; 1707 int ret; 1708 1709 if (bs->drv && bs->drv->format_name) { 1710 printf("format name: %s\n", bs->drv->format_name); 1711 } 1712 if (bs->drv && bs->drv->protocol_name) { 1713 printf("format name: %s\n", bs->drv->protocol_name); 1714 } 1715 1716 ret = bdrv_get_info(bs, &bdi); 1717 if (ret) { 1718 return 0; 1719 } 1720 1721 cvtstr(bdi.cluster_size, s1, sizeof(s1)); 1722 cvtstr(bdi.vm_state_offset, s2, sizeof(s2)); 1723 1724 printf("cluster size: %s\n", s1); 1725 printf("vm state offset: %s\n", s2); 1726 1727 spec_info = bdrv_get_specific_info(bs); 1728 if (spec_info) { 1729 printf("Format specific information:\n"); 1730 bdrv_image_info_specific_dump(fprintf, stdout, spec_info); 1731 qapi_free_ImageInfoSpecific(spec_info); 1732 } 1733 1734 return 0; 1735 } 1736 1737 1738 1739 static const cmdinfo_t info_cmd = { 1740 .name = "info", 1741 .altname = "i", 1742 .cfunc = info_f, 1743 .oneline = "prints information about the current file", 1744 }; 1745 1746 static void discard_help(void) 1747 { 1748 printf( 1749 "\n" 1750 " discards a range of bytes from the given offset\n" 1751 "\n" 1752 " Example:\n" 1753 " 'discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\n" 1754 "\n" 1755 " Discards a segment of the currently open file.\n" 1756 " -C, -- report statistics in a machine parsable format\n" 1757 " -q, -- quiet mode, do not show I/O statistics\n" 1758 "\n"); 1759 } 1760 1761 static int discard_f(BlockBackend *blk, int argc, char **argv); 1762 1763 static const cmdinfo_t discard_cmd = { 1764 .name = "discard", 1765 .altname = "d", 1766 .cfunc = discard_f, 1767 .argmin = 2, 1768 .argmax = -1, 1769 .args = "[-Cq] off len", 1770 .oneline = "discards a number of bytes at a specified offset", 1771 .help = discard_help, 1772 }; 1773 1774 static int discard_f(BlockBackend *blk, int argc, char **argv) 1775 { 1776 struct timeval t1, t2; 1777 int Cflag = 0, qflag = 0; 1778 int c, ret; 1779 int64_t offset; 1780 int count; 1781 1782 while ((c = getopt(argc, argv, "Cq")) != -1) { 1783 switch (c) { 1784 case 'C': 1785 Cflag = 1; 1786 break; 1787 case 'q': 1788 qflag = 1; 1789 break; 1790 default: 1791 return qemuio_command_usage(&discard_cmd); 1792 } 1793 } 1794 1795 if (optind != argc - 2) { 1796 return qemuio_command_usage(&discard_cmd); 1797 } 1798 1799 offset = cvtnum(argv[optind]); 1800 if (offset < 0) { 1801 printf("non-numeric length argument -- %s\n", argv[optind]); 1802 return 0; 1803 } 1804 1805 optind++; 1806 count = cvtnum(argv[optind]); 1807 if (count < 0) { 1808 printf("non-numeric length argument -- %s\n", argv[optind]); 1809 return 0; 1810 } 1811 1812 gettimeofday(&t1, NULL); 1813 ret = blk_discard(blk, offset >> BDRV_SECTOR_BITS, 1814 count >> BDRV_SECTOR_BITS); 1815 gettimeofday(&t2, NULL); 1816 1817 if (ret < 0) { 1818 printf("discard failed: %s\n", strerror(-ret)); 1819 goto out; 1820 } 1821 1822 /* Finally, report back -- -C gives a parsable format */ 1823 if (!qflag) { 1824 t2 = tsub(t2, t1); 1825 print_report("discard", &t2, offset, count, count, 1, Cflag); 1826 } 1827 1828 out: 1829 return 0; 1830 } 1831 1832 static int alloc_f(BlockBackend *blk, int argc, char **argv) 1833 { 1834 BlockDriverState *bs = blk_bs(blk); 1835 int64_t offset, sector_num; 1836 int nb_sectors, remaining; 1837 char s1[64]; 1838 int num, sum_alloc; 1839 int ret; 1840 1841 offset = cvtnum(argv[1]); 1842 if (offset < 0) { 1843 printf("non-numeric offset argument -- %s\n", argv[1]); 1844 return 0; 1845 } else if (offset & 0x1ff) { 1846 printf("offset %" PRId64 " is not sector aligned\n", 1847 offset); 1848 return 0; 1849 } 1850 1851 if (argc == 3) { 1852 nb_sectors = cvtnum(argv[2]); 1853 if (nb_sectors < 0) { 1854 printf("non-numeric length argument -- %s\n", argv[2]); 1855 return 0; 1856 } 1857 } else { 1858 nb_sectors = 1; 1859 } 1860 1861 remaining = nb_sectors; 1862 sum_alloc = 0; 1863 sector_num = offset >> 9; 1864 while (remaining) { 1865 ret = bdrv_is_allocated(bs, sector_num, remaining, &num); 1866 if (ret < 0) { 1867 printf("is_allocated failed: %s\n", strerror(-ret)); 1868 return 0; 1869 } 1870 sector_num += num; 1871 remaining -= num; 1872 if (ret) { 1873 sum_alloc += num; 1874 } 1875 if (num == 0) { 1876 nb_sectors -= remaining; 1877 remaining = 0; 1878 } 1879 } 1880 1881 cvtstr(offset, s1, sizeof(s1)); 1882 1883 printf("%d/%d sectors allocated at offset %s\n", 1884 sum_alloc, nb_sectors, s1); 1885 return 0; 1886 } 1887 1888 static const cmdinfo_t alloc_cmd = { 1889 .name = "alloc", 1890 .altname = "a", 1891 .argmin = 1, 1892 .argmax = 2, 1893 .cfunc = alloc_f, 1894 .args = "off [sectors]", 1895 .oneline = "checks if a sector is present in the file", 1896 }; 1897 1898 1899 static int map_is_allocated(BlockDriverState *bs, int64_t sector_num, 1900 int64_t nb_sectors, int64_t *pnum) 1901 { 1902 int num, num_checked; 1903 int ret, firstret; 1904 1905 num_checked = MIN(nb_sectors, INT_MAX); 1906 ret = bdrv_is_allocated(bs, sector_num, num_checked, &num); 1907 if (ret < 0) { 1908 return ret; 1909 } 1910 1911 firstret = ret; 1912 *pnum = num; 1913 1914 while (nb_sectors > 0 && ret == firstret) { 1915 sector_num += num; 1916 nb_sectors -= num; 1917 1918 num_checked = MIN(nb_sectors, INT_MAX); 1919 ret = bdrv_is_allocated(bs, sector_num, num_checked, &num); 1920 if (ret == firstret && num) { 1921 *pnum += num; 1922 } else { 1923 break; 1924 } 1925 } 1926 1927 return firstret; 1928 } 1929 1930 static int map_f(BlockBackend *blk, int argc, char **argv) 1931 { 1932 int64_t offset; 1933 int64_t nb_sectors, total_sectors; 1934 char s1[64]; 1935 int64_t num; 1936 int ret; 1937 const char *retstr; 1938 1939 offset = 0; 1940 total_sectors = blk_nb_sectors(blk); 1941 if (total_sectors < 0) { 1942 error_report("Failed to query image length: %s", 1943 strerror(-total_sectors)); 1944 return 0; 1945 } 1946 1947 nb_sectors = total_sectors; 1948 1949 do { 1950 ret = map_is_allocated(blk_bs(blk), offset, nb_sectors, &num); 1951 if (ret < 0) { 1952 error_report("Failed to get allocation status: %s", strerror(-ret)); 1953 return 0; 1954 } else if (!num) { 1955 error_report("Unexpected end of image"); 1956 return 0; 1957 } 1958 1959 retstr = ret ? " allocated" : "not allocated"; 1960 cvtstr(offset << 9ULL, s1, sizeof(s1)); 1961 printf("[% 24" PRId64 "] % 8" PRId64 "/% 8" PRId64 " sectors %s " 1962 "at offset %s (%d)\n", 1963 offset << 9ULL, num, nb_sectors, retstr, s1, ret); 1964 1965 offset += num; 1966 nb_sectors -= num; 1967 } while (offset < total_sectors); 1968 1969 return 0; 1970 } 1971 1972 static const cmdinfo_t map_cmd = { 1973 .name = "map", 1974 .argmin = 0, 1975 .argmax = 0, 1976 .cfunc = map_f, 1977 .args = "", 1978 .oneline = "prints the allocated areas of a file", 1979 }; 1980 1981 static int break_f(BlockBackend *blk, int argc, char **argv) 1982 { 1983 int ret; 1984 1985 ret = bdrv_debug_breakpoint(blk_bs(blk), argv[1], argv[2]); 1986 if (ret < 0) { 1987 printf("Could not set breakpoint: %s\n", strerror(-ret)); 1988 } 1989 1990 return 0; 1991 } 1992 1993 static int remove_break_f(BlockBackend *blk, int argc, char **argv) 1994 { 1995 int ret; 1996 1997 ret = bdrv_debug_remove_breakpoint(blk_bs(blk), argv[1]); 1998 if (ret < 0) { 1999 printf("Could not remove breakpoint %s: %s\n", argv[1], strerror(-ret)); 2000 } 2001 2002 return 0; 2003 } 2004 2005 static const cmdinfo_t break_cmd = { 2006 .name = "break", 2007 .argmin = 2, 2008 .argmax = 2, 2009 .cfunc = break_f, 2010 .args = "event tag", 2011 .oneline = "sets a breakpoint on event and tags the stopped " 2012 "request as tag", 2013 }; 2014 2015 static const cmdinfo_t remove_break_cmd = { 2016 .name = "remove_break", 2017 .argmin = 1, 2018 .argmax = 1, 2019 .cfunc = remove_break_f, 2020 .args = "tag", 2021 .oneline = "remove a breakpoint by tag", 2022 }; 2023 2024 static int resume_f(BlockBackend *blk, int argc, char **argv) 2025 { 2026 int ret; 2027 2028 ret = bdrv_debug_resume(blk_bs(blk), argv[1]); 2029 if (ret < 0) { 2030 printf("Could not resume request: %s\n", strerror(-ret)); 2031 } 2032 2033 return 0; 2034 } 2035 2036 static const cmdinfo_t resume_cmd = { 2037 .name = "resume", 2038 .argmin = 1, 2039 .argmax = 1, 2040 .cfunc = resume_f, 2041 .args = "tag", 2042 .oneline = "resumes the request tagged as tag", 2043 }; 2044 2045 static int wait_break_f(BlockBackend *blk, int argc, char **argv) 2046 { 2047 while (!bdrv_debug_is_suspended(blk_bs(blk), argv[1])) { 2048 aio_poll(blk_get_aio_context(blk), true); 2049 } 2050 2051 return 0; 2052 } 2053 2054 static const cmdinfo_t wait_break_cmd = { 2055 .name = "wait_break", 2056 .argmin = 1, 2057 .argmax = 1, 2058 .cfunc = wait_break_f, 2059 .args = "tag", 2060 .oneline = "waits for the suspension of a request", 2061 }; 2062 2063 static int abort_f(BlockBackend *blk, int argc, char **argv) 2064 { 2065 abort(); 2066 } 2067 2068 static const cmdinfo_t abort_cmd = { 2069 .name = "abort", 2070 .cfunc = abort_f, 2071 .flags = CMD_NOFILE_OK, 2072 .oneline = "simulate a program crash using abort(3)", 2073 }; 2074 2075 static void sigraise_help(void) 2076 { 2077 printf( 2078 "\n" 2079 " raises the given signal\n" 2080 "\n" 2081 " Example:\n" 2082 " 'sigraise %i' - raises SIGTERM\n" 2083 "\n" 2084 " Invokes raise(signal), where \"signal\" is the mandatory integer argument\n" 2085 " given to sigraise.\n" 2086 "\n", SIGTERM); 2087 } 2088 2089 static int sigraise_f(BlockBackend *blk, int argc, char **argv); 2090 2091 static const cmdinfo_t sigraise_cmd = { 2092 .name = "sigraise", 2093 .cfunc = sigraise_f, 2094 .argmin = 1, 2095 .argmax = 1, 2096 .flags = CMD_NOFILE_OK, 2097 .args = "signal", 2098 .oneline = "raises a signal", 2099 .help = sigraise_help, 2100 }; 2101 2102 static int sigraise_f(BlockBackend *blk, int argc, char **argv) 2103 { 2104 int sig = cvtnum(argv[1]); 2105 if (sig < 0) { 2106 printf("non-numeric signal number argument -- %s\n", argv[1]); 2107 return 0; 2108 } 2109 2110 /* Using raise() to kill this process does not necessarily flush all open 2111 * streams. At least stdout and stderr (although the latter should be 2112 * non-buffered anyway) should be flushed, though. */ 2113 fflush(stdout); 2114 fflush(stderr); 2115 2116 raise(sig); 2117 return 0; 2118 } 2119 2120 static void sleep_cb(void *opaque) 2121 { 2122 bool *expired = opaque; 2123 *expired = true; 2124 } 2125 2126 static int sleep_f(BlockBackend *blk, int argc, char **argv) 2127 { 2128 char *endptr; 2129 long ms; 2130 struct QEMUTimer *timer; 2131 bool expired = false; 2132 2133 ms = strtol(argv[1], &endptr, 0); 2134 if (ms < 0 || *endptr != '\0') { 2135 printf("%s is not a valid number\n", argv[1]); 2136 return 0; 2137 } 2138 2139 timer = timer_new_ns(QEMU_CLOCK_HOST, sleep_cb, &expired); 2140 timer_mod(timer, qemu_clock_get_ns(QEMU_CLOCK_HOST) + SCALE_MS * ms); 2141 2142 while (!expired) { 2143 main_loop_wait(false); 2144 } 2145 2146 timer_free(timer); 2147 2148 return 0; 2149 } 2150 2151 static const cmdinfo_t sleep_cmd = { 2152 .name = "sleep", 2153 .argmin = 1, 2154 .argmax = 1, 2155 .cfunc = sleep_f, 2156 .flags = CMD_NOFILE_OK, 2157 .oneline = "waits for the given value in milliseconds", 2158 }; 2159 2160 static void help_oneline(const char *cmd, const cmdinfo_t *ct) 2161 { 2162 if (cmd) { 2163 printf("%s ", cmd); 2164 } else { 2165 printf("%s ", ct->name); 2166 if (ct->altname) { 2167 printf("(or %s) ", ct->altname); 2168 } 2169 } 2170 2171 if (ct->args) { 2172 printf("%s ", ct->args); 2173 } 2174 printf("-- %s\n", ct->oneline); 2175 } 2176 2177 static void help_onecmd(const char *cmd, const cmdinfo_t *ct) 2178 { 2179 help_oneline(cmd, ct); 2180 if (ct->help) { 2181 ct->help(); 2182 } 2183 } 2184 2185 static void help_all(void) 2186 { 2187 const cmdinfo_t *ct; 2188 2189 for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) { 2190 help_oneline(ct->name, ct); 2191 } 2192 printf("\nUse 'help commandname' for extended help.\n"); 2193 } 2194 2195 static int help_f(BlockBackend *blk, int argc, char **argv) 2196 { 2197 const cmdinfo_t *ct; 2198 2199 if (argc == 1) { 2200 help_all(); 2201 return 0; 2202 } 2203 2204 ct = find_command(argv[1]); 2205 if (ct == NULL) { 2206 printf("command %s not found\n", argv[1]); 2207 return 0; 2208 } 2209 2210 help_onecmd(argv[1], ct); 2211 return 0; 2212 } 2213 2214 static const cmdinfo_t help_cmd = { 2215 .name = "help", 2216 .altname = "?", 2217 .cfunc = help_f, 2218 .argmin = 0, 2219 .argmax = 1, 2220 .flags = CMD_FLAG_GLOBAL, 2221 .args = "[command]", 2222 .oneline = "help for one or all commands", 2223 }; 2224 2225 bool qemuio_command(BlockBackend *blk, const char *cmd) 2226 { 2227 char *input; 2228 const cmdinfo_t *ct; 2229 char **v; 2230 int c; 2231 bool done = false; 2232 2233 input = g_strdup(cmd); 2234 v = breakline(input, &c); 2235 if (c) { 2236 ct = find_command(v[0]); 2237 if (ct) { 2238 done = command(blk, ct, c, v); 2239 } else { 2240 fprintf(stderr, "command \"%s\" not found\n", v[0]); 2241 } 2242 } 2243 g_free(input); 2244 g_free(v); 2245 2246 return done; 2247 } 2248 2249 static void __attribute((constructor)) init_qemuio_commands(void) 2250 { 2251 /* initialize commands */ 2252 qemuio_add_command(&help_cmd); 2253 qemuio_add_command(&read_cmd); 2254 qemuio_add_command(&readv_cmd); 2255 qemuio_add_command(&write_cmd); 2256 qemuio_add_command(&writev_cmd); 2257 qemuio_add_command(&multiwrite_cmd); 2258 qemuio_add_command(&aio_read_cmd); 2259 qemuio_add_command(&aio_write_cmd); 2260 qemuio_add_command(&aio_flush_cmd); 2261 qemuio_add_command(&flush_cmd); 2262 qemuio_add_command(&truncate_cmd); 2263 qemuio_add_command(&length_cmd); 2264 qemuio_add_command(&info_cmd); 2265 qemuio_add_command(&discard_cmd); 2266 qemuio_add_command(&alloc_cmd); 2267 qemuio_add_command(&map_cmd); 2268 qemuio_add_command(&break_cmd); 2269 qemuio_add_command(&remove_break_cmd); 2270 qemuio_add_command(&resume_cmd); 2271 qemuio_add_command(&wait_break_cmd); 2272 qemuio_add_command(&abort_cmd); 2273 qemuio_add_command(&sleep_cmd); 2274 qemuio_add_command(&sigraise_cmd); 2275 } 2276