[Spice-commits] 53 commits - arch_init.c block.c block/qcow2-refcount.c blockdev.c bsd-user/main.c configure coroutine-sigaltstack.c coroutine-ucontext.c hmp-commands.hx hw/block-common.h hw/ide hw/pc.h hw/pc_piix.c hw/pc_q35.c hw/scsi-disk.c include/block include/migration include/qemu include/qemu-common.h linux-user/main.c migration.c qapi-schema.json qemu-coroutine.c qemu-doc.texi qemu-img-cmds.hx qemu-img.c qemu-img.texi qemu-io.c qemu-log.c qemu-nbd.c qemu-nbd.texi qemu-options.hx slirp/socket.c target-arm/translate.c target-i386/helper.h target-i386/int_helper.c target-i386/translate.c target-ppc/translate.c tcg/tci tests/check-qjson.c tests/qemu-iotests tests/test-coroutine.c ui/Makefile.objs ui/gtk.c vl.c
Gerd Hoffmann
kraxel at kemper.freedesktop.org
Thu Feb 28 04:41:06 PST 2013
arch_init.c | 1
block.c | 80 ++++-
block/qcow2-refcount.c | 52 ++-
blockdev.c | 41 ++
bsd-user/main.c | 18 -
configure | 27 +
coroutine-sigaltstack.c | 43 --
coroutine-ucontext.c | 43 --
hmp-commands.hx | 4
hw/block-common.h | 2
hw/ide/qdev.c | 5
hw/pc.h | 31 +
hw/pc_piix.c | 18 +
hw/pc_q35.c | 19 +
hw/scsi-disk.c | 13
include/block/block.h | 9
include/migration/migration.h | 1
include/qemu-common.h | 12
include/qemu/log.h | 8
linux-user/main.c | 16 -
migration.c | 15
qapi-schema.json | 50 +++
qemu-coroutine.c | 45 ++
qemu-doc.texi | 8
qemu-img-cmds.hx | 34 +-
qemu-img.c | 620 ++++++++++++++++++++++++++++++++++-----
qemu-img.texi | 61 +++
qemu-io.c | 11
qemu-log.c | 29 -
qemu-nbd.c | 18 -
qemu-nbd.texi | 4
qemu-options.hx | 12
slirp/socket.c | 1
target-arm/translate.c | 30 -
target-i386/helper.h | 4
target-i386/int_helper.c | 40 --
target-i386/translate.c | 167 +++-------
target-ppc/translate.c | 9
tcg/tci/README | 2
tests/check-qjson.c | 664 ++++++++++++++++++++++++++++++++++++++++++
tests/qemu-iotests/026 | 6
tests/qemu-iotests/036 | 3
tests/qemu-iotests/039 | 2
tests/qemu-iotests/044.out | 2
tests/qemu-iotests/048 | 78 ++++
tests/qemu-iotests/048.out | 31 +
tests/qemu-iotests/049 | 123 +++++++
tests/qemu-iotests/049.out | 212 +++++++++++++
tests/qemu-iotests/common.rc | 7
tests/qemu-iotests/group | 2
tests/test-coroutine.c | 2
ui/Makefile.objs | 2
ui/gtk.c | 206 ++++++++++---
vl.c | 4
54 files changed, 2434 insertions(+), 513 deletions(-)
New commits:
commit a4bcea3d67949c6be45992bd5092a19f163bcd4e
Author: Richard Henderson <rth at twiddle.net>
Date: Tue Feb 26 12:06:23 2013 -0800
target-i386: Use mulu2 and muls2
These correspond very closely to the insns that we're emulating.
Signed-off-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/target-i386/helper.h b/target-i386/helper.h
index 26a0cc8..d6974df 100644
--- a/target-i386/helper.h
+++ b/target-i386/helper.h
@@ -14,12 +14,8 @@ DEF_HELPER_2(idivw_AX, void, env, tl)
DEF_HELPER_2(divl_EAX, void, env, tl)
DEF_HELPER_2(idivl_EAX, void, env, tl)
#ifdef TARGET_X86_64
-DEF_HELPER_2(mulq_EAX_T0, void, env, tl)
-DEF_HELPER_2(imulq_EAX_T0, void, env, tl)
-DEF_HELPER_3(imulq_T0_T1, tl, env, tl, tl)
DEF_HELPER_2(divq_EAX, void, env, tl)
DEF_HELPER_2(idivq_EAX, void, env, tl)
-DEF_HELPER_FLAGS_2(umulh, TCG_CALL_NO_RWG_SE, tl, tl, tl)
#endif
DEF_HELPER_2(aam, void, env, int)
diff --git a/target-i386/int_helper.c b/target-i386/int_helper.c
index 3b56075..74c7c36 100644
--- a/target-i386/int_helper.c
+++ b/target-i386/int_helper.c
@@ -374,46 +374,6 @@ static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
return 0;
}
-void helper_mulq_EAX_T0(CPUX86State *env, target_ulong t0)
-{
- uint64_t r0, r1;
-
- mulu64(&r0, &r1, EAX, t0);
- EAX = r0;
- EDX = r1;
- CC_DST = r0;
- CC_SRC = r1;
-}
-
-target_ulong helper_umulh(target_ulong t0, target_ulong t1)
-{
- uint64_t h, l;
- mulu64(&l, &h, t0, t1);
- return h;
-}
-
-void helper_imulq_EAX_T0(CPUX86State *env, target_ulong t0)
-{
- uint64_t r0, r1;
-
- muls64(&r0, &r1, EAX, t0);
- EAX = r0;
- EDX = r1;
- CC_DST = r0;
- CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
-}
-
-target_ulong helper_imulq_T0_T1(CPUX86State *env, target_ulong t0,
- target_ulong t1)
-{
- uint64_t r0, r1;
-
- muls64(&r0, &r1, t0, t1);
- CC_DST = r0;
- CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
- return r0;
-}
-
void helper_divq_EAX(CPUX86State *env, target_ulong t0)
{
uint64_t r0, r1;
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 605cd88..3b92f3b 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -4111,31 +4111,18 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
ot = s->dflag == 2 ? OT_QUAD : OT_LONG;
gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
switch (ot) {
- TCGv_i64 t0, t1;
default:
- t0 = tcg_temp_new_i64();
- t1 = tcg_temp_new_i64();
-#ifdef TARGET_X86_64
- tcg_gen_ext32u_i64(t0, cpu_T[0]);
- tcg_gen_ext32u_i64(t1, cpu_regs[R_EDX]);
-#else
- tcg_gen_extu_i32_i64(t0, cpu_T[0]);
- tcg_gen_extu_i32_i64(t0, cpu_regs[R_EDX]);
-#endif
- tcg_gen_mul_i64(t0, t0, t1);
- tcg_gen_trunc_i64_tl(cpu_T[0], t0);
- tcg_gen_shri_i64(t0, t0, 32);
- tcg_gen_trunc_i64_tl(cpu_T[1], t0);
- tcg_temp_free_i64(t0);
- tcg_temp_free_i64(t1);
- gen_op_mov_reg_T0(OT_LONG, s->vex_v);
- gen_op_mov_reg_T1(OT_LONG, reg);
+ tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+ tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_regs[R_EDX]);
+ tcg_gen_mulu2_i32(cpu_tmp2_i32, cpu_tmp3_i32,
+ cpu_tmp2_i32, cpu_tmp3_i32);
+ tcg_gen_extu_i32_tl(cpu_regs[s->vex_v], cpu_tmp2_i32);
+ tcg_gen_extu_i32_tl(cpu_regs[reg], cpu_tmp3_i32);
break;
#ifdef TARGET_X86_64
case OT_QUAD:
- tcg_gen_mov_tl(cpu_T[1], cpu_regs[R_EDX]);
- tcg_gen_mul_tl(cpu_regs[s->vex_v], cpu_T[0], cpu_T[1]);
- gen_helper_umulh(cpu_regs[reg], cpu_T[0], cpu_T[1]);
+ tcg_gen_mulu2_i64(cpu_regs[s->vex_v], cpu_regs[reg],
+ cpu_T[0], cpu_regs[R_EDX]);
break;
#endif
}
@@ -5032,39 +5019,22 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
break;
default:
case OT_LONG:
-#ifdef TARGET_X86_64
- gen_op_mov_TN_reg(OT_LONG, 1, R_EAX);
- tcg_gen_ext32u_tl(cpu_T[0], cpu_T[0]);
- tcg_gen_ext32u_tl(cpu_T[1], cpu_T[1]);
- tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
- gen_op_mov_reg_T0(OT_LONG, R_EAX);
- tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
- tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 32);
- gen_op_mov_reg_T0(OT_LONG, R_EDX);
- tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]);
-#else
- {
- TCGv_i64 t0, t1;
- t0 = tcg_temp_new_i64();
- t1 = tcg_temp_new_i64();
- gen_op_mov_TN_reg(OT_LONG, 1, R_EAX);
- tcg_gen_extu_i32_i64(t0, cpu_T[0]);
- tcg_gen_extu_i32_i64(t1, cpu_T[1]);
- tcg_gen_mul_i64(t0, t0, t1);
- tcg_gen_trunc_i64_i32(cpu_T[0], t0);
- gen_op_mov_reg_T0(OT_LONG, R_EAX);
- tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
- tcg_gen_shri_i64(t0, t0, 32);
- tcg_gen_trunc_i64_i32(cpu_T[0], t0);
- gen_op_mov_reg_T0(OT_LONG, R_EDX);
- tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]);
- }
-#endif
+ tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+ tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_regs[R_EAX]);
+ tcg_gen_mulu2_i32(cpu_tmp2_i32, cpu_tmp3_i32,
+ cpu_tmp2_i32, cpu_tmp3_i32);
+ tcg_gen_extu_i32_tl(cpu_regs[R_EAX], cpu_tmp2_i32);
+ tcg_gen_extu_i32_tl(cpu_regs[R_EDX], cpu_tmp3_i32);
+ tcg_gen_mov_tl(cpu_cc_dst, cpu_regs[R_EAX]);
+ tcg_gen_mov_tl(cpu_cc_src, cpu_regs[R_EDX]);
set_cc_op(s, CC_OP_MULL);
break;
#ifdef TARGET_X86_64
case OT_QUAD:
- gen_helper_mulq_EAX_T0(cpu_env, cpu_T[0]);
+ tcg_gen_mulu2_i64(cpu_regs[R_EAX], cpu_regs[R_EDX],
+ cpu_T[0], cpu_regs[R_EAX]);
+ tcg_gen_mov_tl(cpu_cc_dst, cpu_regs[R_EAX]);
+ tcg_gen_mov_tl(cpu_cc_src, cpu_regs[R_EDX]);
set_cc_op(s, CC_OP_MULQ);
break;
#endif
@@ -5100,41 +5070,25 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
break;
default:
case OT_LONG:
-#ifdef TARGET_X86_64
- gen_op_mov_TN_reg(OT_LONG, 1, R_EAX);
- tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]);
- tcg_gen_ext32s_tl(cpu_T[1], cpu_T[1]);
- tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
- gen_op_mov_reg_T0(OT_LONG, R_EAX);
- tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
- tcg_gen_ext32s_tl(cpu_tmp0, cpu_T[0]);
- tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0);
- tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 32);
- gen_op_mov_reg_T0(OT_LONG, R_EDX);
-#else
- {
- TCGv_i64 t0, t1;
- t0 = tcg_temp_new_i64();
- t1 = tcg_temp_new_i64();
- gen_op_mov_TN_reg(OT_LONG, 1, R_EAX);
- tcg_gen_ext_i32_i64(t0, cpu_T[0]);
- tcg_gen_ext_i32_i64(t1, cpu_T[1]);
- tcg_gen_mul_i64(t0, t0, t1);
- tcg_gen_trunc_i64_i32(cpu_T[0], t0);
- gen_op_mov_reg_T0(OT_LONG, R_EAX);
- tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
- tcg_gen_sari_tl(cpu_tmp0, cpu_T[0], 31);
- tcg_gen_shri_i64(t0, t0, 32);
- tcg_gen_trunc_i64_i32(cpu_T[0], t0);
- gen_op_mov_reg_T0(OT_LONG, R_EDX);
- tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0);
- }
-#endif
+ tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+ tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_regs[R_EAX]);
+ tcg_gen_muls2_i32(cpu_tmp2_i32, cpu_tmp3_i32,
+ cpu_tmp2_i32, cpu_tmp3_i32);
+ tcg_gen_extu_i32_tl(cpu_regs[R_EAX], cpu_tmp2_i32);
+ tcg_gen_extu_i32_tl(cpu_regs[R_EDX], cpu_tmp3_i32);
+ tcg_gen_sari_i32(cpu_tmp2_i32, cpu_tmp2_i32, 31);
+ tcg_gen_mov_tl(cpu_cc_dst, cpu_regs[R_EAX]);
+ tcg_gen_sub_i32(cpu_tmp2_i32, cpu_tmp2_i32, cpu_tmp3_i32);
+ tcg_gen_extu_i32_tl(cpu_cc_src, cpu_tmp2_i32);
set_cc_op(s, CC_OP_MULL);
break;
#ifdef TARGET_X86_64
case OT_QUAD:
- gen_helper_imulq_EAX_T0(cpu_env, cpu_T[0]);
+ tcg_gen_muls2_i64(cpu_regs[R_EAX], cpu_regs[R_EDX],
+ cpu_T[0], cpu_regs[R_EAX]);
+ tcg_gen_mov_tl(cpu_cc_dst, cpu_regs[R_EAX]);
+ tcg_gen_sari_tl(cpu_cc_src, cpu_regs[R_EAX], 63);
+ tcg_gen_sub_tl(cpu_cc_src, cpu_cc_src, cpu_regs[R_EDX]);
set_cc_op(s, CC_OP_MULQ);
break;
#endif
@@ -5389,37 +5343,27 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
} else {
gen_op_mov_TN_reg(ot, 1, reg);
}
-
-#ifdef TARGET_X86_64
- if (ot == OT_QUAD) {
- gen_helper_imulq_T0_T1(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]);
- } else
-#endif
- if (ot == OT_LONG) {
+ switch (ot) {
#ifdef TARGET_X86_64
- tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]);
- tcg_gen_ext32s_tl(cpu_T[1], cpu_T[1]);
- tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
- tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
- tcg_gen_ext32s_tl(cpu_tmp0, cpu_T[0]);
- tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0);
-#else
- {
- TCGv_i64 t0, t1;
- t0 = tcg_temp_new_i64();
- t1 = tcg_temp_new_i64();
- tcg_gen_ext_i32_i64(t0, cpu_T[0]);
- tcg_gen_ext_i32_i64(t1, cpu_T[1]);
- tcg_gen_mul_i64(t0, t0, t1);
- tcg_gen_trunc_i64_i32(cpu_T[0], t0);
- tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
- tcg_gen_sari_tl(cpu_tmp0, cpu_T[0], 31);
- tcg_gen_shri_i64(t0, t0, 32);
- tcg_gen_trunc_i64_i32(cpu_T[1], t0);
- tcg_gen_sub_tl(cpu_cc_src, cpu_T[1], cpu_tmp0);
- }
+ case OT_QUAD:
+ tcg_gen_muls2_i64(cpu_regs[reg], cpu_T[1], cpu_T[0], cpu_T[1]);
+ tcg_gen_mov_tl(cpu_cc_dst, cpu_regs[reg]);
+ tcg_gen_sari_tl(cpu_cc_src, cpu_cc_dst, 63);
+ tcg_gen_sub_tl(cpu_cc_src, cpu_cc_src, cpu_T[1]);
+ break;
#endif
- } else {
+ case OT_LONG:
+ tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+ tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]);
+ tcg_gen_muls2_i32(cpu_tmp2_i32, cpu_tmp3_i32,
+ cpu_tmp2_i32, cpu_tmp3_i32);
+ tcg_gen_extu_i32_tl(cpu_regs[reg], cpu_tmp2_i32);
+ tcg_gen_sari_i32(cpu_tmp2_i32, cpu_tmp2_i32, 31);
+ tcg_gen_mov_tl(cpu_cc_dst, cpu_regs[reg]);
+ tcg_gen_sub_i32(cpu_tmp2_i32, cpu_tmp2_i32, cpu_tmp3_i32);
+ tcg_gen_extu_i32_tl(cpu_cc_src, cpu_tmp2_i32);
+ break;
+ default:
tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]);
tcg_gen_ext16s_tl(cpu_T[1], cpu_T[1]);
/* XXX: use 32 bit mul which could be faster */
@@ -5427,8 +5371,9 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
tcg_gen_ext16s_tl(cpu_tmp0, cpu_T[0]);
tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0);
+ gen_op_mov_reg_T0(ot, reg);
+ break;
}
- gen_op_mov_reg_T0(ot, reg);
set_cc_op(s, CC_OP_MULB + ot);
break;
case 0x1c0:
commit ee24aaf356f44ca7c8fbef136a438c12091cffd0
Merge: 31e76f6 7bd43ec
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Tue Feb 26 13:36:09 2013 -0600
Merge remote-tracking branch 'kiszka/queues/slirp' into staging
# By Jan Kiszka
# Via Jan Kiszka
* kiszka/queues/slirp:
slirp: Properly initialize pollfds_idx of new sockets
commit 31e76f65a98e1502cbfd362eed5768c48e264c23
Author: Alexander Graf <agraf at suse.de>
Date: Tue Feb 26 00:46:10 2013 +0100
glib: Add compat wrapper for g_poll on old glib
Older glib doesn't implement g_poll(). Most notably the glib version in use
on SLE11 is on 2.18 which is hit by this.
We do want to use g_poll() in the source however. So on older systems, just
wrap it with functions that do exist on older versions.
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Alexander Graf <agraf at suse.de>
Message-id: 1361835970-2889-1-git-send-email-agraf at suse.de
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/include/qemu-common.h b/include/qemu-common.h
index 80016ad..5e13708 100644
--- a/include/qemu-common.h
+++ b/include/qemu-common.h
@@ -142,6 +142,18 @@ int qemu_main(int argc, char **argv, char **envp);
void qemu_get_timedate(struct tm *tm, int offset);
int qemu_timedate_diff(struct tm *tm);
+#if !GLIB_CHECK_VERSION(2, 20, 0)
+/*
+ * Glib before 2.20.0 doesn't implement g_poll, so wrap it to compile properly
+ * on older systems.
+ */
+static inline gint g_poll(GPollFD *fds, guint nfds, gint timeout)
+{
+ GMainContext *ctx = g_main_context_default();
+ return g_main_context_get_poll_func(ctx)(fds, nfds, timeout);
+}
+#endif
+
/**
* is_help_option:
* @s: string to test
commit 989b697ddd46769b0999e8cd16b5ecd393204734
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Tue Feb 26 17:52:40 2013 +0000
qemu-log: default to stderr for logging output
Switch the default for qemu_log logging output from "/tmp/qemu.log"
to stderr. This is an incompatible change in some sense, but logging
is mostly used for debugging purposes so it shouldn't affect production
use. The previous behaviour can be obtained by adding "-D /tmp/qemu.log"
to the command line.
This change requires us to:
* update all the documentation/help text (we take the opportunity
to smooth out minor inconsistencies between the phrasing in
linux-user/bsd-user/system help messages)
* make linux-user and bsd-user defer to qemu-log for the default
logging destination rather than overriding it themselves
* ensure that all logfile closing is done via qemu_log_close()
and that that function doesn't close stderr
as well as the obvious change to the behaviour of do_qemu_set_log()
when no logfile name has been specified.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Reviewed-by: Stefan Hajnoczi <stefanha at redhat.com>
Reviewed-by: Markus Armbruster <armbru at redhat.com>
Message-id: 1361901160-28729-1-git-send-email-peter.maydell at linaro.org
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 097fbfe..cc84981 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -34,8 +34,6 @@
#include "qemu/timer.h"
#include "qemu/envlist.h"
-#define DEBUG_LOGFILE "/tmp/qemu.log"
-
int singlestep;
#if defined(CONFIG_USE_GUEST_BASE)
unsigned long mmap_min_addr;
@@ -691,11 +689,12 @@ static void usage(void)
"-bsd type select emulated BSD type FreeBSD/NetBSD/OpenBSD (default)\n"
"\n"
"Debug options:\n"
- "-d options activate log (default logfile=%s)\n"
- "-D logfile override default logfile location\n"
- "-p pagesize set the host page size to 'pagesize'\n"
- "-singlestep always run in singlestep mode\n"
- "-strace log system calls\n"
+ "-d item1[,...] enable logging of specified items\n"
+ " (use '-d help' for a list of log items)\n"
+ "-D logfile write logs to 'logfile' (default stderr)\n"
+ "-p pagesize set the host page size to 'pagesize'\n"
+ "-singlestep always run in singlestep mode\n"
+ "-strace log system calls\n"
"\n"
"Environment variables:\n"
"QEMU_STRACE Print system calls and arguments similar to the\n"
@@ -709,8 +708,7 @@ static void usage(void)
,
TARGET_ARCH,
interp_prefix,
- x86_stack_size,
- DEBUG_LOGFILE);
+ x86_stack_size);
exit(1);
}
@@ -733,7 +731,7 @@ int main(int argc, char **argv)
{
const char *filename;
const char *cpu_model;
- const char *log_file = DEBUG_LOGFILE;
+ const char *log_file = NULL;
const char *log_mask = NULL;
struct target_pt_regs regs1, *regs = ®s1;
struct image_info info1, *info = &info1;
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 64008a9..cef7708 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -295,14 +295,14 @@ ETEXI
.name = "log",
.args_type = "items:s",
.params = "item1[,...]",
- .help = "activate logging of the specified items to '/tmp/qemu.log'",
+ .help = "activate logging of the specified items",
.mhandler.cmd = do_log,
},
STEXI
@item log @var{item1}[,...]
@findex log
-Activate logging of the specified items to @file{/tmp/qemu.log}.
+Activate logging of the specified items.
ETEXI
{
diff --git a/include/qemu/log.h b/include/qemu/log.h
index 4527003..6b0db02 100644
--- a/include/qemu/log.h
+++ b/include/qemu/log.h
@@ -116,8 +116,12 @@ static inline void qemu_log_flush(void)
/* Close the log file */
static inline void qemu_log_close(void)
{
- fclose(qemu_logfile);
- qemu_logfile = NULL;
+ if (qemu_logfile) {
+ if (qemu_logfile != stderr) {
+ fclose(qemu_logfile);
+ }
+ qemu_logfile = NULL;
+ }
}
/* Set up a new log file */
diff --git a/linux-user/main.c b/linux-user/main.c
index e515684..29845f9 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -35,8 +35,6 @@
#include "qemu/envlist.h"
#include "elf.h"
-#define DEBUG_LOGFILE "/tmp/qemu.log"
-
char *exec_path;
int singlestep;
@@ -3296,9 +3294,10 @@ static const struct qemu_argument arg_table[] = {
"size", "reserve 'size' bytes for guest virtual address space"},
#endif
{"d", "QEMU_LOG", true, handle_arg_log,
- "options", "activate log"},
+ "item[,...]", "enable logging of specified items "
+ "(use '-d help' for a list of items)"},
{"D", "QEMU_LOG_FILENAME", true, handle_arg_log_filename,
- "logfile", "override default logfile location"},
+ "logfile", "write logs to 'logfile' (default stderr)"},
{"p", "QEMU_PAGESIZE", true, handle_arg_pagesize,
"pagesize", "set the host page size to 'pagesize'"},
{"singlestep", "QEMU_SINGLESTEP", false, handle_arg_singlestep,
@@ -3351,11 +3350,9 @@ static void usage(void)
printf("\n"
"Defaults:\n"
"QEMU_LD_PREFIX = %s\n"
- "QEMU_STACK_SIZE = %ld byte\n"
- "QEMU_LOG = %s\n",
+ "QEMU_STACK_SIZE = %ld byte\n",
interp_prefix,
- guest_stack_size,
- DEBUG_LOGFILE);
+ guest_stack_size);
printf("\n"
"You can use -E and -U options or the QEMU_SET_ENV and\n"
@@ -3439,7 +3436,6 @@ static int parse_args(int argc, char **argv)
int main(int argc, char **argv, char **envp)
{
- const char *log_file = DEBUG_LOGFILE;
struct target_pt_regs regs1, *regs = ®s1;
struct image_info info1, *info = &info1;
struct linux_binprm bprm;
@@ -3482,8 +3478,6 @@ int main(int argc, char **argv, char **envp)
cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
#endif
- /* init debug */
- qemu_set_log_filename(log_file);
optind = parse_args(argc, argv);
/* Zero out regs */
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 6d7f50d..747e052 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -2642,8 +2642,8 @@ Pre-allocate a guest virtual address space of the given size (in bytes).
Debug options:
@table @option
- at item -d
-Activate log (logfile=/tmp/qemu.log)
+ at item -d item1,...
+Activate logging of the specified items (use '-d help' for a list of log items)
@item -p pagesize
Act as if the host page size was 'pagesize' bytes
@item -g port
@@ -2781,8 +2781,8 @@ FreeBSD, NetBSD and OpenBSD (default).
Debug options:
@table @option
- at item -d
-Activate log (logfile=/tmp/qemu.log)
+ at item -d item1,...
+Activate logging of the specified items (use '-d help' for a list of log items)
@item -p pagesize
Act as if the host page size was 'pagesize' bytes
@item -singlestep
diff --git a/qemu-log.c b/qemu-log.c
index 2f47aaf..797f2af 100644
--- a/qemu-log.c
+++ b/qemu-log.c
@@ -20,12 +20,6 @@
#include "qemu-common.h"
#include "qemu/log.h"
-#ifdef WIN32
-#define DEFAULT_LOGFILENAME "qemu.log"
-#else
-#define DEFAULT_LOGFILENAME "/tmp/qemu.log"
-#endif
-
static char *logfilename;
FILE *qemu_logfile;
int qemu_loglevel;
@@ -56,14 +50,17 @@ void qemu_log_mask(int mask, const char *fmt, ...)
/* enable or disable low levels log */
void do_qemu_set_log(int log_flags, bool use_own_buffers)
{
- const char *fname = logfilename ?: DEFAULT_LOGFILENAME;
-
qemu_loglevel = log_flags;
if (qemu_loglevel && !qemu_logfile) {
- qemu_logfile = fopen(fname, log_append ? "a" : "w");
- if (!qemu_logfile) {
- perror(fname);
- _exit(1);
+ if (logfilename) {
+ qemu_logfile = fopen(logfilename, log_append ? "a" : "w");
+ if (!qemu_logfile) {
+ perror(logfilename);
+ _exit(1);
+ }
+ } else {
+ /* Default to stderr if no log file specified */
+ qemu_logfile = stderr;
}
/* must avoid mmap() usage of glibc by setting a buffer "by hand" */
if (use_own_buffers) {
@@ -81,8 +78,7 @@ void do_qemu_set_log(int log_flags, bool use_own_buffers)
}
}
if (!qemu_loglevel && qemu_logfile) {
- fclose(qemu_logfile);
- qemu_logfile = NULL;
+ qemu_log_close();
}
}
@@ -90,10 +86,7 @@ void qemu_set_log_filename(const char *filename)
{
g_free(logfilename);
logfilename = g_strdup(filename);
- if (qemu_logfile) {
- fclose(qemu_logfile);
- qemu_logfile = NULL;
- }
+ qemu_log_close();
qemu_set_log(qemu_loglevel);
}
diff --git a/qemu-options.hx b/qemu-options.hx
index 51ff726..797d992 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2517,21 +2517,21 @@ Shorthand for -gdb tcp::1234, i.e. open a gdbserver on TCP port 1234
ETEXI
DEF("d", HAS_ARG, QEMU_OPTION_d, \
- "-d item1,... output log to /tmp/qemu.log (use '-d help' for a list of log items)\n",
+ "-d item1,... enable logging of specified items (use '-d help' for a list of log items)\n",
QEMU_ARCH_ALL)
STEXI
- at item -d
+ at item -d @var{item1}[,...]
@findex -d
-Output log in /tmp/qemu.log
+Enable logging of specified items. Use '-d help' for a list of log items.
ETEXI
DEF("D", HAS_ARG, QEMU_OPTION_D, \
- "-D logfile output log to logfile (instead of the default /tmp/qemu.log)\n",
+ "-D logfile output log to logfile (default stderr)\n",
QEMU_ARCH_ALL)
STEXI
@item -D @var{logfile}
@findex -D
-Output log in @var{logfile} instead of /tmp/qemu.log
+Output log in @var{logfile} instead of to stderr
ETEXI
DEF("L", HAS_ARG, QEMU_OPTION_L, \
diff --git a/tcg/tci/README b/tcg/tci/README
index 6ac1ac9..dc57f07 100644
--- a/tcg/tci/README
+++ b/tcg/tci/README
@@ -52,7 +52,7 @@ The only difference from running QEMU with TCI to running without TCI
should be speed. Especially during development of TCI, it was very
useful to compare runs with and without TCI. Create /tmp/qemu.log by
- qemu-system-i386 -d in_asm,op_opt,cpu -singlestep
+ qemu-system-i386 -d in_asm,op_opt,cpu -D /tmp/qemu.log -singlestep
once with interpreter and once without interpreter and compare the resulting
qemu.log files. This is also useful to see the effects of additional
commit ab4004495cb1cf38ab2e35f84ee54e669e2ad08a
Author: Hu Tao <hutao at cn.fujitsu.com>
Date: Mon Feb 25 10:27:48 2013 +0800
show --disable-gtk and --enable-gtk in the help message
Signed-off-by: Hu Tao <hutao at cn.fujitsu.com>
Message-id: 1361759268-16314-1-git-send-email-hutao at cn.fujitsu.com
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/configure b/configure
index 8b6309f..19738ac 100755
--- a/configure
+++ b/configure
@@ -1055,6 +1055,8 @@ echo " --disable-strip disable stripping binaries"
echo " --disable-werror disable compilation abort on warning"
echo " --disable-sdl disable SDL"
echo " --enable-sdl enable SDL"
+echo " --disable-gtk disable gtk UI"
+echo " --enable-gtk enable gtk UI"
echo " --disable-virtfs disable VirtFS"
echo " --enable-virtfs enable VirtFS"
echo " --disable-vnc disable VNC"
commit bc0477c7d6445730b22e733ad4a65f0cc23fa405
Author: Daniel P. Berrange <berrange at redhat.com>
Date: Mon Feb 25 15:20:46 2013 +0000
Add compat for GDK_KEY_XXX symbols
The GDK_KEY_XXX symbols are new in GTK3 and only the most
recent GTK2 releases. Most versions of GTK2 have simply
used GDK_XXX
Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
Message-id: 1361805646-6425-14-git-send-email-berrange at redhat.com
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/ui/gtk.c b/ui/gtk.c
index 82f0bb2..544593e 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -88,6 +88,15 @@ static inline void gdk_drawable_get_size(GdkWindow *w, gint *ww, gint *wh)
#define gtk_widget_get_realized(widget) GTK_WIDGET_REALIZED(widget)
#endif
+#ifndef GDK_KEY_0
+#define GDK_KEY_0 GDK_0
+#define GDK_KEY_1 GDK_1
+#define GDK_KEY_2 GDK_2
+#define GDK_KEY_f GDK_f
+#define GDK_KEY_g GDK_g
+#define GDK_KEY_plus GDK_plus
+#define GDK_KEY_minus GDK_minus
+#endif
typedef struct VirtualConsole
{
commit ef6413a2a833abe24aae072bd59c7434969fc59d
Author: Daniel P. Berrange <berrange at redhat.com>
Date: Mon Feb 25 15:20:45 2013 +0000
Add compat macro for gtk_widget_get_realized
The gtk_widget_get_realized method only arrived in GTK 2.20,
so defined a compat macro for earlier GTK
Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
Message-id: 1361805646-6425-13-git-send-email-berrange at redhat.com
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/ui/gtk.c b/ui/gtk.c
index fa4c3b0..82f0bb2 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -84,6 +84,11 @@ static inline void gdk_drawable_get_size(GdkWindow *w, gint *ww, gint *wh)
}
#endif
+#if !GTK_CHECK_VERSION(2, 20, 0)
+#define gtk_widget_get_realized(widget) GTK_WIDGET_REALIZED(widget)
+#endif
+
+
typedef struct VirtualConsole
{
GtkWidget *menu_item;
commit 528de90ab7133e22df7c1da4632a6dcd525e88f0
Author: Daniel P. Berrange <berrange at redhat.com>
Date: Mon Feb 25 15:20:44 2013 +0000
Add support for enabling build with GTK3
Add a arg to configure to switch from GTK2 (default) to
GTK3 (optional) build for QEMU.
./configure --with-gtkabi=3.0
will choose GTK3, while
./configure --with-gtkabi=2.0
will choose GTK2 (and remains the current default)
Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
Message-id: 1361805646-6425-12-git-send-email-berrange at redhat.com
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/configure b/configure
index dcaa67c..8b6309f 100755
--- a/configure
+++ b/configure
@@ -227,6 +227,7 @@ seccomp=""
glusterfs=""
virtio_blk_data_plane=""
gtk=""
+gtkabi="2.0"
# parse CC options first
for opt do
@@ -902,6 +903,8 @@ for opt do
;;
--enable-gtk) gtk="yes"
;;
+ --with-gtkabi=*) gtkabi="$optarg"
+ ;;
*) echo "ERROR: unknown option $opt"; show_help="yes"
;;
esac
@@ -1644,12 +1647,22 @@ fi
# GTK probe
if test "$gtk" != "no"; then
- if $pkg_config --exists 'gtk+-2.0 >= 2.18.0' && \
- $pkg_config --exists 'vte >= 0.24.0'; then
- gtk_cflags=`$pkg_config --cflags gtk+-2.0 2>/dev/null`
- gtk_libs=`$pkg_config --libs gtk+-2.0 2>/dev/null`
- vte_cflags=`$pkg_config --cflags vte 2>/dev/null`
- vte_libs=`$pkg_config --libs vte 2>/dev/null`
+ gtkpackage="gtk+-$gtkabi"
+ if test "$gtkabi" = "3.0" ; then
+ gtkversion="3.0.0"
+ vtepackage="vte-2.90"
+ vteversion="0.32.0"
+ else
+ gtkversion="2.18.0"
+ vtepackage="vte"
+ vteversion="0.24.0"
+ fi
+ if $pkg_config --exists "$gtkpackage >= $gtkversion" && \
+ $pkg_config --exists "$vtepackage >= $vteversion"; then
+ gtk_cflags=`$pkg_config --cflags $gtkpackage 2>/dev/null`
+ gtk_libs=`$pkg_config --libs $gtkpackage 2>/dev/null`
+ vte_cflags=`$pkg_config --cflags $vtepackage 2>/dev/null`
+ vte_libs=`$pkg_config --libs $vtepackage 2>/dev/null`
libs_softmmu="$gtk_libs $vte_libs $libs_softmmu"
gtk="yes"
else
commit 0d20664018a401120af28ff80ac8d22fbc887956
Author: Daniel P. Berrange <berrange at redhat.com>
Date: Mon Feb 25 15:20:43 2013 +0000
Ensure x_keymap.o is built when GTK is enabled
The x_keymap.o file is required by both GTK and SDL builds,
so it must be explicitly listed as a GTK dep to ensure the
linker works when SDL is disabled
Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
Message-id: 1361805646-6425-11-git-send-email-berrange at redhat.com
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index 85c50cd..6ddc0de 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -13,7 +13,7 @@ common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
common-obj-$(CONFIG_COCOA) += cocoa.o
common-obj-$(CONFIG_CURSES) += curses.o
common-obj-$(CONFIG_VNC) += $(vnc-obj-y)
-common-obj-$(CONFIG_GTK) += gtk.o
+common-obj-$(CONFIG_GTK) += gtk.o x_keymap.o
$(obj)/sdl.o $(obj)/sdl_zoom.o: QEMU_CFLAGS += $(SDL_CFLAGS)
commit fe43bca85b269314b007cd9b2eecc4a52aa73dde
Author: Daniel P. Berrange <berrange at redhat.com>
Date: Mon Feb 25 15:20:42 2013 +0000
Replace expose-event handler with draw handler in GTK3
In GTK3 the 'expose-event' signal has been replaced by a new
'draw' signal. The only difference is that the latter will
pre-create the cairo drawing context & set the clip mask.
Since the drawing code is already structured in a nice way,
we can just wire up the 'gd_draw_event' method to the 'draw'
signal in GTK3
Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
Message-id: 1361805646-6425-10-git-send-email-berrange at redhat.com
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/ui/gtk.c b/ui/gtk.c
index c89c7c4..fa4c3b0 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -433,6 +433,7 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
return TRUE;
}
+#if !GTK_CHECK_VERSION(3, 0, 0)
static gboolean gd_expose_event(GtkWidget *widget, GdkEventExpose *expose,
void *opaque)
{
@@ -453,6 +454,7 @@ static gboolean gd_expose_event(GtkWidget *widget, GdkEventExpose *expose,
return ret;
}
+#endif
static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
void *opaque)
@@ -1100,8 +1102,13 @@ static void gd_connect_signals(GtkDisplayState *s)
g_signal_connect(s->window, "delete-event",
G_CALLBACK(gd_window_close), s);
+#if GTK_CHECK_VERSION(3, 0, 0)
+ g_signal_connect(s->drawing_area, "draw",
+ G_CALLBACK(gd_draw_event), s);
+#else
g_signal_connect(s->drawing_area, "expose-event",
G_CALLBACK(gd_expose_event), s);
+#endif
g_signal_connect(s->drawing_area, "motion-notify-event",
G_CALLBACK(gd_motion_event), s);
g_signal_connect(s->drawing_area, "button-press-event",
commit 1ed76b59c4f8670eb06df48cebe086da06111e1f
Author: Daniel P. Berrange <berrange at redhat.com>
Date: Mon Feb 25 15:20:41 2013 +0000
Conditionalize use of gtk_widget_size_request
The gtk_widget_size_request method has been replaced by
the gtk_widget_get_preferred_size method in GTK3. Conditionally
call the new method in GTK3
Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
Message-id: 1361805646-6425-9-git-send-email-berrange at redhat.com
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/ui/gtk.c b/ui/gtk.c
index 93c3b43..c89c7c4 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -305,7 +305,11 @@ static void gd_resize(DisplayState *ds)
gtk_widget_set_size_request(s->drawing_area,
ds_get_width(ds) * s->scale_x,
ds_get_height(ds) * s->scale_y);
+#if GTK_CHECK_VERSION(3, 0, 0)
+ gtk_widget_get_preferred_size(s->vbox, NULL, &req);
+#else
gtk_widget_size_request(s->vbox, &req);
+#endif
gtk_window_resize(GTK_WINDOW(s->window),
req.width * sx, req.height * sy);
commit 8906de769be0978fed31a0341d0a5829a4ef7ecf
Author: Daniel P. Berrange <berrange at redhat.com>
Date: Mon Feb 25 15:20:40 2013 +0000
Conditionalize use of gdk_display_warp_pointer
In GTK3 the gdk_display_warp_pointer method is deprecated.
Instead we should use gdk_device_warp on the GdkDevice
instead associated with the event being processed.
Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
Message-id: 1361805646-6425-8-git-send-email-berrange at redhat.com
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/ui/gtk.c b/ui/gtk.c
index 182a16c..93c3b43 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -501,7 +501,6 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
}
if (!kbd_mouse_is_absolute() && gd_is_grab_active(s)) {
- GdkDisplay *display = gtk_widget_get_display(s->drawing_area);
GdkScreen *screen = gtk_widget_get_screen(s->drawing_area);
int x = (int)motion->x_root;
int y = (int)motion->y_root;
@@ -527,7 +526,13 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
}
if (x != (int)motion->x_root || y != (int)motion->y_root) {
+#if GTK_CHECK_VERSION(3, 0, 0)
+ GdkDevice *dev = gdk_event_get_device((GdkEvent *)motion);
+ gdk_device_warp(dev, screen, x, y);
+#else
+ GdkDisplay *display = gtk_widget_get_display(widget);
gdk_display_warp_pointer(display, screen, x, y);
+#endif
s->last_x = -1;
s->last_y = -1;
return FALSE;
commit 530daf82c129c2a8a6fa757b3ef5a21f1f50f66a
Author: Daniel P. Berrange <berrange at redhat.com>
Date: Mon Feb 25 15:20:39 2013 +0000
Replace gtk_menu_append with gtk_menu_shell_append
The gtk_menu_append method has long been deprecated in favour
of the gtk_menu_shell_append method. The former is now entirely
gone in GTK3, so switch all code to the latter which works on
both GTK2 and GTK3
Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
Message-id: 1361805646-6425-7-git-send-email-berrange at redhat.com
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/ui/gtk.c b/ui/gtk.c
index 4211b7e..182a16c 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1066,7 +1066,7 @@ static GSList *gd_vc_init(GtkDisplayState *s, VirtualConsole *vc, int index, GSL
g_signal_connect(vc->menu_item, "activate",
G_CALLBACK(gd_menu_switch_vc), s);
- gtk_menu_append(GTK_MENU(s->view_menu), vc->menu_item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), vc->menu_item);
qemu_chr_generic_open(vc->chr);
if (vc->chr->init) {
@@ -1148,26 +1148,26 @@ static void gd_create_menus(GtkDisplayState *s)
s->machine_menu_item = gtk_menu_item_new_with_mnemonic(_("_Machine"));
s->pause_item = gtk_check_menu_item_new_with_mnemonic(_("_Pause"));
- gtk_menu_append(GTK_MENU(s->machine_menu), s->pause_item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->machine_menu), s->pause_item);
separator = gtk_separator_menu_item_new();
- gtk_menu_append(GTK_MENU(s->machine_menu), separator);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->machine_menu), separator);
s->reset_item = gtk_image_menu_item_new_with_mnemonic(_("_Reset"));
- gtk_menu_append(GTK_MENU(s->machine_menu), s->reset_item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->machine_menu), s->reset_item);
s->powerdown_item = gtk_image_menu_item_new_with_mnemonic(_("Power _Down"));
- gtk_menu_append(GTK_MENU(s->machine_menu), s->powerdown_item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->machine_menu), s->powerdown_item);
separator = gtk_separator_menu_item_new();
- gtk_menu_append(GTK_MENU(s->machine_menu), separator);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->machine_menu), separator);
s->quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
gtk_stock_lookup(GTK_STOCK_QUIT, &item);
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->quit_item),
"<QEMU>/Machine/Quit");
gtk_accel_map_add_entry("<QEMU>/Machine/Quit", item.keyval, item.modifier);
- gtk_menu_append(GTK_MENU(s->machine_menu), s->quit_item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->machine_menu), s->quit_item);
s->view_menu = gtk_menu_new();
gtk_menu_set_accel_group(GTK_MENU(s->view_menu), accel_group);
@@ -1178,53 +1178,53 @@ static void gd_create_menus(GtkDisplayState *s)
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->full_screen_item),
"<QEMU>/View/Full Screen");
gtk_accel_map_add_entry("<QEMU>/View/Full Screen", GDK_KEY_f, GDK_CONTROL_MASK | GDK_MOD1_MASK);
- gtk_menu_append(GTK_MENU(s->view_menu), s->full_screen_item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), s->full_screen_item);
separator = gtk_separator_menu_item_new();
- gtk_menu_append(GTK_MENU(s->view_menu), separator);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), separator);
s->zoom_in_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_IN, NULL);
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_in_item),
"<QEMU>/View/Zoom In");
gtk_accel_map_add_entry("<QEMU>/View/Zoom In", GDK_KEY_plus, GDK_CONTROL_MASK | GDK_MOD1_MASK);
- gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_in_item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), s->zoom_in_item);
s->zoom_out_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_OUT, NULL);
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_out_item),
"<QEMU>/View/Zoom Out");
gtk_accel_map_add_entry("<QEMU>/View/Zoom Out", GDK_KEY_minus, GDK_CONTROL_MASK | GDK_MOD1_MASK);
- gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_out_item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), s->zoom_out_item);
s->zoom_fixed_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_100, NULL);
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_fixed_item),
"<QEMU>/View/Zoom Fixed");
gtk_accel_map_add_entry("<QEMU>/View/Zoom Fixed", GDK_KEY_0, GDK_CONTROL_MASK | GDK_MOD1_MASK);
- gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_fixed_item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), s->zoom_fixed_item);
s->zoom_fit_item = gtk_check_menu_item_new_with_mnemonic(_("Zoom To _Fit"));
- gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_fit_item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), s->zoom_fit_item);
separator = gtk_separator_menu_item_new();
- gtk_menu_append(GTK_MENU(s->view_menu), separator);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), separator);
s->grab_on_hover_item = gtk_check_menu_item_new_with_mnemonic(_("Grab On _Hover"));
- gtk_menu_append(GTK_MENU(s->view_menu), s->grab_on_hover_item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), s->grab_on_hover_item);
s->grab_item = gtk_check_menu_item_new_with_mnemonic(_("_Grab Input"));
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->grab_item),
"<QEMU>/View/Grab Input");
gtk_accel_map_add_entry("<QEMU>/View/Grab Input", GDK_KEY_g, GDK_CONTROL_MASK | GDK_MOD1_MASK);
- gtk_menu_append(GTK_MENU(s->view_menu), s->grab_item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), s->grab_item);
separator = gtk_separator_menu_item_new();
- gtk_menu_append(GTK_MENU(s->view_menu), separator);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), separator);
s->vga_item = gtk_radio_menu_item_new_with_mnemonic(group, "_VGA");
group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(s->vga_item));
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->vga_item),
"<QEMU>/View/VGA");
gtk_accel_map_add_entry("<QEMU>/View/VGA", GDK_KEY_1, GDK_CONTROL_MASK | GDK_MOD1_MASK);
- gtk_menu_append(GTK_MENU(s->view_menu), s->vga_item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), s->vga_item);
for (i = 0; i < nb_vcs; i++) {
VirtualConsole *vc = &s->vc[i];
@@ -1234,10 +1234,10 @@ static void gd_create_menus(GtkDisplayState *s)
}
separator = gtk_separator_menu_item_new();
- gtk_menu_append(GTK_MENU(s->view_menu), separator);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), separator);
s->show_tabs_item = gtk_check_menu_item_new_with_mnemonic(_("Show _Tabs"));
- gtk_menu_append(GTK_MENU(s->view_menu), s->show_tabs_item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), s->show_tabs_item);
g_object_set_data(G_OBJECT(s->window), "accel_group", accel_group);
gtk_window_add_accel_group(GTK_WINDOW(s->window), accel_group);
commit 51572ab087b900ea67cc25f1c49dae4112274221
Author: Daniel P. Berrange <berrange at redhat.com>
Date: Mon Feb 25 15:20:38 2013 +0000
Remove use of GtkVBox in GTK3
The GtkVBox class is deprecated, in favour of just using the
GtkBox class directly. Eventually even GtkBox will be
deprecated in favour of GtkGrid, but that is a bigger fix
which can wait.
Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
Message-id: 1361805646-6425-6-git-send-email-berrange at redhat.com
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/ui/gtk.c b/ui/gtk.c
index 19d554d..4211b7e 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1264,7 +1264,11 @@ void gtk_display_init(DisplayState *ds)
s->dcl.dpy_refresh = gd_refresh;
s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+#if GTK_CHECK_VERSION(3, 2, 0)
+ s->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+#else
s->vbox = gtk_vbox_new(FALSE, 0);
+#endif
s->notebook = gtk_notebook_new();
s->drawing_area = gtk_drawing_area_new();
s->menu_bar = gtk_menu_bar_new();
commit 2a05485d72504ed92ce91dffd1f5867974c47ff0
Author: Daniel P. Berrange <berrange at redhat.com>
Date: Mon Feb 25 15:20:37 2013 +0000
Conditionalize use of gdk_pointer_grab / gdk_pointer_ungrab
On GTK3 there is support for multiple pointer devices, so
rather than using gdk_pointer_grab / gdk_pointer_ungrab
we should iterate over all devices, grabbing each one in
turn
Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
Message-id: 1361805646-6425-5-git-send-email-berrange at redhat.com
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/ui/gtk.c b/ui/gtk.c
index 3826bea..19d554d 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -807,25 +807,79 @@ static void gd_ungrab_keyboard(GtkDisplayState *s)
#endif
}
+static void gd_grab_pointer(GtkDisplayState *s)
+{
+#if GTK_CHECK_VERSION(3, 0, 0)
+ GdkDisplay *display = gtk_widget_get_display(s->drawing_area);
+ GdkDeviceManager *mgr = gdk_display_get_device_manager(display);
+ GList *devices = gdk_device_manager_list_devices(mgr,
+ GDK_DEVICE_TYPE_MASTER);
+ GList *tmp = devices;
+ while (tmp) {
+ GdkDevice *dev = tmp->data;
+ if (gdk_device_get_source(dev) == GDK_SOURCE_MOUSE) {
+ gdk_device_grab(dev,
+ gtk_widget_get_window(s->drawing_area),
+ GDK_OWNERSHIP_NONE,
+ FALSE, /* All events to come to our
+ window directly */
+ GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_BUTTON_MOTION_MASK |
+ GDK_SCROLL_MASK,
+ s->null_cursor,
+ GDK_CURRENT_TIME);
+ }
+ tmp = tmp->next;
+ }
+ g_list_free(devices);
+#else
+ gdk_pointer_grab(gtk_widget_get_window(s->drawing_area),
+ FALSE, /* All events to come to our window directly */
+ GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_BUTTON_MOTION_MASK |
+ GDK_SCROLL_MASK,
+ NULL, /* Allow cursor to move over entire desktop */
+ s->null_cursor,
+ GDK_CURRENT_TIME);
+#endif
+}
+
+static void gd_ungrab_pointer(GtkDisplayState *s)
+{
+#if GTK_CHECK_VERSION(3, 0, 0)
+ GdkDisplay *display = gtk_widget_get_display(s->drawing_area);
+ GdkDeviceManager *mgr = gdk_display_get_device_manager(display);
+ GList *devices = gdk_device_manager_list_devices(mgr,
+ GDK_DEVICE_TYPE_MASTER);
+ GList *tmp = devices;
+ while (tmp) {
+ GdkDevice *dev = tmp->data;
+ if (gdk_device_get_source(dev) == GDK_SOURCE_MOUSE) {
+ gdk_device_ungrab(dev,
+ GDK_CURRENT_TIME);
+ }
+ tmp = tmp->next;
+ }
+ g_list_free(devices);
+#else
+ gdk_pointer_ungrab(GDK_CURRENT_TIME);
+#endif
+}
+
static void gd_menu_grab_input(GtkMenuItem *item, void *opaque)
{
GtkDisplayState *s = opaque;
if (gd_is_grab_active(s)) {
gd_grab_keyboard(s);
- gdk_pointer_grab(gtk_widget_get_window(GTK_WIDGET(s->drawing_area)),
- FALSE, /* All events to come to our window directly */
- GDK_POINTER_MOTION_MASK |
- GDK_BUTTON_PRESS_MASK |
- GDK_BUTTON_RELEASE_MASK |
- GDK_BUTTON_MOTION_MASK |
- GDK_SCROLL_MASK,
- NULL, /* Allow cursor to move over entire desktop */
- s->null_cursor,
- GDK_CURRENT_TIME);
+ gd_grab_pointer(s);
} else {
gd_ungrab_keyboard(s);
- gdk_pointer_ungrab(GDK_CURRENT_TIME);
+ gd_ungrab_pointer(s);
}
gd_update_caption(s);
commit 655199da197d2c3407d4bc937c9d3d3ac4551764
Author: Daniel P. Berrange <berrange at redhat.com>
Date: Mon Feb 25 15:20:36 2013 +0000
Conditionalize use of gdk_keyboard_grab / gdk_keyboard_ungrab
On GTK3 there is support for multiple keyboard devices, so
rather than using gdk_keyboard_grab / gdk_keyboard_ungrab
we should iterate over all devices, grabbing each one in
turn
Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
Message-id: 1361805646-6425-4-git-send-email-berrange at redhat.com
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/ui/gtk.c b/ui/gtk.c
index 8ccd95f..3826bea 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -758,14 +758,53 @@ static void gd_menu_zoom_fit(GtkMenuItem *item, void *opaque)
static void gd_grab_keyboard(GtkDisplayState *s)
{
- gdk_keyboard_grab(gtk_widget_get_window(GTK_WIDGET(s->drawing_area)),
+#if GTK_CHECK_VERSION(3, 0, 0)
+ GdkDisplay *display = gtk_widget_get_display(s->drawing_area);
+ GdkDeviceManager *mgr = gdk_display_get_device_manager(display);
+ GList *devices = gdk_device_manager_list_devices(mgr,
+ GDK_DEVICE_TYPE_MASTER);
+ GList *tmp = devices;
+ while (tmp) {
+ GdkDevice *dev = tmp->data;
+ if (gdk_device_get_source(dev) == GDK_SOURCE_KEYBOARD) {
+ gdk_device_grab(dev,
+ gtk_widget_get_window(s->drawing_area),
+ GDK_OWNERSHIP_NONE,
+ FALSE,
+ GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
+ NULL,
+ GDK_CURRENT_TIME);
+ }
+ tmp = tmp->next;
+ }
+ g_list_free(devices);
+#else
+ gdk_keyboard_grab(gtk_widget_get_window(s->drawing_area),
FALSE,
GDK_CURRENT_TIME);
+#endif
}
static void gd_ungrab_keyboard(GtkDisplayState *s)
{
+#if GTK_CHECK_VERSION(3, 0, 0)
+ GdkDisplay *display = gtk_widget_get_display(s->drawing_area);
+ GdkDeviceManager *mgr = gdk_display_get_device_manager(display);
+ GList *devices = gdk_device_manager_list_devices(mgr,
+ GDK_DEVICE_TYPE_MASTER);
+ GList *tmp = devices;
+ while (tmp) {
+ GdkDevice *dev = tmp->data;
+ if (gdk_device_get_source(dev) == GDK_SOURCE_KEYBOARD) {
+ gdk_device_ungrab(dev,
+ GDK_CURRENT_TIME);
+ }
+ tmp = tmp->next;
+ }
+ g_list_free(devices);
+#else
gdk_keyboard_ungrab(GDK_CURRENT_TIME);
+#endif
}
static void gd_menu_grab_input(GtkMenuItem *item, void *opaque)
commit 66962f14378d0adf2e7d0fcfac66e2248b09bb4d
Author: Daniel P. Berrange <berrange at redhat.com>
Date: Mon Feb 25 15:20:35 2013 +0000
Remove use of gdk_drawable_get_{screen, display}
The gdk_drawable_get_screen and gdk_drawable_get_display
methods don't exist in GDK3. Fortunately, even on GTK2
they are not required - we can call the equivalent
gtk_widget_get_screen/gtk_widget_get_display methods
which have existed since GTK 2.2
Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
Message-id: 1361805646-6425-3-git-send-email-berrange at redhat.com
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/ui/gtk.c b/ui/gtk.c
index dfffbb8..8ccd95f 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -501,9 +501,8 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
}
if (!kbd_mouse_is_absolute() && gd_is_grab_active(s)) {
- GdkDrawable *drawable = GDK_DRAWABLE(gtk_widget_get_window(s->drawing_area));
- GdkDisplay *display = gdk_drawable_get_display(drawable);
- GdkScreen *screen = gdk_drawable_get_screen(drawable);
+ GdkDisplay *display = gtk_widget_get_display(s->drawing_area);
+ GdkScreen *screen = gtk_widget_get_screen(s->drawing_area);
int x = (int)motion->x_root;
int y = (int)motion->y_root;
commit cba68834c69f2d0fd04127301171fedac63d9b67
Author: Daniel P. Berrange <berrange at redhat.com>
Date: Mon Feb 25 15:20:34 2013 +0000
Add compat for gdk_drawable_get_size on GTK3
GTK3 lacks the gdk_drawable_get_size method, so we create a
stub impl which gets the get_width/get_height mehtods instead
Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
Message-id: 1361805646-6425-2-git-send-email-berrange at redhat.com
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/ui/gtk.c b/ui/gtk.c
index dcce36d..dfffbb8 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -74,6 +74,16 @@
#define MAX_VCS 10
+
+/* Compatibility define to let us build on both Gtk2 and Gtk3 */
+#if GTK_CHECK_VERSION(3, 0, 0)
+static inline void gdk_drawable_get_size(GdkWindow *w, gint *ww, gint *wh)
+{
+ *ww = gdk_window_get_width(w);
+ *wh = gdk_window_get_height(w);
+}
+#endif
+
typedef struct VirtualConsole
{
GtkWidget *menu_item;
commit f963e4d0ca5b7704aed8048e2bc293597d333dfb
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Mon Feb 25 16:02:30 2013 +0100
gtk ui: unbreak spice
Merge of the gtk ui brought a initialitation order issue for spice:
The using_spice variable isn't set yet when checked, leading to the
default UI being activated (additionally to spice remote access).
Let's set display_remote when we find a -spice switch on the command
line, like we do for vnc.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
Message-id: 1361804550-15858-1-git-send-email-kraxel at redhat.com
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/vl.c b/vl.c
index 0da156e..febd2ea 100644
--- a/vl.c
+++ b/vl.c
@@ -3767,6 +3767,7 @@ int main(int argc, char **argv, char **envp)
if (!opts) {
exit(1);
}
+ display_remote++;
break;
case QEMU_OPTION_writeconfig:
{
@@ -4006,9 +4007,6 @@ int main(int argc, char **argv, char **envp)
}
}
- if (using_spice) {
- display_remote++;
- }
if (display_type == DT_DEFAULT && !display_remote) {
#if defined(CONFIG_GTK)
display_type = DT_GTK;
commit 864a556e9a800116a305f10fbb714268ca7e9bc3
Merge: 9a1d7f0 bf3caa3
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Tue Feb 26 07:44:39 2013 -0600
Merge remote-tracking branch 'kwolf/for-anthony' into staging
# By Paolo Bonzini (7) and others
# Via Kevin Wolf
* kwolf/for-anthony: (22 commits)
pc: add compatibility machine types for 1.4
blockdev: enable discard by default
qemu-nbd: add --discard option
blockdev: add discard suboption to -drive
block: implement BDRV_O_UNMAP
block: complete all IOs before .bdrv_truncate
coroutine: trim down nesting level in perf_nesting test
coroutine: move pooling to common code
qemu-iotests: Test qcow2 image creation options
qemu-iotests: Add qemu-img compare test
qemu-img: Add compare subcommand
qemu-img: Add "Quiet mode" option
block: Add synchronous wrapper for bdrv_co_is_allocated_above
block: refuse negative iops and bps values
block: use Error in do_check_io_limits()
qcow2: support compressed clusters in BlockFragInfo
qemu-img: add compressed clusters to BlockFragInfo
qemu-img: fix missing space in qemu-img check output
qcow2: record fragmentation statistics during check
qcow2: introduce check_refcounts_l1/l2() flags
...
commit 9a1d7f00efd4b69f051d4223a70ca91af0ccb19d
Merge: b1c07f0 90f8ae7
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Tue Feb 26 07:44:32 2013 -0600
Merge remote-tracking branch 'quintela/stats.next' into staging
# By Juan Quintela
# Via Juan Quintela
* quintela/stats.next:
migration: calculate expected_downtime
migration: don't account sleep time for calculating bandwidth
migration: calculate end time after we have sent the data
migration: change initial value of expected_downtime
commit b1c07f06ed0e2094197274e636a90ad33674653c
Merge: 08f4a0f 3960c41
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Tue Feb 26 07:44:24 2013 -0600
Merge remote-tracking branch 'luiz/queue/qmp' into staging
# By Markus Armbruster
# Via Luiz Capitulino
* luiz/queue/qmp:
check-qjson: More thorough testing of UTF-8 in strings
commit 7bd43ec2dd3ffaa12e6331af41fc55d4b2b12f13
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date: Fri Feb 22 20:47:10 2013 +0100
slirp: Properly initialize pollfds_idx of new sockets
Otherwise we may start processing sockets in slirp_pollfds_poll that
were created past slirp_pollfds_fill.
Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
Reviewed-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/slirp/socket.c b/slirp/socket.c
index a7ab933..bb639ae 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -51,6 +51,7 @@ socreate(Slirp *slirp)
so->so_state = SS_NOFDREF;
so->s = -1;
so->slirp = slirp;
+ so->pollfds_idx = -1;
}
return(so);
}
commit 08f4a0f7ee899c32bac91114e859d2687cbcf1d7
Author: Richard Henderson <rth at twiddle.net>
Date: Mon Feb 25 11:41:40 2013 -0800
target-ppc: Fix SUBFE carry
While ~T0+T1+CF = T1-T0+CF-1 is true for the low 32-bits,
it does not produce the correct carry-out to bit 33. Do
exactly what the manual says.
Cc: Alexander Graf <agraf at suse.de>
Signed-off-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index f886441..80d5366 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -1120,14 +1120,15 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1,
}
if (add_ca) {
- /* dest = ~arg1 + arg2 + ca = arg2 - arg1 + ca - 1. */
+ /* dest = ~arg1 + arg2 + ca. */
if (compute_ca) {
- TCGv zero;
- tcg_gen_subi_tl(cpu_ca, cpu_ca, 1);
+ TCGv zero, inv1 = tcg_temp_new();
+ tcg_gen_not_tl(inv1, arg1);
zero = tcg_const_tl(0);
tcg_gen_add2_tl(t0, cpu_ca, arg2, zero, cpu_ca, zero);
- tcg_gen_sub2_tl(t0, cpu_ca, t0, cpu_ca, arg1, zero);
+ tcg_gen_add2_tl(t0, cpu_ca, t0, cpu_ca, inv1, zero);
tcg_temp_free(zero);
+ tcg_temp_free(inv1);
} else {
tcg_gen_sub_tl(t0, arg2, arg1);
tcg_gen_add_tl(t0, t0, cpu_ca);
commit e77f083292916ba43b940fdacd2fc1001b750d1d
Author: Richard Henderson <rth at twiddle.net>
Date: Mon Feb 25 11:41:39 2013 -0800
target-arm: Fix sbc_CC carry
While T0+~T1+CF = T0-T1+CF-1 is true for the low 32-bits,
it does not produce the correct carry-out to bit 33. Do
exactly what the manual says.
Using the ~T1 makes the add and subtract code paths nearly
identical, so have sbc_CC use adc_CC.
Cc: Peter Maydell <peter.maydell at linaro.org>
Reported-by: Laurent Desnogues <laurent.desnogues at gmail.com>
Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 6d91b70..f2f649d 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -464,33 +464,13 @@ static void gen_sub_CC(TCGv dest, TCGv t0, TCGv t1)
tcg_gen_mov_i32(dest, cpu_NF);
}
-/* dest = T0 + ~T1 + CF = T0 - T1 + CF - 1. Compute C, N, V and Z flags */
+/* dest = T0 + ~T1 + CF. Compute C, N, V and Z flags */
static void gen_sbc_CC(TCGv dest, TCGv t0, TCGv t1)
{
TCGv tmp = tcg_temp_new_i32();
- tcg_gen_subi_i32(cpu_CF, cpu_CF, 1);
- if (TCG_TARGET_HAS_add2_i32) {
- tcg_gen_movi_i32(tmp, 0);
- tcg_gen_add2_i32(cpu_NF, cpu_CF, t0, tmp, cpu_CF, tmp);
- tcg_gen_sub2_i32(cpu_NF, cpu_CF, cpu_NF, cpu_CF, t1, tmp);
- } else {
- TCGv_i64 q0 = tcg_temp_new_i64();
- TCGv_i64 q1 = tcg_temp_new_i64();
- tcg_gen_extu_i32_i64(q0, t0);
- tcg_gen_extu_i32_i64(q1, t1);
- tcg_gen_sub_i64(q0, q0, q1);
- tcg_gen_extu_i32_i64(q1, cpu_CF);
- tcg_gen_add_i64(q0, q0, q1);
- tcg_gen_extr_i64_i32(cpu_NF, cpu_CF, q0);
- tcg_temp_free_i64(q0);
- tcg_temp_free_i64(q1);
- }
- tcg_gen_mov_i32(cpu_ZF, cpu_NF);
- tcg_gen_xor_i32(cpu_VF, cpu_NF, t0);
- tcg_gen_xor_i32(tmp, t0, t1);
- tcg_gen_and_i32(cpu_VF, cpu_VF, tmp);
- tcg_temp_free_i32(tmp);
- tcg_gen_mov_i32(dest, cpu_NF);
+ tcg_gen_not_i32(tmp, t1);
+ gen_adc_CC(dest, t0, tmp);
+ tcg_temp_free(tmp);
}
#define GEN_SHIFT(name) \
commit 8c3ac601bdaf8d4d81823a79f2a166b586db7dab
Author: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
Date: Mon Feb 25 11:41:38 2013 -0800
arm/translate.c: Fix adc_CC/sbc_CC implementation
commits 49b4c31efcce45ab714f286f14fa5d5173f9069d and
2de68a4900ef6eb67380b0c128abfe1976bc66e8 reworked the implementation of adc_CC
and sub_CC. The new implementations (on the TCG_TARGET_HAS_add2_i32 code path)
are incorrect. The new logic is:
CF:NF = 0:A +/- 0:CF
CF:NF = CF:A +/- 0:B
The lower 32 bits of the intermediate result stored in NF needs to be passes
into the second addition in place of A (s/CF:A/CF:NF):
CF:NF = 0:A +/- 0:CF
CF:NF = CF:NF +/- 0:B
This patch fixes the issue.
Cc: Peter Maydell <peter.maydell at linaro.org>
Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
Signed-off-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 9993aea..6d91b70 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -428,7 +428,7 @@ static void gen_adc_CC(TCGv dest, TCGv t0, TCGv t1)
if (TCG_TARGET_HAS_add2_i32) {
tcg_gen_movi_i32(tmp, 0);
tcg_gen_add2_i32(cpu_NF, cpu_CF, t0, tmp, cpu_CF, tmp);
- tcg_gen_add2_i32(cpu_NF, cpu_CF, t0, cpu_CF, t1, tmp);
+ tcg_gen_add2_i32(cpu_NF, cpu_CF, cpu_NF, cpu_CF, t1, tmp);
} else {
TCGv_i64 q0 = tcg_temp_new_i64();
TCGv_i64 q1 = tcg_temp_new_i64();
@@ -472,7 +472,7 @@ static void gen_sbc_CC(TCGv dest, TCGv t0, TCGv t1)
if (TCG_TARGET_HAS_add2_i32) {
tcg_gen_movi_i32(tmp, 0);
tcg_gen_add2_i32(cpu_NF, cpu_CF, t0, tmp, cpu_CF, tmp);
- tcg_gen_sub2_i32(cpu_NF, cpu_CF, t0, cpu_CF, t1, tmp);
+ tcg_gen_sub2_i32(cpu_NF, cpu_CF, cpu_NF, cpu_CF, t1, tmp);
} else {
TCGv_i64 q0 = tcg_temp_new_i64();
TCGv_i64 q1 = tcg_temp_new_i64();
commit bf3caa3dc17552b323cec6831301a22cfc98ecd5
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Fri Feb 8 14:06:15 2013 +0100
pc: add compatibility machine types for 1.4
Adds both pc-i440fx-1.4 and pc-q35-1.4.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/hw/pc.h b/hw/pc.h
index fbcf43d..da1b102 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -187,4 +187,35 @@ void pc_system_firmware_init(MemoryRegion *rom_memory);
int e820_add_entry(uint64_t, uint64_t, uint32_t);
+#define PC_COMPAT_1_4 \
+ {\
+ .driver = "scsi-hd",\
+ .property = "discard_granularity",\
+ .value = stringify(0),\
+ },{\
+ .driver = "scsi-cd",\
+ .property = "discard_granularity",\
+ .value = stringify(0),\
+ },{\
+ .driver = "scsi-disk",\
+ .property = "discard_granularity",\
+ .value = stringify(0),\
+ },{\
+ .driver = "ide-hd",\
+ .property = "discard_granularity",\
+ .value = stringify(0),\
+ },{\
+ .driver = "ide-cd",\
+ .property = "discard_granularity",\
+ .value = stringify(0),\
+ },{\
+ .driver = "ide-drive",\
+ .property = "discard_granularity",\
+ .value = stringify(0),\
+ },{\
+ .driver = "virtio-blk-pci",\
+ .property = "discard_granularity",\
+ .value = stringify(0),\
+ }
+
#endif
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 0af436c..aa9cc81 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -294,8 +294,8 @@ static void pc_xen_hvm_init(QEMUMachineInitArgs *args)
}
#endif
-static QEMUMachine pc_i440fx_machine_v1_4 = {
- .name = "pc-i440fx-1.4",
+static QEMUMachine pc_i440fx_machine_v1_5 = {
+ .name = "pc-i440fx-1.5",
.alias = "pc",
.desc = "Standard PC (i440FX + PIIX, 1996)",
.init = pc_init_pci,
@@ -304,7 +304,20 @@ static QEMUMachine pc_i440fx_machine_v1_4 = {
DEFAULT_MACHINE_OPTIONS,
};
+static QEMUMachine pc_i440fx_machine_v1_4 = {
+ .name = "pc-i440fx-1.4",
+ .desc = "Standard PC (i440FX + PIIX, 1996)",
+ .init = pc_init_pci,
+ .max_cpus = 255,
+ .compat_props = (GlobalProperty[]) {
+ PC_COMPAT_1_4,
+ { /* end of list */ }
+ },
+ DEFAULT_MACHINE_OPTIONS,
+};
+
#define PC_COMPAT_1_3 \
+ PC_COMPAT_1_4, \
{\
.driver = "usb-tablet",\
.property = "usb_version",\
@@ -679,6 +692,7 @@ static QEMUMachine xenfv_machine = {
static void pc_machine_init(void)
{
+ qemu_register_machine(&pc_i440fx_machine_v1_5);
qemu_register_machine(&pc_i440fx_machine_v1_4);
qemu_register_machine(&pc_machine_v1_3);
qemu_register_machine(&pc_machine_v1_2);
diff --git a/hw/pc_q35.c b/hw/pc_q35.c
index 6f5ff8d..e22fb98 100644
--- a/hw/pc_q35.c
+++ b/hw/pc_q35.c
@@ -209,8 +209,8 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
}
}
-static QEMUMachine pc_q35_machine = {
- .name = "pc-q35-1.4",
+static QEMUMachine pc_q35_machine_v1_5 = {
+ .name = "pc-q35-1.5",
.alias = "q35",
.desc = "Standard PC (Q35 + ICH9, 2009)",
.init = pc_q35_init,
@@ -218,9 +218,22 @@ static QEMUMachine pc_q35_machine = {
DEFAULT_MACHINE_OPTIONS,
};
+static QEMUMachine pc_q35_machine_v1_4 = {
+ .name = "pc-q35-1.4",
+ .desc = "Standard PC (Q35 + ICH9, 2009)",
+ .init = pc_q35_init,
+ .max_cpus = 255,
+ .compat_props = (GlobalProperty[]) {
+ PC_COMPAT_1_4,
+ { /* end of list */ }
+ },
+ DEFAULT_MACHINE_OPTIONS,
+};
+
static void pc_q35_machine_init(void)
{
- qemu_register_machine(&pc_q35_machine);
+ qemu_register_machine(&pc_q35_machine_v1_5);
+ qemu_register_machine(&pc_q35_machine_v1_4);
}
machine_init(pc_q35_machine_init);
commit 215e47b9ea2cd7926333b7dc683024aa00e0c386
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Fri Feb 8 14:06:14 2013 +0100
blockdev: enable discard by default
Because discard is now a host parameter, we can always fake it as enabled
in the guest. This is an extension of the current choice to ignore
"not supported" errors from the host when discard_granularity is set
to nonzero.
The default granularity is set to the logical block size or 4k, whichever
is largest, because cluster sizes below 4k are rarely used and 4K is a
typical block size for files.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/hw/block-common.h b/hw/block-common.h
index bb808f7..dd11532 100644
--- a/hw/block-common.h
+++ b/hw/block-common.h
@@ -50,7 +50,7 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0), \
DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1), \
DEFINE_PROP_UINT32("discard_granularity", _state, \
- _conf.discard_granularity, 0)
+ _conf.discard_granularity, -1)
#define DEFINE_BLOCK_CHS_PROPERTIES(_state, _conf) \
DEFINE_PROP_UINT32("cyls", _state, _conf.cyls, 0), \
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index c436b38..fd06da7 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -143,7 +143,10 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
IDEState *s = bus->ifs + dev->unit;
- if (dev->conf.discard_granularity && dev->conf.discard_granularity != 512) {
+ if (dev->conf.discard_granularity == -1) {
+ dev->conf.discard_granularity = 512;
+ } else if (dev->conf.discard_granularity &&
+ dev->conf.discard_granularity != 512) {
error_report("discard_granularity must be 512 for ide");
return -1;
}
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 28e75bb..d411586 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -41,9 +41,11 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
#include <scsi/sg.h>
#endif
-#define SCSI_DMA_BUF_SIZE 131072
-#define SCSI_MAX_INQUIRY_LEN 256
-#define SCSI_MAX_MODE_LEN 256
+#define SCSI_DMA_BUF_SIZE 131072
+#define SCSI_MAX_INQUIRY_LEN 256
+#define SCSI_MAX_MODE_LEN 256
+
+#define DEFAULT_DISCARD_GRANULARITY 4096
typedef struct SCSIDiskState SCSIDiskState;
@@ -2059,6 +2061,11 @@ static int scsi_initfn(SCSIDevice *dev)
return -1;
}
+ if (s->qdev.conf.discard_granularity == -1) {
+ s->qdev.conf.discard_granularity =
+ MAX(s->qdev.conf.logical_block_size, DEFAULT_DISCARD_GRANULARITY);
+ }
+
if (!s->version) {
s->version = g_strdup(qemu_get_version());
}
commit ded9d2d5e247dc4d141c01bc8dc99d6ec832f9e8
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Fri Feb 8 14:06:13 2013 +0100
qemu-nbd: add --discard option
Similar to --cache and --aio, this option mimics the discard suboption
of "-drive".
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 0a6091b..e7268d0 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -33,9 +33,10 @@
#include <libgen.h>
#include <pthread.h>
-#define SOCKET_PATH "/var/lock/qemu-nbd-%s"
-#define QEMU_NBD_OPT_CACHE 1
-#define QEMU_NBD_OPT_AIO 2
+#define SOCKET_PATH "/var/lock/qemu-nbd-%s"
+#define QEMU_NBD_OPT_CACHE 1
+#define QEMU_NBD_OPT_AIO 2
+#define QEMU_NBD_OPT_DISCARD 3
static NBDExport *exp;
static int verbose;
@@ -330,6 +331,7 @@ int main(int argc, char **argv)
#ifdef CONFIG_LINUX_AIO
{ "aio", 1, NULL, QEMU_NBD_OPT_AIO },
#endif
+ { "discard", 1, NULL, QEMU_NBD_OPT_DISCARD },
{ "shared", 1, NULL, 'e' },
{ "persistent", 0, NULL, 't' },
{ "verbose", 0, NULL, 'v' },
@@ -344,6 +346,7 @@ int main(int argc, char **argv)
int ret;
int fd;
bool seen_cache = false;
+ bool seen_discard = false;
#ifdef CONFIG_LINUX_AIO
bool seen_aio = false;
#endif
@@ -389,6 +392,15 @@ int main(int argc, char **argv)
}
break;
#endif
+ case QEMU_NBD_OPT_DISCARD:
+ if (seen_discard) {
+ errx(EXIT_FAILURE, "--discard can only be specified once");
+ }
+ seen_discard = true;
+ if (bdrv_parse_discard_flags(optarg, &flags) == -1) {
+ errx(EXIT_FAILURE, "Invalid discard mode `%s'", optarg);
+ }
+ break;
case 'b':
bindto = optarg;
break;
diff --git a/qemu-nbd.texi b/qemu-nbd.texi
index 3e57200..5f3f3e3 100644
--- a/qemu-nbd.texi
+++ b/qemu-nbd.texi
@@ -35,6 +35,10 @@ Export QEMU disk image using NBD protocol.
@item --aio=@var{aio}
choose asynchronous I/O mode between @samp{threads} (the default)
and @samp{native} (Linux only).
+ at item --discard=@var{discard}
+ toggles whether @dfn{discard} (also known as @dfn{trim} or @dfn{unmap})
+ requests are ignored or passed to the filesystem. The default is no
+ (@samp{--discard=ignore}).
@item -c, --connect=@var{dev}
connect @var{filename} to NBD device @var{dev}
@item -d, --disconnect
commit a9384aff5315e7568b6ebc171f4a482e01f06526
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Fri Feb 8 14:06:12 2013 +0100
blockdev: add discard suboption to -drive
Add support for BDRV_O_UNMAP from the QEMU command-line.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/blockdev.c b/blockdev.c
index b307ed9..0e67d06 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -391,6 +391,13 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type)
}
}
+ if ((buf = qemu_opt_get(opts, "discard")) != NULL) {
+ if (bdrv_parse_discard_flags(buf, &bdrv_flags) != 0) {
+ error_report("invalid discard option");
+ return NULL;
+ }
+ }
+
bdrv_flags |= BDRV_O_CACHE_WB;
if ((buf = qemu_opt_get(opts, "cache")) != NULL) {
if (bdrv_parse_cache_flags(buf, &bdrv_flags) != 0) {
@@ -1501,6 +1508,10 @@ QemuOptsList qemu_drive_opts = {
.type = QEMU_OPT_STRING,
.help = "disk image",
},{
+ .name = "discard",
+ .type = QEMU_OPT_STRING,
+ .help = "discard operation (ignore/off, unmap/on)",
+ },{
.name = "cache",
.type = QEMU_OPT_STRING,
.help = "host cache usage (none, writeback, writethrough, "
diff --git a/qemu-options.hx b/qemu-options.hx
index 2832d82..51ff726 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -440,6 +440,8 @@ These options have the same definition as they have in @option{-hdachs}.
@var{cache} is "none", "writeback", "unsafe", "directsync" or "writethrough" and controls how the host cache is used to access block data.
@item aio=@var{aio}
@var{aio} is "threads", or "native" and selects between pthread based disk I/O and native Linux AIO.
+ at item discard=@var{discard}
+ at var{discard} is one of "ignore" (or "off") or "unmap" (or "on") and controls whether @dfn{discard} (also known as @dfn{trim} or @dfn{unmap}) requests are ignored or passed to the filesystem. Some machine types may not support discard requests.
@item format=@var{format}
Specify which disk @var{format} will be used rather than detecting
the format. Can be used to specifiy format=raw to avoid interpreting
commit 9e8f1835ea3ab3be83634f34c1bb8b69cd871766
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Fri Feb 8 14:06:11 2013 +0100
block: implement BDRV_O_UNMAP
It is better to present homogeneous hardware independent of the storage
technology that is chosen on the host, hence we make discard a host
parameter; the user can choose whether to pass it down to the image
format and protocol, or to ignore it.
Using DISCARD with filesystems can cause very severe fragmentation, so it
is left default-off for now. This can change later when we implement the
"anchor" operation for efficient management of preallocated files.
There is still one choice to make: whether DISCARD has an effect on the
dirty bitmap or not. I chose yes, though there is a disadvantage: if
the guest is buggy and issues discards for data that is in use, there
will be no way to migrate storage for that guest without downgrading
the machine type to an older one.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block.c b/block.c
index f184b37..4582961 100644
--- a/block.c
+++ b/block.c
@@ -581,6 +581,26 @@ static int refresh_total_sectors(BlockDriverState *bs, int64_t hint)
}
/**
+ * Set open flags for a given discard mode
+ *
+ * Return 0 on success, -1 if the discard mode was invalid.
+ */
+int bdrv_parse_discard_flags(const char *mode, int *flags)
+{
+ *flags &= ~BDRV_O_UNMAP;
+
+ if (!strcmp(mode, "off") || !strcmp(mode, "ignore")) {
+ /* do nothing */
+ } else if (!strcmp(mode, "on") || !strcmp(mode, "unmap")) {
+ *flags |= BDRV_O_UNMAP;
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
* Set open flags for a given cache mode
*
* Return 0 on success, -1 if the cache mode was invalid.
@@ -4191,6 +4211,11 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
bdrv_reset_dirty(bs, sector_num, nb_sectors);
}
+ /* Do nothing if disabled. */
+ if (!(bs->open_flags & BDRV_O_UNMAP)) {
+ return 0;
+ }
+
if (bs->drv->bdrv_co_discard) {
return bs->drv->bdrv_co_discard(bs, sector_num, nb_sectors);
} else if (bs->drv->bdrv_aio_discard) {
diff --git a/include/block/block.h b/include/block/block.h
index b4a24da..0f750d7 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -84,6 +84,7 @@ typedef struct BlockDevOps {
#define BDRV_O_INCOMING 0x0800 /* consistency hint for incoming migration */
#define BDRV_O_CHECK 0x1000 /* open solely for consistency check */
#define BDRV_O_ALLOW_RDWR 0x2000 /* allow reopen to change from r/o to r/w */
+#define BDRV_O_UNMAP 0x4000 /* execute guest UNMAP/TRIM operations */
#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH)
@@ -133,6 +134,7 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old);
void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top);
void bdrv_delete(BlockDriverState *bs);
int bdrv_parse_cache_flags(const char *mode, int *flags);
+int bdrv_parse_discard_flags(const char *mode, int *flags);
int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
int bdrv_open_backing_file(BlockDriverState *bs);
int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
diff --git a/qemu-io.c b/qemu-io.c
index 6188093..7b3de42 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -1899,7 +1899,7 @@ int main(int argc, char **argv)
{
int readonly = 0;
int growable = 0;
- const char *sopt = "hVc:rsnmgkt:T:";
+ const char *sopt = "hVc:d:rsnmgkt:T:";
const struct option lopt[] = {
{ "help", 0, NULL, 'h' },
{ "version", 0, NULL, 'V' },
@@ -1911,13 +1911,14 @@ int main(int argc, char **argv)
{ "misalign", 0, NULL, 'm' },
{ "growable", 0, NULL, 'g' },
{ "native-aio", 0, NULL, 'k' },
+ { "discard", 1, NULL, 'd' },
{ "cache", 1, NULL, 't' },
{ "trace", 1, NULL, 'T' },
{ NULL, 0, NULL, 0 }
};
int c;
int opt_index = 0;
- int flags = 0;
+ int flags = BDRV_O_UNMAP;
progname = basename(argv[0]);
@@ -1929,6 +1930,12 @@ int main(int argc, char **argv)
case 'n':
flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
break;
+ case 'd':
+ if (bdrv_parse_discard_flags(optarg, &flags) < 0) {
+ error_report("Invalid discard option: %s", optarg);
+ exit(1);
+ }
+ break;
case 'c':
add_user_command(optarg);
break;
commit 9a665b2b8640e464f0a778216fc2dca8d02acf33
Author: Peter Lieven <pl at dlhnet.de>
Date: Mon Feb 18 13:48:31 2013 +0100
block: complete all IOs before .bdrv_truncate
bdrv_truncate() invalidates the bdrv_check_request() result for
in-flight requests, so there should better be none.
Cc: qemu-stable at nongnu.org
Signed-off-by: Peter Lieven <pl at kamp.de>
Reported-by: Kevin Wolf <kwolf at redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block.c b/block.c
index a4d7125..f184b37 100644
--- a/block.c
+++ b/block.c
@@ -2427,6 +2427,10 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
return -EACCES;
if (bdrv_in_use(bs))
return -EBUSY;
+
+ /* There better not be any in-flight IOs when we truncate the device. */
+ bdrv_drain_all();
+
ret = drv->bdrv_truncate(bs, offset);
if (ret == 0) {
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
commit 027003152f4cf21952f9282b4487daf3fdd372ba
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Tue Feb 19 11:59:10 2013 +0100
coroutine: trim down nesting level in perf_nesting test
20000 nested coroutines require 20 GB of virtual address space.
Only nest 1000 of them so that the test (only enabled with
"-m perf" on the command line) runs on 32-bit machines too.
Cc: qemu-stable at nongnu.org
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/tests/test-coroutine.c b/tests/test-coroutine.c
index 4c6cc81..39be046 100644
--- a/tests/test-coroutine.c
+++ b/tests/test-coroutine.c
@@ -183,7 +183,7 @@ static void perf_nesting(void)
double duration;
maxcycles = 100000000;
- maxnesting = 20000;
+ maxnesting = 1000;
Coroutine *root;
NestData nd = {
.n_enter = 0,
commit 402397843e20e35d6cb7c80837c7cfdb19ede591
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Tue Feb 19 11:59:09 2013 +0100
coroutine: move pooling to common code
The coroutine pool code is duplicated between the ucontext and
sigaltstack backends, and absent from the win32 backend. But the
code can be shared easily by moving it to qemu-coroutine.c.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/coroutine-sigaltstack.c b/coroutine-sigaltstack.c
index e37ebac..b4d1762 100644
--- a/coroutine-sigaltstack.c
+++ b/coroutine-sigaltstack.c
@@ -33,15 +33,6 @@
#include "qemu-common.h"
#include "block/coroutine_int.h"
-enum {
- /* Maximum free pool size prevents holding too many freed coroutines */
- POOL_MAX_SIZE = 64,
-};
-
-/** Free list to speed up creation */
-static QSLIST_HEAD(, Coroutine) pool = QSLIST_HEAD_INITIALIZER(pool);
-static unsigned int pool_size;
-
typedef struct {
Coroutine base;
void *stack;
@@ -85,17 +76,6 @@ static void qemu_coroutine_thread_cleanup(void *opaque)
g_free(s);
}
-static void __attribute__((destructor)) coroutine_cleanup(void)
-{
- Coroutine *co;
- Coroutine *tmp;
-
- QSLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) {
- g_free(DO_UPCAST(CoroutineUContext, base, co)->stack);
- g_free(co);
- }
-}
-
static void __attribute__((constructor)) coroutine_init(void)
{
int ret;
@@ -164,7 +144,7 @@ static void coroutine_trampoline(int signal)
coroutine_bootstrap(self, co);
}
-static Coroutine *coroutine_new(void)
+Coroutine *qemu_coroutine_new(void)
{
const size_t stack_size = 1 << 20;
CoroutineUContext *co;
@@ -272,31 +252,10 @@ static Coroutine *coroutine_new(void)
return &co->base;
}
-Coroutine *qemu_coroutine_new(void)
-{
- Coroutine *co;
-
- co = QSLIST_FIRST(&pool);
- if (co) {
- QSLIST_REMOVE_HEAD(&pool, pool_next);
- pool_size--;
- } else {
- co = coroutine_new();
- }
- return co;
-}
-
void qemu_coroutine_delete(Coroutine *co_)
{
CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_);
- if (pool_size < POOL_MAX_SIZE) {
- QSLIST_INSERT_HEAD(&pool, &co->base, pool_next);
- co->base.caller = NULL;
- pool_size++;
- return;
- }
-
g_free(co->stack);
g_free(co);
}
diff --git a/coroutine-ucontext.c b/coroutine-ucontext.c
index a9c30e9..6f8ffa8 100644
--- a/coroutine-ucontext.c
+++ b/coroutine-ucontext.c
@@ -34,15 +34,6 @@
#include <valgrind/valgrind.h>
#endif
-enum {
- /* Maximum free pool size prevents holding too many freed coroutines */
- POOL_MAX_SIZE = 64,
-};
-
-/** Free list to speed up creation */
-static QSLIST_HEAD(, Coroutine) pool = QSLIST_HEAD_INITIALIZER(pool);
-static unsigned int pool_size;
-
typedef struct {
Coroutine base;
void *stack;
@@ -96,17 +87,6 @@ static void qemu_coroutine_thread_cleanup(void *opaque)
g_free(s);
}
-static void __attribute__((destructor)) coroutine_cleanup(void)
-{
- Coroutine *co;
- Coroutine *tmp;
-
- QSLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) {
- g_free(DO_UPCAST(CoroutineUContext, base, co)->stack);
- g_free(co);
- }
-}
-
static void __attribute__((constructor)) coroutine_init(void)
{
int ret;
@@ -140,7 +120,7 @@ static void coroutine_trampoline(int i0, int i1)
}
}
-static Coroutine *coroutine_new(void)
+Coroutine *qemu_coroutine_new(void)
{
const size_t stack_size = 1 << 20;
CoroutineUContext *co;
@@ -185,20 +165,6 @@ static Coroutine *coroutine_new(void)
return &co->base;
}
-Coroutine *qemu_coroutine_new(void)
-{
- Coroutine *co;
-
- co = QSLIST_FIRST(&pool);
- if (co) {
- QSLIST_REMOVE_HEAD(&pool, pool_next);
- pool_size--;
- } else {
- co = coroutine_new();
- }
- return co;
-}
-
#ifdef CONFIG_VALGRIND_H
#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
/* Work around an unused variable in the valgrind.h macro... */
@@ -217,13 +183,6 @@ void qemu_coroutine_delete(Coroutine *co_)
{
CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_);
- if (pool_size < POOL_MAX_SIZE) {
- QSLIST_INSERT_HEAD(&pool, &co->base, pool_next);
- co->base.caller = NULL;
- pool_size++;
- return;
- }
-
#ifdef CONFIG_VALGRIND_H
valgrind_stack_deregister(co);
#endif
diff --git a/qemu-coroutine.c b/qemu-coroutine.c
index 0f6e268..25a14c6 100644
--- a/qemu-coroutine.c
+++ b/qemu-coroutine.c
@@ -17,13 +17,54 @@
#include "block/coroutine.h"
#include "block/coroutine_int.h"
+enum {
+ /* Maximum free pool size prevents holding too many freed coroutines */
+ POOL_MAX_SIZE = 64,
+};
+
+/** Free list to speed up creation */
+static QSLIST_HEAD(, Coroutine) pool = QSLIST_HEAD_INITIALIZER(pool);
+static unsigned int pool_size;
+
Coroutine *qemu_coroutine_create(CoroutineEntry *entry)
{
- Coroutine *co = qemu_coroutine_new();
+ Coroutine *co;
+
+ co = QSLIST_FIRST(&pool);
+ if (co) {
+ QSLIST_REMOVE_HEAD(&pool, pool_next);
+ pool_size--;
+ } else {
+ co = qemu_coroutine_new();
+ }
+
co->entry = entry;
return co;
}
+static void coroutine_delete(Coroutine *co)
+{
+ if (pool_size < POOL_MAX_SIZE) {
+ QSLIST_INSERT_HEAD(&pool, co, pool_next);
+ co->caller = NULL;
+ pool_size++;
+ return;
+ }
+
+ qemu_coroutine_delete(co);
+}
+
+static void __attribute__((destructor)) coroutine_cleanup(void)
+{
+ Coroutine *co;
+ Coroutine *tmp;
+
+ QSLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) {
+ QSLIST_REMOVE_HEAD(&pool, pool_next);
+ qemu_coroutine_delete(co);
+ }
+}
+
static void coroutine_swap(Coroutine *from, Coroutine *to)
{
CoroutineAction ret;
@@ -35,7 +76,7 @@ static void coroutine_swap(Coroutine *from, Coroutine *to)
return;
case COROUTINE_TERMINATE:
trace_qemu_coroutine_terminate(to);
- qemu_coroutine_delete(to);
+ coroutine_delete(to);
return;
default:
abort();
commit 4dc9f9d67dbf5d062d8db188b81cef435f291dd8
Author: Kevin Wolf <kwolf at redhat.com>
Date: Tue Jan 29 10:46:52 2013 +0100
qemu-iotests: Test qcow2 image creation options
Just create lots of images and try out each of the creation options that
qcow2 provides (except backing_file/fmt for now)
I'm not totally happy with the behaviour of qemu-img in each of the
cases, but let's be explicit and update the test when we do change
things later.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/tests/qemu-iotests/049 b/tests/qemu-iotests/049
new file mode 100755
index 0000000..6c6017e
--- /dev/null
+++ b/tests/qemu-iotests/049
@@ -0,0 +1,123 @@
+#!/bin/bash
+#
+# Check qemu-img option parsing
+#
+# Copyright (C) 2013 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=kwolf at redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+function filter_test_dir()
+{
+ sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
+ -e "s#$TEST_DIR#TEST_DIR#g"
+}
+
+function test_qemu_img()
+{
+ echo qemu-img "$@" | filter_test_dir
+ $QEMU_IMG "$@" 2>&1 | filter_test_dir
+ echo
+}
+
+echo "=== Check correct interpretation of suffixes for image size ==="
+echo
+sizes="1024 1024b 1k 1K 1M 1G 1T "
+sizes+="1024.0 1024.0b 1.5k 1.5K 1.5M 1.5G 1.5T"
+
+echo "== 1. Traditional size parameter =="
+echo
+for s in $sizes; do
+ test_qemu_img create -f $IMGFMT $TEST_IMG $s
+done
+
+echo "== 2. Specifying size via -o =="
+echo
+for s in $sizes; do
+ test_qemu_img create -f $IMGFMT -o size=$s $TEST_IMG
+done
+
+echo "== 3. Invalid sizes =="
+echo
+sizes="-1024 -1k 1kilobyte foobar"
+
+for s in $sizes; do
+ test_qemu_img create -f $IMGFMT $TEST_IMG -- $s
+ test_qemu_img create -f $IMGFMT -o size=$s $TEST_IMG
+done
+
+echo "== Check correct interpretation of suffixes for cluster size =="
+echo
+sizes="1024 1024b 1k 1K 1M "
+sizes+="1024.0 1024.0b 0.5k 0.5K 0.5M"
+
+for s in $sizes; do
+ test_qemu_img create -f $IMGFMT -o cluster_size=$s $TEST_IMG 64M
+done
+
+echo "== Check compat level option =="
+echo
+test_qemu_img create -f $IMGFMT -o compat=0.10 $TEST_IMG 64M
+test_qemu_img create -f $IMGFMT -o compat=1.1 $TEST_IMG 64M
+
+test_qemu_img create -f $IMGFMT -o compat=0.42 $TEST_IMG 64M
+test_qemu_img create -f $IMGFMT -o compat=foobar $TEST_IMG 64M
+
+echo "== Check preallocation option =="
+echo
+test_qemu_img create -f $IMGFMT -o preallocation=off $TEST_IMG 64M
+test_qemu_img create -f $IMGFMT -o preallocation=metadata $TEST_IMG 64M
+test_qemu_img create -f $IMGFMT -o preallocation=1234 $TEST_IMG 64M
+
+echo "== Check encryption option =="
+echo
+test_qemu_img create -f $IMGFMT -o encryption=off $TEST_IMG 64M
+test_qemu_img create -f $IMGFMT -o encryption=on $TEST_IMG 64M
+
+echo "== Check lazy_refcounts option (only with v3) =="
+echo
+test_qemu_img create -f $IMGFMT -o compat=1.1,lazy_refcounts=off $TEST_IMG 64M
+test_qemu_img create -f $IMGFMT -o compat=1.1,lazy_refcounts=on $TEST_IMG 64M
+
+test_qemu_img create -f $IMGFMT -o compat=0.10,lazy_refcounts=off $TEST_IMG 64M
+test_qemu_img create -f $IMGFMT -o compat=0.10,lazy_refcounts=on $TEST_IMG 64M
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out
new file mode 100644
index 0000000..72db13f
--- /dev/null
+++ b/tests/qemu-iotests/049.out
@@ -0,0 +1,212 @@
+QA output created by 049
+=== Check correct interpretation of suffixes for image size ===
+
+== 1. Traditional size parameter ==
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024b
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1k
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1K
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1G
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1T
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0b
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5k
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5K
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5G
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5T
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 encryption=off cluster_size=65536 lazy_refcounts=off
+
+== 2. Specifying size via -o ==
+
+qemu-img create -f qcow2 -o size=1024 TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1024b TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1k TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1K TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1M TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1G TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1T TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1024.0 TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1024.0b TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1.5k TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1.5K TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1.5M TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1.5G TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1.5T TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 encryption=off cluster_size=65536 lazy_refcounts=off
+
+== 3. Invalid sizes ==
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- -1024
+qemu-img: Image size must be less than 8 EiB!
+
+qemu-img create -f qcow2 -o size=-1024 TEST_DIR/t.qcow2
+qemu-img: qcow2 doesn't support shrinking images yet
+qemu-img: Formatting or formatting option not supported for file format 'qcow2'
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=-1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- -1k
+qemu-img: Image size must be less than 8 EiB!
+
+qemu-img create -f qcow2 -o size=-1k TEST_DIR/t.qcow2
+qemu-img: qcow2 doesn't support shrinking images yet
+qemu-img: Formatting or formatting option not supported for file format 'qcow2'
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=-1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- 1kilobyte
+qemu-img: Invalid image size specified! You may use k, M, G or T suffixes for
+qemu-img: kilobytes, megabytes, gigabytes and terabytes.
+
+qemu-img create -f qcow2 -o size=1kilobyte TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- foobar
+qemu-img: Invalid image size specified! You may use k, M, G or T suffixes for
+qemu-img: kilobytes, megabytes, gigabytes and terabytes.
+
+qemu-img create -f qcow2 -o size=foobar TEST_DIR/t.qcow2
+qemu-img: Parameter 'size' expects a size
+qemu-img: Invalid options for file format 'qcow2'.
+
+== Check correct interpretation of suffixes for cluster size ==
+
+qemu-img create -f qcow2 -o cluster_size=1024 TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o cluster_size=1024b TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o cluster_size=1k TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o cluster_size=1K TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o cluster_size=1M TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1048576 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o cluster_size=1024.0 TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o cluster_size=1024.0b TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o cluster_size=0.5k TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=512 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o cluster_size=0.5K TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=512 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o cluster_size=0.5M TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=524288 lazy_refcounts=off
+
+== Check compat level option ==
+
+qemu-img create -f qcow2 -o compat=0.10 TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.10' encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o compat=1.1 TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='1.1' encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o compat=0.42 TEST_DIR/t.qcow2 64M
+Invalid compatibility level: '0.42'
+qemu-img: TEST_DIR/t.qcow2: error while creating qcow2: Invalid argument
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.42' encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o compat=foobar TEST_DIR/t.qcow2 64M
+Invalid compatibility level: 'foobar'
+qemu-img: TEST_DIR/t.qcow2: error while creating qcow2: Invalid argument
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='foobar' encryption=off cluster_size=65536 lazy_refcounts=off
+
+== Check preallocation option ==
+
+qemu-img create -f qcow2 -o preallocation=off TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation='off' lazy_refcounts=off
+
+qemu-img create -f qcow2 -o preallocation=metadata TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation='metadata' lazy_refcounts=off
+
+qemu-img create -f qcow2 -o preallocation=1234 TEST_DIR/t.qcow2 64M
+Invalid preallocation mode: '1234'
+qemu-img: TEST_DIR/t.qcow2: error while creating qcow2: Invalid argument
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation='1234' lazy_refcounts=off
+
+== Check encryption option ==
+
+qemu-img create -f qcow2 -o encryption=off TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o encryption=on TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on cluster_size=65536 lazy_refcounts=off
+
+== Check lazy_refcounts option (only with v3) ==
+
+qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=off TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='1.1' encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=on TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='1.1' encryption=off cluster_size=65536 lazy_refcounts=on
+
+qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=off TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.10' encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=on TEST_DIR/t.qcow2 64M
+Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater)
+qemu-img: TEST_DIR/t.qcow2: error while creating qcow2: Invalid argument
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.10' encryption=off cluster_size=65536 lazy_refcounts=on
+
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 1c0dfef..fcf57e0 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -55,3 +55,4 @@
046 rw auto aio
047 rw auto
048 img auto quick
+049 rw auto
commit e930d201bc8066a314b9e115e4a2afca50f9c504
Author: Miroslav Rezanina <mrezanin at redhat.com>
Date: Wed Feb 13 09:09:42 2013 +0100
qemu-iotests: Add qemu-img compare test
Simple test for qemu-img compare to check it's working correctly.
Signed-off-by: Miroslav Rezanina <mrezanin at redhat.com>
Reviewed-by: Kevin Wolf <kwolf at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/tests/qemu-iotests/048 b/tests/qemu-iotests/048
new file mode 100755
index 0000000..7cce049
--- /dev/null
+++ b/tests/qemu-iotests/048
@@ -0,0 +1,78 @@
+#!/bin/bash
+##
+## qemu-img compare test
+##
+##
+## Copyright (C) 2013 Red Hat, Inc.
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program. If not, see <http://www.gnu.org/licenses/>.
+##
+#
+# creator
+owner=mrezanin at redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+status=1 # failure is the default!
+
+_cleanup()
+{
+ echo "Cleanup"
+ _cleanup_test_img
+ rm ${TEST_IMG2}
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_compare()
+{
+ $QEMU_IMG compare "$@" $TEST_IMG ${TEST_IMG2}
+ echo $?
+}
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+. ./common.pattern
+
+_supported_fmt raw qcow qcow2 qed
+_supported_proto file
+_supported_os Linux
+
+# Setup test basic parameters
+TEST_IMG2=$TEST_IMG.2
+CLUSTER_SIZE=4096
+size=1024M
+
+_make_test_img $size
+io_pattern write 524288 $CLUSTER_SIZE $CLUSTER_SIZE 4 45
+
+# Compare identical images
+cp $TEST_IMG ${TEST_IMG2}
+_compare
+_compare -q
+
+# Compare images with different size
+$QEMU_IMG resize $TEST_IMG +512M
+_compare
+_compare -s
+
+# Compare images with different content
+io_pattern write 1228800 $CLUSTER_SIZE 0 1 67
+_compare
+io_pattern write 0 $CLUSTER_SIZE 0 1 123
+_compare
+
+# Cleanup
+status=0
diff --git a/tests/qemu-iotests/048.out b/tests/qemu-iotests/048.out
new file mode 100644
index 0000000..68f65d5
--- /dev/null
+++ b/tests/qemu-iotests/048.out
@@ -0,0 +1,31 @@
+QA output created by 048
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+=== IO: pattern 45
+qemu-io> wrote 4096/4096 bytes at offset 524288
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 4096/4096 bytes at offset 528384
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 4096/4096 bytes at offset 532480
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 4096/4096 bytes at offset 536576
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> Images are identical.
+0
+0
+Image resized.
+Warning: Image size mismatch!
+Images are identical.
+0
+Strict mode: Image size mismatch!
+1
+=== IO: pattern 67
+qemu-io> wrote 4096/4096 bytes at offset 1228800
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> Content mismatch at offset 1228800!
+1
+=== IO: pattern 123
+qemu-io> wrote 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> Content mismatch at offset 0!
+1
+Cleanup
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 1bbd2bf..1c0dfef 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -54,3 +54,4 @@
045 rw auto
046 rw auto aio
047 rw auto
+048 img auto quick
commit d14ed18c8d10a936e6f8b55f56afb4b75c305e10
Author: Miroslav Rezanina <mrezanin at redhat.com>
Date: Wed Feb 13 09:09:41 2013 +0100
qemu-img: Add compare subcommand
This patch adds new qemu-img subcommand that compares content of two disk
images.
Signed-off-by: Miroslav Rezanina <mrezanin at redhat.com>
Reviewed-by: Kevin Wolf <kwolf at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
index 9283776..4ca7e95 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -27,6 +27,12 @@ STEXI
@item commit [-q] [-f @var{fmt}] [-t @var{cache}] @var{filename}
ETEXI
+DEF("compare", img_compare,
+ "compare [-f fmt] [-F fmt] [-p] [-q] [-s] filename1 filename2")
+STEXI
+ at item compare [-f @var{fmt}] [-F @var{fmt}] [-p] [-q] [-s] @var{filename1} @var{filename2}
+ETEXI
+
DEF("convert", img_convert,
"convert [-c] [-p] [-q] [-f fmt] [-t cache] [-O output_fmt] [-o options] [-s snapshot_name] [-S sparse_size] filename [filename2 [...]] output_filename")
STEXI
diff --git a/qemu-img.c b/qemu-img.c
index 3e2996e..471de7d 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -113,7 +113,12 @@ static void help(void)
" '-a' applies a snapshot (revert disk to saved state)\n"
" '-c' creates a snapshot\n"
" '-d' deletes a snapshot\n"
- " '-l' lists all snapshots in the given image\n";
+ " '-l' lists all snapshots in the given image\n"
+ "\n"
+ "Parameters to compare subcommand:\n"
+ " '-f' first image format\n"
+ " '-F' second image format\n"
+ " '-s' run in Strict mode - fail on different image size or sector allocation\n";
printf("%s\nSupported formats:", help_msg);
bdrv_iterate_format(format_print, NULL);
@@ -820,6 +825,289 @@ static int compare_sectors(const uint8_t *buf1, const uint8_t *buf2, int n,
#define IO_BUF_SIZE (2 * 1024 * 1024)
+static int64_t sectors_to_bytes(int64_t sectors)
+{
+ return sectors << BDRV_SECTOR_BITS;
+}
+
+static int64_t sectors_to_process(int64_t total, int64_t from)
+{
+ return MIN(total - from, IO_BUF_SIZE >> BDRV_SECTOR_BITS);
+}
+
+/*
+ * Check if passed sectors are empty (not allocated or contain only 0 bytes)
+ *
+ * Returns 0 in case sectors are filled with 0, 1 if sectors contain non-zero
+ * data and negative value on error.
+ *
+ * @param bs: Driver used for accessing file
+ * @param sect_num: Number of first sector to check
+ * @param sect_count: Number of sectors to check
+ * @param filename: Name of disk file we are checking (logging purpose)
+ * @param buffer: Allocated buffer for storing read data
+ * @param quiet: Flag for quiet mode
+ */
+static int check_empty_sectors(BlockDriverState *bs, int64_t sect_num,
+ int sect_count, const char *filename,
+ uint8_t *buffer, bool quiet)
+{
+ int pnum, ret = 0;
+ ret = bdrv_read(bs, sect_num, buffer, sect_count);
+ if (ret < 0) {
+ error_report("Error while reading offset %" PRId64 " of %s: %s",
+ sectors_to_bytes(sect_num), filename, strerror(-ret));
+ return ret;
+ }
+ ret = is_allocated_sectors(buffer, sect_count, &pnum);
+ if (ret || pnum != sect_count) {
+ qprintf(quiet, "Content mismatch at offset %" PRId64 "!\n",
+ sectors_to_bytes(ret ? sect_num : sect_num + pnum));
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Compares two images. Exit codes:
+ *
+ * 0 - Images are identical
+ * 1 - Images differ
+ * >1 - Error occurred
+ */
+static int img_compare(int argc, char **argv)
+{
+ const char *fmt1 = NULL, *fmt2 = NULL, *filename1, *filename2;
+ BlockDriverState *bs1, *bs2;
+ int64_t total_sectors1, total_sectors2;
+ uint8_t *buf1 = NULL, *buf2 = NULL;
+ int pnum1, pnum2;
+ int allocated1, allocated2;
+ int ret = 0; /* return value - 0 Ident, 1 Different, >1 Error */
+ bool progress = false, quiet = false, strict = false;
+ int64_t total_sectors;
+ int64_t sector_num = 0;
+ int64_t nb_sectors;
+ int c, pnum;
+ uint64_t bs_sectors;
+ uint64_t progress_base;
+
+ for (;;) {
+ c = getopt(argc, argv, "hpf:F:sq");
+ if (c == -1) {
+ break;
+ }
+ switch (c) {
+ case '?':
+ case 'h':
+ help();
+ break;
+ case 'f':
+ fmt1 = optarg;
+ break;
+ case 'F':
+ fmt2 = optarg;
+ break;
+ case 'p':
+ progress = true;
+ break;
+ case 'q':
+ quiet = true;
+ break;
+ case 's':
+ strict = true;
+ break;
+ }
+ }
+
+ /* Progress is not shown in Quiet mode */
+ if (quiet) {
+ progress = false;
+ }
+
+
+ if (optind > argc - 2) {
+ help();
+ }
+ filename1 = argv[optind++];
+ filename2 = argv[optind++];
+
+ /* Initialize before goto out */
+ qemu_progress_init(progress, 2.0);
+
+ bs1 = bdrv_new_open(filename1, fmt1, BDRV_O_FLAGS, true, quiet);
+ if (!bs1) {
+ error_report("Can't open file %s", filename1);
+ ret = 2;
+ goto out3;
+ }
+
+ bs2 = bdrv_new_open(filename2, fmt2, BDRV_O_FLAGS, true, quiet);
+ if (!bs2) {
+ error_report("Can't open file %s", filename2);
+ ret = 2;
+ goto out2;
+ }
+
+ buf1 = qemu_blockalign(bs1, IO_BUF_SIZE);
+ buf2 = qemu_blockalign(bs2, IO_BUF_SIZE);
+ bdrv_get_geometry(bs1, &bs_sectors);
+ total_sectors1 = bs_sectors;
+ bdrv_get_geometry(bs2, &bs_sectors);
+ total_sectors2 = bs_sectors;
+ total_sectors = MIN(total_sectors1, total_sectors2);
+ progress_base = MAX(total_sectors1, total_sectors2);
+
+ qemu_progress_print(0, 100);
+
+ if (strict && total_sectors1 != total_sectors2) {
+ ret = 1;
+ qprintf(quiet, "Strict mode: Image size mismatch!\n");
+ goto out;
+ }
+
+ for (;;) {
+ nb_sectors = sectors_to_process(total_sectors, sector_num);
+ if (nb_sectors <= 0) {
+ break;
+ }
+ allocated1 = bdrv_is_allocated_above(bs1, NULL, sector_num, nb_sectors,
+ &pnum1);
+ if (allocated1 < 0) {
+ ret = 3;
+ error_report("Sector allocation test failed for %s", filename1);
+ goto out;
+ }
+
+ allocated2 = bdrv_is_allocated_above(bs2, NULL, sector_num, nb_sectors,
+ &pnum2);
+ if (allocated2 < 0) {
+ ret = 3;
+ error_report("Sector allocation test failed for %s", filename2);
+ goto out;
+ }
+ nb_sectors = MIN(pnum1, pnum2);
+
+ if (allocated1 == allocated2) {
+ if (allocated1) {
+ ret = bdrv_read(bs1, sector_num, buf1, nb_sectors);
+ if (ret < 0) {
+ error_report("Error while reading offset %" PRId64 " of %s:"
+ " %s", sectors_to_bytes(sector_num), filename1,
+ strerror(-ret));
+ ret = 4;
+ goto out;
+ }
+ ret = bdrv_read(bs2, sector_num, buf2, nb_sectors);
+ if (ret < 0) {
+ error_report("Error while reading offset %" PRId64
+ " of %s: %s", sectors_to_bytes(sector_num),
+ filename2, strerror(-ret));
+ ret = 4;
+ goto out;
+ }
+ ret = compare_sectors(buf1, buf2, nb_sectors, &pnum);
+ if (ret || pnum != nb_sectors) {
+ ret = 1;
+ qprintf(quiet, "Content mismatch at offset %" PRId64 "!\n",
+ sectors_to_bytes(
+ ret ? sector_num : sector_num + pnum));
+ goto out;
+ }
+ }
+ } else {
+ if (strict) {
+ ret = 1;
+ qprintf(quiet, "Strict mode: Offset %" PRId64
+ " allocation mismatch!\n",
+ sectors_to_bytes(sector_num));
+ goto out;
+ }
+
+ if (allocated1) {
+ ret = check_empty_sectors(bs1, sector_num, nb_sectors,
+ filename1, buf1, quiet);
+ } else {
+ ret = check_empty_sectors(bs2, sector_num, nb_sectors,
+ filename2, buf1, quiet);
+ }
+ if (ret) {
+ if (ret < 0) {
+ ret = 4;
+ error_report("Error while reading offset %" PRId64 ": %s",
+ sectors_to_bytes(sector_num), strerror(-ret));
+ }
+ goto out;
+ }
+ }
+ sector_num += nb_sectors;
+ qemu_progress_print(((float) nb_sectors / progress_base)*100, 100);
+ }
+
+ if (total_sectors1 != total_sectors2) {
+ BlockDriverState *bs_over;
+ int64_t total_sectors_over;
+ const char *filename_over;
+
+ qprintf(quiet, "Warning: Image size mismatch!\n");
+ if (total_sectors1 > total_sectors2) {
+ total_sectors_over = total_sectors1;
+ bs_over = bs1;
+ filename_over = filename1;
+ } else {
+ total_sectors_over = total_sectors2;
+ bs_over = bs2;
+ filename_over = filename2;
+ }
+
+ for (;;) {
+ nb_sectors = sectors_to_process(total_sectors_over, sector_num);
+ if (nb_sectors <= 0) {
+ break;
+ }
+ ret = bdrv_is_allocated_above(bs_over, NULL, sector_num,
+ nb_sectors, &pnum);
+ if (ret < 0) {
+ ret = 3;
+ error_report("Sector allocation test failed for %s",
+ filename_over);
+ goto out;
+
+ }
+ nb_sectors = pnum;
+ if (ret) {
+ ret = check_empty_sectors(bs_over, sector_num, nb_sectors,
+ filename_over, buf1, quiet);
+ if (ret) {
+ if (ret < 0) {
+ ret = 4;
+ error_report("Error while reading offset %" PRId64
+ " of %s: %s", sectors_to_bytes(sector_num),
+ filename_over, strerror(-ret));
+ }
+ goto out;
+ }
+ }
+ sector_num += nb_sectors;
+ qemu_progress_print(((float) nb_sectors / progress_base)*100, 100);
+ }
+ }
+
+ qprintf(quiet, "Images are identical.\n");
+ ret = 0;
+
+out:
+ bdrv_delete(bs2);
+ qemu_vfree(buf1);
+ qemu_vfree(buf2);
+out2:
+ bdrv_delete(bs1);
+out3:
+ qemu_progress_end();
+ return ret;
+}
+
static int img_convert(int argc, char **argv)
{
int c, ret = 0, n, n1, bs_n, bs_i, compress, cluster_size, cluster_sectors;
diff --git a/qemu-img.texi b/qemu-img.texi
index 43430fb..69f1bda 100644
--- a/qemu-img.texi
+++ b/qemu-img.texi
@@ -84,6 +84,18 @@ deletes a snapshot
lists all snapshots in the given image
@end table
+Parameters to compare subcommand:
+
+ at table @option
+
+ at item -f
+First image format
+ at item -F
+Second image format
+ at item -s
+Strict mode - fail on on different image size or sector allocation
+ at end table
+
Command description:
@table @option
@@ -118,6 +130,47 @@ it doesn't need to be specified separately in this case.
Commit the changes recorded in @var{filename} in its base image.
+ at item compare [-f @var{fmt}] [-F @var{fmt}] [-p] [-s] [-q] @var{filename1} @var{filename2}
+
+Check if two images have the same content. You can compare images with
+different format or settings.
+
+The format is probed unless you specify it by @var{-f} (used for
+ at var{filename1}) and/or @var{-F} (used for @var{filename2}) option.
+
+By default, images with different size are considered identical if the larger
+image contains only unallocated and/or zeroed sectors in the area after the end
+of the other image. In addition, if any sector is not allocated in one image
+and contains only zero bytes in the second one, it is evaluated as equal. You
+can use Strict mode by specifying the @var{-s} option. When compare runs in
+Strict mode, it fails in case image size differs or a sector is allocated in
+one image and is not allocated in the second one.
+
+By default, compare prints out a result message. This message displays
+information that both images are same or the position of the first different
+byte. In addition, result message can report different image size in case
+Strict mode is used.
+
+Compare exits with @code{0} in case the images are equal and with @code{1}
+in case the images differ. Other exit codes mean an error occurred during
+execution and standard error output should contain an error message.
+The following table sumarizes all exit codes of the compare subcommand:
+
+ at table @option
+
+ at item 0
+Images are identical
+ at item 1
+Images differ
+ at item 2
+Error on opening an image
+ at item 3
+Error on checking a sector allocation
+ at item 4
+Error on reading data
+
+ at end table
+
@item convert [-c] [-p] [-f @var{fmt}] [-t @var{cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename}
Convert the disk image @var{filename} or a snapshot @var{snapshot_name} to disk image @var{output_filename}
commit f382d43a9180ed20c671dc058d5452c2df7d3c61
Author: Miroslav Rezanina <mrezanin at redhat.com>
Date: Wed Feb 13 09:09:40 2013 +0100
qemu-img: Add "Quiet mode" option
There can be a need to turn output to stdout off. This patch adds a -q option
that enable "Quiet mode". In Quiet mode, only errors are printed out.
Signed-off-by: Miroslav Rezanina <mrezanin at redhat.com>
Reviewed-by: Kevin Wolf <kwolf at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/block.c b/block.c
index 08039d2..a4d7125 100644
--- a/block.c
+++ b/block.c
@@ -4470,7 +4470,8 @@ bdrv_acct_done(BlockDriverState *bs, BlockAcctCookie *cookie)
void bdrv_img_create(const char *filename, const char *fmt,
const char *base_filename, const char *base_fmt,
- char *options, uint64_t img_size, int flags, Error **errp)
+ char *options, uint64_t img_size, int flags,
+ Error **errp, bool quiet)
{
QEMUOptionParameter *param = NULL, *create_options = NULL;
QEMUOptionParameter *backing_fmt, *backing_file, *size;
@@ -4579,10 +4580,11 @@ void bdrv_img_create(const char *filename, const char *fmt,
}
}
- printf("Formatting '%s', fmt=%s ", filename, fmt);
- print_option_parameters(param);
- puts("");
-
+ if (!quiet) {
+ printf("Formatting '%s', fmt=%s ", filename, fmt);
+ print_option_parameters(param);
+ puts("");
+ }
ret = bdrv_create(drv, filename, param);
if (ret < 0) {
if (ret == -ENOTSUP) {
diff --git a/blockdev.c b/blockdev.c
index ba3759c..b307ed9 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -804,7 +804,7 @@ void qmp_transaction(BlockdevActionList *dev_list, Error **errp)
bdrv_img_create(new_image_file, format,
states->old_bs->filename,
states->old_bs->drv->format_name,
- NULL, -1, flags, &local_err);
+ NULL, -1, flags, &local_err, false);
if (error_is_set(&local_err)) {
error_propagate(errp, local_err);
goto delete_and_fail;
@@ -1296,7 +1296,7 @@ void qmp_drive_mirror(const char *device, const char *target,
/* create new image w/o backing file */
assert(format && drv);
bdrv_img_create(target, format,
- NULL, NULL, NULL, size, flags, &local_err);
+ NULL, NULL, NULL, size, flags, &local_err, false);
} else {
switch (mode) {
case NEW_IMAGE_MODE_EXISTING:
@@ -1307,7 +1307,7 @@ void qmp_drive_mirror(const char *device, const char *target,
bdrv_img_create(target, format,
source->filename,
source->drv->format_name,
- NULL, size, flags, &local_err);
+ NULL, size, flags, &local_err, false);
break;
default:
abort();
diff --git a/include/block/block.h b/include/block/block.h
index 94d84b4..b4a24da 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -353,7 +353,8 @@ int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
void bdrv_img_create(const char *filename, const char *fmt,
const char *base_filename, const char *base_fmt,
- char *options, uint64_t img_size, int flags, Error **errp);
+ char *options, uint64_t img_size, int flags,
+ Error **errp, bool quiet);
void bdrv_set_buffer_alignment(BlockDriverState *bs, int align);
void *qemu_blockalign(BlockDriverState *bs, size_t size);
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
index 259fc14..9283776 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -10,27 +10,27 @@ STEXI
ETEXI
DEF("check", img_check,
- "check [-f fmt] [--output=ofmt] [-r [leaks | all]] filename")
+ "check [-q] [-f fmt] [--output=ofmt] [-r [leaks | all]] filename")
STEXI
- at item check [-f @var{fmt}] [--output=@var{ofmt}] [-r [leaks | all]] @var{filename}
+ at item check [-q] [-f @var{fmt}] [--output=@var{ofmt}] [-r [leaks | all]] @var{filename}
ETEXI
DEF("create", img_create,
- "create [-f fmt] [-o options] filename [size]")
+ "create [-q] [-f fmt] [-o options] filename [size]")
STEXI
- at item create [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}]
+ at item create [-q] [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}]
ETEXI
DEF("commit", img_commit,
- "commit [-f fmt] [-t cache] filename")
+ "commit [-q] [-f fmt] [-t cache] filename")
STEXI
- at item commit [-f @var{fmt}] [-t @var{cache}] @var{filename}
+ at item commit [-q] [-f @var{fmt}] [-t @var{cache}] @var{filename}
ETEXI
DEF("convert", img_convert,
- "convert [-c] [-p] [-f fmt] [-t cache] [-O output_fmt] [-o options] [-s snapshot_name] [-S sparse_size] filename [filename2 [...]] output_filename")
+ "convert [-c] [-p] [-q] [-f fmt] [-t cache] [-O output_fmt] [-o options] [-s snapshot_name] [-S sparse_size] filename [filename2 [...]] output_filename")
STEXI
- at item convert [-c] [-p] [-f @var{fmt}] [-t @var{cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename}
+ at item convert [-c] [-p] [-q] [-f @var{fmt}] [-t @var{cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename}
ETEXI
DEF("info", img_info,
@@ -40,20 +40,20 @@ STEXI
ETEXI
DEF("snapshot", img_snapshot,
- "snapshot [-l | -a snapshot | -c snapshot | -d snapshot] filename")
+ "snapshot [-q] [-l | -a snapshot | -c snapshot | -d snapshot] filename")
STEXI
- at item snapshot [-l | -a @var{snapshot} | -c @var{snapshot} | -d @var{snapshot}] @var{filename}
+ at item snapshot [-q] [-l | -a @var{snapshot} | -c @var{snapshot} | -d @var{snapshot}] @var{filename}
ETEXI
DEF("rebase", img_rebase,
- "rebase [-f fmt] [-t cache] [-p] [-u] -b backing_file [-F backing_fmt] filename")
+ "rebase [-q] [-f fmt] [-t cache] [-p] [-u] -b backing_file [-F backing_fmt] filename")
STEXI
- at item rebase [-f @var{fmt}] [-t @var{cache}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
+ at item rebase [-q] [-f @var{fmt}] [-t @var{cache}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
ETEXI
DEF("resize", img_resize,
- "resize filename [+ | -]size")
+ "resize [-q] filename [+ | -]size")
STEXI
- at item resize @var{filename} [+ | -]@var{size}
+ at item resize [-q] @var{filename} [+ | -]@var{size}
@end table
ETEXI
diff --git a/qemu-img.c b/qemu-img.c
index fa9b2af..3e2996e 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -32,6 +32,7 @@
#include "block/block_int.h"
#include <getopt.h>
#include <stdio.h>
+#include <stdarg.h>
#ifdef _WIN32
#include <windows.h>
@@ -96,6 +97,7 @@ static void help(void)
" rebasing in this case (useful for renaming the backing file)\n"
" '-h' with or without a command shows this help and lists the supported formats\n"
" '-p' show progress of command (only certain commands)\n"
+ " '-q' use Quiet mode - do not print any output (except errors)\n"
" '-S' indicates the consecutive number of bytes that must contain only zeros\n"
" for qemu-img to create a sparse image during conversion\n"
" '--output' takes the format in which the output must be done (human or json)\n"
@@ -119,6 +121,18 @@ static void help(void)
exit(1);
}
+static int qprintf(bool quiet, const char *fmt, ...)
+{
+ int ret = 0;
+ if (!quiet) {
+ va_list args;
+ va_start(args, fmt);
+ ret = vprintf(fmt, args);
+ va_end(args);
+ }
+ return ret;
+}
+
#if defined(WIN32)
/* XXX: put correct support for win32 */
static int read_password(char *buf, int buf_size)
@@ -237,7 +251,8 @@ static int print_block_option_help(const char *filename, const char *fmt)
static BlockDriverState *bdrv_new_open(const char *filename,
const char *fmt,
int flags,
- bool require_io)
+ bool require_io,
+ bool quiet)
{
BlockDriverState *bs;
BlockDriver *drv;
@@ -263,7 +278,7 @@ static BlockDriverState *bdrv_new_open(const char *filename,
}
if (bdrv_is_encrypted(bs) && require_io) {
- printf("Disk image '%s' is encrypted.\n", filename);
+ qprintf(quiet, "Disk image '%s' is encrypted.\n", filename);
if (read_password(password, sizeof(password)) < 0) {
error_report("No password given");
goto fail;
@@ -312,9 +327,10 @@ static int img_create(int argc, char **argv)
const char *base_filename = NULL;
char *options = NULL;
Error *local_err = NULL;
+ bool quiet = false;
for(;;) {
- c = getopt(argc, argv, "F:b:f:he6o:");
+ c = getopt(argc, argv, "F:b:f:he6o:q");
if (c == -1) {
break;
}
@@ -343,6 +359,9 @@ static int img_create(int argc, char **argv)
case 'o':
options = optarg;
break;
+ case 'q':
+ quiet = true;
+ break;
}
}
@@ -375,7 +394,7 @@ static int img_create(int argc, char **argv)
}
bdrv_img_create(filename, fmt, base_filename, base_fmt,
- options, img_size, BDRV_O_FLAGS, &local_err);
+ options, img_size, BDRV_O_FLAGS, &local_err, quiet);
if (error_is_set(&local_err)) {
error_report("%s", error_get_pretty(local_err));
error_free(local_err);
@@ -385,7 +404,7 @@ static int img_create(int argc, char **argv)
return 0;
}
-static void dump_json_image_check(ImageCheck *check)
+static void dump_json_image_check(ImageCheck *check, bool quiet)
{
Error *errp = NULL;
QString *str;
@@ -396,47 +415,52 @@ static void dump_json_image_check(ImageCheck *check)
obj = qmp_output_get_qobject(ov);
str = qobject_to_json_pretty(obj);
assert(str != NULL);
- printf("%s\n", qstring_get_str(str));
+ qprintf(quiet, "%s\n", qstring_get_str(str));
qobject_decref(obj);
qmp_output_visitor_cleanup(ov);
QDECREF(str);
}
-static void dump_human_image_check(ImageCheck *check)
+static void dump_human_image_check(ImageCheck *check, bool quiet)
{
if (!(check->corruptions || check->leaks || check->check_errors)) {
- printf("No errors were found on the image.\n");
+ qprintf(quiet, "No errors were found on the image.\n");
} else {
if (check->corruptions) {
- printf("\n%" PRId64 " errors were found on the image.\n"
- "Data may be corrupted, or further writes to the image "
- "may corrupt it.\n",
- check->corruptions);
+ qprintf(quiet, "\n%" PRId64 " errors were found on the image.\n"
+ "Data may be corrupted, or further writes to the image "
+ "may corrupt it.\n",
+ check->corruptions);
}
if (check->leaks) {
- printf("\n%" PRId64 " leaked clusters were found on the image.\n"
- "This means waste of disk space, but no harm to data.\n",
- check->leaks);
+ qprintf(quiet,
+ "\n%" PRId64 " leaked clusters were found on the image.\n"
+ "This means waste of disk space, but no harm to data.\n",
+ check->leaks);
}
if (check->check_errors) {
- printf("\n%" PRId64 " internal errors have occurred during the check.\n",
- check->check_errors);
+ qprintf(quiet,
+ "\n%" PRId64
+ " internal errors have occurred during the check.\n",
+ check->check_errors);
}
}
if (check->total_clusters != 0 && check->allocated_clusters != 0) {
- printf("%" PRId64 "/%" PRId64 " = %0.2f%% allocated, "
- "%0.2f%% fragmented, %0.2f%% compressed clusters\n",
- check->allocated_clusters, check->total_clusters,
- check->allocated_clusters * 100.0 / check->total_clusters,
- check->fragmented_clusters * 100.0 / check->allocated_clusters,
- check->compressed_clusters * 100.0 / check->allocated_clusters);
+ qprintf(quiet, "%" PRId64 "/%" PRId64 " = %0.2f%% allocated, "
+ "%0.2f%% fragmented, %0.2f%% compressed clusters\n",
+ check->allocated_clusters, check->total_clusters,
+ check->allocated_clusters * 100.0 / check->total_clusters,
+ check->fragmented_clusters * 100.0 / check->allocated_clusters,
+ check->compressed_clusters * 100.0 /
+ check->allocated_clusters);
}
if (check->image_end_offset) {
- printf("Image end offset: %" PRId64 "\n", check->image_end_offset);
+ qprintf(quiet,
+ "Image end offset: %" PRId64 "\n", check->image_end_offset);
}
}
@@ -496,6 +520,7 @@ static int img_check(int argc, char **argv)
int fix = 0;
int flags = BDRV_O_FLAGS | BDRV_O_CHECK;
ImageCheck *check;
+ bool quiet = false;
fmt = NULL;
output = NULL;
@@ -508,7 +533,7 @@ static int img_check(int argc, char **argv)
{"output", required_argument, 0, OPTION_OUTPUT},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, "f:hr:",
+ c = getopt_long(argc, argv, "f:hr:q",
long_options, &option_index);
if (c == -1) {
break;
@@ -535,6 +560,9 @@ static int img_check(int argc, char **argv)
case OPTION_OUTPUT:
output = optarg;
break;
+ case 'q':
+ quiet = true;
+ break;
}
}
if (optind >= argc) {
@@ -551,7 +579,7 @@ static int img_check(int argc, char **argv)
return 1;
}
- bs = bdrv_new_open(filename, fmt, flags, true);
+ bs = bdrv_new_open(filename, fmt, flags, true, quiet);
if (!bs) {
return 1;
}
@@ -574,12 +602,13 @@ static int img_check(int argc, char **argv)
corruptions_fixed = check->corruptions_fixed;
if (output_format == OFORMAT_HUMAN) {
- printf("The following inconsistencies were found and repaired:\n\n"
- " %" PRId64 " leaked clusters\n"
- " %" PRId64 " corruptions\n\n"
- "Double checking the fixed image now...\n",
- check->leaks_fixed,
- check->corruptions_fixed);
+ qprintf(quiet,
+ "The following inconsistencies were found and repaired:\n\n"
+ " %" PRId64 " leaked clusters\n"
+ " %" PRId64 " corruptions\n\n"
+ "Double checking the fixed image now...\n",
+ check->leaks_fixed,
+ check->corruptions_fixed);
}
ret = collect_image_check(bs, check, filename, fmt, 0);
@@ -590,10 +619,10 @@ static int img_check(int argc, char **argv)
switch (output_format) {
case OFORMAT_HUMAN:
- dump_human_image_check(check);
+ dump_human_image_check(check, quiet);
break;
case OFORMAT_JSON:
- dump_json_image_check(check);
+ dump_json_image_check(check, quiet);
break;
}
@@ -622,11 +651,12 @@ static int img_commit(int argc, char **argv)
int c, ret, flags;
const char *filename, *fmt, *cache;
BlockDriverState *bs;
+ bool quiet = false;
fmt = NULL;
cache = BDRV_DEFAULT_CACHE;
for(;;) {
- c = getopt(argc, argv, "f:ht:");
+ c = getopt(argc, argv, "f:ht:q");
if (c == -1) {
break;
}
@@ -641,6 +671,9 @@ static int img_commit(int argc, char **argv)
case 't':
cache = optarg;
break;
+ case 'q':
+ quiet = true;
+ break;
}
}
if (optind >= argc) {
@@ -655,14 +688,14 @@ static int img_commit(int argc, char **argv)
return -1;
}
- bs = bdrv_new_open(filename, fmt, flags, true);
+ bs = bdrv_new_open(filename, fmt, flags, true, quiet);
if (!bs) {
return 1;
}
ret = bdrv_commit(bs);
switch(ret) {
case 0:
- printf("Image committed.\n");
+ qprintf(quiet, "Image committed.\n");
break;
case -ENOENT:
error_report("No disk inserted");
@@ -805,6 +838,7 @@ static int img_convert(int argc, char **argv)
const char *snapshot_name = NULL;
float local_progress = 0;
int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */
+ bool quiet = false;
fmt = NULL;
out_fmt = "raw";
@@ -812,7 +846,7 @@ static int img_convert(int argc, char **argv)
out_baseimg = NULL;
compress = 0;
for(;;) {
- c = getopt(argc, argv, "f:O:B:s:hce6o:pS:t:");
+ c = getopt(argc, argv, "f:O:B:s:hce6o:pS:t:q");
if (c == -1) {
break;
}
@@ -866,9 +900,16 @@ static int img_convert(int argc, char **argv)
case 't':
cache = optarg;
break;
+ case 'q':
+ quiet = true;
+ break;
}
}
+ if (quiet) {
+ progress = 0;
+ }
+
bs_n = argc - optind - 1;
if (bs_n < 1) {
help();
@@ -897,7 +938,8 @@ static int img_convert(int argc, char **argv)
total_sectors = 0;
for (bs_i = 0; bs_i < bs_n; bs_i++) {
- bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, BDRV_O_FLAGS, true);
+ bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, BDRV_O_FLAGS, true,
+ quiet);
if (!bs[bs_i]) {
error_report("Could not open '%s'", argv[optind + bs_i]);
ret = -1;
@@ -1016,7 +1058,7 @@ static int img_convert(int argc, char **argv)
return -1;
}
- out_bs = bdrv_new_open(out_filename, out_fmt, flags, true);
+ out_bs = bdrv_new_open(out_filename, out_fmt, flags, true, quiet);
if (!out_bs) {
ret = -1;
goto out;
@@ -1479,7 +1521,7 @@ static ImageInfoList *collect_image_info_list(const char *filename,
g_hash_table_insert(filenames, (gpointer)filename, NULL);
bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING,
- false);
+ false, false);
if (!bs) {
goto err;
}
@@ -1605,11 +1647,12 @@ static int img_snapshot(int argc, char **argv)
int c, ret = 0, bdrv_oflags;
int action = 0;
qemu_timeval tv;
+ bool quiet = false;
bdrv_oflags = BDRV_O_FLAGS | BDRV_O_RDWR;
/* Parse commandline parameters */
for(;;) {
- c = getopt(argc, argv, "la:c:d:h");
+ c = getopt(argc, argv, "la:c:d:hq");
if (c == -1) {
break;
}
@@ -1650,6 +1693,9 @@ static int img_snapshot(int argc, char **argv)
action = SNAPSHOT_DELETE;
snapshot_name = optarg;
break;
+ case 'q':
+ quiet = true;
+ break;
}
}
@@ -1659,7 +1705,7 @@ static int img_snapshot(int argc, char **argv)
filename = argv[optind++];
/* Open the image */
- bs = bdrv_new_open(filename, NULL, bdrv_oflags, true);
+ bs = bdrv_new_open(filename, NULL, bdrv_oflags, true, quiet);
if (!bs) {
return 1;
}
@@ -1719,6 +1765,7 @@ static int img_rebase(int argc, char **argv)
int c, flags, ret;
int unsafe = 0;
int progress = 0;
+ bool quiet = false;
/* Parse commandline parameters */
fmt = NULL;
@@ -1726,7 +1773,7 @@ static int img_rebase(int argc, char **argv)
out_baseimg = NULL;
out_basefmt = NULL;
for(;;) {
- c = getopt(argc, argv, "uhf:F:b:pt:");
+ c = getopt(argc, argv, "uhf:F:b:pt:q");
if (c == -1) {
break;
}
@@ -1753,9 +1800,16 @@ static int img_rebase(int argc, char **argv)
case 't':
cache = optarg;
break;
+ case 'q':
+ quiet = true;
+ break;
}
}
+ if (quiet) {
+ progress = 0;
+ }
+
if ((optind >= argc) || (!unsafe && !out_baseimg)) {
help();
}
@@ -1777,7 +1831,7 @@ static int img_rebase(int argc, char **argv)
* Ignore the old backing file for unsafe rebase in case we want to correct
* the reference to a renamed or moved backing file.
*/
- bs = bdrv_new_open(filename, fmt, flags, true);
+ bs = bdrv_new_open(filename, fmt, flags, true, quiet);
if (!bs) {
return 1;
}
@@ -1989,6 +2043,7 @@ static int img_resize(int argc, char **argv)
int c, ret, relative;
const char *filename, *fmt, *size;
int64_t n, total_size;
+ bool quiet = false;
BlockDriverState *bs = NULL;
QemuOpts *param;
static QemuOptsList resize_options = {
@@ -2017,7 +2072,7 @@ static int img_resize(int argc, char **argv)
/* Parse getopt arguments */
fmt = NULL;
for(;;) {
- c = getopt(argc, argv, "f:h");
+ c = getopt(argc, argv, "f:hq");
if (c == -1) {
break;
}
@@ -2029,6 +2084,9 @@ static int img_resize(int argc, char **argv)
case 'f':
fmt = optarg;
break;
+ case 'q':
+ quiet = true;
+ break;
}
}
if (optind >= argc) {
@@ -2062,7 +2120,7 @@ static int img_resize(int argc, char **argv)
n = qemu_opt_get_size(param, BLOCK_OPT_SIZE, 0);
qemu_opts_del(param);
- bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR, true);
+ bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR, true, quiet);
if (!bs) {
ret = -1;
goto out;
@@ -2082,7 +2140,7 @@ static int img_resize(int argc, char **argv)
ret = bdrv_truncate(bs, total_size);
switch (ret) {
case 0:
- printf("Image resized.\n");
+ qprintf(quiet, "Image resized.\n");
break;
case -ENOTSUP:
error_report("This image does not support resize");
diff --git a/qemu-img.texi b/qemu-img.texi
index 1a6c9e3..43430fb 100644
--- a/qemu-img.texi
+++ b/qemu-img.texi
@@ -54,6 +54,9 @@ indicates that target image must be compressed (qcow format only)
with or without a command shows help and lists the supported formats
@item -p
display progress bar (convert and rebase commands only)
+ at item -q
+Quiet mode - do not print any output (except errors). There's no progress bar
+in case both @var{-q} and @var{-p} options are used.
@item -S @var{size}
indicates the consecutive number of bytes that must contain only zeros
for qemu-img to create a sparse image during conversion. This value is rounded
commit b35b2bba5b372ff912c5fe7e5ad6c5a9d883464f
Author: Miroslav Rezanina <mrezanin at redhat.com>
Date: Wed Feb 13 09:09:39 2013 +0100
block: Add synchronous wrapper for bdrv_co_is_allocated_above
There's no synchronous wrapper for bdrv_co_is_allocated_above function
so it's not possible to check for sector allocation in an image with
a backing file.
Signed-off-by: Miroslav Rezanina <mrezanin at redhat.com>
Reviewed-by: Kevin Wolf <kwolf at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/block.c b/block.c
index 50dab8e..08039d2 100644
--- a/block.c
+++ b/block.c
@@ -2681,6 +2681,7 @@ int bdrv_has_zero_init(BlockDriverState *bs)
typedef struct BdrvCoIsAllocatedData {
BlockDriverState *bs;
+ BlockDriverState *base;
int64_t sector_num;
int nb_sectors;
int *pnum;
@@ -2813,6 +2814,44 @@ int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top,
return 0;
}
+/* Coroutine wrapper for bdrv_is_allocated_above() */
+static void coroutine_fn bdrv_is_allocated_above_co_entry(void *opaque)
+{
+ BdrvCoIsAllocatedData *data = opaque;
+ BlockDriverState *top = data->bs;
+ BlockDriverState *base = data->base;
+
+ data->ret = bdrv_co_is_allocated_above(top, base, data->sector_num,
+ data->nb_sectors, data->pnum);
+ data->done = true;
+}
+
+/*
+ * Synchronous wrapper around bdrv_co_is_allocated_above().
+ *
+ * See bdrv_co_is_allocated_above() for details.
+ */
+int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
+ int64_t sector_num, int nb_sectors, int *pnum)
+{
+ Coroutine *co;
+ BdrvCoIsAllocatedData data = {
+ .bs = top,
+ .base = base,
+ .sector_num = sector_num,
+ .nb_sectors = nb_sectors,
+ .pnum = pnum,
+ .done = false,
+ };
+
+ co = qemu_coroutine_create(bdrv_is_allocated_above_co_entry);
+ qemu_coroutine_enter(co, &data);
+ while (!data.done) {
+ qemu_aio_wait();
+ }
+ return data.ret;
+}
+
BlockInfo *bdrv_query_info(BlockDriverState *bs)
{
BlockInfo *info = g_malloc0(sizeof(*info));
diff --git a/include/block/block.h b/include/block/block.h
index 9661f9a..94d84b4 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -280,6 +280,8 @@ int bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors);
int bdrv_has_zero_init(BlockDriverState *bs);
int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
int *pnum);
+int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
+ int64_t sector_num, int nb_sectors, int *pnum);
void bdrv_set_on_error(BlockDriverState *bs, BlockdevOnError on_read_error,
BlockdevOnError on_write_error);
commit 7d81c1413c9c9bdcc966453636e4ca7776b59861
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date: Wed Feb 13 16:53:43 2013 +0100
block: refuse negative iops and bps values
Negative I/O throttling iops and bps values do not make sense so reject
them with an error message.
Reviewed-by: Kevin Wolf <kwolf at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/blockdev.c b/blockdev.c
index 9b03513..ba3759c 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -274,6 +274,16 @@ static bool do_check_io_limits(BlockIOLimit *io_limits, Error **errp)
return false;
}
+ if (io_limits->bps[BLOCK_IO_LIMIT_TOTAL] < 0 ||
+ io_limits->bps[BLOCK_IO_LIMIT_WRITE] < 0 ||
+ io_limits->bps[BLOCK_IO_LIMIT_READ] < 0 ||
+ io_limits->iops[BLOCK_IO_LIMIT_TOTAL] < 0 ||
+ io_limits->iops[BLOCK_IO_LIMIT_WRITE] < 0 ||
+ io_limits->iops[BLOCK_IO_LIMIT_READ] < 0) {
+ error_setg(errp, "bps and iops values must be 0 or greater");
+ return false;
+ }
+
return true;
}
commit c546194f260fb3e391193cb8cc33505618077ecb
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date: Wed Feb 13 16:53:42 2013 +0100
block: use Error in do_check_io_limits()
The do_check_io_limits() function returns false when I/O limits are
invalid but it doesn't set an Error to indicate why. The two
do_check_io_limits() callers duplicate error reporting. Solve this by
passing an Error pointer into do_check_io_limits().
Note that the two callers report slightly different errors: drive_init()
prints a custom error message while qmp_block_set_io_throttle() does
error_set(errp, QERR_INVALID_PARAMETER_COMBINATION).
QERR_INVALID_PARAMETER_COMBINATION is a generic error, see
include/qapi/qmp/qerror.h:
#define QERR_INVALID_PARAMETER_COMBINATION \
ERROR_CLASS_GENERIC_ERROR, "Invalid parameter combination"
Since it is generic we are not obliged to keep this error. Switch to
the custom error message which contains more information.
This patch prepares for adding additional checks with their own error
messages to do_check_io_limits(). The next patch adds a new check.
Reviewed-by: Kevin Wolf <kwolf at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/blockdev.c b/blockdev.c
index 63e6f1e..9b03513 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -255,7 +255,7 @@ static int parse_block_error_action(const char *buf, bool is_read)
}
}
-static bool do_check_io_limits(BlockIOLimit *io_limits)
+static bool do_check_io_limits(BlockIOLimit *io_limits, Error **errp)
{
bool bps_flag;
bool iops_flag;
@@ -269,6 +269,8 @@ static bool do_check_io_limits(BlockIOLimit *io_limits)
&& ((io_limits->iops[BLOCK_IO_LIMIT_READ] != 0)
|| (io_limits->iops[BLOCK_IO_LIMIT_WRITE] != 0));
if (bps_flag || iops_flag) {
+ error_setg(errp, "bps(iops) and bps_rd/bps_wr(iops_rd/iops_wr) "
+ "cannot be used at the same time");
return false;
}
@@ -297,6 +299,7 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type)
int snapshot = 0;
bool copy_on_read;
int ret;
+ Error *error = NULL;
translation = BIOS_ATA_TRANSLATION_AUTO;
media = MEDIA_DISK;
@@ -427,9 +430,9 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type)
io_limits.iops[BLOCK_IO_LIMIT_WRITE] =
qemu_opt_get_number(opts, "iops_wr", 0);
- if (!do_check_io_limits(&io_limits)) {
- error_report("bps(iops) and bps_rd/bps_wr(iops_rd/iops_wr) "
- "cannot be used at the same time");
+ if (!do_check_io_limits(&io_limits, &error)) {
+ error_report("%s", error_get_pretty(error));
+ error_free(error);
return NULL;
}
@@ -975,8 +978,7 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
io_limits.iops[BLOCK_IO_LIMIT_READ] = iops_rd;
io_limits.iops[BLOCK_IO_LIMIT_WRITE]= iops_wr;
- if (!do_check_io_limits(&io_limits)) {
- error_set(errp, QERR_INVALID_PARAMETER_COMBINATION);
+ if (!do_check_io_limits(&io_limits, errp)) {
return;
}
commit 4db35162ea54d84c29074adfcff470ee2687e7b9
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date: Thu Feb 7 17:15:05 2013 +0100
qcow2: support compressed clusters in BlockFragInfo
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 771b7b2..55543ed 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -968,6 +968,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
if (flags & CHECK_FRAG_INFO) {
res->bfi.allocated_clusters++;
+ res->bfi.compressed_clusters++;
/* Compressed clusters are fragmented by nature. Since they
* take up sub-sector space but we only have sector granularity
commit e6439d783cce2c5cdbe4f8028f0b45162b540f82
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date: Thu Feb 7 17:15:04 2013 +0100
qemu-img: add compressed clusters to BlockFragInfo
Show how many clusters are compressed. This can be used to monitor how
many compressed clusters remain and whether to recompress the image.
Suggested-by: Cole Robinson <crobinso at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/include/block/block.h b/include/block/block.h
index ce61883..9661f9a 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -24,6 +24,7 @@ typedef struct BlockFragInfo {
uint64_t allocated_clusters;
uint64_t total_clusters;
uint64_t fragmented_clusters;
+ uint64_t compressed_clusters;
} BlockFragInfo;
typedef struct QEMUSnapshotInfo {
diff --git a/qapi-schema.json b/qapi-schema.json
index c20725c..28b070f 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -279,6 +279,10 @@
# field is present if the driver for the image format
# supports it
#
+# @compressed-clusters: #optional total number of compressed clusters, this
+# field is present if the driver for the image format
+# supports it
+#
# Since: 1.4
#
##
@@ -288,7 +292,7 @@
'*image-end-offset': 'int', '*corruptions': 'int', '*leaks': 'int',
'*corruptions-fixed': 'int', '*leaks-fixed': 'int',
'*total-clusters': 'int', '*allocated-clusters': 'int',
- '*fragmented-clusters': 'int' } }
+ '*fragmented-clusters': 'int', '*compressed-clusters': 'int' } }
##
# @StatusInfo:
diff --git a/qemu-img.c b/qemu-img.c
index 0e34bf0..fa9b2af 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -428,10 +428,11 @@ static void dump_human_image_check(ImageCheck *check)
if (check->total_clusters != 0 && check->allocated_clusters != 0) {
printf("%" PRId64 "/%" PRId64 " = %0.2f%% allocated, "
- "%0.2f%% fragmented\n",
+ "%0.2f%% fragmented, %0.2f%% compressed clusters\n",
check->allocated_clusters, check->total_clusters,
check->allocated_clusters * 100.0 / check->total_clusters,
- check->fragmented_clusters * 100.0 / check->allocated_clusters);
+ check->fragmented_clusters * 100.0 / check->allocated_clusters,
+ check->compressed_clusters * 100.0 / check->allocated_clusters);
}
if (check->image_end_offset) {
@@ -472,6 +473,8 @@ static int collect_image_check(BlockDriverState *bs,
check->has_allocated_clusters = result.bfi.allocated_clusters != 0;
check->fragmented_clusters = result.bfi.fragmented_clusters;
check->has_fragmented_clusters = result.bfi.fragmented_clusters != 0;
+ check->compressed_clusters = result.bfi.compressed_clusters;
+ check->has_compressed_clusters = result.bfi.compressed_clusters != 0;
return 0;
}
diff --git a/tests/qemu-iotests/044.out b/tests/qemu-iotests/044.out
index 9c48673..5eed3f8 100644
--- a/tests/qemu-iotests/044.out
+++ b/tests/qemu-iotests/044.out
@@ -1,4 +1,5 @@
No errors were found on the image.
+7292415/8391499= 86.90% allocated, 0.00% fragmented, 0.00% compressed clusters
Image end offset: 4296447488
.
----------------------------------------------------------------------
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index 5ba960b..e522d61 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -162,7 +162,7 @@ _cleanup_test_img()
_check_test_img()
{
$QEMU_IMG check "$@" -f $IMGFMT $TEST_IMG 2>&1 | \
- sed -e "/fragmented$/d" \
+ sed -e '/allocated.*fragmented.*compressed clusters/d' \
-e 's/qemu-img: This image format does not support checks/No errors were found on the image./' \
-e '/Image end offset: [0-9]\+/d'
}
commit c9fc50839863f05545caca92bb9fbead8b1c91bd
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date: Thu Feb 7 17:15:03 2013 +0100
qemu-img: fix missing space in qemu-img check output
The qemu-img check fragmentation printf() is missing a space before the
'=' sign. The human output is not guaranteed to be stable and we are
not aware of screen scrapers, so add the missing space.
Also fix the missing indentation of the printf() arguments.
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/qemu-img.c b/qemu-img.c
index 34249fe..0e34bf0 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -427,10 +427,11 @@ static void dump_human_image_check(ImageCheck *check)
}
if (check->total_clusters != 0 && check->allocated_clusters != 0) {
- printf("%" PRId64 "/%" PRId64 "= %0.2f%% allocated, %0.2f%% fragmented\n",
- check->allocated_clusters, check->total_clusters,
- check->allocated_clusters * 100.0 / check->total_clusters,
- check->fragmented_clusters * 100.0 / check->allocated_clusters);
+ printf("%" PRId64 "/%" PRId64 " = %0.2f%% allocated, "
+ "%0.2f%% fragmented\n",
+ check->allocated_clusters, check->total_clusters,
+ check->allocated_clusters * 100.0 / check->total_clusters,
+ check->fragmented_clusters * 100.0 / check->allocated_clusters);
}
if (check->image_end_offset) {
commit fba31bae2d776fb4134186a830a252523df7933f
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date: Thu Feb 7 17:15:02 2013 +0100
qcow2: record fragmentation statistics during check
The qemu-img check command can display fragmentation statistics:
* Total number of clusters in virtual disk
* Number of allocated clusters
* Number of fragmented clusters
This patch adds fragmentation statistics support to qcow2.
Compressed and normal clusters count as allocated. Zero clusters are
not counted as allocated unless their L2 entry has a non-zero offset
(e.g. preallocation).
Only the current L1 table counts towards the statistics - snapshots are
ignored.
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 4eec4b1..771b7b2 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -917,6 +917,7 @@ static void inc_refcounts(BlockDriverState *bs,
/* Flags for check_refcounts_l1() and check_refcounts_l2() */
enum {
CHECK_OFLAG_COPIED = 0x1, /* check QCOW_OFLAG_COPIED matches refcount */
+ CHECK_FRAG_INFO = 0x2, /* update BlockFragInfo counters */
};
/*
@@ -933,6 +934,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
{
BDRVQcowState *s = bs->opaque;
uint64_t *l2_table, l2_entry;
+ uint64_t next_contiguous_offset = 0;
int i, l2_size, nb_csectors, refcount;
/* Read L2 table from disk */
@@ -963,6 +965,17 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
l2_entry &= s->cluster_offset_mask;
inc_refcounts(bs, res, refcount_table, refcount_table_size,
l2_entry & ~511, nb_csectors * 512);
+
+ if (flags & CHECK_FRAG_INFO) {
+ res->bfi.allocated_clusters++;
+
+ /* Compressed clusters are fragmented by nature. Since they
+ * take up sub-sector space but we only have sector granularity
+ * I/O we need to re-read the same sectors even for adjacent
+ * compressed clusters.
+ */
+ res->bfi.fragmented_clusters++;
+ }
break;
case QCOW2_CLUSTER_ZERO:
@@ -990,6 +1003,15 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
}
}
+ if (flags & CHECK_FRAG_INFO) {
+ res->bfi.allocated_clusters++;
+ if (next_contiguous_offset &&
+ offset != next_contiguous_offset) {
+ res->bfi.fragmented_clusters++;
+ }
+ next_contiguous_offset = offset + s->cluster_size;
+ }
+
/* Mark cluster as used */
inc_refcounts(bs, res, refcount_table,refcount_table_size,
offset, s->cluster_size);
@@ -1125,6 +1147,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
size = bdrv_getlength(bs->file);
nb_clusters = size_to_clusters(s, size);
+ res->bfi.total_clusters = nb_clusters;
refcount_table = g_malloc0(nb_clusters * sizeof(uint16_t));
/* header */
@@ -1134,7 +1157,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
/* current L1 table */
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
s->l1_table_offset, s->l1_size,
- CHECK_OFLAG_COPIED);
+ CHECK_OFLAG_COPIED | CHECK_FRAG_INFO);
if (ret < 0) {
goto fail;
}
commit 801f70445293ec8ed2d78fd92313c2f71fa48ac9
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date: Thu Feb 7 17:15:01 2013 +0100
qcow2: introduce check_refcounts_l1/l2() flags
The check_refcounts_l1/l2() functions have a check_copied argument to
check that the QCOW_O_COPIED flag is consistent with refcount == 1.
This should be a bool, not an int.
However, the next patch introduces qcow2 fragmentation statistics and
also needs to pass an option to check_refcounts_l1/l2(). This is a good
opportunity to use an int flags field.
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index d36cb4d..4eec4b1 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -914,6 +914,11 @@ static void inc_refcounts(BlockDriverState *bs,
}
}
+/* Flags for check_refcounts_l1() and check_refcounts_l2() */
+enum {
+ CHECK_OFLAG_COPIED = 0x1, /* check QCOW_OFLAG_COPIED matches refcount */
+};
+
/*
* Increases the refcount in the given refcount table for the all clusters
* referenced in the L2 table. While doing so, performs some checks on L2
@@ -924,7 +929,7 @@ static void inc_refcounts(BlockDriverState *bs,
*/
static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
uint16_t *refcount_table, int refcount_table_size, int64_t l2_offset,
- int check_copied)
+ int flags)
{
BDRVQcowState *s = bs->opaque;
uint64_t *l2_table, l2_entry;
@@ -971,7 +976,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
/* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
uint64_t offset = l2_entry & L2E_OFFSET_MASK;
- if (check_copied) {
+ if (flags & CHECK_OFLAG_COPIED) {
refcount = get_refcount(bs, offset >> s->cluster_bits);
if (refcount < 0) {
fprintf(stderr, "Can't get refcount for offset %"
@@ -1028,7 +1033,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
uint16_t *refcount_table,
int refcount_table_size,
int64_t l1_table_offset, int l1_size,
- int check_copied)
+ int flags)
{
BDRVQcowState *s = bs->opaque;
uint64_t *l1_table, l2_offset, l1_size2;
@@ -1057,7 +1062,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
l2_offset = l1_table[i];
if (l2_offset) {
/* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
- if (check_copied) {
+ if (flags & CHECK_OFLAG_COPIED) {
refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED)
>> s->cluster_bits);
if (refcount < 0) {
@@ -1086,7 +1091,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
/* Process and check L2 entries */
ret = check_refcounts_l2(bs, res, refcount_table,
- refcount_table_size, l2_offset, check_copied);
+ refcount_table_size, l2_offset, flags);
if (ret < 0) {
goto fail;
}
@@ -1128,7 +1133,8 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
/* current L1 table */
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
- s->l1_table_offset, s->l1_size, 1);
+ s->l1_table_offset, s->l1_size,
+ CHECK_OFLAG_COPIED);
if (ret < 0) {
goto fail;
}
commit 8599ea4c42c098d2657ed632ad569f7a665706a4
Author: Federico Simoncelli <fsimonce at redhat.com>
Date: Mon Jan 28 06:59:47 2013 -0500
qemu-img: add json output option to the check command
This option --output=[human|json] makes qemu-img check output a human
or JSON representation at the choice of the user.
Signed-off-by: Federico Simoncelli <fsimonce at redhat.com>
Reviewed-by: Eric Blake <eblake at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/qapi-schema.json b/qapi-schema.json
index cd7ea25..c20725c 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -245,6 +245,52 @@
'*backing-filename-format': 'str', '*snapshots': ['SnapshotInfo'] } }
##
+# @ImageCheck:
+#
+# Information about a QEMU image file check
+#
+# @filename: name of the image file checked
+#
+# @format: format of the image file checked
+#
+# @check-errors: number of unexpected errors occurred during check
+#
+# @image-end-offset: #optional offset (in bytes) where the image ends, this
+# field is present if the driver for the image format
+# supports it
+#
+# @corruptions: #optional number of corruptions found during the check if any
+#
+# @leaks: #optional number of leaks found during the check if any
+#
+# @corruptions-fixed: #optional number of corruptions fixed during the check
+# if any
+#
+# @leaks-fixed: #optional number of leaks fixed during the check if any
+#
+# @total-clusters: #optional total number of clusters, this field is present
+# if the driver for the image format supports it
+#
+# @allocated-clusters: #optional total number of allocated clusters, this
+# field is present if the driver for the image format
+# supports it
+#
+# @fragmented-clusters: #optional total number of fragmented clusters, this
+# field is present if the driver for the image format
+# supports it
+#
+# Since: 1.4
+#
+##
+
+{ 'type': 'ImageCheck',
+ 'data': {'filename': 'str', 'format': 'str', 'check-errors': 'int',
+ '*image-end-offset': 'int', '*corruptions': 'int', '*leaks': 'int',
+ '*corruptions-fixed': 'int', '*leaks-fixed': 'int',
+ '*total-clusters': 'int', '*allocated-clusters': 'int',
+ '*fragmented-clusters': 'int' } }
+
+##
# @StatusInfo:
#
# Information about VCPU run state
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
index a181363..259fc14 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -10,9 +10,9 @@ STEXI
ETEXI
DEF("check", img_check,
- "check [-f fmt] [-r [leaks | all]] filename")
+ "check [-f fmt] [--output=ofmt] [-r [leaks | all]] filename")
STEXI
- at item check [-f @var{fmt}] [-r [leaks | all]] @var{filename}
+ at item check [-f @var{fmt}] [--output=@var{ofmt}] [-r [leaks | all]] @var{filename}
ETEXI
DEF("create", img_create,
diff --git a/qemu-img.c b/qemu-img.c
index e80c1c5..34249fe 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -42,6 +42,16 @@ typedef struct img_cmd_t {
int (*handler)(int argc, char **argv);
} img_cmd_t;
+enum {
+ OPTION_OUTPUT = 256,
+ OPTION_BACKING_CHAIN = 257,
+};
+
+typedef enum OutputFormat {
+ OFORMAT_JSON,
+ OFORMAT_HUMAN,
+} OutputFormat;
+
/* Default to cache=writeback as data integrity is not important for qemu-tcg. */
#define BDRV_O_FLAGS BDRV_O_CACHE_WB
#define BDRV_DEFAULT_CACHE "writeback"
@@ -375,6 +385,96 @@ static int img_create(int argc, char **argv)
return 0;
}
+static void dump_json_image_check(ImageCheck *check)
+{
+ Error *errp = NULL;
+ QString *str;
+ QmpOutputVisitor *ov = qmp_output_visitor_new();
+ QObject *obj;
+ visit_type_ImageCheck(qmp_output_get_visitor(ov),
+ &check, NULL, &errp);
+ obj = qmp_output_get_qobject(ov);
+ str = qobject_to_json_pretty(obj);
+ assert(str != NULL);
+ printf("%s\n", qstring_get_str(str));
+ qobject_decref(obj);
+ qmp_output_visitor_cleanup(ov);
+ QDECREF(str);
+}
+
+static void dump_human_image_check(ImageCheck *check)
+{
+ if (!(check->corruptions || check->leaks || check->check_errors)) {
+ printf("No errors were found on the image.\n");
+ } else {
+ if (check->corruptions) {
+ printf("\n%" PRId64 " errors were found on the image.\n"
+ "Data may be corrupted, or further writes to the image "
+ "may corrupt it.\n",
+ check->corruptions);
+ }
+
+ if (check->leaks) {
+ printf("\n%" PRId64 " leaked clusters were found on the image.\n"
+ "This means waste of disk space, but no harm to data.\n",
+ check->leaks);
+ }
+
+ if (check->check_errors) {
+ printf("\n%" PRId64 " internal errors have occurred during the check.\n",
+ check->check_errors);
+ }
+ }
+
+ if (check->total_clusters != 0 && check->allocated_clusters != 0) {
+ printf("%" PRId64 "/%" PRId64 "= %0.2f%% allocated, %0.2f%% fragmented\n",
+ check->allocated_clusters, check->total_clusters,
+ check->allocated_clusters * 100.0 / check->total_clusters,
+ check->fragmented_clusters * 100.0 / check->allocated_clusters);
+ }
+
+ if (check->image_end_offset) {
+ printf("Image end offset: %" PRId64 "\n", check->image_end_offset);
+ }
+}
+
+static int collect_image_check(BlockDriverState *bs,
+ ImageCheck *check,
+ const char *filename,
+ const char *fmt,
+ int fix)
+{
+ int ret;
+ BdrvCheckResult result;
+
+ ret = bdrv_check(bs, &result, fix);
+ if (ret < 0) {
+ return ret;
+ }
+
+ check->filename = g_strdup(filename);
+ check->format = g_strdup(bdrv_get_format_name(bs));
+ check->check_errors = result.check_errors;
+ check->corruptions = result.corruptions;
+ check->has_corruptions = result.corruptions != 0;
+ check->leaks = result.leaks;
+ check->has_leaks = result.leaks != 0;
+ check->corruptions_fixed = result.corruptions_fixed;
+ check->has_corruptions_fixed = result.corruptions != 0;
+ check->leaks_fixed = result.leaks_fixed;
+ check->has_leaks_fixed = result.leaks != 0;
+ check->image_end_offset = result.image_end_offset;
+ check->has_image_end_offset = result.image_end_offset != 0;
+ check->total_clusters = result.bfi.total_clusters;
+ check->has_total_clusters = result.bfi.total_clusters != 0;
+ check->allocated_clusters = result.bfi.allocated_clusters;
+ check->has_allocated_clusters = result.bfi.allocated_clusters != 0;
+ check->fragmented_clusters = result.bfi.fragmented_clusters;
+ check->has_fragmented_clusters = result.bfi.fragmented_clusters != 0;
+
+ return 0;
+}
+
/*
* Checks an image for consistency. Exit codes:
*
@@ -386,15 +486,26 @@ static int img_create(int argc, char **argv)
static int img_check(int argc, char **argv)
{
int c, ret;
- const char *filename, *fmt;
+ OutputFormat output_format = OFORMAT_HUMAN;
+ const char *filename, *fmt, *output;
BlockDriverState *bs;
- BdrvCheckResult result;
int fix = 0;
int flags = BDRV_O_FLAGS | BDRV_O_CHECK;
+ ImageCheck *check;
fmt = NULL;
+ output = NULL;
for(;;) {
- c = getopt(argc, argv, "f:hr:");
+ int option_index = 0;
+ static const struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"format", required_argument, 0, 'f'},
+ {"repair", no_argument, 0, 'r'},
+ {"output", required_argument, 0, OPTION_OUTPUT},
+ {0, 0, 0, 0}
+ };
+ c = getopt_long(argc, argv, "f:hr:",
+ long_options, &option_index);
if (c == -1) {
break;
}
@@ -417,6 +528,9 @@ static int img_check(int argc, char **argv)
help();
}
break;
+ case OPTION_OUTPUT:
+ output = optarg;
+ break;
}
}
if (optind >= argc) {
@@ -424,77 +538,79 @@ static int img_check(int argc, char **argv)
}
filename = argv[optind++];
+ if (output && !strcmp(output, "json")) {
+ output_format = OFORMAT_JSON;
+ } else if (output && !strcmp(output, "human")) {
+ output_format = OFORMAT_HUMAN;
+ } else if (output) {
+ error_report("--output must be used with human or json as argument.");
+ return 1;
+ }
+
bs = bdrv_new_open(filename, fmt, flags, true);
if (!bs) {
return 1;
}
- ret = bdrv_check(bs, &result, fix);
+
+ check = g_new0(ImageCheck, 1);
+ ret = collect_image_check(bs, check, filename, fmt, fix);
if (ret == -ENOTSUP) {
- error_report("This image format does not support checks");
- bdrv_delete(bs);
- return 1;
+ if (output_format == OFORMAT_HUMAN) {
+ error_report("This image format does not support checks");
+ }
+ ret = 1;
+ goto fail;
}
- if (result.corruptions_fixed || result.leaks_fixed) {
- printf("The following inconsistencies were found and repaired:\n\n"
- " %d leaked clusters\n"
- " %d corruptions\n\n"
- "Double checking the fixed image now...\n",
- result.leaks_fixed,
- result.corruptions_fixed);
- ret = bdrv_check(bs, &result, 0);
- }
+ if (check->corruptions_fixed || check->leaks_fixed) {
+ int corruptions_fixed, leaks_fixed;
- if (!(result.corruptions || result.leaks || result.check_errors)) {
- printf("No errors were found on the image.\n");
- } else {
- if (result.corruptions) {
- printf("\n%d errors were found on the image.\n"
- "Data may be corrupted, or further writes to the image "
- "may corrupt it.\n",
- result.corruptions);
- }
+ leaks_fixed = check->leaks_fixed;
+ corruptions_fixed = check->corruptions_fixed;
- if (result.leaks) {
- printf("\n%d leaked clusters were found on the image.\n"
- "This means waste of disk space, but no harm to data.\n",
- result.leaks);
+ if (output_format == OFORMAT_HUMAN) {
+ printf("The following inconsistencies were found and repaired:\n\n"
+ " %" PRId64 " leaked clusters\n"
+ " %" PRId64 " corruptions\n\n"
+ "Double checking the fixed image now...\n",
+ check->leaks_fixed,
+ check->corruptions_fixed);
}
- if (result.check_errors) {
- printf("\n%d internal errors have occurred during the check.\n",
- result.check_errors);
- }
- }
+ ret = collect_image_check(bs, check, filename, fmt, 0);
- if (result.bfi.total_clusters != 0 && result.bfi.allocated_clusters != 0) {
- printf("%" PRId64 "/%" PRId64 "= %0.2f%% allocated, %0.2f%% fragmented\n",
- result.bfi.allocated_clusters, result.bfi.total_clusters,
- result.bfi.allocated_clusters * 100.0 / result.bfi.total_clusters,
- result.bfi.fragmented_clusters * 100.0 / result.bfi.allocated_clusters);
+ check->leaks_fixed = leaks_fixed;
+ check->corruptions_fixed = corruptions_fixed;
}
- if (result.image_end_offset > 0) {
- printf("Image end offset: %" PRId64 "\n", result.image_end_offset);
+ switch (output_format) {
+ case OFORMAT_HUMAN:
+ dump_human_image_check(check);
+ break;
+ case OFORMAT_JSON:
+ dump_json_image_check(check);
+ break;
}
- bdrv_delete(bs);
-
- if (ret < 0 || result.check_errors) {
- printf("\nAn error has occurred during the check: %s\n"
- "The check is not complete and may have missed error.\n",
- strerror(-ret));
- return 1;
+ if (ret || check->check_errors) {
+ ret = 1;
+ goto fail;
}
- if (result.corruptions) {
- return 2;
- } else if (result.leaks) {
- return 3;
+ if (check->corruptions) {
+ ret = 2;
+ } else if (check->leaks) {
+ ret = 3;
} else {
- return 0;
+ ret = 0;
}
+
+fail:
+ qapi_free_ImageCheck(check);
+ bdrv_delete(bs);
+
+ return ret;
}
static int img_commit(int argc, char **argv)
@@ -1396,16 +1512,6 @@ err:
return NULL;
}
-enum {
- OPTION_OUTPUT = 256,
- OPTION_BACKING_CHAIN = 257,
-};
-
-typedef enum OutputFormat {
- OFORMAT_JSON,
- OFORMAT_HUMAN,
-} OutputFormat;
-
static int img_info(int argc, char **argv)
{
int c;
diff --git a/qemu-img.texi b/qemu-img.texi
index 00fca8d..1a6c9e3 100644
--- a/qemu-img.texi
+++ b/qemu-img.texi
@@ -84,9 +84,10 @@ lists all snapshots in the given image
Command description:
@table @option
- at item check [-f @var{fmt}] [-r [leaks | all]] @var{filename}
+ at item check [-f @var{fmt}] [--output=@var{ofmt}] [-r [leaks | all]] @var{filename}
-Perform a consistency check on the disk image @var{filename}.
+Perform a consistency check on the disk image @var{filename}. The command can
+output in the format @var{ofmt} which is either @code{human} or @code{json}.
If @code{-r} is specified, qemu-img tries to repair any inconsistencies found
during the check. @code{-r leaks} repairs only cluster leaks, whereas
commit c6bb9ad198c2caa9c7c8ba360a07630b5c10e4a8
Author: Federico Simoncelli <fsimonce at redhat.com>
Date: Mon Jan 28 06:59:46 2013 -0500
qemu-img: find the image end offset during check
This patch adds the support for reporting the image end offset (in
bytes). This is particularly useful after a conversion (or a rebase)
where the destination is a block device in order to find the first
unused byte at the end of the image.
Signed-off-by: Federico Simoncelli <fsimonce at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index bc1784c..d36cb4d 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -1112,7 +1112,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
BdrvCheckMode fix)
{
BDRVQcowState *s = bs->opaque;
- int64_t size, i;
+ int64_t size, i, highest_cluster;
int nb_clusters, refcount1, refcount2;
QCowSnapshot *sn;
uint16_t *refcount_table;
@@ -1183,7 +1183,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
}
/* compare ref counts */
- for(i = 0; i < nb_clusters; i++) {
+ for (i = 0, highest_cluster = 0; i < nb_clusters; i++) {
refcount1 = get_refcount(bs, i);
if (refcount1 < 0) {
fprintf(stderr, "Can't get refcount for cluster %" PRId64 ": %s\n",
@@ -1193,6 +1193,11 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
}
refcount2 = refcount_table[i];
+
+ if (refcount1 > 0 || refcount2 > 0) {
+ highest_cluster = i;
+ }
+
if (refcount1 != refcount2) {
/* Check if we're allowed to fix the mismatch */
@@ -1227,6 +1232,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
}
}
+ res->image_end_offset = (highest_cluster + 1) * s->cluster_size;
ret = 0;
fail:
diff --git a/include/block/block.h b/include/block/block.h
index 5c3b911..ce61883 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -213,6 +213,7 @@ typedef struct BdrvCheckResult {
int check_errors;
int corruptions_fixed;
int leaks_fixed;
+ int64_t image_end_offset;
BlockFragInfo bfi;
} BdrvCheckResult;
diff --git a/qemu-img.c b/qemu-img.c
index 85d3740..e80c1c5 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -475,6 +475,10 @@ static int img_check(int argc, char **argv)
result.bfi.fragmented_clusters * 100.0 / result.bfi.allocated_clusters);
}
+ if (result.image_end_offset > 0) {
+ printf("Image end offset: %" PRId64 "\n", result.image_end_offset);
+ }
+
bdrv_delete(bs);
if (ret < 0 || result.check_errors) {
diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026
index 1602ccd..107a3ff 100755
--- a/tests/qemu-iotests/026
+++ b/tests/qemu-iotests/026
@@ -102,7 +102,7 @@ if [ "$event" == "l2_load" ]; then
$QEMU_IO -c "read $vmstate 0 128k " $BLKDBG_TEST_IMG | _filter_qemu_io
fi
-$QEMU_IMG check $TEST_IMG 2>&1 | grep -v "refcount=1 reference=0"
+_check_test_img 2>&1 | grep -v "refcount=1 reference=0"
done
done
@@ -147,7 +147,7 @@ echo
echo "Event: $event; errno: $errno; imm: $imm; once: $once; write $vmstate"
$QEMU_IO -c "write $vmstate 0 64M" $BLKDBG_TEST_IMG | _filter_qemu_io
-$QEMU_IMG check $TEST_IMG 2>&1 | grep -v "refcount=1 reference=0"
+_check_test_img 2>&1 | grep -v "refcount=1 reference=0"
done
done
@@ -186,7 +186,7 @@ echo
echo "Event: $event; errno: $errno; imm: $imm; once: $once"
$QEMU_IO -c "write -b 0 64k" $BLKDBG_TEST_IMG | _filter_qemu_io
-$QEMU_IMG check $TEST_IMG 2>&1 | grep -v "refcount=1 reference=0"
+_check_test_img 2>&1 | grep -v "refcount=1 reference=0"
done
done
diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036
index 329533e..4dbfc57 100755
--- a/tests/qemu-iotests/036
+++ b/tests/qemu-iotests/036
@@ -59,7 +59,8 @@ _make_test_img 64M
echo
echo === Repair image ===
echo
-$QEMU_IMG check -r all $TEST_IMG
+_check_test_img -r all
+
./qcow2.py $TEST_IMG dump-header
# success, all done
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
index c5ae806..ae35175 100755
--- a/tests/qemu-iotests/039
+++ b/tests/qemu-iotests/039
@@ -86,7 +86,7 @@ $QEMU_IO -r -c "read -P 0x5a 0 512" $TEST_IMG | _filter_qemu_io
echo
echo "== Repairing the image file must succeed =="
-$QEMU_IMG check -r all $TEST_IMG
+_check_test_img -r all
# The dirty bit must not be set
./qcow2.py $TEST_IMG dump-header | grep incompatible_features
diff --git a/tests/qemu-iotests/044.out b/tests/qemu-iotests/044.out
index 7a40071..9c48673 100644
--- a/tests/qemu-iotests/044.out
+++ b/tests/qemu-iotests/044.out
@@ -1,4 +1,5 @@
No errors were found on the image.
+Image end offset: 4296447488
.
----------------------------------------------------------------------
Ran 1 tests
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index aef5f52..5ba960b 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -161,9 +161,10 @@ _cleanup_test_img()
_check_test_img()
{
- $QEMU_IMG check -f $IMGFMT $TEST_IMG 2>&1 | \
- grep -v "fragmented$" | \
- sed -e 's/qemu-img\: This image format does not support checks/No errors were found on the image./'
+ $QEMU_IMG check "$@" -f $IMGFMT $TEST_IMG 2>&1 | \
+ sed -e "/fragmented$/d" \
+ -e 's/qemu-img: This image format does not support checks/No errors were found on the image./' \
+ -e '/Image end offset: [0-9]\+/d'
}
_img_info()
commit 90f8ae724a575861f093fbdbfd49a925bcfec327
Author: Juan Quintela <quintela at redhat.com>
Date: Fri Feb 1 13:22:37 2013 +0100
migration: calculate expected_downtime
We removed the calculation in commit e4ed1541ac9413eac494a03532e34beaf8a7d1c5
Now we add it back. We need to create dirty_bytes_rate because we
can't include cpu-all.h from migration.c, and there is no other way to
include TARGET_PAGE_SIZE.
Signed-off-by: Juan Quintela <quintela at redhat.com>
Reviewed-by: Orit Wasserman <owasserm at redhat.com>
diff --git a/arch_init.c b/arch_init.c
index 8da868b..8daeafa 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -414,6 +414,7 @@ static void migration_bitmap_sync(void)
if (end_time > start_time + 1000) {
s->dirty_pages_rate = num_dirty_pages_period * 1000
/ (end_time - start_time);
+ s->dirty_bytes_rate = s->dirty_pages_rate * TARGET_PAGE_SIZE;
start_time = end_time;
num_dirty_pages_period = 0;
}
diff --git a/include/migration/migration.h b/include/migration/migration.h
index a8c9639..d121409 100644
--- a/include/migration/migration.h
+++ b/include/migration/migration.h
@@ -51,6 +51,7 @@ struct MigrationState
int64_t downtime;
int64_t expected_downtime;
int64_t dirty_pages_rate;
+ int64_t dirty_bytes_rate;
bool enabled_capabilities[MIGRATION_CAPABILITY_MAX];
int64_t xbzrle_cache_size;
bool complete;
diff --git a/migration.c b/migration.c
index 6649e3a..11725ae 100644
--- a/migration.c
+++ b/migration.c
@@ -738,6 +738,11 @@ static void *buffered_file_thread(void *opaque)
DPRINTF("transferred %" PRIu64 " time_spent %" PRIu64
" bandwidth %g max_size %" PRId64 "\n",
transferred_bytes, time_spent, bandwidth, max_size);
+ /* if we haven't sent anything, we don't want to recalculate
+ 10000 is a small enough number for our purposes */
+ if (s->dirty_bytes_rate && transferred_bytes > 10000) {
+ s->expected_downtime = s->dirty_bytes_rate / bandwidth;
+ }
s->bytes_xfer = 0;
sleep_time = 0;
commit 7161082c8d8cf167c508976887a0a63f4db92b51
Author: Juan Quintela <quintela at redhat.com>
Date: Fri Feb 1 12:41:38 2013 +0100
migration: don't account sleep time for calculating bandwidth
While we are sleeping we are not sending, so we should not use that
time to estimate our bandwidth.
Signed-off-by: Juan Quintela <quintela at redhat.com>
Reviewed-by: Orit Wasserman <owasserm at redhat.com>
diff --git a/migration.c b/migration.c
index b8e412f..6649e3a 100644
--- a/migration.c
+++ b/migration.c
@@ -658,6 +658,7 @@ static void *buffered_file_thread(void *opaque)
{
MigrationState *s = opaque;
int64_t initial_time = qemu_get_clock_ms(rt_clock);
+ int64_t sleep_time = 0;
int64_t max_size = 0;
bool last_round = false;
int ret;
@@ -730,7 +731,7 @@ static void *buffered_file_thread(void *opaque)
current_time = qemu_get_clock_ms(rt_clock);
if (current_time >= initial_time + BUFFER_DELAY) {
uint64_t transferred_bytes = s->bytes_xfer;
- uint64_t time_spent = current_time - initial_time;
+ uint64_t time_spent = current_time - initial_time - sleep_time;
double bandwidth = transferred_bytes / time_spent;
max_size = bandwidth * migrate_max_downtime() / 1000000;
@@ -739,11 +740,13 @@ static void *buffered_file_thread(void *opaque)
transferred_bytes, time_spent, bandwidth, max_size);
s->bytes_xfer = 0;
+ sleep_time = 0;
initial_time = current_time;
}
if (!last_round && (s->bytes_xfer >= s->xfer_limit)) {
/* usleep expects microseconds */
g_usleep((initial_time + BUFFER_DELAY - current_time)*1000);
+ sleep_time += qemu_get_clock_ms(rt_clock) - current_time;
}
ret = buffered_flush(s);
if (ret < 0) {
commit a3e879cd51c4f614f702117c4b1449f0218c00f3
Author: Juan Quintela <quintela at redhat.com>
Date: Fri Feb 1 12:39:08 2013 +0100
migration: calculate end time after we have sent the data
Signed-off-by: Juan Quintela <quintela at redhat.com>
Reviewed-by: Orit Wasserman <owasserm at redhat.com>
diff --git a/migration.c b/migration.c
index b3f5ba4..b8e412f 100644
--- a/migration.c
+++ b/migration.c
@@ -673,7 +673,7 @@ static void *buffered_file_thread(void *opaque)
qemu_mutex_unlock_iothread();
while (true) {
- int64_t current_time = qemu_get_clock_ms(rt_clock);
+ int64_t current_time;
uint64_t pending_size;
qemu_mutex_lock_iothread();
@@ -727,6 +727,7 @@ static void *buffered_file_thread(void *opaque)
}
}
qemu_mutex_unlock_iothread();
+ current_time = qemu_get_clock_ms(rt_clock);
if (current_time >= initial_time + BUFFER_DELAY) {
uint64_t transferred_bytes = s->bytes_xfer;
uint64_t time_spent = current_time - initial_time;
commit cc283e3bf04d2f64eb6ec2ee5bcd36edd779fe89
Author: Juan Quintela <quintela at redhat.com>
Date: Fri Feb 1 11:12:26 2013 +0100
migration: change initial value of expected_downtime
0 is a very bad initial value, what we are trying to get is
max_downtime, so that is a much better estimation.
Signed-off-by: Juan Quintela <quintela at redhat.com>
Reviewed-by: Orit Wasserman <owasserm at redhat.com>
diff --git a/migration.c b/migration.c
index b1ebb01..b3f5ba4 100644
--- a/migration.c
+++ b/migration.c
@@ -774,6 +774,8 @@ void migrate_fd_connect(MigrationState *s)
s->buffer = NULL;
s->buffer_size = 0;
s->buffer_capacity = 0;
+ /* This is a best 1st approximation. ns to ms */
+ s->expected_downtime = max_downtime/1000000;
s->xfer_limit = s->bandwidth_limit / XFER_LIMIT_RATIO;
s->complete = false;
commit 3960c41f05bf776cc23a4a3b861f729fa65295a5
Author: Markus Armbruster <armbru at redhat.com>
Date: Tue Feb 5 09:30:55 2013 +0100
check-qjson: More thorough testing of UTF-8 in strings
Test cases are scraped from Markus Kuhn's UTF-8 decoder capability and
stress test at
http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
Unfortunately, both JSON parser and formatter misbehave right now.
This test expects current, incorrect results. They're all clearly
marked, and are to be replaced by correct ones as the bugs get fixed.
See comments in new utf8_string() for details.
Signed-off-by: Markus Armbruster <armbru at redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/tests/check-qjson.c b/tests/check-qjson.c
index 32ffb43..ec85a0c 100644
--- a/tests/check-qjson.c
+++ b/tests/check-qjson.c
@@ -1,8 +1,10 @@
/*
* Copyright IBM, Corp. 2009
+ * Copyright (c) 2013 Red Hat Inc.
*
* Authors:
* Anthony Liguori <aliguori at us.ibm.com>
+ * Markus Armbruster <armbru at redhat.com>,
*
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
* See the COPYING.LIB file in the top-level directory.
@@ -131,6 +133,667 @@ static void single_quote_string(void)
}
}
+static void utf8_string(void)
+{
+ /*
+ * FIXME Current behavior for invalid UTF-8 sequences is
+ * incorrect. This test expects current, incorrect results.
+ * They're all marked "bug:" below, and are to be replaced by
+ * correct ones as the bugs get fixed.
+ *
+ * The JSON parser rejects some invalid sequences, but accepts
+ * others without correcting the problem.
+ *
+ * The JSON formatter replaces some invalid sequences by U+FFFF (a
+ * noncharacter), and goes wonky for others.
+ *
+ * For both directions, we should either reject all invalid
+ * sequences, or minimize overlong sequences and replace all other
+ * invalid sequences by a suitable replacement character. A
+ * common choice for replacement is U+FFFD.
+ *
+ * Problem: we can't easily deal with embedded U+0000. Parsing
+ * the JSON string "this \\u0000" is fun" yields "this \0 is fun",
+ * which gets misinterpreted as NUL-terminated "this ". We should
+ * consider using overlong encoding \xC0\x80 for U+0000 ("modified
+ * UTF-8").
+ *
+ * Test cases are scraped from Markus Kuhn's UTF-8 decoder
+ * capability and stress test at
+ * http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
+ */
+ static const struct {
+ const char *json_in;
+ const char *utf8_out;
+ const char *json_out; /* defaults to @json_in */
+ const char *utf8_in; /* defaults to @utf8_out */
+ } test_cases[] = {
+ /*
+ * Bug markers used here:
+ * - bug: not corrected
+ * JSON parser fails to correct invalid sequence(s)
+ * - bug: rejected
+ * JSON parser rejects invalid sequence(s)
+ * We may choose to define this as feature
+ * - bug: want "\"...\""
+ * JSON formatter produces incorrect result, this is the
+ * correct one, assuming replacement character U+FFFF
+ * - bug: want "..." (no \")
+ * JSON parser produces incorrect result, this is the
+ * correct one, assuming replacement character U+FFFF
+ * We may choose to reject instead of replace
+ * Not marked explicitly, but trivial to find:
+ * - JSON formatter replacing invalid sequence by \\uFFFF is a
+ * bug if we want it to fail for invalid sequences.
+ */
+
+ /* 1 Some correct UTF-8 text */
+ {
+ /* a bit of German */
+ "\"Falsches \xC3\x9C" "ben von Xylophonmusik qu\xC3\xA4lt"
+ " jeden gr\xC3\xB6\xC3\x9F" "eren Zwerg.\"",
+ "Falsches \xC3\x9C" "ben von Xylophonmusik qu\xC3\xA4lt"
+ " jeden gr\xC3\xB6\xC3\x9F" "eren Zwerg.",
+ "\"Falsches \\u00DCben von Xylophonmusik qu\\u00E4lt"
+ " jeden gr\\u00F6\\u00DFeren Zwerg.\"",
+ },
+ {
+ /* a bit of Greek */
+ "\"\xCE\xBA\xE1\xBD\xB9\xCF\x83\xCE\xBC\xCE\xB5\"",
+ "\xCE\xBA\xE1\xBD\xB9\xCF\x83\xCE\xBC\xCE\xB5",
+ "\"\\u03BA\\u1F79\\u03C3\\u03BC\\u03B5\"",
+ },
+ /* 2 Boundary condition test cases */
+ /* 2.1 First possible sequence of a certain length */
+ /* 2.1.1 1 byte U+0000 */
+ {
+ "\"\\u0000\"",
+ "", /* bug: want overlong "\xC0\x80" */
+ "\"\"", /* bug: want "\"\\u0000\"" */
+ },
+ /* 2.1.2 2 bytes U+0080 */
+ {
+ "\"\xC2\x80\"",
+ "\xC2\x80",
+ "\"\\u0080\"",
+ },
+ /* 2.1.3 3 bytes U+0800 */
+ {
+ "\"\xE0\xA0\x80\"",
+ "\xE0\xA0\x80",
+ "\"\\u0800\"",
+ },
+ /* 2.1.4 4 bytes U+10000 */
+ {
+ "\"\xF0\x90\x80\x80\"",
+ "\xF0\x90\x80\x80",
+ "\"\\u0400\\uFFFF\"", /* bug: want "\"\\uD800\\uDC00\"" */
+ },
+ /* 2.1.5 5 bytes U+200000 */
+ {
+ "\"\xF8\x88\x80\x80\x80\"",
+ NULL, /* bug: rejected */
+ "\"\\u8200\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
+ "\xF8\x88\x80\x80\x80",
+ },
+ /* 2.1.6 6 bytes U+4000000 */
+ {
+ "\"\xFC\x84\x80\x80\x80\x80\"",
+ NULL, /* bug: rejected */
+ "\"\\uC100\\uFFFF\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
+ "\xFC\x84\x80\x80\x80\x80",
+ },
+ /* 2.2 Last possible sequence of a certain length */
+ /* 2.2.1 1 byte U+007F */
+ {
+ "\"\x7F\"",
+ "\x7F",
+ "\"\177\"",
+ },
+ /* 2.2.2 2 bytes U+07FF */
+ {
+ "\"\xDF\xBF\"",
+ "\xDF\xBF",
+ "\"\\u07FF\"",
+ },
+ /* 2.2.3 3 bytes U+FFFF */
+ {
+ "\"\xEF\xBF\xBF\"",
+ "\xEF\xBF\xBF",
+ "\"\\uFFFF\"",
+ },
+ /* 2.2.4 4 bytes U+1FFFFF */
+ {
+ "\"\xF7\xBF\xBF\xBF\"",
+ NULL, /* bug: rejected */
+ "\"\\u7FFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
+ "\xF7\xBF\xBF\xBF",
+ },
+ /* 2.2.5 5 bytes U+3FFFFFF */
+ {
+ "\"\xFB\xBF\xBF\xBF\xBF\"",
+ NULL, /* bug: rejected */
+ "\"\\uBFFF\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
+ "\xFB\xBF\xBF\xBF\xBF",
+ },
+ /* 2.2.6 6 bytes U+7FFFFFFF */
+ {
+ "\"\xFD\xBF\xBF\xBF\xBF\xBF\"",
+ NULL, /* bug: rejected */
+ "\"\\uDFFF\\uFFFF\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
+ "\xFD\xBF\xBF\xBF\xBF\xBF",
+ },
+ /* 2.3 Other boundary conditions */
+ {
+ /* U+D7FF */
+ "\"\xED\x9F\xBF\"",
+ "\xED\x9F\xBF",
+ "\"\\uD7FF\"",
+ },
+ {
+ /* U+E000 */
+ "\"\xEE\x80\x80\"",
+ "\xEE\x80\x80",
+ "\"\\uE000\"",
+ },
+ {
+ /* U+FFFD */
+ "\"\xEF\xBF\xBD\"",
+ "\xEF\xBF\xBD",
+ "\"\\uFFFD\"",
+ },
+ {
+ /* U+10FFFF */
+ "\"\xF4\x8F\xBF\xBF\"",
+ "\xF4\x8F\xBF\xBF",
+ "\"\\u43FF\\uFFFF\"", /* bug: want "\"\\uDBFF\\uDFFF\"" */
+ },
+ {
+ /* U+110000 */
+ "\"\xF4\x90\x80\x80\"",
+ "\xF4\x90\x80\x80",
+ "\"\\u4400\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
+ },
+ /* 3 Malformed sequences */
+ /* 3.1 Unexpected continuation bytes */
+ /* 3.1.1 First continuation byte */
+ {
+ "\"\x80\"",
+ "\x80", /* bug: not corrected */
+ "\"\\uFFFF\"",
+ },
+ /* 3.1.2 Last continuation byte */
+ {
+ "\"\xBF\"",
+ "\xBF", /* bug: not corrected */
+ "\"\\uFFFF\"",
+ },
+ /* 3.1.3 2 continuation bytes */
+ {
+ "\"\x80\xBF\"",
+ "\x80\xBF", /* bug: not corrected */
+ "\"\\uFFFF\\uFFFF\"",
+ },
+ /* 3.1.4 3 continuation bytes */
+ {
+ "\"\x80\xBF\x80\"",
+ "\x80\xBF\x80", /* bug: not corrected */
+ "\"\\uFFFF\\uFFFF\\uFFFF\"",
+ },
+ /* 3.1.5 4 continuation bytes */
+ {
+ "\"\x80\xBF\x80\xBF\"",
+ "\x80\xBF\x80\xBF", /* bug: not corrected */
+ "\"\\uFFFF\\uFFFF\\uFFFF\\uFFFF\"",
+ },
+ /* 3.1.6 5 continuation bytes */
+ {
+ "\"\x80\xBF\x80\xBF\x80\"",
+ "\x80\xBF\x80\xBF\x80", /* bug: not corrected */
+ "\"\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\"",
+ },
+ /* 3.1.7 6 continuation bytes */
+ {
+ "\"\x80\xBF\x80\xBF\x80\xBF\"",
+ "\x80\xBF\x80\xBF\x80\xBF", /* bug: not corrected */
+ "\"\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\"",
+ },
+ /* 3.1.8 7 continuation bytes */
+ {
+ "\"\x80\xBF\x80\xBF\x80\xBF\x80\"",
+ "\x80\xBF\x80\xBF\x80\xBF\x80", /* bug: not corrected */
+ "\"\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\"",
+ },
+ /* 3.1.9 Sequence of all 64 possible continuation bytes */
+ {
+ "\"\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F"
+ "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7"
+ "\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF"
+ "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7"
+ "\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF\"",
+ /* bug: not corrected */
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F"
+ "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7"
+ "\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF"
+ "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7"
+ "\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF",
+ "\"\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF"
+ "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF"
+ "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF"
+ "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF"
+ "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF"
+ "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF"
+ "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF"
+ "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\""
+ },
+ /* 3.2 Lonely start characters */
+ /* 3.2.1 All 32 first bytes of 2-byte sequences, followed by space */
+ {
+ "\"\xC0 \xC1 \xC2 \xC3 \xC4 \xC5 \xC6 \xC7 "
+ "\xC8 \xC9 \xCA \xCB \xCC \xCD \xCE \xCF "
+ "\xD0 \xD1 \xD2 \xD3 \xD4 \xD5 \xD6 \xD7 "
+ "\xD8 \xD9 \xDA \xDB \xDC \xDD \xDE \xDF \"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF "
+ "\\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF "
+ "\\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF "
+ "\\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \"",
+ "\xC0 \xC1 \xC2 \xC3 \xC4 \xC5 \xC6 \xC7 "
+ "\xC8 \xC9 \xCA \xCB \xCC \xCD \xCE \xCF "
+ "\xD0 \xD1 \xD2 \xD3 \xD4 \xD5 \xD6 \xD7 "
+ "\xD8 \xD9 \xDA \xDB \xDC \xDD \xDE \xDF ",
+ },
+ /* 3.2.2 All 16 first bytes of 3-byte sequences, followed by space */
+ {
+ "\"\xE0 \xE1 \xE2 \xE3 \xE4 \xE5 \xE6 \xE7 "
+ "\xE8 \xE9 \xEA \xEB \xEC \xED \xEE \xEF \"",
+ /* bug: not corrected */
+ "\xE0 \xE1 \xE2 \xE3 \xE4 \xE5 \xE6 \xE7 "
+ "\xE8 \xE9 \xEA \xEB \xEC \xED \xEE \xEF ",
+ "\"\\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF "
+ "\\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \"",
+ },
+ /* 3.2.3 All 8 first bytes of 4-byte sequences, followed by space */
+ {
+ "\"\xF0 \xF1 \xF2 \xF3 \xF4 \xF5 \xF6 \xF7 \"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \"",
+ "\xF0 \xF1 \xF2 \xF3 \xF4 \xF5 \xF6 \xF7 ",
+ },
+ /* 3.2.4 All 4 first bytes of 5-byte sequences, followed by space */
+ {
+ "\"\xF8 \xF9 \xFA \xFB \"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFF \\uFFFF \\uFFFF \\uFFFF \"",
+ "\xF8 \xF9 \xFA \xFB ",
+ },
+ /* 3.2.5 All 2 first bytes of 6-byte sequences, followed by space */
+ {
+ "\"\xFC \xFD \"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFF \\uFFFF \"",
+ "\xFC \xFD ",
+ },
+ /* 3.3 Sequences with last continuation byte missing */
+ /* 3.3.1 2-byte sequence with last byte missing (U+0000) */
+ {
+ "\"\xC0\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFF\"",
+ "\xC0",
+ },
+ /* 3.3.2 3-byte sequence with last byte missing (U+0000) */
+ {
+ "\"\xE0\x80\"",
+ "\xE0\x80", /* bug: not corrected */
+ "\"\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
+ },
+ /* 3.3.3 4-byte sequence with last byte missing (U+0000) */
+ {
+ "\"\xF0\x80\x80\"",
+ "\xF0\x80\x80", /* bug: not corrected */
+ "\"\\u0000\"", /* bug: want "\"\\uFFFF\"" */
+ },
+ /* 3.3.4 5-byte sequence with last byte missing (U+0000) */
+ {
+ /* invalid */
+ "\"\xF8\x80\x80\x80\"", /* bug: not corrected */
+ NULL, /* bug: rejected */
+ "\"\\u8000\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
+ "\xF8\x80\x80\x80",
+ },
+ /* 3.3.5 6-byte sequence with last byte missing (U+0000) */
+ {
+ "\"\xFC\x80\x80\x80\x80\"",
+ NULL, /* bug: rejected */
+ "\"\\uC000\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
+ "\xFC\x80\x80\x80\x80",
+ },
+ /* 3.3.6 2-byte sequence with last byte missing (U+07FF) */
+ {
+ "\"\xDF\"",
+ "\xDF", /* bug: not corrected */
+ "\"\\uFFFF\"",
+ },
+ /* 3.3.7 3-byte sequence with last byte missing (U+FFFF) */
+ {
+ "\"\xEF\xBF\"",
+ "\xEF\xBF", /* bug: not corrected */
+ "\"\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
+ },
+ /* 3.3.8 4-byte sequence with last byte missing (U+1FFFFF) */
+ {
+ "\"\xF7\xBF\xBF\"",
+ NULL, /* bug: rejected */
+ "\"\\u7FFF\"", /* bug: want "\"\\uFFFF\"" */
+ "\xF7\xBF\xBF",
+ },
+ /* 3.3.9 5-byte sequence with last byte missing (U+3FFFFFF) */
+ {
+ "\"\xFB\xBF\xBF\xBF\"",
+ NULL, /* bug: rejected */
+ "\"\\uBFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
+ "\xFB\xBF\xBF\xBF",
+ },
+ /* 3.3.10 6-byte sequence with last byte missing (U+7FFFFFFF) */
+ {
+ "\"\xFD\xBF\xBF\xBF\xBF\"",
+ NULL, /* bug: rejected */
+ "\"\\uDFFF\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"", */
+ "\xFD\xBF\xBF\xBF\xBF",
+ },
+ /* 3.4 Concatenation of incomplete sequences */
+ {
+ "\"\xC0\xE0\x80\xF0\x80\x80\xF8\x80\x80\x80\xFC\x80\x80\x80\x80"
+ "\xDF\xEF\xBF\xF7\xBF\xBF\xFB\xBF\xBF\xBF\xFD\xBF\xBF\xBF\xBF\"",
+ NULL, /* bug: rejected */
+ /* bug: want "\"\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF"
+ "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\"" */
+ "\"\\u0020\\uFFFF\\u0000\\u8000\\uFFFF\\uC000\\uFFFF\\uFFFF"
+ "\\u07EF\\uFFFF\\u7FFF\\uBFFF\\uFFFF\\uDFFF\\uFFFF\\uFFFF\"",
+ "\xC0\xE0\x80\xF0\x80\x80\xF8\x80\x80\x80\xFC\x80\x80\x80\x80"
+ "\xDF\xEF\xBF\xF7\xBF\xBF\xFB\xBF\xBF\xBF\xFD\xBF\xBF\xBF\xBF",
+ },
+ /* 3.5 Impossible bytes */
+ {
+ "\"\xFE\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFF\"",
+ "\xFE",
+ },
+ {
+ "\"\xFF\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFF\"",
+ "\xFF",
+ },
+ {
+ "\"\xFE\xFE\xFF\xFF\"",
+ NULL, /* bug: rejected */
+ /* bug: want "\"\\uFFFF\\uFFFF\\uFFFF\\uFFFF\"" */
+ "\"\\uEFBF\\uFFFF\"",
+ "\xFE\xFE\xFF\xFF",
+ },
+ /* 4 Overlong sequences */
+ /* 4.1 Overlong '/' */
+ {
+ "\"\xC0\xAF\"",
+ NULL, /* bug: rejected */
+ "\"\\u002F\"", /* bug: want "\"/\"" */
+ "\xC0\xAF",
+ },
+ {
+ "\"\xE0\x80\xAF\"",
+ "\xE0\x80\xAF", /* bug: not corrected */
+ "\"\\u002F\"", /* bug: want "\"/\"" */
+ },
+ {
+ "\"\xF0\x80\x80\xAF\"",
+ "\xF0\x80\x80\xAF", /* bug: not corrected */
+ "\"\\u0000\\uFFFF\"" /* bug: want "\"/\"" */
+ },
+ {
+ "\"\xF8\x80\x80\x80\xAF\"",
+ NULL, /* bug: rejected */
+ "\"\\u8000\\uFFFF\\uFFFF\"", /* bug: want "\"/\"" */
+ "\xF8\x80\x80\x80\xAF",
+ },
+ {
+ "\"\xFC\x80\x80\x80\x80\xAF\"",
+ NULL, /* bug: rejected */
+ "\"\\uC000\\uFFFF\\uFFFF\\uFFFF\"", /* bug: want "\"/\"" */
+ "\xFC\x80\x80\x80\x80\xAF",
+ },
+ /* 4.2 Maximum overlong sequences */
+ {
+ /* \U+007F */
+ "\"\xC1\xBF\"",
+ NULL, /* bug: rejected */
+ "\"\\u007F\"", /* bug: want "\"\177\"" */
+ "\xC1\xBF",
+ },
+ {
+ /* \U+07FF */
+ "\"\xE0\x9F\xBF\"",
+ "\xE0\x9F\xBF", /* bug: not corrected */
+ "\"\\u07FF\"",
+ },
+ {
+ /* \U+FFFF */
+ "\"\xF0\x8F\xBF\xBF\"",
+ "\xF0\x8F\xBF\xBF", /* bug: not corrected */
+ "\"\\u03FF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
+ },
+ {
+ /* \U+1FFFFF */
+ "\"\xF8\x87\xBF\xBF\xBF\"",
+ NULL, /* bug: rejected */
+ "\"\\u81FF\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
+ "\xF8\x87\xBF\xBF\xBF",
+ },
+ {
+ /* \U+3FFFFFF */
+ "\"\xFC\x83\xBF\xBF\xBF\xBF\"",
+ NULL, /* bug: rejected */
+ "\"\\uC0FF\\uFFFF\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
+ "\xFC\x83\xBF\xBF\xBF\xBF",
+ },
+ /* 4.3 Overlong representation of the NUL character */
+ {
+ /* \U+0000 */
+ "\"\xC0\x80\"",
+ NULL, /* bug: rejected */
+ "\"\\u0000\"",
+ "\xC0\x80",
+ },
+ {
+ /* \U+0000 */
+ "\"\xE0\x80\x80\"",
+ "\xE0\x80\x80", /* bug: not corrected */
+ "\"\\u0000\"",
+ },
+ {
+ /* \U+0000 */
+ "\"\xF0\x80\x80\x80\"",
+ "\xF0\x80\x80\x80", /* bug: not corrected */
+ "\"\\u0000\\uFFFF\"", /* bug: want "\"\\u0000\"" */
+ },
+ {
+ /* \U+0000 */
+ "\"\xF8\x80\x80\x80\x80\"",
+ NULL, /* bug: rejected */
+ "\"\\u8000\\uFFFF\\uFFFF\"", /* bug: want "\"\\u0000\"" */
+ "\xF8\x80\x80\x80\x80",
+ },
+ {
+ /* \U+0000 */
+ "\"\xFC\x80\x80\x80\x80\x80\"",
+ NULL, /* bug: rejected */
+ "\"\\uC000\\uFFFF\\uFFFF\\uFFFF\"", /* bug: want "\"\\u0000\"" */
+ "\xFC\x80\x80\x80\x80\x80",
+ },
+ /* 5 Illegal code positions */
+ /* 5.1 Single UTF-16 surrogates */
+ {
+ /* \U+D800 */
+ "\"\xED\xA0\x80\"",
+ "\xED\xA0\x80", /* bug: not corrected */
+ "\"\\uD800\"", /* bug: want "\"\\uFFFF\"" */
+ },
+ {
+ /* \U+DB7F */
+ "\"\xED\xAD\xBF\"",
+ "\xED\xAD\xBF", /* bug: not corrected */
+ "\"\\uDB7F\"", /* bug: want "\"\\uFFFF\"" */
+ },
+ {
+ /* \U+DB80 */
+ "\"\xED\xAE\x80\"",
+ "\xED\xAE\x80", /* bug: not corrected */
+ "\"\\uDB80\"", /* bug: want "\"\\uFFFF\"" */
+ },
+ {
+ /* \U+DBFF */
+ "\"\xED\xAF\xBF\"",
+ "\xED\xAF\xBF", /* bug: not corrected */
+ "\"\\uDBFF\"", /* bug: want "\"\\uFFFF\"" */
+ },
+ {
+ /* \U+DC00 */
+ "\"\xED\xB0\x80\"",
+ "\xED\xB0\x80", /* bug: not corrected */
+ "\"\\uDC00\"", /* bug: want "\"\\uFFFF\"" */
+ },
+ {
+ /* \U+DF80 */
+ "\"\xED\xBE\x80\"",
+ "\xED\xBE\x80", /* bug: not corrected */
+ "\"\\uDF80\"", /* bug: want "\"\\uFFFF\"" */
+ },
+ {
+ /* \U+DFFF */
+ "\"\xED\xBF\xBF\"",
+ "\xED\xBF\xBF", /* bug: not corrected */
+ "\"\\uDFFF\"", /* bug: want "\"\\uFFFF\"" */
+ },
+ /* 5.2 Paired UTF-16 surrogates */
+ {
+ /* \U+D800\U+DC00 */
+ "\"\xED\xA0\x80\xED\xB0\x80\"",
+ "\xED\xA0\x80\xED\xB0\x80", /* bug: not corrected */
+ "\"\\uD800\\uDC00\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */
+ },
+ {
+ /* \U+D800\U+DFFF */
+ "\"\xED\xA0\x80\xED\xBF\xBF\"",
+ "\xED\xA0\x80\xED\xBF\xBF", /* bug: not corrected */
+ "\"\\uD800\\uDFFF\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */
+ },
+ {
+ /* \U+DB7F\U+DC00 */
+ "\"\xED\xAD\xBF\xED\xB0\x80\"",
+ "\xED\xAD\xBF\xED\xB0\x80", /* bug: not corrected */
+ "\"\\uDB7F\\uDC00\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */
+ },
+ {
+ /* \U+DB7F\U+DFFF */
+ "\"\xED\xAD\xBF\xED\xBF\xBF\"",
+ "\xED\xAD\xBF\xED\xBF\xBF", /* bug: not corrected */
+ "\"\\uDB7F\\uDFFF\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */
+ },
+ {
+ /* \U+DB80\U+DC00 */
+ "\"\xED\xAE\x80\xED\xB0\x80\"",
+ "\xED\xAE\x80\xED\xB0\x80", /* bug: not corrected */
+ "\"\\uDB80\\uDC00\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */
+ },
+ {
+ /* \U+DB80\U+DFFF */
+ "\"\xED\xAE\x80\xED\xBF\xBF\"",
+ "\xED\xAE\x80\xED\xBF\xBF", /* bug: not corrected */
+ "\"\\uDB80\\uDFFF\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */
+ },
+ {
+ /* \U+DBFF\U+DC00 */
+ "\"\xED\xAF\xBF\xED\xB0\x80\"",
+ "\xED\xAF\xBF\xED\xB0\x80", /* bug: not corrected */
+ "\"\\uDBFF\\uDC00\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */
+ },
+ {
+ /* \U+DBFF\U+DFFF */
+ "\"\xED\xAF\xBF\xED\xBF\xBF\"",
+ "\xED\xAF\xBF\xED\xBF\xBF", /* bug: not corrected */
+ "\"\\uDBFF\\uDFFF\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */
+ },
+ /* 5.3 Other illegal code positions */
+ {
+ /* \U+FFFE */
+ "\"\xEF\xBF\xBE\"",
+ "\xEF\xBF\xBE", /* bug: not corrected */
+ "\"\\uFFFE\"", /* bug: not corrected */
+ },
+ {
+ /* \U+FFFF */
+ "\"\xEF\xBF\xBF\"",
+ "\xEF\xBF\xBF", /* bug: not corrected */
+ "\"\\uFFFF\"", /* bug: not corrected */
+ },
+ {}
+ };
+ int i;
+ QObject *obj;
+ QString *str;
+ const char *json_in, *utf8_out, *utf8_in, *json_out;
+
+ for (i = 0; test_cases[i].json_in; i++) {
+ json_in = test_cases[i].json_in;
+ utf8_out = test_cases[i].utf8_out;
+ utf8_in = test_cases[i].utf8_in ?: test_cases[i].utf8_out;
+ json_out = test_cases[i].json_out ?: test_cases[i].json_in;
+
+ obj = qobject_from_json(json_in);
+ if (utf8_out) {
+ g_assert(obj);
+ g_assert(qobject_type(obj) == QTYPE_QSTRING);
+ str = qobject_to_qstring(obj);
+ g_assert_cmpstr(qstring_get_str(str), ==, utf8_out);
+ } else {
+ g_assert(!obj);
+ }
+ qobject_decref(obj);
+
+ obj = QOBJECT(qstring_from_str(utf8_in));
+ str = qobject_to_json(obj);
+ if (json_out) {
+ g_assert(str);
+ g_assert_cmpstr(qstring_get_str(str), ==, json_out);
+ } else {
+ g_assert(!str);
+ }
+ QDECREF(str);
+ qobject_decref(obj);
+
+ /*
+ * Disabled, because json_out currently contains the crap
+ * qobject_to_json() produces.
+ * FIXME Enable once these bugs have been fixed.
+ */
+ if (0 && json_out != json_in) {
+ obj = qobject_from_json(json_out);
+ g_assert(obj);
+ g_assert(qobject_type(obj) == QTYPE_QSTRING);
+ str = qobject_to_qstring(obj);
+ g_assert_cmpstr(qstring_get_str(str), ==, utf8_out);
+ }
+ }
+}
+
static void vararg_string(void)
{
int i;
@@ -748,6 +1411,7 @@ int main(int argc, char **argv)
g_test_add_func("/literals/string/simple", simple_string);
g_test_add_func("/literals/string/escaped", escaped_string);
+ g_test_add_func("/literals/string/utf8", utf8_string);
g_test_add_func("/literals/string/single_quote", single_quote_string);
g_test_add_func("/literals/string/vararg", vararg_string);
More information about the Spice-commits
mailing list