X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=qemu-io-cmds.c;h=41580b52473e6139985ebade8d3f55ecc608c13a;hb=0e01b76e7cc43068f6b8cc05297f61539ccd5279;hp=e70855254af003e594f3c628bd12ad8193fac695;hpb=e0d3795654b7eb5b91b478bc7e6b717b192a8bce;p=mirror_qemu.git diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index e70855254a..41580b5247 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -8,11 +8,18 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "qemu-io.h" -#include "block/block_int.h" +#include "sysemu/block-backend.h" +#include "block/block.h" +#include "block/block_int.h" /* for info_f() */ #include "block/qapi.h" +#include "qemu/error-report.h" #include "qemu/main-loop.h" #include "qemu/timer.h" +#include "sysemu/block-backend.h" +#include "qemu/cutils.h" #define CMD_NOFILE_OK 0x01 @@ -40,24 +47,24 @@ int qemuio_command_usage(const cmdinfo_t *ci) return 0; } -static int init_check_command(BlockDriverState *bs, const cmdinfo_t *ct) +static int init_check_command(BlockBackend *blk, const cmdinfo_t *ct) { if (ct->flags & CMD_FLAG_GLOBAL) { return 1; } - if (!(ct->flags & CMD_NOFILE_OK) && !bs) { + if (!(ct->flags & CMD_NOFILE_OK) && !blk) { fprintf(stderr, "no file open, try 'help open'\n"); return 0; } return 1; } -static int command(BlockDriverState *bs, const cmdinfo_t *ct, int argc, +static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc, char **argv) { char *cmd = argv[0]; - if (!init_check_command(bs, ct)) { + if (!init_check_command(blk, ct)) { return 0; } @@ -78,7 +85,7 @@ static int command(BlockDriverState *bs, const cmdinfo_t *ct, int argc, return 0; } optind = 0; - return ct->cfunc(bs, argc, argv); + return ct->cfunc(blk, argc, argv); } static const cmdinfo_t *find_command(const char *cmd) @@ -132,7 +139,29 @@ static char **breakline(char *input, int *count) static int64_t cvtnum(const char *s) { char *end; - return strtosz_suffix(s, &end, STRTOSZ_DEFSUFFIX_B); + int64_t ret; + + ret = qemu_strtosz_suffix(s, &end, QEMU_STRTOSZ_DEFSUFFIX_B); + if (*end != '\0') { + /* Detritus at the end of the string */ + return -EINVAL; + } + return ret; +} + +static void print_cvtnum_err(int64_t rc, const char *arg) +{ + switch (rc) { + case -EINVAL: + printf("Parsing error: non-numeric argument," + " or extraneous/unrecognized suffix -- %s\n", arg); + break; + case -ERANGE: + printf("Parsing error: argument too large -- %s\n", arg); + break; + default: + printf("Parsing error: %s\n", arg); + } } #define EXABYTES(x) ((long long)(x) << 60) @@ -267,14 +296,14 @@ static int parse_pattern(const char *arg) */ #define MISALIGN_OFFSET 16 -static void *qemu_io_alloc(BlockDriverState *bs, size_t len, int pattern) +static void *qemu_io_alloc(BlockBackend *blk, size_t len, int pattern) { void *buf; if (qemuio_misalign) { len += MISALIGN_OFFSET; } - buf = qemu_blockalign(bs, len); + buf = blk_blockalign(blk, len); memset(buf, pattern, len); if (qemuio_misalign) { buf += MISALIGN_OFFSET; @@ -290,9 +319,10 @@ static void qemu_io_free(void *p) qemu_vfree(p); } -static void dump_buffer(const void *buffer, int64_t offset, int len) +static void dump_buffer(const void *buffer, int64_t offset, int64_t len) { - int i, j; + uint64_t i; + int j; const uint8_t *p; for (i = 0, p = buffer; i < len; i += 16) { @@ -315,7 +345,7 @@ static void dump_buffer(const void *buffer, int64_t offset, int len) } static void print_report(const char *op, struct timeval *t, int64_t offset, - int count, int total, int cnt, int Cflag) + int64_t count, int64_t total, int cnt, int Cflag) { char s1[64], s2[64], ts[64]; @@ -323,12 +353,12 @@ static void print_report(const char *op, struct timeval *t, int64_t offset, if (!Cflag) { cvtstr((double)total, s1, sizeof(s1)); cvtstr(tdiv((double)total, *t), s2, sizeof(s2)); - printf("%s %d/%d bytes at offset %" PRId64 "\n", + printf("%s %"PRId64"/%"PRId64" bytes at offset %" PRId64 "\n", op, total, count, offset); printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n", s1, cnt, ts, s2, tdiv((double)cnt, *t)); } else {/* bytes,ops,time,bytes/sec,ops/sec */ - printf("%d,%d,%s,%.3f,%.3f\n", + printf("%"PRId64",%d,%s,%.3f,%.3f\n", total, cnt, ts, tdiv((double)total, *t), tdiv((double)cnt, *t)); @@ -340,7 +370,7 @@ static void print_report(const char *op, struct timeval *t, int64_t offset, * vector matching it. */ static void * -create_iovec(BlockDriverState *bs, QEMUIOVector *qiov, char **argv, int nr_iov, +create_iovec(BlockBackend *blk, QEMUIOVector *qiov, char **argv, int nr_iov, int pattern) { size_t *sizes = g_new0(size_t, nr_iov); @@ -355,13 +385,13 @@ create_iovec(BlockDriverState *bs, QEMUIOVector *qiov, char **argv, int nr_iov, len = cvtnum(arg); if (len < 0) { - printf("non-numeric length argument -- %s\n", arg); + print_cvtnum_err(len, arg); goto fail; } /* should be SIZE_T_MAX, but that doesn't exist */ if (len > INT_MAX) { - printf("too large length argument -- %s\n", arg); + printf("Argument '%s' exceeds maximum size %d\n", arg, INT_MAX); goto fail; } @@ -377,7 +407,7 @@ create_iovec(BlockDriverState *bs, QEMUIOVector *qiov, char **argv, int nr_iov, qemu_iovec_init(qiov, nr_iov); - buf = p = qemu_io_alloc(bs, count, pattern); + buf = p = qemu_io_alloc(blk, count, pattern); for (i = 0; i < nr_iov; i++) { qemu_iovec_add(qiov, p, sizes[i]); @@ -389,12 +419,16 @@ fail: return buf; } -static int do_read(BlockDriverState *bs, char *buf, int64_t offset, int count, - int *total) +static int do_read(BlockBackend *blk, char *buf, int64_t offset, int64_t count, + int64_t *total) { int ret; - ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9); + if (count >> 9 > INT_MAX) { + return -ERANGE; + } + + ret = blk_read(blk, offset >> 9, (uint8_t *)buf, count >> 9); if (ret < 0) { return ret; } @@ -402,12 +436,16 @@ static int do_read(BlockDriverState *bs, char *buf, int64_t offset, int count, return 1; } -static int do_write(BlockDriverState *bs, char *buf, int64_t offset, int count, - int *total) +static int do_write(BlockBackend *blk, char *buf, int64_t offset, int64_t count, + int64_t *total) { int ret; - ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9); + if (count >> 9 > INT_MAX) { + return -ERANGE; + } + + ret = blk_write(blk, offset >> 9, (uint8_t *)buf, count >> 9); if (ret < 0) { return ret; } @@ -415,20 +453,28 @@ static int do_write(BlockDriverState *bs, char *buf, int64_t offset, int count, return 1; } -static int do_pread(BlockDriverState *bs, char *buf, int64_t offset, int count, - int *total) +static int do_pread(BlockBackend *blk, char *buf, int64_t offset, + int64_t count, int64_t *total) { - *total = bdrv_pread(bs, offset, (uint8_t *)buf, count); + if (count > INT_MAX) { + return -ERANGE; + } + + *total = blk_pread(blk, offset, (uint8_t *)buf, count); if (*total < 0) { return *total; } return 1; } -static int do_pwrite(BlockDriverState *bs, char *buf, int64_t offset, int count, - int *total) +static int do_pwrite(BlockBackend *blk, char *buf, int64_t offset, + int64_t count, int64_t *total) { - *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count); + if (count > INT_MAX) { + return -ERANGE; + } + + *total = blk_pwrite(blk, offset, (uint8_t *)buf, count); if (*total < 0) { return *total; } @@ -436,10 +482,10 @@ static int do_pwrite(BlockDriverState *bs, char *buf, int64_t offset, int count, } typedef struct { - BlockDriverState *bs; + BlockBackend *blk; int64_t offset; - int count; - int *total; + int64_t count; + int64_t *total; int ret; bool done; } CoWriteZeroes; @@ -448,8 +494,8 @@ static void coroutine_fn co_write_zeroes_entry(void *opaque) { CoWriteZeroes *data = opaque; - data->ret = bdrv_co_write_zeroes(data->bs, data->offset / BDRV_SECTOR_SIZE, - data->count / BDRV_SECTOR_SIZE, 0); + data->ret = blk_co_write_zeroes(data->blk, data->offset / BDRV_SECTOR_SIZE, + data->count / BDRV_SECTOR_SIZE, 0); data->done = true; if (data->ret < 0) { *data->total = data->ret; @@ -459,22 +505,26 @@ static void coroutine_fn co_write_zeroes_entry(void *opaque) *data->total = data->count; } -static int do_co_write_zeroes(BlockDriverState *bs, int64_t offset, int count, - int *total) +static int do_co_write_zeroes(BlockBackend *blk, int64_t offset, int64_t count, + int64_t *total) { Coroutine *co; CoWriteZeroes data = { - .bs = bs, + .blk = blk, .offset = offset, .count = count, .total = total, .done = false, }; + if (count >> BDRV_SECTOR_BITS > INT_MAX) { + return -ERANGE; + } + co = qemu_coroutine_create(co_write_zeroes_entry); qemu_coroutine_enter(co, &data); while (!data.done) { - aio_poll(bdrv_get_aio_context(bs), true); + aio_poll(blk_get_aio_context(blk), true); } if (data.ret < 0) { return data.ret; @@ -483,12 +533,16 @@ static int do_co_write_zeroes(BlockDriverState *bs, int64_t offset, int count, } } -static int do_write_compressed(BlockDriverState *bs, char *buf, int64_t offset, - int count, int *total) +static int do_write_compressed(BlockBackend *blk, char *buf, int64_t offset, + int64_t count, int64_t *total) { int ret; - ret = bdrv_write_compressed(bs, offset >> 9, (uint8_t *)buf, count >> 9); + if (count >> 9 > INT_MAX) { + return -ERANGE; + } + + ret = blk_write_compressed(blk, offset >> 9, (uint8_t *)buf, count >> 9); if (ret < 0) { return ret; } @@ -496,20 +550,28 @@ static int do_write_compressed(BlockDriverState *bs, char *buf, int64_t offset, return 1; } -static int do_load_vmstate(BlockDriverState *bs, char *buf, int64_t offset, - int count, int *total) +static int do_load_vmstate(BlockBackend *blk, char *buf, int64_t offset, + int64_t count, int64_t *total) { - *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count); + if (count > INT_MAX) { + return -ERANGE; + } + + *total = blk_load_vmstate(blk, (uint8_t *)buf, offset, count); if (*total < 0) { return *total; } return 1; } -static int do_save_vmstate(BlockDriverState *bs, char *buf, int64_t offset, - int count, int *total) +static int do_save_vmstate(BlockBackend *blk, char *buf, int64_t offset, + int64_t count, int64_t *total) { - *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count); + if (count > INT_MAX) { + return -ERANGE; + } + + *total = blk_save_vmstate(blk, (uint8_t *)buf, offset, count); if (*total < 0) { return *total; } @@ -522,13 +584,13 @@ static void aio_rw_done(void *opaque, int ret) *(int *)opaque = ret; } -static int do_aio_readv(BlockDriverState *bs, QEMUIOVector *qiov, +static int do_aio_readv(BlockBackend *blk, QEMUIOVector *qiov, int64_t offset, int *total) { int async_ret = NOT_DONE; - bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9, - aio_rw_done, &async_ret); + blk_aio_readv(blk, offset >> 9, qiov, qiov->size >> 9, + aio_rw_done, &async_ret); while (async_ret == NOT_DONE) { main_loop_wait(false); } @@ -537,13 +599,13 @@ static int do_aio_readv(BlockDriverState *bs, QEMUIOVector *qiov, return async_ret < 0 ? async_ret : 1; } -static int do_aio_writev(BlockDriverState *bs, QEMUIOVector *qiov, +static int do_aio_writev(BlockBackend *blk, QEMUIOVector *qiov, int64_t offset, int *total) { int async_ret = NOT_DONE; - bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9, - aio_rw_done, &async_ret); + blk_aio_writev(blk, offset >> 9, qiov, qiov->size >> 9, + aio_rw_done, &async_ret); while (async_ret == NOT_DONE) { main_loop_wait(false); } @@ -567,7 +629,7 @@ static void multiwrite_cb(void *opaque, int ret) } } -static int do_aio_multiwrite(BlockDriverState *bs, BlockRequest* reqs, +static int do_aio_multiwrite(BlockBackend *blk, BlockRequest* reqs, int num_reqs, int *total) { int i, ret; @@ -583,7 +645,7 @@ static int do_aio_multiwrite(BlockDriverState *bs, BlockRequest* reqs, *total += reqs[i].qiov->size; } - ret = bdrv_aio_multiwrite(bs, reqs, num_reqs); + ret = blk_aio_multiwrite(blk, reqs, num_reqs); if (ret < 0) { return ret; } @@ -609,7 +671,7 @@ static void read_help(void) " -b, -- read from the VM state rather than the virtual disk\n" " -C, -- report statistics in a machine parsable format\n" " -l, -- length for pattern verification (only with -P)\n" -" -p, -- use bdrv_pread to read the file\n" +" -p, -- use blk_pread to read the file\n" " -P, -- use a pattern to verify read data\n" " -q, -- quiet mode, do not show I/O statistics\n" " -s, -- start offset for pattern verification (only with -P)\n" @@ -617,7 +679,7 @@ static void read_help(void) "\n"); } -static int read_f(BlockDriverState *bs, int argc, char **argv); +static int read_f(BlockBackend *blk, int argc, char **argv); static const cmdinfo_t read_cmd = { .name = "read", @@ -630,7 +692,7 @@ static const cmdinfo_t read_cmd = { .help = read_help, }; -static int read_f(BlockDriverState *bs, int argc, char **argv) +static int read_f(BlockBackend *blk, int argc, char **argv) { struct timeval t1, t2; int Cflag = 0, pflag = 0, qflag = 0, vflag = 0; @@ -638,12 +700,13 @@ static int read_f(BlockDriverState *bs, int argc, char **argv) int c, cnt; char *buf; int64_t offset; - int count; + int64_t count; /* Some compilers get confused and warn if this is not initialized. */ - int total = 0; - int pattern = 0, pattern_offset = 0, pattern_count = 0; + int64_t total = 0; + int pattern = 0; + int64_t pattern_offset = 0, pattern_count = 0; - while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != EOF) { + while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != -1) { switch (c) { case 'b': bflag = 1; @@ -655,7 +718,7 @@ static int read_f(BlockDriverState *bs, int argc, char **argv) lflag = 1; pattern_count = cvtnum(optarg); if (pattern_count < 0) { - printf("non-numeric length argument -- %s\n", optarg); + print_cvtnum_err(pattern_count, optarg); return 0; } break; @@ -676,7 +739,7 @@ static int read_f(BlockDriverState *bs, int argc, char **argv) sflag = 1; pattern_offset = cvtnum(optarg); if (pattern_offset < 0) { - printf("non-numeric length argument -- %s\n", optarg); + print_cvtnum_err(pattern_offset, optarg); return 0; } break; @@ -699,14 +762,18 @@ static int read_f(BlockDriverState *bs, int argc, char **argv) offset = cvtnum(argv[optind]); if (offset < 0) { - printf("non-numeric length argument -- %s\n", argv[optind]); + print_cvtnum_err(offset, argv[optind]); return 0; } optind++; count = cvtnum(argv[optind]); if (count < 0) { - printf("non-numeric length argument -- %s\n", argv[optind]); + print_cvtnum_err(count, argv[optind]); + return 0; + } else if (count > SIZE_MAX) { + printf("length cannot exceed %" PRIu64 ", given %s\n", + (uint64_t) SIZE_MAX, argv[optind]); return 0; } @@ -730,21 +797,21 @@ static int read_f(BlockDriverState *bs, int argc, char **argv) return 0; } if (count & 0x1ff) { - printf("count %d is not sector aligned\n", + printf("count %"PRId64" is not sector aligned\n", count); return 0; } } - buf = qemu_io_alloc(bs, count, 0xab); + buf = qemu_io_alloc(blk, count, 0xab); gettimeofday(&t1, NULL); if (pflag) { - cnt = do_pread(bs, buf, offset, count, &total); + cnt = do_pread(blk, buf, offset, count, &total); } else if (bflag) { - cnt = do_load_vmstate(bs, buf, offset, count, &total); + cnt = do_load_vmstate(blk, buf, offset, count, &total); } else { - cnt = do_read(bs, buf, offset, count, &total); + cnt = do_read(blk, buf, offset, count, &total); } gettimeofday(&t2, NULL); @@ -758,7 +825,7 @@ static int read_f(BlockDriverState *bs, int argc, char **argv) memset(cmp_buf, pattern, pattern_count); if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) { printf("Pattern verification failed at offset %" - PRId64 ", %d bytes\n", + PRId64 ", %"PRId64" bytes\n", offset + pattern_offset, pattern_count); } g_free(cmp_buf); @@ -801,7 +868,7 @@ static void readv_help(void) "\n"); } -static int readv_f(BlockDriverState *bs, int argc, char **argv); +static int readv_f(BlockBackend *blk, int argc, char **argv); static const cmdinfo_t readv_cmd = { .name = "readv", @@ -813,7 +880,7 @@ static const cmdinfo_t readv_cmd = { .help = readv_help, }; -static int readv_f(BlockDriverState *bs, int argc, char **argv) +static int readv_f(BlockBackend *blk, int argc, char **argv) { struct timeval t1, t2; int Cflag = 0, qflag = 0, vflag = 0; @@ -827,7 +894,7 @@ static int readv_f(BlockDriverState *bs, int argc, char **argv) int pattern = 0; int Pflag = 0; - while ((c = getopt(argc, argv, "CP:qv")) != EOF) { + while ((c = getopt(argc, argv, "CP:qv")) != -1) { switch (c) { case 'C': Cflag = 1; @@ -857,7 +924,7 @@ static int readv_f(BlockDriverState *bs, int argc, char **argv) offset = cvtnum(argv[optind]); if (offset < 0) { - printf("non-numeric length argument -- %s\n", argv[optind]); + print_cvtnum_err(offset, argv[optind]); return 0; } optind++; @@ -869,13 +936,13 @@ static int readv_f(BlockDriverState *bs, int argc, char **argv) } nr_iov = argc - optind; - buf = create_iovec(bs, &qiov, &argv[optind], nr_iov, 0xab); + buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, 0xab); if (buf == NULL) { return 0; } gettimeofday(&t1, NULL); - cnt = do_aio_readv(bs, &qiov, offset, &total); + cnt = do_aio_readv(blk, &qiov, offset, &total); gettimeofday(&t2, NULL); if (cnt < 0) { @@ -923,16 +990,16 @@ static void write_help(void) " Writes into a segment of the currently open file, using a buffer\n" " filled with a set pattern (0xcdcdcdcd).\n" " -b, -- write to the VM state rather than the virtual disk\n" -" -c, -- write compressed data with bdrv_write_compressed\n" -" -p, -- use bdrv_pwrite to write the file\n" +" -c, -- write compressed data with blk_write_compressed\n" +" -p, -- use blk_pwrite to write the file\n" " -P, -- use different pattern to fill file\n" " -C, -- report statistics in a machine parsable format\n" " -q, -- quiet mode, do not show I/O statistics\n" -" -z, -- write zeroes using bdrv_co_write_zeroes\n" +" -z, -- write zeroes using blk_co_write_zeroes\n" "\n"); } -static int write_f(BlockDriverState *bs, int argc, char **argv); +static int write_f(BlockBackend *blk, int argc, char **argv); static const cmdinfo_t write_cmd = { .name = "write", @@ -945,7 +1012,7 @@ static const cmdinfo_t write_cmd = { .help = write_help, }; -static int write_f(BlockDriverState *bs, int argc, char **argv) +static int write_f(BlockBackend *blk, int argc, char **argv) { struct timeval t1, t2; int Cflag = 0, pflag = 0, qflag = 0, bflag = 0, Pflag = 0, zflag = 0; @@ -953,12 +1020,12 @@ static int write_f(BlockDriverState *bs, int argc, char **argv) int c, cnt; char *buf = NULL; int64_t offset; - int count; + int64_t count; /* Some compilers get confused and warn if this is not initialized. */ - int total = 0; + int64_t total = 0; int pattern = 0xcd; - while ((c = getopt(argc, argv, "bcCpP:qz")) != EOF) { + while ((c = getopt(argc, argv, "bcCpP:qz")) != -1) { switch (c) { case 'b': bflag = 1; @@ -1006,14 +1073,18 @@ static int write_f(BlockDriverState *bs, int argc, char **argv) offset = cvtnum(argv[optind]); if (offset < 0) { - printf("non-numeric length argument -- %s\n", argv[optind]); + print_cvtnum_err(offset, argv[optind]); return 0; } optind++; count = cvtnum(argv[optind]); if (count < 0) { - printf("non-numeric length argument -- %s\n", argv[optind]); + print_cvtnum_err(count, argv[optind]); + return 0; + } else if (count > SIZE_MAX) { + printf("length cannot exceed %" PRIu64 ", given %s\n", + (uint64_t) SIZE_MAX, argv[optind]); return 0; } @@ -1025,27 +1096,27 @@ static int write_f(BlockDriverState *bs, int argc, char **argv) } if (count & 0x1ff) { - printf("count %d is not sector aligned\n", + printf("count %"PRId64" is not sector aligned\n", count); return 0; } } if (!zflag) { - buf = qemu_io_alloc(bs, count, pattern); + buf = qemu_io_alloc(blk, count, pattern); } gettimeofday(&t1, NULL); if (pflag) { - cnt = do_pwrite(bs, buf, offset, count, &total); + cnt = do_pwrite(blk, buf, offset, count, &total); } else if (bflag) { - cnt = do_save_vmstate(bs, buf, offset, count, &total); + cnt = do_save_vmstate(blk, buf, offset, count, &total); } else if (zflag) { - cnt = do_co_write_zeroes(bs, offset, count, &total); + cnt = do_co_write_zeroes(blk, offset, count, &total); } else if (cflag) { - cnt = do_write_compressed(bs, buf, offset, count, &total); + cnt = do_write_compressed(blk, buf, offset, count, &total); } else { - cnt = do_write(bs, buf, offset, count, &total); + cnt = do_write(blk, buf, offset, count, &total); } gettimeofday(&t2, NULL); @@ -1088,7 +1159,7 @@ writev_help(void) "\n"); } -static int writev_f(BlockDriverState *bs, int argc, char **argv); +static int writev_f(BlockBackend *blk, int argc, char **argv); static const cmdinfo_t writev_cmd = { .name = "writev", @@ -1100,7 +1171,7 @@ static const cmdinfo_t writev_cmd = { .help = writev_help, }; -static int writev_f(BlockDriverState *bs, int argc, char **argv) +static int writev_f(BlockBackend *blk, int argc, char **argv) { struct timeval t1, t2; int Cflag = 0, qflag = 0; @@ -1113,7 +1184,7 @@ static int writev_f(BlockDriverState *bs, int argc, char **argv) int pattern = 0xcd; QEMUIOVector qiov; - while ((c = getopt(argc, argv, "CqP:")) != EOF) { + while ((c = getopt(argc, argv, "CqP:")) != -1) { switch (c) { case 'C': Cflag = 1; @@ -1138,7 +1209,7 @@ static int writev_f(BlockDriverState *bs, int argc, char **argv) offset = cvtnum(argv[optind]); if (offset < 0) { - printf("non-numeric length argument -- %s\n", argv[optind]); + print_cvtnum_err(offset, argv[optind]); return 0; } optind++; @@ -1150,13 +1221,13 @@ static int writev_f(BlockDriverState *bs, int argc, char **argv) } nr_iov = argc - optind; - buf = create_iovec(bs, &qiov, &argv[optind], nr_iov, pattern); + buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern); if (buf == NULL) { return 0; } gettimeofday(&t1, NULL); - cnt = do_aio_writev(bs, &qiov, offset, &total); + cnt = do_aio_writev(blk, &qiov, offset, &total); gettimeofday(&t2, NULL); if (cnt < 0) { @@ -1197,7 +1268,7 @@ static void multiwrite_help(void) "\n"); } -static int multiwrite_f(BlockDriverState *bs, int argc, char **argv); +static int multiwrite_f(BlockBackend *blk, int argc, char **argv); static const cmdinfo_t multiwrite_cmd = { .name = "multiwrite", @@ -1209,7 +1280,7 @@ static const cmdinfo_t multiwrite_cmd = { .help = multiwrite_help, }; -static int multiwrite_f(BlockDriverState *bs, int argc, char **argv) +static int multiwrite_f(BlockBackend *blk, int argc, char **argv) { struct timeval t1, t2; int Cflag = 0, qflag = 0; @@ -1225,7 +1296,7 @@ static int multiwrite_f(BlockDriverState *bs, int argc, char **argv) int i; BlockRequest *reqs; - while ((c = getopt(argc, argv, "CqP:")) != EOF) { + while ((c = getopt(argc, argv, "CqP:")) != -1) { switch (c) { case 'C': Cflag = 1; @@ -1265,7 +1336,7 @@ static int multiwrite_f(BlockDriverState *bs, int argc, char **argv) /* Read the offset of the request */ offset = cvtnum(argv[optind]); if (offset < 0) { - printf("non-numeric offset argument -- %s\n", argv[optind]); + print_cvtnum_err(offset, argv[optind]); goto out; } optind++; @@ -1290,7 +1361,7 @@ static int multiwrite_f(BlockDriverState *bs, int argc, char **argv) nr_iov = j - optind; /* Build request */ - buf[i] = create_iovec(bs, &qiovs[i], &argv[optind], nr_iov, pattern); + buf[i] = create_iovec(blk, &qiovs[i], &argv[optind], nr_iov, pattern); if (buf[i] == NULL) { goto out; } @@ -1308,7 +1379,7 @@ static int multiwrite_f(BlockDriverState *bs, int argc, char **argv) nr_reqs = i; gettimeofday(&t1, NULL); - cnt = do_aio_multiwrite(bs, reqs, nr_reqs, &total); + cnt = do_aio_multiwrite(blk, reqs, nr_reqs, &total); gettimeofday(&t2, NULL); if (cnt < 0) { @@ -1337,6 +1408,7 @@ out: } struct aio_ctx { + BlockBackend *blk; QEMUIOVector qiov; int64_t offset; char *buf; @@ -1344,6 +1416,8 @@ struct aio_ctx { int vflag; int Cflag; int Pflag; + int zflag; + BlockAcctCookie acct; int pattern; struct timeval t1; }; @@ -1358,9 +1432,12 @@ static void aio_write_done(void *opaque, int ret) if (ret < 0) { printf("aio_write failed: %s\n", strerror(-ret)); + block_acct_failed(blk_get_stats(ctx->blk), &ctx->acct); goto out; } + block_acct_done(blk_get_stats(ctx->blk), &ctx->acct); + if (ctx->qflag) { goto out; } @@ -1370,8 +1447,10 @@ static void aio_write_done(void *opaque, int ret) print_report("wrote", &t2, ctx->offset, ctx->qiov.size, ctx->qiov.size, 1, ctx->Cflag); out: - qemu_io_free(ctx->buf); - qemu_iovec_destroy(&ctx->qiov); + if (!ctx->zflag) { + qemu_io_free(ctx->buf); + qemu_iovec_destroy(&ctx->qiov); + } g_free(ctx); } @@ -1384,6 +1463,7 @@ static void aio_read_done(void *opaque, int ret) if (ret < 0) { printf("readv failed: %s\n", strerror(-ret)); + block_acct_failed(blk_get_stats(ctx->blk), &ctx->acct); goto out; } @@ -1398,6 +1478,8 @@ static void aio_read_done(void *opaque, int ret) g_free(cmp_buf); } + block_acct_done(blk_get_stats(ctx->blk), &ctx->acct); + if (ctx->qflag) { goto out; } @@ -1436,7 +1518,7 @@ static void aio_read_help(void) "\n"); } -static int aio_read_f(BlockDriverState *bs, int argc, char **argv); +static int aio_read_f(BlockBackend *blk, int argc, char **argv); static const cmdinfo_t aio_read_cmd = { .name = "aio_read", @@ -1448,12 +1530,13 @@ static const cmdinfo_t aio_read_cmd = { .help = aio_read_help, }; -static int aio_read_f(BlockDriverState *bs, int argc, char **argv) +static int aio_read_f(BlockBackend *blk, int argc, char **argv) { int nr_iov, c; struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); - while ((c = getopt(argc, argv, "CP:qv")) != EOF) { + ctx->blk = blk; + while ((c = getopt(argc, argv, "CP:qv")) != -1) { switch (c) { case 'C': ctx->Cflag = 1; @@ -1485,7 +1568,7 @@ static int aio_read_f(BlockDriverState *bs, int argc, char **argv) ctx->offset = cvtnum(argv[optind]); if (ctx->offset < 0) { - printf("non-numeric length argument -- %s\n", argv[optind]); + print_cvtnum_err(ctx->offset, argv[optind]); g_free(ctx); return 0; } @@ -1494,20 +1577,24 @@ static int aio_read_f(BlockDriverState *bs, int argc, char **argv) if (ctx->offset & 0x1ff) { printf("offset %" PRId64 " is not sector aligned\n", ctx->offset); + block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_READ); g_free(ctx); return 0; } nr_iov = argc - optind; - ctx->buf = create_iovec(bs, &ctx->qiov, &argv[optind], nr_iov, 0xab); + ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, 0xab); if (ctx->buf == NULL) { + block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_READ); g_free(ctx); return 0; } gettimeofday(&ctx->t1, NULL); - bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov, - ctx->qiov.size >> 9, aio_read_done, ctx); + block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size, + BLOCK_ACCT_READ); + blk_aio_readv(blk, ctx->offset >> 9, &ctx->qiov, + ctx->qiov.size >> 9, aio_read_done, ctx); return 0; } @@ -1528,28 +1615,30 @@ static void aio_write_help(void) " -P, -- use different pattern to fill file\n" " -C, -- report statistics in a machine parsable format\n" " -q, -- quiet mode, do not show I/O statistics\n" +" -z, -- write zeroes using blk_aio_write_zeroes\n" "\n"); } -static int aio_write_f(BlockDriverState *bs, int argc, char **argv); +static int aio_write_f(BlockBackend *blk, int argc, char **argv); static const cmdinfo_t aio_write_cmd = { .name = "aio_write", .cfunc = aio_write_f, .argmin = 2, .argmax = -1, - .args = "[-Cq] [-P pattern ] off len [len..]", + .args = "[-Cqz] [-P pattern ] off len [len..]", .oneline = "asynchronously writes a number of bytes", .help = aio_write_help, }; -static int aio_write_f(BlockDriverState *bs, int argc, char **argv) +static int aio_write_f(BlockBackend *blk, int argc, char **argv) { int nr_iov, c; int pattern = 0xcd; struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); - while ((c = getopt(argc, argv, "CqP:")) != EOF) { + ctx->blk = blk; + while ((c = getopt(argc, argv, "CqP:z")) != -1) { switch (c) { case 'C': ctx->Cflag = 1; @@ -1564,6 +1653,9 @@ static int aio_write_f(BlockDriverState *bs, int argc, char **argv) return 0; } break; + case 'z': + ctx->zflag = 1; + break; default: g_free(ctx); return qemuio_command_usage(&aio_write_cmd); @@ -1575,9 +1667,21 @@ static int aio_write_f(BlockDriverState *bs, int argc, char **argv) return qemuio_command_usage(&aio_write_cmd); } + if (ctx->zflag && optind != argc - 2) { + printf("-z supports only a single length parameter\n"); + g_free(ctx); + return 0; + } + + if (ctx->zflag && ctx->Pflag) { + printf("-z and -P cannot be specified at the same time\n"); + g_free(ctx); + return 0; + } + ctx->offset = cvtnum(argv[optind]); if (ctx->offset < 0) { - printf("non-numeric length argument -- %s\n", argv[optind]); + print_cvtnum_err(ctx->offset, argv[optind]); g_free(ctx); return 0; } @@ -1586,26 +1690,48 @@ static int aio_write_f(BlockDriverState *bs, int argc, char **argv) if (ctx->offset & 0x1ff) { printf("offset %" PRId64 " is not sector aligned\n", ctx->offset); + block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_WRITE); g_free(ctx); return 0; } - nr_iov = argc - optind; - ctx->buf = create_iovec(bs, &ctx->qiov, &argv[optind], nr_iov, pattern); - if (ctx->buf == NULL) { - g_free(ctx); - return 0; - } + if (ctx->zflag) { + int64_t count = cvtnum(argv[optind]); + if (count < 0) { + print_cvtnum_err(count, argv[optind]); + g_free(ctx); + return 0; + } - gettimeofday(&ctx->t1, NULL); - bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov, - ctx->qiov.size >> 9, aio_write_done, ctx); + ctx->qiov.size = count; + blk_aio_write_zeroes(blk, ctx->offset >> 9, count >> 9, 0, + aio_write_done, ctx); + } else { + nr_iov = argc - optind; + ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, + pattern); + if (ctx->buf == NULL) { + block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_WRITE); + g_free(ctx); + return 0; + } + + gettimeofday(&ctx->t1, NULL); + block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size, + BLOCK_ACCT_WRITE); + + blk_aio_writev(blk, ctx->offset >> 9, &ctx->qiov, + ctx->qiov.size >> 9, aio_write_done, ctx); + } return 0; } -static int aio_flush_f(BlockDriverState *bs, int argc, char **argv) +static int aio_flush_f(BlockBackend *blk, int argc, char **argv) { - bdrv_drain_all(); + BlockAcctCookie cookie; + block_acct_start(blk_get_stats(blk), &cookie, 0, BLOCK_ACCT_FLUSH); + blk_drain_all(); + block_acct_done(blk_get_stats(blk), &cookie); return 0; } @@ -1615,9 +1741,9 @@ static const cmdinfo_t aio_flush_cmd = { .oneline = "completes all outstanding aio requests" }; -static int flush_f(BlockDriverState *bs, int argc, char **argv) +static int flush_f(BlockBackend *blk, int argc, char **argv) { - bdrv_flush(bs); + blk_flush(blk); return 0; } @@ -1628,18 +1754,18 @@ static const cmdinfo_t flush_cmd = { .oneline = "flush all in-core file state to disk", }; -static int truncate_f(BlockDriverState *bs, int argc, char **argv) +static int truncate_f(BlockBackend *blk, int argc, char **argv) { int64_t offset; int ret; offset = cvtnum(argv[1]); if (offset < 0) { - printf("non-numeric truncate argument -- %s\n", argv[1]); + print_cvtnum_err(offset, argv[1]); return 0; } - ret = bdrv_truncate(bs, offset); + ret = blk_truncate(blk, offset); if (ret < 0) { printf("truncate: %s\n", strerror(-ret)); return 0; @@ -1658,12 +1784,12 @@ static const cmdinfo_t truncate_cmd = { .oneline = "truncates the current file at the given offset", }; -static int length_f(BlockDriverState *bs, int argc, char **argv) +static int length_f(BlockBackend *blk, int argc, char **argv) { int64_t size; char s1[64]; - size = bdrv_getlength(bs); + size = blk_getlength(blk); if (size < 0) { printf("getlength: %s\n", strerror(-size)); return 0; @@ -1683,8 +1809,9 @@ static const cmdinfo_t length_cmd = { }; -static int info_f(BlockDriverState *bs, int argc, char **argv) +static int info_f(BlockBackend *blk, int argc, char **argv) { + BlockDriverState *bs = blk_bs(blk); BlockDriverInfo bdi; ImageInfoSpecific *spec_info; char s1[64], s2[64]; @@ -1742,7 +1869,7 @@ static void discard_help(void) "\n"); } -static int discard_f(BlockDriverState *bs, int argc, char **argv); +static int discard_f(BlockBackend *blk, int argc, char **argv); static const cmdinfo_t discard_cmd = { .name = "discard", @@ -1755,15 +1882,14 @@ static const cmdinfo_t discard_cmd = { .help = discard_help, }; -static int discard_f(BlockDriverState *bs, int argc, char **argv) +static int discard_f(BlockBackend *blk, int argc, char **argv) { struct timeval t1, t2; int Cflag = 0, qflag = 0; int c, ret; - int64_t offset; - int count; + int64_t offset, count; - while ((c = getopt(argc, argv, "Cq")) != EOF) { + while ((c = getopt(argc, argv, "Cq")) != -1) { switch (c) { case 'C': Cflag = 1; @@ -1782,20 +1908,25 @@ static int discard_f(BlockDriverState *bs, int argc, char **argv) offset = cvtnum(argv[optind]); if (offset < 0) { - printf("non-numeric length argument -- %s\n", argv[optind]); + print_cvtnum_err(offset, argv[optind]); return 0; } optind++; count = cvtnum(argv[optind]); if (count < 0) { - printf("non-numeric length argument -- %s\n", argv[optind]); + print_cvtnum_err(count, argv[optind]); + return 0; + } else if (count >> BDRV_SECTOR_BITS > INT_MAX) { + printf("length cannot exceed %"PRIu64", given %s\n", + (uint64_t)INT_MAX << BDRV_SECTOR_BITS, + argv[optind]); return 0; } gettimeofday(&t1, NULL); - ret = bdrv_discard(bs, offset >> BDRV_SECTOR_BITS, - count >> BDRV_SECTOR_BITS); + ret = blk_discard(blk, offset >> BDRV_SECTOR_BITS, + count >> BDRV_SECTOR_BITS); gettimeofday(&t2, NULL); if (ret < 0) { @@ -1813,17 +1944,17 @@ out: return 0; } -static int alloc_f(BlockDriverState *bs, int argc, char **argv) +static int alloc_f(BlockBackend *blk, int argc, char **argv) { - int64_t offset, sector_num; - int nb_sectors, remaining; + BlockDriverState *bs = blk_bs(blk); + int64_t offset, sector_num, nb_sectors, remaining; char s1[64]; - int num, sum_alloc; - int ret; + int num, ret; + int64_t sum_alloc; offset = cvtnum(argv[1]); if (offset < 0) { - printf("non-numeric offset argument -- %s\n", argv[1]); + print_cvtnum_err(offset, argv[1]); return 0; } else if (offset & 0x1ff) { printf("offset %" PRId64 " is not sector aligned\n", @@ -1834,7 +1965,11 @@ static int alloc_f(BlockDriverState *bs, int argc, char **argv) if (argc == 3) { nb_sectors = cvtnum(argv[2]); if (nb_sectors < 0) { - printf("non-numeric length argument -- %s\n", argv[2]); + print_cvtnum_err(nb_sectors, argv[2]); + return 0; + } else if (nb_sectors > INT_MAX) { + printf("length argument cannot exceed %d, given %s\n", + INT_MAX, argv[2]); return 0; } } else { @@ -1863,7 +1998,7 @@ static int alloc_f(BlockDriverState *bs, int argc, char **argv) cvtstr(offset, s1, sizeof(s1)); - printf("%d/%d sectors allocated at offset %s\n", + printf("%"PRId64"/%"PRId64" sectors allocated at offset %s\n", sum_alloc, nb_sectors, s1); return 0; } @@ -1910,20 +2045,27 @@ static int map_is_allocated(BlockDriverState *bs, int64_t sector_num, return firstret; } -static int map_f(BlockDriverState *bs, int argc, char **argv) +static int map_f(BlockBackend *blk, int argc, char **argv) { int64_t offset; - int64_t nb_sectors; + int64_t nb_sectors, total_sectors; char s1[64]; int64_t num; int ret; const char *retstr; offset = 0; - nb_sectors = bs->total_sectors; + total_sectors = blk_nb_sectors(blk); + if (total_sectors < 0) { + error_report("Failed to query image length: %s", + strerror(-total_sectors)); + return 0; + } + + nb_sectors = total_sectors; do { - ret = map_is_allocated(bs, offset, nb_sectors, &num); + ret = map_is_allocated(blk_bs(blk), offset, nb_sectors, &num); if (ret < 0) { error_report("Failed to get allocation status: %s", strerror(-ret)); return 0; @@ -1940,7 +2082,7 @@ static int map_f(BlockDriverState *bs, int argc, char **argv) offset += num; nb_sectors -= num; - } while (offset < bs->total_sectors); + } while (offset < total_sectors); return 0; } @@ -1954,11 +2096,111 @@ static const cmdinfo_t map_cmd = { .oneline = "prints the allocated areas of a file", }; -static int break_f(BlockDriverState *bs, int argc, char **argv) +static void reopen_help(void) +{ + printf( +"\n" +" Changes the open options of an already opened image\n" +"\n" +" Example:\n" +" 'reopen -o lazy-refcounts=on' - activates lazy refcount writeback on a qcow2 image\n" +"\n" +" -r, -- Reopen the image read-only\n" +" -c, -- Change the cache mode to the given value\n" +" -o, -- Changes block driver options (cf. 'open' command)\n" +"\n"); +} + +static int reopen_f(BlockBackend *blk, int argc, char **argv); + +static QemuOptsList reopen_opts = { + .name = "reopen", + .merge_lists = true, + .head = QTAILQ_HEAD_INITIALIZER(reopen_opts.head), + .desc = { + /* no elements => accept any params */ + { /* end of list */ } + }, +}; + +static const cmdinfo_t reopen_cmd = { + .name = "reopen", + .argmin = 0, + .argmax = -1, + .cfunc = reopen_f, + .args = "[-r] [-c cache] [-o options]", + .oneline = "reopens an image with new options", + .help = reopen_help, +}; + +static int reopen_f(BlockBackend *blk, int argc, char **argv) +{ + BlockDriverState *bs = blk_bs(blk); + QemuOpts *qopts; + QDict *opts; + int c; + int flags = bs->open_flags; + bool writethrough = !blk_enable_write_cache(blk); + + BlockReopenQueue *brq; + Error *local_err = NULL; + + while ((c = getopt(argc, argv, "c:o:r")) != -1) { + switch (c) { + case 'c': + if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) { + error_report("Invalid cache option: %s", optarg); + return 0; + } + break; + case 'o': + if (!qemu_opts_parse_noisily(&reopen_opts, optarg, 0)) { + qemu_opts_reset(&reopen_opts); + return 0; + } + break; + case 'r': + flags &= ~BDRV_O_RDWR; + break; + default: + qemu_opts_reset(&reopen_opts); + return qemuio_command_usage(&reopen_cmd); + } + } + + if (optind != argc) { + qemu_opts_reset(&reopen_opts); + return qemuio_command_usage(&reopen_cmd); + } + + if (writethrough != blk_enable_write_cache(blk) && + blk_get_attached_dev(blk)) + { + error_report("Cannot change cache.writeback: Device attached"); + qemu_opts_reset(&reopen_opts); + return 0; + } + + qopts = qemu_opts_find(&reopen_opts, NULL); + opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL; + qemu_opts_reset(&reopen_opts); + + brq = bdrv_reopen_queue(NULL, bs, opts, flags); + bdrv_reopen_multiple(brq, &local_err); + if (local_err) { + error_report_err(local_err); + } else { + blk_set_enable_write_cache(blk, !writethrough); + } + + return 0; +} + +static int break_f(BlockBackend *blk, int argc, char **argv) { int ret; - ret = bdrv_debug_breakpoint(bs, argv[1], argv[2]); + ret = bdrv_debug_breakpoint(blk_bs(blk), argv[1], argv[2]); if (ret < 0) { printf("Could not set breakpoint: %s\n", strerror(-ret)); } @@ -1966,11 +2208,11 @@ static int break_f(BlockDriverState *bs, int argc, char **argv) return 0; } -static int remove_break_f(BlockDriverState *bs, int argc, char **argv) +static int remove_break_f(BlockBackend *blk, int argc, char **argv) { int ret; - ret = bdrv_debug_remove_breakpoint(bs, argv[1]); + ret = bdrv_debug_remove_breakpoint(blk_bs(blk), argv[1]); if (ret < 0) { printf("Could not remove breakpoint %s: %s\n", argv[1], strerror(-ret)); } @@ -1997,11 +2239,11 @@ static const cmdinfo_t remove_break_cmd = { .oneline = "remove a breakpoint by tag", }; -static int resume_f(BlockDriverState *bs, int argc, char **argv) +static int resume_f(BlockBackend *blk, int argc, char **argv) { int ret; - ret = bdrv_debug_resume(bs, argv[1]); + ret = bdrv_debug_resume(blk_bs(blk), argv[1]); if (ret < 0) { printf("Could not resume request: %s\n", strerror(-ret)); } @@ -2018,10 +2260,10 @@ static const cmdinfo_t resume_cmd = { .oneline = "resumes the request tagged as tag", }; -static int wait_break_f(BlockDriverState *bs, int argc, char **argv) +static int wait_break_f(BlockBackend *blk, int argc, char **argv) { - while (!bdrv_debug_is_suspended(bs, argv[1])) { - aio_poll(bdrv_get_aio_context(bs), true); + while (!bdrv_debug_is_suspended(blk_bs(blk), argv[1])) { + aio_poll(blk_get_aio_context(blk), true); } return 0; @@ -2036,7 +2278,7 @@ static const cmdinfo_t wait_break_cmd = { .oneline = "waits for the suspension of a request", }; -static int abort_f(BlockDriverState *bs, int argc, char **argv) +static int abort_f(BlockBackend *blk, int argc, char **argv) { abort(); } @@ -2062,7 +2304,7 @@ static void sigraise_help(void) "\n", SIGTERM); } -static int sigraise_f(BlockDriverState *bs, int argc, char **argv); +static int sigraise_f(BlockBackend *blk, int argc, char **argv); static const cmdinfo_t sigraise_cmd = { .name = "sigraise", @@ -2075,11 +2317,15 @@ static const cmdinfo_t sigraise_cmd = { .help = sigraise_help, }; -static int sigraise_f(BlockDriverState *bs, int argc, char **argv) +static int sigraise_f(BlockBackend *blk, int argc, char **argv) { - int sig = cvtnum(argv[1]); + int64_t sig = cvtnum(argv[1]); if (sig < 0) { - printf("non-numeric signal number argument -- %s\n", argv[1]); + print_cvtnum_err(sig, argv[1]); + return 0; + } else if (sig > NSIG) { + printf("signal argument '%s' is too large to be a valid signal\n", + argv[1]); return 0; } @@ -2099,7 +2345,7 @@ static void sleep_cb(void *opaque) *expired = true; } -static int sleep_f(BlockDriverState *bs, int argc, char **argv) +static int sleep_f(BlockBackend *blk, int argc, char **argv) { char *endptr; long ms; @@ -2168,7 +2414,7 @@ static void help_all(void) printf("\nUse 'help commandname' for extended help.\n"); } -static int help_f(BlockDriverState *bs, int argc, char **argv) +static int help_f(BlockBackend *blk, int argc, char **argv) { const cmdinfo_t *ct; @@ -2198,7 +2444,7 @@ static const cmdinfo_t help_cmd = { .oneline = "help for one or all commands", }; -bool qemuio_command(BlockDriverState *bs, const char *cmd) +bool qemuio_command(BlockBackend *blk, const char *cmd) { char *input; const cmdinfo_t *ct; @@ -2211,7 +2457,7 @@ bool qemuio_command(BlockDriverState *bs, const char *cmd) if (c) { ct = find_command(v[0]); if (ct) { - done = command(bs, ct, c, v); + done = command(blk, ct, c, v); } else { fprintf(stderr, "command \"%s\" not found\n", v[0]); } @@ -2241,6 +2487,7 @@ static void __attribute((constructor)) init_qemuio_commands(void) qemuio_add_command(&discard_cmd); qemuio_add_command(&alloc_cmd); qemuio_add_command(&map_cmd); + qemuio_add_command(&reopen_cmd); qemuio_add_command(&break_cmd); qemuio_add_command(&remove_break_cmd); qemuio_add_command(&resume_cmd);