X-Git-Url: https://git.proxmox.com/?p=mirror_qemu.git;a=blobdiff_plain;f=qemu-io-cmds.c;h=8904733961ed4e3707fe6c72d7542b2469372434;hp=5bf5f281785dfa62920a40afb72fba9f91d4b512;hb=c4107e8208d0222f9b328691b519aaee4101db87;hpb=3b2a4d3901b8b45840c0e0495ee1cbd13123739d diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index 5bf5f28178..8904733961 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -10,6 +10,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "qapi/qmp/qdict.h" #include "qemu-io.h" #include "sysemu/block-backend.h" #include "block/block.h" @@ -113,7 +114,7 @@ static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc, } } - optind = 0; + qemu_reset_optind(); return ct->cfunc(blk, argc, argv); } @@ -247,20 +248,21 @@ static void cvtstr(double value, char *str, size_t size) -static struct timeval tsub(struct timeval t1, struct timeval t2) +static struct timespec tsub(struct timespec t1, struct timespec t2) { - t1.tv_usec -= t2.tv_usec; - if (t1.tv_usec < 0) { - t1.tv_usec += 1000000; + t1.tv_nsec -= t2.tv_nsec; + if (t1.tv_nsec < 0) { + t1.tv_nsec += NANOSECONDS_PER_SECOND; t1.tv_sec--; } t1.tv_sec -= t2.tv_sec; return t1; } -static double tdiv(double value, struct timeval tv) +static double tdiv(double value, struct timespec tv) { - return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0)); + double seconds = tv.tv_sec + (tv.tv_nsec / 1e9); + return value / seconds; } #define HOURS(sec) ((sec) / (60 * 60)) @@ -273,29 +275,27 @@ enum { VERBOSE_FIXED_TIME = 0x2, }; -static void timestr(struct timeval *tv, char *ts, size_t size, int format) +static void timestr(struct timespec *tv, char *ts, size_t size, int format) { - double usec = (double)tv->tv_usec / 1000000.0; + double frac_sec = tv->tv_nsec / 1e9; if (format & TERSE_FIXED_TIME) { if (!HOURS(tv->tv_sec)) { - snprintf(ts, size, "%u:%02u.%02u", - (unsigned int) MINUTES(tv->tv_sec), - (unsigned int) SECONDS(tv->tv_sec), - (unsigned int) (usec * 100)); + snprintf(ts, size, "%u:%05.2f", + (unsigned int) MINUTES(tv->tv_sec), + SECONDS(tv->tv_sec) + frac_sec); return; } format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */ } if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) { - snprintf(ts, size, "%u:%02u:%02u.%02u", + snprintf(ts, size, "%u:%02u:%05.2f", (unsigned int) HOURS(tv->tv_sec), (unsigned int) MINUTES(tv->tv_sec), - (unsigned int) SECONDS(tv->tv_sec), - (unsigned int) (usec * 100)); + SECONDS(tv->tv_sec) + frac_sec); } else { - snprintf(ts, size, "0.%04u sec", (unsigned int) (usec * 10000)); + snprintf(ts, size, "%05.2f sec", frac_sec); } } @@ -375,7 +375,7 @@ static void dump_buffer(const void *buffer, int64_t offset, int64_t len) } } -static void print_report(const char *op, struct timeval *t, int64_t offset, +static void print_report(const char *op, struct timespec *t, int64_t offset, int64_t count, int64_t total, int cnt, bool Cflag) { char s1[64], s2[64], ts[64]; @@ -537,7 +537,7 @@ static int do_write_compressed(BlockBackend *blk, char *buf, int64_t offset, { int ret; - if (bytes >> 9 > BDRV_REQUEST_MAX_SECTORS) { + if (bytes > BDRV_REQUEST_MAX_BYTES) { return -ERANGE; } @@ -648,7 +648,7 @@ static const cmdinfo_t read_cmd = { static int read_f(BlockBackend *blk, int argc, char **argv) { - struct timeval t1, t2; + struct timespec t1, t2; bool Cflag = false, qflag = false, vflag = false; bool Pflag = false, sflag = false, lflag = false, bflag = false; int c, cnt, ret; @@ -757,13 +757,13 @@ static int read_f(BlockBackend *blk, int argc, char **argv) buf = qemu_io_alloc(blk, count, 0xab); - gettimeofday(&t1, NULL); + clock_gettime(CLOCK_MONOTONIC, &t1); if (bflag) { ret = do_load_vmstate(blk, buf, offset, count, &total); } else { ret = do_pread(blk, buf, offset, count, &total); } - gettimeofday(&t2, NULL); + clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { printf("read failed: %s\n", strerror(-ret)); @@ -835,7 +835,7 @@ static const cmdinfo_t readv_cmd = { static int readv_f(BlockBackend *blk, int argc, char **argv) { - struct timeval t1, t2; + struct timespec t1, t2; bool Cflag = false, qflag = false, vflag = false; int c, cnt, ret; char *buf; @@ -890,9 +890,9 @@ static int readv_f(BlockBackend *blk, int argc, char **argv) return -EINVAL; } - gettimeofday(&t1, NULL); + clock_gettime(CLOCK_MONOTONIC, &t1); ret = do_aio_readv(blk, &qiov, offset, &total); - gettimeofday(&t2, NULL); + clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { printf("readv failed: %s\n", strerror(-ret)); @@ -907,7 +907,7 @@ static int readv_f(BlockBackend *blk, int argc, char **argv) memset(cmp_buf, pattern, qiov.size); if (memcmp(buf, cmp_buf, qiov.size)) { printf("Pattern verification failed at offset %" - PRId64 ", %zd bytes\n", offset, qiov.size); + PRId64 ", %zu bytes\n", offset, qiov.size); ret = -EINVAL; } g_free(cmp_buf); @@ -945,6 +945,7 @@ static void write_help(void) " -b, -- write to the VM state rather than the virtual disk\n" " -c, -- write compressed data with blk_write_compressed\n" " -f, -- use Force Unit Access semantics\n" +" -n, -- with -z, don't allow slow fallback\n" " -p, -- ignored for backwards compatibility\n" " -P, -- use different pattern to fill file\n" " -C, -- report statistics in a machine parsable format\n" @@ -963,14 +964,14 @@ static const cmdinfo_t write_cmd = { .perm = BLK_PERM_WRITE, .argmin = 2, .argmax = -1, - .args = "[-bcCfquz] [-P pattern] off len", + .args = "[-bcCfnquz] [-P pattern] off len", .oneline = "writes a number of bytes at a specified offset", .help = write_help, }; static int write_f(BlockBackend *blk, int argc, char **argv) { - struct timeval t1, t2; + struct timespec t1, t2; bool Cflag = false, qflag = false, bflag = false; bool Pflag = false, zflag = false, cflag = false; int flags = 0; @@ -982,7 +983,7 @@ static int write_f(BlockBackend *blk, int argc, char **argv) int64_t total = 0; int pattern = 0xcd; - while ((c = getopt(argc, argv, "bcCfpP:quz")) != -1) { + while ((c = getopt(argc, argv, "bcCfnpP:quz")) != -1) { switch (c) { case 'b': bflag = true; @@ -996,6 +997,9 @@ static int write_f(BlockBackend *blk, int argc, char **argv) case 'f': flags |= BDRV_REQ_FUA; break; + case 'n': + flags |= BDRV_REQ_NO_FALLBACK; + break; case 'p': /* Ignored for backwards compatibility */ break; @@ -1036,6 +1040,11 @@ static int write_f(BlockBackend *blk, int argc, char **argv) return -EINVAL; } + if ((flags & BDRV_REQ_NO_FALLBACK) && !zflag) { + printf("-n requires -z to be specified\n"); + return -EINVAL; + } + if ((flags & BDRV_REQ_MAY_UNMAP) && !zflag) { printf("-u requires -z to be specified\n"); return -EINVAL; @@ -1081,7 +1090,7 @@ static int write_f(BlockBackend *blk, int argc, char **argv) buf = qemu_io_alloc(blk, count, pattern); } - gettimeofday(&t1, NULL); + clock_gettime(CLOCK_MONOTONIC, &t1); if (bflag) { ret = do_save_vmstate(blk, buf, offset, count, &total); } else if (zflag) { @@ -1091,7 +1100,7 @@ static int write_f(BlockBackend *blk, int argc, char **argv) } else { ret = do_pwrite(blk, buf, offset, count, flags, &total); } - gettimeofday(&t2, NULL); + clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { printf("write failed: %s\n", strerror(-ret)); @@ -1150,7 +1159,7 @@ static const cmdinfo_t writev_cmd = { static int writev_f(BlockBackend *blk, int argc, char **argv) { - struct timeval t1, t2; + struct timespec t1, t2; bool Cflag = false, qflag = false; int flags = 0; int c, cnt, ret; @@ -1203,9 +1212,9 @@ static int writev_f(BlockBackend *blk, int argc, char **argv) return -EINVAL; } - gettimeofday(&t1, NULL); + clock_gettime(CLOCK_MONOTONIC, &t1); ret = do_aio_writev(blk, &qiov, offset, flags, &total); - gettimeofday(&t2, NULL); + clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { printf("writev failed: %s\n", strerror(-ret)); @@ -1240,15 +1249,15 @@ struct aio_ctx { bool zflag; BlockAcctCookie acct; int pattern; - struct timeval t1; + struct timespec t1; }; static void aio_write_done(void *opaque, int ret) { struct aio_ctx *ctx = opaque; - struct timeval t2; + struct timespec t2; - gettimeofday(&t2, NULL); + clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { @@ -1278,9 +1287,9 @@ out: static void aio_read_done(void *opaque, int ret) { struct aio_ctx *ctx = opaque; - struct timeval t2; + struct timespec t2; - gettimeofday(&t2, NULL); + clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { printf("readv failed: %s\n", strerror(-ret)); @@ -1294,7 +1303,7 @@ static void aio_read_done(void *opaque, int ret) memset(cmp_buf, ctx->pattern, ctx->qiov.size); if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) { printf("Pattern verification failed at offset %" - PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size); + PRId64 ", %zu bytes\n", ctx->offset, ctx->qiov.size); } g_free(cmp_buf); } @@ -1415,7 +1424,7 @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv) return -EINVAL; } - gettimeofday(&ctx->t1, NULL); + clock_gettime(CLOCK_MONOTONIC, &ctx->t1); block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size, BLOCK_ACCT_READ); blk_aio_preadv(blk, ctx->offset, &ctx->qiov, 0, aio_read_done, ctx); @@ -1560,7 +1569,7 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) return -EINVAL; } - gettimeofday(&ctx->t1, NULL); + clock_gettime(CLOCK_MONOTONIC, &ctx->t1); block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size, BLOCK_ACCT_WRITE); @@ -1660,6 +1669,7 @@ static int info_f(BlockBackend *blk, int argc, char **argv) BlockDriverState *bs = blk_bs(blk); BlockDriverInfo bdi; ImageInfoSpecific *spec_info; + Error *local_err = NULL; char s1[64], s2[64]; int ret; @@ -1681,10 +1691,14 @@ static int info_f(BlockBackend *blk, int argc, char **argv) printf("cluster size: %s\n", s1); printf("vm state offset: %s\n", s2); - spec_info = bdrv_get_specific_info(bs); + spec_info = bdrv_get_specific_info(bs, &local_err); + if (local_err) { + error_report_err(local_err); + return -EIO; + } if (spec_info) { printf("Format specific information:\n"); - bdrv_image_info_specific_dump(fprintf, stdout, spec_info); + bdrv_image_info_specific_dump(spec_info); qapi_free_ImageInfoSpecific(spec_info); } @@ -1731,7 +1745,7 @@ static const cmdinfo_t discard_cmd = { static int discard_f(BlockBackend *blk, int argc, char **argv) { - struct timeval t1, t2; + struct timespec t1, t2; bool Cflag = false, qflag = false; int c, ret; int64_t offset, bytes; @@ -1766,16 +1780,15 @@ static int discard_f(BlockBackend *blk, int argc, char **argv) if (bytes < 0) { print_cvtnum_err(bytes, argv[optind]); return bytes; - } else if (bytes >> BDRV_SECTOR_BITS > BDRV_REQUEST_MAX_SECTORS) { + } else if (bytes > BDRV_REQUEST_MAX_BYTES) { printf("length cannot exceed %"PRIu64", given %s\n", - (uint64_t)BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS, - argv[optind]); + (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]); return -EINVAL; } - gettimeofday(&t1, NULL); + clock_gettime(CLOCK_MONOTONIC, &t1); ret = blk_pdiscard(blk, offset, bytes); - gettimeofday(&t2, NULL); + clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { printf("discard failed: %s\n", strerror(-ret)); @@ -1978,6 +1991,7 @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) int flags = bs->open_flags; bool writethrough = !blk_enable_write_cache(blk); bool has_rw_option = false; + bool has_cache_option = false; BlockReopenQueue *brq; Error *local_err = NULL; @@ -1989,6 +2003,7 @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) error_report("Invalid cache option: %s", optarg); return -EINVAL; } + has_cache_option = true; break; case 'o': if (!qemu_opts_parse_noisily(&reopen_opts, optarg, 0)) { @@ -2025,7 +2040,7 @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) return -EINVAL; } - if (writethrough != blk_enable_write_cache(blk) && + if (!writethrough != blk_enable_write_cache(blk) && blk_get_attached_dev(blk)) { error_report("Cannot change cache.writeback: Device attached"); @@ -2046,12 +2061,34 @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) } qopts = qemu_opts_find(&reopen_opts, NULL); - opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL; + opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : qdict_new(); qemu_opts_reset(&reopen_opts); + if (qdict_haskey(opts, BDRV_OPT_READ_ONLY)) { + if (has_rw_option) { + error_report("Cannot set both -r/-w and '" BDRV_OPT_READ_ONLY "'"); + qobject_unref(opts); + return -EINVAL; + } + } else { + qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !(flags & BDRV_O_RDWR)); + } + + if (qdict_haskey(opts, BDRV_OPT_CACHE_DIRECT) || + qdict_haskey(opts, BDRV_OPT_CACHE_NO_FLUSH)) { + if (has_cache_option) { + error_report("Cannot set both -c and the cache options"); + qobject_unref(opts); + return -EINVAL; + } + } else { + qdict_put_bool(opts, BDRV_OPT_CACHE_DIRECT, flags & BDRV_O_NOCACHE); + qdict_put_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, flags & BDRV_O_NO_FLUSH); + } + bdrv_subtree_drained_begin(bs); - brq = bdrv_reopen_queue(NULL, bs, opts, flags); - bdrv_reopen_multiple(bdrv_get_aio_context(bs), brq, &local_err); + brq = bdrv_reopen_queue(NULL, bs, opts, true); + bdrv_reopen_multiple(brq, &local_err); bdrv_subtree_drained_end(bs); if (local_err) {