X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=qemu-io-cmds.c;h=53477e1e176c73b0dc8142766cec07adecf9e1fb;hb=c147b5153e733a14fc65d2098e7036754c185ad1;hp=ffbcf31cfc6389e7b615bfc9529dc3e9629220f8;hpb=6e8d2b654656830877937ba02bb8ea1c4945a1fc;p=mirror_qemu.git diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index ffbcf31cfc..53477e1e17 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -9,11 +9,18 @@ */ #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" #define CMD_NOFILE_OK 0x01 -int qemuio_misalign; +bool qemuio_misalign; static cmdinfo_t *cmdtab; static int ncmds; @@ -26,7 +33,7 @@ static int compare_cmdname(const void *a, const void *b) void qemuio_add_command(const cmdinfo_t *ci) { - cmdtab = g_realloc(cmdtab, ++ncmds * sizeof(*cmdtab)); + cmdtab = g_renew(cmdinfo_t, cmdtab, ++ncmds); cmdtab[ncmds - 1] = *ci; qsort(cmdtab, ncmds, sizeof(*cmdtab), compare_cmdname); } @@ -37,24 +44,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; } @@ -75,7 +82,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) @@ -92,27 +99,33 @@ static const cmdinfo_t *find_command(const char *cmd) return NULL; } +/* Invoke fn() for commands with a matching prefix */ +void qemuio_complete_command(const char *input, + void (*fn)(const char *cmd, void *opaque), + void *opaque) +{ + cmdinfo_t *ct; + size_t input_len = strlen(input); + + for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) { + if (strncmp(input, ct->name, input_len) == 0) { + fn(ct->name, opaque); + } + } +} + static char **breakline(char *input, int *count) { int c = 0; char *p; - char **rval = g_malloc0(sizeof(char *)); - char **tmp; + char **rval = g_new0(char *, 1); while (rval && (p = qemu_strsep(&input, " ")) != NULL) { if (!*p) { continue; } c++; - tmp = g_realloc(rval, sizeof(*rval) * (c + 1)); - if (!tmp) { - g_free(rval); - rval = NULL; - c = 0; - break; - } else { - rval = tmp; - } + rval = g_renew(char *, rval, (c + 1)); rval[c - 1] = p; rval[c] = NULL; } @@ -258,14 +271,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; @@ -331,7 +344,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); @@ -368,7 +381,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]); @@ -380,12 +393,12 @@ fail: return buf; } -static int do_read(BlockDriverState *bs, char *buf, int64_t offset, int count, +static int do_read(BlockBackend *blk, char *buf, int64_t offset, int count, int *total) { int ret; - ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9); + ret = blk_read(blk, offset >> 9, (uint8_t *)buf, count >> 9); if (ret < 0) { return ret; } @@ -393,12 +406,12 @@ 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, +static int do_write(BlockBackend *blk, char *buf, int64_t offset, int count, int *total) { int ret; - ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9); + ret = blk_write(blk, offset >> 9, (uint8_t *)buf, count >> 9); if (ret < 0) { return ret; } @@ -406,20 +419,20 @@ 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, +static int do_pread(BlockBackend *blk, char *buf, int64_t offset, int count, int *total) { - *total = bdrv_pread(bs, offset, (uint8_t *)buf, count); + *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, +static int do_pwrite(BlockBackend *blk, char *buf, int64_t offset, int count, int *total) { - *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count); + *total = blk_pwrite(blk, offset, (uint8_t *)buf, count); if (*total < 0) { return *total; } @@ -427,7 +440,7 @@ 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; @@ -439,8 +452,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); + 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; @@ -450,12 +463,12 @@ 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, +static int do_co_write_zeroes(BlockBackend *blk, int64_t offset, int count, int *total) { Coroutine *co; CoWriteZeroes data = { - .bs = bs, + .blk = blk, .offset = offset, .count = count, .total = total, @@ -465,7 +478,7 @@ static int do_co_write_zeroes(BlockDriverState *bs, int64_t offset, int count, co = qemu_coroutine_create(co_write_zeroes_entry); qemu_coroutine_enter(co, &data); while (!data.done) { - qemu_aio_wait(); + aio_poll(blk_get_aio_context(blk), true); } if (data.ret < 0) { return data.ret; @@ -474,12 +487,12 @@ 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, +static int do_write_compressed(BlockBackend *blk, char *buf, int64_t offset, int count, int *total) { int ret; - ret = bdrv_write_compressed(bs, offset >> 9, (uint8_t *)buf, count >> 9); + ret = blk_write_compressed(blk, offset >> 9, (uint8_t *)buf, count >> 9); if (ret < 0) { return ret; } @@ -487,20 +500,20 @@ 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, +static int do_load_vmstate(BlockBackend *blk, char *buf, int64_t offset, int count, int *total) { - *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count); + *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, +static int do_save_vmstate(BlockBackend *blk, char *buf, int64_t offset, int count, int *total) { - *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count); + *total = blk_save_vmstate(blk, (uint8_t *)buf, offset, count); if (*total < 0) { return *total; } @@ -513,13 +526,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); } @@ -528,13 +541,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); } @@ -558,7 +571,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; @@ -574,7 +587,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; } @@ -600,7 +613,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" @@ -608,7 +621,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", @@ -621,7 +634,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; @@ -634,7 +647,7 @@ static int read_f(BlockDriverState *bs, int argc, char **argv) int total = 0; int pattern = 0, 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; @@ -727,15 +740,15 @@ static int read_f(BlockDriverState *bs, int argc, char **argv) } } - 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); @@ -792,7 +805,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", @@ -804,7 +817,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; @@ -818,7 +831,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; @@ -860,13 +873,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) { @@ -914,16 +927,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", @@ -936,7 +949,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; @@ -949,7 +962,7 @@ static int write_f(BlockDriverState *bs, int argc, char **argv) int 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; @@ -1023,20 +1036,20 @@ static int write_f(BlockDriverState *bs, int argc, char **argv) } 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); @@ -1069,7 +1082,7 @@ writev_help(void) " writes a range of bytes from the given offset source from multiple buffers\n" "\n" " Example:\n" -" 'write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n" +" 'writev 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n" "\n" " Writes into a segment of the currently open file, using a buffer\n" " filled with a set pattern (0xcdcdcdcd).\n" @@ -1079,7 +1092,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", @@ -1091,7 +1104,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; @@ -1104,7 +1117,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; @@ -1141,13 +1154,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) { @@ -1188,7 +1201,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", @@ -1200,7 +1213,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; @@ -1216,7 +1229,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; @@ -1246,9 +1259,9 @@ static int multiwrite_f(BlockDriverState *bs, int argc, char **argv) } } - reqs = g_malloc0(nr_reqs * sizeof(*reqs)); - buf = g_malloc0(nr_reqs * sizeof(*buf)); - qiovs = g_malloc(nr_reqs * sizeof(*qiovs)); + reqs = g_new0(BlockRequest, nr_reqs); + buf = g_new0(char *, nr_reqs); + qiovs = g_new(QEMUIOVector, nr_reqs); for (i = 0; i < nr_reqs && optind < argc; i++) { int j; @@ -1281,7 +1294,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; } @@ -1299,7 +1312,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) { @@ -1328,6 +1341,7 @@ out: } struct aio_ctx { + BlockBackend *blk; QEMUIOVector qiov; int64_t offset; char *buf; @@ -1335,6 +1349,7 @@ struct aio_ctx { int vflag; int Cflag; int Pflag; + BlockAcctCookie acct; int pattern; struct timeval t1; }; @@ -1352,6 +1367,8 @@ static void aio_write_done(void *opaque, int ret) goto out; } + block_acct_done(blk_get_stats(ctx->blk), &ctx->acct); + if (ctx->qflag) { goto out; } @@ -1389,6 +1406,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; } @@ -1427,7 +1446,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", @@ -1439,12 +1458,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; @@ -1490,15 +1510,17 @@ static int aio_read_f(BlockDriverState *bs, int argc, char **argv) } 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) { 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; } @@ -1522,7 +1544,7 @@ static void aio_write_help(void) "\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", @@ -1534,13 +1556,14 @@ static const cmdinfo_t aio_write_cmd = { .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:")) != -1) { switch (c) { case 'C': ctx->Cflag = 1; @@ -1582,21 +1605,23 @@ static int aio_write_f(BlockDriverState *bs, int argc, char **argv) } nr_iov = argc - optind; - ctx->buf = create_iovec(bs, &ctx->qiov, &argv[optind], nr_iov, pattern); + ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, pattern); if (ctx->buf == NULL) { 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); + 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(); + blk_drain_all(); return 0; } @@ -1606,9 +1631,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; } @@ -1619,7 +1644,7 @@ 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; @@ -1630,7 +1655,7 @@ static int truncate_f(BlockDriverState *bs, int argc, char **argv) return 0; } - ret = bdrv_truncate(bs, offset); + ret = blk_truncate(blk, offset); if (ret < 0) { printf("truncate: %s\n", strerror(-ret)); return 0; @@ -1649,12 +1674,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; @@ -1674,9 +1699,11 @@ 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]; int ret; @@ -1698,6 +1725,13 @@ static int info_f(BlockDriverState *bs, int argc, char **argv) printf("cluster size: %s\n", s1); printf("vm state offset: %s\n", s2); + spec_info = bdrv_get_specific_info(bs); + if (spec_info) { + printf("Format specific information:\n"); + bdrv_image_info_specific_dump(fprintf, stdout, spec_info); + qapi_free_ImageInfoSpecific(spec_info); + } + return 0; } @@ -1725,7 +1759,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", @@ -1738,7 +1772,7 @@ 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; @@ -1746,7 +1780,7 @@ static int discard_f(BlockDriverState *bs, int argc, char **argv) int64_t offset; int count; - while ((c = getopt(argc, argv, "Cq")) != EOF) { + while ((c = getopt(argc, argv, "Cq")) != -1) { switch (c) { case 'C': Cflag = 1; @@ -1777,8 +1811,8 @@ static int discard_f(BlockDriverState *bs, int argc, char **argv) } 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) { @@ -1796,8 +1830,9 @@ out: return 0; } -static int alloc_f(BlockDriverState *bs, int argc, char **argv) +static int alloc_f(BlockBackend *blk, int argc, char **argv) { + BlockDriverState *bs = blk_bs(blk); int64_t offset, sector_num; int nb_sectors, remaining; char s1[64]; @@ -1829,6 +1864,10 @@ static int alloc_f(BlockDriverState *bs, int argc, char **argv) sector_num = offset >> 9; while (remaining) { ret = bdrv_is_allocated(bs, sector_num, remaining, &num); + if (ret < 0) { + printf("is_allocated failed: %s\n", strerror(-ret)); + return 0; + } sector_num += num; remaining -= num; if (ret) { @@ -1879,7 +1918,7 @@ static int map_is_allocated(BlockDriverState *bs, int64_t sector_num, num_checked = MIN(nb_sectors, INT_MAX); ret = bdrv_is_allocated(bs, sector_num, num_checked, &num); - if (ret == firstret) { + if (ret == firstret && num) { *pnum += num; } else { break; @@ -1889,23 +1928,33 @@ 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; + } else if (!num) { + error_report("Unexpected end of image"); + return 0; } retstr = ret ? " allocated" : "not allocated"; @@ -1916,7 +1965,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; } @@ -1930,11 +1979,11 @@ 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 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)); } @@ -1942,6 +1991,18 @@ static int break_f(BlockDriverState *bs, int argc, char **argv) return 0; } +static int remove_break_f(BlockBackend *blk, int argc, char **argv) +{ + int ret; + + 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)); + } + + return 0; +} + static const cmdinfo_t break_cmd = { .name = "break", .argmin = 2, @@ -1952,11 +2013,20 @@ static const cmdinfo_t break_cmd = { "request as tag", }; -static int resume_f(BlockDriverState *bs, int argc, char **argv) +static const cmdinfo_t remove_break_cmd = { + .name = "remove_break", + .argmin = 1, + .argmax = 1, + .cfunc = remove_break_f, + .args = "tag", + .oneline = "remove a breakpoint by tag", +}; + +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)); } @@ -1973,10 +2043,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])) { - qemu_aio_wait(); + while (!bdrv_debug_is_suspended(blk_bs(blk), argv[1])) { + aio_poll(blk_get_aio_context(blk), true); } return 0; @@ -1991,7 +2061,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(); } @@ -2003,6 +2073,91 @@ static const cmdinfo_t abort_cmd = { .oneline = "simulate a program crash using abort(3)", }; +static void sigraise_help(void) +{ + printf( +"\n" +" raises the given signal\n" +"\n" +" Example:\n" +" 'sigraise %i' - raises SIGTERM\n" +"\n" +" Invokes raise(signal), where \"signal\" is the mandatory integer argument\n" +" given to sigraise.\n" +"\n", SIGTERM); +} + +static int sigraise_f(BlockBackend *blk, int argc, char **argv); + +static const cmdinfo_t sigraise_cmd = { + .name = "sigraise", + .cfunc = sigraise_f, + .argmin = 1, + .argmax = 1, + .flags = CMD_NOFILE_OK, + .args = "signal", + .oneline = "raises a signal", + .help = sigraise_help, +}; + +static int sigraise_f(BlockBackend *blk, int argc, char **argv) +{ + int sig = cvtnum(argv[1]); + if (sig < 0) { + printf("non-numeric signal number argument -- %s\n", argv[1]); + return 0; + } + + /* Using raise() to kill this process does not necessarily flush all open + * streams. At least stdout and stderr (although the latter should be + * non-buffered anyway) should be flushed, though. */ + fflush(stdout); + fflush(stderr); + + raise(sig); + return 0; +} + +static void sleep_cb(void *opaque) +{ + bool *expired = opaque; + *expired = true; +} + +static int sleep_f(BlockBackend *blk, int argc, char **argv) +{ + char *endptr; + long ms; + struct QEMUTimer *timer; + bool expired = false; + + ms = strtol(argv[1], &endptr, 0); + if (ms < 0 || *endptr != '\0') { + printf("%s is not a valid number\n", argv[1]); + return 0; + } + + timer = timer_new_ns(QEMU_CLOCK_HOST, sleep_cb, &expired); + timer_mod(timer, qemu_clock_get_ns(QEMU_CLOCK_HOST) + SCALE_MS * ms); + + while (!expired) { + main_loop_wait(false); + } + + timer_free(timer); + + return 0; +} + +static const cmdinfo_t sleep_cmd = { + .name = "sleep", + .argmin = 1, + .argmax = 1, + .cfunc = sleep_f, + .flags = CMD_NOFILE_OK, + .oneline = "waits for the given value in milliseconds", +}; + static void help_oneline(const char *cmd, const cmdinfo_t *ct) { if (cmd) { @@ -2038,7 +2193,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; @@ -2068,7 +2223,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; @@ -2081,7 +2236,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]); } @@ -2112,7 +2267,10 @@ static void __attribute((constructor)) init_qemuio_commands(void) qemuio_add_command(&alloc_cmd); qemuio_add_command(&map_cmd); qemuio_add_command(&break_cmd); + qemuio_add_command(&remove_break_cmd); qemuio_add_command(&resume_cmd); qemuio_add_command(&wait_break_cmd); qemuio_add_command(&abort_cmd); + qemuio_add_command(&sleep_cmd); + qemuio_add_command(&sigraise_cmd); }