1e3aff4f6Saliguori /* 2e3aff4f6Saliguori * Command line utility to exercise the QEMU I/O path. 3e3aff4f6Saliguori * 4e3aff4f6Saliguori * Copyright (C) 2009 Red Hat, Inc. 5e3aff4f6Saliguori * Copyright (c) 2003-2005 Silicon Graphics, Inc. 6e3aff4f6Saliguori * 7e3aff4f6Saliguori * This work is licensed under the terms of the GNU GPL, version 2 or later. 8e3aff4f6Saliguori * See the COPYING file in the top-level directory. 9e3aff4f6Saliguori */ 10*c32d766aSStefan Weil #include <sys/time.h> 11e3aff4f6Saliguori #include <sys/types.h> 12e3aff4f6Saliguori #include <stdarg.h> 13e3aff4f6Saliguori #include <stdio.h> 14e3aff4f6Saliguori #include <getopt.h> 15*c32d766aSStefan Weil #include <libgen.h> 16e3aff4f6Saliguori 17e3aff4f6Saliguori #include "qemu-common.h" 18e3aff4f6Saliguori #include "block_int.h" 19e3aff4f6Saliguori #include "cmd.h" 20e3aff4f6Saliguori 21e3aff4f6Saliguori #define VERSION "0.0.1" 22e3aff4f6Saliguori 23e3aff4f6Saliguori #define CMD_NOFILE_OK 0x01 24e3aff4f6Saliguori 25e3aff4f6Saliguori char *progname; 26e3aff4f6Saliguori static BlockDriverState *bs; 27e3aff4f6Saliguori 28e3aff4f6Saliguori static int misalign; 29e3aff4f6Saliguori 30e3aff4f6Saliguori /* 31cf070d7eSChristoph Hellwig * Parse the pattern argument to various sub-commands. 32cf070d7eSChristoph Hellwig * 33cf070d7eSChristoph Hellwig * Because the pattern is used as an argument to memset it must evaluate 34cf070d7eSChristoph Hellwig * to an unsigned integer that fits into a single byte. 35cf070d7eSChristoph Hellwig */ 36cf070d7eSChristoph Hellwig static int parse_pattern(const char *arg) 37cf070d7eSChristoph Hellwig { 38cf070d7eSChristoph Hellwig char *endptr = NULL; 39cf070d7eSChristoph Hellwig long pattern; 40cf070d7eSChristoph Hellwig 41cf070d7eSChristoph Hellwig pattern = strtol(arg, &endptr, 0); 42cf070d7eSChristoph Hellwig if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') { 43cf070d7eSChristoph Hellwig printf("%s is not a valid pattern byte\n", arg); 44cf070d7eSChristoph Hellwig return -1; 45cf070d7eSChristoph Hellwig } 46cf070d7eSChristoph Hellwig 47cf070d7eSChristoph Hellwig return pattern; 48cf070d7eSChristoph Hellwig } 49cf070d7eSChristoph Hellwig 50cf070d7eSChristoph Hellwig /* 51e3aff4f6Saliguori * Memory allocation helpers. 52e3aff4f6Saliguori * 53e3aff4f6Saliguori * Make sure memory is aligned by default, or purposefully misaligned if 54e3aff4f6Saliguori * that is specified on the command line. 55e3aff4f6Saliguori */ 56e3aff4f6Saliguori 57e3aff4f6Saliguori #define MISALIGN_OFFSET 16 58e3aff4f6Saliguori static void *qemu_io_alloc(size_t len, int pattern) 59e3aff4f6Saliguori { 60e3aff4f6Saliguori void *buf; 61e3aff4f6Saliguori 62e3aff4f6Saliguori if (misalign) 63e3aff4f6Saliguori len += MISALIGN_OFFSET; 64e3aff4f6Saliguori buf = qemu_memalign(512, len); 65e3aff4f6Saliguori memset(buf, pattern, len); 66e3aff4f6Saliguori if (misalign) 67e3aff4f6Saliguori buf += MISALIGN_OFFSET; 68e3aff4f6Saliguori return buf; 69e3aff4f6Saliguori } 70e3aff4f6Saliguori 71e3aff4f6Saliguori static void qemu_io_free(void *p) 72e3aff4f6Saliguori { 73e3aff4f6Saliguori if (misalign) 74e3aff4f6Saliguori p -= MISALIGN_OFFSET; 75e3aff4f6Saliguori qemu_vfree(p); 76e3aff4f6Saliguori } 77e3aff4f6Saliguori 78e3aff4f6Saliguori static void 793abcdf49SStefan Weil dump_buffer(const void *buffer, int64_t offset, int len) 80e3aff4f6Saliguori { 81e3aff4f6Saliguori int i, j; 823abcdf49SStefan Weil const uint8_t *p; 83e3aff4f6Saliguori 84e3aff4f6Saliguori for (i = 0, p = buffer; i < len; i += 16) { 853abcdf49SStefan Weil const uint8_t *s = p; 86e3aff4f6Saliguori 87e3aff4f6Saliguori printf("%08llx: ", (unsigned long long)offset + i); 88e3aff4f6Saliguori for (j = 0; j < 16 && i + j < len; j++, p++) 89e3aff4f6Saliguori printf("%02x ", *p); 90e3aff4f6Saliguori printf(" "); 91e3aff4f6Saliguori for (j = 0; j < 16 && i + j < len; j++, s++) { 923abcdf49SStefan Weil if (isalnum(*s)) 93e3aff4f6Saliguori printf("%c", *s); 94e3aff4f6Saliguori else 95e3aff4f6Saliguori printf("."); 96e3aff4f6Saliguori } 97e3aff4f6Saliguori printf("\n"); 98e3aff4f6Saliguori } 99e3aff4f6Saliguori } 100e3aff4f6Saliguori 101e3aff4f6Saliguori static void 102e3aff4f6Saliguori print_report(const char *op, struct timeval *t, int64_t offset, 103e3aff4f6Saliguori int count, int total, int cnt, int Cflag) 104e3aff4f6Saliguori { 105e3aff4f6Saliguori char s1[64], s2[64], ts[64]; 106e3aff4f6Saliguori 107e3aff4f6Saliguori timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0); 108e3aff4f6Saliguori if (!Cflag) { 109e3aff4f6Saliguori cvtstr((double)total, s1, sizeof(s1)); 110e3aff4f6Saliguori cvtstr(tdiv((double)total, *t), s2, sizeof(s2)); 111e3aff4f6Saliguori printf("%s %d/%d bytes at offset %lld\n", 112e3aff4f6Saliguori op, total, count, (long long)offset); 113e3aff4f6Saliguori printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n", 114e3aff4f6Saliguori s1, cnt, ts, s2, tdiv((double)cnt, *t)); 115e3aff4f6Saliguori } else {/* bytes,ops,time,bytes/sec,ops/sec */ 116e3aff4f6Saliguori printf("%d,%d,%s,%.3f,%.3f\n", 117e3aff4f6Saliguori total, cnt, ts, 118e3aff4f6Saliguori tdiv((double)total, *t), 119e3aff4f6Saliguori tdiv((double)cnt, *t)); 120e3aff4f6Saliguori } 121e3aff4f6Saliguori } 122e3aff4f6Saliguori 123cf57298aSChristoph Hellwig /* 124cf57298aSChristoph Hellwig * Parse multiple length statements for vectored I/O, and construct an I/O 125cf57298aSChristoph Hellwig * vector matching it. 126cf57298aSChristoph Hellwig */ 127cf57298aSChristoph Hellwig static void * 128cf57298aSChristoph Hellwig create_iovec(QEMUIOVector *qiov, char **argv, int nr_iov, int pattern) 129cf57298aSChristoph Hellwig { 130cf57298aSChristoph Hellwig size_t *sizes = calloc(nr_iov, sizeof(size_t)); 131cf57298aSChristoph Hellwig size_t count = 0; 132cf57298aSChristoph Hellwig void *buf, *p; 133cf57298aSChristoph Hellwig int i; 134cf57298aSChristoph Hellwig 135cf57298aSChristoph Hellwig for (i = 0; i < nr_iov; i++) { 136cf57298aSChristoph Hellwig char *arg = argv[i]; 137cf57298aSChristoph Hellwig long long len; 138cf57298aSChristoph Hellwig 139cf57298aSChristoph Hellwig len = cvtnum(arg); 140cf57298aSChristoph Hellwig if (len < 0) { 141cf57298aSChristoph Hellwig printf("non-numeric length argument -- %s\n", arg); 142cf57298aSChristoph Hellwig return NULL; 143cf57298aSChristoph Hellwig } 144cf57298aSChristoph Hellwig 145cf57298aSChristoph Hellwig /* should be SIZE_T_MAX, but that doesn't exist */ 146cf57298aSChristoph Hellwig if (len > UINT_MAX) { 147cf57298aSChristoph Hellwig printf("too large length argument -- %s\n", arg); 148cf57298aSChristoph Hellwig return NULL; 149cf57298aSChristoph Hellwig } 150cf57298aSChristoph Hellwig 151cf57298aSChristoph Hellwig if (len & 0x1ff) { 152cf57298aSChristoph Hellwig printf("length argument %lld is not sector aligned\n", 153cf57298aSChristoph Hellwig len); 154cf57298aSChristoph Hellwig return NULL; 155cf57298aSChristoph Hellwig } 156cf57298aSChristoph Hellwig 157cf57298aSChristoph Hellwig sizes[i] = len; 158cf57298aSChristoph Hellwig count += len; 159cf57298aSChristoph Hellwig } 160cf57298aSChristoph Hellwig 161cf57298aSChristoph Hellwig qemu_iovec_init(qiov, nr_iov); 162cf57298aSChristoph Hellwig 163cf57298aSChristoph Hellwig buf = p = qemu_io_alloc(count, pattern); 164cf57298aSChristoph Hellwig 165cf57298aSChristoph Hellwig for (i = 0; i < nr_iov; i++) { 166cf57298aSChristoph Hellwig qemu_iovec_add(qiov, p, sizes[i]); 167cf57298aSChristoph Hellwig p += sizes[i]; 168cf57298aSChristoph Hellwig } 169cf57298aSChristoph Hellwig 170cf57298aSChristoph Hellwig free(sizes); 171cf57298aSChristoph Hellwig return buf; 172cf57298aSChristoph Hellwig } 173cf57298aSChristoph Hellwig 174e3aff4f6Saliguori static int do_read(char *buf, int64_t offset, int count, int *total) 175e3aff4f6Saliguori { 176e3aff4f6Saliguori int ret; 177e3aff4f6Saliguori 178e3aff4f6Saliguori ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9); 179e3aff4f6Saliguori if (ret < 0) 180e3aff4f6Saliguori return ret; 181e3aff4f6Saliguori *total = count; 182e3aff4f6Saliguori return 1; 183e3aff4f6Saliguori } 184e3aff4f6Saliguori 185e3aff4f6Saliguori static int do_write(char *buf, int64_t offset, int count, int *total) 186e3aff4f6Saliguori { 187e3aff4f6Saliguori int ret; 188e3aff4f6Saliguori 189e3aff4f6Saliguori ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9); 190e3aff4f6Saliguori if (ret < 0) 191e3aff4f6Saliguori return ret; 192e3aff4f6Saliguori *total = count; 193e3aff4f6Saliguori return 1; 194e3aff4f6Saliguori } 195e3aff4f6Saliguori 196e3aff4f6Saliguori static int do_pread(char *buf, int64_t offset, int count, int *total) 197e3aff4f6Saliguori { 198e3aff4f6Saliguori *total = bdrv_pread(bs, offset, (uint8_t *)buf, count); 199e3aff4f6Saliguori if (*total < 0) 200e3aff4f6Saliguori return *total; 201e3aff4f6Saliguori return 1; 202e3aff4f6Saliguori } 203e3aff4f6Saliguori 204e3aff4f6Saliguori static int do_pwrite(char *buf, int64_t offset, int count, int *total) 205e3aff4f6Saliguori { 206e3aff4f6Saliguori *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count); 207e3aff4f6Saliguori if (*total < 0) 208e3aff4f6Saliguori return *total; 209e3aff4f6Saliguori return 1; 210e3aff4f6Saliguori } 211e3aff4f6Saliguori 212ca94dbc7SKevin Wolf static int do_load_vmstate(char *buf, int64_t offset, int count, int *total) 213ca94dbc7SKevin Wolf { 214ca94dbc7SKevin Wolf *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count); 215ca94dbc7SKevin Wolf if (*total < 0) 216ca94dbc7SKevin Wolf return *total; 217ca94dbc7SKevin Wolf return 1; 218ca94dbc7SKevin Wolf } 219ca94dbc7SKevin Wolf 220ca94dbc7SKevin Wolf static int do_save_vmstate(char *buf, int64_t offset, int count, int *total) 221ca94dbc7SKevin Wolf { 222ca94dbc7SKevin Wolf *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count); 223ca94dbc7SKevin Wolf if (*total < 0) 224ca94dbc7SKevin Wolf return *total; 225ca94dbc7SKevin Wolf return 1; 226ca94dbc7SKevin Wolf } 227ca94dbc7SKevin Wolf 228e3aff4f6Saliguori #define NOT_DONE 0x7fffffff 229e3aff4f6Saliguori static void aio_rw_done(void *opaque, int ret) 230e3aff4f6Saliguori { 231e3aff4f6Saliguori *(int *)opaque = ret; 232e3aff4f6Saliguori } 233e3aff4f6Saliguori 234e3aff4f6Saliguori static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total) 235e3aff4f6Saliguori { 236e3aff4f6Saliguori BlockDriverAIOCB *acb; 237e3aff4f6Saliguori int async_ret = NOT_DONE; 238e3aff4f6Saliguori 239e3aff4f6Saliguori acb = bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9, 240e3aff4f6Saliguori aio_rw_done, &async_ret); 241e3aff4f6Saliguori if (!acb) 242e3aff4f6Saliguori return -EIO; 243e3aff4f6Saliguori 244e3aff4f6Saliguori while (async_ret == NOT_DONE) 245e3aff4f6Saliguori qemu_aio_wait(); 246e3aff4f6Saliguori 247e3aff4f6Saliguori *total = qiov->size; 248e3aff4f6Saliguori return async_ret < 0 ? async_ret : 1; 249e3aff4f6Saliguori } 250e3aff4f6Saliguori 251e3aff4f6Saliguori static int do_aio_writev(QEMUIOVector *qiov, int64_t offset, int *total) 252e3aff4f6Saliguori { 253e3aff4f6Saliguori BlockDriverAIOCB *acb; 254e3aff4f6Saliguori int async_ret = NOT_DONE; 255e3aff4f6Saliguori 256e3aff4f6Saliguori acb = bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9, 257e3aff4f6Saliguori aio_rw_done, &async_ret); 258e3aff4f6Saliguori if (!acb) 259e3aff4f6Saliguori return -EIO; 260e3aff4f6Saliguori 261e3aff4f6Saliguori while (async_ret == NOT_DONE) 262e3aff4f6Saliguori qemu_aio_wait(); 263e3aff4f6Saliguori 2647e9bbc9fSaliguori *total = qiov->size; 265e3aff4f6Saliguori return async_ret < 0 ? async_ret : 1; 266e3aff4f6Saliguori } 267e3aff4f6Saliguori 268e3aff4f6Saliguori 269e3aff4f6Saliguori static const cmdinfo_t read_cmd; 270e3aff4f6Saliguori 271e3aff4f6Saliguori static void 272e3aff4f6Saliguori read_help(void) 273e3aff4f6Saliguori { 274e3aff4f6Saliguori printf( 275e3aff4f6Saliguori "\n" 276e3aff4f6Saliguori " reads a range of bytes from the given offset\n" 277e3aff4f6Saliguori "\n" 278e3aff4f6Saliguori " Example:\n" 279e3aff4f6Saliguori " 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n" 280e3aff4f6Saliguori "\n" 281e3aff4f6Saliguori " Reads a segment of the currently open file, optionally dumping it to the\n" 282e3aff4f6Saliguori " standard output stream (with -v option) for subsequent inspection.\n" 283ca94dbc7SKevin Wolf " -b, -- read from the VM state rather than the virtual disk\n" 284d9654a58SKevin Wolf " -C, -- report statistics in a machine parsable format\n" 285d9654a58SKevin Wolf " -l, -- length for pattern verification (only with -P)\n" 286e3aff4f6Saliguori " -p, -- use bdrv_pread to read the file\n" 287c48101aeSaliguori " -P, -- use a pattern to verify read data\n" 288e3aff4f6Saliguori " -q, -- quite mode, do not show I/O statistics\n" 289d9654a58SKevin Wolf " -s, -- start offset for pattern verification (only with -P)\n" 290d9654a58SKevin Wolf " -v, -- dump buffer to standard output\n" 291e3aff4f6Saliguori "\n"); 292e3aff4f6Saliguori } 293e3aff4f6Saliguori 294e3aff4f6Saliguori static int 295e3aff4f6Saliguori read_f(int argc, char **argv) 296e3aff4f6Saliguori { 297e3aff4f6Saliguori struct timeval t1, t2; 298e3aff4f6Saliguori int Cflag = 0, pflag = 0, qflag = 0, vflag = 0; 299ca94dbc7SKevin Wolf int Pflag = 0, sflag = 0, lflag = 0, bflag = 0; 300e3aff4f6Saliguori int c, cnt; 301e3aff4f6Saliguori char *buf; 302e3aff4f6Saliguori int64_t offset; 303d4ec5228SPaul Brook int count; 304d4ec5228SPaul Brook /* Some compilers get confused and warn if this is not initialized. */ 305d4ec5228SPaul Brook int total = 0; 306d9654a58SKevin Wolf int pattern = 0, pattern_offset = 0, pattern_count = 0; 307e3aff4f6Saliguori 308ca94dbc7SKevin Wolf while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != EOF) { 309e3aff4f6Saliguori switch (c) { 310ca94dbc7SKevin Wolf case 'b': 311ca94dbc7SKevin Wolf bflag = 1; 312ca94dbc7SKevin Wolf break; 313e3aff4f6Saliguori case 'C': 314e3aff4f6Saliguori Cflag = 1; 315e3aff4f6Saliguori break; 316d9654a58SKevin Wolf case 'l': 317d9654a58SKevin Wolf lflag = 1; 318d9654a58SKevin Wolf pattern_count = cvtnum(optarg); 319d9654a58SKevin Wolf if (pattern_count < 0) { 320d9654a58SKevin Wolf printf("non-numeric length argument -- %s\n", optarg); 321d9654a58SKevin Wolf return 0; 322d9654a58SKevin Wolf } 323d9654a58SKevin Wolf break; 324e3aff4f6Saliguori case 'p': 325e3aff4f6Saliguori pflag = 1; 326e3aff4f6Saliguori break; 327c48101aeSaliguori case 'P': 328c48101aeSaliguori Pflag = 1; 329cf070d7eSChristoph Hellwig pattern = parse_pattern(optarg); 330cf070d7eSChristoph Hellwig if (pattern < 0) 331cf070d7eSChristoph Hellwig return 0; 332c48101aeSaliguori break; 333e3aff4f6Saliguori case 'q': 334e3aff4f6Saliguori qflag = 1; 335e3aff4f6Saliguori break; 336d9654a58SKevin Wolf case 's': 337d9654a58SKevin Wolf sflag = 1; 338d9654a58SKevin Wolf pattern_offset = cvtnum(optarg); 339d9654a58SKevin Wolf if (pattern_offset < 0) { 340d9654a58SKevin Wolf printf("non-numeric length argument -- %s\n", optarg); 341d9654a58SKevin Wolf return 0; 342d9654a58SKevin Wolf } 343d9654a58SKevin Wolf break; 344e3aff4f6Saliguori case 'v': 345e3aff4f6Saliguori vflag = 1; 346e3aff4f6Saliguori break; 347e3aff4f6Saliguori default: 348e3aff4f6Saliguori return command_usage(&read_cmd); 349e3aff4f6Saliguori } 350e3aff4f6Saliguori } 351e3aff4f6Saliguori 352e3aff4f6Saliguori if (optind != argc - 2) 353e3aff4f6Saliguori return command_usage(&read_cmd); 354e3aff4f6Saliguori 355ca94dbc7SKevin Wolf if (bflag && pflag) { 356ca94dbc7SKevin Wolf printf("-b and -p cannot be specified at the same time\n"); 357ca94dbc7SKevin Wolf return 0; 358ca94dbc7SKevin Wolf } 359ca94dbc7SKevin Wolf 360e3aff4f6Saliguori offset = cvtnum(argv[optind]); 361e3aff4f6Saliguori if (offset < 0) { 362e3aff4f6Saliguori printf("non-numeric length argument -- %s\n", argv[optind]); 363e3aff4f6Saliguori return 0; 364e3aff4f6Saliguori } 365e3aff4f6Saliguori 366e3aff4f6Saliguori optind++; 367e3aff4f6Saliguori count = cvtnum(argv[optind]); 368e3aff4f6Saliguori if (count < 0) { 369e3aff4f6Saliguori printf("non-numeric length argument -- %s\n", argv[optind]); 370e3aff4f6Saliguori return 0; 371e3aff4f6Saliguori } 372e3aff4f6Saliguori 373d9654a58SKevin Wolf if (!Pflag && (lflag || sflag)) { 374d9654a58SKevin Wolf return command_usage(&read_cmd); 375d9654a58SKevin Wolf } 376d9654a58SKevin Wolf 377d9654a58SKevin Wolf if (!lflag) { 378d9654a58SKevin Wolf pattern_count = count - pattern_offset; 379d9654a58SKevin Wolf } 380d9654a58SKevin Wolf 381d9654a58SKevin Wolf if ((pattern_count < 0) || (pattern_count + pattern_offset > count)) { 382d9654a58SKevin Wolf printf("pattern verfication range exceeds end of read data\n"); 383d9654a58SKevin Wolf return 0; 384d9654a58SKevin Wolf } 385d9654a58SKevin Wolf 386e3aff4f6Saliguori if (!pflag) 387e3aff4f6Saliguori if (offset & 0x1ff) { 388e3aff4f6Saliguori printf("offset %lld is not sector aligned\n", 389e3aff4f6Saliguori (long long)offset); 390e3aff4f6Saliguori return 0; 391e3aff4f6Saliguori 392e3aff4f6Saliguori if (count & 0x1ff) { 393e3aff4f6Saliguori printf("count %d is not sector aligned\n", 394e3aff4f6Saliguori count); 395e3aff4f6Saliguori return 0; 396e3aff4f6Saliguori } 397e3aff4f6Saliguori } 398e3aff4f6Saliguori 399e3aff4f6Saliguori buf = qemu_io_alloc(count, 0xab); 400e3aff4f6Saliguori 401e3aff4f6Saliguori gettimeofday(&t1, NULL); 402e3aff4f6Saliguori if (pflag) 403e3aff4f6Saliguori cnt = do_pread(buf, offset, count, &total); 404ca94dbc7SKevin Wolf else if (bflag) 405ca94dbc7SKevin Wolf cnt = do_load_vmstate(buf, offset, count, &total); 406e3aff4f6Saliguori else 407e3aff4f6Saliguori cnt = do_read(buf, offset, count, &total); 408e3aff4f6Saliguori gettimeofday(&t2, NULL); 409e3aff4f6Saliguori 410e3aff4f6Saliguori if (cnt < 0) { 411e3aff4f6Saliguori printf("read failed: %s\n", strerror(-cnt)); 4127d8abfcbSKevin Wolf goto out; 413e3aff4f6Saliguori } 414e3aff4f6Saliguori 415c48101aeSaliguori if (Pflag) { 416d9654a58SKevin Wolf void* cmp_buf = malloc(pattern_count); 417d9654a58SKevin Wolf memset(cmp_buf, pattern, pattern_count); 418d9654a58SKevin Wolf if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) { 419c48101aeSaliguori printf("Pattern verification failed at offset %lld, " 420c48101aeSaliguori "%d bytes\n", 421d9654a58SKevin Wolf (long long) offset + pattern_offset, pattern_count); 422c48101aeSaliguori } 423c48101aeSaliguori free(cmp_buf); 424c48101aeSaliguori } 425c48101aeSaliguori 426e3aff4f6Saliguori if (qflag) 4277d8abfcbSKevin Wolf goto out; 428e3aff4f6Saliguori 429e3aff4f6Saliguori if (vflag) 430e3aff4f6Saliguori dump_buffer(buf, offset, count); 431e3aff4f6Saliguori 432e3aff4f6Saliguori /* Finally, report back -- -C gives a parsable format */ 433e3aff4f6Saliguori t2 = tsub(t2, t1); 434e3aff4f6Saliguori print_report("read", &t2, offset, count, total, cnt, Cflag); 435e3aff4f6Saliguori 4367d8abfcbSKevin Wolf out: 437e3aff4f6Saliguori qemu_io_free(buf); 438e3aff4f6Saliguori 439e3aff4f6Saliguori return 0; 440e3aff4f6Saliguori } 441e3aff4f6Saliguori 442e3aff4f6Saliguori static const cmdinfo_t read_cmd = { 443e3aff4f6Saliguori .name = "read", 444e3aff4f6Saliguori .altname = "r", 445e3aff4f6Saliguori .cfunc = read_f, 446e3aff4f6Saliguori .argmin = 2, 447e3aff4f6Saliguori .argmax = -1, 448ca94dbc7SKevin Wolf .args = "[-abCpqv] [-P pattern [-s off] [-l len]] off len", 449e3aff4f6Saliguori .oneline = "reads a number of bytes at a specified offset", 450e3aff4f6Saliguori .help = read_help, 451e3aff4f6Saliguori }; 452e3aff4f6Saliguori 453e3aff4f6Saliguori static const cmdinfo_t readv_cmd; 454e3aff4f6Saliguori 455e3aff4f6Saliguori static void 456e3aff4f6Saliguori readv_help(void) 457e3aff4f6Saliguori { 458e3aff4f6Saliguori printf( 459e3aff4f6Saliguori "\n" 460e3aff4f6Saliguori " reads a range of bytes from the given offset into multiple buffers\n" 461e3aff4f6Saliguori "\n" 462e3aff4f6Saliguori " Example:\n" 463e3aff4f6Saliguori " 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n" 464e3aff4f6Saliguori "\n" 465e3aff4f6Saliguori " Reads a segment of the currently open file, optionally dumping it to the\n" 466e3aff4f6Saliguori " standard output stream (with -v option) for subsequent inspection.\n" 467e3aff4f6Saliguori " Uses multiple iovec buffers if more than one byte range is specified.\n" 468e3aff4f6Saliguori " -C, -- report statistics in a machine parsable format\n" 469c48101aeSaliguori " -P, -- use a pattern to verify read data\n" 470e3aff4f6Saliguori " -v, -- dump buffer to standard output\n" 471e3aff4f6Saliguori " -q, -- quite mode, do not show I/O statistics\n" 472e3aff4f6Saliguori "\n"); 473e3aff4f6Saliguori } 474e3aff4f6Saliguori 475e3aff4f6Saliguori static int 476e3aff4f6Saliguori readv_f(int argc, char **argv) 477e3aff4f6Saliguori { 478e3aff4f6Saliguori struct timeval t1, t2; 479e3aff4f6Saliguori int Cflag = 0, qflag = 0, vflag = 0; 480e3aff4f6Saliguori int c, cnt; 481cf57298aSChristoph Hellwig char *buf; 482e3aff4f6Saliguori int64_t offset; 483cf57298aSChristoph Hellwig int total; 484cf57298aSChristoph Hellwig int nr_iov; 485e3aff4f6Saliguori QEMUIOVector qiov; 486c48101aeSaliguori int pattern = 0; 487c48101aeSaliguori int Pflag = 0; 488e3aff4f6Saliguori 489c48101aeSaliguori while ((c = getopt(argc, argv, "CP:qv")) != EOF) { 490e3aff4f6Saliguori switch (c) { 491e3aff4f6Saliguori case 'C': 492e3aff4f6Saliguori Cflag = 1; 493e3aff4f6Saliguori break; 494c48101aeSaliguori case 'P': 495c48101aeSaliguori Pflag = 1; 496cf070d7eSChristoph Hellwig pattern = parse_pattern(optarg); 497cf070d7eSChristoph Hellwig if (pattern < 0) 498cf070d7eSChristoph Hellwig return 0; 499c48101aeSaliguori break; 500e3aff4f6Saliguori case 'q': 501e3aff4f6Saliguori qflag = 1; 502e3aff4f6Saliguori break; 503e3aff4f6Saliguori case 'v': 504e3aff4f6Saliguori vflag = 1; 505e3aff4f6Saliguori break; 506e3aff4f6Saliguori default: 507e3aff4f6Saliguori return command_usage(&readv_cmd); 508e3aff4f6Saliguori } 509e3aff4f6Saliguori } 510e3aff4f6Saliguori 511e3aff4f6Saliguori if (optind > argc - 2) 512e3aff4f6Saliguori return command_usage(&readv_cmd); 513e3aff4f6Saliguori 514e3aff4f6Saliguori 515e3aff4f6Saliguori offset = cvtnum(argv[optind]); 516e3aff4f6Saliguori if (offset < 0) { 517e3aff4f6Saliguori printf("non-numeric length argument -- %s\n", argv[optind]); 518e3aff4f6Saliguori return 0; 519e3aff4f6Saliguori } 520e3aff4f6Saliguori optind++; 521e3aff4f6Saliguori 522e3aff4f6Saliguori if (offset & 0x1ff) { 523e3aff4f6Saliguori printf("offset %lld is not sector aligned\n", 524e3aff4f6Saliguori (long long)offset); 525e3aff4f6Saliguori return 0; 526e3aff4f6Saliguori } 527e3aff4f6Saliguori 528e3aff4f6Saliguori nr_iov = argc - optind; 529cf57298aSChristoph Hellwig buf = create_iovec(&qiov, &argv[optind], nr_iov, 0xab); 530e3aff4f6Saliguori 531e3aff4f6Saliguori gettimeofday(&t1, NULL); 532e3aff4f6Saliguori cnt = do_aio_readv(&qiov, offset, &total); 533e3aff4f6Saliguori gettimeofday(&t2, NULL); 534e3aff4f6Saliguori 535e3aff4f6Saliguori if (cnt < 0) { 536e3aff4f6Saliguori printf("readv failed: %s\n", strerror(-cnt)); 5377d8abfcbSKevin Wolf goto out; 538e3aff4f6Saliguori } 539e3aff4f6Saliguori 540c48101aeSaliguori if (Pflag) { 541cf57298aSChristoph Hellwig void* cmp_buf = malloc(qiov.size); 542cf57298aSChristoph Hellwig memset(cmp_buf, pattern, qiov.size); 543cf57298aSChristoph Hellwig if (memcmp(buf, cmp_buf, qiov.size)) { 544c48101aeSaliguori printf("Pattern verification failed at offset %lld, " 545cf57298aSChristoph Hellwig "%zd bytes\n", 546cf57298aSChristoph Hellwig (long long) offset, qiov.size); 547c48101aeSaliguori } 548c48101aeSaliguori free(cmp_buf); 549c48101aeSaliguori } 550c48101aeSaliguori 551e3aff4f6Saliguori if (qflag) 5527d8abfcbSKevin Wolf goto out; 553e3aff4f6Saliguori 554e3aff4f6Saliguori if (vflag) 555e3aff4f6Saliguori dump_buffer(buf, offset, qiov.size); 556e3aff4f6Saliguori 557e3aff4f6Saliguori /* Finally, report back -- -C gives a parsable format */ 558e3aff4f6Saliguori t2 = tsub(t2, t1); 559e3aff4f6Saliguori print_report("read", &t2, offset, qiov.size, total, cnt, Cflag); 560e3aff4f6Saliguori 5617d8abfcbSKevin Wolf out: 562e3aff4f6Saliguori qemu_io_free(buf); 563e3aff4f6Saliguori return 0; 564e3aff4f6Saliguori } 565e3aff4f6Saliguori 566e3aff4f6Saliguori static const cmdinfo_t readv_cmd = { 567e3aff4f6Saliguori .name = "readv", 568e3aff4f6Saliguori .cfunc = readv_f, 569e3aff4f6Saliguori .argmin = 2, 570e3aff4f6Saliguori .argmax = -1, 571c48101aeSaliguori .args = "[-Cqv] [-P pattern ] off len [len..]", 572e3aff4f6Saliguori .oneline = "reads a number of bytes at a specified offset", 573e3aff4f6Saliguori .help = readv_help, 574e3aff4f6Saliguori }; 575e3aff4f6Saliguori 576e3aff4f6Saliguori static const cmdinfo_t write_cmd; 577e3aff4f6Saliguori 578e3aff4f6Saliguori static void 579e3aff4f6Saliguori write_help(void) 580e3aff4f6Saliguori { 581e3aff4f6Saliguori printf( 582e3aff4f6Saliguori "\n" 583e3aff4f6Saliguori " writes a range of bytes from the given offset\n" 584e3aff4f6Saliguori "\n" 585e3aff4f6Saliguori " Example:\n" 586e3aff4f6Saliguori " 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n" 587e3aff4f6Saliguori "\n" 588e3aff4f6Saliguori " Writes into a segment of the currently open file, using a buffer\n" 589e3aff4f6Saliguori " filled with a set pattern (0xcdcdcdcd).\n" 590ca94dbc7SKevin Wolf " -b, -- write to the VM state rather than the virtual disk\n" 591e3aff4f6Saliguori " -p, -- use bdrv_pwrite to write the file\n" 592e3aff4f6Saliguori " -P, -- use different pattern to fill file\n" 593e3aff4f6Saliguori " -C, -- report statistics in a machine parsable format\n" 594e3aff4f6Saliguori " -q, -- quite mode, do not show I/O statistics\n" 595e3aff4f6Saliguori "\n"); 596e3aff4f6Saliguori } 597e3aff4f6Saliguori 598e3aff4f6Saliguori static int 599e3aff4f6Saliguori write_f(int argc, char **argv) 600e3aff4f6Saliguori { 601e3aff4f6Saliguori struct timeval t1, t2; 602ca94dbc7SKevin Wolf int Cflag = 0, pflag = 0, qflag = 0, bflag = 0; 603e3aff4f6Saliguori int c, cnt; 604e3aff4f6Saliguori char *buf; 605e3aff4f6Saliguori int64_t offset; 606d4ec5228SPaul Brook int count; 607d4ec5228SPaul Brook /* Some compilers get confused and warn if this is not initialized. */ 608d4ec5228SPaul Brook int total = 0; 609e3aff4f6Saliguori int pattern = 0xcd; 610e3aff4f6Saliguori 611ca94dbc7SKevin Wolf while ((c = getopt(argc, argv, "bCpP:q")) != EOF) { 612e3aff4f6Saliguori switch (c) { 613ca94dbc7SKevin Wolf case 'b': 614ca94dbc7SKevin Wolf bflag = 1; 615ca94dbc7SKevin Wolf break; 616e3aff4f6Saliguori case 'C': 617e3aff4f6Saliguori Cflag = 1; 618e3aff4f6Saliguori break; 619e3aff4f6Saliguori case 'p': 620e3aff4f6Saliguori pflag = 1; 621e3aff4f6Saliguori break; 622e3aff4f6Saliguori case 'P': 623cf070d7eSChristoph Hellwig pattern = parse_pattern(optarg); 624cf070d7eSChristoph Hellwig if (pattern < 0) 625cf070d7eSChristoph Hellwig return 0; 626e3aff4f6Saliguori break; 627e3aff4f6Saliguori case 'q': 628e3aff4f6Saliguori qflag = 1; 629e3aff4f6Saliguori break; 630e3aff4f6Saliguori default: 631e3aff4f6Saliguori return command_usage(&write_cmd); 632e3aff4f6Saliguori } 633e3aff4f6Saliguori } 634e3aff4f6Saliguori 635e3aff4f6Saliguori if (optind != argc - 2) 636e3aff4f6Saliguori return command_usage(&write_cmd); 637e3aff4f6Saliguori 638ca94dbc7SKevin Wolf if (bflag && pflag) { 639ca94dbc7SKevin Wolf printf("-b and -p cannot be specified at the same time\n"); 640ca94dbc7SKevin Wolf return 0; 641ca94dbc7SKevin Wolf } 642ca94dbc7SKevin Wolf 643e3aff4f6Saliguori offset = cvtnum(argv[optind]); 644e3aff4f6Saliguori if (offset < 0) { 645e3aff4f6Saliguori printf("non-numeric length argument -- %s\n", argv[optind]); 646e3aff4f6Saliguori return 0; 647e3aff4f6Saliguori } 648e3aff4f6Saliguori 649e3aff4f6Saliguori optind++; 650e3aff4f6Saliguori count = cvtnum(argv[optind]); 651e3aff4f6Saliguori if (count < 0) { 652e3aff4f6Saliguori printf("non-numeric length argument -- %s\n", argv[optind]); 653e3aff4f6Saliguori return 0; 654e3aff4f6Saliguori } 655e3aff4f6Saliguori 656e3aff4f6Saliguori if (!pflag) { 657e3aff4f6Saliguori if (offset & 0x1ff) { 658e3aff4f6Saliguori printf("offset %lld is not sector aligned\n", 659e3aff4f6Saliguori (long long)offset); 660e3aff4f6Saliguori return 0; 661e3aff4f6Saliguori } 662e3aff4f6Saliguori 663e3aff4f6Saliguori if (count & 0x1ff) { 664e3aff4f6Saliguori printf("count %d is not sector aligned\n", 665e3aff4f6Saliguori count); 666e3aff4f6Saliguori return 0; 667e3aff4f6Saliguori } 668e3aff4f6Saliguori } 669e3aff4f6Saliguori 670e3aff4f6Saliguori buf = qemu_io_alloc(count, pattern); 671e3aff4f6Saliguori 672e3aff4f6Saliguori gettimeofday(&t1, NULL); 673e3aff4f6Saliguori if (pflag) 674e3aff4f6Saliguori cnt = do_pwrite(buf, offset, count, &total); 675ca94dbc7SKevin Wolf else if (bflag) 676ca94dbc7SKevin Wolf cnt = do_save_vmstate(buf, offset, count, &total); 677e3aff4f6Saliguori else 678e3aff4f6Saliguori cnt = do_write(buf, offset, count, &total); 679e3aff4f6Saliguori gettimeofday(&t2, NULL); 680e3aff4f6Saliguori 681e3aff4f6Saliguori if (cnt < 0) { 682e3aff4f6Saliguori printf("write failed: %s\n", strerror(-cnt)); 6837d8abfcbSKevin Wolf goto out; 684e3aff4f6Saliguori } 685e3aff4f6Saliguori 686e3aff4f6Saliguori if (qflag) 6877d8abfcbSKevin Wolf goto out; 688e3aff4f6Saliguori 689e3aff4f6Saliguori /* Finally, report back -- -C gives a parsable format */ 690e3aff4f6Saliguori t2 = tsub(t2, t1); 691e3aff4f6Saliguori print_report("wrote", &t2, offset, count, total, cnt, Cflag); 692e3aff4f6Saliguori 6937d8abfcbSKevin Wolf out: 694e3aff4f6Saliguori qemu_io_free(buf); 695e3aff4f6Saliguori 696e3aff4f6Saliguori return 0; 697e3aff4f6Saliguori } 698e3aff4f6Saliguori 699e3aff4f6Saliguori static const cmdinfo_t write_cmd = { 700e3aff4f6Saliguori .name = "write", 701e3aff4f6Saliguori .altname = "w", 702e3aff4f6Saliguori .cfunc = write_f, 703e3aff4f6Saliguori .argmin = 2, 704e3aff4f6Saliguori .argmax = -1, 705ca94dbc7SKevin Wolf .args = "[-abCpq] [-P pattern ] off len", 706e3aff4f6Saliguori .oneline = "writes a number of bytes at a specified offset", 707e3aff4f6Saliguori .help = write_help, 708e3aff4f6Saliguori }; 709e3aff4f6Saliguori 710e3aff4f6Saliguori static const cmdinfo_t writev_cmd; 711e3aff4f6Saliguori 712e3aff4f6Saliguori static void 713e3aff4f6Saliguori writev_help(void) 714e3aff4f6Saliguori { 715e3aff4f6Saliguori printf( 716e3aff4f6Saliguori "\n" 717e3aff4f6Saliguori " writes a range of bytes from the given offset source from multiple buffers\n" 718e3aff4f6Saliguori "\n" 719e3aff4f6Saliguori " Example:\n" 720e3aff4f6Saliguori " 'write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n" 721e3aff4f6Saliguori "\n" 722e3aff4f6Saliguori " Writes into a segment of the currently open file, using a buffer\n" 723e3aff4f6Saliguori " filled with a set pattern (0xcdcdcdcd).\n" 724e3aff4f6Saliguori " -P, -- use different pattern to fill file\n" 725e3aff4f6Saliguori " -C, -- report statistics in a machine parsable format\n" 726e3aff4f6Saliguori " -q, -- quite mode, do not show I/O statistics\n" 727e3aff4f6Saliguori "\n"); 728e3aff4f6Saliguori } 729e3aff4f6Saliguori 730e3aff4f6Saliguori static int 731e3aff4f6Saliguori writev_f(int argc, char **argv) 732e3aff4f6Saliguori { 733e3aff4f6Saliguori struct timeval t1, t2; 734e3aff4f6Saliguori int Cflag = 0, qflag = 0; 735e3aff4f6Saliguori int c, cnt; 736cf57298aSChristoph Hellwig char *buf; 737e3aff4f6Saliguori int64_t offset; 738cf57298aSChristoph Hellwig int total; 739cf57298aSChristoph Hellwig int nr_iov; 740e3aff4f6Saliguori int pattern = 0xcd; 741e3aff4f6Saliguori QEMUIOVector qiov; 742e3aff4f6Saliguori 743e3aff4f6Saliguori while ((c = getopt(argc, argv, "CqP:")) != EOF) { 744e3aff4f6Saliguori switch (c) { 745e3aff4f6Saliguori case 'C': 746e3aff4f6Saliguori Cflag = 1; 747e3aff4f6Saliguori break; 748e3aff4f6Saliguori case 'q': 749e3aff4f6Saliguori qflag = 1; 750e3aff4f6Saliguori break; 751e3aff4f6Saliguori case 'P': 752cf070d7eSChristoph Hellwig pattern = parse_pattern(optarg); 753cf070d7eSChristoph Hellwig if (pattern < 0) 754cf070d7eSChristoph Hellwig return 0; 755e3aff4f6Saliguori break; 756e3aff4f6Saliguori default: 757e3aff4f6Saliguori return command_usage(&writev_cmd); 758e3aff4f6Saliguori } 759e3aff4f6Saliguori } 760e3aff4f6Saliguori 761e3aff4f6Saliguori if (optind > argc - 2) 762e3aff4f6Saliguori return command_usage(&writev_cmd); 763e3aff4f6Saliguori 764e3aff4f6Saliguori offset = cvtnum(argv[optind]); 765e3aff4f6Saliguori if (offset < 0) { 766e3aff4f6Saliguori printf("non-numeric length argument -- %s\n", argv[optind]); 767e3aff4f6Saliguori return 0; 768e3aff4f6Saliguori } 769e3aff4f6Saliguori optind++; 770e3aff4f6Saliguori 771e3aff4f6Saliguori if (offset & 0x1ff) { 772e3aff4f6Saliguori printf("offset %lld is not sector aligned\n", 773e3aff4f6Saliguori (long long)offset); 774e3aff4f6Saliguori return 0; 775e3aff4f6Saliguori } 776e3aff4f6Saliguori 777e3aff4f6Saliguori nr_iov = argc - optind; 778cf57298aSChristoph Hellwig buf = create_iovec(&qiov, &argv[optind], nr_iov, pattern); 779e3aff4f6Saliguori 780e3aff4f6Saliguori gettimeofday(&t1, NULL); 781e3aff4f6Saliguori cnt = do_aio_writev(&qiov, offset, &total); 782e3aff4f6Saliguori gettimeofday(&t2, NULL); 783e3aff4f6Saliguori 784e3aff4f6Saliguori if (cnt < 0) { 785e3aff4f6Saliguori printf("writev failed: %s\n", strerror(-cnt)); 7867d8abfcbSKevin Wolf goto out; 787e3aff4f6Saliguori } 788e3aff4f6Saliguori 789e3aff4f6Saliguori if (qflag) 7907d8abfcbSKevin Wolf goto out; 791e3aff4f6Saliguori 792e3aff4f6Saliguori /* Finally, report back -- -C gives a parsable format */ 793e3aff4f6Saliguori t2 = tsub(t2, t1); 794e3aff4f6Saliguori print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag); 7957d8abfcbSKevin Wolf out: 796e3aff4f6Saliguori qemu_io_free(buf); 797e3aff4f6Saliguori return 0; 798e3aff4f6Saliguori } 799e3aff4f6Saliguori 800e3aff4f6Saliguori static const cmdinfo_t writev_cmd = { 801e3aff4f6Saliguori .name = "writev", 802e3aff4f6Saliguori .cfunc = writev_f, 803e3aff4f6Saliguori .argmin = 2, 804e3aff4f6Saliguori .argmax = -1, 805e3aff4f6Saliguori .args = "[-Cq] [-P pattern ] off len [len..]", 806e3aff4f6Saliguori .oneline = "writes a number of bytes at a specified offset", 807e3aff4f6Saliguori .help = writev_help, 808e3aff4f6Saliguori }; 809e3aff4f6Saliguori 81095533d5fSChristoph Hellwig struct aio_ctx { 81195533d5fSChristoph Hellwig QEMUIOVector qiov; 81295533d5fSChristoph Hellwig int64_t offset; 81395533d5fSChristoph Hellwig char *buf; 81495533d5fSChristoph Hellwig int qflag; 81595533d5fSChristoph Hellwig int vflag; 81695533d5fSChristoph Hellwig int Cflag; 81795533d5fSChristoph Hellwig int Pflag; 81895533d5fSChristoph Hellwig int pattern; 81995533d5fSChristoph Hellwig struct timeval t1; 82095533d5fSChristoph Hellwig }; 82195533d5fSChristoph Hellwig 82295533d5fSChristoph Hellwig static void 82395533d5fSChristoph Hellwig aio_write_done(void *opaque, int ret) 82495533d5fSChristoph Hellwig { 82595533d5fSChristoph Hellwig struct aio_ctx *ctx = opaque; 82695533d5fSChristoph Hellwig struct timeval t2; 82795533d5fSChristoph Hellwig 82895533d5fSChristoph Hellwig gettimeofday(&t2, NULL); 82995533d5fSChristoph Hellwig 83095533d5fSChristoph Hellwig 83195533d5fSChristoph Hellwig if (ret < 0) { 83295533d5fSChristoph Hellwig printf("aio_write failed: %s\n", strerror(-ret)); 8337d8abfcbSKevin Wolf goto out; 83495533d5fSChristoph Hellwig } 83595533d5fSChristoph Hellwig 836230d4fa4SChristoph Hellwig if (ctx->qflag) { 8377d8abfcbSKevin Wolf goto out; 838230d4fa4SChristoph Hellwig } 83995533d5fSChristoph Hellwig 84095533d5fSChristoph Hellwig /* Finally, report back -- -C gives a parsable format */ 84195533d5fSChristoph Hellwig t2 = tsub(t2, ctx->t1); 842230d4fa4SChristoph Hellwig print_report("wrote", &t2, ctx->offset, ctx->qiov.size, 843230d4fa4SChristoph Hellwig ctx->qiov.size, 1, ctx->Cflag); 8447d8abfcbSKevin Wolf out: 84595533d5fSChristoph Hellwig qemu_io_free(ctx->buf); 84695533d5fSChristoph Hellwig free(ctx); 84795533d5fSChristoph Hellwig } 84895533d5fSChristoph Hellwig 84995533d5fSChristoph Hellwig static const cmdinfo_t aio_read_cmd; 85095533d5fSChristoph Hellwig 85195533d5fSChristoph Hellwig static void 85295533d5fSChristoph Hellwig aio_read_done(void *opaque, int ret) 85395533d5fSChristoph Hellwig { 85495533d5fSChristoph Hellwig struct aio_ctx *ctx = opaque; 85595533d5fSChristoph Hellwig struct timeval t2; 85695533d5fSChristoph Hellwig 85795533d5fSChristoph Hellwig gettimeofday(&t2, NULL); 85895533d5fSChristoph Hellwig 85995533d5fSChristoph Hellwig if (ret < 0) { 86095533d5fSChristoph Hellwig printf("readv failed: %s\n", strerror(-ret)); 8617d8abfcbSKevin Wolf goto out; 86295533d5fSChristoph Hellwig } 86395533d5fSChristoph Hellwig 86495533d5fSChristoph Hellwig if (ctx->Pflag) { 865230d4fa4SChristoph Hellwig void *cmp_buf = malloc(ctx->qiov.size); 86695533d5fSChristoph Hellwig 867230d4fa4SChristoph Hellwig memset(cmp_buf, ctx->pattern, ctx->qiov.size); 868230d4fa4SChristoph Hellwig if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) { 86995533d5fSChristoph Hellwig printf("Pattern verification failed at offset %lld, " 870230d4fa4SChristoph Hellwig "%zd bytes\n", 871230d4fa4SChristoph Hellwig (long long) ctx->offset, ctx->qiov.size); 87295533d5fSChristoph Hellwig } 87395533d5fSChristoph Hellwig free(cmp_buf); 87495533d5fSChristoph Hellwig } 87595533d5fSChristoph Hellwig 876230d4fa4SChristoph Hellwig if (ctx->qflag) { 8777d8abfcbSKevin Wolf goto out; 878230d4fa4SChristoph Hellwig } 87995533d5fSChristoph Hellwig 880230d4fa4SChristoph Hellwig if (ctx->vflag) { 881230d4fa4SChristoph Hellwig dump_buffer(ctx->buf, ctx->offset, ctx->qiov.size); 882230d4fa4SChristoph Hellwig } 88395533d5fSChristoph Hellwig 88495533d5fSChristoph Hellwig /* Finally, report back -- -C gives a parsable format */ 88595533d5fSChristoph Hellwig t2 = tsub(t2, ctx->t1); 886230d4fa4SChristoph Hellwig print_report("read", &t2, ctx->offset, ctx->qiov.size, 887230d4fa4SChristoph Hellwig ctx->qiov.size, 1, ctx->Cflag); 8887d8abfcbSKevin Wolf out: 88995533d5fSChristoph Hellwig qemu_io_free(ctx->buf); 89095533d5fSChristoph Hellwig free(ctx); 89195533d5fSChristoph Hellwig } 89295533d5fSChristoph Hellwig 89395533d5fSChristoph Hellwig static void 89495533d5fSChristoph Hellwig aio_read_help(void) 89595533d5fSChristoph Hellwig { 89695533d5fSChristoph Hellwig printf( 89795533d5fSChristoph Hellwig "\n" 89895533d5fSChristoph Hellwig " asynchronously reads a range of bytes from the given offset\n" 89995533d5fSChristoph Hellwig "\n" 90095533d5fSChristoph Hellwig " Example:\n" 90195533d5fSChristoph Hellwig " 'aio_read -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n" 90295533d5fSChristoph Hellwig "\n" 90395533d5fSChristoph Hellwig " Reads a segment of the currently open file, optionally dumping it to the\n" 90495533d5fSChristoph Hellwig " standard output stream (with -v option) for subsequent inspection.\n" 90595533d5fSChristoph Hellwig " The read is performed asynchronously and should the aio_flush command \n" 90695533d5fSChristoph Hellwig " should be used to ensure all outstanding aio requests have been completed\n" 90795533d5fSChristoph Hellwig " -C, -- report statistics in a machine parsable format\n" 90895533d5fSChristoph Hellwig " -P, -- use a pattern to verify read data\n" 90995533d5fSChristoph Hellwig " -v, -- dump buffer to standard output\n" 91095533d5fSChristoph Hellwig " -q, -- quite mode, do not show I/O statistics\n" 91195533d5fSChristoph Hellwig "\n"); 91295533d5fSChristoph Hellwig } 91395533d5fSChristoph Hellwig 91495533d5fSChristoph Hellwig static int 91595533d5fSChristoph Hellwig aio_read_f(int argc, char **argv) 91695533d5fSChristoph Hellwig { 917cf57298aSChristoph Hellwig int nr_iov, c; 91895533d5fSChristoph Hellwig struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx)); 91995533d5fSChristoph Hellwig BlockDriverAIOCB *acb; 92095533d5fSChristoph Hellwig 92195533d5fSChristoph Hellwig while ((c = getopt(argc, argv, "CP:qv")) != EOF) { 92295533d5fSChristoph Hellwig switch (c) { 92395533d5fSChristoph Hellwig case 'C': 92495533d5fSChristoph Hellwig ctx->Cflag = 1; 92595533d5fSChristoph Hellwig break; 92695533d5fSChristoph Hellwig case 'P': 92795533d5fSChristoph Hellwig ctx->Pflag = 1; 928cf070d7eSChristoph Hellwig ctx->pattern = parse_pattern(optarg); 929cf070d7eSChristoph Hellwig if (ctx->pattern < 0) 930cf070d7eSChristoph Hellwig return 0; 93195533d5fSChristoph Hellwig break; 93295533d5fSChristoph Hellwig case 'q': 93395533d5fSChristoph Hellwig ctx->qflag = 1; 93495533d5fSChristoph Hellwig break; 93595533d5fSChristoph Hellwig case 'v': 93695533d5fSChristoph Hellwig ctx->vflag = 1; 93795533d5fSChristoph Hellwig break; 93895533d5fSChristoph Hellwig default: 9397d8abfcbSKevin Wolf free(ctx); 94095533d5fSChristoph Hellwig return command_usage(&aio_read_cmd); 94195533d5fSChristoph Hellwig } 94295533d5fSChristoph Hellwig } 94395533d5fSChristoph Hellwig 9447d8abfcbSKevin Wolf if (optind > argc - 2) { 9457d8abfcbSKevin Wolf free(ctx); 94695533d5fSChristoph Hellwig return command_usage(&aio_read_cmd); 9477d8abfcbSKevin Wolf } 94895533d5fSChristoph Hellwig 94995533d5fSChristoph Hellwig ctx->offset = cvtnum(argv[optind]); 95095533d5fSChristoph Hellwig if (ctx->offset < 0) { 95195533d5fSChristoph Hellwig printf("non-numeric length argument -- %s\n", argv[optind]); 9527d8abfcbSKevin Wolf free(ctx); 95395533d5fSChristoph Hellwig return 0; 95495533d5fSChristoph Hellwig } 95595533d5fSChristoph Hellwig optind++; 95695533d5fSChristoph Hellwig 95795533d5fSChristoph Hellwig if (ctx->offset & 0x1ff) { 95895533d5fSChristoph Hellwig printf("offset %lld is not sector aligned\n", 95995533d5fSChristoph Hellwig (long long)ctx->offset); 9607d8abfcbSKevin Wolf free(ctx); 96195533d5fSChristoph Hellwig return 0; 96295533d5fSChristoph Hellwig } 96395533d5fSChristoph Hellwig 96495533d5fSChristoph Hellwig nr_iov = argc - optind; 965cf57298aSChristoph Hellwig ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, 0xab); 96695533d5fSChristoph Hellwig 96795533d5fSChristoph Hellwig gettimeofday(&ctx->t1, NULL); 96895533d5fSChristoph Hellwig acb = bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov, 96995533d5fSChristoph Hellwig ctx->qiov.size >> 9, aio_read_done, ctx); 9707d8abfcbSKevin Wolf if (!acb) { 9717d8abfcbSKevin Wolf free(ctx->buf); 9727d8abfcbSKevin Wolf free(ctx); 97395533d5fSChristoph Hellwig return -EIO; 9747d8abfcbSKevin Wolf } 97595533d5fSChristoph Hellwig 97695533d5fSChristoph Hellwig return 0; 97795533d5fSChristoph Hellwig } 97895533d5fSChristoph Hellwig 97995533d5fSChristoph Hellwig static const cmdinfo_t aio_read_cmd = { 98095533d5fSChristoph Hellwig .name = "aio_read", 98195533d5fSChristoph Hellwig .cfunc = aio_read_f, 98295533d5fSChristoph Hellwig .argmin = 2, 98395533d5fSChristoph Hellwig .argmax = -1, 98495533d5fSChristoph Hellwig .args = "[-Cqv] [-P pattern ] off len [len..]", 98595533d5fSChristoph Hellwig .oneline = "asynchronously reads a number of bytes", 98695533d5fSChristoph Hellwig .help = aio_read_help, 98795533d5fSChristoph Hellwig }; 98895533d5fSChristoph Hellwig 98995533d5fSChristoph Hellwig static const cmdinfo_t aio_write_cmd; 99095533d5fSChristoph Hellwig 99195533d5fSChristoph Hellwig static void 99295533d5fSChristoph Hellwig aio_write_help(void) 99395533d5fSChristoph Hellwig { 99495533d5fSChristoph Hellwig printf( 99595533d5fSChristoph Hellwig "\n" 99695533d5fSChristoph Hellwig " asynchronously writes a range of bytes from the given offset source \n" 99795533d5fSChristoph Hellwig " from multiple buffers\n" 99895533d5fSChristoph Hellwig "\n" 99995533d5fSChristoph Hellwig " Example:\n" 100095533d5fSChristoph Hellwig " 'aio_write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n" 100195533d5fSChristoph Hellwig "\n" 100295533d5fSChristoph Hellwig " Writes into a segment of the currently open file, using a buffer\n" 100395533d5fSChristoph Hellwig " filled with a set pattern (0xcdcdcdcd).\n" 100495533d5fSChristoph Hellwig " The write is performed asynchronously and should the aio_flush command \n" 100595533d5fSChristoph Hellwig " should be used to ensure all outstanding aio requests have been completed\n" 100695533d5fSChristoph Hellwig " -P, -- use different pattern to fill file\n" 100795533d5fSChristoph Hellwig " -C, -- report statistics in a machine parsable format\n" 100895533d5fSChristoph Hellwig " -q, -- quite mode, do not show I/O statistics\n" 100995533d5fSChristoph Hellwig "\n"); 101095533d5fSChristoph Hellwig } 101195533d5fSChristoph Hellwig 101295533d5fSChristoph Hellwig 101395533d5fSChristoph Hellwig static int 101495533d5fSChristoph Hellwig aio_write_f(int argc, char **argv) 101595533d5fSChristoph Hellwig { 1016cf57298aSChristoph Hellwig int nr_iov, c; 101795533d5fSChristoph Hellwig int pattern = 0xcd; 101895533d5fSChristoph Hellwig struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx)); 101995533d5fSChristoph Hellwig BlockDriverAIOCB *acb; 102095533d5fSChristoph Hellwig 102195533d5fSChristoph Hellwig while ((c = getopt(argc, argv, "CqP:")) != EOF) { 102295533d5fSChristoph Hellwig switch (c) { 102395533d5fSChristoph Hellwig case 'C': 102495533d5fSChristoph Hellwig ctx->Cflag = 1; 102595533d5fSChristoph Hellwig break; 102695533d5fSChristoph Hellwig case 'q': 102795533d5fSChristoph Hellwig ctx->qflag = 1; 102895533d5fSChristoph Hellwig break; 102995533d5fSChristoph Hellwig case 'P': 1030cf070d7eSChristoph Hellwig pattern = parse_pattern(optarg); 1031cf070d7eSChristoph Hellwig if (pattern < 0) 1032cf070d7eSChristoph Hellwig return 0; 103395533d5fSChristoph Hellwig break; 103495533d5fSChristoph Hellwig default: 10357d8abfcbSKevin Wolf free(ctx); 103695533d5fSChristoph Hellwig return command_usage(&aio_write_cmd); 103795533d5fSChristoph Hellwig } 103895533d5fSChristoph Hellwig } 103995533d5fSChristoph Hellwig 10407d8abfcbSKevin Wolf if (optind > argc - 2) { 10417d8abfcbSKevin Wolf free(ctx); 104295533d5fSChristoph Hellwig return command_usage(&aio_write_cmd); 10437d8abfcbSKevin Wolf } 104495533d5fSChristoph Hellwig 104595533d5fSChristoph Hellwig ctx->offset = cvtnum(argv[optind]); 104695533d5fSChristoph Hellwig if (ctx->offset < 0) { 104795533d5fSChristoph Hellwig printf("non-numeric length argument -- %s\n", argv[optind]); 10487d8abfcbSKevin Wolf free(ctx); 104995533d5fSChristoph Hellwig return 0; 105095533d5fSChristoph Hellwig } 105195533d5fSChristoph Hellwig optind++; 105295533d5fSChristoph Hellwig 105395533d5fSChristoph Hellwig if (ctx->offset & 0x1ff) { 105495533d5fSChristoph Hellwig printf("offset %lld is not sector aligned\n", 105595533d5fSChristoph Hellwig (long long)ctx->offset); 10567d8abfcbSKevin Wolf free(ctx); 105795533d5fSChristoph Hellwig return 0; 105895533d5fSChristoph Hellwig } 105995533d5fSChristoph Hellwig 106095533d5fSChristoph Hellwig nr_iov = argc - optind; 1061cf57298aSChristoph Hellwig ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, pattern); 106295533d5fSChristoph Hellwig 106395533d5fSChristoph Hellwig gettimeofday(&ctx->t1, NULL); 106495533d5fSChristoph Hellwig acb = bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov, 106595533d5fSChristoph Hellwig ctx->qiov.size >> 9, aio_write_done, ctx); 10667d8abfcbSKevin Wolf if (!acb) { 10677d8abfcbSKevin Wolf free(ctx->buf); 10687d8abfcbSKevin Wolf free(ctx); 106995533d5fSChristoph Hellwig return -EIO; 10707d8abfcbSKevin Wolf } 107195533d5fSChristoph Hellwig 107295533d5fSChristoph Hellwig return 0; 107395533d5fSChristoph Hellwig } 107495533d5fSChristoph Hellwig 107595533d5fSChristoph Hellwig static const cmdinfo_t aio_write_cmd = { 107695533d5fSChristoph Hellwig .name = "aio_write", 107795533d5fSChristoph Hellwig .cfunc = aio_write_f, 107895533d5fSChristoph Hellwig .argmin = 2, 107995533d5fSChristoph Hellwig .argmax = -1, 108095533d5fSChristoph Hellwig .args = "[-Cq] [-P pattern ] off len [len..]", 108195533d5fSChristoph Hellwig .oneline = "asynchronously writes a number of bytes", 108295533d5fSChristoph Hellwig .help = aio_write_help, 108395533d5fSChristoph Hellwig }; 108495533d5fSChristoph Hellwig 108595533d5fSChristoph Hellwig static int 108695533d5fSChristoph Hellwig aio_flush_f(int argc, char **argv) 108795533d5fSChristoph Hellwig { 108895533d5fSChristoph Hellwig qemu_aio_flush(); 108995533d5fSChristoph Hellwig return 0; 109095533d5fSChristoph Hellwig } 109195533d5fSChristoph Hellwig 109295533d5fSChristoph Hellwig static const cmdinfo_t aio_flush_cmd = { 109395533d5fSChristoph Hellwig .name = "aio_flush", 109495533d5fSChristoph Hellwig .cfunc = aio_flush_f, 109595533d5fSChristoph Hellwig .oneline = "completes all outstanding aio requets" 109695533d5fSChristoph Hellwig }; 109795533d5fSChristoph Hellwig 1098e3aff4f6Saliguori static int 1099e3aff4f6Saliguori flush_f(int argc, char **argv) 1100e3aff4f6Saliguori { 1101e3aff4f6Saliguori bdrv_flush(bs); 1102e3aff4f6Saliguori return 0; 1103e3aff4f6Saliguori } 1104e3aff4f6Saliguori 1105e3aff4f6Saliguori static const cmdinfo_t flush_cmd = { 1106e3aff4f6Saliguori .name = "flush", 1107e3aff4f6Saliguori .altname = "f", 1108e3aff4f6Saliguori .cfunc = flush_f, 1109e3aff4f6Saliguori .oneline = "flush all in-core file state to disk", 1110e3aff4f6Saliguori }; 1111e3aff4f6Saliguori 1112e3aff4f6Saliguori static int 1113e3aff4f6Saliguori truncate_f(int argc, char **argv) 1114e3aff4f6Saliguori { 1115e3aff4f6Saliguori int64_t offset; 1116e3aff4f6Saliguori int ret; 1117e3aff4f6Saliguori 1118e3aff4f6Saliguori offset = cvtnum(argv[1]); 1119e3aff4f6Saliguori if (offset < 0) { 1120e3aff4f6Saliguori printf("non-numeric truncate argument -- %s\n", argv[1]); 1121e3aff4f6Saliguori return 0; 1122e3aff4f6Saliguori } 1123e3aff4f6Saliguori 1124e3aff4f6Saliguori ret = bdrv_truncate(bs, offset); 1125e3aff4f6Saliguori if (ret < 0) { 1126e3aff4f6Saliguori printf("truncate: %s", strerror(ret)); 1127e3aff4f6Saliguori return 0; 1128e3aff4f6Saliguori } 1129e3aff4f6Saliguori 1130e3aff4f6Saliguori return 0; 1131e3aff4f6Saliguori } 1132e3aff4f6Saliguori 1133e3aff4f6Saliguori static const cmdinfo_t truncate_cmd = { 1134e3aff4f6Saliguori .name = "truncate", 1135e3aff4f6Saliguori .altname = "t", 1136e3aff4f6Saliguori .cfunc = truncate_f, 1137e3aff4f6Saliguori .argmin = 1, 1138e3aff4f6Saliguori .argmax = 1, 1139e3aff4f6Saliguori .args = "off", 1140e3aff4f6Saliguori .oneline = "truncates the current file at the given offset", 1141e3aff4f6Saliguori }; 1142e3aff4f6Saliguori 1143e3aff4f6Saliguori static int 1144e3aff4f6Saliguori length_f(int argc, char **argv) 1145e3aff4f6Saliguori { 1146e3aff4f6Saliguori int64_t size; 1147e3aff4f6Saliguori char s1[64]; 1148e3aff4f6Saliguori 1149e3aff4f6Saliguori size = bdrv_getlength(bs); 1150e3aff4f6Saliguori if (size < 0) { 1151e3aff4f6Saliguori printf("getlength: %s", strerror(size)); 1152e3aff4f6Saliguori return 0; 1153e3aff4f6Saliguori } 1154e3aff4f6Saliguori 1155e3aff4f6Saliguori cvtstr(size, s1, sizeof(s1)); 1156e3aff4f6Saliguori printf("%s\n", s1); 1157e3aff4f6Saliguori return 0; 1158e3aff4f6Saliguori } 1159e3aff4f6Saliguori 1160e3aff4f6Saliguori 1161e3aff4f6Saliguori static const cmdinfo_t length_cmd = { 1162e3aff4f6Saliguori .name = "length", 1163e3aff4f6Saliguori .altname = "l", 1164e3aff4f6Saliguori .cfunc = length_f, 1165e3aff4f6Saliguori .oneline = "gets the length of the current file", 1166e3aff4f6Saliguori }; 1167e3aff4f6Saliguori 1168e3aff4f6Saliguori 1169e3aff4f6Saliguori static int 1170e3aff4f6Saliguori info_f(int argc, char **argv) 1171e3aff4f6Saliguori { 1172e3aff4f6Saliguori BlockDriverInfo bdi; 1173e3aff4f6Saliguori char s1[64], s2[64]; 1174e3aff4f6Saliguori int ret; 1175e3aff4f6Saliguori 1176e3aff4f6Saliguori if (bs->drv && bs->drv->format_name) 1177e3aff4f6Saliguori printf("format name: %s\n", bs->drv->format_name); 1178e3aff4f6Saliguori if (bs->drv && bs->drv->protocol_name) 1179e3aff4f6Saliguori printf("format name: %s\n", bs->drv->protocol_name); 1180e3aff4f6Saliguori 1181e3aff4f6Saliguori ret = bdrv_get_info(bs, &bdi); 1182e3aff4f6Saliguori if (ret) 1183e3aff4f6Saliguori return 0; 1184e3aff4f6Saliguori 1185e3aff4f6Saliguori cvtstr(bdi.cluster_size, s1, sizeof(s1)); 1186e3aff4f6Saliguori cvtstr(bdi.vm_state_offset, s2, sizeof(s2)); 1187e3aff4f6Saliguori 1188e3aff4f6Saliguori printf("cluster size: %s\n", s1); 1189e3aff4f6Saliguori printf("vm state offset: %s\n", s2); 1190e3aff4f6Saliguori 1191e3aff4f6Saliguori return 0; 1192e3aff4f6Saliguori } 1193e3aff4f6Saliguori 1194e3aff4f6Saliguori 1195e3aff4f6Saliguori 1196e3aff4f6Saliguori static const cmdinfo_t info_cmd = { 1197e3aff4f6Saliguori .name = "info", 1198e3aff4f6Saliguori .altname = "i", 1199e3aff4f6Saliguori .cfunc = info_f, 1200e3aff4f6Saliguori .oneline = "prints information about the current file", 1201e3aff4f6Saliguori }; 1202e3aff4f6Saliguori 1203e3aff4f6Saliguori static int 1204e3aff4f6Saliguori alloc_f(int argc, char **argv) 1205e3aff4f6Saliguori { 1206e3aff4f6Saliguori int64_t offset; 1207a7824a88SKevin Wolf int nb_sectors, remaining; 1208e3aff4f6Saliguori char s1[64]; 1209a7824a88SKevin Wolf int num, sum_alloc; 1210e3aff4f6Saliguori int ret; 1211e3aff4f6Saliguori 1212e3aff4f6Saliguori offset = cvtnum(argv[1]); 1213e3aff4f6Saliguori if (offset & 0x1ff) { 1214e3aff4f6Saliguori printf("offset %lld is not sector aligned\n", 1215e3aff4f6Saliguori (long long)offset); 1216e3aff4f6Saliguori return 0; 1217e3aff4f6Saliguori } 1218e3aff4f6Saliguori 1219e3aff4f6Saliguori if (argc == 3) 1220e3aff4f6Saliguori nb_sectors = cvtnum(argv[2]); 1221e3aff4f6Saliguori else 1222e3aff4f6Saliguori nb_sectors = 1; 1223e3aff4f6Saliguori 1224a7824a88SKevin Wolf remaining = nb_sectors; 1225a7824a88SKevin Wolf sum_alloc = 0; 1226a7824a88SKevin Wolf while (remaining) { 1227e3aff4f6Saliguori ret = bdrv_is_allocated(bs, offset >> 9, nb_sectors, &num); 1228a7824a88SKevin Wolf remaining -= num; 1229a7824a88SKevin Wolf if (ret) { 1230a7824a88SKevin Wolf sum_alloc += num; 1231a7824a88SKevin Wolf } 1232a7824a88SKevin Wolf } 1233e3aff4f6Saliguori 1234e3aff4f6Saliguori cvtstr(offset, s1, sizeof(s1)); 1235e3aff4f6Saliguori 1236e3aff4f6Saliguori if (nb_sectors == 1) 1237a7824a88SKevin Wolf printf("sector allocated at offset %s\n", s1); 1238e3aff4f6Saliguori else 1239a7824a88SKevin Wolf printf("%d/%d sectors allocated at offset %s\n", 1240a7824a88SKevin Wolf sum_alloc, nb_sectors, s1); 1241e3aff4f6Saliguori return 0; 1242e3aff4f6Saliguori } 1243e3aff4f6Saliguori 1244e3aff4f6Saliguori static const cmdinfo_t alloc_cmd = { 1245e3aff4f6Saliguori .name = "alloc", 1246e3aff4f6Saliguori .altname = "a", 1247e3aff4f6Saliguori .argmin = 1, 1248e3aff4f6Saliguori .argmax = 2, 1249e3aff4f6Saliguori .cfunc = alloc_f, 1250e3aff4f6Saliguori .args = "off [sectors]", 1251e3aff4f6Saliguori .oneline = "checks if a sector is present in the file", 1252e3aff4f6Saliguori }; 1253e3aff4f6Saliguori 1254e3aff4f6Saliguori static int 1255e3aff4f6Saliguori close_f(int argc, char **argv) 1256e3aff4f6Saliguori { 1257e3aff4f6Saliguori bdrv_close(bs); 1258e3aff4f6Saliguori bs = NULL; 1259e3aff4f6Saliguori return 0; 1260e3aff4f6Saliguori } 1261e3aff4f6Saliguori 1262e3aff4f6Saliguori static const cmdinfo_t close_cmd = { 1263e3aff4f6Saliguori .name = "close", 1264e3aff4f6Saliguori .altname = "c", 1265e3aff4f6Saliguori .cfunc = close_f, 1266e3aff4f6Saliguori .oneline = "close the current open file", 1267e3aff4f6Saliguori }; 1268e3aff4f6Saliguori 12699c4bab26SChristoph Hellwig static int openfile(char *name, int flags, int growable) 1270e3aff4f6Saliguori { 1271e3aff4f6Saliguori if (bs) { 1272e3aff4f6Saliguori fprintf(stderr, "file open already, try 'help close'\n"); 1273e3aff4f6Saliguori return 1; 1274e3aff4f6Saliguori } 1275e3aff4f6Saliguori 1276e3aff4f6Saliguori bs = bdrv_new("hda"); 1277e3aff4f6Saliguori if (!bs) 1278e3aff4f6Saliguori return 1; 1279e3aff4f6Saliguori 12801db6947dSChristoph Hellwig if (growable) { 12811db6947dSChristoph Hellwig flags |= BDRV_O_FILE; 12821db6947dSChristoph Hellwig } 12831db6947dSChristoph Hellwig 1284e3aff4f6Saliguori if (bdrv_open(bs, name, flags) == -1) { 1285e3aff4f6Saliguori fprintf(stderr, "%s: can't open device %s\n", progname, name); 1286e3aff4f6Saliguori bs = NULL; 1287e3aff4f6Saliguori return 1; 1288e3aff4f6Saliguori } 1289e3aff4f6Saliguori 12909c4bab26SChristoph Hellwig if (growable) { 12919c4bab26SChristoph Hellwig bs->growable = 1; 12929c4bab26SChristoph Hellwig } 1293e3aff4f6Saliguori return 0; 1294e3aff4f6Saliguori } 1295e3aff4f6Saliguori 1296e3aff4f6Saliguori static void 1297e3aff4f6Saliguori open_help(void) 1298e3aff4f6Saliguori { 1299e3aff4f6Saliguori printf( 1300e3aff4f6Saliguori "\n" 1301e3aff4f6Saliguori " opens a new file in the requested mode\n" 1302e3aff4f6Saliguori "\n" 1303e3aff4f6Saliguori " Example:\n" 1304e3aff4f6Saliguori " 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n" 1305e3aff4f6Saliguori "\n" 1306e3aff4f6Saliguori " Opens a file for subsequent use by all of the other qemu-io commands.\n" 1307e3aff4f6Saliguori " -C, -- create new file if it doesn't exist\n" 1308e3aff4f6Saliguori " -r, -- open file read-only\n" 1309e3aff4f6Saliguori " -s, -- use snapshot file\n" 1310e3aff4f6Saliguori " -n, -- disable host cache\n" 13119c4bab26SChristoph Hellwig " -g, -- allow file to grow (only applies to protocols)" 1312e3aff4f6Saliguori "\n"); 1313e3aff4f6Saliguori } 1314e3aff4f6Saliguori 1315e3aff4f6Saliguori static const cmdinfo_t open_cmd; 1316e3aff4f6Saliguori 1317e3aff4f6Saliguori static int 1318e3aff4f6Saliguori open_f(int argc, char **argv) 1319e3aff4f6Saliguori { 1320e3aff4f6Saliguori int flags = 0; 1321e3aff4f6Saliguori int readonly = 0; 13229c4bab26SChristoph Hellwig int growable = 0; 1323e3aff4f6Saliguori int c; 1324e3aff4f6Saliguori 13259c4bab26SChristoph Hellwig while ((c = getopt(argc, argv, "snCrg")) != EOF) { 1326e3aff4f6Saliguori switch (c) { 1327e3aff4f6Saliguori case 's': 1328e3aff4f6Saliguori flags |= BDRV_O_SNAPSHOT; 1329e3aff4f6Saliguori break; 1330e3aff4f6Saliguori case 'n': 1331e3aff4f6Saliguori flags |= BDRV_O_NOCACHE; 1332e3aff4f6Saliguori break; 1333e3aff4f6Saliguori case 'C': 1334e3aff4f6Saliguori flags |= BDRV_O_CREAT; 1335e3aff4f6Saliguori break; 1336e3aff4f6Saliguori case 'r': 1337e3aff4f6Saliguori readonly = 1; 1338e3aff4f6Saliguori break; 13399c4bab26SChristoph Hellwig case 'g': 13409c4bab26SChristoph Hellwig growable = 1; 13419c4bab26SChristoph Hellwig break; 1342e3aff4f6Saliguori default: 1343e3aff4f6Saliguori return command_usage(&open_cmd); 1344e3aff4f6Saliguori } 1345e3aff4f6Saliguori } 1346e3aff4f6Saliguori 1347e3aff4f6Saliguori if (readonly) 1348e3aff4f6Saliguori flags |= BDRV_O_RDONLY; 1349e3aff4f6Saliguori else 1350e3aff4f6Saliguori flags |= BDRV_O_RDWR; 1351e3aff4f6Saliguori 1352e3aff4f6Saliguori if (optind != argc - 1) 1353e3aff4f6Saliguori return command_usage(&open_cmd); 1354e3aff4f6Saliguori 13559c4bab26SChristoph Hellwig return openfile(argv[optind], flags, growable); 1356e3aff4f6Saliguori } 1357e3aff4f6Saliguori 1358e3aff4f6Saliguori static const cmdinfo_t open_cmd = { 1359e3aff4f6Saliguori .name = "open", 1360e3aff4f6Saliguori .altname = "o", 1361e3aff4f6Saliguori .cfunc = open_f, 1362e3aff4f6Saliguori .argmin = 1, 1363e3aff4f6Saliguori .argmax = -1, 1364e3aff4f6Saliguori .flags = CMD_NOFILE_OK, 1365e3aff4f6Saliguori .args = "[-Crsn] [path]", 1366e3aff4f6Saliguori .oneline = "open the file specified by path", 1367e3aff4f6Saliguori .help = open_help, 1368e3aff4f6Saliguori }; 1369e3aff4f6Saliguori 1370e3aff4f6Saliguori static int 1371e3aff4f6Saliguori init_args_command( 1372e3aff4f6Saliguori int index) 1373e3aff4f6Saliguori { 1374e3aff4f6Saliguori /* only one device allowed so far */ 1375e3aff4f6Saliguori if (index >= 1) 1376e3aff4f6Saliguori return 0; 1377e3aff4f6Saliguori return ++index; 1378e3aff4f6Saliguori } 1379e3aff4f6Saliguori 1380e3aff4f6Saliguori static int 1381e3aff4f6Saliguori init_check_command( 1382e3aff4f6Saliguori const cmdinfo_t *ct) 1383e3aff4f6Saliguori { 1384e3aff4f6Saliguori if (ct->flags & CMD_FLAG_GLOBAL) 1385e3aff4f6Saliguori return 1; 1386e3aff4f6Saliguori if (!(ct->flags & CMD_NOFILE_OK) && !bs) { 1387e3aff4f6Saliguori fprintf(stderr, "no file open, try 'help open'\n"); 1388e3aff4f6Saliguori return 0; 1389e3aff4f6Saliguori } 1390e3aff4f6Saliguori return 1; 1391e3aff4f6Saliguori } 1392e3aff4f6Saliguori 1393e3aff4f6Saliguori static void usage(const char *name) 1394e3aff4f6Saliguori { 1395e3aff4f6Saliguori printf( 1396e3aff4f6Saliguori "Usage: %s [-h] [-V] [-Crsnm] [-c cmd] ... [file]\n" 139784844a20SStefan Weil "QEMU Disk exerciser\n" 1398e3aff4f6Saliguori "\n" 1399e3aff4f6Saliguori " -C, --create create new file if it doesn't exist\n" 1400e3aff4f6Saliguori " -c, --cmd command to execute\n" 1401e3aff4f6Saliguori " -r, --read-only export read-only\n" 1402e3aff4f6Saliguori " -s, --snapshot use snapshot file\n" 1403e3aff4f6Saliguori " -n, --nocache disable host cache\n" 14041db6947dSChristoph Hellwig " -g, --growable allow file to grow (only applies to protocols)\n" 1405e3aff4f6Saliguori " -m, --misalign misalign allocations for O_DIRECT\n" 14065c6c3a6cSChristoph Hellwig " -k, --native-aio use kernel AIO implementation (on Linux only)\n" 1407e3aff4f6Saliguori " -h, --help display this help and exit\n" 1408e3aff4f6Saliguori " -V, --version output version information and exit\n" 1409e3aff4f6Saliguori "\n", 1410e3aff4f6Saliguori name); 1411e3aff4f6Saliguori } 1412e3aff4f6Saliguori 1413e3aff4f6Saliguori 1414e3aff4f6Saliguori int main(int argc, char **argv) 1415e3aff4f6Saliguori { 1416e3aff4f6Saliguori int readonly = 0; 14179c4bab26SChristoph Hellwig int growable = 0; 14185c6c3a6cSChristoph Hellwig const char *sopt = "hVc:Crsnmgk"; 1419e3aff4f6Saliguori struct option lopt[] = { 1420660f11beSBlue Swirl { "help", 0, NULL, 'h' }, 1421660f11beSBlue Swirl { "version", 0, NULL, 'V' }, 1422660f11beSBlue Swirl { "offset", 1, NULL, 'o' }, 1423660f11beSBlue Swirl { "cmd", 1, NULL, 'c' }, 1424660f11beSBlue Swirl { "create", 0, NULL, 'C' }, 1425660f11beSBlue Swirl { "read-only", 0, NULL, 'r' }, 1426660f11beSBlue Swirl { "snapshot", 0, NULL, 's' }, 1427660f11beSBlue Swirl { "nocache", 0, NULL, 'n' }, 1428660f11beSBlue Swirl { "misalign", 0, NULL, 'm' }, 1429660f11beSBlue Swirl { "growable", 0, NULL, 'g' }, 14305c6c3a6cSChristoph Hellwig { "native-aio", 0, NULL, 'k' }, 1431660f11beSBlue Swirl { NULL, 0, NULL, 0 } 1432e3aff4f6Saliguori }; 1433e3aff4f6Saliguori int c; 1434e3aff4f6Saliguori int opt_index = 0; 1435e3aff4f6Saliguori int flags = 0; 1436e3aff4f6Saliguori 1437e3aff4f6Saliguori progname = basename(argv[0]); 1438e3aff4f6Saliguori 1439e3aff4f6Saliguori while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) { 1440e3aff4f6Saliguori switch (c) { 1441e3aff4f6Saliguori case 's': 1442e3aff4f6Saliguori flags |= BDRV_O_SNAPSHOT; 1443e3aff4f6Saliguori break; 1444e3aff4f6Saliguori case 'n': 1445e3aff4f6Saliguori flags |= BDRV_O_NOCACHE; 1446e3aff4f6Saliguori break; 1447e3aff4f6Saliguori case 'c': 1448e3aff4f6Saliguori add_user_command(optarg); 1449e3aff4f6Saliguori break; 1450e3aff4f6Saliguori case 'C': 1451e3aff4f6Saliguori flags |= BDRV_O_CREAT; 1452e3aff4f6Saliguori break; 1453e3aff4f6Saliguori case 'r': 1454e3aff4f6Saliguori readonly = 1; 1455e3aff4f6Saliguori break; 1456e3aff4f6Saliguori case 'm': 1457e3aff4f6Saliguori misalign = 1; 1458e3aff4f6Saliguori break; 14599c4bab26SChristoph Hellwig case 'g': 14609c4bab26SChristoph Hellwig growable = 1; 14619c4bab26SChristoph Hellwig break; 14625c6c3a6cSChristoph Hellwig case 'k': 14635c6c3a6cSChristoph Hellwig flags |= BDRV_O_NATIVE_AIO; 14645c6c3a6cSChristoph Hellwig break; 1465e3aff4f6Saliguori case 'V': 1466e3aff4f6Saliguori printf("%s version %s\n", progname, VERSION); 1467e3aff4f6Saliguori exit(0); 1468e3aff4f6Saliguori case 'h': 1469e3aff4f6Saliguori usage(progname); 1470e3aff4f6Saliguori exit(0); 1471e3aff4f6Saliguori default: 1472e3aff4f6Saliguori usage(progname); 1473e3aff4f6Saliguori exit(1); 1474e3aff4f6Saliguori } 1475e3aff4f6Saliguori } 1476e3aff4f6Saliguori 1477e3aff4f6Saliguori if ((argc - optind) > 1) { 1478e3aff4f6Saliguori usage(progname); 1479e3aff4f6Saliguori exit(1); 1480e3aff4f6Saliguori } 1481e3aff4f6Saliguori 1482e3aff4f6Saliguori bdrv_init(); 1483e3aff4f6Saliguori 1484e3aff4f6Saliguori /* initialize commands */ 1485e3aff4f6Saliguori quit_init(); 1486e3aff4f6Saliguori help_init(); 1487e3aff4f6Saliguori add_command(&open_cmd); 1488e3aff4f6Saliguori add_command(&close_cmd); 1489e3aff4f6Saliguori add_command(&read_cmd); 1490e3aff4f6Saliguori add_command(&readv_cmd); 1491e3aff4f6Saliguori add_command(&write_cmd); 1492e3aff4f6Saliguori add_command(&writev_cmd); 149395533d5fSChristoph Hellwig add_command(&aio_read_cmd); 149495533d5fSChristoph Hellwig add_command(&aio_write_cmd); 149595533d5fSChristoph Hellwig add_command(&aio_flush_cmd); 1496e3aff4f6Saliguori add_command(&flush_cmd); 1497e3aff4f6Saliguori add_command(&truncate_cmd); 1498e3aff4f6Saliguori add_command(&length_cmd); 1499e3aff4f6Saliguori add_command(&info_cmd); 1500e3aff4f6Saliguori add_command(&alloc_cmd); 1501e3aff4f6Saliguori 1502e3aff4f6Saliguori add_args_command(init_args_command); 1503e3aff4f6Saliguori add_check_command(init_check_command); 1504e3aff4f6Saliguori 1505e3aff4f6Saliguori /* open the device */ 1506e3aff4f6Saliguori if (readonly) 1507e3aff4f6Saliguori flags |= BDRV_O_RDONLY; 1508e3aff4f6Saliguori else 1509e3aff4f6Saliguori flags |= BDRV_O_RDWR; 1510e3aff4f6Saliguori 1511e3aff4f6Saliguori if ((argc - optind) == 1) 15129c4bab26SChristoph Hellwig openfile(argv[optind], flags, growable); 1513e3aff4f6Saliguori command_loop(); 1514e3aff4f6Saliguori 151595533d5fSChristoph Hellwig /* 151695533d5fSChristoph Hellwig * Make sure all outstanding requests get flushed the program exits. 151795533d5fSChristoph Hellwig */ 151895533d5fSChristoph Hellwig qemu_aio_flush(); 151995533d5fSChristoph Hellwig 1520e3aff4f6Saliguori if (bs) 1521e3aff4f6Saliguori bdrv_close(bs); 1522e3aff4f6Saliguori return 0; 1523e3aff4f6Saliguori } 1524