:p
atchew
Login
Hi, This series makes HMP compile-time optional via --disable-hmp. The resulting binary speaks only QMP - reducing the attack surface, binary size and enforcing a separation between machine-readable interface and interactive debugging console. QMP offers almost all the functionality HMP could provide, so a separate standalone "HMP-like" console could be implemented on top of it. The rough list of missing commands (+complexity estimation) after this series: Debugging / introspection: - info registers (medium) - plus $reg expression handling - x/xp read memory (medium) - gpa2hpa/gpa2hva/gva2gpa address translation (medium) - info lapic (high) - deep x86 APIC state, lots of registers - info mem (high) - virtual memory mappings, different per arch - info tlb (high) - virt-to-phys mappings, also per arch - info mtree (high) - memory region tree, multiple view modes - info skeys (medium) - s390x storage keys - info cmma (medium) - s390x CMMA values - info qdm (easy) - could probably be folded into QOM introspection - info qtree (medium) - same, maybe QOM introspection is enough - info snapshots (medium) - info usbhost (medium) - info via (medium) -- VIA south bridge state Simple actions / settings: - gdbserver (trivial) - boot_set (easy) - mce (easy) - x86 MCE injection - sum (easy) - memory checksum - sync-profile (easy) - enable/disable/reset - info sync-profile (medium) - one-insn-per-tb (easy) - could be a QOM property on the accelerator - pcie_aer_inject_error (easy) - migration_mode (medium?) - i/o ioport read/write (easy) - hostfwd-add/hostfwd-remove (medium) - slirp port forwarding - log/logfile (medium) - trace-file (medium) Also, to let clients do disassembly on their side, it'd be useful to have something like "query-disassemble-info" that gives the client what architecture and endianness is used etc. In the meantime, being able to build without HMP is valuable and helps identifying the missing pieces. The series does so by steps: - preparatory cleanups and bug fixes - add commands without QMP equivalent and needed for tests - convert most iotests and qtests from HMP to QMP - guard HMP-only code paths - make HMP source files conditional in the build system Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- Marc-André Lureau (40): vl: fix -monitor none prefix matching hmp: remove 'vcpu' argument from trace-event help hmp: fix snapshot_blkdev argument type target/i386: decouple cpu_x86_inject_mce() from Monitor system: move gpa2hva() to system memory unit s390x: prevent crash if given invalid CPU# system: decouple qmp_inject_nmi() from Monitor hmp: correct the nmi documentation monitor: move HMP-only fields from Monitor to MonitorHMP tests/functional: use query-version QMP command instead of HMP net/qapi: add x-query-usernet tests: use x-query-usernet RFC: qtest: add -qtest-no-ts option qemu-io: propagate errors through Error API instead of printf block: add x-qemu-io QMP command tests/qemu-iotests/N: use x-qemu-io QMP command tests/qemu-iotests/181, 192, 249: convert to QMP tests/qemu-iotests/186: convert from HMP to QMP tests/qemu-iotests/copy-before-write: convert to QMP tests/qemu-iotests: skip some 172 & 267 that require HMP RFC: qtest: add qemu-io command to the qtest protocol RFC: qtest/ide-test: convert to use qtest qemu-io command tests/qtest/numa-test: replace HMP "info numa" with QMP query-cpus-fast tests/qtest/pnv: drop unnecessary -serial mon:stdio net: add x-query-network QMP command tests/qtest/netdev-socket: replace HMP with x-query-network QMP tests/qtest/cdrom-test: replace HMP "info block" with QMP query-block tests/qtest/qmp-test: don't depend on human-monitor-command build-sys: add 'hmp' option tests/qtest/device-introspect-test: fix test without HMP tests/qtest/drive_del-test: guard HMP-dependent tests with CONFIG_HMP qapi: make HMP-specific schema entries conditional on CONFIG_HMP monitor: guard HMP-specific code with CONFIG_HMP util: guard monitor_vprintf callers with CONFIG_HMP system: guard HMP initialization paths with CONFIG_HMP hw: guard BusClass::print_dev with CONFIG_HMP target: guard MonitorDef tables with CONFIG_HMP Guard HMP command implementations with CONFIG_HMP build-sys: make HMP source files conditional on have_hmp gitlab-ci: add --disable-hmp to build-without-defaults meson.build | 6 +- qapi/block.json | 34 ++ qapi/control.json | 4 +- qapi/machine.json | 5 +- qapi/misc.json | 3 +- qapi/net.json | 166 ++++++++++ qapi/qom.json | 5 +- include/hw/core/qdev.h | 2 + include/hw/core/sysemu-cpu-ops.h | 2 + include/monitor/hmp.h | 2 + include/monitor/monitor.h | 11 +- include/net/net.h | 3 +- include/qemu-io.h | 4 +- include/system/memory.h | 2 + include/system/qtest.h | 3 +- monitor/monitor-internal.h | 4 +- net/hub.h | 4 +- target/i386/cpu.h | 4 +- tests/qtest/libqtest.h | 11 + accel/accel-system.c | 2 + accel/tcg/monitor.c | 2 + block/monitor/block-hmp-cmds.c | 60 +--- block/monitor/qmp-cmds.c | 79 +++++ chardev/char.c | 7 + gdbstub/system.c | 8 + hw/char/virtio-serial-bus.c | 6 + hw/core/sysbus.c | 6 + hw/i386/kvm/xen-stubs.c | 2 + hw/i386/kvm/xen_evtchn.c | 3 +- hw/i386/sgx.c | 2 + hw/misc/auxbus.c | 16 +- hw/misc/mos6522-stub.c | 2 + hw/misc/mos6522.c | 2 + hw/pci/pci-hmp-cmds.c | 2 + hw/pci/pci-stub.c | 2 + hw/pci/pci.c | 2 + hw/s390x/s390-skeys.c | 2 + hw/s390x/s390-stattrib.c | 4 + hw/s390x/s390-virtio-ccw.c | 5 + hw/uefi/ovmf-log.c | 2 + hw/usb/bus.c | 6 + hw/usb/host-libusb.c | 6 + hw/xen/xen-bus.c | 4 + migration/dirtyrate.c | 2 + monitor/hmp-cmds.c | 48 +-- monitor/hmp.c | 5 +- monitor/monitor.c | 47 ++- monitor/qmp-cmds.c | 2 + net/hub.c | 29 +- net/net-hmp-cmds.c | 59 +++- net/net.c | 70 +++- net/slirp.c | 41 ++- qemu-io-cmds.c | 426 +++++++++++++------------ qemu-io.c | 17 +- replay/replay-debugging.c | 8 + replay/stubs-system.c | 6 + stubs/monitor-core.c | 2 + stubs/monitor-internal.c | 2 + system/cpus.c | 7 +- system/dirtylimit.c | 6 + system/physmem.c | 31 ++ system/qdev-monitor.c | 4 + system/qtest.c | 75 ++++- system/vl.c | 13 +- target/i386/cpu-apic.c | 2 + target/i386/cpu.c | 4 + target/i386/helper.c | 49 +-- target/i386/kvm/kvm.c | 4 +- target/i386/monitor.c | 9 +- target/i386/sev.c | 2 + target/m68k/cpu.c | 4 + target/m68k/monitor.c | 2 + target/ppc/monitor.c | 2 + target/riscv/monitor.c | 3 + target/sh4/monitor.c | 2 + target/sparc/cpu.c | 5 +- target/sparc/monitor.c | 2 + target/xtensa/monitor.c | 2 + tests/qtest/cdrom-test.c | 29 +- tests/qtest/device-introspect-test.c | 111 +++++-- tests/qtest/drive_del-test.c | 14 + tests/qtest/ide-test.c | 4 +- tests/qtest/libqtest.c | 14 + tests/qtest/netdev-socket.c | 143 +++++---- tests/qtest/numa-test.c | 63 +++- tests/qtest/pnv-host-i2c-test.c | 2 +- tests/qtest/pnv-xive2-test.c | 2 +- tests/qtest/qmp-test.c | 9 +- tests/unit/test-util-sockets.c | 4 +- tools/qemu-vnc/stubs.c | 2 + util/error-report.c | 8 +- util/qemu-print.c | 6 + .gitlab-ci.d/buildtest.yml | 1 + audio/meson.build | 4 +- backends/meson.build | 5 +- block/monitor/meson.build | 5 +- chardev/meson.build | 5 +- disas/meson.build | 4 +- dump/meson.build | 5 +- hmp-commands-info.hx | 6 +- hmp-commands.hx | 14 +- hw/core/meson.build | 5 +- hw/i386/meson.build | 4 +- hw/net/meson.build | 4 +- hw/pci/meson.build | 4 +- hw/virtio/meson.build | 4 +- meson_options.txt | 2 + migration/meson.build | 4 +- monitor/meson.build | 9 +- net/meson.build | 4 +- python/qemu/utils/__init__.py | 5 +- qemu-options.hx | 7 +- qom/meson.build | 4 +- scripts/meson-buildoptions.sh | 3 + stats/meson.build | 5 +- stubs/meson.build | 12 +- system/meson.build | 9 +- tests/functional/generic/test_version.py | 10 +- tests/functional/qemu_test/utils.py | 8 +- tests/qemu-iotests/004.out | 20 +- tests/qemu-iotests/021.out | 60 ++-- tests/qemu-iotests/060 | 8 +- tests/qemu-iotests/060.out | 44 ++- tests/qemu-iotests/071 | 30 +- tests/qemu-iotests/071.out | 14 +- tests/qemu-iotests/072.out | 2 +- tests/qemu-iotests/080.out | 4 +- tests/qemu-iotests/089.out | 4 +- tests/qemu-iotests/114.out | 2 +- tests/qemu-iotests/117 | 5 +- tests/qemu-iotests/117.out | 7 +- tests/qemu-iotests/120 | 4 +- tests/qemu-iotests/120.out | 2 +- tests/qemu-iotests/134.out | 2 +- tests/qemu-iotests/137.out | 2 +- tests/qemu-iotests/156 | 36 +-- tests/qemu-iotests/156.out | 48 +-- tests/qemu-iotests/161 | 18 +- tests/qemu-iotests/161.out | 24 +- tests/qemu-iotests/171 | 2 +- tests/qemu-iotests/171.out | 68 ++-- tests/qemu-iotests/172 | 5 + tests/qemu-iotests/181 | 99 ++++-- tests/qemu-iotests/181.out | 36 ++- tests/qemu-iotests/186 | 20 +- tests/qemu-iotests/186.out | 440 ++++++-------------------- tests/qemu-iotests/192 | 22 +- tests/qemu-iotests/192.out | 17 +- tests/qemu-iotests/214.out | 2 +- tests/qemu-iotests/220.out | 2 +- tests/qemu-iotests/244.out | 12 +- tests/qemu-iotests/249 | 18 +- tests/qemu-iotests/249.out | 18 +- tests/qemu-iotests/267 | 4 + tests/qemu-iotests/271.out | 14 +- tests/qemu-iotests/283 | 4 +- tests/qemu-iotests/283.out | 4 +- tests/qemu-iotests/common.rc | 7 + tests/qemu-iotests/iotests.py | 4 +- tests/qemu-iotests/tests/copy-before-write | 98 +++--- tests/qemu-iotests/tests/image-fleecing | 4 +- tests/qemu-iotests/tests/image-fleecing.out | 52 +-- tests/qemu-iotests/tests/migrate-bitmaps-test | 4 +- tests/qtest/meson.build | 8 +- tests/vm/basevm.py | 13 +- trace/meson.build | 5 +- ui/meson.build | 4 +- 167 files changed, 2092 insertions(+), 1292 deletions(-) --- base-commit: e89049b3ba5f1f0468bc0d294173345597514a1b change-id: 20260521-qemu-no-hmp-ead3f0bf79c0 Best regards, -- Marc-André Lureau <marcandre.lureau@redhat.com>
Use g_strcmp0() for exact match instead of strncmp() which would incorrectly treat any string starting with "none" as disabling the monitor. Fixes: 70e098af88f ("monitor: allow to disable the default monitor") Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- system/vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/vl.c b/system/vl.c index XXXXXXX..XXXXXXX 100644 --- a/system/vl.c +++ b/system/vl.c @@ -XXX,XX +XXX,XX @@ void qemu_init(int argc, char **argv) } case QEMU_OPTION_monitor: default_monitor = 0; - if (strncmp(optarg, "none", 4)) { + if (g_strcmp0(optarg, "none")) { monitor_parse(optarg, "readline", false); } break; -- 2.54.0
Fixes: 89aafcf2a793 ("trace: remove code that depends on setting vcpu") Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- hmp-commands-info.hx | 6 +++--- hmp-commands.hx | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index XXXXXXX..XXXXXXX 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx @@ -XXX,XX +XXX,XX @@ ERST { .name = "trace-events", - .args_type = "name:s?,vcpu:i?", - .params = "[name] [vcpu]", + .args_type = "name:s?", + .params = "[name]", .help = "show available trace-events & their state " - "(name: event name pattern; vcpu: vCPU to query, default is any)", + "(name: event name pattern)", .cmd = hmp_info_trace_events, .command_completion = info_trace_events_completion, }, diff --git a/hmp-commands.hx b/hmp-commands.hx index XXXXXXX..XXXXXXX 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -XXX,XX +XXX,XX @@ ERST { .name = "trace-event", - .args_type = "name:s,option:b,vcpu:i?", - .params = "name on|off [vcpu]", - .help = "changes status of a specific trace event " - "(vcpu: vCPU to set, default is all)", + .args_type = "name:s,option:b", + .params = "name on|off", + .help = "changes status of a specific trace event", .cmd = hmp_trace_event, .command_completion = trace_event_completion, }, -- 2.54.0
The `snapshot-file` argument for `snapshot_blkdev` is mandatory. Correct the `args_type` definition to reflect this. Fixes: 6106e2492fe ("qapi: Convert blockdev_snapshot_sync") Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- hmp-commands.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index XXXXXXX..XXXXXXX 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -XXX,XX +XXX,XX @@ ERST { .name = "snapshot_blkdev", - .args_type = "reuse:-n,device:B,snapshot-file:s?,format:s?", + .args_type = "reuse:-n,device:B,snapshot-file:s,format:s?", .params = "[-n] device [new-image-file] [format]", .help = "initiates a live snapshot\n\t\t\t" "of device. If a new image file is specified, the\n\t\t\t" -- 2.54.0
Replace monitor_printf() error reporting with the standard **errp pattern. Drop the Monitor *mon parameter and return bool to indicate success, improving the function usage from non-HMP contexts. Update the KVM MCE injection path and hmp_mce() accordingly. Notes: - we may want to print the error in KVM path too - multiple error prints are now accumulated with error hints Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- target/i386/cpu.h | 4 ++-- target/i386/helper.c | 49 ++++++++++++++++++++++++++++--------------------- target/i386/kvm/kvm.c | 4 ++-- target/i386/monitor.c | 6 ++++-- 4 files changed, 36 insertions(+), 27 deletions(-) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -XXX,XX +XXX,XX @@ void do_cpu_init(X86CPU *cpu); #define MCE_INJECT_BROADCAST 1 #define MCE_INJECT_UNCOND_AO 2 -void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank, +bool cpu_x86_inject_mce(X86CPU *cpu, int bank, uint64_t status, uint64_t mcg_status, uint64_t addr, - uint64_t misc, int flags); + uint64_t misc, int flags, Error **errp); uint32_t cpu_cc_compute_all(CPUX86State *env1); diff --git a/target/i386/helper.c b/target/i386/helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -XXX,XX +XXX,XX @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "qapi/qapi-events-run-state.h" #include "cpu.h" #include "exec/cputlb.h" @@ -XXX,XX +XXX,XX @@ #ifndef CONFIG_USER_ONLY #include "system/hw_accel.h" #include "system/memory.h" -#include "monitor/monitor.h" #include "kvm/kvm_i386.h" #endif #include "qemu/log.h" @@ -XXX,XX +XXX,XX @@ out: } typedef struct MCEInjectionParams { - Monitor *mon; + GString *err; int bank; uint64_t status; uint64_t mcg_status; @@ -XXX,XX +XXX,XX @@ static void do_inject_x86_mce(CPUState *cs, run_on_cpu_data data) * reporting is disabled */ if ((cenv->mcg_cap & MCG_CTL_P) && cenv->mcg_ctl != ~(uint64_t)0) { - monitor_printf(params->mon, - "CPU %d: Uncorrected error reporting disabled\n", - cs->cpu_index); + g_string_append_printf(params->err, + "CPU %d: Uncorrected error reporting disabled\n", + cs->cpu_index); return; } @@ -XXX,XX +XXX,XX @@ static void do_inject_x86_mce(CPUState *cs, run_on_cpu_data data) * reporting is disabled for the bank */ if (banks[0] != ~(uint64_t)0) { - monitor_printf(params->mon, - "CPU %d: Uncorrected error reporting disabled for" - " bank %d\n", - cs->cpu_index, params->bank); + g_string_append_printf(params->err, + "CPU %d: Uncorrected error reporting disabled for bank %d\n", + cs->cpu_index, params->bank); return; } @@ -XXX,XX +XXX,XX @@ static void do_inject_x86_mce(CPUState *cs, run_on_cpu_data data) if (need_reset) { emit_guest_memory_failure(MEMORY_FAILURE_ACTION_RESET, ar, recursive); - monitor_printf(params->mon, "%s", msg); + g_string_append_printf(params->err, "%s\n", msg); qemu_log_mask(CPU_LOG_RESET, "%s\n", msg); qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); return; @@ -XXX,XX +XXX,XX @@ static void do_inject_x86_mce(CPUState *cs, run_on_cpu_data data) emit_guest_memory_failure(MEMORY_FAILURE_ACTION_INJECT, ar, recursive); } -void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank, +bool cpu_x86_inject_mce(X86CPU *cpu, int bank, uint64_t status, uint64_t mcg_status, uint64_t addr, - uint64_t misc, int flags) + uint64_t misc, int flags, Error **errp) { + ERRP_GUARD(); CPUState *cs = CPU(cpu); CPUX86State *cenv = &cpu->env; + g_autoptr(GString) err = g_string_new(NULL); MCEInjectionParams params = { - .mon = mon, + .err = err, .bank = bank, .status = status, .mcg_status = mcg_status, @@ -XXX,XX +XXX,XX @@ void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank, unsigned bank_num = cenv->mcg_cap & 0xff; if (!cenv->mcg_cap) { - monitor_printf(mon, "MCE injection not supported\n"); - return; + error_setg(errp, "MCE injection not supported"); + return false; } if (bank >= bank_num) { - monitor_printf(mon, "Invalid MCE bank number\n"); - return; + error_setg(errp, "Invalid MCE bank number"); + return false; } if (!(status & MCI_STATUS_VAL)) { - monitor_printf(mon, "Invalid MCE status code\n"); - return; + error_setg(errp, "Invalid MCE status code"); + return false; } if ((flags & MCE_INJECT_BROADCAST) && !cpu_x86_support_mca_broadcast(cenv)) { - monitor_printf(mon, "Guest CPU does not support MCA broadcast\n"); - return; + error_setg(errp, "Guest CPU does not support MCA broadcast"); + return false; } run_on_cpu(cs, do_inject_x86_mce, RUN_ON_CPU_HOST_PTR(¶ms)); @@ -XXX,XX +XXX,XX @@ void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank, run_on_cpu(other_cs, do_inject_x86_mce, RUN_ON_CPU_HOST_PTR(¶ms)); } } + if (params.err->len) { + error_setg(errp, "Failed to inject MCE"); + error_append_hint(errp, "%s", params.err->str); + return false; + } + return true; } static inline target_ulong get_memio_eip(CPUX86State *env) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index XXXXXXX..XXXXXXX 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -XXX,XX +XXX,XX @@ static void kvm_mce_inject(X86CPU *cpu, hwaddr paddr, int code) flags = 0; } - cpu_x86_inject_mce(NULL, cpu, 9, status, mcg_status, paddr, - (MCM_ADDR_PHYS << 6) | 0xc, flags); + cpu_x86_inject_mce(cpu, 9, status, mcg_status, paddr, + (MCM_ADDR_PHYS << 6) | 0xc, flags, NULL); } static void emit_hypervisor_memory_failure(MemoryFailureAction action, bool ar) diff --git a/target/i386/monitor.c b/target/i386/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/target/i386/monitor.c +++ b/target/i386/monitor.c @@ -XXX,XX +XXX,XX @@ void hmp_mce(Monitor *mon, const QDict *qdict) uint64_t addr = qdict_get_int(qdict, "addr"); uint64_t misc = qdict_get_int(qdict, "misc"); int flags = MCE_INJECT_UNCOND_AO; + Error *err = NULL; if (qdict_get_try_bool(qdict, "broadcast", false)) { flags |= MCE_INJECT_BROADCAST; @@ -XXX,XX +XXX,XX @@ void hmp_mce(Monitor *mon, const QDict *qdict) cs = qemu_get_cpu(cpu_index); if (cs != NULL) { cpu = X86_CPU(cs); - cpu_x86_inject_mce(mon, cpu, bank, status, mcg_status, addr, misc, - flags); + cpu_x86_inject_mce(cpu, bank, status, mcg_status, addr, misc, + flags, &err); + hmp_handle_error(mon, err); } } -- 2.54.0
The function is now used by SEV code path. Move it to physmem.c rather than hmp-cmds.c. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- include/monitor/monitor.h | 2 -- include/system/memory.h | 2 ++ monitor/hmp-cmds.c | 31 ------------------------------- system/physmem.c | 31 +++++++++++++++++++++++++++++++ 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index XXXXXXX..XXXXXXX 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -XXX,XX +XXX,XX @@ int monitor_get_cpu_index(Monitor *mon); int monitor_puts_locked(Monitor *mon, const char *str); void monitor_flush_locked(Monitor *mon); -void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, uint64_t size, Error **errp); - void monitor_read_command(MonitorHMP *mon, int show_prompt); int monitor_read_password(MonitorHMP *mon, ReadLineFunc *readline_func, void *opaque); diff --git a/include/system/memory.h b/include/system/memory.h index XXXXXXX..XXXXXXX 100644 --- a/include/system/memory.h +++ b/include/system/memory.h @@ -XXX,XX +XXX,XX @@ bool ram_block_discard_is_required(void); void ram_block_add_cpr_blocker(RAMBlock *rb, Error **errp); void ram_block_del_cpr_blocker(RAMBlock *rb); +void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, uint64_t size, Error **errp); + #endif diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -XXX,XX +XXX,XX @@ void hmp_physical_memory_dump(Monitor *mon, const QDict *qdict) memory_dump(mon, count, format, size, addr, true); } -void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, uint64_t size, Error **errp) -{ - Int128 gpa_region_size; - MemoryRegionSection mrs = memory_region_find(get_system_memory(), - addr, size); - - if (!mrs.mr) { - error_setg(errp, - "No memory is mapped at address 0x%" HWADDR_PRIx, addr); - return NULL; - } - - if (!memory_region_is_ram(mrs.mr) && !memory_region_is_romd(mrs.mr)) { - error_setg(errp, - "Memory at address 0x%" HWADDR_PRIx " is not RAM", addr); - memory_region_unref(mrs.mr); - return NULL; - } - - gpa_region_size = int128_make64(size); - if (int128_lt(mrs.size, gpa_region_size)) { - error_setg(errp, "Size of memory region at 0x%" HWADDR_PRIx - " exceeded.", addr); - memory_region_unref(mrs.mr); - return NULL; - } - - *p_mr = mrs.mr; - return qemu_map_ram_ptr(mrs.mr->ram_block, mrs.offset_within_region); -} - void hmp_gpa2hva(Monitor *mon, const QDict *qdict) { hwaddr addr = qdict_get_int(qdict, "addr"); diff --git a/system/physmem.c b/system/physmem.c index XXXXXXX..XXXXXXX 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -XXX,XX +XXX,XX @@ void ram_block_del_cpr_blocker(RAMBlock *rb) { migrate_del_blocker(&rb->cpr_blocker); } + +void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, uint64_t size, Error **errp) +{ + Int128 gpa_region_size; + MemoryRegionSection mrs = memory_region_find(get_system_memory(), + addr, size); + + if (!mrs.mr) { + error_setg(errp, + "No memory is mapped at address 0x%" HWADDR_PRIx, addr); + return NULL; + } + + if (!memory_region_is_ram(mrs.mr) && !memory_region_is_romd(mrs.mr)) { + error_setg(errp, + "Memory at address 0x%" HWADDR_PRIx " is not RAM", addr); + memory_region_unref(mrs.mr); + return NULL; + } + + gpa_region_size = int128_make64(size); + if (int128_lt(mrs.size, gpa_region_size)) { + error_setg(errp, "Size of memory region at 0x%" HWADDR_PRIx + " exceeded.", addr); + memory_region_unref(mrs.mr); + return NULL; + } + + *p_mr = mrs.mr; + return qemu_map_ram_ptr(mrs.mr->ram_block, mrs.offset_within_region); +} -- 2.54.0
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- hw/s390x/s390-virtio-ccw.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -XXX,XX +XXX,XX @@ static void s390_nmi(NMIState *n, int cpu_index, Error **errp) { CPUState *cs = qemu_get_cpu(cpu_index); + if (!cs) { + error_setg(errp, "CPU %d does not exist", cpu_index); + return; + } + s390_cpu_restart(S390_CPU(cs)); } -- 2.54.0
Use first_cpu directly instead of going through monitor_get_cpu_index(), as this is HMP-territory. QMP doesn't have a `cpu` command, we should add arguments instead when needed. Update the inject-nmi doc to accurately describe per-architecture NMI delivery. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- qapi/machine.json | 5 +++-- system/cpus.c | 7 +++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/qapi/machine.json b/qapi/machine.json index XXXXXXX..XXXXXXX 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -XXX,XX +XXX,XX @@ ## # @inject-nmi: # -# Injects a Non-Maskable Interrupt into the default CPU (x86/s390) or -# all CPUs (ppc64). The command fails when the guest doesn't support +# Injects a Non-Maskable Interrupt into the virtual machine. The NMI +# is delivered to all vCPUs (x86, hppa, ppc64) or to the first vCPU +# (s390). The command fails when the guest doesn't support # injecting. # # Since: 0.14 diff --git a/system/cpus.c b/system/cpus.c index XXXXXXX..XXXXXXX 100644 --- a/system/cpus.c +++ b/system/cpus.c @@ -XXX,XX +XXX,XX @@ exit: void qmp_inject_nmi(Error **errp) { - nmi_monitor_handle(monitor_get_cpu_index(monitor_cur()), errp); + int cpu_index = UNASSIGNED_CPU_INDEX; + if (first_cpu) { + cpu_index = first_cpu->cpu_index; + } + nmi_monitor_handle(cpu_index, errp); } - -- 2.54.0
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- hmp-commands.hx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index XXXXXXX..XXXXXXX 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -XXX,XX +XXX,XX @@ ERST .cmd = hmp_nmi, }, SRST -``nmi`` *cpu* - Inject an NMI on the default CPU (x86/s390) or all CPUs (ppc64). +``nmi`` + Inject an NMI on the associated monitor vCPU (``cpu`` command, on s390x) or + all vCPUs (on other architectures). ERST { -- 2.54.0
mon_cpu_path and reset_seen are only used by HMP monitors; move them from the base Monitor struct into MonitorHMP to properly encapsulate HMP-specific state. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- monitor/monitor-internal.h | 4 ++-- monitor/hmp-cmds.c | 17 ++++++++++------- monitor/hmp.c | 5 +++-- monitor/monitor.c | 16 +++++++++++----- 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index XXXXXXX..XXXXXXX 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -XXX,XX +XXX,XX @@ struct Monitor { bool skip_flush; bool use_io_thread; - char *mon_cpu_path; QTAILQ_ENTRY(Monitor) entry; /* @@ -XXX,XX +XXX,XX @@ struct Monitor { GString *outbuf; guint out_watch; int mux_out; - int reset_seen; }; struct MonitorHMP { @@ -XXX,XX +XXX,XX @@ struct MonitorHMP { * These members can be safely accessed without locks. */ ReadLineState *rs; + char *mon_cpu_path; + int reset_seen; }; typedef struct { diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -XXX,XX +XXX,XX @@ void hmp_dumpdtb(Monitor *mon, const QDict *qdict) /* Set the current CPU defined by the user. Callers must hold BQL. */ int monitor_set_cpu(Monitor *mon, int cpu_index) { + assert(!monitor_is_qmp(mon)); + MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); CPUState *cpu; cpu = qemu_get_cpu(cpu_index); if (cpu == NULL) { return -1; } - g_free(mon->mon_cpu_path); - mon->mon_cpu_path = object_get_canonical_path(OBJECT(cpu)); + g_free(hmp_mon->mon_cpu_path); + hmp_mon->mon_cpu_path = object_get_canonical_path(OBJECT(cpu)); return 0; } /* Callers must hold BQL. */ static CPUState *mon_get_cpu_sync(Monitor *mon, bool synchronize) { + MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); CPUState *cpu = NULL; - if (mon->mon_cpu_path) { - cpu = (CPUState *) object_resolve_path_type(mon->mon_cpu_path, + if (hmp_mon->mon_cpu_path) { + cpu = (CPUState *) object_resolve_path_type(hmp_mon->mon_cpu_path, TYPE_CPU, NULL); if (!cpu) { - g_free(mon->mon_cpu_path); - mon->mon_cpu_path = NULL; + g_free(hmp_mon->mon_cpu_path); + hmp_mon->mon_cpu_path = NULL; } } - if (!mon->mon_cpu_path) { + if (!hmp_mon->mon_cpu_path) { if (!first_cpu) { return NULL; } diff --git a/monitor/hmp.c b/monitor/hmp.c index XXXXXXX..XXXXXXX 100644 --- a/monitor/hmp.c +++ b/monitor/hmp.c @@ -XXX,XX +XXX,XX @@ static void monitor_read(void *opaque, const uint8_t *buf, int size) static void monitor_event(void *opaque, QEMUChrEvent event) { Monitor *mon = opaque; + MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); switch (event) { case CHR_EVENT_MUX_IN: @@ -XXX,XX +XXX,XX @@ static void monitor_event(void *opaque, QEMUChrEvent event) case CHR_EVENT_MUX_OUT: qemu_mutex_lock(&mon->mon_lock); if (!mon->mux_out) { - if (mon->reset_seen && !mon->suspend_cnt) { + if (hmp_mon->reset_seen && !mon->suspend_cnt) { monitor_puts_locked(mon, "\n"); } else { monitor_flush_locked(mon); @@ -XXX,XX +XXX,XX @@ static void monitor_event(void *opaque, QEMUChrEvent event) monitor_printf(mon, "QEMU %s monitor - type 'help' for more " "information\n", QEMU_VERSION); qemu_mutex_lock(&mon->mon_lock); - mon->reset_seen = 1; + hmp_mon->reset_seen = 1; if (!mon->mux_out) { /* Suspend-resume forces the prompt to be printed. */ monitor_suspend(mon); diff --git a/monitor/monitor.c b/monitor/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -XXX,XX +XXX,XX @@ static void monitor_accept_input(void *opaque) Monitor *mon = opaque; qemu_mutex_lock(&mon->mon_lock); - if (!monitor_is_qmp(mon) && mon->reset_seen) { + if (!monitor_is_qmp(mon)) { MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); assert(hmp_mon->rs); - readline_restart(hmp_mon->rs); + bool reset_seen = hmp_mon->reset_seen; + if (reset_seen) { + readline_restart(hmp_mon->rs); + } qemu_mutex_unlock(&mon->mon_lock); - readline_show_prompt(hmp_mon->rs); + if (reset_seen) { + readline_show_prompt(hmp_mon->rs); + } } else { qemu_mutex_unlock(&mon->mon_lock); } @@ -XXX,XX +XXX,XX @@ void monitor_data_init(Monitor *mon, bool is_qmp, bool skip_flush, void monitor_data_destroy(Monitor *mon) { - g_free(mon->mon_cpu_path); qemu_chr_fe_deinit(&mon->chr, false); if (monitor_is_qmp(mon)) { monitor_data_destroy_qmp(container_of(mon, MonitorQMP, common)); } else { - readline_free(container_of(mon, MonitorHMP, common)->rs); + MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); + readline_free(hmp_mon->rs); + g_free(hmp_mon->mon_cpu_path); } g_string_free(mon->outbuf, true); qemu_mutex_destroy(&mon->mon_lock); -- 2.54.0
Replace the human-monitor-command based version test with the native QMP query-version command, which returns structured version data. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/functional/generic/test_version.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/functional/generic/test_version.py b/tests/functional/generic/test_version.py index XXXXXXX..XXXXXXX 100755 --- a/tests/functional/generic/test_version.py +++ b/tests/functional/generic/test_version.py @@ -XXX,XX +XXX,XX @@ class Version(QemuSystemTest): - def test_qmp_human_info_version(self): + def test_qmp_query_version(self): self.set_machine('none') self.vm.add_args('-nodefaults') self.vm.launch() - res = self.vm.cmd('human-monitor-command', - command_line='info version') - self.assertRegex(res, r'^(\d+\.\d+\.\d)') + res = self.vm.cmd('query-version') + version = res['qemu'] + self.assertIsInstance(version['major'], int) + self.assertIsInstance(version['minor'], int) + self.assertIsInstance(version['micro'], int) if __name__ == '__main__': QemuSystemTest.main() -- 2.54.0
Add a QMP equivalent to hmp "info usernet", so we can disable HMP. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- qapi/net.json | 44 ++++++++++++++++++++++++++++++++++++++++++++ net/slirp.c | 34 ++++++++++++++++++++++++++++------ 2 files changed, 72 insertions(+), 6 deletions(-) diff --git a/qapi/net.json b/qapi/net.json index XXXXXXX..XXXXXXX 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -XXX,XX +XXX,XX @@ ## { 'event': 'NETDEV_VHOST_USER_DISCONNECTED', 'data': { 'netdev-id': 'str' } } + +## +# @UsernetInfo: +# +# Information about a user-mode network stack (slirp). +# +# @hub-id: The hub id, if available. +# +# @hub-name: The name of the hub. +# +# @info: Network information from slirp. +# +# Since: 11.1 +## +{ 'struct': 'UsernetInfo', + 'data': { + '*hub-id': 'int', + 'hub-name': 'str', + 'info': 'str' }, + 'if': 'CONFIG_SLIRP' } + +## +# @x-query-usernet: +# +# Query user-mode network stack connection states. +# +# Features: +# +# @unstable: This command is meant for debugging. +# +# Returns: list of user-mode network stack information. +# +# Since: 11.1 +# +# .. qmp-example:: +# +# -> { "execute": "x-query-usernet" } +# <- { "return": [ { "hub-id": 0, "hub-name": "vnet", +# "info": "..." } ] } +## +{ 'command': 'x-query-usernet', + 'returns': ['UsernetInfo'], + 'if': 'CONFIG_SLIRP', + 'features': [ 'unstable' ] } diff --git a/net/slirp.c b/net/slirp.c index XXXXXXX..XXXXXXX 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -XXX,XX +XXX,XX @@ #include "system/system.h" #include "qemu/cutils.h" #include "qapi/error.h" +#include "qapi/qapi-commands-net.h" #include "qobject/qdict.h" #include "util.h" #include "migration/register.h" @@ -XXX,XX +XXX,XX @@ static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp) return -1; } -void hmp_info_usernet(Monitor *mon, const QDict *qdict) +UsernetInfoList *qmp_x_query_usernet(Error **errp) { + UsernetInfoList *head = NULL, **tail = &head; SlirpState *s; QTAILQ_FOREACH(s, &slirp_stacks, entry) { + UsernetInfo *ui = g_new0(UsernetInfo, 1); int id; - bool got_hub_id = net_hub_id_for_client(&s->nc, &id) == 0; - char *info = slirp_connection_info(s->slirp); + + if (net_hub_id_for_client(&s->nc, &id) == 0) { + ui->has_hub_id = true; + ui->hub_id = id; + } + ui->hub_name = g_strdup(s->nc.name); + ui->info = slirp_connection_info(s->slirp); + + QAPI_LIST_APPEND(tail, ui); + } + + return head; +} + +void hmp_info_usernet(Monitor *mon, const QDict *qdict) +{ + g_autoptr(UsernetInfoList) list = NULL; + UsernetInfoList *entry; + + list = qmp_x_query_usernet(&error_abort); + for (entry = list; entry; entry = entry->next) { + UsernetInfo *ui = entry->value; monitor_printf(mon, "Hub %d (%s):\n%s", - got_hub_id ? id : -1, - s->nc.name, info); - g_free(info); + ui->has_hub_id ? (int)ui->hub_id : -1, + ui->hub_name, ui->info); } } -- 2.54.0
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- python/qemu/utils/__init__.py | 5 +++-- tests/functional/qemu_test/utils.py | 8 ++++++-- tests/vm/basevm.py | 13 ++++++++----- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/python/qemu/utils/__init__.py b/python/qemu/utils/__init__.py index XXXXXXX..XXXXXXX 100644 --- a/python/qemu/utils/__init__.py +++ b/python/qemu/utils/__init__.py @@ -XXX,XX +XXX,XX @@ def get_info_usernet_hostfwd_port(info_usernet_output: str) -> Optional[int]: """ Returns the port given to the hostfwd parameter via info usernet - :param info_usernet_output: output generated by hmp command "info usernet" + :param info_usernet_output: output generated by "info usernet" or + the "info" field from x-query-usernet :return: the port number allocated by the hostfwd option """ - for line in info_usernet_output.split('\r\n'): + for line in info_usernet_output.splitlines(): regex = r'TCP.HOST_FORWARD.*127\.0\.0\.1\s+(\d+)\s+10\.' match = re.search(regex, line) if match is not None: diff --git a/tests/functional/qemu_test/utils.py b/tests/functional/qemu_test/utils.py index XXXXXXX..XXXXXXX 100644 --- a/tests/functional/qemu_test/utils.py +++ b/tests/functional/qemu_test/utils.py @@ -XXX,XX +XXX,XX @@ def get_usernet_hostfwd_port(vm): - res = vm.cmd('human-monitor-command', command_line='info usernet') - return get_info_usernet_hostfwd_port(res) + res = vm.cmd('x-query-usernet') + for entry in res: + port = get_info_usernet_hostfwd_port(entry['info']) + if port is not None: + return port + return None def pow2ceil(x): """ diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index XXXXXXX..XXXXXXX 100644 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -XXX,XX +XXX,XX @@ def boot(self, img, extra_args=[]): self._guest = guest # Init console so we can start consuming the chars. self.console_init() - usernet_info = guest.cmd("human-monitor-command", - command_line="info usernet") - self.ssh_port = get_info_usernet_hostfwd_port(usernet_info) + res = guest.cmd("x-query-usernet") + for entry in res: + port = get_info_usernet_hostfwd_port(entry['info']) + if port is not None: + self.ssh_port = port + break if not self.ssh_port: - raise Exception("Cannot find ssh port from 'info usernet':\n%s" % \ - usernet_info) + raise Exception("Cannot find ssh port from" + " 'x-query-usernet': %s" % res) def console_init(self, timeout = None): if timeout == None: -- 2.54.0
Add an option to disable printing the timestamp in the reply. This may help tests that want to compare the output between runs. It's not use by this series after all, it could be excluded. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- qapi/qom.json | 5 ++- include/system/qtest.h | 3 +- system/qtest.c | 61 ++++++++++++++++++++++----- system/vl.c | 7 ++- qemu-options.hx | 1 + tests/qemu-iotests/iotests.py | 4 +- tests/qemu-iotests/tests/copy-before-write | 4 +- tests/qemu-iotests/tests/migrate-bitmaps-test | 4 +- 8 files changed, 70 insertions(+), 19 deletions(-) diff --git a/qapi/qom.json b/qapi/qom.json index XXXXXXX..XXXXXXX 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -XXX,XX +XXX,XX @@ # # @log: the path to a log file # +# @ts: if true, print timestamps in the log. Default true. +# # Since: 6.0 ## { 'struct': 'QtestProperties', 'data': { 'chardev': 'str', - '*log': 'str' } } + '*log': 'str', + '*ts': 'bool' } } ## # @RemoteObjectProperties: diff --git a/include/system/qtest.h b/include/system/qtest.h index XXXXXXX..XXXXXXX 100644 --- a/include/system/qtest.h +++ b/include/system/qtest.h @@ -XXX,XX +XXX,XX @@ void G_GNUC_PRINTF(2, 3) qtest_sendf(CharFrontend *chr, const char *fmt, ...); void qtest_set_command_cb(bool (*pc_cb)(CharFrontend *chr, gchar **words)); bool qtest_driver(void); -void qtest_server_init(const char *qtest_chrdev, const char *qtest_log, Error **errp); +void qtest_server_init(const char *qtest_chrdev, const char *qtest_log, + bool qtest_no_ts, Error **errp); void qtest_server_set_send_handler(void (*send)(void *, const char *), void *opaque); diff --git a/system/qtest.c b/system/qtest.c index XXXXXXX..XXXXXXX 100644 --- a/system/qtest.c +++ b/system/qtest.c @@ -XXX,XX +XXX,XX @@ struct QTest { Object parent; bool has_machine_link; + bool ts; char *chr_name; Chardev *chr; CharFrontend qtest_chr; @@ -XXX,XX +XXX,XX @@ static GString *inbuf; static int irq_levels[MAX_IRQ]; static GTimer *timer; static bool qtest_opened; +static bool qtest_ts = true; static void (*qtest_server_send)(void*, const char*); static void *qtest_server_send_opaque; @@ -XXX,XX +XXX,XX @@ static int hex2nib(char ch) } } -static void qtest_log_timestamp(void) +static void qtest_log_timestamp(const char c) { if (!qtest_log_fp || !qtest_opened) { return; } - fprintf(qtest_log_fp, "[S +" FMT_timeval "] ", g_timer_elapsed(timer, NULL)); + fprintf(qtest_log_fp, "[%c", c); + if (qtest_ts) { + fprintf(qtest_log_fp, " +" FMT_timeval, g_timer_elapsed(timer, NULL)); + } + fprintf(qtest_log_fp, "]"); } static void G_GNUC_PRINTF(1, 2) qtest_log_send(const char *fmt, ...) @@ -XXX,XX +XXX,XX @@ static void G_GNUC_PRINTF(1, 2) qtest_log_send(const char *fmt, ...) return; } - qtest_log_timestamp(); - + qtest_log_timestamp('S'); + fprintf(qtest_log_fp, " "); va_start(ap, fmt); vfprintf(qtest_log_fp, fmt, ap); va_end(ap); @@ -XXX,XX +XXX,XX @@ static void qtest_server_char_be_send(void *opaque, const char *str) static void qtest_send(CharFrontend *chr, const char *str) { - qtest_log_timestamp(); + if (qtest_log_fp) { + qtest_log_timestamp('S'); + fprintf(qtest_log_fp, " "); + } qtest_server_send(qtest_server_send_opaque, str); } @@ -XXX,XX +XXX,XX @@ static void qtest_process_command(CharFrontend *chr, gchar **words) if (qtest_log_fp) { int i; - fprintf(qtest_log_fp, "[R +" FMT_timeval "]", g_timer_elapsed(timer, NULL)); + qtest_log_timestamp('R'); for (i = 0; words[i]; i++) { fprintf(qtest_log_fp, " %s", words[i]); } @@ -XXX,XX +XXX,XX @@ static void qtest_event(void *opaque, QEMUChrEvent event) timer = g_timer_new(); qtest_opened = true; if (qtest_log_fp) { - fprintf(qtest_log_fp, "[I " FMT_timeval "] OPENED\n", g_timer_elapsed(timer, NULL)); + qtest_log_timestamp('I'); + fprintf(qtest_log_fp, " OPENED\n"); } break; case CHR_EVENT_CLOSED: @@ -XXX,XX +XXX,XX @@ static void qtest_event(void *opaque, QEMUChrEvent event) /* Ignore CLOSED events if we have already closed the log */ break; } - qtest_opened = false; if (qtest_log_fp) { - fprintf(qtest_log_fp, "[I +" FMT_timeval "] CLOSED\n", g_timer_elapsed(timer, NULL)); + qtest_log_timestamp('I'); + fprintf(qtest_log_fp, " CLOSED\n"); } + qtest_opened = false; g_clear_pointer(&timer, g_timer_destroy); break; default: @@ -XXX,XX +XXX,XX @@ static void qtest_event(void *opaque, QEMUChrEvent event) } } -void qtest_server_init(const char *qtest_chrdev, const char *qtest_log, Error **errp) +void qtest_server_init(const char *qtest_chrdev, const char *qtest_log, + bool no_ts, Error **errp) { ERRP_GUARD(); Chardev *chr; @@ -XXX,XX +XXX,XX @@ void qtest_server_init(const char *qtest_chrdev, const char *qtest_log, Error ** if (qtest_log) { object_property_set_str(qobj, "log", qtest_log, &error_abort); } + if (no_ts) { + object_property_set_bool(qobj, "ts", false, &error_abort); + } object_property_add_child(qdev_get_machine(), "qtest", qobj); user_creatable_complete(USER_CREATABLE(qobj), errp); if (*errp) { @@ -XXX,XX +XXX,XX @@ static bool qtest_server_start(QTest *q, Error **errp) qtest_log_fp = stderr; } + qtest_ts = q->ts; + if (!qemu_chr_fe_init(&q->qtest_chr, chr, errp)) { return false; } @@ -XXX,XX +XXX,XX @@ static char *qtest_get_log(Object *obj, Error **errp) return g_strdup(q->log); } +static bool qtest_get_ts(Object *obj, Error **errp) +{ + QTest *q = QTEST(obj); + + return q->ts; +} + +static void qtest_set_ts(Object *obj, bool value, Error **errp) +{ + QTest *q = QTEST(obj); + + q->ts = value; +} + static void qtest_set_chardev(Object *obj, const char *value, Error **errp) { QTest *q = QTEST(obj); @@ -XXX,XX +XXX,XX @@ static void qtest_class_init(ObjectClass *oc, const void *data) qtest_get_chardev, qtest_set_chardev); object_class_property_add_str(oc, "log", qtest_get_log, qtest_set_log); + object_class_property_add_bool(oc, "ts", + qtest_get_ts, qtest_set_ts); } static void qtest_finalize(Object *obj) @@ -XXX,XX +XXX,XX @@ static void qtest_finalize(Object *obj) object_unref(q->chr); } +static void qtest_init(Object *obj) +{ + QTest *q = QTEST(obj); + + q->ts = true; +} + static const TypeInfo qtest_info = { .name = TYPE_QTEST, .parent = TYPE_OBJECT, .class_init = qtest_class_init, + .instance_init = qtest_init, .instance_finalize = qtest_finalize, .instance_size = sizeof(QTest), .interfaces = (const InterfaceInfo[]) { diff --git a/system/vl.c b/system/vl.c index XXXXXXX..XXXXXXX 100644 --- a/system/vl.c +++ b/system/vl.c @@ -XXX,XX +XXX,XX @@ static const char *log_file; static bool list_data_dirs; static const char *qtest_chrdev; static const char *qtest_log; +static bool qtest_no_ts; static int has_defaults = 1; static int default_audio = 1; @@ -XXX,XX +XXX,XX @@ static bool object_create_late(const char *type) static void qemu_create_late_backends(void) { if (qtest_chrdev) { - qtest_server_init(qtest_chrdev, qtest_log, &error_fatal); + qtest_server_init(qtest_chrdev, qtest_log, qtest_no_ts, + &error_fatal); } net_init_clients(); @@ -XXX,XX +XXX,XX @@ void qemu_init(int argc, char **argv) case QEMU_OPTION_qtest_log: qtest_log = optarg; break; + case QEMU_OPTION_qtest_no_ts: + qtest_no_ts = true; + break; case QEMU_OPTION_sandbox: olist = qemu_find_opts("sandbox"); if (!olist) { diff --git a/qemu-options.hx b/qemu-options.hx index XXXXXXX..XXXXXXX 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -XXX,XX +XXX,XX @@ ERST HXCOMM Internal use DEF("qtest", HAS_ARG, QEMU_OPTION_qtest, "", QEMU_ARCH_ALL) DEF("qtest-log", HAS_ARG, QEMU_OPTION_qtest_log, "", QEMU_ARCH_ALL) +DEF("qtest-no-ts", 0, QEMU_OPTION_qtest_no_ts, "", QEMU_ARCH_ALL) #if defined(CONFIG_POSIX) && !defined(EMSCRIPTEN) DEF("run-with", HAS_ARG, QEMU_OPTION_run_with, diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -XXX,XX +XXX,XX @@ def filter_nbd_exports(output: str) -> str: return re.sub(r'((min|opt|max) block): [0-9]+', r'\1: XXX', output) def filter_qtest(output: str) -> str: - output = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', output) - output = re.sub(r'\n?\[I \+\d+\.\d+\] CLOSED\n?$', '', output) + output = re.sub(r'^\[I \+?\d+\.\d+\] OPENED\n', '', output) + output = re.sub(r'\n?\[I \+?\d+\.\d+\] CLOSED\n?$', '', output) return output Msg = TypeVar('Msg', Dict[str, Any], List[Any], str) diff --git a/tests/qemu-iotests/tests/copy-before-write b/tests/qemu-iotests/tests/copy-before-write index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/tests/copy-before-write +++ b/tests/qemu-iotests/tests/copy-before-write @@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 0 self.vm.shutdown() log = self.vm.get_log() - log = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', log) - log = re.sub(r'\[I \+\d+\.\d+\] CLOSED\n?$', '', log) + log = re.sub(r'^\[I \+?\d+\.\d+\] OPENED\n', '', log) + log = re.sub(r'\[I \+?\d+\.\d+\] CLOSED\n?$', '', log) log = iotests.filter_qemu_io(log) return log diff --git a/tests/qemu-iotests/tests/migrate-bitmaps-test b/tests/qemu-iotests/tests/migrate-bitmaps-test index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/tests/migrate-bitmaps-test +++ b/tests/qemu-iotests/tests/migrate-bitmaps-test @@ -XXX,XX +XXX,XX @@ class TestDirtyBitmapMigration(iotests.QMPTestCase): # catch 'Could not reopen qcow2 layer: Bitmap already exists' # possible error log = self.vm_b.get_log() - log = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', log) - log = re.sub(r'\[I \+\d+\.\d+\] CLOSED\n?$', '', log) + log = re.sub(r'^\[I \+?\d+\.\d+\] OPENED\n', '', log) + log = re.sub(r'\[I \+?\d+\.\d+\] CLOSED\n?$', '', log) self.assertEqual(log, '') # recreate vm_b, as we don't want -incoming option (this will lead -- 2.54.0
Convert the qemu-io command infrastructure to use QEMU's Error API (Error **errp) for error propagation instead of printing directly to stdout/stderr via printf/fprintf. The cfunc_t typedef, all ~35 command functions, the dispatcher chain (command/init_check_command/qemuio_command), and helper functions (parse_pattern, create_iovec, qemu_io_alloc_from_file) all gain an Error **errp parameter. Async completion callbacks (aio_read_done, aio_write_done, aio_discard_done) use error_report() since they have no Error path back to the caller. Update tests: - error_report_err() prepends qemu-io: prefix - copy-before-write: check the HMP return value, rather than stdio - other tests: update to check JSON {"return": "Error: error text"} Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- include/qemu-io.h | 4 +- block/monitor/block-hmp-cmds.c | 2 +- qemu-io-cmds.c | 426 +++++++++++++++-------------- qemu-io.c | 17 +- tests/qemu-iotests/004.out | 20 +- tests/qemu-iotests/021.out | 60 ++-- tests/qemu-iotests/060.out | 44 ++- tests/qemu-iotests/071.out | 10 +- tests/qemu-iotests/072.out | 2 +- tests/qemu-iotests/080.out | 4 +- tests/qemu-iotests/089.out | 4 +- tests/qemu-iotests/114.out | 2 +- tests/qemu-iotests/134.out | 2 +- tests/qemu-iotests/137.out | 2 +- tests/qemu-iotests/171 | 2 +- tests/qemu-iotests/171.out | 68 ++--- tests/qemu-iotests/214.out | 2 +- tests/qemu-iotests/220.out | 2 +- tests/qemu-iotests/244.out | 12 +- tests/qemu-iotests/249.out | 6 +- tests/qemu-iotests/271.out | 14 +- tests/qemu-iotests/tests/copy-before-write | 66 +++-- 22 files changed, 404 insertions(+), 367 deletions(-) diff --git a/include/qemu-io.h b/include/qemu-io.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu-io.h +++ b/include/qemu-io.h @@ -XXX,XX +XXX,XX @@ * Operate on @blk using @argc/@argv as the command's arguments, and * return 0 on success or negative errno on failure. */ -typedef int (*cfunc_t)(BlockBackend *blk, int argc, char **argv); +typedef int (*cfunc_t)(BlockBackend *blk, int argc, char **argv, Error **errp); typedef void (*helpfunc_t)(void); @@ -XXX,XX +XXX,XX @@ typedef struct cmdinfo { extern bool qemuio_misalign; -int qemuio_command(BlockBackend *blk, const char *cmd); +int qemuio_command(BlockBackend *blk, const char *cmd, Error **errp); void qemuio_add_command(const cmdinfo_t *ci); void qemuio_command_usage(const cmdinfo_t *ci); diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/block/monitor/block-hmp-cmds.c +++ b/block/monitor/block-hmp-cmds.c @@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict) * extended, possibly resulting in a read-only guest device keeping write * permissions. Ugly, but it appears to be the lesser evil. */ - qemuio_command(blk, command); + qemuio_command(blk, command, &err); fail: blk_unref(local_blk); diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -XXX,XX +XXX,XX @@ void qemuio_command_usage(const cmdinfo_t *ci) printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline); } -static int init_check_command(BlockBackend *blk, const cmdinfo_t *ct) +static int init_check_command(BlockBackend *blk, const cmdinfo_t *ct, + Error **errp) { if (ct->flags & CMD_FLAG_GLOBAL) { return 1; } if (!(ct->flags & CMD_NOFILE_OK) && !blk) { - fprintf(stderr, "no file open, try 'help open'\n"); + error_setg(errp, "no file open, try 'help open'"); return 0; } return 1; } static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc, - char **argv) + char **argv, Error **errp) { char *cmd = argv[0]; - if (!init_check_command(blk, ct)) { + if (!init_check_command(blk, ct, errp)) { return -EINVAL; } if (argc - 1 < ct->argmin || (ct->argmax != -1 && argc - 1 > ct->argmax)) { if (ct->argmax == -1) { - fprintf(stderr, - "bad argument count %d to %s, expected at least %d arguments\n", - argc-1, cmd, ct->argmin); + error_setg(errp, + "bad argument count %d to %s," + " expected at least %d arguments", + argc - 1, cmd, ct->argmin); } else if (ct->argmin == ct->argmax) { - fprintf(stderr, - "bad argument count %d to %s, expected %d arguments\n", - argc-1, cmd, ct->argmin); + error_setg(errp, + "bad argument count %d to %s, expected %d arguments", + argc - 1, cmd, ct->argmin); } else { - fprintf(stderr, - "bad argument count %d to %s, expected between %d and %d arguments\n", - argc-1, cmd, ct->argmin, ct->argmax); + error_setg(errp, + "bad argument count %d to %s," + " expected between %d and %d arguments", + argc - 1, cmd, ct->argmin, ct->argmax); } return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc, if (ct->perm & ~orig_perm) { uint64_t new_perm; - Error *local_err = NULL; int ret; new_perm = orig_perm | ct->perm; - ret = blk_set_perm(blk, new_perm, orig_shared_perm, &local_err); + ret = blk_set_perm(blk, new_perm, orig_shared_perm, errp); if (ret < 0) { - error_report_err(local_err); return ret; } } } qemu_reset_optind(); - return ct->cfunc(blk, argc, argv); + return ct->cfunc(blk, argc, argv, errp); } static const cmdinfo_t *find_command(const char *cmd) @@ -XXX,XX +XXX,XX @@ static int64_t cvtnum(const char *s) return value; } -static void print_cvtnum_err(int64_t rc, const char *arg) +static void set_cvtnum_err(int64_t rc, const char *arg, Error **errp) { switch (rc) { case -EINVAL: - printf("Parsing error: non-numeric argument," - " or extraneous/unrecognized suffix -- %s\n", arg); + error_setg(errp, "Parsing error: non-numeric argument," + " or extraneous/unrecognized suffix -- %s", arg); break; case -ERANGE: - printf("Parsing error: argument too large -- %s\n", arg); + error_setg(errp, "Parsing error: argument too large -- %s", arg); break; default: - printf("Parsing error: %s\n", arg); + error_setg(errp, "Parsing error: %s", arg); } } @@ -XXX,XX +XXX,XX @@ static void timestr(struct timespec *tv, char *ts, size_t size, int format) * Because the pattern is used as an argument to memset it must evaluate * to an unsigned integer that fits into a single byte. */ -static int parse_pattern(const char *arg) +static int parse_pattern(const char *arg, Error **errp) { char *endptr = NULL; long pattern; pattern = strtol(arg, &endptr, 0); if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') { - printf("%s is not a valid pattern byte\n", arg); + error_setg(errp, "%s is not a valid pattern byte", arg); return -1; } @@ -XXX,XX +XXX,XX @@ static void qemu_io_free(BlockBackend *blk, void *p, size_t len, * NULL on error */ static void *qemu_io_alloc_from_file(BlockBackend *blk, size_t len, - const char *file_name, bool register_buf) + const char *file_name, bool register_buf, + Error **errp) { size_t alloc_len = len + (qemuio_misalign ? MISALIGN_OFFSET : 0); char *alloc_buf, *buf, *end; @@ -XXX,XX +XXX,XX @@ static void *qemu_io_alloc_from_file(BlockBackend *blk, size_t len, int pattern_len; if (!f) { - perror(file_name); + error_setg_errno(errp, errno, "%s", file_name); return NULL; } @@ -XXX,XX +XXX,XX @@ static void *qemu_io_alloc_from_file(BlockBackend *blk, size_t len, pattern_len = fread(buf, 1, len, f); if (ferror(f)) { - perror(file_name); + error_setg_errno(errp, errno, "%s", file_name); goto error; } if (pattern_len == 0) { - fprintf(stderr, "%s: file is empty\n", file_name); + error_setg(errp, "%s: file is empty", file_name); goto error; } @@ -XXX,XX +XXX,XX @@ static void print_report(const char *op, struct timespec *t, int64_t offset, */ static void * create_iovec(BlockBackend *blk, QEMUIOVector *qiov, char **argv, int nr_iov, - int pattern, bool register_buf) + int pattern, bool register_buf, Error **errp) { size_t *sizes = g_new0(size_t, nr_iov); size_t count = 0; @@ -XXX,XX +XXX,XX @@ create_iovec(BlockBackend *blk, QEMUIOVector *qiov, char **argv, int nr_iov, len = cvtnum(arg); if (len < 0) { - print_cvtnum_err(len, arg); + set_cvtnum_err(len, arg, errp); goto fail; } if (len > BDRV_REQUEST_MAX_BYTES) { - printf("Argument '%s' exceeds maximum size %" PRIu64 "\n", arg, - (uint64_t)BDRV_REQUEST_MAX_BYTES); + error_setg(errp, "Argument '%s' exceeds maximum size %" PRIu64, + arg, (uint64_t)BDRV_REQUEST_MAX_BYTES); goto fail; } if (count > BDRV_REQUEST_MAX_BYTES - len) { - printf("The total number of bytes exceed the maximum size %" PRIu64 - "\n", (uint64_t)BDRV_REQUEST_MAX_BYTES); + error_setg(errp, + "The total number of bytes exceed the maximum size %" + PRIu64, (uint64_t)BDRV_REQUEST_MAX_BYTES); goto fail; } @@ -XXX,XX +XXX,XX @@ static void read_help(void) "\n"); } -static int read_f(BlockBackend *blk, int argc, char **argv); +static int read_f(BlockBackend *blk, int argc, char **argv, Error **errp); static const cmdinfo_t read_cmd = { .name = "read", @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t read_cmd = { .help = read_help, }; -static int read_f(BlockBackend *blk, int argc, char **argv) +static int read_f(BlockBackend *blk, int argc, char **argv, Error **errp) { struct timespec t1, t2; bool Cflag = false, qflag = false, vflag = false; @@ -XXX,XX +XXX,XX @@ static int read_f(BlockBackend *blk, int argc, char **argv) lflag = true; pattern_count = cvtnum(optarg); if (pattern_count < 0) { - print_cvtnum_err(pattern_count, optarg); + set_cvtnum_err(pattern_count, optarg, errp); return pattern_count; } break; @@ -XXX,XX +XXX,XX @@ static int read_f(BlockBackend *blk, int argc, char **argv) break; case 'P': Pflag = true; - pattern = parse_pattern(optarg); + pattern = parse_pattern(optarg, errp); if (pattern < 0) { return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int read_f(BlockBackend *blk, int argc, char **argv) sflag = true; pattern_offset = cvtnum(optarg); if (pattern_offset < 0) { - print_cvtnum_err(pattern_offset, optarg); + set_cvtnum_err(pattern_offset, optarg, errp); return pattern_offset; } break; @@ -XXX,XX +XXX,XX @@ static int read_f(BlockBackend *blk, int argc, char **argv) offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } optind++; count = cvtnum(argv[optind]); if (count < 0) { - print_cvtnum_err(count, argv[optind]); + set_cvtnum_err(count, argv[optind], errp); return count; } else if (count > BDRV_REQUEST_MAX_BYTES) { - printf("length cannot exceed %" PRIu64 ", given %s\n", - (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]); + error_setg(errp, "length cannot exceed %" PRIu64 ", given %s", + (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]); return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int read_f(BlockBackend *blk, int argc, char **argv) } if ((pattern_count < 0) || (pattern_count + pattern_offset > count)) { - printf("pattern verification range exceeds end of read data\n"); + error_setg(errp, "pattern verification range exceeds end of read data"); return -EINVAL; } if (bflag) { if (!QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)) { - printf("%" PRId64 " is not a sector-aligned value for 'offset'\n", - offset); + error_setg(errp, + "%" PRId64 " is not a sector-aligned value for 'offset'", + offset); return -EINVAL; } if (!QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE)) { - printf("%"PRId64" is not a sector-aligned value for 'count'\n", - count); + error_setg(errp, + "%" PRId64 " is not a sector-aligned value for 'count'", + count); return -EINVAL; } if (flags & BDRV_REQ_REGISTERED_BUF) { - printf("I/O buffer registration is not supported when reading " - "from vmstate\n"); + error_setg(errp, "I/O buffer registration is not supported when" + " reading from vmstate"); return -EINVAL; } } @@ -XXX,XX +XXX,XX @@ static int read_f(BlockBackend *blk, int argc, char **argv) clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { - printf("read failed: %s\n", strerror(-ret)); + error_setg(errp, "read failed: %s", strerror(-ret)); goto out; } cnt = ret; @@ -XXX,XX +XXX,XX @@ static int read_f(BlockBackend *blk, int argc, char **argv) void *cmp_buf = g_malloc(pattern_count); memset(cmp_buf, pattern, pattern_count); if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) { - printf("Pattern verification failed at offset %" - PRId64 ", %"PRId64" bytes\n", - offset + pattern_offset, pattern_count); + error_setg(errp, "Pattern verification failed at offset %" + PRId64 ", %" PRId64 " bytes", + offset + pattern_offset, pattern_count); ret = -EINVAL; } g_free(cmp_buf); @@ -XXX,XX +XXX,XX @@ static void readv_help(void) "\n"); } -static int readv_f(BlockBackend *blk, int argc, char **argv); +static int readv_f(BlockBackend *blk, int argc, char **argv, Error **errp); static const cmdinfo_t readv_cmd = { .name = "readv", @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t readv_cmd = { .help = readv_help, }; -static int readv_f(BlockBackend *blk, int argc, char **argv) +static int readv_f(BlockBackend *blk, int argc, char **argv, Error **errp) { struct timespec t1, t2; bool Cflag = false, qflag = false, vflag = false; @@ -XXX,XX +XXX,XX @@ static int readv_f(BlockBackend *blk, int argc, char **argv) break; case 'P': Pflag = true; - pattern = parse_pattern(optarg); + pattern = parse_pattern(optarg, errp); if (pattern < 0) { return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int readv_f(BlockBackend *blk, int argc, char **argv) offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } optind++; nr_iov = argc - optind; buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, 0xab, - flags & BDRV_REQ_REGISTERED_BUF); + flags & BDRV_REQ_REGISTERED_BUF, errp); if (buf == NULL) { return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int readv_f(BlockBackend *blk, int argc, char **argv) clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { - printf("readv failed: %s\n", strerror(-ret)); + error_setg(errp, "readv failed: %s", strerror(-ret)); goto out; } cnt = ret; @@ -XXX,XX +XXX,XX @@ static int readv_f(BlockBackend *blk, int argc, char **argv) void *cmp_buf = g_malloc(qiov.size); memset(cmp_buf, pattern, qiov.size); if (memcmp(buf, cmp_buf, qiov.size)) { - printf("Pattern verification failed at offset %" - PRId64 ", %zu bytes\n", offset, qiov.size); + error_setg(errp, "Pattern verification failed at offset %" + PRId64 ", %zu bytes", offset, qiov.size); ret = -EINVAL; } g_free(cmp_buf); @@ -XXX,XX +XXX,XX @@ static void write_help(void) "\n"); } -static int write_f(BlockBackend *blk, int argc, char **argv); +static int write_f(BlockBackend *blk, int argc, char **argv, Error **errp); static const cmdinfo_t write_cmd = { .name = "write", @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t write_cmd = { .help = write_help, }; -static int write_f(BlockBackend *blk, int argc, char **argv) +static int write_f(BlockBackend *blk, int argc, char **argv, Error **errp) { struct timespec t1, t2; bool Cflag = false, qflag = false, bflag = false; @@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv) break; case 'P': Pflag = true; - pattern = parse_pattern(optarg); + pattern = parse_pattern(optarg, errp); if (pattern < 0) { return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv) } if (bflag && zflag) { - printf("-b and -z cannot be specified at the same time\n"); + error_setg(errp, "-b and -z cannot be specified at the same time"); return -EINVAL; } if ((flags & BDRV_REQ_FUA) && (bflag || cflag)) { - printf("-f and -b or -c cannot be specified at the same time\n"); + error_setg(errp, + "-f and -b or -c cannot be specified at the same time"); return -EINVAL; } if ((flags & BDRV_REQ_NO_FALLBACK) && !zflag) { - printf("-n requires -z to be specified\n"); + error_setg(errp, "-n requires -z to be specified"); return -EINVAL; } if ((flags & BDRV_REQ_MAY_UNMAP) && !zflag) { - printf("-u requires -z to be specified\n"); + error_setg(errp, "-u requires -z to be specified"); return -EINVAL; } if (zflag + Pflag + sflag > 1) { - printf("Only one of -z, -P, and -s " - "can be specified at the same time\n"); + error_setg(errp, "Only one of -z, -P, and -s " + "can be specified at the same time"); return -EINVAL; } offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } optind++; count = cvtnum(argv[optind]); if (count < 0) { - print_cvtnum_err(count, argv[optind]); + set_cvtnum_err(count, argv[optind], errp); return count; } else if (count > BDRV_REQUEST_MAX_BYTES && !(flags & BDRV_REQ_NO_FALLBACK)) { - printf("length cannot exceed %" PRIu64 " without -n, given %s\n", - (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]); + error_setg(errp, + "length cannot exceed %" PRIu64 " without -n, given %s", + (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]); return -EINVAL; } if (bflag || cflag) { if (!QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)) { - printf("%" PRId64 " is not a sector-aligned value for 'offset'\n", - offset); + error_setg(errp, + "%" PRId64 " is not a sector-aligned value for 'offset'", + offset); return -EINVAL; } if (!QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE)) { - printf("%"PRId64" is not a sector-aligned value for 'count'\n", - count); + error_setg(errp, + "%" PRId64 " is not a sector-aligned value for 'count'", + count); return -EINVAL; } } if (zflag) { if (flags & BDRV_REQ_REGISTERED_BUF) { - printf("cannot combine zero write with registered I/O buffer\n"); + error_setg(errp, + "cannot combine zero write with registered I/O buffer"); return -EINVAL; } } else { if (sflag) { buf = qemu_io_alloc_from_file(blk, count, file_name, - flags & BDRV_REQ_REGISTERED_BUF); + flags & BDRV_REQ_REGISTERED_BUF, + errp); if (!buf) { return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv) clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { - printf("write failed: %s\n", strerror(-ret)); + error_setg(errp, "write failed: %s", strerror(-ret)); goto out; } cnt = ret; @@ -XXX,XX +XXX,XX @@ writev_help(void) "\n"); } -static int writev_f(BlockBackend *blk, int argc, char **argv); +static int writev_f(BlockBackend *blk, int argc, char **argv, Error **errp); static const cmdinfo_t writev_cmd = { .name = "writev", @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t writev_cmd = { .help = writev_help, }; -static int writev_f(BlockBackend *blk, int argc, char **argv) +static int writev_f(BlockBackend *blk, int argc, char **argv, Error **errp) { struct timespec t1, t2; bool Cflag = false, qflag = false; @@ -XXX,XX +XXX,XX @@ static int writev_f(BlockBackend *blk, int argc, char **argv) flags |= BDRV_REQ_REGISTERED_BUF; break; case 'P': - pattern = parse_pattern(optarg); + pattern = parse_pattern(optarg, errp); if (pattern < 0) { return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int writev_f(BlockBackend *blk, int argc, char **argv) offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } optind++; nr_iov = argc - optind; buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern, - flags & BDRV_REQ_REGISTERED_BUF); + flags & BDRV_REQ_REGISTERED_BUF, errp); if (buf == NULL) { return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int writev_f(BlockBackend *blk, int argc, char **argv) clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { - printf("writev failed: %s\n", strerror(-ret)); + error_setg(errp, "writev failed: %s", strerror(-ret)); goto out; } cnt = ret; @@ -XXX,XX +XXX,XX @@ static void aio_write_done(void *opaque, int ret) if (ret < 0) { - printf("aio_write failed: %s\n", strerror(-ret)); + error_report("aio_write failed: %s", strerror(-ret)); block_acct_failed(blk_get_stats(ctx->blk), &ctx->acct); goto out; } @@ -XXX,XX +XXX,XX @@ static void aio_read_done(void *opaque, int ret) clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { - printf("readv failed: %s\n", strerror(-ret)); + error_report("readv failed: %s", strerror(-ret)); block_acct_failed(blk_get_stats(ctx->blk), &ctx->acct); goto out; } @@ -XXX,XX +XXX,XX @@ static void aio_read_done(void *opaque, int ret) memset(cmp_buf, ctx->pattern, ctx->qiov.size); if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) { - printf("Pattern verification failed at offset %" - PRId64 ", %zu bytes\n", ctx->offset, ctx->qiov.size); + error_report("Pattern verification failed at offset %" + PRId64 ", %zu bytes", ctx->offset, ctx->qiov.size); } g_free(cmp_buf); } @@ -XXX,XX +XXX,XX @@ static void aio_read_help(void) "\n"); } -static int aio_read_f(BlockBackend *blk, int argc, char **argv); +static int aio_read_f(BlockBackend *blk, int argc, char **argv, Error **errp); static const cmdinfo_t aio_read_cmd = { .name = "aio_read", @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t aio_read_cmd = { .help = aio_read_help, }; -static int aio_read_f(BlockBackend *blk, int argc, char **argv) +static int aio_read_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int nr_iov, c; struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); @@ -XXX,XX +XXX,XX @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv) break; case 'P': ctx->Pflag = true; - ctx->pattern = parse_pattern(optarg); + ctx->pattern = parse_pattern(optarg, errp); if (ctx->pattern < 0) { g_free(ctx); return -EINVAL; @@ -XXX,XX +XXX,XX @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv) ctx->offset = cvtnum(argv[optind]); if (ctx->offset < 0) { int ret = ctx->offset; - print_cvtnum_err(ret, argv[optind]); + set_cvtnum_err(ret, argv[optind], errp); g_free(ctx); return ret; } @@ -XXX,XX +XXX,XX @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv) nr_iov = argc - optind; ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, 0xab, - ctx->flags & BDRV_REQ_REGISTERED_BUF); + ctx->flags & BDRV_REQ_REGISTERED_BUF, errp); if (ctx->buf == NULL) { block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_READ); g_free(ctx); @@ -XXX,XX +XXX,XX @@ static void aio_write_help(void) "\n"); } -static int aio_write_f(BlockBackend *blk, int argc, char **argv); +static int aio_write_f(BlockBackend *blk, int argc, char **argv, Error **errp); static const cmdinfo_t aio_write_cmd = { .name = "aio_write", @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t aio_write_cmd = { .help = aio_write_help, }; -static int aio_write_f(BlockBackend *blk, int argc, char **argv) +static int aio_write_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int nr_iov, c; int pattern = 0xcd; @@ -XXX,XX +XXX,XX @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) ctx->flags |= BDRV_REQ_MAY_UNMAP; break; case 'P': - pattern = parse_pattern(optarg); + pattern = parse_pattern(optarg, errp); if (pattern < 0) { g_free(ctx); return -EINVAL; @@ -XXX,XX +XXX,XX @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) } if (ctx->zflag && optind != argc - 2) { - printf("-z supports only a single length parameter\n"); + error_setg(errp, "-z supports only a single length parameter"); g_free(ctx); return -EINVAL; } if ((ctx->flags & BDRV_REQ_MAY_UNMAP) && !ctx->zflag) { - printf("-u requires -z to be specified\n"); + error_setg(errp, "-u requires -z to be specified"); g_free(ctx); return -EINVAL; } if (ctx->zflag && ctx->Pflag) { - printf("-z and -P cannot be specified at the same time\n"); + error_setg(errp, "-z and -P cannot be specified at the same time"); g_free(ctx); return -EINVAL; } if (ctx->zflag && (ctx->flags & BDRV_REQ_REGISTERED_BUF)) { - printf("cannot combine zero write with registered I/O buffer\n"); + error_setg(errp, + "cannot combine zero write with registered I/O buffer"); g_free(ctx); return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) ctx->offset = cvtnum(argv[optind]); if (ctx->offset < 0) { int ret = ctx->offset; - print_cvtnum_err(ret, argv[optind]); + set_cvtnum_err(ret, argv[optind], errp); g_free(ctx); return ret; } @@ -XXX,XX +XXX,XX @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) if (ctx->zflag) { int64_t count = cvtnum(argv[optind]); if (count < 0) { - print_cvtnum_err(count, argv[optind]); + set_cvtnum_err(count, argv[optind], errp); g_free(ctx); return count; } @@ -XXX,XX +XXX,XX @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) } else { nr_iov = argc - optind; ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, - pattern, ctx->flags & BDRV_REQ_REGISTERED_BUF); + pattern, + ctx->flags & BDRV_REQ_REGISTERED_BUF, errp); if (ctx->buf == NULL) { block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_WRITE); g_free(ctx); @@ -XXX,XX +XXX,XX @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) return 0; } -static int aio_flush_f(BlockBackend *blk, int argc, char **argv) +static int aio_flush_f(BlockBackend *blk, int argc, char **argv, Error **errp) { BlockAcctCookie cookie; block_acct_start(blk_get_stats(blk), &cookie, 0, BLOCK_ACCT_FLUSH); @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t aio_flush_cmd = { .oneline = "completes all outstanding aio requests" }; -static int flush_f(BlockBackend *blk, int argc, char **argv) +static int flush_f(BlockBackend *blk, int argc, char **argv, Error **errp) { return blk_flush(blk); } @@ -XXX,XX +XXX,XX @@ static inline int64_t tosector(int64_t bytes) return bytes >> BDRV_SECTOR_BITS; } -static int zone_report_f(BlockBackend *blk, int argc, char **argv) +static int zone_report_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int ret; int64_t offset; @@ -XXX,XX +XXX,XX @@ static int zone_report_f(BlockBackend *blk, int argc, char **argv) ++optind; offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } ++optind; val = cvtnum(argv[optind]); if (val < 0) { - print_cvtnum_err(val, argv[optind]); + set_cvtnum_err(val, argv[optind], errp); return val; } if (val > UINT_MAX) { - printf("Number of zones must be less than 2^32\n"); + error_setg(errp, "Number of zones must be less than 2^32"); return -ERANGE; } nr_zones = val; @@ -XXX,XX +XXX,XX @@ static int zone_report_f(BlockBackend *blk, int argc, char **argv) zones = g_new(BlockZoneDescriptor, nr_zones); ret = blk_zone_report(blk, offset, &nr_zones, zones); if (ret < 0) { - printf("zone report failed: %s\n", strerror(-ret)); + error_setg(errp, "zone report failed: %s", strerror(-ret)); } else { for (int i = 0; i < nr_zones; ++i) { printf("start: 0x%" PRIx64 ", len 0x%" PRIx64 ", " @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t zone_report_cmd = { .oneline = "report zone information", }; -static int zone_open_f(BlockBackend *blk, int argc, char **argv) +static int zone_open_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int ret; int64_t offset, len; ++optind; offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } ++optind; len = cvtnum(argv[optind]); if (len < 0) { - print_cvtnum_err(len, argv[optind]); + set_cvtnum_err(len, argv[optind], errp); return len; } ret = blk_zone_mgmt(blk, BLK_ZO_OPEN, offset, len); if (ret < 0) { - printf("zone open failed: %s\n", strerror(-ret)); + error_setg(errp, "zone open failed: %s", strerror(-ret)); } return ret; } @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t zone_open_cmd = { .oneline = "explicit open a range of zones in zone block device", }; -static int zone_close_f(BlockBackend *blk, int argc, char **argv) +static int zone_close_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int ret; int64_t offset, len; ++optind; offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } ++optind; len = cvtnum(argv[optind]); if (len < 0) { - print_cvtnum_err(len, argv[optind]); + set_cvtnum_err(len, argv[optind], errp); return len; } ret = blk_zone_mgmt(blk, BLK_ZO_CLOSE, offset, len); if (ret < 0) { - printf("zone close failed: %s\n", strerror(-ret)); + error_setg(errp, "zone close failed: %s", strerror(-ret)); } return ret; } @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t zone_close_cmd = { .oneline = "close a range of zones in zone block device", }; -static int zone_finish_f(BlockBackend *blk, int argc, char **argv) +static int zone_finish_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int ret; int64_t offset, len; ++optind; offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } ++optind; len = cvtnum(argv[optind]); if (len < 0) { - print_cvtnum_err(len, argv[optind]); + set_cvtnum_err(len, argv[optind], errp); return len; } ret = blk_zone_mgmt(blk, BLK_ZO_FINISH, offset, len); if (ret < 0) { - printf("zone finish failed: %s\n", strerror(-ret)); + error_setg(errp, "zone finish failed: %s", strerror(-ret)); } return ret; } @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t zone_finish_cmd = { .oneline = "finish a range of zones in zone block device", }; -static int zone_reset_f(BlockBackend *blk, int argc, char **argv) +static int zone_reset_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int ret; int64_t offset, len; ++optind; offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } ++optind; len = cvtnum(argv[optind]); if (len < 0) { - print_cvtnum_err(len, argv[optind]); + set_cvtnum_err(len, argv[optind], errp); return len; } ret = blk_zone_mgmt(blk, BLK_ZO_RESET, offset, len); if (ret < 0) { - printf("zone reset failed: %s\n", strerror(-ret)); + error_setg(errp, "zone reset failed: %s", strerror(-ret)); } return ret; } @@ -XXX,XX +XXX,XX @@ static int do_aio_zone_append(BlockBackend *blk, QEMUIOVector *qiov, return async_ret < 0 ? async_ret : 1; } -static int zone_append_f(BlockBackend *blk, int argc, char **argv) +static int zone_append_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int ret; bool pflag = false; @@ -XXX,XX +XXX,XX @@ static int zone_append_f(BlockBackend *blk, int argc, char **argv) offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } optind++; nr_iov = argc - optind; buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern, - flags & BDRV_REQ_REGISTERED_BUF); + flags & BDRV_REQ_REGISTERED_BUF, errp); if (buf == NULL) { return -EINVAL; } ret = do_aio_zone_append(blk, &qiov, &offset, flags, &total); if (ret < 0) { - printf("zone append failed: %s\n", strerror(-ret)); + error_setg(errp, "zone append failed: %s", strerror(-ret)); goto out; } @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t zone_append_cmd = { .oneline = "append write a number of bytes at a specified offset", }; -static int truncate_f(BlockBackend *blk, int argc, char **argv); +static int truncate_f(BlockBackend *blk, int argc, char **argv, Error **errp); static const cmdinfo_t truncate_cmd = { .name = "truncate", .altname = "t", @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t truncate_cmd = { .oneline = "truncates the current file at the given offset", }; -static int truncate_f(BlockBackend *blk, int argc, char **argv) +static int truncate_f(BlockBackend *blk, int argc, char **argv, Error **errp) { - Error *local_err = NULL; int64_t offset; int c, ret; PreallocMode prealloc = PREALLOC_MODE_OFF; @@ -XXX,XX +XXX,XX @@ static int truncate_f(BlockBackend *blk, int argc, char **argv) prealloc = qapi_enum_parse(&PreallocMode_lookup, optarg, PREALLOC_MODE__MAX, NULL); if (prealloc == PREALLOC_MODE__MAX) { - error_report("Invalid preallocation mode '%s'", optarg); + error_setg(errp, "Invalid preallocation mode '%s'", optarg); return -EINVAL; } break; @@ -XXX,XX +XXX,XX @@ static int truncate_f(BlockBackend *blk, int argc, char **argv) offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[1]); + set_cvtnum_err(offset, argv[1], errp); return offset; } @@ -XXX,XX +XXX,XX @@ static int truncate_f(BlockBackend *blk, int argc, char **argv) * exact=true. It is better to err on the "emit more errors" side * than to be overly permissive. */ - ret = blk_truncate(blk, offset, false, prealloc, 0, &local_err); + ret = blk_truncate(blk, offset, false, prealloc, 0, errp); if (ret < 0) { - error_report_err(local_err); return ret; } return 0; } -static int length_f(BlockBackend *blk, int argc, char **argv) +static int length_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int64_t size; char s1[64]; size = blk_getlength(blk); if (size < 0) { - printf("getlength: %s\n", strerror(-size)); + error_setg(errp, "getlength: %s", strerror(-size)); return size; } @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t length_cmd = { }; -static int info_f(BlockBackend *blk, int argc, char **argv) +static int info_f(BlockBackend *blk, int argc, char **argv, Error **errp) { BlockDriverState *bs = blk_bs(blk); BlockDriverInfo bdi; ImageInfoSpecific *spec_info; - Error *local_err = NULL; char s1[64], s2[64]; int ret; @@ -XXX,XX +XXX,XX @@ static int info_f(BlockBackend *blk, int argc, char **argv) printf("cluster size: %s\n", s1); printf("vm state offset: %s\n", s2); - spec_info = bdrv_get_specific_info(bs, &local_err); - if (local_err) { - error_report_err(local_err); - return -EIO; + { + Error *local_err = NULL; + spec_info = bdrv_get_specific_info(bs, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return -EIO; + } } if (spec_info) { bdrv_image_info_specific_dump(spec_info, @@ -XXX,XX +XXX,XX @@ static void discard_help(void) "\n"); } -static int discard_f(BlockBackend *blk, int argc, char **argv); +static int discard_f(BlockBackend *blk, int argc, char **argv, Error **errp); static const cmdinfo_t discard_cmd = { .name = "discard", @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t discard_cmd = { .help = discard_help, }; -static int discard_f(BlockBackend *blk, int argc, char **argv) +static int discard_f(BlockBackend *blk, int argc, char **argv, Error **errp) { struct timespec t1, t2; bool Cflag = false, qflag = false; @@ -XXX,XX +XXX,XX @@ static int discard_f(BlockBackend *blk, int argc, char **argv) offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } optind++; bytes = cvtnum(argv[optind]); if (bytes < 0) { - print_cvtnum_err(bytes, argv[optind]); + set_cvtnum_err(bytes, argv[optind], errp); return bytes; } else if (bytes > BDRV_REQUEST_MAX_BYTES) { - printf("length cannot exceed %"PRIu64", given %s\n", - (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]); + error_setg(errp, "length cannot exceed %" PRIu64 ", given %s", + (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]); return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int discard_f(BlockBackend *blk, int argc, char **argv) clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { - printf("discard failed: %s\n", strerror(-ret)); + error_setg(errp, "discard failed: %s", strerror(-ret)); return ret; } @@ -XXX,XX +XXX,XX @@ static void aio_discard_help(void) "\n"); } -static int aio_discard_f(BlockBackend *blk, int argc, char **argv); +static int aio_discard_f(BlockBackend *blk, int argc, char **argv, + Error **errp); static const cmdinfo_t aio_discard_cmd = { .name = "aio_discard", @@ -XXX,XX +XXX,XX @@ static void aio_discard_done(void *opaque, int ret) clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { - printf("aio_discard failed: %s\n", strerror(-ret)); + error_report("aio_discard failed: %s", strerror(-ret)); block_acct_failed(blk_get_stats(ctx->blk), &ctx->acct); goto out; } @@ -XXX,XX +XXX,XX @@ out: g_free(ctx); } -static int aio_discard_f(BlockBackend *blk, int argc, char **argv) +static int aio_discard_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int c, ret; int64_t count; @@ -XXX,XX +XXX,XX @@ static int aio_discard_f(BlockBackend *blk, int argc, char **argv) ctx->offset = cvtnum(argv[optind]); if (ctx->offset < 0) { ret = ctx->offset; - print_cvtnum_err(ret, argv[optind]); + set_cvtnum_err(ret, argv[optind], errp); g_free(ctx); return ret; } @@ -XXX,XX +XXX,XX @@ static int aio_discard_f(BlockBackend *blk, int argc, char **argv) count = cvtnum(argv[optind]); if (count < 0) { - print_cvtnum_err(count, argv[optind]); + set_cvtnum_err(count, argv[optind], errp); g_free(ctx); return count; } @@ -XXX,XX +XXX,XX @@ static int aio_discard_f(BlockBackend *blk, int argc, char **argv) return 0; } -static int alloc_f(BlockBackend *blk, int argc, char **argv) +static int alloc_f(BlockBackend *blk, int argc, char **argv, Error **errp) { BlockDriverState *bs = blk_bs(blk); int64_t offset, start, remaining, count; @@ -XXX,XX +XXX,XX @@ static int alloc_f(BlockBackend *blk, int argc, char **argv) start = offset = cvtnum(argv[1]); if (offset < 0) { - print_cvtnum_err(offset, argv[1]); + set_cvtnum_err(offset, argv[1], errp); return offset; } if (argc == 3) { count = cvtnum(argv[2]); if (count < 0) { - print_cvtnum_err(count, argv[2]); + set_cvtnum_err(count, argv[2], errp); return count; } } else { @@ -XXX,XX +XXX,XX @@ static int alloc_f(BlockBackend *blk, int argc, char **argv) while (remaining) { ret = bdrv_is_allocated(bs, offset, remaining, &num); if (ret < 0) { - printf("is_allocated failed: %s\n", strerror(-ret)); + error_setg(errp, "is_allocated failed: %s", strerror(-ret)); return ret; } offset += num; @@ -XXX,XX +XXX,XX @@ static int map_is_allocated(BlockDriverState *bs, int64_t offset, return firstret; } -static int map_f(BlockBackend *blk, int argc, char **argv) +static int map_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int64_t offset, bytes; char s1[64], s2[64]; @@ -XXX,XX +XXX,XX @@ static int map_f(BlockBackend *blk, int argc, char **argv) offset = 0; bytes = blk_getlength(blk); if (bytes < 0) { - error_report("Failed to query image length: %s", strerror(-bytes)); + error_setg(errp, "Failed to query image length: %s", strerror(-bytes)); return bytes; } while (bytes) { ret = map_is_allocated(blk_bs(blk), offset, bytes, &num); if (ret < 0) { - error_report("Failed to get allocation status: %s", strerror(-ret)); + error_setg(errp, "Failed to get allocation status: %s", + strerror(-ret)); return ret; } else if (!num) { - error_report("Unexpected end of image"); + error_setg(errp, "Unexpected end of image"); return -EIO; } @@ -XXX,XX +XXX,XX @@ static void reopen_help(void) "\n"); } -static int reopen_f(BlockBackend *blk, int argc, char **argv); +static int reopen_f(BlockBackend *blk, int argc, char **argv, Error **errp); static QemuOptsList reopen_opts = { .name = "reopen", @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t reopen_cmd = { .help = reopen_help, }; -static int reopen_f(BlockBackend *blk, int argc, char **argv) +static int reopen_f(BlockBackend *blk, int argc, char **argv, Error **errp) { BlockDriverState *bs = blk_bs(blk); QemuOpts *qopts; @@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) bool writethrough = !blk_enable_write_cache(blk); bool has_rw_option = false; bool has_cache_option = false; - Error *local_err = NULL; while ((c = getopt(argc, argv, "c:o:rw")) != -1) { switch (c) { case 'c': if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) { - error_report("Invalid cache option: %s", optarg); + error_setg(errp, "Invalid cache option: %s", optarg); return -EINVAL; } has_cache_option = true; @@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) break; case 'r': if (has_rw_option) { - error_report("Only one -r/-w option may be given"); + error_setg(errp, "Only one -r/-w option may be given"); return -EINVAL; } flags &= ~BDRV_O_RDWR; @@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) break; case 'w': if (has_rw_option) { - error_report("Only one -r/-w option may be given"); + error_setg(errp, "Only one -r/-w option may be given"); return -EINVAL; } flags |= BDRV_O_RDWR; @@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) if (!writethrough != blk_enable_write_cache(blk) && blk_get_attached_dev(blk)) { - error_report("Cannot change cache.writeback: Device attached"); + error_setg(errp, "Cannot change cache.writeback: Device attached"); qemu_opts_reset(&reopen_opts); return -EBUSY; } @@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) if (qdict_haskey(opts, BDRV_OPT_READ_ONLY)) { if (has_rw_option) { - error_report("Cannot set both -r/-w and '" BDRV_OPT_READ_ONLY "'"); + error_setg(errp, + "Cannot set both -r/-w and '" BDRV_OPT_READ_ONLY "'"); qobject_unref(opts); return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) if (qdict_haskey(opts, BDRV_OPT_CACHE_DIRECT) || qdict_haskey(opts, BDRV_OPT_CACHE_NO_FLUSH)) { if (has_cache_option) { - error_report("Cannot set both -c and the cache options"); + error_setg(errp, "Cannot set both -c and the cache options"); qobject_unref(opts); return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) qdict_put_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, flags & BDRV_O_NO_FLUSH); } - bdrv_reopen(bs, opts, true, &local_err); - - if (local_err) { - error_report_err(local_err); - return -EINVAL; + { + Error *local_err = NULL; + bdrv_reopen(bs, opts, true, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return -EINVAL; + } } blk_set_enable_write_cache(blk, !writethrough); return 0; } -static int break_f(BlockBackend *blk, int argc, char **argv) +static int break_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int ret; ret = bdrv_debug_breakpoint(blk_bs(blk), argv[1], argv[2]); if (ret < 0) { - printf("Could not set breakpoint: %s\n", strerror(-ret)); + error_setg(errp, "Could not set breakpoint: %s", strerror(-ret)); return ret; } return 0; } -static int remove_break_f(BlockBackend *blk, int argc, char **argv) +static int remove_break_f(BlockBackend *blk, int argc, char **argv, + Error **errp) { int ret; ret = bdrv_debug_remove_breakpoint(blk_bs(blk), argv[1]); if (ret < 0) { - printf("Could not remove breakpoint %s: %s\n", argv[1], strerror(-ret)); + error_setg(errp, "Could not remove breakpoint %s: %s", + argv[1], strerror(-ret)); return ret; } @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t remove_break_cmd = { .oneline = "remove a breakpoint by tag", }; -static int resume_f(BlockBackend *blk, int argc, char **argv) +static int resume_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int ret; ret = bdrv_debug_resume(blk_bs(blk), argv[1]); if (ret < 0) { - printf("Could not resume request: %s\n", strerror(-ret)); + error_setg(errp, "Could not resume request: %s", strerror(-ret)); return ret; } @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t resume_cmd = { .oneline = "resumes the request tagged as tag", }; -static int wait_break_f(BlockBackend *blk, int argc, char **argv) +static int wait_break_f(BlockBackend *blk, int argc, char **argv, Error **errp) { while (!bdrv_debug_is_suspended(blk_bs(blk), argv[1])) { aio_poll(blk_get_aio_context(blk), true); @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t wait_break_cmd = { .oneline = "waits for the suspension of a request", }; -static int abort_f(BlockBackend *blk, int argc, char **argv) +static int abort_f(BlockBackend *blk, int argc, char **argv, Error **errp) { abort(); } @@ -XXX,XX +XXX,XX @@ static void sigraise_help(void) "\n", SIGTERM); } -static int sigraise_f(BlockBackend *blk, int argc, char **argv); +static int sigraise_f(BlockBackend *blk, int argc, char **argv, Error **errp); static const cmdinfo_t sigraise_cmd = { .name = "sigraise", @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t sigraise_cmd = { .help = sigraise_help, }; -static int sigraise_f(BlockBackend *blk, int argc, char **argv) +static int sigraise_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int64_t sig = cvtnum(argv[1]); if (sig < 0) { - print_cvtnum_err(sig, argv[1]); + set_cvtnum_err(sig, argv[1], errp); return sig; } else if (sig > NSIG) { - printf("signal argument '%s' is too large to be a valid signal\n", - argv[1]); + error_setg(errp, + "signal argument '%s' is too large to be a valid signal", + argv[1]); return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static void sleep_cb(void *opaque) *expired = true; } -static int sleep_f(BlockBackend *blk, int argc, char **argv) +static int sleep_f(BlockBackend *blk, int argc, char **argv, Error **errp) { char *endptr; long ms; @@ -XXX,XX +XXX,XX @@ static int sleep_f(BlockBackend *blk, int argc, char **argv) ms = strtol(argv[1], &endptr, 0); if (ms < 0 || *endptr != '\0') { - printf("%s is not a valid number\n", argv[1]); + error_setg(errp, "%s is not a valid number", argv[1]); return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static void help_all(void) printf("\nUse 'help commandname' for extended help.\n"); } -static int help_f(BlockBackend *blk, int argc, char **argv) +static int help_f(BlockBackend *blk, int argc, char **argv, Error **errp) { const cmdinfo_t *ct; @@ -XXX,XX +XXX,XX @@ static int help_f(BlockBackend *blk, int argc, char **argv) ct = find_command(argv[1]); if (ct == NULL) { - printf("command %s not found\n", argv[1]); + error_setg(errp, "command %s not found", argv[1]); return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t help_cmd = { * Called with aio context of blk acquired. Or with qemu_get_aio_context() * context acquired if blk is NULL. */ -int qemuio_command(BlockBackend *blk, const char *cmd) +int qemuio_command(BlockBackend *blk, const char *cmd, Error **errp) { char *input; const cmdinfo_t *ct; @@ -XXX,XX +XXX,XX @@ int qemuio_command(BlockBackend *blk, const char *cmd) if (c) { ct = find_command(v[0]); if (ct) { - ret = command(blk, ct, c, v); + ret = command(blk, ct, c, v, errp); } else { - fprintf(stderr, "command \"%s\" not found\n", v[0]); + error_setg(errp, "command \"%s\" not found", v[0]); ret = -EINVAL; } } diff --git a/qemu-io.c b/qemu-io.c index XXXXXXX..XXXXXXX 100644 --- a/qemu-io.c +++ b/qemu-io.c @@ -XXX,XX +XXX,XX @@ static int get_eof_char(void) #endif } -static int close_f(BlockBackend *blk, int argc, char **argv) +static int close_f(BlockBackend *blk, int argc, char **argv, Error **errp) { blk_unref(qemuio_blk); qemuio_blk = NULL; @@ -XXX,XX +XXX,XX @@ static void open_help(void) "\n"); } -static int open_f(BlockBackend *blk, int argc, char **argv); +static int open_f(BlockBackend *blk, int argc, char **argv, Error **errp); static const cmdinfo_t open_cmd = { .name = "open", @@ -XXX,XX +XXX,XX @@ static QemuOptsList empty_opts = { }, }; -static int open_f(BlockBackend *blk, int argc, char **argv) +static int open_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int flags = BDRV_O_UNMAP; int readonly = 0; @@ -XXX,XX +XXX,XX @@ static int open_f(BlockBackend *blk, int argc, char **argv) return 0; } -static int quit_f(BlockBackend *blk, int argc, char **argv) +static int quit_f(BlockBackend *blk, int argc, char **argv, Error **errp) { quit_qemu_io = true; return 0; @@ -XXX,XX +XXX,XX @@ static void prep_fetchline(void *opaque) static int do_qemuio_command(const char *cmd) { - return qemuio_command(qemuio_blk, cmd); + Error *local_err = NULL; + int ret; + + ret = qemuio_command(qemuio_blk, cmd, &local_err); + if (local_err) { + error_report_err(local_err); + } + return ret; } static int command_loop(void) diff --git a/tests/qemu-iotests/004.out b/tests/qemu-iotests/004.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/004.out +++ b/tests/qemu-iotests/004.out @@ -XXX,XX +XXX,XX @@ wrote 1048576/1048576 bytes at offset 133169152 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) write into image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write at image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write past image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error pwrite past image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error writev past image boundary -writev failed: Input/output error +qemu-io: writev failed: Input/output error read before image boundary read 1048576/1048576 bytes at offset 133169152 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read into image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error read at image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error read past image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error pread past image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error readv past image boundary -readv failed: Input/output error +qemu-io: readv failed: Input/output error *** done diff --git a/tests/qemu-iotests/021.out b/tests/qemu-iotests/021.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/021.out +++ b/tests/qemu-iotests/021.out @@ -XXX,XX +XXX,XX @@ QA output created by 021 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 == testing writev -P -1 == --1 is not a valid pattern byte +qemu-io: -1 is not a valid pattern byte == testing read -P -1 == --1 is not a valid pattern byte +qemu-io: -1 is not a valid pattern byte == testing write -P -1 == --1 is not a valid pattern byte +qemu-io: -1 is not a valid pattern byte == testing readv -P -1 == --1 is not a valid pattern byte +qemu-io: -1 is not a valid pattern byte == testing aio_read -P -1 == --1 is not a valid pattern byte +qemu-io: -1 is not a valid pattern byte == testing aio_write -P -1 == --1 is not a valid pattern byte +qemu-io: -1 is not a valid pattern byte == testing writev -P 300 == -300 is not a valid pattern byte +qemu-io: 300 is not a valid pattern byte == testing read -P 300 == -300 is not a valid pattern byte +qemu-io: 300 is not a valid pattern byte == testing write -P 300 == -300 is not a valid pattern byte +qemu-io: 300 is not a valid pattern byte == testing readv -P 300 == -300 is not a valid pattern byte +qemu-io: 300 is not a valid pattern byte == testing aio_read -P 300 == -300 is not a valid pattern byte +qemu-io: 300 is not a valid pattern byte == testing aio_write -P 300 == -300 is not a valid pattern byte +qemu-io: 300 is not a valid pattern byte == testing writev -P 12m == -12m is not a valid pattern byte +qemu-io: 12m is not a valid pattern byte == testing read -P 12m == -12m is not a valid pattern byte +qemu-io: 12m is not a valid pattern byte == testing write -P 12m == -12m is not a valid pattern byte +qemu-io: 12m is not a valid pattern byte == testing readv -P 12m == -12m is not a valid pattern byte +qemu-io: 12m is not a valid pattern byte == testing aio_read -P 12m == -12m is not a valid pattern byte +qemu-io: 12m is not a valid pattern byte == testing aio_write -P 12m == -12m is not a valid pattern byte +qemu-io: 12m is not a valid pattern byte == testing writev -P 4k == -4k is not a valid pattern byte +qemu-io: 4k is not a valid pattern byte == testing read -P 4k == -4k is not a valid pattern byte +qemu-io: 4k is not a valid pattern byte == testing write -P 4k == -4k is not a valid pattern byte +qemu-io: 4k is not a valid pattern byte == testing readv -P 4k == -4k is not a valid pattern byte +qemu-io: 4k is not a valid pattern byte == testing aio_read -P 4k == -4k is not a valid pattern byte +qemu-io: 4k is not a valid pattern byte == testing aio_write -P 4k == -4k is not a valid pattern byte +qemu-io: 4k is not a valid pattern byte == testing writev -P route66 == -route66 is not a valid pattern byte +qemu-io: route66 is not a valid pattern byte == testing read -P route66 == -route66 is not a valid pattern byte +qemu-io: route66 is not a valid pattern byte == testing write -P route66 == -route66 is not a valid pattern byte +qemu-io: route66 is not a valid pattern byte == testing readv -P route66 == -route66 is not a valid pattern byte +qemu-io: route66 is not a valid pattern byte == testing aio_read -P route66 == -route66 is not a valid pattern byte +qemu-io: route66 is not a valid pattern byte == testing aio_write -P route66 == -route66 is not a valid pattern byte +qemu-io: route66 is not a valid pattern byte *** done diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/060.out +++ b/tests/qemu-iotests/060.out @@ -XXX,XX +XXX,XX @@ ERROR cluster 3 refcount=1 reference=3 Data may be corrupted, or further writes to the image may corrupt it. incompatible_features [] qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with active L1 table); further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error incompatible_features [1] image: TEST_DIR/t.IMGFMT file format: IMGFMT @@ -XXX,XX +XXX,XX @@ Format specific information: corrupt: true extended l2: false qemu-io: can't open device TEST_DIR/t.IMGFMT: IMGFMT: Image is corrupt; cannot be opened read/write -no file open, try 'help open' +qemu-io: no file open, try 'help open' read 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -XXX,XX +XXX,XX @@ ERROR cluster 2 refcount=1 reference=2 Data may be corrupted, or further writes to the image may corrupt it. incompatible_features [] qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with refcount block); further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error incompatible_features [1] ERROR refcount block 0 refcount=2 ERROR cluster 2 refcount=1 reference=2 @@ -XXX,XX +XXX,XX @@ Data may be corrupted, or further writes to the image may corrupt it. This means waste of disk space, but no harm to data. incompatible_features [] qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with inactive L2 table); further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error incompatible_features [1] ERROR cluster 4 refcount=1 reference=2 Leaked cluster 9 refcount=1 reference=0 @@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 0 wrote 65536/65536 bytes at offset 536870912 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with active L2 table); further corruption events will be suppressed +qemu-io: write failed: Input/output error +qemu-io: aio_write failed: No medium found blkdebug: Suspended request '0' -write failed: Input/output error blkdebug: Resuming request '0' -aio_write failed: No medium found === Testing unallocated image header === @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with qcow2_header); further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error === Testing unaligned L1 entry === @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Marking image as corrupt: L2 table offset 0x42a00 unaligned (L1 index: 0); further corruption events will be suppressed -read failed: Input/output error +qemu-io: read failed: Input/output error Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Marking image as corrupt: Cluster allocation offset 0x52a00 unaligned (L2 offset: 0x40000, L2 index: 0); further corruption events will be suppressed -read failed: Input/output error +qemu-io: read failed: Input/output error === Testing unaligned pre-allocated zero cluster === @@ -XXX,XX +XXX,XX @@ qemu-img: Failed to turn zero into data clusters: Input/output error Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 qcow2: Marking image as corrupt: Refblock offset 0x22a00 unaligned (reftable index: 0); further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error === Testing non-fatal corruption on freeing === @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Image is corrupt: Cluster allocation offset 0x52a00 unaligned (L2 offset: 0x40000, L2 index: 0); further non-fatal corruption events will be suppressed -read failed: Input/output error -read failed: Input/output error +qemu-io: read failed: Input/output error +qemu-io: read failed: Input/output error === Testing non-fatal and then fatal corruption report === @@ -XXX,XX +XXX,XX @@ wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Image is corrupt: Cannot free unaligned cluster 0x52a00; further non-fatal corruption events will be suppressed qcow2: Marking image as corrupt: Cluster allocation offset 0x62a00 unaligned (L2 offset: 0x40000, L2 index: 0x1); further corruption events will be suppressed +qemu-io: read failed: Input/output error discard 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read failed: Input/output error === Testing empty refcount table === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with refcount table); further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error ERROR cluster 0 refcount=0 reference=1 ERROR cluster 1 refcount=0 reference=1 ERROR cluster 3 refcount=0 reference=1 @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Marking image as corrupt: Preventing invalid allocation of refcount block at offset 0; further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error ERROR cluster 0 refcount=0 reference=1 ERROR cluster 1 refcount=0 reference=1 ERROR cluster 3 refcount=0 reference=1 @@ -XXX,XX +XXX,XX @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 qcow2: Marking image as corrupt: Preventing invalid allocation of L2 table at offset 0; further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error ERROR cluster 0 refcount=0 reference=1 ERROR cluster 1 refcount=0 reference=1 ERROR cluster 2 refcount=0 reference=1 @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 wrote 65536/65536 bytes at offset 65536 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Marking image as corrupt: Preventing invalid allocation of compressed cluster at offset 0; further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error ERROR cluster 0 refcount=0 reference=1 ERROR cluster 1 refcount=0 reference=1 ERROR cluster 2 refcount=0 reference=1 @@ -XXX,XX +XXX,XX @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 qcow2: Marking image as corrupt: Preventing invalid allocation of L2 table at offset 0; further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error === Testing dirty corrupt image === @@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 0 discard 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Marking image as corrupt: Preallocated zero cluster offset 0x2a00 unaligned (guest offset: 0); further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error --- Repairing --- Repairing offset=2a00: Preallocated cluster is not properly aligned; L2 entry corrupted. The following inconsistencies were found and repaired: @@ -XXX,XX +XXX,XX @@ wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Marking image as corrupt: Refblock offset 0x2a00 unaligned (reftable index: 0); further corruption events will be suppressed qcow2_free_clusters failed: Input/output error -discard failed: No medium found +qemu-io: discard failed: No medium found --- Repairing --- ERROR refcount block 0 is not cluster aligned; refcount table entry corrupted qcow2: Marking image as corrupt: Refblock offset 0x2a00 unaligned (reftable index: 0); further corruption events will be suppressed @@ -XXX,XX +XXX,XX @@ qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps QMP_VERSION {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_IMAGE_CORRUPTED", "data": {"device": "none0", "msg": "Preventing invalid write on metadata (overlaps with refcount table)", "offset": 65536, "node-name": "drive", "fatal": true, "size": 65536}} -write failed: Input/output error -{"return": ""} +{"return": "Error: write failed: Input/output error\r\n"} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} {"return": {}} @@ -XXX,XX +XXX,XX @@ QMP_VERSION {"return": {}} qcow2: Image is corrupt: L2 table offset 0x2a2a2a00 unaligned (L1 index: 0); further non-fatal corruption events will be suppressed {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_IMAGE_CORRUPTED", "data": {"device": "", "msg": "L2 table offset 0x2a2a2a00 unaligned (L1 index: 0)", "node-name": "drive", "fatal": false}} -{"return": ""} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} {"return": {}} diff --git a/tests/qemu-iotests/071.out b/tests/qemu-iotests/071.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/071.out +++ b/tests/qemu-iotests/071.out @@ -XXX,XX +XXX,XX @@ blkverify: read offset=0 bytes=512 contents mismatch at offset 0 === Testing blkdebug through filename === -read failed: Input/output error +qemu-io: read failed: Input/output error === Testing blkdebug through file blockref === -read failed: Input/output error +qemu-io: read failed: Input/output error === Testing blkdebug on existing block device === @@ -XXX,XX +XXX,XX @@ QMP_VERSION {"return": {}} {"return": {}} {"return": {}} -read failed: Input/output error -{"return": ""} +{"return": "Error: read failed: Input/output error\r\n"} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} {"return": {}} @@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) {"return": ""} -read failed: Input/output error -{"return": ""} +{"return": "Error: read failed: Input/output error\r\n"} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} QEMU_PROG: Failed to flush the L2 table cache: Input/output error QEMU_PROG: Failed to flush the refcount block cache: Input/output error diff --git a/tests/qemu-iotests/072.out b/tests/qemu-iotests/072.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/072.out +++ b/tests/qemu-iotests/072.out @@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 512 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 512/512 bytes at offset 1024 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Pattern verification failed at offset 0, 512 bytes +qemu-io: Pattern verification failed at offset 0, 512 bytes read 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) *** done diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/080.out +++ b/tests/qemu-iotests/080.out @@ -XXX,XX +XXX,XX @@ wrote 512/512 bytes at offset 0 qemu-img: Failed to load snapshot: Snapshot L1 table offset invalid qemu-img: Snapshot L1 table offset invalid qemu-img: Failed to turn zero into data clusters: Invalid argument +qemu-io: write failed: Invalid argument qemu-io: Failed to flush the refcount block cache: Invalid argument -write failed: Invalid argument qemu-img: Snapshot L1 table offset invalid qemu-img: Could not apply snapshot 'test': Failed to load snapshot: Invalid argument qemu-img: Could not delete snapshot 'test': Snapshot L1 table offset invalid @@ -XXX,XX +XXX,XX @@ wrote 512/512 bytes at offset 0 qemu-img: Failed to load snapshot: Snapshot L1 table too large qemu-img: Snapshot L1 table too large qemu-img: Failed to turn zero into data clusters: File too large +qemu-io: write failed: File too large qemu-io: Failed to flush the refcount block cache: File too large -write failed: File too large qemu-img: Snapshot L1 table too large qemu-img: Could not apply snapshot 'test': Failed to load snapshot: File too large qemu-img: Could not delete snapshot 'test': Snapshot L1 table too large diff --git a/tests/qemu-iotests/089.out b/tests/qemu-iotests/089.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/089.out +++ b/tests/qemu-iotests/089.out @@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 512 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 512/512 bytes at offset 1024 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Pattern verification failed at offset 0, 512 bytes +qemu-io: Pattern verification failed at offset 0, 512 bytes read 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 0 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 wrote 512/512 bytes at offset 229376 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read failed: Input/output error +qemu-io: read failed: Input/output error === Testing qemu-img info output === diff --git a/tests/qemu-iotests/114.out b/tests/qemu-iotests/114.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/114.out +++ b/tests/qemu-iotests/114.out @@ -XXX,XX +XXX,XX @@ cluster_size: 65536 backing file: TEST_DIR/t.IMGFMT.base backing file format: foo qemu-io: can't open device TEST_DIR/t.qcow2: Could not open backing file: Unknown driver 'foo' -no file open, try 'help open' +qemu-io: no file open, try 'help open' read 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qemu-img: Could not change the backing file to 'TEST_DIR/t.qcow2.base': backing format must be specified diff --git a/tests/qemu-iotests/134.out b/tests/qemu-iotests/134.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/134.out +++ b/tests/qemu-iotests/134.out @@ -XXX,XX +XXX,XX @@ read 134217728/134217728 bytes at offset 0 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == verify pattern failure with wrong password == -Pattern verification failed at offset 0, 134217728 bytes +qemu-io: Pattern verification failed at offset 0, 134217728 bytes read 134217728/134217728 bytes at offset 0 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) *** done diff --git a/tests/qemu-iotests/137.out b/tests/qemu-iotests/137.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/137.out +++ b/tests/qemu-iotests/137.out @@ -XXX,XX +XXX,XX @@ OK: Dirty bit not set Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 qemu-io: Parameter 'lazy-refcounts' expects 'on' or 'off' qcow2: Marking image as corrupt: Preventing invalid allocation of L2 table at offset 0; further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error *** done diff --git a/tests/qemu-iotests/171 b/tests/qemu-iotests/171 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/171 +++ b/tests/qemu-iotests/171 @@ -XXX,XX +XXX,XX @@ img_offset=512 img_size=512 _make_test_img $size ( -$QEMU_IO "$(img_json)" <<EOT +$QEMU_IO "$(img_json)" 2>&1 <<EOT write -P 0x0a 0 512 write -P 0x0a 511 1 write -P 0x0a 512 1 diff --git a/tests/qemu-iotests/171.out b/tests/qemu-iotests/171.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/171.out +++ b/tests/qemu-iotests/171.out @@ -XXX,XX +XXX,XX @@ wrote 1/1 bytes at offset 3583 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) write across image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write at image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write after image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error writev before/after image boundary -writev failed: Input/output error +qemu-io: writev failed: Input/output error read before image boundary read 1/1 bytes at offset 3583 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read across image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error read at image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error read after image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error readv before/after image boundary -readv failed: Input/output error +qemu-io: readv failed: Input/output error fill image with pattern wrote 4096/4096 bytes at offset 0 @@ -XXX,XX +XXX,XX @@ read 4/4 bytes at offset 510 4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) write zeroes across image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write zeroes at image boundary and check wrote 2/2 bytes at offset 3582 @@ -XXX,XX +XXX,XX @@ wrote 2/2 bytes at offset 3582 00000ffe: 00 00 .. read 2/2 bytes at offset 4094 2 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read failed: Input/output error +qemu-io: read failed: Input/output error fill image with pattern wrote 4096/4096 bytes at offset 0 @@ -XXX,XX +XXX,XX @@ read 4/4 bytes at offset 510 4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) discard across image boundary -discard failed: Input/output error +qemu-io: discard failed: Input/output error discard at image boundary and check discard 2/2 bytes at offset 3582 @@ -XXX,XX +XXX,XX @@ discard 2/2 bytes at offset 3582 00000ffe: 00 00 .. read 2/2 bytes at offset 4094 2 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read failed: Input/output error +qemu-io: read failed: Input/output error == test 'offset' and 'size' options == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4096 @@ -XXX,XX +XXX,XX @@ wrote 1/1 bytes at offset 2047 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) write across image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write at image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write after image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error writev before/after image boundary -writev failed: Input/output error +qemu-io: writev failed: Input/output error read before image boundary read 1/1 bytes at offset 2047 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read across image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error read at image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error read after image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error readv before/after image boundary -readv failed: Input/output error +qemu-io: readv failed: Input/output error fill image with pattern wrote 4096/4096 bytes at offset 0 @@ -XXX,XX +XXX,XX @@ read 4/4 bytes at offset 510 4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) write zeroes across image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write zeroes at image boundary and check wrote 2/2 bytes at offset 2046 @@ -XXX,XX +XXX,XX @@ read 4/4 bytes at offset 510 4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) discard across image boundary -discard failed: Input/output error +qemu-io: discard failed: Input/output error discard at image boundary and check discard 2/2 bytes at offset 2046 @@ -XXX,XX +XXX,XX @@ wrote 1/1 bytes at offset 2047 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) write across image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write at image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write after image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error writev before/after image boundary -writev failed: Input/output error +qemu-io: writev failed: Input/output error read before image boundary read 1/1 bytes at offset 2047 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read across image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error read at image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error read after image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error readv before/after image boundary -readv failed: Input/output error +qemu-io: readv failed: Input/output error fill image with pattern wrote 4096/4096 bytes at offset 0 @@ -XXX,XX +XXX,XX @@ read 4/4 bytes at offset 8 4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) write zeroes across image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write zeroes at image boundary and check wrote 2/2 bytes at offset 2046 @@ -XXX,XX +XXX,XX @@ read 4/4 bytes at offset 8 4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) discard across image boundary -discard failed: Input/output error +qemu-io: discard failed: Input/output error discard at image boundary and check discard 2/2 bytes at offset 2046 @@ -XXX,XX +XXX,XX @@ wrote 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 1/1 bytes at offset 511 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -write failed: Input/output error +qemu-io: write failed: Input/output error wrote 1024/1024 bytes at offset 0 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 1/1 bytes at offset 1023 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -write failed: Input/output error +qemu-io: write failed: Input/output error checking boundaries 000001fe: 00 00 0a 0a .... read 4/4 bytes at offset 510 diff --git a/tests/qemu-iotests/214.out b/tests/qemu-iotests/214.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/214.out +++ b/tests/qemu-iotests/214.out @@ -XXX,XX +XXX,XX @@ wrote 2097152/2097152 bytes at offset 0 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 2097152/2097152 bytes at offset 2097152 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read failed: Input/output error +qemu-io: read failed: Input/output error No errors were found on the image. read 4194304/4194304 bytes at offset 0 4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) diff --git a/tests/qemu-iotests/220.out b/tests/qemu-iotests/220.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/220.out +++ b/tests/qemu-iotests/220.out @@ -XXX,XX +XXX,XX @@ wrote 2097152/2097152 bytes at offset 37748736 No errors were found on the image. image size 39845888 == Trying to write compressed cluster == -write failed: File too large +qemu-io: write failed: File too large image size 562949957615616 == Writing normal cluster == wrote 2097152/2097152 bytes at offset 0 diff --git a/tests/qemu-iotests/244.out b/tests/qemu-iotests/244.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/244.out +++ b/tests/qemu-iotests/244.out @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0 read 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qemu-io: can't open device TEST_DIR/t.qcow2: Could not open 'inexistent': No such file or directory -no file open, try 'help open' +qemu-io: no file open, try 'help open' Data file required, but without data file name in the image: qemu-io: can't open device TEST_DIR/t.qcow2: 'data-file' is required for this image -no file open, try 'help open' +qemu-io: no file open, try 'help open' read 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qemu-io: can't open device TEST_DIR/t.qcow2: Could not open 'inexistent': No such file or directory -no file open, try 'help open' +qemu-io: no file open, try 'help open' Setting data-file for an image with internal data: Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 qemu-io: can't open device TEST_DIR/t.qcow2: 'data-file' can only be set for images with an external data file -no file open, try 'help open' +qemu-io: no file open, try 'help open' qemu-io: can't open device TEST_DIR/t.qcow2: Could not open 'inexistent': No such file or directory -no file open, try 'help open' +qemu-io: no file open, try 'help open' === Conflicting features === @@ -XXX,XX +XXX,XX @@ qemu-img: error while writing at byte 0: Operation not supported Convert uncompressed, then write compressed data manually: Images are identical. -write failed: Operation not supported +qemu-io: write failed: Operation not supported No errors were found on the image. Take an internal snapshot: diff --git a/tests/qemu-iotests/249.out b/tests/qemu-iotests/249.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/249.out +++ b/tests/qemu-iotests/249.out @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t. { 'execute': 'human-monitor-command', 'arguments': {'command-line': 'qemu-io none0 "aio_write 0 2k"'}} -{"return": "Block node is read-onlyrn"} +{"return": "Error: Block node is read-onlyrn"} === Run block-commit on base using an invalid filter node name @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t. { 'execute': 'human-monitor-command', 'arguments': {'command-line': 'qemu-io none0 "aio_write 0 2k"'}} -{"return": "Block node is read-onlyrn"} +{"return": "Error: Block node is read-onlyrn"} === Run block-commit on base using the default filter node name @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t. { 'execute': 'human-monitor-command', 'arguments': {'command-line': 'qemu-io none0 "aio_write 0 2k"'}} -{"return": "Block node is read-onlyrn"} +{"return": "Error: Block node is read-onlyrn"} *** done diff --git a/tests/qemu-iotests/271.out b/tests/qemu-iotests/271.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/271.out +++ b/tests/qemu-iotests/271.out @@ -XXX,XX +XXX,XX @@ L2 entry #0: 0x8000000000050001 0000000000000001 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 L2 entry #1: 0x8000000000060000 00000001ffffffff qcow2: Marking image as corrupt: Invalid cluster entry found (L2 offset: 0x40000, L2 index: 0x1); further corruption events will be suppressed -read failed: Input/output error +qemu-io: read failed: Input/output error ### Corrupted L2 entries - read test (unallocated) ### @@ -XXX,XX +XXX,XX @@ L2 entry #0: 0x0000000000000001 0000000000000000 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 L2 entry #0: 0x0000000000000000 0000000000000001 qcow2: Marking image as corrupt: Invalid cluster entry found (L2 offset: 0x40000, L2 index: 0); further corruption events will be suppressed -read failed: Input/output error +qemu-io: read failed: Input/output error # Both 'subcluster is zero' and 'subcluster is allocated' bits set Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 L2 entry #1: 0x0000000000000000 0000000100000001 qcow2: Marking image as corrupt: Invalid cluster entry found (L2 offset: 0x40000, L2 index: 0x1); further corruption events will be suppressed -read failed: Input/output error +qemu-io: read failed: Input/output error ### Compressed cluster with subcluster bitmap != 0 - read test ### @@ -XXX,XX +XXX,XX @@ L2 entry #0: 0x8000000000050001 0000000000000001 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 L2 entry #1: 0x8000000000060000 00000001ffffffff qcow2: Marking image as corrupt: Invalid cluster entry found (L2 offset: 0x40000, L2 index: 0x1); further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error ### Corrupted L2 entries - write test (unallocated) ### @@ -XXX,XX +XXX,XX @@ L2 entry #0: 0x8000000000060000 0000000000000001 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 L2 entry #0: 0x0000000000000000 0000000000000001 qcow2: Marking image as corrupt: Invalid cluster entry found (L2 offset: 0x40000, L2 index: 0); further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error # Both 'subcluster is zero' and 'subcluster is allocated' bits set Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 L2 entry #1: 0x0000000000000000 0000000100000001 qcow2: Marking image as corrupt: Invalid cluster entry found (L2 offset: 0x40000, L2 index: 0x1); further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error ### Compressed cluster with subcluster bitmap != 0 - write test ### @@ -XXX,XX +XXX,XX @@ Double checking the fixed image now... 1 errors were found on the image. Data may be corrupted, or further writes to the image may corrupt it. qcow2: Marking image as corrupt: Cluster allocation offset 0x50200 unaligned (L2 offset: 0x40000, L2 index: 0); further corruption events will be suppressed -read failed: Input/output error +qemu-io: read failed: Input/output error # Corrupted L2 entry, no allocated subclusters # Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw Repairing offset=50200: Preallocated cluster is not properly aligned; L2 entry corrupted. diff --git a/tests/qemu-iotests/tests/copy-before-write b/tests/qemu-iotests/tests/copy-before-write index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/tests/copy-before-write +++ b/tests/qemu-iotests/tests/copy-before-write @@ -XXX,XX +XXX,XX @@ class TestCbwError(iotests.QMPTestCase): result = self.vm.qmp('human-monitor-command', command_line='qemu-io cbw "write 0 1M"') - self.assert_qmp(result, 'return', '') + write_res = result['return'] result = self.vm.qmp('human-monitor-command', command_line='qemu-io access "read 0 1M"') - self.assert_qmp(result, 'return', '') + read_res = result['return'] self.vm.shutdown() log = self.vm.get_log() log = iotests.filter_qtest(log) log = iotests.filter_qemu_io(log) - return log + return log, write_res, read_res def do_cbw_error_via_blockdev_backup(self, on_cbw_error=None): self.vm.cmd('blockdev-add', { @@ -XXX,XX +XXX,XX @@ class TestCbwError(iotests.QMPTestCase): result = self.vm.qmp('human-monitor-command', command_line='qemu-io cbw "write 0 1M"') - self.assert_qmp(result, 'return', '') + write_res = result['return'] result = self.vm.qmp('human-monitor-command', command_line='qemu-io access "read 0 1M"') - self.assert_qmp(result, 'return', '') + read_res = result['return'] self.vm.shutdown() log = self.vm.get_log() log = iotests.filter_qemu_io(log) - return log + return log, write_res, read_res def test_break_snapshot_on_cbw_error(self): """break-snapshot behavior: Guest write succeed, but further snapshot-read fails, as snapshot is broken. """ - log = self.do_cbw_error('break-snapshot') + log, write_res, read_res = self.do_cbw_error('break-snapshot') + self.assertEqual(write_res, '') + self.assertIn('read failed: Permission denied', read_res) self.assertEqual(log, """\ wrote 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read failed: Permission denied """) def test_break_guest_write_on_cbw_error(self): @@ -XXX,XX +XXX,XX @@ read failed: Permission denied Guest write fails, but snapshot-access continues working and further snapshot-read succeeds. """ - log = self.do_cbw_error('break-guest-write') + log, write_res, read_res = self.do_cbw_error('break-guest-write') + self.assertIn('write failed: Input/output error', write_res) + self.assertEqual(read_res, '') self.assertEqual(log, """\ -write failed: Input/output error read 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) """) @@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 0 """Ensure CBW filter accepts break-snapshot policy specified in blockdev-backup QMP command. """ - log = self.do_cbw_error_via_blockdev_backup('break-snapshot') + log, write_res, read_res = \ + self.do_cbw_error_via_blockdev_backup('break-snapshot') + self.assertEqual(write_res, '') + self.assertIn('read failed: Permission denied', read_res) self.assertEqual(log, """\ wrote 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read failed: Permission denied """) def test_break_guest_write_policy_forwarding(self): """Ensure CBW filter accepts break-guest-write policy specified in blockdev-backup QMP command. """ - log = self.do_cbw_error_via_blockdev_backup('break-guest-write') + log, write_res, read_res = \ + self.do_cbw_error_via_blockdev_backup('break-guest-write') + self.assertIn('write failed: Input/output error', write_res) + self.assertEqual(read_res, '') self.assertEqual(log, """\ -write failed: Input/output error read 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) """) @@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 0 """Ensure break-guest-write policy is used by default when on-cbw-error is not explicitly specified. """ - log = self.do_cbw_error_via_blockdev_backup() + log, write_res, read_res = \ + self.do_cbw_error_via_blockdev_backup() + self.assertIn('write failed: Input/output error', write_res) + self.assertEqual(read_res, '') self.assertEqual(log, """\ -write failed: Input/output error read 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) """) @@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 0 result = self.vm.qmp('human-monitor-command', command_line='qemu-io cbw "write 0 512K"') - self.assert_qmp(result, 'return', '') + write1_res = result['return'] # We need second write to trigger throttling result = self.vm.qmp('human-monitor-command', command_line='qemu-io cbw "write 512K 512K"') - self.assert_qmp(result, 'return', '') + write2_res = result['return'] result = self.vm.qmp('human-monitor-command', command_line='qemu-io access "read 0 1M"') - self.assert_qmp(result, 'return', '') + read_res = result['return'] self.vm.shutdown() log = self.vm.get_log() log = re.sub(r'^\[I \+?\d+\.\d+\] OPENED\n', '', log) log = re.sub(r'\[I \+?\d+\.\d+\] CLOSED\n?$', '', log) log = iotests.filter_qemu_io(log) - return log + return log, write1_res, write2_res, read_res def test_timeout_break_guest(self): - log = self.do_cbw_timeout('break-guest-write') + log, write1_res, write2_res, read_res = \ + self.do_cbw_timeout('break-guest-write') + self.assertEqual(write1_res, '') # macOS and FreeBSD tend to represent ETIMEDOUT as # "Operation timed out", when Linux prefer # "Connection timed out" - log = log.replace('Operation timed out', - 'Connection timed out') + write2_res = write2_res.replace('Operation timed out', + 'Connection timed out') + self.assertIn('write failed: Connection timed out', write2_res) + self.assertEqual(read_res, '') self.assertEqual(log, """\ wrote 524288/524288 bytes at offset 0 512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -write failed: Connection timed out read 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) """) def test_timeout_break_snapshot(self): - log = self.do_cbw_timeout('break-snapshot') + log, write1_res, write2_res, read_res = \ + self.do_cbw_timeout('break-snapshot') + self.assertEqual(write1_res, '') + self.assertEqual(write2_res, '') + self.assertIn('read failed: Permission denied', read_res) self.assertEqual(log, """\ wrote 524288/524288 bytes at offset 0 512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 524288/524288 bytes at offset 524288 512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read failed: Permission denied """) -- 2.54.0
Add an x-qemu-io QMP command that runs qemu-io commands on block devices. The command accepts a device name (block backend name, node-name, or qdev ID) and a qemu-io command string. Refactor hmp_qemu_io() to be a thin wrapper around the new QMP command, following the standard HMP-over-QMP pattern used by other block commands. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- qapi/block.json | 34 +++++++++++++ block/monitor/block-hmp-cmds.c | 60 ++-------------------- block/monitor/qmp-cmds.c | 79 +++++++++++++++++++++++++++++ block/monitor/meson.build | 1 + tests/qemu-iotests/tests/image-fleecing | 4 +- tests/qemu-iotests/tests/image-fleecing.out | 52 +++++++++---------- 6 files changed, 145 insertions(+), 85 deletions(-) diff --git a/qapi/block.json b/qapi/block.json index XXXXXXX..XXXXXXX 100644 --- a/qapi/block.json +++ b/qapi/block.json @@ -XXX,XX +XXX,XX @@ '*boundaries-zap': ['uint64'], '*boundaries-flush': ['uint64'] }, 'allow-preconfig': true } + +## +# @x-qemu-io: +# +# Run a qemu-io command on a block device. Take either a block +# backend name or a qdev ID to identify the device. +# +# @device: the block backend name, node-name to run the +# command on. +# +# @qdev: the qdev ID of the block device to run the +# command on. +# +# @command: the qemu-io command string to execute. +# +# Features: +# +# @unstable: This command is for testing only. +# +# Since: 11.1 +# +# .. qmp-example:: +# +# -> { "execute": "x-qemu-io", +# "arguments": { "device": "virtio0", +# "command": "read 0 512" } } +# <- { "return": {} } +## +{ 'command': 'x-qemu-io', + 'data': { '*device': 'str', + '*qdev': 'str', + 'command': 'str' }, + 'features': [ 'unstable' ], + 'allow-preconfig': true } diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/block/monitor/block-hmp-cmds.c +++ b/block/monitor/block-hmp-cmds.c @@ -XXX,XX +XXX,XX @@ #include "block/qapi.h" #include "block/block_int.h" #include "block/block-hmp-cmds.h" -#include "qemu-io.h" static void hmp_drive_add_node(Monitor *mon, const char *optstr) { @@ -XXX,XX +XXX,XX @@ void hmp_eject(Monitor *mon, const QDict *qdict) void hmp_qemu_io(Monitor *mon, const QDict *qdict) { - BlockBackend *blk = NULL; - BlockDriverState *bs = NULL; - BlockBackend *local_blk = NULL; bool qdev = qdict_get_try_bool(qdict, "qdev", false); const char *device = qdict_get_str(qdict, "device"); const char *command = qdict_get_str(qdict, "command"); Error *err = NULL; - int ret; - - if (qdev) { - blk = blk_by_qdev_id(device, &err); - if (!blk) { - goto fail; - } - } else { - blk = blk_by_name(device); - if (!blk) { - bs = bdrv_lookup_bs(NULL, device, &err); - if (!bs) { - goto fail; - } - } - } - - if (bs) { - blk = local_blk = blk_new(bdrv_get_aio_context(bs), 0, BLK_PERM_ALL); - ret = blk_insert_bs(blk, bs, &err); - if (ret < 0) { - goto fail; - } - } - - /* - * Notably absent: Proper permission management. This is sad, but it seems - * almost impossible to achieve without changing the semantics and thereby - * limiting the use cases of the qemu-io HMP command. - * - * In an ideal world we would unconditionally create a new BlockBackend for - * qemuio_command(), but we have commands like 'reopen' and want them to - * take effect on the exact BlockBackend whose name the user passed instead - * of just on a temporary copy of it. - * - * Another problem is that deleting the temporary BlockBackend involves - * draining all requests on it first, but some qemu-iotests cases want to - * issue multiple aio_read/write requests and expect them to complete in - * the background while the monitor has already returned. - * - * This is also what prevents us from saving the original permissions and - * restoring them later: We can't revoke permissions until all requests - * have completed, and we don't know when that is nor can we really let - * anything else run before we have revoken them to avoid race conditions. - * - * What happens now is that command() in qemu-io-cmds.c can extend the - * permissions if necessary for the qemu-io command. And they simply stay - * extended, possibly resulting in a read-only guest device keeping write - * permissions. Ugly, but it appears to be the lesser evil. - */ - qemuio_command(blk, command, &err); -fail: - blk_unref(local_blk); + qmp_x_qemu_io(qdev ? NULL : device, + qdev ? device : NULL, + command, &err); hmp_handle_error(mon, err); } diff --git a/block/monitor/qmp-cmds.c b/block/monitor/qmp-cmds.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/block/monitor/qmp-cmds.c @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "qemu/osdep.h" + +#include "system/block-backend.h" +#include "block/block_int.h" +#include "qapi/qapi-commands-block.h" +#include "qapi/error.h" +#include "qemu-io.h" + +void qmp_x_qemu_io(const char *device, const char *qdev, + const char *command, Error **errp) +{ + BlockBackend *blk = NULL; + BlockBackend *local_blk = NULL; + BlockDriverState *bs = NULL; + int ret; + + if (!device && !qdev) { + error_setg(errp, "Must specify either device or qdev"); + return; + } + if (qdev && device) { + error_setg(errp, "Cannot specify both qdev and device"); + return; + } + + if (qdev) { + blk = blk_by_qdev_id(qdev, errp); + if (!blk) { + return; + } + } else { + blk = blk_by_name(device); + if (!blk) { + bs = bdrv_lookup_bs(NULL, device, errp); + if (!bs) { + return; + } + } + } + + if (bs) { + blk = local_blk = blk_new(bdrv_get_aio_context(bs), 0, BLK_PERM_ALL); + ret = blk_insert_bs(blk, bs, errp); + if (ret < 0) { + goto fail; + } + } + + /* + * Notably absent: Proper permission management. This is sad, but it seems + * almost impossible to achieve without changing the semantics and thereby + * limiting the use cases of the qemu-io command. + * + * In an ideal world we would unconditionally create a new BlockBackend for + * qemuio_command(), but we have commands like 'reopen' and want them to + * take effect on the exact BlockBackend whose name the user passed instead + * of just on a temporary copy of it. + * + * Another problem is that deleting the temporary BlockBackend involves + * draining all requests on it first, but some qemu-iotests cases want to + * issue multiple aio_read/write requests and expect them to complete in + * the background while the monitor has already returned. + * + * This is also what prevents us from saving the original permissions and + * restoring them later: We can't revoke permissions until all requests + * have completed, and we don't know when that is nor can we really let + * anything else run before we have revoken them to avoid race conditions. + * + * What happens now is that command() in qemu-io-cmds.c can extend the + * permissions if necessary for the qemu-io command. And they simply stay + * extended, possibly resulting in a read-only guest device keeping write + * permissions. Ugly, but it appears to be the lesser evil. + */ + qemuio_command(blk, command, errp); + +fail: + blk_unref(local_blk); +} diff --git a/block/monitor/meson.build b/block/monitor/meson.build index XXXXXXX..XXXXXXX 100644 --- a/block/monitor/meson.build +++ b/block/monitor/meson.build @@ -XXX,XX +XXX,XX @@ system_ss.add(files('block-hmp-cmds.c')) block_ss.add(files('bitmap-qmp-cmds.c')) +system_ss.add(files('qmp-cmds.c')) diff --git a/tests/qemu-iotests/tests/image-fleecing b/tests/qemu-iotests/tests/image-fleecing index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/tests/image-fleecing +++ b/tests/qemu-iotests/tests/image-fleecing @@ -XXX,XX +XXX,XX @@ def do_test(vm, use_cbw, use_snapshot_access_filter, base_img_path, for p in overwrite: cmd = 'write -P%s %s %s' % p log(cmd) - log(vm.hmp_qemu_io(qom_path, cmd, qdev=True)) + log(vm.qmp('x-qemu-io', qdev='sda', command=cmd)) if push_backup: # Check that previous operations were done during backup, not after # If backup is already finished, it's possible that it was finished - # even before hmp qemu_io write, and we didn't actually test + # even before qemu_io write, and we didn't actually test # copy-before-write operation. This should not happen, as we use # speed=1. But worth checking. result = vm.qmp('query-block-jobs') diff --git a/tests/qemu-iotests/tests/image-fleecing.out b/tests/qemu-iotests/tests/image-fleecing.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/tests/image-fleecing.out +++ b/tests/qemu-iotests/tests/image-fleecing.out @@ -XXX,XX +XXX,XX @@ read -P0 0x3fe0000 64k --- Testing COW --- write -P0xab 0 64k -{"return": ""} +{"return": {}} write -P0xad 0x00f8000 64k -{"return": ""} +{"return": {}} write -P0x1d 0x2008000 64k -{"return": ""} +{"return": {}} write -P0xea 0x3fe0000 64k -{"return": ""} +{"return": {}} --- Verifying Data --- @@ -XXX,XX +XXX,XX @@ read -P0 0x3fe0000 64k --- Testing COW --- write -P0xab 0 64k -{"return": ""} +{"return": {}} write -P0xad 0x00f8000 64k -{"return": ""} +{"return": {}} write -P0x1d 0x2008000 64k -{"return": ""} +{"return": {}} write -P0xea 0x3fe0000 64k -{"return": ""} +{"return": {}} --- Verifying Data --- @@ -XXX,XX +XXX,XX @@ read -P0 0x3fe0000 64k --- Testing COW --- write -P0xab 0 64k -{"return": ""} +{"return": {}} write -P0xad 0x00f8000 64k -{"return": ""} +{"return": {}} write -P0x1d 0x2008000 64k -{"return": ""} +{"return": {}} write -P0xea 0x3fe0000 64k -{"return": ""} +{"return": {}} --- Verifying Data --- @@ -XXX,XX +XXX,XX @@ read -P0xd5 1M 64k read -P0xdc 32M 64k read -P0xcd 0x3ff0000 64k read -P0 0x00f8000 32k -read failed: Invalid argument +qemu-io: read failed: Invalid argument read -P0 0x2010000 32k -read failed: Invalid argument +qemu-io: read failed: Invalid argument read -P0 0x3fe0000 64k -read failed: Invalid argument +qemu-io: read failed: Invalid argument --- Testing COW --- write -P0xab 0 64k -{"return": ""} +{"return": {}} write -P0xad 0x00f8000 64k -{"return": ""} +{"return": {}} write -P0x1d 0x2008000 64k -{"return": ""} +{"return": {}} write -P0xea 0x3fe0000 64k -{"return": ""} +{"return": {}} --- Verifying Data --- @@ -XXX,XX +XXX,XX @@ read -P0xd5 1M 64k read -P0xdc 32M 64k read -P0xcd 0x3ff0000 64k read -P0 0x00f8000 32k -read failed: Invalid argument +qemu-io: read failed: Invalid argument read -P0 0x2010000 32k -read failed: Invalid argument +qemu-io: read failed: Invalid argument read -P0 0x3fe0000 64k -read failed: Invalid argument +qemu-io: read failed: Invalid argument --- Cleanup --- @@ -XXX,XX +XXX,XX @@ Done --- Testing COW --- write -P0xab 0 64k -{"return": ""} +{"return": {}} write -P0xad 0x00f8000 64k -{"return": ""} +{"return": {}} write -P0x1d 0x2008000 64k -{"return": ""} +{"return": {}} write -P0xea 0x3fe0000 64k -{"return": ""} +{"return": {}} {"data": {"device": "push-backup", "len": 67108864, "offset": 67108864, "speed": 0, "type": "backup"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"return": {}} -- 2.54.0
Replace human-monitor-command wrapping of the HMP qemu-io command with direct x-qemu-io QMP calls in the two test cases that exercised corrupted image behavior through the monitor. The only output change is the QMP response: {"return": {}} (void) instead of {"return": ""} (empty HMP string). Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qemu-iotests/060 | 8 ++++---- tests/qemu-iotests/060.out | 2 +- tests/qemu-iotests/071 | 30 +++++++++++++++++------------ tests/qemu-iotests/071.out | 8 ++++---- tests/qemu-iotests/117 | 5 +++-- tests/qemu-iotests/117.out | 7 ++++--- tests/qemu-iotests/120 | 4 ++-- tests/qemu-iotests/120.out | 2 +- tests/qemu-iotests/156 | 36 +++++++++++++++++----------------- tests/qemu-iotests/156.out | 48 +++++++++++++++++++++++----------------------- tests/qemu-iotests/161 | 18 ++++++++--------- tests/qemu-iotests/161.out | 24 +++++++++++------------ tests/qemu-iotests/249 | 12 ++++++------ tests/qemu-iotests/249.out | 18 ++++++++--------- tests/qemu-iotests/283 | 4 ++-- tests/qemu-iotests/283.out | 4 ++-- 16 files changed, 119 insertions(+), 111 deletions(-) diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/060 +++ b/tests/qemu-iotests/060 @@ -XXX,XX +XXX,XX @@ echo _make_test_img 64M poke_file "$TEST_IMG" "$rt_offset" "\x00\x00\x00\x00\x00\x00\x00\x00" echo "{'execute': 'qmp_capabilities'} - {'execute': 'human-monitor-command', - 'arguments': {'command-line': 'qemu-io drive \"write 0 512\"'}} + {'execute': 'x-qemu-io', + 'arguments': {'device': 'drive', 'command': 'write 0 512'}} {'execute': 'quit'}" \ | $QEMU -qmp stdio -nographic -nodefaults \ -drive if=none,node-name=drive,file="$TEST_IMG",driver=qcow2 \ @@ -XXX,XX +XXX,XX @@ poke_file "$TEST_IMG" "$l1_offset" "\x00\x00\x00\x00\x2a\x2a\x2a\x2a" # Inactive images are effectively read-only images, so this should be a # non-fatal corruption (which does not modify the image) echo "{'execute': 'qmp_capabilities'} - {'execute': 'human-monitor-command', - 'arguments': {'command-line': 'qemu-io drive \"read 0 512\"'}} + {'execute': 'x-qemu-io', + 'arguments': {'device': 'drive', 'command': 'read 0 512'}} {'execute': 'quit'}" \ | $QEMU -qmp stdio -nographic -nodefaults \ -blockdev "{'node-name': 'drive', diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/060.out +++ b/tests/qemu-iotests/060.out @@ -XXX,XX +XXX,XX @@ qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps QMP_VERSION {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_IMAGE_CORRUPTED", "data": {"device": "none0", "msg": "Preventing invalid write on metadata (overlaps with refcount table)", "offset": 65536, "node-name": "drive", "fatal": true, "size": 65536}} -{"return": "Error: write failed: Input/output error\r\n"} +{"error": {"class": "GenericError", "desc": "write failed: Input/output error"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} {"return": {}} diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/071 +++ b/tests/qemu-iotests/071 @@ -XXX,XX +XXX,XX @@ run_qemu <<EOF } } } -{ "execute": "human-monitor-command", +{ "execute": "x-qemu-io", "arguments": { - "command-line": 'qemu-io drive0-debug "read 0 512"' + "device": "drive0-debug", + "command": "read 0 512" } } { "execute": "quit" } @@ -XXX,XX +XXX,XX @@ run_qemu <<EOF } } } -{ "execute": "human-monitor-command", +{ "execute": "x-qemu-io", "arguments": { - "command-line": 'qemu-io drive0-verify "read 0 512"' + "device": "drive0-verify", + "command": "read 0 512" } } { "execute": "quit" } @@ -XXX,XX +XXX,XX @@ run_qemu <<EOF "raw": "drive0" } } -{ "execute": "human-monitor-command", +{ "execute": "x-qemu-io", "arguments": { - "command-line": 'qemu-io drive0-verify "read 0 512"' + "device": "drive0-verify", + "command": "read 0 512" } } { "execute": "quit" } @@ -XXX,XX +XXX,XX @@ run_qemu <<EOF } } } -{ "execute": "human-monitor-command", +{ "execute": "x-qemu-io", "arguments": { - "command-line": 'qemu-io drive0-debug "read 0 512"' + "device": "drive0-debug", + "command": "read 0 512" } } -{ "execute": "human-monitor-command", +{ "execute": "x-qemu-io", "arguments": { - "command-line": 'qemu-io drive0-debug "write 0 512"' + "device": "drive0-debug", + "command": "write 0 512" } } -{ "execute": "human-monitor-command", +{ "execute": "x-qemu-io", "arguments": { - "command-line": 'qemu-io drive0-debug "read 0 512"' + "device": "drive0-debug", + "command": "read 0 512" } } { "execute": "quit" } diff --git a/tests/qemu-iotests/071.out b/tests/qemu-iotests/071.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/071.out +++ b/tests/qemu-iotests/071.out @@ -XXX,XX +XXX,XX @@ QMP_VERSION {"return": {}} {"return": {}} {"return": {}} -{"return": "Error: read failed: Input/output error\r\n"} +{"error": {"class": "GenericError", "desc": "read failed: Input/output error"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} {"return": {}} @@ -XXX,XX +XXX,XX @@ QMP_VERSION {"return": {}} read 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -{"return": ""} +{"return": {}} wrote 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -{"return": ""} -{"return": "Error: read failed: Input/output error\r\n"} +{"return": {}} +{"error": {"class": "GenericError", "desc": "read failed: Input/output error"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} QEMU_PROG: Failed to flush the L2 table cache: Input/output error QEMU_PROG: Failed to flush the refcount block cache: Input/output error diff --git a/tests/qemu-iotests/117 b/tests/qemu-iotests/117 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/117 +++ b/tests/qemu-iotests/117 @@ -XXX,XX +XXX,XX @@ _send_qemu_cmd $QEMU_HANDLE \ 'return' _send_qemu_cmd $QEMU_HANDLE \ - "{ 'execute': 'human-monitor-command', - 'arguments': { 'command-line': 'qemu-io format \"write -P 42 0 64k\"' } }" \ + "{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'format', + 'command': 'write -P 42 0 64k' } }" \ 'return' _send_qemu_cmd $QEMU_HANDLE \ diff --git a/tests/qemu-iotests/117.out b/tests/qemu-iotests/117.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/117.out +++ b/tests/qemu-iotests/117.out @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65536 'driver': 'IMGFMT', 'file': 'protocol' } } {"return": {}} -{ 'execute': 'human-monitor-command', - 'arguments': { 'command-line': 'qemu-io format "write -P 42 0 64k"' } } +{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'format', + 'command': 'write -P 42 0 64k' } } wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -{"return": ""} +{"return": {}} { 'execute': 'quit' } {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} {"return": {}} diff --git a/tests/qemu-iotests/120 b/tests/qemu-iotests/120 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/120 +++ b/tests/qemu-iotests/120 @@ -XXX,XX +XXX,XX @@ _require_drivers raw _make_test_img 64M echo "{'execute': 'qmp_capabilities'} - {'execute': 'human-monitor-command', - 'arguments': {'command-line': 'qemu-io drv \"write -P 42 0 64k\"'}} + {'execute': 'x-qemu-io', + 'arguments': {'device': 'drv', 'command': 'write -P 42 0 64k'}} {'execute': 'quit'}" \ | $QEMU -qmp stdio -nographic -nodefaults \ -drive id=drv,if=none,file="$TEST_IMG",driver=raw,file.driver=$IMGFMT \ diff --git a/tests/qemu-iotests/120.out b/tests/qemu-iotests/120.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/120.out +++ b/tests/qemu-iotests/120.out @@ -XXX,XX +XXX,XX @@ QMP_VERSION {"return": {}} wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -{"return": ""} +{"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} {"return": {}} read 65536/65536 bytes at offset 0 diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/156 +++ b/tests/qemu-iotests/156 @@ -XXX,XX +XXX,XX @@ _send_qemu_cmd $QEMU_HANDLE \ # Write something to the snapshot _send_qemu_cmd $QEMU_HANDLE \ - "{ 'execute': 'human-monitor-command', - 'arguments': { 'command-line': - 'qemu-io source \"write -P 3 128k 128k\"' } }" \ + "{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'source', + 'command': 'write -P 3 128k 128k' } }" \ 'return' # Create target image @@ -XXX,XX +XXX,XX @@ _send_qemu_cmd $QEMU_HANDLE \ # Write some more _send_qemu_cmd $QEMU_HANDLE \ - "{ 'execute': 'human-monitor-command', - 'arguments': { 'command-line': - 'qemu-io source \"write -P 4 192k 64k\"' } }" \ + "{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'source', + 'command': 'write -P 4 192k 64k' } }" \ 'return' # Copy source backing chain to the target before completing the job @@ -XXX,XX +XXX,XX @@ echo # Check online disk contents _send_qemu_cmd $QEMU_HANDLE \ - "{ 'execute': 'human-monitor-command', - 'arguments': { 'command-line': - 'qemu-io source \"read -P 1 0k 64k\"' } }" \ + "{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'source', + 'command': 'read -P 1 0k 64k' } }" \ 'return' _send_qemu_cmd $QEMU_HANDLE \ - "{ 'execute': 'human-monitor-command', - 'arguments': { 'command-line': - 'qemu-io source \"read -P 2 64k 64k\"' } }" \ + "{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'source', + 'command': 'read -P 2 64k 64k' } }" \ 'return' _send_qemu_cmd $QEMU_HANDLE \ - "{ 'execute': 'human-monitor-command', - 'arguments': { 'command-line': - 'qemu-io source \"read -P 3 128k 64k\"' } }" \ + "{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'source', + 'command': 'read -P 3 128k 64k' } }" \ 'return' _send_qemu_cmd $QEMU_HANDLE \ - "{ 'execute': 'human-monitor-command', - 'arguments': { 'command-line': - 'qemu-io source \"read -P 4 192k 64k\"' } }" \ + "{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'source', + 'command': 'read -P 4 192k 64k' } }" \ 'return' echo diff --git a/tests/qemu-iotests/156.out b/tests/qemu-iotests/156.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/156.out +++ b/tests/qemu-iotests/156.out @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT.overlay', fmt=IMGFMT size=1048576 backing_file=TES 'format': 'IMGFMT', 'mode': 'existing' } } {"return": {}} -{ 'execute': 'human-monitor-command', - 'arguments': { 'command-line': - 'qemu-io source "write -P 3 128k 128k"' } } +{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'source', + 'command': 'write -P 3 128k 128k' } } wrote 131072/131072 bytes at offset 131072 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -{"return": ""} +{"return": {}} Formatting 'TEST_DIR/t.IMGFMT.target.overlay', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.target backing_fmt=IMGFMT { 'execute': 'drive-mirror', 'arguments': { 'device': 'source', @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT.target.overlay', fmt=IMGFMT size=1048576 backing_f {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "source"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "source", "len": 131072, "offset": 131072, "speed": 0, "type": "mirror"}} -{ 'execute': 'human-monitor-command', - 'arguments': { 'command-line': - 'qemu-io source "write -P 4 192k 64k"' } } +{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'source', + 'command': 'write -P 4 192k 64k' } } wrote 65536/65536 bytes at offset 196608 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -{"return": ""} +{"return": {}} { 'execute': 'block-job-complete', 'arguments': { 'device': 'source' } } {"return": {}} @@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 196608 {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "source"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "source"}} -{ 'execute': 'human-monitor-command', - 'arguments': { 'command-line': - 'qemu-io source "read -P 1 0k 64k"' } } +{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'source', + 'command': 'read -P 1 0k 64k' } } read 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -{"return": ""} -{ 'execute': 'human-monitor-command', - 'arguments': { 'command-line': - 'qemu-io source "read -P 2 64k 64k"' } } +{"return": {}} +{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'source', + 'command': 'read -P 2 64k 64k' } } read 65536/65536 bytes at offset 65536 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -{"return": ""} -{ 'execute': 'human-monitor-command', - 'arguments': { 'command-line': - 'qemu-io source "read -P 3 128k 64k"' } } +{"return": {}} +{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'source', + 'command': 'read -P 3 128k 64k' } } read 65536/65536 bytes at offset 131072 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -{"return": ""} -{ 'execute': 'human-monitor-command', - 'arguments': { 'command-line': - 'qemu-io source "read -P 4 192k 64k"' } } +{"return": {}} +{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'source', + 'command': 'read -P 4 192k 64k' } } read 65536/65536 bytes at offset 196608 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -{"return": ""} +{"return": {}} { 'execute': 'quit' } {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} diff --git a/tests/qemu-iotests/161 b/tests/qemu-iotests/161 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/161 +++ b/tests/qemu-iotests/161 @@ -XXX,XX +XXX,XX @@ _send_qemu_cmd $QEMU_HANDLE \ 'return' _send_qemu_cmd $QEMU_HANDLE \ - "{ 'execute': 'human-monitor-command', - 'arguments': { 'command-line': - 'qemu-io none0 \"reopen -o backing.detect-zeroes=on\"' } }" \ + "{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'none0', + 'command': 'reopen -o backing.detect-zeroes=on' } }" \ "return" _cleanup_qemu @@ -XXX,XX +XXX,XX @@ _send_qemu_cmd $QEMU_HANDLE \ sleep 0.5 _send_qemu_cmd $QEMU_HANDLE \ - "{ 'execute': 'human-monitor-command', - 'arguments': { 'command-line': - 'qemu-io none0 \"reopen -o backing.detect-zeroes=on\"' } }" \ + "{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'none0', + 'command': 'reopen -o backing.detect-zeroes=on' } }" \ "return" _cleanup_qemu @@ -XXX,XX +XXX,XX @@ _send_qemu_cmd $QEMU_HANDLE \ sleep 0.5 _send_qemu_cmd $QEMU_HANDLE \ - "{ 'execute': 'human-monitor-command', - 'arguments': { 'command-line': - 'qemu-io none0 \"reopen -o backing.detect-zeroes=on\"' } }" \ + "{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'none0', + 'command': 'reopen -o backing.detect-zeroes=on' } }" \ "return" _cleanup_qemu diff --git a/tests/qemu-iotests/161.out b/tests/qemu-iotests/161.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/161.out +++ b/tests/qemu-iotests/161.out @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t. { 'execute': 'qmp_capabilities' } {"return": {}} -{ 'execute': 'human-monitor-command', - 'arguments': { 'command-line': - 'qemu-io none0 "reopen -o backing.detect-zeroes=on"' } } -{"return": ""} +{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'none0', + 'command': 'reopen -o backing.detect-zeroes=on' } } +{"return": {}} *** Stream and then change an option on the backing file @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t. {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "none0"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "none0"}} {"return": {}} -{ 'execute': 'human-monitor-command', - 'arguments': { 'command-line': - 'qemu-io none0 "reopen -o backing.detect-zeroes=on"' } } +{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'none0', + 'command': 'reopen -o backing.detect-zeroes=on' } } {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "none0"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "none0"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "none0", "len": 1048576, "offset": 1048576, "speed": 0, "type": "stream"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "none0"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "none0"}} -{"return": ""} +{"return": {}} *** Commit and then change an option on the backing file @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t. {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "none0"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "none0"}} {"return": {}} -{ 'execute': 'human-monitor-command', - 'arguments': { 'command-line': - 'qemu-io none0 "reopen -o backing.detect-zeroes=on"' } } +{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'none0', + 'command': 'reopen -o backing.detect-zeroes=on' } } {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "none0"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "none0"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "none0", "len": 1048576, "offset": 1048576, "speed": 0, "type": "commit"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "none0"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "none0"}} -{"return": ""} +{"return": {}} *** done diff --git a/tests/qemu-iotests/249 b/tests/qemu-iotests/249 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/249 +++ b/tests/qemu-iotests/249 @@ -XXX,XX +XXX,XX @@ echo echo '=== Send a write command to a drive opened in read-only mode (1)' echo _send_qemu_cmd $QEMU_HANDLE \ - "{ 'execute': 'human-monitor-command', - 'arguments': {'command-line': 'qemu-io none0 \"aio_write 0 2k\"'}}" \ + "{ 'execute': 'x-qemu-io', + 'arguments': {'device': 'none0', 'command': 'aio_write 0 2k'}}" \ 'return' echo @@ -XXX,XX +XXX,XX @@ echo echo '=== Send a write command to a drive opened in read-only mode (2)' echo _send_qemu_cmd $QEMU_HANDLE \ - "{ 'execute': 'human-monitor-command', - 'arguments': {'command-line': 'qemu-io none0 \"aio_write 0 2k\"'}}" \ + "{ 'execute': 'x-qemu-io', + 'arguments': {'device': 'none0', 'command': 'aio_write 0 2k'}}" \ 'return' echo @@ -XXX,XX +XXX,XX @@ echo echo '=== Send a write command to a drive opened in read-only mode (3)' echo _send_qemu_cmd $QEMU_HANDLE \ - "{ 'execute': 'human-monitor-command', - 'arguments': {'command-line': 'qemu-io none0 \"aio_write 0 2k\"'}}" \ + "{ 'execute': 'x-qemu-io', + 'arguments': {'device': 'none0', 'command': 'aio_write 0 2k'}}" \ 'return' _cleanup_qemu diff --git a/tests/qemu-iotests/249.out b/tests/qemu-iotests/249.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/249.out +++ b/tests/qemu-iotests/249.out @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t. === Send a write command to a drive opened in read-only mode (1) -{ 'execute': 'human-monitor-command', - 'arguments': {'command-line': 'qemu-io none0 "aio_write 0 2k"'}} -{"return": "Error: Block node is read-onlyrn"} +{ 'execute': 'x-qemu-io', + 'arguments': {'device': 'none0', 'command': 'aio_write 0 2k'}} +{"error": {"class": "GenericError", "desc": "Block node is read-only"}} === Run block-commit on base using an invalid filter node name @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t. === Send a write command to a drive opened in read-only mode (2) -{ 'execute': 'human-monitor-command', - 'arguments': {'command-line': 'qemu-io none0 "aio_write 0 2k"'}} -{"return": "Error: Block node is read-onlyrn"} +{ 'execute': 'x-qemu-io', + 'arguments': {'device': 'none0', 'command': 'aio_write 0 2k'}} +{"error": {"class": "GenericError", "desc": "Block node is read-only"}} === Run block-commit on base using the default filter node name @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t. === Send a write command to a drive opened in read-only mode (3) -{ 'execute': 'human-monitor-command', - 'arguments': {'command-line': 'qemu-io none0 "aio_write 0 2k"'}} -{"return": "Error: Block node is read-onlyrn"} +{ 'execute': 'x-qemu-io', + 'arguments': {'device': 'none0', 'command': 'aio_write 0 2k'}} +{"error": {"class": "GenericError", "desc": "Block node is read-only"}} *** done diff --git a/tests/qemu-iotests/283 b/tests/qemu-iotests/283 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/283 +++ b/tests/qemu-iotests/283 @@ -XXX,XX +XXX,XX @@ vm.event_wait('BLOCK_JOB_COMPLETED', 5.0) # The filter should be gone now. Check that by trying to access it # with qemu-io (which will most likely crash qemu if it is still # there.). -vm.qmp_log('human-monitor-command', - command_line='qemu-io backup-filter "write 0 1M"') +vm.qmp_log('x-qemu-io', + device='backup-filter', command='write 0 1M') # (Also, do an explicit check.) assert vm.node_info('backup-filter') is None diff --git a/tests/qemu-iotests/283.out b/tests/qemu-iotests/283.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/283.out +++ b/tests/qemu-iotests/283.out @@ -XXX,XX +XXX,XX @@ {"return": {}} {"execute": "job-finalize", "arguments": {"id": "backup"}} {"return": {}} -{"execute": "human-monitor-command", "arguments": {"command-line": "qemu-io backup-filter \"write 0 1M\""}} -{"return": "Error: Cannot find device='' nor node-name='backup-filter'\r\n"} +{"execute": "x-qemu-io", "arguments": {"command": "write 0 1M", "device": "backup-filter"}} +{"error": {"class": "GenericError", "desc": "Cannot find device='' nor node-name='backup-filter'"}} {"execute": "job-dismiss", "arguments": {"id": "backup"}} {"return": {}} -- 2.54.0
Convert tests 181 and 192 from HMP monitor commands to QMP: - Remove qemu_comm_method="monitor" and add qmp_capabilities negotiation. - Replace HMP commands (qemu-io, migrate_set_capability, migrate_set_parameter, migrate, info migrate, nbd_server_start, nbd_server_add, quit) with their QMP equivalents (x-qemu-io, migrate-set-capabilities, migrate-set-parameters, migrate, query-migrate, nbd-server-start, nbd-server-add, quit). Unlike human-monitor-command which wraps errors inside {"return": "Error: ..."}, x-qemu-io returns errors as a proper QMP {"error": ...} response. Match 'return\|error' on x-qemu-io calls so the test terminates on both success and failure, rather than hanging until timeout. Apply the same fix to test 249. Remove the HMP output drain idiom (send empty command, wait for prompt) after query-migrate polling in test 181. In QMP, an empty line produces no response, so this would hang. Capture the RESUME event delivered on the destination QMP channel after postcopy migration completes. This event was not visible in HMP mode. Update expected output for all three tests. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qemu-iotests/181 | 99 ++++++++++++++++++++++++++++++++++------------ tests/qemu-iotests/181.out | 36 ++++++++++++----- tests/qemu-iotests/192 | 22 +++++++++-- tests/qemu-iotests/192.out | 17 ++++++-- tests/qemu-iotests/249 | 6 +-- 5 files changed, 134 insertions(+), 46 deletions(-) diff --git a/tests/qemu-iotests/181 b/tests/qemu-iotests/181 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/181 +++ b/tests/qemu-iotests/181 @@ -XXX,XX +XXX,XX @@ echo echo === Starting VMs === echo -qemu_comm_method="monitor" - if [ "$IMGOPTSSYNTAX" = "true" ]; then _launch_qemu \ -drive "${TEST_IMG}",cache=${CACHEMODE},aio=$AIOMODE,id=disk @@ -XXX,XX +XXX,XX @@ else fi dest=$QEMU_HANDLE +_send_qemu_cmd $src \ + "{ 'execute': 'qmp_capabilities' }" \ + 'return' + +_send_qemu_cmd $dest \ + "{ 'execute': 'qmp_capabilities' }" \ + 'return' + echo echo === Write something on the source === echo silent= -_send_qemu_cmd $src 'qemu-io disk "write -P 0x55 0 64k"' "(qemu)" -_send_qemu_cmd $src "" "ops/sec" -_send_qemu_cmd $src 'qemu-io disk "read -P 0x55 0 64k"' "(qemu)" -_send_qemu_cmd $src "" "ops/sec" +_send_qemu_cmd $src \ + "{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'disk', + 'command': 'write -P 0x55 0 64k' } }" \ + 'return\|error' + +_send_qemu_cmd $src \ + "{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'disk', + 'command': 'read -P 0x55 0 64k' } }" \ + 'return\|error' echo echo === Do postcopy migration to destination === @@ -XXX,XX +XXX,XX @@ echo # switch to postcopy # Enable postcopy-ram capability both on source and destination silent=yes -_send_qemu_cmd $dest 'migrate_set_capability postcopy-ram on' "(qemu)" - qemu_error_no_exit=yes success_or_failure=yes \ - _send_qemu_cmd $dest '' "(qemu)" "Postcopy is not supported" -if [ ${QEMU_STATUS[$dest]} -lt 0 ]; then - _send_qemu_cmd $dest '' "(qemu)" + _send_qemu_cmd $dest \ + "{ 'execute': 'migrate-set-capabilities', + 'arguments': { 'capabilities': [ + { 'capability': 'postcopy-ram', 'state': true } ] } }" \ + 'return' 'error' - _send_qemu_cmd $src 'quit' "" - _send_qemu_cmd $dest 'quit' "" +if [ ${QEMU_STATUS[$dest]} -lt 0 ]; then + _send_qemu_cmd $src \ + "{ 'execute': 'quit' }" \ + 'return' + _send_qemu_cmd $dest \ + "{ 'execute': 'quit' }" \ + 'return' wait=1 _cleanup_qemu _notrun 'Postcopy is not supported' fi -_send_qemu_cmd $src 'migrate_set_parameter max-bandwidth 4k' "(qemu)" -_send_qemu_cmd $src 'migrate_set_capability postcopy-ram on' "(qemu)" -_send_qemu_cmd $src "migrate -d unix:${MIG_SOCKET}" "(qemu)" -_send_qemu_cmd $src 'migrate_start_postcopy' "(qemu)" +_send_qemu_cmd $src \ + "{ 'execute': 'migrate-set-parameters', + 'arguments': { 'max-bandwidth': 4096 } }" \ + 'return' + +_send_qemu_cmd $src \ + "{ 'execute': 'migrate-set-capabilities', + 'arguments': { 'capabilities': [ + { 'capability': 'postcopy-ram', 'state': true } ] } }" \ + 'return' + +_send_qemu_cmd $src \ + "{ 'execute': 'migrate', + 'arguments': { 'uri': 'unix:${MIG_SOCKET}' } }" \ + 'return' + +_send_qemu_cmd $src \ + "{ 'execute': 'migrate-start-postcopy' }" \ + 'return' QEMU_COMM_TIMEOUT=1 qemu_cmd_repeat=10 silent=yes \ - _send_qemu_cmd $src "info migrate" "completed\|failed" -silent=yes _send_qemu_cmd $src "" "(qemu)" + _send_qemu_cmd $src \ + "{ 'execute': 'query-migrate' }" \ + "completed\|failed" echo echo === Do some I/O on the destination === @@ -XXX,XX +XXX,XX @@ echo # of the node name, which would create a new BlockBackend and not test whether # the guest has the necessary permissions to access the image now silent= -_send_qemu_cmd $dest 'qemu-io disk "read -P 0x55 0 64k"' "(qemu)" -_send_qemu_cmd $dest "" "ops/sec" -_send_qemu_cmd $dest 'qemu-io disk "write -P 0x66 1M 64k"' "(qemu)" -_send_qemu_cmd $dest "" "ops/sec" +capture_events="RESUME" +_send_qemu_cmd $dest \ + "{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'disk', + 'command': 'read -P 0x55 0 64k' } }" \ + 'return\|error' +capture_events= + +_send_qemu_cmd $dest \ + "{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'disk', + 'command': 'write -P 0x66 1M 64k' } }" \ + 'return\|error' echo echo === Shut down and check image === echo -_send_qemu_cmd $src 'quit' "" -_send_qemu_cmd $dest 'quit' "" +_send_qemu_cmd $src \ + "{ 'execute': 'quit' }" \ + 'return' + +_send_qemu_cmd $dest \ + "{ 'execute': 'quit' }" \ + 'return' + wait=1 _cleanup_qemu _check_test_img diff --git a/tests/qemu-iotests/181.out b/tests/qemu-iotests/181.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/181.out +++ b/tests/qemu-iotests/181.out @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 === Starting VMs === +{ 'execute': 'qmp_capabilities' } +{"return": {}} +{ 'execute': 'qmp_capabilities' } +{"return": {}} === Write something on the source === -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qemu-io disk "write -P 0x55 0 64k" +{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'disk', + 'command': 'write -P 0x55 0 64k' } } wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -(qemu) -(qemu) qemu-io disk "read -P 0x55 0 64k" +{"return": {}} +{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'disk', + 'command': 'read -P 0x55 0 64k' } } read 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": {}} === Do postcopy migration to destination === === Do some I/O on the destination === -(qemu) qemu-io disk "read -P 0x55 0 64k" +{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'disk', + 'command': 'read -P 0x55 0 64k' } } read 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -(qemu) -(qemu) qemu-io disk "write -P 0x66 1M 64k" +{"return": {}} +{ 'execute': 'x-qemu-io', + 'arguments': { 'device': 'disk', + 'command': 'write -P 0x66 1M 64k' } } wrote 65536/65536 bytes at offset 1048576 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": {}} === Shut down and check image === -(qemu) quit -(qemu) -(qemu) quit +{ 'execute': 'quit' } +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} +{"return": {}} +{ 'execute': 'quit' } +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} +{"return": {}} No errors were found on the image. *** done diff --git a/tests/qemu-iotests/192 b/tests/qemu-iotests/192 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/192 +++ b/tests/qemu-iotests/192 @@ -XXX,XX +XXX,XX @@ else DRIVE_ARG=if=ide,id=drive0,format=$IMGFMT,file=$TEST_IMG fi -qemu_comm_method="monitor" _launch_qemu -drive $DRIVE_ARG -incoming defer h=$QEMU_HANDLE if [ "${VALGRIND_QEMU}" == "y" ]; then @@ -XXX,XX +XXX,XX @@ else QEMU_COMM_TIMEOUT=1 fi -_send_qemu_cmd $h "nbd_server_start unix:$SOCK_DIR/nbd" "(qemu)" -_send_qemu_cmd $h "nbd_server_add -w drive0" "(qemu)" -_send_qemu_cmd $h "q" "(qemu)" +_send_qemu_cmd $h \ + "{ 'execute': 'qmp_capabilities' }" \ + 'return' + +_send_qemu_cmd $h \ + "{ 'execute': 'nbd-server-start', + 'arguments': { 'addr': { 'type': 'unix', + 'data': { 'path': '$SOCK_DIR/nbd' } } } }" \ + 'return' + +_send_qemu_cmd $h \ + "{ 'execute': 'nbd-server-add', + 'arguments': { 'device': 'drive0', 'writable': true } }" \ + 'return' + +_send_qemu_cmd $h \ + "{ 'execute': 'quit' }" \ + 'return' # success, all done echo "*** done" diff --git a/tests/qemu-iotests/192.out b/tests/qemu-iotests/192.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/192.out +++ b/tests/qemu-iotests/192.out @@ -XXX,XX +XXX,XX @@ QA output created by 192 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) nbd_server_start unix:SOCK_DIR/nbd -(qemu) nbd_server_add -w drive0 -(qemu) q +{ 'execute': 'qmp_capabilities' } +{"return": {}} +{ 'execute': 'nbd-server-start', + 'arguments': { 'addr': { 'type': 'unix', + 'data': { 'path': 'SOCK_DIR/nbd' } } } } +{"return": {}} +{ 'execute': 'nbd-server-add', + 'arguments': { 'device': 'drive0', 'writable': true } } +{"return": {}} +{ 'execute': 'quit' } +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "drive0"}} +{"return": {}} *** done diff --git a/tests/qemu-iotests/249 b/tests/qemu-iotests/249 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/249 +++ b/tests/qemu-iotests/249 @@ -XXX,XX +XXX,XX @@ echo _send_qemu_cmd $QEMU_HANDLE \ "{ 'execute': 'x-qemu-io', 'arguments': {'device': 'none0', 'command': 'aio_write 0 2k'}}" \ - 'return' + 'return\|error' echo echo '=== Run block-commit on base using an invalid filter node name' @@ -XXX,XX +XXX,XX @@ echo _send_qemu_cmd $QEMU_HANDLE \ "{ 'execute': 'x-qemu-io', 'arguments': {'device': 'none0', 'command': 'aio_write 0 2k'}}" \ - 'return' + 'return\|error' echo echo '=== Run block-commit on base using the default filter node name' @@ -XXX,XX +XXX,XX @@ echo _send_qemu_cmd $QEMU_HANDLE \ "{ 'execute': 'x-qemu-io', 'arguments': {'device': 'none0', 'command': 'aio_write 0 2k'}}" \ - 'return' + 'return\|error' _cleanup_qemu -- 2.54.0
Replace HMP 'info block' with QMP 'query-block' so the test works with --disable-hmp builds. Use -qmp stdio instead of -monitor stdio, send JSON commands via printf, and filter with _filter_qmp and _filter_qmp_empty_return instead of _filter_hmp. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qemu-iotests/186 | 20 +-- tests/qemu-iotests/186.out | 440 +++++++++++---------------------------------- 2 files changed, 108 insertions(+), 352 deletions(-) diff --git a/tests/qemu-iotests/186 b/tests/qemu-iotests/186 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/186 +++ b/tests/qemu-iotests/186 @@ -XXX,XX +XXX,XX @@ #!/usr/bin/env bash # group: rw auto # -# Test 'info block' with all kinds of configurations +# Test 'query-block' with all kinds of configurations # # Copyright (C) 2017 Red Hat, Inc. # @@ -XXX,XX +XXX,XX @@ do_run_qemu() { echo Testing: "$@" - ( - if ! test -t 0; then - while read cmd; do - echo $cmd - done - fi - echo quit - ) | $QEMU -S -display none -device virtio-scsi-pci -monitor stdio "$@" 2>&1 + printf '{"execute":"qmp_capabilities"}\n{"execute":"query-block"}\n{"execute":"quit"}\n' | + $QEMU -S -display none -device virtio-scsi-pci -monitor none -qmp stdio "$@" 2>&1 echo } check_info_block() { - echo "info block" | - do_run_qemu "$@" | _filter_win32 | _filter_hmp | _filter_qemu | - _filter_generated_node_ids | _filter_qom_path + do_run_qemu "$@" | _filter_win32 | _filter_qemu | _filter_qmp | + _filter_qmp_empty_return | + grep -v '"event"' | + _filter_generated_node_ids | + sed 's/device\[[0-9]\+\]/device[N]/g' } diff --git a/tests/qemu-iotests/186.out b/tests/qemu-iotests/186.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/186.out +++ b/tests/qemu-iotests/186.out @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 === Empty drives === Testing: -device floppy -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -/machine/peripheral-anon/device[1]: [not inserted] - Attached to: /machine/peripheral-anon/device[N] - Removable device: not locked, tray closed -(qemu) quit +QMP_VERSION +{"return": [{"device": "", "locked": false, "removable": true, "qdev": "/machine/peripheral-anon/device[N]", "type": "unknown"}]} Testing: -device floppy,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -qdev_id: [not inserted] - Attached to: qdev_id - Removable device: not locked, tray closed -(qemu) quit +QMP_VERSION +{"return": [{"device": "", "locked": false, "removable": true, "qdev": "qdev_id", "type": "unknown"}]} Testing: -device ide-cd -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -/machine/peripheral-anon/device[1]: [not inserted] - Attached to: /machine/peripheral-anon/device[N] - Removable device: not locked, tray closed -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "", "locked": false, "removable": true, "qdev": "/machine/peripheral-anon/device[N]", "tray_open": false, "type": "unknown"}]} Testing: -device ide-cd,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -qdev_id: [not inserted] - Attached to: qdev_id - Removable device: not locked, tray closed -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "", "locked": false, "removable": true, "qdev": "qdev_id", "tray_open": false, "type": "unknown"}]} Testing: -device scsi-cd -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -/machine/peripheral-anon/device[1]: [not inserted] - Attached to: /machine/peripheral-anon/device[N] - Removable device: not locked, tray closed -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "", "locked": false, "removable": true, "qdev": "/machine/peripheral-anon/device[N]", "tray_open": false, "type": "unknown"}]} Testing: -device scsi-cd,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -qdev_id: [not inserted] - Attached to: qdev_id - Removable device: not locked, tray closed -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "", "locked": false, "removable": true, "qdev": "qdev_id", "tray_open": false, "type": "unknown"}]} === -blockdev/-device=<node-name> === Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device ide-hd,drive=null -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -null: json:{"read-zeroes": true, "driver": "null-co"} (null-co) - Attached to: /machine/peripheral-anon/device[N] - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}"}, "qdev": "/machine/peripheral-anon/device[N]", "type": "unknown"}]} Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device ide-hd,drive=null,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -null: json:{"read-zeroes": true, "driver": "null-co"} (null-co) - Attached to: qdev_id - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}"}, "qdev": "qdev_id", "type": "unknown"}]} Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device scsi-hd,drive=null -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -null: json:{"read-zeroes": true, "driver": "null-co"} (null-co) - Attached to: /machine/peripheral-anon/device[N] - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}"}, "qdev": "/machine/peripheral-anon/device[N]", "type": "unknown"}]} Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device scsi-hd,drive=null,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -null: json:{"read-zeroes": true, "driver": "null-co"} (null-co) - Attached to: qdev_id - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}"}, "qdev": "qdev_id", "type": "unknown"}]} Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device virtio-blk-pci,drive=null -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -null: json:{"read-zeroes": true, "driver": "null-co"} (null-co) - Attached to: /machine/peripheral-anon/device[N]/virtio-backend - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}"}, "qdev": "/machine/peripheral-anon/device[N]/virtio-backend", "type": "unknown"}]} Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device virtio-blk-pci,drive=null,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -null: json:{"read-zeroes": true, "driver": "null-co"} (null-co) - Attached to: /machine/peripheral/qdev_id/virtio-backend - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}"}, "qdev": "/machine/peripheral/qdev_id/virtio-backend", "type": "unknown"}]} Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device floppy,drive=null -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -null: json:{"read-zeroes": true, "driver": "null-co"} (null-co) - Attached to: /machine/peripheral-anon/device[N] - Removable device: not locked, tray closed - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"device": "", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}"}, "qdev": "/machine/peripheral-anon/device[N]", "type": "unknown"}]} Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device floppy,drive=null,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -null: json:{"read-zeroes": true, "driver": "null-co"} (null-co) - Attached to: qdev_id - Removable device: not locked, tray closed - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"device": "", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}"}, "qdev": "qdev_id", "type": "unknown"}]} Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device ide-cd,drive=null -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -null: json:{"read-zeroes": true, "driver": "null-co"} (null-co) - Attached to: /machine/peripheral-anon/device[N] - Removable device: not locked, tray closed - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}"}, "qdev": "/machine/peripheral-anon/device[N]", "tray_open": false, "type": "unknown"}]} Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device ide-cd,drive=null,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -null: json:{"read-zeroes": true, "driver": "null-co"} (null-co) - Attached to: qdev_id - Removable device: not locked, tray closed - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}"}, "qdev": "qdev_id", "tray_open": false, "type": "unknown"}]} Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device scsi-cd,drive=null -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -null: json:{"read-zeroes": true, "driver": "null-co"} (null-co) - Attached to: /machine/peripheral-anon/device[N] - Removable device: not locked, tray closed - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}"}, "qdev": "/machine/peripheral-anon/device[N]", "tray_open": false, "type": "unknown"}]} Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device scsi-cd,drive=null,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -null: json:{"read-zeroes": true, "driver": "null-co"} (null-co) - Attached to: qdev_id - Removable device: not locked, tray closed - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": true, \"driver\": \"null-co\"}"}, "qdev": "qdev_id", "tray_open": false, "type": "unknown"}]} === -drive if=none/-device=<node-name> === Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device ide-hd,drive=null,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Removable device: not locked, tray closed - Cache mode: writeback - -null: json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Attached to: qdev_id - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"device": "none0", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "type": "unknown"}, {"io-status": "ok", "device": "", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "vi rtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "qdev_id", "type": "unknown"}]} Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device scsi-hd,drive=null,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Removable device: not locked, tray closed - Cache mode: writeback - -null: json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Attached to: qdev_id - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"device": "none0", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "type": "unknown"}, {"io-status": "ok", "device": "", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "vi rtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "qdev_id", "type": "unknown"}]} Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device virtio-blk-pci,drive=null,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Removable device: not locked, tray closed - Cache mode: writeback - -null: json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Attached to: /machine/peripheral/qdev_id/virtio-backend - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"device": "none0", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "type": "unknown"}, {"io-status": "ok", "device": "", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "vi rtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "/machine/peripheral/qdev_id/virtio-backend", "type": "unknown"}]} Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device floppy,drive=null,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Removable device: not locked, tray closed - Cache mode: writeback - -null: json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Attached to: qdev_id - Removable device: not locked, tray closed - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"device": "none0", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "type": "unknown"}, {"device": "", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741 824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "qdev_id", "type": "unknown"}]} Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device ide-cd,drive=null,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Removable device: not locked, tray closed - Cache mode: writeback - -null: json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Attached to: qdev_id - Removable device: not locked, tray closed - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"device": "none0", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "type": "unknown"}, {"io-status": "ok", "device": "", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "vir tual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "qdev_id", "tray_open": false, "type": "unknown"}]} Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device scsi-cd,drive=null,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Removable device: not locked, tray closed - Cache mode: writeback - -null: json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Attached to: qdev_id - Removable device: not locked, tray closed - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"device": "none0", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "type": "unknown"}, {"io-status": "ok", "device": "", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "vir tual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "qdev_id", "tray_open": false, "type": "unknown"}]} === -drive if=none/-device=<bb-name> (with medium) === Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device ide-hd,drive=none0 -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Attached to: /machine/peripheral-anon/device[N] - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "none0", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "/machine/peripheral-anon/device[N]", "type": "unknown"}]} Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device ide-hd,drive=none0,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Attached to: qdev_id - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "none0", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "qdev_id", "type": "unknown"}]} Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device scsi-hd,drive=none0 -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Attached to: /machine/peripheral-anon/device[N] - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "none0", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "/machine/peripheral-anon/device[N]", "type": "unknown"}]} Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device scsi-hd,drive=none0,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Attached to: qdev_id - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "none0", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "qdev_id", "type": "unknown"}]} Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device virtio-blk-pci,drive=none0 -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Attached to: /machine/peripheral-anon/device[N]/virtio-backend - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "none0", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "/machine/peripheral-anon/device[N]/virtio-backend", "type": "unknown"}]} Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device virtio-blk-pci,drive=none0,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Attached to: /machine/peripheral/qdev_id/virtio-backend - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "none0", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "/machine/peripheral/qdev_id/virtio-backend", "type": "unknown"}]} Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device floppy,drive=none0 -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Attached to: /machine/peripheral-anon/device[N] - Removable device: not locked, tray closed - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"device": "none0", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "/machine/peripheral-anon/device[N]", "type": "unknown"}]} Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device floppy,drive=none0,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Attached to: qdev_id - Removable device: not locked, tray closed - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"device": "none0", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "qdev_id", "type": "unknown"}]} Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device ide-cd,drive=none0 -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Attached to: /machine/peripheral-anon/device[N] - Removable device: not locked, tray closed - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "none0", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "/machine/peripheral-anon/device[N]", "tray_open": false, "type": "unknown"}]} Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device ide-cd,drive=none0,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Attached to: qdev_id - Removable device: not locked, tray closed - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "none0", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "qdev_id", "tray_open": false, "type": "unknown"}]} Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device scsi-cd,drive=none0 -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Attached to: /machine/peripheral-anon/device[N] - Removable device: not locked, tray closed - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "none0", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "/machine/peripheral-anon/device[N]", "tray_open": false, "type": "unknown"}]} Testing: -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device scsi-cd,drive=none0,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Attached to: qdev_id - Removable device: not locked, tray closed - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "none0", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "null", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "qdev_id", "tray_open": false, "type": "unknown"}]} === -drive if=none/-device=<bb-name> (without medium) === Testing: -drive if=none -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0: [not inserted] - Removable device: not locked, tray closed -(qemu) quit +QMP_VERSION +{"return": [{"device": "none0", "locked": false, "removable": true, "type": "unknown"}]} Testing: -drive if=none -device floppy,drive=none0 -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0: [not inserted] - Attached to: /machine/peripheral-anon/device[N] - Removable device: not locked, tray closed -(qemu) quit +QMP_VERSION +{"return": [{"device": "none0", "locked": false, "removable": true, "qdev": "/machine/peripheral-anon/device[N]", "type": "unknown"}]} Testing: -drive if=none -device floppy,drive=none0,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0: [not inserted] - Attached to: qdev_id - Removable device: not locked, tray closed -(qemu) quit +QMP_VERSION +{"return": [{"device": "none0", "locked": false, "removable": true, "qdev": "qdev_id", "type": "unknown"}]} Testing: -drive if=none -device ide-cd,drive=none0 -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0: [not inserted] - Attached to: /machine/peripheral-anon/device[N] - Removable device: not locked, tray closed -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "none0", "locked": false, "removable": true, "qdev": "/machine/peripheral-anon/device[N]", "tray_open": false, "type": "unknown"}]} Testing: -drive if=none -device ide-cd,drive=none0,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0: [not inserted] - Attached to: qdev_id - Removable device: not locked, tray closed -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "none0", "locked": false, "removable": true, "qdev": "qdev_id", "tray_open": false, "type": "unknown"}]} Testing: -drive if=none -device scsi-cd,drive=none0 -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0: [not inserted] - Attached to: /machine/peripheral-anon/device[N] - Removable device: not locked, tray closed -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "none0", "locked": false, "removable": true, "qdev": "/machine/peripheral-anon/device[N]", "tray_open": false, "type": "unknown"}]} Testing: -drive if=none -device scsi-cd,drive=none0,id=qdev_id -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -none0: [not inserted] - Attached to: qdev_id - Removable device: not locked, tray closed -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "none0", "locked": false, "removable": true, "qdev": "qdev_id", "tray_open": false, "type": "unknown"}]} === -drive if=... === Testing: -drive if=floppy -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -floppy0: [not inserted] - Attached to: /machine/unattached/device[N] - Removable device: not locked, tray closed -(qemu) quit +QMP_VERSION +{"return": [{"device": "floppy0", "locked": false, "removable": true, "qdev": "/machine/unattached/device[N]", "type": "unknown"}]} Testing: -drive if=floppy,driver=null-co,read-zeroes=on -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -floppy0 (NODE_NAME): json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Attached to: /machine/unattached/device[N] - Removable device: not locked, tray closed - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"device": "floppy0", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "NODE_NAME", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "/machine/unattached/device[N]", "type": "unknown"}]} Testing: -drive if=ide,driver=null-co,read-zeroes=on -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -ide0-hd0 (NODE_NAME): json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Attached to: /machine/unattached/device[N] - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "ide0-hd0", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "NODE_NAME", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "/machine/unattached/device[N]", "type": "unknown"}]} Testing: -drive if=ide,media=cdrom -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -ide0-cd0: [not inserted] - Attached to: /machine/unattached/device[N] - Removable device: not locked, tray closed -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "ide0-cd0", "locked": false, "removable": true, "qdev": "/machine/unattached/device[N]", "tray_open": false, "type": "unknown"}]} Testing: -drive if=ide,driver=null-co,read-zeroes=on,media=cdrom -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -ide0-cd0 (NODE_NAME): json:{"read-zeroes": "on", "driver": "null-co"} (null-co, read-only) - Attached to: /machine/unattached/device[N] - Removable device: not locked, tray closed - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "ide0-cd0", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": true, "children": [], "node-name": "NODE_NAME", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "/machine/unattached/device[N]", "tray_open": false, "type": "unknown"}]} Testing: -drive if=virtio,driver=null-co,read-zeroes=on -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -virtio0 (NODE_NAME): json:{"read-zeroes": "on", "driver": "null-co"} (null-co) - Attached to: /machine/peripheral-anon/device[N]/virtio-backend - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"io-status": "ok", "device": "virtio0", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1073741824, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "NODE_NAME", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\"}"}, "qdev": "/machine/peripheral-anon/device[N]/virtio-backend", "type": "unknown"}]} Testing: -drive if=pflash,driver=null-co,read-zeroes=on,size=1M -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) info block -pflash0 (NODE_NAME): json:{"read-zeroes": "on", "driver": "null-co", "size": "1M"} (null-co) - Attached to: /machine/system.flash0 - Cache mode: writeback -(qemu) quit +QMP_VERSION +{"return": [{"device": "pflash0", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "active": true, "image": {"limits": {"request-alignment": 1, "min-mem-alignment": 512, "opt-mem-alignment": 4096, "max-iov": 1024}, "virtual-size": 1048576, "filename": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\", \"size\": \"1M\"}", "format": "null-co", "actual-size": 0}, "iops_wr": 0, "ro": false, "children": [], "node-name": "NODE_NAME", "backing_file_depth": 0, "drv": "null-co", "iops": 0, "bps_wr": 0, "write_threshold": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "cache": {"no-flush": false, "direct": false, "writeback": true}, "file": "json:{\"read-zeroes\": \"on\", \"driver\": \"null-co\", \"size\": \"1M\"}"}, "qdev": "/machine/system.flash0", "type": "unknown"}]} *** done -- 2.54.0
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qemu-iotests/tests/copy-before-write | 42 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/tests/qemu-iotests/tests/copy-before-write b/tests/qemu-iotests/tests/copy-before-write index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/tests/copy-before-write +++ b/tests/qemu-iotests/tests/copy-before-write @@ -XXX,XX +XXX,XX @@ class TestCbwError(iotests.QMPTestCase): 'file': 'cbw' }) - result = self.vm.qmp('human-monitor-command', - command_line='qemu-io cbw "write 0 1M"') - write_res = result['return'] + result = self.vm.qmp('x-qemu-io', + device='cbw', command='write 0 1M') + write_res = result.get('error', {}).get('desc', '') - result = self.vm.qmp('human-monitor-command', - command_line='qemu-io access "read 0 1M"') - read_res = result['return'] + result = self.vm.qmp('x-qemu-io', + device='access', command='read 0 1M') + read_res = result.get('error', {}).get('desc', '') self.vm.shutdown() log = self.vm.get_log() @@ -XXX,XX +XXX,XX @@ class TestCbwError(iotests.QMPTestCase): 'file': 'cbw' }) - result = self.vm.qmp('human-monitor-command', - command_line='qemu-io cbw "write 0 1M"') - write_res = result['return'] + result = self.vm.qmp('x-qemu-io', + device='cbw', command='write 0 1M') + write_res = result.get('error', {}).get('desc', '') - result = self.vm.qmp('human-monitor-command', - command_line='qemu-io access "read 0 1M"') - read_res = result['return'] + result = self.vm.qmp('x-qemu-io', + device='access', command='read 0 1M') + read_res = result.get('error', {}).get('desc', '') self.vm.shutdown() log = self.vm.get_log() @@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 0 'file': 'cbw' }) - result = self.vm.qmp('human-monitor-command', - command_line='qemu-io cbw "write 0 512K"') - write1_res = result['return'] + result = self.vm.qmp('x-qemu-io', + device='cbw', command='write 0 512K') + write1_res = result.get('error', {}).get('desc', '') # We need second write to trigger throttling - result = self.vm.qmp('human-monitor-command', - command_line='qemu-io cbw "write 512K 512K"') - write2_res = result['return'] + result = self.vm.qmp('x-qemu-io', + device='cbw', command='write 512K 512K') + write2_res = result.get('error', {}).get('desc', '') - result = self.vm.qmp('human-monitor-command', - command_line='qemu-io access "read 0 1M"') - read_res = result['return'] + result = self.vm.qmp('x-qemu-io', + device='access', command='read 0 1M') + read_res = result.get('error', {}).get('desc', '') self.vm.shutdown() log = self.vm.get_log() -- 2.54.0
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qemu-iotests/172 | 5 +++++ tests/qemu-iotests/267 | 4 ++++ tests/qemu-iotests/common.rc | 7 +++++++ 3 files changed, 16 insertions(+) diff --git a/tests/qemu-iotests/172 b/tests/qemu-iotests/172 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/172 +++ b/tests/qemu-iotests/172 @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 . ./common.rc . ./common.filter +# HMP: info block & info qtree +# rewrite with qom-list/get + query-block is possible, +# but hardly in bash +_require_hmp + _supported_fmt qcow2 _supported_proto file _supported_os Linux diff --git a/tests/qemu-iotests/267 b/tests/qemu-iotests/267 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/267 +++ b/tests/qemu-iotests/267 @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 . ./common.rc . ./common.filter +# HMP: savevm/loadvm, info snapshots +# TODO: rewrite with QMP snapshot-save/load +_require_hmp + _supported_fmt qcow2 _supported_proto file _supported_os Linux diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -XXX,XX +XXX,XX @@ _require_secret() rm -f "$TEST_IMG" } +_require_hmp() +{ + if ! echo quit | $QEMU -M none -monitor stdio > /dev/null 2>&1; then + _notrun "HMP monitor not available" + fi +} + _qcow2_dump_header() { if [[ "$1" == "--no-filter-compression" ]]; then -- 2.54.0
Add a "qemu-io" command to the qtest protocol so that tests can issue block layer I/O commands without going through the HMP monitor's "human-monitor-command" QMP, or use QMP at all. Unfortunately, many tests will prefer to use QMP as they also monitor and log other events. It's easier if it is pipelined in the same stream. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qtest/libqtest.h | 11 +++++++++++ system/qtest.c | 14 ++++++++++++++ tests/qtest/libqtest.c | 14 ++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/libqtest.h +++ b/tests/qtest/libqtest.h @@ -XXX,XX +XXX,XX @@ char *qtest_hmp(QTestState *s, const char *fmt, ...) G_GNUC_PRINTF(2, 3); char *qtest_vhmp(QTestState *s, const char *fmt, va_list ap) G_GNUC_PRINTF(2, 0); +/** + * qtest_qemu_io: + * @s: #QTestState instance to operate on. + * @device: block device node-name or BlockBackend name. + * @fmt: qemu-io command to send, formats arguments like sprintf(). + * + * Send a qemu-io command via the qtest protocol. + */ +void qtest_qemu_io(QTestState *s, const char *device, + const char *fmt, ...) G_GNUC_PRINTF(3, 4); + void qtest_module_load(QTestState *s, const char *prefix, const char *libname); /** diff --git a/system/qtest.c b/system/qtest.c index XXXXXXX..XXXXXXX 100644 --- a/system/qtest.c +++ b/system/qtest.c @@ -XXX,XX +XXX,XX @@ #include "qemu/cutils.h" #include "qemu/target-info.h" #include "qom/object_interfaces.h" +#include "qapi-commands-block.h" #define MAX_IRQ 256 @@ -XXX,XX +XXX,XX @@ static void qtest_process_command(CharFrontend *chr, gchar **words) new_ns = qemu_clock_advance_virtual_time(ns); qtest_sendf(chr, "%s %"PRIi64"\n", new_ns == ns ? "OK" : "FAIL", new_ns); + } else if (strcmp(words[0], "qemu-io") == 0) { + const char *io_dev; + g_autofree char *io_cmd = NULL; + Error *err = NULL; + + g_assert(words[1] && words[2]); + io_dev = words[1]; + io_cmd = g_strjoinv(" ", &words[2]); + + qmp_x_qemu_io(io_dev, NULL, io_cmd, &err); + qtest_sendf(chr, err ? "FAIL %s\n" : "OK\n", + err ? error_get_pretty(err) : NULL); + error_free(err); } else if (process_command_cb && process_command_cb(chr, words)) { /* Command got consumed by the callback handler */ } else { diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -XXX,XX +XXX,XX @@ char *qtest_hmp(QTestState *s, const char *fmt, ...) return ret; } +void qtest_qemu_io(QTestState *s, const char *device, + const char *fmt, ...) +{ + va_list ap; + g_autofree char *cmd = NULL; + + va_start(ap, fmt); + cmd = g_strdup_vprintf(fmt, ap); + va_end(ap); + + qtest_sendf(s, "qemu-io %s %s\n", device, cmd); + qtest_rsp(s); +} + const char *qtest_get_arch(void) { /* -- 2.54.0
Depend on the previous commit to be accepted. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qtest/ide-test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qtest/ide-test.c b/tests/qtest/ide-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/ide-test.c +++ b/tests/qtest/ide-test.c @@ -XXX,XX +XXX,XX @@ static void test_flush(void) make_dirty(qts, 0); /* Delay the completion of the flush request until we explicitly do it */ - g_free(qtest_hmp(qts, "qemu-io ide0-hd0 \"break flush_to_os A\"")); + qtest_qemu_io(qts, "ide0-hd0", "break flush_to_os A"); /* FLUSH CACHE command on device 0*/ qpci_io_writeb(dev, ide_bar, reg_device, 0); @@ -XXX,XX +XXX,XX @@ static void test_flush(void) assert_bit_clear(data, DF | ERR | DRQ); /* Complete the command */ - g_free(qtest_hmp(qts, "qemu-io ide0-hd0 \"resume A\"")); + qtest_qemu_io(qts, "ide0-hd0", "resume A"); /* Check registers */ data = qpci_io_readb(dev, ide_bar, reg_device); -- 2.54.0
Convert the three test functions that relied on HMP "info numa" to use QMP "query-cpus-fast" instead, verifying each CPU's node-id through the structured response. Add a check_cpu_node() helper for the per-CPU assertions. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qtest/numa-test.c | 63 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/tests/qtest/numa-test.c b/tests/qtest/numa-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/numa-test.c +++ b/tests/qtest/numa-test.c @@ -XXX,XX +XXX,XX @@ static char *make_cli(const GString *generic_cli, const char *test_cli) return g_strdup_printf("%s %s", generic_cli->str, test_cli); } +static void check_cpu_node(QTestState *qts, int cpu_idx, int expected_node) +{ + QDict *resp; + QList *cpus; + QListEntry *e; + bool found = false; + + resp = qtest_qmp(qts, "{ 'execute': 'query-cpus-fast' }"); + g_assert(resp); + g_assert(qdict_haskey(resp, "return")); + cpus = qdict_get_qlist(resp, "return"); + g_assert(cpus); + + QLIST_FOREACH_ENTRY(cpus, e) { + QDict *cpu = qobject_to(QDict, qlist_entry_obj(e)); + int64_t idx = qdict_get_int(cpu, "cpu-index"); + if (idx == cpu_idx) { + QDict *props = qdict_get_qdict(cpu, "props"); + g_assert(qdict_haskey(props, "node-id")); + g_assert_cmpint(qdict_get_int(props, "node-id"), ==, expected_node); + found = true; + break; + } + } + g_assert(found); + qobject_unref(resp); +} + static void test_mon_explicit(const void *data) { QTestState *qts; - g_autofree char *s = NULL; g_autofree char *cli = NULL; + int i; cli = make_cli(data, "-machine smp.cpus=8 -numa node,nodeid=0,memdev=ram,cpus=0-3 " "-numa node,nodeid=1,cpus=4-7"); qts = qtest_init(cli); - s = qtest_hmp(qts, "info numa"); - g_assert(strstr(s, "node 0 cpus: 0 1 2 3")); - g_assert(strstr(s, "node 1 cpus: 4 5 6 7")); + for (i = 0; i < 4; i++) { + check_cpu_node(qts, i, 0); + } + for (i = 4; i < 8; i++) { + check_cpu_node(qts, i, 1); + } qtest_quit(qts); } @@ -XXX,XX +XXX,XX @@ static void test_mon_explicit(const void *data) static void test_def_cpu_split(const void *data) { QTestState *qts; - g_autofree char *s = NULL; g_autofree char *cli = NULL; + int even_cpus[] = {0, 2, 4, 6}; + int odd_cpus[] = {1, 3, 5, 7}; + int i; cli = make_cli(data, "-machine smp.cpus=8,smp.sockets=8 " "-numa node,memdev=ram -numa node"); qts = qtest_init(cli); - s = qtest_hmp(qts, "info numa"); - g_assert(strstr(s, "node 0 cpus: 0 2 4 6")); - g_assert(strstr(s, "node 1 cpus: 1 3 5 7")); + for (i = 0; i < 4; i++) { + check_cpu_node(qts, even_cpus[i], 0); + check_cpu_node(qts, odd_cpus[i], 1); + } qtest_quit(qts); } @@ -XXX,XX +XXX,XX @@ static void test_def_cpu_split(const void *data) static void test_mon_partial(const void *data) { QTestState *qts; - g_autofree char *s = NULL; g_autofree char *cli = NULL; + int node0_cpus[] = {0, 1, 2, 3, 6, 7}; + int node1_cpus[] = {4, 5}; + int i; cli = make_cli(data, "-machine smp.cpus=8 " "-numa node,nodeid=0,memdev=ram,cpus=0-1 " "-numa node,nodeid=1,cpus=4-5 "); qts = qtest_init(cli); - s = qtest_hmp(qts, "info numa"); - g_assert(strstr(s, "node 0 cpus: 0 1 2 3 6 7")); - g_assert(strstr(s, "node 1 cpus: 4 5")); + for (i = 0; i < 6; i++) { + check_cpu_node(qts, node0_cpus[i], 0); + } + for (i = 0; i < 2; i++) { + check_cpu_node(qts, node1_cpus[i], 1); + } qtest_quit(qts); } -- 2.54.0
The pnv-xive2-test and pnv-host-i2c-test pass "-serial mon:stdio" but never use HMP commands. The "mon:" chardev prefix creates an HMP monitor mux, which fails when HMP is disabled. Other pnv tests (e.g. pnv-spi-seeprom-test) don't specify -serial at all. Drop the unnecessary -serial mon:stdio option. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qtest/pnv-host-i2c-test.c | 2 +- tests/qtest/pnv-xive2-test.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qtest/pnv-host-i2c-test.c b/tests/qtest/pnv-host-i2c-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/pnv-host-i2c-test.c +++ b/tests/qtest/pnv-host-i2c-test.c @@ -XXX,XX +XXX,XX @@ static void test_host_i2c(const void *data) } qts = qtest_initf("-M %s -smp %d,cores=1,threads=%d -nographic " - "-nodefaults -serial mon:stdio -S " + "-nodefaults -S " "-d guest_errors", machine, SMT, SMT); diff --git a/tests/qtest/pnv-xive2-test.c b/tests/qtest/pnv-xive2-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/pnv-xive2-test.c +++ b/tests/qtest/pnv-xive2-test.c @@ -XXX,XX +XXX,XX @@ static void test_xive(void) QTestState *qts; qts = qtest_initf("-M powernv10 -smp %d,cores=1,threads=%d -nographic " - "-nodefaults -serial mon:stdio -S " + "-nodefaults -S " "-d guest_errors -trace '*xive*'", SMT, SMT); init_xive(qts); -- 2.54.0
Add a structured x-query-network QMP command that returns network configuration as a NetworkInfo struct with pre-grouped hub information and a flat list of non-hub clients. Each hub includes its ports with inlined peer client info, and each client includes attached netfilter details. Refactor hmp_info_network() to consume only the QMP result instead of directly accessing internal net_clients state. This decouples HMP from internal data structures, making it possible to remove HMP support without losing programmatic network introspection. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- qapi/net.json | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++ include/net/net.h | 3 +- net/hub.h | 4 +- net/hub.c | 29 +++++++------ net/net-hmp-cmds.c | 59 +++++++++++++++++++------- net/net.c | 70 +++++++++++++++++++++++------- 6 files changed, 243 insertions(+), 44 deletions(-) diff --git a/qapi/net.json b/qapi/net.json index XXXXXXX..XXXXXXX 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -XXX,XX +XXX,XX @@ 'returns': ['UsernetInfo'], 'if': 'CONFIG_SLIRP', 'features': [ 'unstable' ] } + +## +# @NetFilterInfo: +# +# Information about a netfilter attached to a network client. +# +# @name: filter object name (QOM path component) +# +# @type: QOM type name (e.g. "filter-mirror") +# +# @info: filter properties as comma-separated key=value pairs +# (excluding @type) +# +# Since: 11.1 +## +{ 'struct': 'NetFilterInfo', + 'data': { + 'name': 'str', + 'type': 'str', + 'info': 'str' } } + +## +# @NetworkClientInfo: +# +# Information about a network client. +# +# @name: unique network client identifier +# +# @queue-index: index of this queue (0 for single-queue clients) +# +# @type: network client driver type +# +# @info-str: driver-specific formatted information string (e.g. +# "model=e1000,macaddr=52:54:00:12:34:56") +# +# @peer: the connected peer client (always a leaf; the peer's own +# peer field is never populated) +# +# @filters: attached netfilters +# +# Since: 11.1 +## +{ 'struct': 'NetworkClientInfo', + 'data': { + 'name': 'str', + 'queue-index': 'uint32', + 'type': 'NetClientDriver', + 'info-str': 'str', + '*peer': 'NetworkClientInfo', + 'filters': ['NetFilterInfo'] } } + +## +# @NetHubPortInfo: +# +# Information about a hub port. +# +# @name: hub port identifier +# +# @peer: the network client connected through this port +# +# Since: 11.1 +## +{ 'struct': 'NetHubPortInfo', + 'data': { + 'name': 'str', + '*peer': 'NetworkClientInfo' } } + +## +# @NetHubInfo: +# +# Information about a network hub. +# +# @id: hub identifier +# +# @ports: list of ports on this hub +# +# Since: 11.1 +## +{ 'struct': 'NetHubInfo', + 'data': { + 'id': 'int', + 'ports': ['NetHubPortInfo'] } } + +## +# @NetworkInfo: +# +# Information about the network configuration. +# +# @hubs: network hubs and their ports +# +# @clients: network clients not associated with a hub +# +# Since: 11.1 +## +{ 'struct': 'NetworkInfo', + 'data': { + 'hubs': ['NetHubInfo'], + 'clients': ['NetworkClientInfo'] } } + +## +# @x-query-network: +# +# Query the network configuration including hubs and clients. +# +# Features: +# +# @unstable: This command is meant for debugging. +# +# Returns: @NetworkInfo describing hubs and clients. +# +# Since: 11.1 +# +# .. qmp-example:: +# +# -> { "execute": "x-query-network" } +# <- { "return": { "clients": [ { "name": "st0", +# "queue-index": 0, "type": "stream", +# "info-str": "listening" } ] } } +## +{ 'command': 'x-query-network', + 'returns': 'NetworkInfo', + 'features': [ 'unstable' ] } diff --git a/include/net/net.h b/include/net/net.h index XXXXXXX..XXXXXXX 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -XXX,XX +XXX,XX @@ DeviceState *qemu_create_nic_device(const char *typename, bool match_default, void qemu_create_nic_bus_devices(BusState *bus, const char *parent_type, const char *default_model, const char *alias, const char *alias_target); -void print_net_client(Monitor *mon, NetClientState *nc); void net_socket_rs_init(SocketReadState *rs, SocketReadStateFinalize *finalize, bool vnet_hdr); @@ -XXX,XX +XXX,XX @@ void netdev_add(QemuOpts *opts, Error **errp); int net_hub_id_for_client(NetClientState *nc, int *id); +NetworkClientInfo *net_client_info(NetClientState *nc); + #define DEFAULT_NETWORK_SCRIPT CONFIG_SYSCONFDIR "/qemu-ifup" #define DEFAULT_NETWORK_DOWN_SCRIPT CONFIG_SYSCONFDIR "/qemu-ifdown" #define DEFAULT_BRIDGE_HELPER CONFIG_QEMU_HELPERDIR "/qemu-bridge-helper" diff --git a/net/hub.h b/net/hub.h index XXXXXXX..XXXXXXX 100644 --- a/net/hub.h +++ b/net/hub.h @@ -XXX,XX +XXX,XX @@ #ifndef NET_HUB_H #define NET_HUB_H +#include "qapi/qapi-types-net.h" + NetClientState *net_hub_add_port(int hub_id, const char *name, NetClientState *hubpeer); -void net_hub_info(Monitor *mon); void net_hub_check_clients(void); bool net_hub_flush(NetClientState *nc); +NetHubInfoList *net_hub_query_info(void); #endif /* NET_HUB_H */ diff --git a/net/hub.c b/net/hub.c index XXXXXXX..XXXXXXX 100644 --- a/net/hub.c +++ b/net/hub.c @@ -XXX,XX +XXX,XX @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "monitor/monitor.h" +#include "qapi/util.h" #include "net/net.h" #include "clients.h" #include "hub.h" @@ -XXX,XX +XXX,XX @@ NetClientState *net_hub_add_port(int hub_id, const char *name, return &port->nc; } -/** - * Print hub configuration - */ -void net_hub_info(Monitor *mon) +NetHubInfoList *net_hub_query_info(void) { + NetHubInfoList *head = NULL, **tail = &head; NetHub *hub; - NetHubPort *port; QLIST_FOREACH(hub, &hubs, next) { - monitor_printf(mon, "hub %d\n", hub->id); + NetHubInfo *hi = g_new0(NetHubInfo, 1); + NetHubPortInfoList **ptail = &hi->ports; + NetHubPort *port; + + hi->id = hub->id; + QLIST_FOREACH(port, &hub->ports, next) { - monitor_printf(mon, " \\ %s", port->nc.name); + NetHubPortInfo *pi = g_new0(NetHubPortInfo, 1); + pi->name = g_strdup(port->nc.name); if (port->nc.peer) { - monitor_printf(mon, ": "); - print_net_client(mon, port->nc.peer); - } else { - monitor_printf(mon, "\n"); + pi->peer = net_client_info(port->nc.peer); } + QAPI_LIST_APPEND(ptail, pi); } + + QAPI_LIST_APPEND(tail, hi); } + + return head; } /** diff --git a/net/net-hmp-cmds.c b/net/net-hmp-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/net/net-hmp-cmds.c +++ b/net/net-hmp-cmds.c @@ -XXX,XX +XXX,XX @@ #include "monitor/hmp-completion.h" #include "monitor/monitor.h" #include "net/net.h" -#include "net/hub.h" #include "qapi/clone-visitor.h" #include "qapi/qapi-commands-net.h" #include "qapi/qapi-visit-net.h" +#include "qapi/error.h" #include "qobject/qdict.h" #include "qemu/config-file.h" #include "qemu/help_option.h" #include "qemu/option.h" -void hmp_info_network(Monitor *mon, const QDict *qdict) +static void hmp_print_client_info(Monitor *mon, NetworkClientInfo *ci) { - NetClientState *nc, *peer; - NetClientDriver type; + NetFilterInfoList *f; + + monitor_printf(mon, "%s: index=%" PRIu32 ",type=%s,%s\n", + ci->name, ci->queue_index, + NetClientDriver_str(ci->type), ci->info_str); + if (ci->filters) { + monitor_printf(mon, "filters:\n"); + for (f = ci->filters; f; f = f->next) { + monitor_printf(mon, " - %s: type=%s%s%s\n", + f->value->name, f->value->type, + f->value->info[0] ? "," : "", f->value->info); + } + } +} - net_hub_info(mon); +void hmp_info_network(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + g_autoptr(NetworkInfo) info = qmp_x_query_network(&err); + NetHubInfoList *h; + NetworkClientInfoList *entry; - QTAILQ_FOREACH(nc, &net_clients, next) { - peer = nc->peer; - type = nc->info->type; + if (hmp_handle_error(mon, err)) { + return; + } - /* Skip if already printed in hub info */ - if (net_hub_id_for_client(nc, NULL) == 0) { - continue; + for (h = info->hubs; h; h = h->next) { + NetHubPortInfoList *p; + + monitor_printf(mon, "hub %d\n", (int)h->value->id); + for (p = h->value->ports; p; p = p->next) { + if (p->value->peer) { + monitor_printf(mon, " \\ %s: ", p->value->name); + hmp_print_client_info(mon, p->value->peer); + } else { + monitor_printf(mon, " \\ %s\n", p->value->name); + } } + } + + for (entry = info->clients; entry; entry = entry->next) { + NetworkClientInfo *ci = entry->value; - if (!peer || type == NET_CLIENT_DRIVER_NIC) { - print_net_client(mon, nc); + if (!ci->peer || ci->type == NET_CLIENT_DRIVER_NIC) { + hmp_print_client_info(mon, ci); } /* else it's a netdev connected to a NIC, printed with the NIC */ - if (peer && type == NET_CLIENT_DRIVER_NIC) { + if (ci->peer && ci->type == NET_CLIENT_DRIVER_NIC) { monitor_printf(mon, " \\ "); - print_net_client(mon, peer); + hmp_print_client_info(mon, ci->peer); } } } diff --git a/net/net.c b/net/net.c index XXXXXXX..XXXXXXX 100644 --- a/net/net.c +++ b/net/net.c @@ -XXX,XX +XXX,XX @@ void qmp_netdev_del(const char *id, Error **errp) } } -static void netfilter_print_info(Monitor *mon, NetFilterState *nf) +static char *netfilter_get_info_str(NetFilterState *nf) { char *str; ObjectProperty *prop; ObjectPropertyIterator iter; Visitor *v; + GString *buf = g_string_new(NULL); - /* generate info str */ object_property_iter_init(&iter, OBJECT(nf)); while ((prop = object_property_iter_next(&iter))) { if (!strcmp(prop->name, "type")) { @@ -XXX,XX +XXX,XX @@ static void netfilter_print_info(Monitor *mon, NetFilterState *nf) object_property_get(OBJECT(nf), prop->name, v, NULL); visit_complete(v, &str); visit_free(v); - monitor_printf(mon, ",%s=%s", prop->name, str); + if (buf->len > 0) { + g_string_append_c(buf, ','); + } + g_string_append_printf(buf, "%s=%s", prop->name, str); g_free(str); } - monitor_printf(mon, "\n"); + + return g_string_free(buf, false); } -void print_net_client(Monitor *mon, NetClientState *nc) +static NetworkClientInfo *net_client_info_no_peer(NetClientState *nc) { + NetworkClientInfo *info = g_new0(NetworkClientInfo, 1); NetFilterState *nf; - monitor_printf(mon, "%s: index=%d,type=%s,%s\n", nc->name, - nc->queue_index, - NetClientDriver_str(nc->info->type), - nc->info_str); + info->name = g_strdup(nc->name); + info->queue_index = nc->queue_index; + info->type = nc->info->type; + info->info_str = g_strdup(nc->info_str); + if (!QTAILQ_EMPTY(&nc->filters)) { - monitor_printf(mon, "filters:\n"); + NetFilterInfoList **ftail = &info->filters; + QTAILQ_FOREACH(nf, &nc->filters, next) { + NetFilterInfo *fi = g_new0(NetFilterInfo, 1); + fi->name = g_strdup( + object_get_canonical_path_component(OBJECT(nf))); + fi->type = g_strdup(object_get_typename(OBJECT(nf))); + fi->info = netfilter_get_info_str(nf); + QAPI_LIST_APPEND(ftail, fi); + } } - QTAILQ_FOREACH(nf, &nc->filters, next) { - monitor_printf(mon, " - %s: type=%s", - object_get_canonical_path_component(OBJECT(nf)), - object_get_typename(OBJECT(nf))); - netfilter_print_info(mon, nf); + + return info; +} + +NetworkClientInfo *net_client_info(NetClientState *nc) +{ + NetworkClientInfo *info = net_client_info_no_peer(nc); + + if (nc->peer) { + info->peer = net_client_info_no_peer(nc->peer); } + + return info; +} + +NetworkInfo *qmp_x_query_network(Error **errp) +{ + NetworkInfo *info = g_new0(NetworkInfo, 1); + NetworkClientInfoList **tail = &info->clients; + NetClientState *nc; + + info->hubs = net_hub_query_info(); + + QTAILQ_FOREACH(nc, &net_clients, next) { + /* Skip if already gathered in hub info */ + if (net_hub_id_for_client(nc, NULL) == 0) { + continue; + } + QAPI_LIST_APPEND(tail, net_client_info(nc)); + } + + return info; } RxFilterInfoList *qmp_query_rx_filter(const char *name, Error **errp) -- 2.54.0
Replace the HMP "info network" text parsing with the structured x-query-network QMP command. This makes the test assertions more robust by matching individual fields (info-str) instead of parsing the full HMP line format. The EXPECT_STATE macro now takes an explicit netdev id argument to look up the client by name in the QMP response. The strrchr truncation is made NULL-safe: if the truncation character is not found, the full string is compared (and the final g_assert_cmpstr will catch mismatches). While at it, fix the pre-existing duplicate "qemu/sockets.h" include, and reorder includes. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qtest/netdev-socket.c | 143 +++++++++++++++++++++++++------------------- 1 file changed, 82 insertions(+), 61 deletions(-) diff --git a/tests/qtest/netdev-socket.c b/tests/qtest/netdev-socket.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/netdev-socket.c +++ b/tests/qtest/netdev-socket.c @@ -XXX,XX +XXX,XX @@ */ #include "qemu/osdep.h" -#include "qemu/sockets.h" #include <glib/gstdio.h> #include "../unit/socket-helpers.h" #include "libqtest.h" -#include "qobject/qstring.h" -#include "qemu/sockets.h" -#include "qapi/qobject-input-visitor.h" #include "qapi/qapi-visit-sockets.h" +#include "qapi/qobject-input-visitor.h" +#include "qemu/sockets.h" +#include "qobject/qdict.h" +#include "qobject/qlist.h" +#include "qobject/qstring.h" #define CONNECTION_TIMEOUT 60 -#define EXPECT_STATE(q, e, t) \ -do { \ - char *resp = NULL; \ - g_test_timer_start(); \ - do { \ - g_free(resp); \ - resp = qtest_hmp(q, "info network"); \ - if (t) { \ - strrchr(resp, t)[0] = 0; \ - } \ - if (g_str_equal(resp, e)) { \ - break; \ - } \ - } while (g_test_timer_elapsed() < CONNECTION_TIMEOUT); \ - g_assert_cmpstr(resp, ==, e); \ - g_free(resp); \ +/* + * Only checks info-str; type is implicit from the netdev created by each test + */ +static char *query_net_info_str(QTestState *q, const char *name) +{ + QDict *ret; + QList *clients; + QListEntry *entry; + + ret = qtest_qmp_assert_success_ref(q, "{'execute': 'x-query-network'}"); + clients = qdict_get_qlist(ret, "clients"); + g_assert_nonnull(clients); + + QLIST_FOREACH_ENTRY(clients, entry) { + QDict *client = qobject_to(QDict, qlist_entry_obj(entry)); + if (g_str_equal(qdict_get_str(client, "name"), name)) { + char *info = g_strdup(qdict_get_str(client, "info-str")); + qobject_unref(ret); + return info; + } + } + + g_assert_not_reached(); +} + +#define EXPECT_STATE(q, id, e, t) \ +do { \ + char *info = NULL; \ + g_test_timer_start(); \ + do { \ + g_free(info); \ + info = query_net_info_str(q, id); \ + if (t) { \ + char *p = strrchr(info, t); \ + if (p) { \ + p[0] = 0; \ + } \ + } \ + if (g_str_equal(info, e)) { \ + break; \ + } \ + } while (g_test_timer_elapsed() < CONNECTION_TIMEOUT); \ + g_assert_cmpstr(info, ==, e); \ + g_free(info); \ } while (0) static gchar *tmpdir; @@ -XXX,XX +XXX,XX @@ static void test_stream_inet_ipv4(void) "addr.ipv4=on,addr.ipv6=off," "addr.host=127.0.0.1,addr.port=%d", port); - EXPECT_STATE(qts0, "st0: index=0,type=stream,listening\r\n", 0); + EXPECT_STATE(qts0, "st0", "listening", 0); qts1 = qtest_initf("-nodefaults -M none " "-netdev stream,server=false,id=st0,addr.type=inet," "addr.ipv4=on,addr.ipv6=off," "addr.host=127.0.0.1,addr.port=%d", port); - expect = g_strdup_printf("st0: index=0,type=stream,tcp:127.0.0.1:%d\r\n", - port); - EXPECT_STATE(qts1, expect, 0); + expect = g_strdup_printf("tcp:127.0.0.1:%d", port); + EXPECT_STATE(qts1, "st0", expect, 0); g_free(expect); /* the port is unknown, check only the address */ - EXPECT_STATE(qts0, "st0: index=0,type=stream,tcp:127.0.0.1", ':'); + EXPECT_STATE(qts0, "st0", "tcp:127.0.0.1", ':'); qtest_quit(qts1); qtest_quit(qts0); @@ -XXX,XX +XXX,XX @@ static void test_stream_unix_reconnect(void) "-netdev stream,id=st0,server=true,addr.type=unix," "addr.path=%s", path); - EXPECT_STATE(qts0, "st0: index=0,type=stream,listening\r\n", 0); + EXPECT_STATE(qts0, "st0", "listening", 0); qts1 = qtest_initf("-nodefaults -M none " "-netdev stream,server=false,id=st0,addr.type=unix," @@ -XXX,XX +XXX,XX @@ static void test_stream_inet_ipv6(void) "addr.ipv4=off,addr.ipv6=on," "addr.host=::1,addr.port=%d", port); - EXPECT_STATE(qts0, "st0: index=0,type=stream,listening\r\n", 0); + EXPECT_STATE(qts0, "st0", "listening", 0); qts1 = qtest_initf("-nodefaults -M none " "-netdev stream,server=false,id=st0,addr.type=inet," "addr.ipv4=off,addr.ipv6=on," "addr.host=::1,addr.port=%d", port); - expect = g_strdup_printf("st0: index=0,type=stream,tcp:::1:%d\r\n", - port); - EXPECT_STATE(qts1, expect, 0); + expect = g_strdup_printf("tcp:::1:%d", port); + EXPECT_STATE(qts1, "st0", expect, 0); g_free(expect); /* the port is unknown, check only the address */ - EXPECT_STATE(qts0, "st0: index=0,type=stream,tcp:::1", ':'); + EXPECT_STATE(qts0, "st0", "tcp:::1", ':'); qtest_quit(qts1); qtest_quit(qts0); @@ -XXX,XX +XXX,XX @@ static void test_stream_unix(void) "addr.type=unix,addr.path=%s,", path); - EXPECT_STATE(qts0, "st0: index=0,type=stream,listening\r\n", 0); + EXPECT_STATE(qts0, "st0", "listening", 0); qts1 = qtest_initf("-nodefaults -M none " "-netdev stream,id=st0,server=false," "addr.type=unix,addr.path=%s", path); - expect = g_strdup_printf("st0: index=0,type=stream,unix:%s\r\n", path); - EXPECT_STATE(qts1, expect, 0); - EXPECT_STATE(qts0, expect, 0); + expect = g_strdup_printf("unix:%s", path); + EXPECT_STATE(qts1, "st0", expect, 0); + EXPECT_STATE(qts0, "st0", expect, 0); g_free(expect); g_free(path); @@ -XXX,XX +XXX,XX @@ static void test_stream_unix_abstract(void) "addr.abstract=on", path); - EXPECT_STATE(qts0, "st0: index=0,type=stream,listening\r\n", 0); + EXPECT_STATE(qts0, "st0", "listening", 0); qts1 = qtest_initf("-nodefaults -M none " "-netdev stream,id=st0,server=false," "addr.type=unix,addr.path=%s,addr.abstract=on", path); - expect = g_strdup_printf("st0: index=0,type=stream,unix:%s\r\n", path); - EXPECT_STATE(qts1, expect, 0); - EXPECT_STATE(qts0, expect, 0); + expect = g_strdup_printf("unix:%s", path); + EXPECT_STATE(qts1, "st0", expect, 0); + EXPECT_STATE(qts0, "st0", expect, 0); g_free(expect); g_free(path); @@ -XXX,XX +XXX,XX @@ static void test_stream_fd(void) "-netdev stream,id=st0,addr.type=fd,addr.str=%d", sock[0]); - EXPECT_STATE(qts0, "st0: index=0,type=stream,unix:\r\n", 0); + EXPECT_STATE(qts0, "st0", "unix:", 0); qts1 = qtest_initf("-nodefaults -M none " "-netdev stream,id=st0,addr.type=fd,addr.str=%d", sock[1]); - EXPECT_STATE(qts1, "st0: index=0,type=stream,unix:\r\n", 0); - EXPECT_STATE(qts0, "st0: index=0,type=stream,unix:\r\n", 0); + EXPECT_STATE(qts1, "st0", "unix:", 0); + EXPECT_STATE(qts0, "st0", "unix:", 0); qtest_quit(qts1); qtest_quit(qts0); @@ -XXX,XX +XXX,XX @@ static void test_dgram_inet(void) "remote.type=inet,remote.host=127.0.0.1,remote.port=%d", port[0], port[1]); - expect = g_strdup_printf("st0: index=0,type=dgram," - "udp=127.0.0.1:%d/127.0.0.1:%d\r\n", + expect = g_strdup_printf("udp=127.0.0.1:%d/127.0.0.1:%d", port[0], port[1]); - EXPECT_STATE(qts0, expect, 0); + EXPECT_STATE(qts0, "st0", expect, 0); g_free(expect); qts1 = qtest_initf("-nodefaults -M none " @@ -XXX,XX +XXX,XX @@ static void test_dgram_inet(void) "remote.type=inet,remote.host=127.0.0.1,remote.port=%d", port[1], port[0]); - expect = g_strdup_printf("st0: index=0,type=dgram," - "udp=127.0.0.1:%d/127.0.0.1:%d\r\n", + expect = g_strdup_printf("udp=127.0.0.1:%d/127.0.0.1:%d", port[1], port[0]); - EXPECT_STATE(qts1, expect, 0); + EXPECT_STATE(qts1, "st0", expect, 0); g_free(expect); qtest_quit(qts1); @@ -XXX,XX +XXX,XX @@ static void test_dgram_mcast(void) "-netdev dgram,id=st0," "remote.type=inet,remote.host=230.0.0.1,remote.port=1234"); - EXPECT_STATE(qts, "st0: index=0,type=dgram,mcast=230.0.0.1:1234\r\n", 0); + EXPECT_STATE(qts, "st0", "mcast=230.0.0.1:1234", 0); qtest_quit(qts); } @@ -XXX,XX +XXX,XX @@ static void test_dgram_unix(void) "remote.type=unix,remote.path=%s", path0, path1); - expect = g_strdup_printf("st0: index=0,type=dgram,udp=%s:%s\r\n", - path0, path1); - EXPECT_STATE(qts0, expect, 0); + expect = g_strdup_printf("udp=%s:%s", path0, path1); + EXPECT_STATE(qts0, "st0", expect, 0); g_free(expect); qts1 = qtest_initf("-nodefaults -M none " @@ -XXX,XX +XXX,XX @@ static void test_dgram_unix(void) "remote.type=unix,remote.path=%s", path1, path0); - - expect = g_strdup_printf("st0: index=0,type=dgram,udp=%s:%s\r\n", - path1, path0); - EXPECT_STATE(qts1, expect, 0); + expect = g_strdup_printf("udp=%s:%s", path1, path0); + EXPECT_STATE(qts1, "st0", expect, 0); g_free(expect); unlink(path0); @@ -XXX,XX +XXX,XX @@ static void test_dgram_fd(void) "-netdev dgram,id=st0,local.type=fd,local.str=%d", sv[0]); - expect = g_strdup_printf("st0: index=0,type=dgram,fd=%d unix\r\n", sv[0]); - EXPECT_STATE(qts0, expect, 0); + expect = g_strdup_printf("fd=%d unix", sv[0]); + EXPECT_STATE(qts0, "st0", expect, 0); g_free(expect); qts1 = qtest_initf("-nodefaults -M none " "-netdev dgram,id=st0,local.type=fd,local.str=%d", sv[1]); - - expect = g_strdup_printf("st0: index=0,type=dgram,fd=%d unix\r\n", sv[1]); - EXPECT_STATE(qts1, expect, 0); + expect = g_strdup_printf("fd=%d unix", sv[1]); + EXPECT_STATE(qts1, "st0", expect, 0); g_free(expect); qtest_quit(qts1); -- 2.54.0
The test_cdrom_param() function uses qtest_hmp() to run "info block", which depends on the human-monitor-command QMP endpoint. Replace it with the QMP query-block command so the test works when HMP is disabled (-Dhmp=disabled). Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qtest/cdrom-test.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/tests/qtest/cdrom-test.c b/tests/qtest/cdrom-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/cdrom-test.c +++ b/tests/qtest/cdrom-test.c @@ -XXX,XX +XXX,XX @@ #include "libqtest.h" #include "boot-sector.h" #include "qobject/qdict.h" +#include "qobject/qlist.h" static char isoimage[] = "cdrom-boot-iso-XXXXXX"; @@ -XXX,XX +XXX,XX @@ cleanup: /** * Check that at least the -cdrom parameter is basically working, i.e. we can - * see the filename of the ISO image in the output of "info block" afterwards + * see the filename of the ISO image in the output of "query-block" afterwards */ static void test_cdrom_param(gconstpointer data) { QTestState *qts; - char *resp; + QDict *response; + QList *ret; + QListEntry *entry; + bool found = false; qts = qtest_initf("-M %s -cdrom %s", (const char *)data, isoimage); - resp = qtest_hmp(qts, "info block"); - g_assert(strstr(resp, isoimage) != 0); - g_free(resp); + response = qtest_qmp(qts, "{'execute': 'query-block'}"); + g_assert(response && qdict_haskey(response, "return")); + ret = qdict_get_qlist(response, "return"); + + QLIST_FOREACH_ENTRY(ret, entry) { + QDict *entry_dict = qobject_to(QDict, entry->value); + QDict *inserted = qdict_get_qdict(entry_dict, "inserted"); + if (inserted) { + const char *file = qdict_get_str(inserted, "file"); + if (file && strstr(file, isoimage)) { + found = true; + break; + } + } + } + + g_assert(found); + qobject_unref(response); qtest_quit(qts); } -- 2.54.0
The test was using 'human-monitor-command' (which requires HMP) to verify that an integer 'id' is echoed back on failure. Replace with 'query-name' for the success case and 'block_resize' (missing required args) for the failure case, so the test works regardless of HMP availability. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qtest/qmp-test.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/qtest/qmp-test.c b/tests/qtest/qmp-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/qmp-test.c +++ b/tests/qtest/qmp-test.c @@ -XXX,XX +XXX,XX @@ static void test_qmp_protocol(void) g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, "cookie#1"); qobject_unref(resp); - /* Test command failure with 'id' */ - resp = qtest_qmp(qts, "{ 'execute': 'human-monitor-command', 'id': 2 }"); + /* Test integer 'id' is echoed back on success */ + resp = qtest_qmp(qts, "{ 'execute': 'query-name', 'id': 2 }"); g_assert_cmpint(qdict_get_int(resp, "id"), ==, 2); + qobject_unref(resp); + + /* Test integer 'id' is echoed back on failure */ + resp = qtest_qmp(qts, "{ 'execute': 'block_resize', 'id': 3 }"); + g_assert_cmpint(qdict_get_int(resp, "id"), ==, 3); qmp_expect_error_and_unref(resp, "GenericError"); qtest_quit(qts); -- 2.54.0
Add an option to enable/disable HMP support, default to true. The following commits are going to make --disable-hmp gradually working. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- meson.build | 4 ++++ meson_options.txt | 2 ++ scripts/meson-buildoptions.sh | 3 +++ 3 files changed, 9 insertions(+) diff --git a/meson.build b/meson.build index XXXXXXX..XXXXXXX 100644 --- a/meson.build +++ b/meson.build @@ -XXX,XX +XXX,XX @@ have_vhost_net = have_vhost_net_kernel or have_vhost_net_user or have_vhost_net_ have_tcg = get_option('tcg').allowed() and (have_system or have_user) +have_hmp = get_option('hmp') \ + .disable_auto_if(not have_system) \ + .allowed() have_tools = get_option('tools') \ .disable_auto_if(not have_system) \ .allowed() @@ -XXX,XX +XXX,XX @@ endif config_host_data = configuration_data() config_host_data.set('CONFIG_HAVE_RUST', have_rust) +config_host_data.set('CONFIG_HMP', have_hmp) audio_drivers_selected = [] if have_system audio_drivers_available = { diff --git a/meson_options.txt b/meson_options.txt index XXXXXXX..XXXXXXX 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -XXX,XX +XXX,XX @@ option('cfi', type: 'boolean', value: false, description: 'Control-Flow Integrity (CFI)') option('cfi_debug', type: 'boolean', value: false, description: 'Verbose errors in case of CFI violation') +option('hmp', type : 'feature', value : 'auto', + description: 'HMP monitor support') option('multiprocess', type: 'feature', value: 'auto', description: 'Out of process device emulation support') option('relocatable', type : 'boolean', value : true, diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index XXXXXXX..XXXXXXX 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -XXX,XX +XXX,XX @@ meson_options_help() { printf "%s\n" ' gtk GTK+ user interface' printf "%s\n" ' guest-agent Build QEMU Guest Agent' printf "%s\n" ' guest-agent-msi Build MSI package for the QEMU Guest Agent' + printf "%s\n" ' hmp HMP monitor support' printf "%s\n" ' hv-balloon hv-balloon driver (requires Glib 2.68+ GTree API)' printf "%s\n" ' hvf HVF acceleration support' printf "%s\n" ' iconv Font glyph conversion support' @@ -XXX,XX +XXX,XX @@ _meson_option_parse() { --disable-guest-agent-msi) printf "%s" -Dguest_agent_msi=disabled ;; --enable-hexagon-idef-parser) printf "%s" -Dhexagon_idef_parser=true ;; --disable-hexagon-idef-parser) printf "%s" -Dhexagon_idef_parser=false ;; + --enable-hmp) printf "%s" -Dhmp=enabled ;; + --disable-hmp) printf "%s" -Dhmp=disabled ;; --enable-hv-balloon) printf "%s" -Dhv_balloon=enabled ;; --disable-hv-balloon) printf "%s" -Dhv_balloon=disabled ;; --enable-hvf) printf "%s" -Dhvf=enabled ;; -- 2.54.0
Replace "info qom-tree" with recursive qom-list walk. Disable HMP-only code paths, info qtree, kinda duplicating the test. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qtest/device-introspect-test.c | 111 +++++++++++++++++++++++++++-------- 1 file changed, 88 insertions(+), 23 deletions(-) diff --git a/tests/qtest/device-introspect-test.c b/tests/qtest/device-introspect-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/device-introspect-test.c +++ b/tests/qtest/device-introspect-test.c @@ -XXX,XX +XXX,XX @@ */ /* - * Covers QMP device-list-properties and HMP device_add help. We - * currently don't check that their output makes sense, only that QEMU - * survives. Useful since we've had an astounding number of crash - * bugs around here. + * Covers QMP device-list-properties and HMP device_add help (if + * CONFIG_HMP). We currently don't check that the output makes sense, + * only that QEMU survives. Useful since we've had an astounding + * number of crash bugs around here. */ #include "qemu/osdep.h" @@ -XXX,XX +XXX,XX @@ static QList *device_type_list(QTestState *qts, bool abstract) return qom_list_types(qts, "device", abstract); } +/* + * Recursively walk the QOM composition tree via qom-list and build a + * string representation. This serves two purposes: detecting dangling + * pointers (qom-list would crash QEMU) and detecting leaked objects + * (by comparing the output before and after device introspection). + */ +static void qom_tree_walk(QTestState *qts, const char *path, GString *result) +{ + QDict *resp; + QList *list; + QListEntry *e; + GList *children = NULL; + + resp = qtest_qmp(qts, "{'execute': 'qom-list'," + " 'arguments': {'path': %s}}", path); + g_assert(qdict_haskey(resp, "return")); + list = qdict_get_qlist(resp, "return"); + + QLIST_FOREACH_ENTRY(list, e) { + QDict *prop = qobject_to(QDict, qlist_entry_obj(e)); + const char *type = qdict_get_str(prop, "type"); + if (g_str_has_prefix(type, "child<")) { + const char *name = qdict_get_str(prop, "name"); + children = g_list_prepend(children, g_strdup(name)); + } + } + + children = g_list_sort_with_data(children, (GCompareDataFunc)g_strcmp0, + NULL); + + for (GList *l = children; l; l = l->next) { + const char *name = l->data; + g_autofree char *child_path = (!strcmp(path, "/")) + ? g_strdup_printf("/%s", name) + : g_strdup_printf("%s/%s", path, name); + + g_string_append_printf(result, "%s\n", child_path); + qom_tree_walk(qts, child_path, result); + } + + g_list_free_full(children, g_free); + qobject_unref(resp); +} + +static char *qom_tree_str(QTestState *qts) +{ + GString *result = g_string_new(""); + qom_tree_walk(qts, "/", result); + return g_string_free(result, FALSE); +} + static void test_one_device(QTestState *qts, const char *type) { QDict *resp; - char *help, *escaped; - GRegex *comma; g_test_message("Testing device '%s'", type); @@ -XXX,XX +XXX,XX @@ static void test_one_device(QTestState *qts, const char *type) type); qobject_unref(resp); - comma = g_regex_new(",", 0, 0, NULL); - escaped = g_regex_replace_literal(comma, type, -1, 0, ",,", 0, NULL); - g_regex_unref(comma); +#ifdef CONFIG_HMP + { + g_autofree char *escaped = NULL; + g_autoptr(GRegex) comma = NULL; - help = qtest_hmp(qts, "device_add \"%s,help\"", escaped); - g_free(help); - g_free(escaped); + comma = g_regex_new(",", 0, 0, NULL); + escaped = g_regex_replace_literal(comma, type, -1, 0, ",,", 0, NULL); + g_free(qtest_hmp(qts, "device_add \"%s,help\"", escaped)); + } +#endif } static void test_device_intro_list(void) { QList *types; - char *help; QTestState *qts; qts = qtest_init(common_args); @@ -XXX,XX +XXX,XX @@ static void test_device_intro_list(void) types = device_type_list(qts, true); qobject_unref(types); - help = qtest_hmp(qts, "device_add help"); - g_free(help); +#ifdef CONFIG_HMP + { + g_free(qtest_hmp(qts, "device_add help")); + } +#endif qtest_quit(qts); } @@ -XXX,XX +XXX,XX @@ static void test_qom_list_fields(void) static void test_device_intro_none(void) { QTestState *qts = qtest_init(common_args); - g_autofree char *qom_tree_start = qtest_hmp(qts, "info qom-tree"); + g_autofree char *qom_tree_start = qom_tree_str(qts); g_autofree char *qom_tree_end = NULL; +#ifdef CONFIG_HMP g_autofree char *qtree_start = qtest_hmp(qts, "info qtree"); g_autofree char *qtree_end = NULL; +#endif test_one_device(qts, "nonexistent"); /* Make sure that really nothing changed in the trees */ - qom_tree_end = qtest_hmp(qts, "info qom-tree"); + qom_tree_end = qom_tree_str(qts); g_assert_cmpstr(qom_tree_start, ==, qom_tree_end); +#ifdef CONFIG_HMP qtree_end = qtest_hmp(qts, "info qtree"); g_assert_cmpstr(qtree_start, ==, qtree_end); +#endif qtest_quit(qts); } @@ -XXX,XX +XXX,XX @@ static void test_device_intro_none(void) static void test_device_intro_abstract(void) { QTestState *qts = qtest_init(common_args); - g_autofree char *qom_tree_start = qtest_hmp(qts, "info qom-tree"); + g_autofree char *qom_tree_start = qom_tree_str(qts); g_autofree char *qom_tree_end = NULL; +#ifdef CONFIG_HMP g_autofree char *qtree_start = qtest_hmp(qts, "info qtree"); g_autofree char *qtree_end = NULL; +#endif test_one_device(qts, "device"); /* Make sure that really nothing changed in the trees */ - qom_tree_end = qtest_hmp(qts, "info qom-tree"); + qom_tree_end = qom_tree_str(qts); g_assert_cmpstr(qom_tree_start, ==, qom_tree_end); +#ifdef CONFIG_HMP qtree_end = qtest_hmp(qts, "info qtree"); g_assert_cmpstr(qtree_start, ==, qtree_end); +#endif qtest_quit(qts); } @@ -XXX,XX +XXX,XX @@ static void test_device_intro_concrete(const void *args) QListEntry *entry; const char *type; QTestState *qts = qtest_init(args); - g_autofree char *qom_tree_start = qtest_hmp(qts, "info qom-tree"); + g_autofree char *qom_tree_start = qom_tree_str(qts); g_autofree char *qom_tree_end = NULL; +#ifdef CONFIG_HMP g_autofree char *qtree_start = qtest_hmp(qts, "info qtree"); g_autofree char *qtree_end = NULL; +#endif types = device_type_list(qts, false); @@ -XXX,XX +XXX,XX @@ static void test_device_intro_concrete(const void *args) /* * Some devices leave dangling pointers in QOM behind. - * "info qom-tree" or "info qtree" have a good chance at crashing then. + * Walking the QOM tree via qom-list has a good chance at crashing then. * Also make sure that the tree did not change. */ - qom_tree_end = qtest_hmp(qts, "info qom-tree"); + qom_tree_end = qom_tree_str(qts); g_assert_cmpstr(qom_tree_start, ==, qom_tree_end); - +#ifdef CONFIG_HMP qtree_end = qtest_hmp(qts, "info qtree"); g_assert_cmpstr(qtree_start, ==, qtree_end); +#endif qobject_unref(types); qtest_quit(qts); -- 2.54.0
These tests rely on HMP commands (drive_add, drive_del) that have no direct QMP equivalent. QMP's blockdev-del operates on node-names and rejects deletion of in-use nodes, whereas HMP's drive_del operates on BlockBackend IDs and can detach a drive from a device. The equivalent QMP-based tests already exist (test_blockdev_add_device_add_and_del*). Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qtest/drive_del-test.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/qtest/drive_del-test.c b/tests/qtest/drive_del-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/drive_del-test.c +++ b/tests/qtest/drive_del-test.c @@ -XXX,XX +XXX,XX @@ static void blockdev_add_with_media(QTestState *qts) g_assert(has_blockdev(qts)); } +#ifdef CONFIG_HMP static void drive_add(QTestState *qts) { char *resp = qtest_hmp(qts, "drive_add 0 if=none,id=drive0"); @@ -XXX,XX +XXX,XX @@ static void drive_del(QTestState *qts) g_assert(!has_drive(qts)); g_free(resp); } +#endif /* * qvirtio_get_dev_type: @@ -XXX,XX +XXX,XX @@ static void device_del(QTestState *qts, bool and_reset) qtest_qmp_eventwait(qts, "DEVICE_DELETED"); } +#ifdef CONFIG_HMP static void test_drive_without_dev(void) { QTestState *qts; @@ -XXX,XX +XXX,XX @@ static void test_drive_del_device_del(void) qtest_quit(qts); } +#endif static void test_cli_device_del(void) { @@ -XXX,XX +XXX,XX @@ static void test_device_add_and_del_q35(void) qtest_quit(qts); } +#ifdef CONFIG_HMP static void test_drive_add_device_add_and_del(void) { QTestState *qts; @@ -XXX,XX +XXX,XX @@ static void test_drive_add_device_add_and_del_q35(void) qtest_quit(qts); } +#endif static void test_blockdev_add_device_add_and_del(void) { @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); +#ifdef CONFIG_HMP qtest_add_func("/drive_del/without-dev", test_drive_without_dev); +#endif if (qvirtio_get_dev_type() != NULL) { +#ifdef CONFIG_HMP qtest_add_func("/drive_del/after_failed_device_add", test_after_failed_device_add); qtest_add_func("/drive_del/drive_del_device_del", test_drive_del_device_del); +#endif qtest_add_func("/device_del/drive/cli_device", test_cli_device_del); qtest_add_func("/device_del/drive/device_add", test_device_add_and_del); +#ifdef CONFIG_HMP qtest_add_func("/device_del/drive/drive_add_device_add", test_drive_add_device_add_and_del); +#endif qtest_add_func("/device_del/empty", test_empty_device_del); qtest_add_func("/device_del/blockdev", @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) test_cli_device_del_q35); qtest_add_func("/device_del/drive/device_add_q35", test_device_add_and_del_q35); +#ifdef CONFIG_HMP qtest_add_func("/device_del/drive/drive_add_device_add_q35", test_drive_add_device_add_and_del_q35); +#endif qtest_add_func("/device_del/blockdev_q35", test_blockdev_add_device_add_and_del_q35); } -- 2.54.0
Make the 'readline' value of MonitorMode and the 'human-monitor-command' command conditional on CONFIG_HMP, so they are only available when HMP support is compiled in. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- qapi/control.json | 4 +++- qapi/misc.json | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/qapi/control.json b/qapi/control.json index XXXXXXX..XXXXXXX 100644 --- a/qapi/control.json +++ b/qapi/control.json @@ -XXX,XX +XXX,XX @@ # # Since: 5.0 ## -{ 'enum': 'MonitorMode', 'data': [ 'readline', 'control' ] } +{ 'enum': 'MonitorMode', 'data': [ + { 'name': 'readline', 'if': 'CONFIG_HMP' }, + 'control' ] } ## # @MonitorOptions: diff --git a/qapi/misc.json b/qapi/misc.json index XXXXXXX..XXXXXXX 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -XXX,XX +XXX,XX @@ { 'command': 'human-monitor-command', 'data': {'command-line': 'str', '*cpu-index': 'int'}, 'returns': 'str', - 'features': [ 'savevm-monitor-nodes' ] } + 'features': [ 'savevm-monitor-nodes' ], + 'if': 'CONFIG_HMP' } ## # @getfd: -- 2.54.0
Add #ifdef CONFIG_HMP guards around HMP-specific declarations in monitor headers and implementations: Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- include/monitor/hmp.h | 2 ++ include/monitor/monitor.h | 11 +++++++++++ monitor/monitor.c | 31 +++++++++++++++++++++++++++++++ monitor/qmp-cmds.c | 2 ++ stubs/monitor-core.c | 2 ++ stubs/monitor-internal.c | 2 ++ 6 files changed, 50 insertions(+) diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index XXXXXXX..XXXXXXX 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -XXX,XX +XXX,XX @@ #ifndef HMP_H #define HMP_H +#ifdef CONFIG_HMP #include "qemu/readline.h" #include "qapi/qapi-types-common.h" #include "monitor/monitor.h" @@ -XXX,XX +XXX,XX @@ void hmp_info_cmma(Monitor *mon, const QDict *qdict); void hmp_migrationmode(Monitor *mon, const QDict *qdict); #endif +#endif diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index XXXXXXX..XXXXXXX 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -XXX,XX +XXX,XX @@ bool monitor_cur_is_qmp(void); void monitor_init_globals(void); void monitor_init_globals_core(void); void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp); +#ifdef CONFIG_HMP void monitor_init_hmp(Chardev *chr, bool use_readline, Error **errp); +#endif int monitor_init(MonitorOptions *opts, bool allow_hmp, Error **errp); int monitor_init_opts(QemuOpts *opts, Error **errp); void monitor_cleanup(void); @@ -XXX,XX +XXX,XX @@ int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp); int monitor_fd_param(Monitor *mon, const char *fdname, Error **errp); int monitor_puts(Monitor *mon, const char *str); + +#ifdef CONFIG_HMP int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) G_GNUC_PRINTF(2, 0); int monitor_printf(Monitor *mon, const char *fmt, ...) G_GNUC_PRINTF(2, 3); void monitor_printc(Monitor *mon, int ch); +#endif + void monitor_flush(Monitor *mon); int monitor_get_cpu_index(Monitor *mon); int monitor_puts_locked(Monitor *mon, const char *str); void monitor_flush_locked(Monitor *mon); + +#ifdef CONFIG_HMP void monitor_read_command(MonitorHMP *mon, int show_prompt); int monitor_read_password(MonitorHMP *mon, ReadLineFunc *readline_func, void *opaque); +#endif AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id, const char *opaque, Error **errp); int monitor_fdset_dup_fd_add(int64_t fdset_id, int flags, Error **errp); void monitor_fdset_dup_fd_remove(int dup_fd); +#ifdef CONFIG_HMP void monitor_register_hmp(const char *name, bool info, void (*cmd)(Monitor *mon, const QDict *qdict)); void monitor_register_hmp_info_hrt(const char *name, HumanReadableText *(*handler)(Error **errp)); +#endif #endif /* MONITOR_H */ diff --git a/monitor/monitor.c b/monitor/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -XXX,XX +XXX,XX @@ bool monitor_cur_is_qmp(void) return cur_mon && monitor_is_qmp(cur_mon); } +#ifdef CONFIG_HMP /** * Is @mon is using readline? * Note: not all HMP monitors use readline, e.g., gdbserver has a @@ -XXX,XX +XXX,XX @@ static inline bool monitor_is_hmp_non_interactive(const Monitor *mon) return !monitor_uses_readline(container_of(mon, MonitorHMP, common)); } +#else +static inline bool monitor_is_hmp_non_interactive(const Monitor *mon) +{ + return false; +} +#endif static gboolean monitor_unblocked(void *do_not_use, GIOCondition cond, void *opaque) @@ -XXX,XX +XXX,XX @@ int monitor_puts(Monitor *mon, const char *str) return monitor_puts_locked(mon, str); } +#ifdef CONFIG_HMP int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { char *buf; @@ -XXX,XX +XXX,XX @@ void monitor_printc(Monitor *mon, int c) } monitor_printf(mon, "'"); } +#endif static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = { /* Limit guest-triggerable events to 1 per second */ @@ -XXX,XX +XXX,XX @@ static void monitor_accept_input(void *opaque) Monitor *mon = opaque; qemu_mutex_lock(&mon->mon_lock); +#ifdef CONFIG_HMP if (!monitor_is_qmp(mon)) { MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); assert(hmp_mon->rs); @@ -XXX,XX +XXX,XX @@ static void monitor_accept_input(void *opaque) } else { qemu_mutex_unlock(&mon->mon_lock); } +#else + qemu_mutex_unlock(&mon->mon_lock); +#endif qemu_chr_fe_accept_input(&mon->chr); } @@ -XXX,XX +XXX,XX @@ void monitor_data_destroy(Monitor *mon) if (monitor_is_qmp(mon)) { monitor_data_destroy_qmp(container_of(mon, MonitorQMP, common)); } else { +#ifdef CONFIG_HMP MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); readline_free(hmp_mon->rs); g_free(hmp_mon->mon_cpu_path); +#endif } g_string_free(mon->outbuf, true); qemu_mutex_destroy(&mon->mon_lock); @@ -XXX,XX +XXX,XX @@ int monitor_init(MonitorOptions *opts, bool allow_hmp, Error **errp) } if (!opts->has_mode) { +#ifdef CONFIG_HMP opts->mode = allow_hmp ? MONITOR_MODE_READLINE : MONITOR_MODE_CONTROL; +#else + opts->mode = MONITOR_MODE_CONTROL; +#endif } switch (opts->mode) { case MONITOR_MODE_CONTROL: monitor_init_qmp(chr, opts->pretty, errp); break; +#ifdef CONFIG_HMP case MONITOR_MODE_READLINE: if (!allow_hmp) { error_setg(errp, "Only QMP is supported"); @@ -XXX,XX +XXX,XX @@ int monitor_init(MonitorOptions *opts, bool allow_hmp, Error **errp) } monitor_init_hmp(chr, true, errp); break; +#endif default: g_assert_not_reached(); } @@ -XXX,XX +XXX,XX @@ int monitor_init_opts(QemuOpts *opts, Error **errp) MonitorOptions *options; int ret; +#ifndef CONFIG_HMP + const char *mode = qemu_opt_get(opts, "mode"); + /* readline is HMP.. */ + if (mode && g_str_equal(mode, "readline")) { + error_setg(errp, "HMP monitor is not available," + " use '-qmp' instead of '-monitor'"); + return -1; + } +#endif + v = opts_visitor_new(opts); visit_type_MonitorOptions(v, NULL, &options, errp); visit_free(v); diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/monitor/qmp-cmds.c +++ b/monitor/qmp-cmds.c @@ -XXX,XX +XXX,XX @@ void qmp_add_client(const char *protocol, const char *fdname, } } +#ifdef CONFIG_HMP char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index, int64_t cpu_index, Error **errp) { @@ -XXX,XX +XXX,XX @@ out: monitor_data_destroy(&hmp.common); return output; } +#endif static void __attribute__((__constructor__)) monitor_init_qmp_commands(void) { diff --git a/stubs/monitor-core.c b/stubs/monitor-core.c index XXXXXXX..XXXXXXX 100644 --- a/stubs/monitor-core.c +++ b/stubs/monitor-core.c @@ -XXX,XX +XXX,XX @@ void qapi_event_emit(QAPIEvent event, QDict *qdict) { } +#ifdef CONFIG_HMP int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { /* @@ -XXX,XX +XXX,XX @@ int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) } return -1; } +#endif diff --git a/stubs/monitor-internal.c b/stubs/monitor-internal.c index XXXXXXX..XXXXXXX 100644 --- a/stubs/monitor-internal.c +++ b/stubs/monitor-internal.c @@ -XXX,XX +XXX,XX @@ int monitor_get_fd(Monitor *mon, const char *name, Error **errp) return -1; } +#ifdef CONFIG_HMP void monitor_init_hmp(Chardev *chr, bool use_readline, Error **errp) { } +#endif -- 2.54.0
Guard calls to monitor_vprintf in error-report and qemu-print so they compile without HMP. When CONFIG_HMP is not set, error_vprintf_mon falls back directly to stderr and qemu_vfprintf returns -1 for NULL streams. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/unit/test-util-sockets.c | 4 +++- tools/qemu-vnc/stubs.c | 2 ++ util/error-report.c | 8 +++++--- util/qemu-print.c | 6 ++++++ 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/unit/test-util-sockets.c b/tests/unit/test-util-sockets.c index XXXXXXX..XXXXXXX 100644 --- a/tests/unit/test-util-sockets.c +++ b/tests/unit/test-util-sockets.c @@ -XXX,XX +XXX,XX @@ int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp) */ Monitor *monitor_cur(void) { return cur_mon; } Monitor *monitor_set_cur(Coroutine *co, Monitor *mon) { abort(); } -int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { abort(); } bool monitor_cur_is_qmp(void) { abort(); }; +#ifdef CONFIG_HMP +int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { abort(); } +#endif #ifndef _WIN32 static void test_socket_fd_pass_name_good(void) diff --git a/tools/qemu-vnc/stubs.c b/tools/qemu-vnc/stubs.c index XXXXXXX..XXXXXXX 100644 --- a/tools/qemu-vnc/stubs.c +++ b/tools/qemu-vnc/stubs.c @@ -XXX,XX +XXX,XX @@ Monitor *monitor_set_cur(Coroutine *co, Monitor *mon) return NULL; } +#ifdef CONFIG_HMP int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { return -1; } +#endif /* * Link-time stubs for VMState symbols referenced by VNC code. diff --git a/util/error-report.c b/util/error-report.c index XXXXXXX..XXXXXXX 100644 --- a/util/error-report.c +++ b/util/error-report.c @@ -XXX,XX +XXX,XX @@ error_vprintf_mon(Monitor *cur_mon, const char *fmt, va_list ap) * IOW this will only print if in HMP, otherwise we * fallback to stderr for QMP / no-monitor scenarios. */ +#ifdef CONFIG_HMP int ret = monitor_vprintf(cur_mon, fmt, ap); - if (ret == -1) { - ret = vfprintf(stderr, fmt, ap); + if (ret != -1) { + return ret; } - return ret; +#endif + return vfprintf(stderr, fmt, ap); } /* diff --git a/util/qemu-print.c b/util/qemu-print.c index XXXXXXX..XXXXXXX 100644 --- a/util/qemu-print.c +++ b/util/qemu-print.c @@ -XXX,XX +XXX,XX @@ */ int qemu_vprintf(const char *fmt, va_list ap) { +#ifdef CONFIG_HMP Monitor *cur_mon = monitor_cur(); if (cur_mon) { return monitor_vprintf(cur_mon, fmt, ap); } +#endif return vprintf(fmt, ap); } @@ -XXX,XX +XXX,XX @@ int qemu_printf(const char *fmt, ...) int qemu_vfprintf(FILE *stream, const char *fmt, va_list ap) { if (!stream) { +#ifdef CONFIG_HMP return monitor_vprintf(monitor_cur(), fmt, ap); +#else + return -1; +#endif } return vfprintf(stream, fmt, ap); } -- 2.54.0
- disable default monitor when HMP is not available - hide 'readline' from -mon help text - error out on mux chardev monitor when no HMP - skip HMP monitor terminal for gdb, return E01 for 'qRcmd' remote commands Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- chardev/char.c | 7 +++++++ gdbstub/system.c | 8 ++++++++ system/vl.c | 4 ++++ qemu-options.hx | 6 +++++- 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/chardev/char.c b/chardev/char.c index XXXXXXX..XXXXXXX 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -XXX,XX +XXX,XX @@ static Chardev *qemu_chr_new_from_name(const char *label, const char *filename, if (qemu_opt_get_bool(opts, "mux", 0)) { assert(permit_mux_mon); +#ifdef CONFIG_HMP monitor_init_hmp(chr, true, &err); if (err) { error_report_err(err); @@ -XXX,XX +XXX,XX @@ static Chardev *qemu_chr_new_from_name(const char *label, const char *filename, chr = NULL; goto out; } +#else + error_report("HMP monitor is disabled"); + object_unparent(OBJECT(chr)); + chr = NULL; + goto out; +#endif } out: diff --git a/gdbstub/system.c b/gdbstub/system.c index XXXXXXX..XXXXXXX 100644 --- a/gdbstub/system.c +++ b/gdbstub/system.c @@ -XXX,XX +XXX,XX @@ bool gdbserver_start(const char *device, Error **errp) qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL); +#ifdef CONFIG_HMP /* Initialize a monitor terminal for gdb */ mon_chr = qemu_chardev_new(NULL, TYPE_CHARDEV_GDB, NULL, NULL, &error_abort); monitor_init_hmp(mon_chr, false, &error_abort); +#else + mon_chr = NULL; +#endif } else { qemu_chr_fe_deinit(&gdbserver_system_state.chr, true); mon_chr = gdbserver_system_state.mon_chr; @@ -XXX,XX +XXX,XX @@ void gdb_handle_query_rcmd(GArray *params, void *ctx) len = len / 2; gdb_hextomem(gdbserver_state.mem_buf, gdb_get_cmd_param(params, 0)->data, len); g_byte_array_append(gdbserver_state.mem_buf, &zero, 1); +#ifdef CONFIG_HMP qemu_chr_be_write(gdbserver_system_state.mon_chr, gdbserver_state.mem_buf->data, gdbserver_state.mem_buf->len); gdb_put_packet("OK"); +#else + gdb_put_packet("E01"); +#endif } /* diff --git a/system/vl.c b/system/vl.c index XXXXXXX..XXXXXXX 100644 --- a/system/vl.c +++ b/system/vl.c @@ -XXX,XX +XXX,XX @@ static int has_defaults = 1; static int default_audio = 1; static int default_serial = 1; static int default_parallel = 1; +#ifdef CONFIG_HMP static int default_monitor = 1; +#else +static int default_monitor; /* false */ +#endif static int default_floppy = 1; static int default_cdrom = 1; static bool auto_create_sdcard = true; diff --git a/qemu-options.hx b/qemu-options.hx index XXXXXXX..XXXXXXX 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -XXX,XX +XXX,XX @@ SRST ERST DEF("mon", HAS_ARG, QEMU_OPTION_mon, \ - "-mon [chardev=]name[,mode=readline|control][,pretty=on|off]\n", QEMU_ARCH_ALL) + "-mon [chardev=]name[,mode=" +#ifdef CONFIG_HMP + "readline|" +#endif + "control][,pretty=on|off]\n", QEMU_ARCH_ALL) SRST ``-mon [chardev=]name[,mode=readline|control][,pretty=on|off]`` Set up a monitor connected to the chardev ``name``. -- 2.54.0
The print_dev callback is only used by HMP 'info qtree'. Guard the field in BusClass, all implementations, and the caller with CONFIG_HMP. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- include/hw/core/qdev.h | 2 ++ hw/char/virtio-serial-bus.c | 6 ++++++ hw/core/sysbus.c | 6 ++++++ hw/misc/auxbus.c | 16 +++++++++++----- hw/pci/pci-hmp-cmds.c | 2 ++ hw/pci/pci.c | 2 ++ hw/usb/bus.c | 6 ++++++ hw/xen/xen-bus.c | 4 ++++ system/qdev-monitor.c | 2 ++ 9 files changed, 41 insertions(+), 5 deletions(-) diff --git a/include/hw/core/qdev.h b/include/hw/core/qdev.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/core/qdev.h +++ b/include/hw/core/qdev.h @@ -XXX,XX +XXX,XX @@ DECLARE_OBJ_CHECKERS(BusState, BusClass, struct BusClass { ObjectClass parent_class; +#ifdef CONFIG_HMP /* FIXME first arg should be BusState */ void (*print_dev)(Monitor *mon, DeviceState *dev, int indent); +#endif /* * Return a newly allocated string containing the path of the * device on this bus. diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -XXX,XX +XXX,XX @@ static int virtio_serial_load_device(VirtIODevice *vdev, QEMUFile *f, return 0; } +#ifdef CONFIG_HMP static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent); +#endif static const Property virtser_props[] = { DEFINE_PROP_UINT32("nr", VirtIOSerialPort, id, VIRTIO_CONSOLE_BAD_ID), @@ -XXX,XX +XXX,XX @@ static const Property virtser_props[] = { static void virtser_bus_class_init(ObjectClass *klass, const void *data) { +#ifdef CONFIG_HMP BusClass *k = BUS_CLASS(klass); k->print_dev = virtser_bus_dev_print; +#endif } static const TypeInfo virtser_bus_info = { @@ -XXX,XX +XXX,XX @@ static const TypeInfo virtser_bus_info = { .class_init = virtser_bus_class_init, }; +#ifdef CONFIG_HMP static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent) { VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(qdev); @@ -XXX,XX +XXX,XX @@ static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent) port->host_connected ? "on" : "off", port->throttled ? "on" : "off"); } +#endif /* This function is only used if a port id is not provided by the user */ static uint32_t find_free_port_id(VirtIOSerial *vser) diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/core/sysbus.c +++ b/hw/core/sysbus.c @@ -XXX,XX +XXX,XX @@ #include "monitor/monitor.h" #include "system/address-spaces.h" +#ifdef CONFIG_HMP static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent); +#endif static char *sysbus_get_fw_dev_path(DeviceState *dev); typedef struct SysBusFind { @@ -XXX,XX +XXX,XX @@ static void system_bus_class_init(ObjectClass *klass, const void *data) { BusClass *k = BUS_CLASS(klass); +#ifdef CONFIG_HMP k->print_dev = sysbus_dev_print; +#endif k->get_fw_dev_path = sysbus_get_fw_dev_path; } @@ -XXX,XX +XXX,XX @@ bool sysbus_realize_and_unref(SysBusDevice *dev, Error **errp) return qdev_realize_and_unref(DEVICE(dev), sysbus_get_default(), errp); } +#ifdef CONFIG_HMP static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent) { SysBusDevice *s = SYS_BUS_DEVICE(dev); @@ -XXX,XX +XXX,XX @@ static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent) indent, "", s->mmio[i].addr, size); } } +#endif static char *sysbus_get_fw_dev_path(DeviceState *dev) { diff --git a/hw/misc/auxbus.c b/hw/misc/auxbus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/auxbus.c +++ b/hw/misc/auxbus.c @@ -XXX,XX +XXX,XX @@ } while (0) +#ifdef CONFIG_HMP static void aux_slave_dev_print(Monitor *mon, DeviceState *dev, int indent); +#endif static inline I2CBus *aux_bridge_get_i2c_bus(AUXTOI2CState *bridge); /* aux-bus implementation (internal not public) */ static void aux_bus_class_init(ObjectClass *klass, const void *data) { +#ifdef CONFIG_HMP BusClass *k = BUS_CLASS(klass); /* AUXSlave has an MMIO so we need to change the way we print information * in monitor. */ k->print_dev = aux_slave_dev_print; +#endif } AUXBus *aux_bus_init(DeviceState *parent, const char *name) @@ -XXX,XX +XXX,XX @@ void aux_map_slave(AUXSlave *aux_dev, hwaddr addr) memory_region_add_subregion(bus->aux_io, addr, aux_dev->mmio); } -static bool aux_bus_is_bridge(AUXBus *bus, DeviceState *dev) -{ - return (dev == DEVICE(bus->bridge)); -} - I2CBus *aux_get_i2c_bus(AUXBus *bus) { return aux_bridge_get_i2c_bus(bus->bridge); @@ -XXX,XX +XXX,XX @@ static const TypeInfo aux_to_i2c_type_info = { }; /* aux-slave implementation */ +#ifdef CONFIG_HMP +static bool aux_bus_is_bridge(AUXBus *bus, DeviceState *dev) +{ + return (dev == DEVICE(bus->bridge)); +} + static void aux_slave_dev_print(Monitor *mon, DeviceState *dev, int indent) { AUXBus *bus = AUX_BUS(qdev_get_parent_bus(dev)); @@ -XXX,XX +XXX,XX @@ static void aux_slave_dev_print(Monitor *mon, DeviceState *dev, int indent) object_property_get_uint(OBJECT(s->mmio), "addr", NULL), memory_region_size(s->mmio)); } +#endif void aux_init_mmio(AUXSlave *aux_slave, MemoryRegion *mmio) { diff --git a/hw/pci/pci-hmp-cmds.c b/hw/pci/pci-hmp-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/hw/pci/pci-hmp-cmds.c +++ b/hw/pci/pci-hmp-cmds.c @@ -XXX,XX +XXX,XX @@ void hmp_info_pci(Monitor *mon, const QDict *qdict) qapi_free_PciInfoList(info_list); } +#ifdef CONFIG_HMP void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent) { PCIDevice *d = (PCIDevice *)dev; @@ -XXX,XX +XXX,XX @@ void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent) r->addr, r->addr + r->size - 1); } } +#endif void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict) { diff --git a/hw/pci/pci.c b/hw/pci/pci.c index XXXXXXX..XXXXXXX 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -XXX,XX +XXX,XX @@ static void pci_bus_class_init(ObjectClass *klass, const void *data) ResettableClass *rc = RESETTABLE_CLASS(klass); FWCfgDataGeneratorClass *fwgc = FW_CFG_DATA_GENERATOR_CLASS(klass); +#ifdef CONFIG_HMP k->print_dev = pcibus_dev_print; +#endif k->get_dev_path = pcibus_get_dev_path; k->get_fw_dev_path = pcibus_get_fw_dev_path; k->realize = pci_bus_realize; diff --git a/hw/usb/bus.c b/hw/usb/bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -XXX,XX +XXX,XX @@ #include "trace.h" #include "qemu/cutils.h" +#ifdef CONFIG_HMP static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent); +#endif static char *usb_get_dev_path(DeviceState *dev); static char *usb_get_fw_dev_path(DeviceState *qdev); @@ -XXX,XX +XXX,XX @@ static void usb_bus_class_init(ObjectClass *klass, const void *data) BusClass *k = BUS_CLASS(klass); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); +#ifdef CONFIG_HMP k->print_dev = usb_bus_dev_print; +#endif k->get_dev_path = usb_get_dev_path; k->get_fw_dev_path = usb_get_fw_dev_path; hc->unplug = qdev_simple_device_unplug_cb; @@ -XXX,XX +XXX,XX @@ static const char *usb_speed(unsigned int speed) return txt[speed]; } +#ifdef CONFIG_HMP static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent) { USBDevice *dev = USB_DEVICE(qdev); @@ -XXX,XX +XXX,XX @@ static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent) usb_speed(dev->speed), dev->product_desc, dev->attached ? ", attached" : ""); } +#endif static char *usb_get_dev_path(DeviceState *qdev) { diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -XXX,XX +XXX,XX @@ abort: qemu_xen_xs_transaction_end(xenbus->xsh, tid, true); } +#ifdef CONFIG_HMP static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent) { XenDevice *xendev = XEN_DEVICE(dev); @@ -XXX,XX +XXX,XX @@ static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent) monitor_printf(mon, "%*sname = '%s' frontend_id = %u\n", indent, "", xendev->name, xendev->frontend_id); } +#endif static char *xen_bus_get_dev_path(DeviceState *dev) { @@ -XXX,XX +XXX,XX @@ static void xen_bus_class_init(ObjectClass *class, const void *data) BusClass *bus_class = BUS_CLASS(class); HotplugHandlerClass *hotplug_class = HOTPLUG_HANDLER_CLASS(class); +#ifdef CONFIG_HMP bus_class->print_dev = xen_bus_print_dev; +#endif bus_class->get_dev_path = xen_bus_get_dev_path; bus_class->realize = xen_bus_realize; bus_class->unrealize = xen_bus_unrealize; diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c index XXXXXXX..XXXXXXX 100644 --- a/system/qdev-monitor.c +++ b/system/qdev-monitor.c @@ -XXX,XX +XXX,XX @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) return ret; } +#ifdef CONFIG_HMP #define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__) static void qdev_print_props(Monitor *mon, DeviceState *dev, DeviceClass *dc, @@ -XXX,XX +XXX,XX @@ void hmp_info_qdm(Monitor *mon, const QDict *qdict) { qdev_print_devinfos(true); } +#endif void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp) { -- 2.54.0
Guard SysemuCPUOps::monitor_defs field and the per-target MonitorDef arrays with CONFIG_HMP. These tables are only used by HMP 'print' and 'info registers' commands. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- include/hw/core/sysemu-cpu-ops.h | 2 ++ target/i386/cpu.c | 4 ++++ target/m68k/cpu.c | 4 ++++ target/sparc/cpu.c | 5 +++-- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/include/hw/core/sysemu-cpu-ops.h b/include/hw/core/sysemu-cpu-ops.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/core/sysemu-cpu-ops.h +++ b/include/hw/core/sysemu-cpu-ops.h @@ -XXX,XX +XXX,XX @@ typedef struct SysemuCPUOps { */ int (*monitor_get_register)(CPUState *cs, const char *name, int64_t *pval); +#ifdef CONFIG_HMP /** * @monitor_defs: Array of MonitorDef entries. This field is legacy, * use @gdb_core_xml_file to dump registers instead. */ const MonitorDef *monitor_defs; +#endif /** * @legacy_vmsd: Legacy state for migration. diff --git a/target/i386/cpu.c b/target/i386/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -XXX,XX +XXX,XX @@ static const Property x86_cpu_properties[] = { #ifndef CONFIG_USER_ONLY +#ifdef CONFIG_HMP static int64_t monitor_get_pc(Monitor *mon, const struct MonitorDef *md, int offset) { @@ -XXX,XX +XXX,XX @@ static const MonitorDef x86_monitor_defs[] = { { NULL }, #undef SEG }; +#endif #include "hw/core/sysemu-cpu-ops.h" @@ -XXX,XX +XXX,XX @@ static const struct SysemuCPUOps i386_sysemu_ops = { .write_elf64_note = x86_cpu_write_elf64_note, .write_elf32_qemunote = x86_cpu_write_elf32_qemunote, .write_elf64_qemunote = x86_cpu_write_elf64_qemunote, +#ifdef CONFIG_HMP .monitor_defs = x86_monitor_defs, +#endif .legacy_vmsd = &vmstate_x86_cpu, }; #endif diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_m68k_cpu = { }, }; +#ifdef CONFIG_HMP static const MonitorDef m68k_monitor_defs[] = { { "ssp", offsetof(CPUM68KState, sp[0]) }, { "usp", offsetof(CPUM68KState, sp[1]) }, @@ -XXX,XX +XXX,XX @@ static const MonitorDef m68k_monitor_defs[] = { { "mmusr", offsetof(CPUM68KState, mmu.mmusr) }, { NULL }, }; +#endif #include "hw/core/sysemu-cpu-ops.h" static const struct SysemuCPUOps m68k_sysemu_ops = { .has_work = m68k_cpu_has_work, .get_phys_addr_debug = m68k_cpu_get_phys_addr_debug, +#ifdef CONFIG_HMP .monitor_defs = m68k_monitor_defs, +#endif }; #endif /* !CONFIG_USER_ONLY */ diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -XXX,XX +XXX,XX @@ static const Property sparc_cpu_properties[] = { #ifdef TARGET_SPARC64 #include "monitor/hmp.h" - +#ifdef CONFIG_HMP static const MonitorDef sparc64_monitor_defs[] = { { "asi", offsetof(CPUSPARCState, asi) }, { "pstate", offsetof(CPUSPARCState, pstate) }, @@ -XXX,XX +XXX,XX @@ static const MonitorDef sparc64_monitor_defs[] = { { NULL }, }; #endif +#endif #include "hw/core/sysemu-cpu-ops.h" @@ -XXX,XX +XXX,XX @@ static const struct SysemuCPUOps sparc_sysemu_ops = { .has_work = sparc_cpu_has_work, .get_phys_addr_debug = sparc_cpu_get_phys_addr_debug, .legacy_vmsd = &vmstate_sparc_cpu, -#if defined(TARGET_SPARC64) +#if defined(TARGET_SPARC64) && defined(CONFIG_HMP) .monitor_defs = sparc64_monitor_defs, #endif }; -- 2.54.0
Add #ifdef CONFIG_HMP around all hmp_* function implementations and their HMP-only helpers across subsystems. This covers monitor_register_hmp* callers, hmp_info_* handlers, and HMP-only helper functions like slirp_lookup. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- accel/accel-system.c | 2 ++ accel/tcg/monitor.c | 2 ++ hw/i386/kvm/xen-stubs.c | 2 ++ hw/i386/kvm/xen_evtchn.c | 3 ++- hw/i386/sgx.c | 2 ++ hw/misc/mos6522-stub.c | 2 ++ hw/misc/mos6522.c | 2 ++ hw/pci/pci-stub.c | 2 ++ hw/s390x/s390-skeys.c | 2 ++ hw/s390x/s390-stattrib.c | 4 ++++ hw/uefi/ovmf-log.c | 2 ++ hw/usb/host-libusb.c | 6 ++++++ migration/dirtyrate.c | 2 ++ net/slirp.c | 7 ++++++- replay/replay-debugging.c | 8 ++++++++ replay/stubs-system.c | 6 ++++++ system/dirtylimit.c | 6 ++++++ system/qdev-monitor.c | 2 ++ target/i386/cpu-apic.c | 2 ++ target/i386/monitor.c | 3 +++ target/i386/sev.c | 2 ++ target/m68k/monitor.c | 2 ++ target/ppc/monitor.c | 2 ++ target/riscv/monitor.c | 3 +++ target/sh4/monitor.c | 2 ++ target/sparc/monitor.c | 2 ++ target/xtensa/monitor.c | 2 ++ 27 files changed, 80 insertions(+), 2 deletions(-) diff --git a/accel/accel-system.c b/accel/accel-system.c index XXXXXXX..XXXXXXX 100644 --- a/accel/accel-system.c +++ b/accel/accel-system.c @@ -XXX,XX +XXX,XX @@ void accel_init_ops_interfaces(AccelClass *ac) static void accel_ops_class_init(ObjectClass *oc, const void *data) { +#ifdef CONFIG_HMP monitor_register_hmp_info_hrt("accel", qmp_x_accel_stats); +#endif } static const TypeInfo accel_ops_type_info = { diff --git a/accel/tcg/monitor.c b/accel/tcg/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/accel/tcg/monitor.c +++ b/accel/tcg/monitor.c @@ -XXX,XX +XXX,XX @@ HumanReadableText *qmp_x_query_jit(Error **errp) return human_readable_text_from_str(buf); } +#ifdef CONFIG_HMP static void hmp_tcg_register(void) { monitor_register_hmp_info_hrt("jit", qmp_x_query_jit); } type_init(hmp_tcg_register); +#endif diff --git a/hw/i386/kvm/xen-stubs.c b/hw/i386/kvm/xen-stubs.c index XXXXXXX..XXXXXXX 100644 --- a/hw/i386/kvm/xen-stubs.c +++ b/hw/i386/kvm/xen-stubs.c @@ -XXX,XX +XXX,XX @@ void xen_primary_console_set_be_port(uint16_t port) { } +#ifdef CONFIG_HMP void hmp_xen_event_list(Monitor *mon, const QDict *qdict) { monitor_printf(mon, "XEN emulation is not available in this QEMU\n"); @@ -XXX,XX +XXX,XX @@ void hmp_xen_event_inject(Monitor *mon, const QDict *qdict) { monitor_printf(mon, "XEN emulation is not available in this QEMU\n"); } +#endif diff --git a/hw/i386/kvm/xen_evtchn.c b/hw/i386/kvm/xen_evtchn.c index XXXXXXX..XXXXXXX 100644 --- a/hw/i386/kvm/xen_evtchn.c +++ b/hw/i386/kvm/xen_evtchn.c @@ -XXX,XX +XXX,XX @@ void qmp_xen_event_inject(uint32_t port, Error **errp) } } +#ifdef CONFIG_HMP void hmp_xen_event_list(Monitor *mon, const QDict *qdict) { EvtchnInfoList *iter, *info_list; @@ -XXX,XX +XXX,XX @@ void hmp_xen_event_inject(Monitor *mon, const QDict *qdict) monitor_printf(mon, "Delivered port %d\n", port); } } - +#endif diff --git a/hw/i386/sgx.c b/hw/i386/sgx.c index XXXXXXX..XXXXXXX 100644 --- a/hw/i386/sgx.c +++ b/hw/i386/sgx.c @@ -XXX,XX +XXX,XX @@ SgxInfo *qmp_query_sgx(Error **errp) return info; } +#ifdef CONFIG_HMP void hmp_info_sgx(Monitor *mon, const QDict *qdict) { Error *err = NULL; @@ -XXX,XX +XXX,XX @@ void hmp_info_sgx(Monitor *mon, const QDict *qdict) monitor_printf(mon, "total size=%" PRIu64 "\n", size); } +#endif bool check_sgx_support(void) { diff --git a/hw/misc/mos6522-stub.c b/hw/misc/mos6522-stub.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/mos6522-stub.c +++ b/hw/misc/mos6522-stub.c @@ -XXX,XX +XXX,XX @@ #include "monitor/monitor.h" #include "monitor/hmp.h" +#ifdef CONFIG_HMP void hmp_info_via(Monitor *mon, const QDict *qdict) { monitor_printf(mon, "MOS6522 VIA is not available in this QEMU\n"); } +#endif diff --git a/hw/misc/mos6522.c b/hw/misc/mos6522.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/mos6522.c +++ b/hw/misc/mos6522.c @@ -XXX,XX +XXX,XX @@ void mos6522_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) } } +#ifdef CONFIG_HMP static int qmp_x_query_via_foreach(Object *obj, void *opaque) { GString *buf = opaque; @@ -XXX,XX +XXX,XX @@ void hmp_info_via(Monitor *mon, const QDict *qdict) } monitor_puts(mon, info->human_readable_text); } +#endif /* CONFIG_HMP */ static const MemoryRegionOps mos6522_ops = { .read = mos6522_read, diff --git a/hw/pci/pci-stub.c b/hw/pci/pci-stub.c index XXXXXXX..XXXXXXX 100644 --- a/hw/pci/pci-stub.c +++ b/hw/pci/pci-stub.c @@ -XXX,XX +XXX,XX @@ PciInfoList *qmp_query_pci(Error **errp) return NULL; } +#ifdef CONFIG_HMP void hmp_info_pci(Monitor *mon, const QDict *qdict) { } @@ -XXX,XX +XXX,XX @@ void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict) { monitor_printf(mon, "PCI devices not supported\n"); } +#endif /* kvm-all wants this */ MSIMessage pci_get_msi_message(PCIDevice *dev, int vector) diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-skeys.c +++ b/hw/s390x/s390-skeys.c @@ -XXX,XX +XXX,XX @@ static void write_keys(FILE *f, uint8_t *keys, uint64_t startgfn, } } +#ifdef CONFIG_HMP void hmp_info_skeys(Monitor *mon, const QDict *qdict) { S390SKeysState *ss = s390_get_skeys_device(); @@ -XXX,XX +XXX,XX @@ void hmp_dump_skeys(Monitor *mon, const QDict *qdict) error_report_err(err); } } +#endif void s390_qmp_dump_skeys(const char *filename, Error **errp) { diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-stattrib.c +++ b/hw/s390x/s390-stattrib.c @@ -XXX,XX +XXX,XX @@ #define STATTR_FLAG_ERROR 0x04ULL #define STATTR_FLAG_DONE 0x08ULL +#ifdef CONFIG_HMP static S390StAttribState *s390_get_stattrib_device(void) { S390StAttribState *sas; @@ -XXX,XX +XXX,XX @@ static S390StAttribState *s390_get_stattrib_device(void) assert(sas); return sas; } +#endif void s390_stattrib_init(void) { @@ -XXX,XX +XXX,XX @@ void s390_stattrib_init(void) /* Console commands: */ +#ifdef CONFIG_HMP void hmp_migrationmode(Monitor *mon, const QDict *qdict) { S390StAttribState *sas = s390_get_stattrib_device(); @@ -XXX,XX +XXX,XX @@ void hmp_info_cmma(Monitor *mon, const QDict *qdict) out: g_free(vals); } +#endif /* Migration support: */ diff --git a/hw/uefi/ovmf-log.c b/hw/uefi/ovmf-log.c index XXXXXXX..XXXXXXX 100644 --- a/hw/uefi/ovmf-log.c +++ b/hw/uefi/ovmf-log.c @@ -XXX,XX +XXX,XX @@ FirmwareLog *qmp_query_firmware_log(bool have_max_size, uint64_t max_size, return ret; } +#ifdef CONFIG_HMP void hmp_info_firmware_log(Monitor *mon, const QDict *qdict) { g_autofree gchar *log_esc = NULL; @@ -XXX,XX +XXX,XX @@ void hmp_info_firmware_log(Monitor *mon, const QDict *qdict) log_esc = g_strescape((gchar *)log_out, "\r\n"); monitor_printf(mon, "%s\n", log_esc); } +#endif diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index XXXXXXX..XXXXXXX 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -XXX,XX +XXX,XX @@ static void usb_host_attach_kernel(USBHostDevice *s); # define HAVE_SUPER_PLUS 1 #endif +#ifdef CONFIG_HMP static const char *speed_name[] = { [LIBUSB_SPEED_UNKNOWN] = "?", [LIBUSB_SPEED_LOW] = "1.5", @@ -XXX,XX +XXX,XX @@ static const char *speed_name[] = { [LIBUSB_SPEED_SUPER_PLUS] = "5000+", #endif }; +#endif static const unsigned int speed_map[] = { [LIBUSB_SPEED_LOW] = USB_SPEED_LOW, @@ -XXX,XX +XXX,XX @@ module_kconfig(USB); static void usb_host_register_types(void) { type_register_static(&usb_host_dev_info); +#ifdef CONFIG_HMP monitor_register_hmp("usbhost", true, hmp_info_usbhost); +#endif } type_init(usb_host_register_types) @@ -XXX,XX +XXX,XX @@ static void usb_host_auto_check(void *unused) timer_mod(usb_auto_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 2000); } +#ifdef CONFIG_HMP void hmp_info_usbhost(Monitor *mon, const QDict *qdict) { libusb_device **devs = NULL; @@ -XXX,XX +XXX,XX @@ void hmp_info_usbhost(Monitor *mon, const QDict *qdict) } libusb_free_device_list(devs, 1); } +#endif diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c index XXXXXXX..XXXXXXX 100644 --- a/migration/dirtyrate.c +++ b/migration/dirtyrate.c @@ -XXX,XX +XXX,XX @@ struct DirtyRateInfo *qmp_query_dirty_rate(bool has_calc_time_unit, has_calc_time_unit ? calc_time_unit : TIME_UNIT_SECOND); } +#ifdef CONFIG_HMP void hmp_info_dirty_rate(Monitor *mon, const QDict *qdict) { DirtyRateInfo *info = query_dirty_rate_info(TIME_UNIT_SECOND); @@ -XXX,XX +XXX,XX @@ void hmp_calc_dirty_rate(Monitor *mon, const QDict *qdict) " seconds\n", sec); monitor_printf(mon, "[Please use 'info dirty_rate' to check results]\n"); } +#endif diff --git a/net/slirp.c b/net/slirp.c index XXXXXXX..XXXXXXX 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -XXX,XX +XXX,XX @@ error: return -1; } +#ifdef CONFIG_HMP static SlirpState *slirp_lookup(Monitor *mon, const char *id) { if (id) { @@ -XXX,XX +XXX,XX @@ void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict) fail_syntax: monitor_printf(mon, "invalid format\n"); } +#endif static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp) { @@ -XXX,XX +XXX,XX @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp) return -1; } +#ifdef CONFIG_HMP void hmp_hostfwd_add(Monitor *mon, const QDict *qdict) { const char *redir_str; @@ -XXX,XX +XXX,XX @@ void hmp_hostfwd_add(Monitor *mon, const QDict *qdict) error_report_err(err); } } - } +#endif #if defined(CONFIG_SMBD_COMMAND) @@ -XXX,XX +XXX,XX @@ UsernetInfoList *qmp_x_query_usernet(Error **errp) return head; } +#ifdef CONFIG_HMP void hmp_info_usernet(Monitor *mon, const QDict *qdict) { g_autoptr(UsernetInfoList) list = NULL; @@ -XXX,XX +XXX,XX @@ void hmp_info_usernet(Monitor *mon, const QDict *qdict) ui->hub_name, ui->info); } } +#endif static void net_init_slirp_configs(const StringList *fwd, int flags) diff --git a/replay/replay-debugging.c b/replay/replay-debugging.c index XXXXXXX..XXXXXXX 100644 --- a/replay/replay-debugging.c +++ b/replay/replay-debugging.c @@ -XXX,XX +XXX,XX @@ bool replay_running_debug(void) return replay_is_debugging; } +#ifdef CONFIG_HMP void hmp_info_replay(Monitor *mon, const QDict *qdict) { if (replay_mode == REPLAY_MODE_NONE) { @@ -XXX,XX +XXX,XX @@ void hmp_info_replay(Monitor *mon, const QDict *qdict) replay_get_filename(), replay_get_current_icount()); } } +#endif ReplayInfo *qmp_query_replay(Error **errp) { @@ -XXX,XX +XXX,XX @@ void qmp_replay_break(int64_t icount, Error **errp) } } +#ifdef CONFIG_HMP void hmp_replay_break(Monitor *mon, const QDict *qdict) { int64_t icount = qdict_get_try_int(qdict, "icount", -1LL); @@ -XXX,XX +XXX,XX @@ void hmp_replay_break(Monitor *mon, const QDict *qdict) return; } } +#endif void qmp_replay_delete_break(Error **errp) { @@ -XXX,XX +XXX,XX @@ void qmp_replay_delete_break(Error **errp) } } +#ifdef CONFIG_HMP void hmp_replay_delete_break(Monitor *mon, const QDict *qdict) { Error *err = NULL; @@ -XXX,XX +XXX,XX @@ void hmp_replay_delete_break(Monitor *mon, const QDict *qdict) return; } } +#endif static char *replay_find_nearest_snapshot(int64_t icount, int64_t *snapshot_icount) @@ -XXX,XX +XXX,XX @@ void qmp_replay_seek(int64_t icount, Error **errp) replay_seek(icount, replay_stop_vm, errp); } +#ifdef CONFIG_HMP void hmp_replay_seek(Monitor *mon, const QDict *qdict) { int64_t icount = qdict_get_try_int(qdict, "icount", -1LL); @@ -XXX,XX +XXX,XX @@ void hmp_replay_seek(Monitor *mon, const QDict *qdict) return; } } +#endif static void replay_stop_vm_debug(void *opaque) { diff --git a/replay/stubs-system.c b/replay/stubs-system.c index XXXXXXX..XXXXXXX 100644 --- a/replay/stubs-system.c +++ b/replay/stubs-system.c @@ -XXX,XX +XXX,XX @@ void replay_vmstate_init(void) #include "qapi/error.h" #include "qemu/error-report.h" +#ifdef CONFIG_HMP void hmp_info_replay(Monitor *mon, const QDict *qdict) { error_report("replay support not available"); } + void hmp_replay_break(Monitor *mon, const QDict *qdict) { error_report("replay support not available"); } + void hmp_replay_delete_break(Monitor *mon, const QDict *qdict) { error_report("replay support not available"); } + void hmp_replay_seek(Monitor *mon, const QDict *qdict) { error_report("replay support not available"); } +#endif + ReplayInfo *qmp_query_replay(Error **errp) { error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND, diff --git a/system/dirtylimit.c b/system/dirtylimit.c index XXXXXXX..XXXXXXX 100644 --- a/system/dirtylimit.c +++ b/system/dirtylimit.c @@ -XXX,XX +XXX,XX @@ void qmp_cancel_vcpu_dirty_limit(bool has_cpu_index, dirtylimit_state_unlock(); } +#ifdef CONFIG_HMP void hmp_cancel_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) { int64_t cpu_index = qdict_get_try_int(qdict, "cpu_index", -1); @@ -XXX,XX +XXX,XX @@ void hmp_cancel_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) monitor_printf(mon, "[Please use 'info vcpu_dirty_limit' to query " "dirty limit for virtual CPU]\n"); } +#endif void qmp_set_vcpu_dirty_limit(bool has_cpu_index, int64_t cpu_index, @@ -XXX,XX +XXX,XX @@ void qmp_set_vcpu_dirty_limit(bool has_cpu_index, dirtylimit_state_unlock(); } +#ifdef CONFIG_HMP void hmp_set_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) { int64_t dirty_rate = qdict_get_int(qdict, "dirty_rate"); @@ -XXX,XX +XXX,XX @@ void hmp_set_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) out: hmp_handle_error(mon, err); } +#endif /* Return the max throttle time of each virtual CPU */ uint64_t dirtylimit_throttle_time_per_round(void) @@ -XXX,XX +XXX,XX @@ struct DirtyLimitInfoList *qmp_query_vcpu_dirty_limit(Error **errp) return dirtylimit_query_all(); } +#ifdef CONFIG_HMP void hmp_info_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) { DirtyLimitInfoList *info; @@ -XXX,XX +XXX,XX @@ void hmp_info_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) info->value->current_rate); } } +#endif diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c index XXXXXXX..XXXXXXX 100644 --- a/system/qdev-monitor.c +++ b/system/qdev-monitor.c @@ -XXX,XX +XXX,XX @@ void qmp_device_sync_config(const char *id, Error **errp) qdev_sync_config(dev, errp); } +#ifdef CONFIG_HMP void hmp_device_add(Monitor *mon, const QDict *qdict) { Error *err = NULL; @@ -XXX,XX +XXX,XX @@ void hmp_device_del(Monitor *mon, const QDict *qdict) qmp_device_del(id, &err); hmp_handle_error(mon, err); } +#endif void device_add_completion(ReadLineState *rs, int nb_args, const char *str) { diff --git a/target/i386/cpu-apic.c b/target/i386/cpu-apic.c index XXXXXXX..XXXXXXX 100644 --- a/target/i386/cpu-apic.c +++ b/target/i386/cpu-apic.c @@ -XXX,XX +XXX,XX @@ void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) } } +#ifdef CONFIG_HMP void hmp_info_local_apic(Monitor *mon, const QDict *qdict) { CPUState *cs; @@ -XXX,XX +XXX,XX @@ void hmp_info_local_apic(Monitor *mon, const QDict *qdict) } x86_cpu_dump_local_apic_state(cs, CPU_DUMP_FPU); } +#endif diff --git a/target/i386/monitor.c b/target/i386/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/target/i386/monitor.c +++ b/target/i386/monitor.c @@ -XXX,XX +XXX,XX @@ #include "qapi/qapi-commands-misc.h" #include "system/memory.h" +#ifdef CONFIG_HMP + /* Perform linear address sign extension */ static hwaddr addr_canonical(CPUArchState *env, hwaddr addr) { @@ -XXX,XX +XXX,XX @@ void hmp_mce(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, err); } } +#endif diff --git a/target/i386/sev.c b/target/i386/sev.c index XXXXXXX..XXXXXXX 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -XXX,XX +XXX,XX @@ SevInfo *qmp_query_sev(Error **errp) return info; } +#ifdef CONFIG_HMP void hmp_info_sev(Monitor *mon, const QDict *qdict) { SevInfo *info = sev_get_info(); @@ -XXX,XX +XXX,XX @@ void hmp_info_sev(Monitor *mon, const QDict *qdict) out: qapi_free_SevInfo(info); } +#endif static int sev_get_pdh_info(int fd, guchar **pdh, size_t *pdh_len, guchar **cert_chain, diff --git a/target/m68k/monitor.c b/target/m68k/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/target/m68k/monitor.c +++ b/target/m68k/monitor.c @@ -XXX,XX +XXX,XX @@ #include "monitor/hmp.h" #include "monitor/monitor.h" +#ifdef CONFIG_HMP void hmp_info_tlb(Monitor *mon, const QDict *qdict) { CPUArchState *env1 = mon_get_cpu_env(mon); @@ -XXX,XX +XXX,XX @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict) dump_mmu(env1); } +#endif diff --git a/target/ppc/monitor.c b/target/ppc/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/target/ppc/monitor.c +++ b/target/ppc/monitor.c @@ -XXX,XX +XXX,XX @@ #include "monitor/hmp.h" #include "cpu.h" +#ifdef CONFIG_HMP void hmp_info_tlb(Monitor *mon, const QDict *qdict) { CPUArchState *env1 = mon_get_cpu_env(mon); @@ -XXX,XX +XXX,XX @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict) } dump_mmu(env1); } +#endif diff --git a/target/riscv/monitor.c b/target/riscv/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/monitor.c +++ b/target/riscv/monitor.c @@ -XXX,XX +XXX,XX @@ #define PTE_HEADER_DELIMITER "-------- ---------------- -------- -------\n" #endif +#ifdef CONFIG_HMP + /* Perform linear address sign extension */ static target_ulong addr_canonical(int va_bits, target_ulong addr) { @@ -XXX,XX +XXX,XX @@ void hmp_info_mem(Monitor *mon, const QDict *qdict) mem_info_svxx(mon, env); } +#endif /* CONFIG_HMP */ static bool reg_is_ulong_integer(CPURISCVState *env, const char *name, target_ulong *val, bool is_gprh) diff --git a/target/sh4/monitor.c b/target/sh4/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/target/sh4/monitor.c +++ b/target/sh4/monitor.c @@ -XXX,XX +XXX,XX @@ #include "monitor/monitor.h" #include "monitor/hmp.h" +#ifdef CONFIG_HMP static void print_tlb(Monitor *mon, int idx, tlb_t *tlb) { monitor_printf(mon, " tlb%i:\t" @@ -XXX,XX +XXX,XX @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict) for (i = 0 ; i < UTLB_SIZE ; i++) print_tlb (mon, i, &env->utlb[i]); } +#endif diff --git a/target/sparc/monitor.c b/target/sparc/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/target/sparc/monitor.c +++ b/target/sparc/monitor.c @@ -XXX,XX +XXX,XX @@ #include "monitor/hmp.h" +#ifdef CONFIG_HMP void hmp_info_tlb(Monitor *mon, const QDict *qdict) { CPUArchState *env1 = mon_get_cpu_env(mon); @@ -XXX,XX +XXX,XX @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict) } dump_mmu(env1); } +#endif diff --git a/target/xtensa/monitor.c b/target/xtensa/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/target/xtensa/monitor.c +++ b/target/xtensa/monitor.c @@ -XXX,XX +XXX,XX @@ #include "monitor/monitor.h" #include "monitor/hmp.h" +#ifdef CONFIG_HMP void hmp_info_tlb(Monitor *mon, const QDict *qdict) { CPUArchState *env1 = mon_get_cpu_env(mon); @@ -XXX,XX +XXX,XX @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict) } dump_mmu(env1); } +#endif -- 2.54.0
Exclude all *-hmp-cmds.c files and HMP-only source files from the build when HMP is disabled. Also conditionalise the hmp-commands.hx header generation and the test-hmp qtest. Together with the preceding CONFIG_HMP guards, this makes QEMU buildable with -Dhmp=disabled. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- meson.build | 2 +- audio/meson.build | 4 +++- backends/meson.build | 5 ++++- block/monitor/meson.build | 4 +++- chardev/meson.build | 5 ++++- disas/meson.build | 4 +++- dump/meson.build | 5 ++++- hw/core/meson.build | 5 +++-- hw/i386/meson.build | 4 +++- hw/net/meson.build | 4 +++- hw/pci/meson.build | 4 +++- hw/virtio/meson.build | 4 +++- migration/meson.build | 4 +++- monitor/meson.build | 9 +++++++-- net/meson.build | 4 +++- qom/meson.build | 4 +++- stats/meson.build | 5 ++++- stubs/meson.build | 12 +++++++----- system/meson.build | 9 +++++++-- tests/qtest/meson.build | 8 +++++++- trace/meson.build | 5 ++++- ui/meson.build | 4 +++- 22 files changed, 85 insertions(+), 29 deletions(-) diff --git a/meson.build b/meson.build index XXXXXXX..XXXXXXX 100644 --- a/meson.build +++ b/meson.build @@ -XXX,XX +XXX,XX @@ hx_headers = [ ['qemu-options.hx', 'qemu-options.def'], ['qemu-img-cmds.hx', 'qemu-img-cmds.h'], ] -if have_system +if have_system and have_hmp hx_headers += [ ['hmp-commands.hx', 'hmp-commands.h'], ['hmp-commands-info.hx', 'hmp-commands-info.h'], diff --git a/audio/meson.build b/audio/meson.build index XXXXXXX..XXXXXXX 100644 --- a/audio/meson.build +++ b/audio/meson.build @@ -XXX,XX +XXX,XX @@ audio_ss.add(files( )) # deprecated since v10.2, to be removed -system_ss.add(files('audio-hmp-cmds.c', 'wavcapture.c')) +if have_hmp + system_ss.add(files('audio-hmp-cmds.c', 'wavcapture.c')) +endif audio_modules = {} foreach m : [ diff --git a/backends/meson.build b/backends/meson.build index XXXXXXX..XXXXXXX 100644 --- a/backends/meson.build +++ b/backends/meson.build @@ -XXX,XX +XXX,XX @@ system_ss.add([files( 'cryptodev-builtin.c', - 'cryptodev-hmp-cmds.c', 'cryptodev.c', 'hostmem-ram.c', 'hostmem.c', @@ -XXX,XX +XXX,XX @@ system_ss.add([files( 'confidential-guest-support.c', ), numa]) +if have_hmp + system_ss.add(files('cryptodev-hmp-cmds.c')) +endif + if host_os != 'windows' system_ss.add(files('rng-random.c')) if host_os != 'emscripten' diff --git a/block/monitor/meson.build b/block/monitor/meson.build index XXXXXXX..XXXXXXX 100644 --- a/block/monitor/meson.build +++ b/block/monitor/meson.build @@ -XXX,XX +XXX,XX @@ -system_ss.add(files('block-hmp-cmds.c')) +if have_hmp + system_ss.add(files('block-hmp-cmds.c')) +endif block_ss.add(files('bitmap-qmp-cmds.c')) system_ss.add(files('qmp-cmds.c')) diff --git a/chardev/meson.build b/chardev/meson.build index XXXXXXX..XXXXXXX 100644 --- a/chardev/meson.build +++ b/chardev/meson.build @@ -XXX,XX +XXX,XX @@ endif chardev_ss = chardev_ss.apply({}) system_ss.add(files( - 'char-hmp-cmds.c', 'msmouse.c', 'wctablet.c', 'testdev.c')) +if have_hmp + system_ss.add(files('char-hmp-cmds.c')) +endif + chardev_modules = {} if brlapi.found() diff --git a/disas/meson.build b/disas/meson.build index XXXXXXX..XXXXXXX 100644 --- a/disas/meson.build +++ b/disas/meson.build @@ -XXX,XX +XXX,XX @@ common_ss.add(when: 'CONFIG_TCG', if_true: files( 'objdump.c' )) common_ss.add(files('disas-common.c')) -system_ss.add(files('disas-mon.c')) +if have_hmp + system_ss.add(files('disas-mon.c')) +endif specific_ss.add(capstone) diff --git a/dump/meson.build b/dump/meson.build index XXXXXXX..XXXXXXX 100644 --- a/dump/meson.build +++ b/dump/meson.build @@ -XXX,XX +XXX,XX @@ -system_ss.add([files('dump.c', 'dump-hmp-cmds.c'), snappy, lzo]) +system_ss.add([files('dump.c'), snappy, lzo]) +if have_hmp + system_ss.add(files('dump-hmp-cmds.c')) +endif specific_ss.add(when: 'CONFIG_WINDUMP', if_true: files('win_dump-x86.c')) system_ss.add(when: 'CONFIG_WINDUMP', if_false: files('win_dump-stubs.c')) diff --git a/hw/core/meson.build b/hw/core/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/core/meson.build +++ b/hw/core/meson.build @@ -XXX,XX +XXX,XX @@ system_ss.add(when: 'CONFIG_SPLIT_IRQ', if_true: files('split-irq.c')) system_ss.add(when: 'CONFIG_XILINX_AXI', if_true: files('stream.c')) system_ss.add(when: 'CONFIG_PLATFORM_BUS', if_true: files('sysbus-fdt.c')) system_ss.add(when: 'CONFIG_EIF', if_true: [files('eif.c'), zlib, libcbor, gnutls]) - system_ss.add(files( 'cpu-system.c', 'fw-path-provider.c', 'hotplug.c', 'loader.c', - 'machine-hmp-cmds.c', 'machine-qmp-cmds.c', 'machine.c', 'nmi.c', @@ -XXX,XX +XXX,XX @@ system_ss.add(files( 'vm-change-state-handler.c', 'clock-vmstate.c', )) +if have_hmp + system_ss.add(files('machine-hmp-cmds.c')) +endif user_ss.add(files( 'cpu-user.c', 'qdev-user.c', diff --git a/hw/i386/meson.build b/hw/i386/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/i386/meson.build +++ b/hw/i386/meson.build @@ -XXX,XX +XXX,XX @@ i386_ss.add(when: 'CONFIG_VTD', if_true: files('intel_iommu.c')) i386_ss.add(when: 'CONFIG_VTD_ACCEL', if_true: files('intel_iommu_accel.c')) i386_ss.add(when: 'CONFIG_SGX', if_true: files('sgx-epc.c','sgx.c'), if_false: files('sgx-stub.c')) -stub_ss.add(files('sgx-hmp-stub.c')) +if have_hmp + stub_ss.add(files('sgx-hmp-stub.c')) +endif i386_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-common.c')) i386_ss.add(when: 'CONFIG_PC', if_true: files( diff --git a/hw/net/meson.build b/hw/net/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/net/meson.build +++ b/hw/net/meson.build @@ -XXX,XX +XXX,XX @@ system_ss.add(when: 'CONFIG_ROCKER', if_true: files( 'rocker/rocker_world.c', )) stub_ss.add(files('rocker/rocker-stubs.c')) -system_ss.add(files('rocker/rocker-hmp-cmds.c')) +if have_hmp + system_ss.add(files('rocker/rocker-hmp-cmds.c')) +endif subdir('can') diff --git a/hw/pci/meson.build b/hw/pci/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/pci/meson.build +++ b/hw/pci/meson.build @@ -XXX,XX +XXX,XX @@ pci_ss.add(files( 'pci.c', 'pci_bridge.c', 'pci_host.c', - 'pci-hmp-cmds.c', 'pci-qmp-cmds.c', 'pcie_sriov.c', 'shpc.c', 'slotid_cap.c' )) +if have_hmp + pci_ss.add(files('pci-hmp-cmds.c')) +endif # The functions in these modules can be used by devices too. Since we # allow plugging PCIe devices into PCI buses, include them even if # CONFIG_PCI_EXPRESS=n. diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/virtio/meson.build +++ b/hw/virtio/meson.build @@ -XXX,XX +XXX,XX @@ stub_ss.add(files('vhost-stub.c')) stub_ss.add(files('virtio-stub.c')) stub_ss.add(files('virtio-md-stubs.c')) -system_ss.add(files('virtio-hmp-cmds.c')) +if have_hmp + system_ss.add(files('virtio-hmp-cmds.c')) +endif system_ss.add(when: 'CONFIG_ACPI', if_true: files('virtio-acpi.c')) diff --git a/migration/meson.build b/migration/meson.build index XXXXXXX..XXXXXXX 100644 --- a/migration/meson.build +++ b/migration/meson.build @@ -XXX,XX +XXX,XX @@ system_ss.add(files( 'socket.c', 'tls.c', ), gnutls, zlib) -system_ss.add([spice_headers, files('migration-hmp-cmds.c'), spice]) +if have_hmp + system_ss.add([spice_headers, files('migration-hmp-cmds.c'), spice]) +endif if get_option('replication').allowed() system_ss.add(files('colo-failover.c', 'colo.c', 'multifd-colo.c')) diff --git a/monitor/meson.build b/monitor/meson.build index XXXXXXX..XXXXXXX 100644 --- a/monitor/meson.build +++ b/monitor/meson.build @@ -XXX,XX +XXX,XX @@ qmp_ss.add(files('monitor.c', 'qmp.c', 'qmp-cmds-control.c')) system_ss.add(files( 'fds.c', - 'hmp-cmds.c', - 'hmp.c', 'qemu-config-qmp.c', 'qmp-cmds.c', )) + +if have_hmp + system_ss.add(files( + 'hmp-cmds.c', + 'hmp.c', + )) +endif diff --git a/net/meson.build b/net/meson.build index XXXXXXX..XXXXXXX 100644 --- a/net/meson.build +++ b/net/meson.build @@ -XXX,XX +XXX,XX @@ system_ss.add(files( 'filter-mirror.c', 'filter.c', 'hub.c', - 'net-hmp-cmds.c', 'net.c', 'queue.c', 'socket.c', @@ -XXX,XX +XXX,XX @@ system_ss.add(files( 'stream_data.c', 'util.c', )) +if have_hmp + system_ss.add(files('net-hmp-cmds.c')) +endif if get_option('replication').allowed() or \ get_option('colo_proxy').allowed() diff --git a/qom/meson.build b/qom/meson.build index XXXXXXX..XXXXXXX 100644 --- a/qom/meson.build +++ b/qom/meson.build @@ -XXX,XX +XXX,XX @@ if have_system endif qmp_ss.add(files('qom-qmp-cmds.c')) -system_ss.add(files('qom-hmp-cmds.c')) +if have_hmp + system_ss.add(files('qom-hmp-cmds.c')) +endif diff --git a/stats/meson.build b/stats/meson.build index XXXXXXX..XXXXXXX 100644 --- a/stats/meson.build +++ b/stats/meson.build @@ -1 +1,4 @@ -system_ss.add(files('stats-hmp-cmds.c', 'stats-qmp-cmds.c')) +system_ss.add(files('stats-qmp-cmds.c')) +if have_hmp + system_ss.add(files('stats-hmp-cmds.c')) +endif diff --git a/stubs/meson.build b/stubs/meson.build index XXXXXXX..XXXXXXX 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -XXX,XX +XXX,XX @@ if have_system stub_ss.add(files('qmp-cpu.c')) stub_ss.add(files('qmp-cpu-s390x.c')) stub_ss.add(files('qmp-cpu-s390x-kvm.c')) - stub_ss.add(files('hmp-cmd-info_mem.c')) - stub_ss.add(files('hmp-cmd-info_sev.c')) - stub_ss.add(files('hmp-cmd-info_tlb.c')) - stub_ss.add(files('hmp-cmds-hw-s390x.c')) - stub_ss.add(files('hmp-cmds-target-i386.c')) + if have_hmp + stub_ss.add(files('hmp-cmd-info_mem.c')) + stub_ss.add(files('hmp-cmd-info_sev.c')) + stub_ss.add(files('hmp-cmd-info_tlb.c')) + stub_ss.add(files('hmp-cmds-hw-s390x.c')) + stub_ss.add(files('hmp-cmds-target-i386.c')) + endif endif if have_system or have_user diff --git a/system/meson.build b/system/meson.build index XXXXXXX..XXXXXXX 100644 --- a/system/meson.build +++ b/system/meson.build @@ -XXX,XX +XXX,XX @@ system_ss.add(files( 'qtest.c', 'rtc.c', 'runstate-action.c', - 'runstate-hmp-cmds.c', 'runstate.c', - 'tpm-hmp-cmds.c', 'watchpoint.c', )) +if have_hmp + system_ss.add(files( + 'runstate-hmp-cmds.c', + 'tpm-hmp-cmds.c', + )) +endif + if have_tpm system_ss.add(files('tpm.c')) endif diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -XXX,XX +XXX,XX @@ qtests_generic = [ 'qmp-test', 'qmp-cmd-test', 'qom-test', - 'test-hmp', +] +if have_hmp + qtests_generic += [ + 'test-hmp', + ] +endif +qtests_generic += [ 'qos-test', 'readconfig-test', 'netdev-socket', diff --git a/trace/meson.build b/trace/meson.build index XXXXXXX..XXXXXXX 100644 --- a/trace/meson.build +++ b/trace/meson.build @@ -XXX,XX +XXX,XX @@ -system_ss.add(files('control-target.c', 'trace-hmp-cmds.c')) +system_ss.add(files('control-target.c')) +if have_hmp + system_ss.add(files('trace-hmp-cmds.c')) +endif trace_rs_targets = [] trace_events_files = [] foreach item : [ '.' ] + trace_events_subdirs + qapi_trace_events diff --git a/ui/meson.build b/ui/meson.build index XXXXXXX..XXXXXXX 100644 --- a/ui/meson.build +++ b/ui/meson.build @@ -XXX,XX +XXX,XX @@ system_ss.add(files( 'input-legacy.c', 'input-barrier.c', 'input.c', - 'ui-hmp-cmds.c', 'ui-qmp-cmds.c', 'util.c', )) +if have_hmp + system_ss.add(files('ui-hmp-cmds.c')) +endif system_ss.add(ui) system_ss.add(when: pixman, if_true: files('console-vc.c'), if_false: files('console-vc-stubs.c')) if dbus_display -- 2.54.0
Test the HMP-disabled build configuration in CI to catch regressions when HMP is compiled out. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- .gitlab-ci.d/buildtest.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index XXXXXXX..XXXXXXX 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -XXX,XX +XXX,XX @@ build-without-defaults: --without-default-devices --without-default-features --disable-fdt + --disable-hmp --disable-pie --disable-qom-cast-debug --disable-strip -- 2.54.0
Hi, This series makes HMP compile-time optional via --disable-hmp. The resulting binary speaks only QMP - reducing the attack surface, binary size and enforcing a separation between machine-readable interface and interactive debugging console. QMP offers almost all the functionality HMP could provide, so a separate standalone "HMP-like" console could be implemented on top of it. The rough list of missing commands (+complexity estimation) after this series: Debugging / introspection: - info registers (medium) - plus $reg expression handling - x/xp read memory (medium) - gpa2hpa/gpa2hva/gva2gpa address translation (medium) - info lapic (high) - deep x86 APIC state, lots of registers - info mem (high) - virtual memory mappings, different per arch - info tlb (high) - virt-to-phys mappings, also per arch - info mtree (high) - memory region tree, multiple view modes - info skeys (medium) - s390x storage keys - info cmma (medium) - s390x CMMA values - info qdm (easy) - could probably be folded into QOM introspection - info qtree (medium) - same, maybe QOM introspection is enough - info snapshots (medium) - info usbhost (medium) - info via (medium) -- VIA south bridge state Simple actions / settings: - gdbserver (trivial) - boot_set (easy) - mce (easy) - x86 MCE injection - sum (easy) - memory checksum - sync-profile (easy) - enable/disable/reset - info sync-profile (medium) - one-insn-per-tb (easy) - could be a QOM property on the accelerator - pcie_aer_inject_error (easy) - migration_mode (medium?) - i/o ioport read/write (easy) - hostfwd-add/hostfwd-remove (medium) - slirp port forwarding - log/logfile (medium) - trace-file (medium) Also, to let clients do disassembly on their side, it'd be useful to have something like "query-disassemble-info" that gives the client what architecture and endianness is used etc. In the meantime, being able to build without HMP is valuable and helps identifying the missing pieces. The series does so by steps: - preparatory cleanups and bug fixes - add commands without QMP equivalent and needed for tests - convert most iotests and qtests from HMP to QMP - guard HMP-only code paths - make HMP source files conditional in the build system Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- Changes in v2: - add "target/i386: return an error for invalid CPU in hmp_mce()", suggested by Philippe - drop all the patches converting iotests to QMP - instead skip when HMP is disabled. The series was getting significantly bigger with those, we can address the remaining conversion later. - clean up the series to be fully bisectable - rebased, add r-b trailers - Link to v1: https://lore.kernel.org/qemu-devel/20260521-qemu-no-hmp-v1-0-d104f809e145@redhat.com To: qemu-devel@nongnu.org Cc: Philippe Mathieu-Daudé <philmd@mailo.com> Cc: "Daniel P. Berrangé" <berrange@redhat.com> Cc: Markus Armbruster <armbru@redhat.com> --- Marc-André Lureau (39): vl: fix -monitor none prefix matching hmp: remove 'vcpu' argument from trace-event help hmp: fix snapshot_blkdev argument type target/i386: decouple cpu_x86_inject_mce() from Monitor target/i386: return an error for invalid CPU in hmp_mce() system: move gpa2hva() to system memory unit s390x: prevent crash if given invalid CPU# system: decouple qmp_inject_nmi() from Monitor hmp: correct the nmi documentation monitor: move HMP-only fields from Monitor to MonitorHMP tests/functional: use query-version QMP command instead of HMP net/qapi: add x-query-usernet command python, tests: switch usernet queries from HMP to QMP tests/qtest/pnv: drop unnecessary -serial mon:stdio tests/qtest/qmp-test: don't depend on human-monitor-command tests/qtest/numa-test: replace HMP "info numa" with QMP query-cpus-fast tests/qtest/cdrom-test: replace HMP "info block" with QMP query-block tests/qtest/device-introspect-test: fix test without HMP tests/qemu-iotests/205: fix race in assertExportNotFound net: add x-query-network QMP command tests/qtest/netdev-socket: replace HMP with x-query-network QMP qemu-io: propagate errors through Error API instead of printf RFC: qtest: add qemu-io command to the qtest protocol RFC: qtest/ide-test: convert to use qtest qemu-io command block: add x-qemu-io QMP command tests/qemu-iotests: add qmp_qemu_io() tests/qemu-iotests: convert pause/resume_drive() to QMP build-sys: add 'hmp' option monitor: reject readline monitor when HMP is disabled tests: skip HMP-dependent tests when HMP is disabled util: guard monitor_vprintf callers with CONFIG_HMP qapi: make HMP-specific schema entries conditional on CONFIG_HMP system: guard HMP initialization paths with CONFIG_HMP Guard HMP command implementations with CONFIG_HMP target: guard MonitorDef tables with CONFIG_HMP hw: guard BusClass::print_dev with CONFIG_HMP build-sys: make HMP source files conditional on have_hmp monitor: guard HMP internal helpers with CONFIG_HMP monitor: guard HMP monitor API with CONFIG_HMP meson.build | 6 +- qapi/block.json | 34 ++ qapi/control.json | 4 +- qapi/machine.json | 5 +- qapi/misc.json | 3 +- qapi/net.json | 166 +++++++++ include/hw/core/qdev.h | 2 + include/hw/core/sysemu-cpu-ops.h | 2 + include/monitor/monitor.h | 11 +- include/net/net.h | 3 +- include/qemu-io.h | 4 +- include/system/memory.h | 2 + monitor/monitor-internal.h | 4 +- net/hub.h | 4 +- target/i386/cpu.h | 4 +- tests/qtest/libqtest.h | 11 + accel/accel-system.c | 2 + accel/tcg/monitor.c | 2 + block/monitor/block-hmp-cmds.c | 60 +-- block/monitor/qmp-cmds.c | 79 ++++ chardev/char.c | 7 + gdbstub/system.c | 8 + hw/char/virtio-serial-bus.c | 6 + hw/core/sysbus.c | 6 + hw/i386/kvm/xen-stubs.c | 2 + hw/i386/kvm/xen_evtchn.c | 3 +- hw/i386/sgx.c | 2 + hw/misc/auxbus.c | 16 +- hw/misc/mos6522-stub.c | 2 + hw/misc/mos6522.c | 2 + hw/pci/pci-stub.c | 2 + hw/pci/pci.c | 2 + hw/s390x/s390-skeys.c | 2 + hw/s390x/s390-stattrib.c | 4 + hw/s390x/s390-virtio-ccw.c | 5 + hw/uefi/ovmf-log.c | 2 + hw/usb/bus.c | 6 + hw/usb/host-libusb.c | 6 + hw/xen/xen-bus.c | 4 + migration/dirtyrate.c | 2 + monitor/hmp-cmds.c | 53 +-- monitor/hmp.c | 7 +- monitor/monitor.c | 47 ++- monitor/qmp-cmds.c | 2 + net/hub.c | 29 +- net/net-hmp-cmds.c | 59 ++- net/net.c | 70 +++- net/slirp.c | 41 +- qemu-io-cmds.c | 414 +++++++++++---------- qemu-io.c | 17 +- replay/replay-debugging.c | 8 + replay/stubs-system.c | 6 + stubs/monitor-core.c | 2 + stubs/monitor-internal.c | 2 + system/cpus.c | 7 +- system/dirtylimit.c | 6 + system/physmem.c | 31 ++ system/qdev-monitor.c | 4 + system/qtest.c | 14 + system/vl.c | 6 +- target/i386/cpu-apic.c | 2 + target/i386/cpu.c | 4 + target/i386/helper.c | 49 +-- target/i386/kvm/kvm.c | 4 +- target/i386/monitor.c | 13 +- target/i386/sev.c | 2 + target/m68k/cpu.c | 4 + target/m68k/monitor.c | 2 + target/ppc/monitor.c | 2 + target/riscv/monitor.c | 3 + target/sh4/monitor.c | 2 + target/sparc/cpu.c | 5 +- target/sparc/monitor.c | 2 + target/xtensa/monitor.c | 2 + tests/qtest/cdrom-test.c | 29 +- tests/qtest/device-introspect-test.c | 111 ++++-- tests/qtest/drive_del-test.c | 25 ++ tests/qtest/ide-test.c | 4 +- tests/qtest/libqtest.c | 14 + tests/qtest/netdev-socket.c | 143 ++++--- tests/qtest/numa-test.c | 63 +++- tests/qtest/pnv-host-i2c-test.c | 2 +- tests/qtest/pnv-xive2-test.c | 2 +- tests/qtest/qmp-test.c | 9 +- tests/unit/test-util-sockets.c | 4 +- tools/qemu-vnc/stubs.c | 2 + util/error-report.c | 8 +- util/qemu-print.c | 6 + audio/meson.build | 4 +- backends/meson.build | 5 +- block/monitor/meson.build | 5 +- chardev/meson.build | 5 +- disas/meson.build | 4 +- dump/meson.build | 5 +- hmp-commands-info.hx | 6 +- hmp-commands.hx | 14 +- hw/core/meson.build | 5 +- hw/i386/meson.build | 4 +- hw/net/meson.build | 4 +- hw/pci/meson.build | 4 +- hw/virtio/meson.build | 4 +- meson_options.txt | 2 + migration/meson.build | 4 +- monitor/meson.build | 9 +- net/meson.build | 4 +- python/qemu/utils/__init__.py | 5 +- qemu-options.hx | 6 +- qom/meson.build | 4 +- scripts/meson-buildoptions.sh | 3 + stats/meson.build | 5 +- stubs/meson.build | 12 +- system/meson.build | 9 +- tests/functional/generic/test_version.py | 10 +- tests/functional/qemu_test/utils.py | 8 +- tests/qemu-iotests/004.out | 20 +- tests/qemu-iotests/021.out | 60 +-- tests/qemu-iotests/026.out | 228 ++++++------ tests/qemu-iotests/028 | 1 + tests/qemu-iotests/045 | 3 +- tests/qemu-iotests/051 | 1 + tests/qemu-iotests/056 | 3 +- tests/qemu-iotests/060 | 1 + tests/qemu-iotests/060.out | 44 ++- tests/qemu-iotests/068 | 1 + tests/qemu-iotests/071 | 1 + tests/qemu-iotests/071.out | 10 +- tests/qemu-iotests/072.out | 2 +- tests/qemu-iotests/080.out | 4 +- tests/qemu-iotests/081 | 1 + tests/qemu-iotests/081.out | 2 +- tests/qemu-iotests/083.out | 36 +- tests/qemu-iotests/089.out | 4 +- tests/qemu-iotests/091 | 1 + tests/qemu-iotests/093 | 3 +- tests/qemu-iotests/102 | 1 + tests/qemu-iotests/114.out | 2 +- tests/qemu-iotests/117 | 1 + tests/qemu-iotests/119 | 1 + tests/qemu-iotests/120 | 1 + tests/qemu-iotests/124 | 3 +- tests/qemu-iotests/130 | 1 + tests/qemu-iotests/132 | 3 +- tests/qemu-iotests/134.out | 2 +- tests/qemu-iotests/136 | 3 +- tests/qemu-iotests/137.out | 2 +- tests/qemu-iotests/142 | 1 + tests/qemu-iotests/145 | 1 + tests/qemu-iotests/146 | 1 + tests/qemu-iotests/148 | 3 +- tests/qemu-iotests/151 | 3 +- tests/qemu-iotests/152 | 3 +- tests/qemu-iotests/153 | 1 + tests/qemu-iotests/153.out | 12 +- tests/qemu-iotests/156 | 1 + tests/qemu-iotests/157 | 1 + tests/qemu-iotests/161 | 1 + tests/qemu-iotests/165 | 3 +- tests/qemu-iotests/171 | 2 +- tests/qemu-iotests/171.out | 68 ++-- tests/qemu-iotests/172 | 1 + tests/qemu-iotests/181 | 1 + tests/qemu-iotests/185 | 1 + tests/qemu-iotests/186 | 1 + tests/qemu-iotests/192 | 1 + tests/qemu-iotests/201 | 1 + tests/qemu-iotests/205 | 6 +- tests/qemu-iotests/214.out | 2 +- tests/qemu-iotests/216 | 3 +- tests/qemu-iotests/220.out | 2 +- tests/qemu-iotests/225 | 1 + tests/qemu-iotests/225.out | 4 +- tests/qemu-iotests/232 | 1 + tests/qemu-iotests/236 | 3 +- tests/qemu-iotests/244.out | 12 +- tests/qemu-iotests/245 | 3 +- tests/qemu-iotests/246 | 3 +- tests/qemu-iotests/249 | 1 + tests/qemu-iotests/249.out | 6 +- tests/qemu-iotests/254 | 3 +- tests/qemu-iotests/255 | 3 +- tests/qemu-iotests/257 | 3 +- tests/qemu-iotests/260 | 3 +- tests/qemu-iotests/264 | 3 +- tests/qemu-iotests/267 | 1 + tests/qemu-iotests/271.out | 14 +- tests/qemu-iotests/274 | 3 +- tests/qemu-iotests/280 | 1 + tests/qemu-iotests/281 | 3 +- tests/qemu-iotests/283 | 1 + tests/qemu-iotests/286 | 1 + tests/qemu-iotests/289.out | 2 +- tests/qemu-iotests/298 | 3 +- tests/qemu-iotests/300 | 3 +- tests/qemu-iotests/304 | 3 +- tests/qemu-iotests/305.out | 2 +- tests/qemu-iotests/307.out | 2 +- tests/qemu-iotests/310 | 3 +- tests/qemu-iotests/common.rc | 8 + tests/qemu-iotests/iotests.py | 32 +- tests/qemu-iotests/tests/backup-discard-source | 7 +- tests/qemu-iotests/tests/copy-before-write | 69 ++-- tests/qemu-iotests/tests/file-io-error.out | 2 +- tests/qemu-iotests/tests/image-fleecing | 3 +- tests/qemu-iotests/tests/image-fleecing.out | 12 +- tests/qemu-iotests/tests/inactive-node-nbd.out | 8 +- tests/qemu-iotests/tests/iothreads-create | 3 +- tests/qemu-iotests/tests/luks-detached-header | 3 +- .../tests/migrate-bitmaps-postcopy-test | 3 +- tests/qemu-iotests/tests/migrate-bitmaps-test | 3 +- tests/qemu-iotests/tests/mirror-change-copy-mode | 3 +- tests/qemu-iotests/tests/mirror-ready-cancel-error | 3 +- tests/qemu-iotests/tests/qcow2-internal-snapshots | 1 + tests/qemu-iotests/tests/qsd-migrate | 3 +- tests/qemu-iotests/tests/reopen-file | 3 +- tests/qemu-iotests/tests/write-zeroes-unmap | 1 + tests/qtest/meson.build | 8 +- tests/vm/basevm.py | 13 +- trace/meson.build | 5 +- ui/meson.build | 4 +- 219 files changed, 1917 insertions(+), 927 deletions(-) --- base-commit: 1b4d5bb3e233c9fc84663be28635d122c9a2b81e change-id: 20260521-qemu-no-hmp-ead3f0bf79c0 Best regards, -- Marc-André Lureau <marcandre.lureau@redhat.com>
Use g_strcmp0() for exact match instead of strncmp() which would incorrectly treat any string starting with "none" as disabling the monitor. Fixes: 70e098af88f ("monitor: allow to disable the default monitor") Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- system/vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/vl.c b/system/vl.c index XXXXXXX..XXXXXXX 100644 --- a/system/vl.c +++ b/system/vl.c @@ -XXX,XX +XXX,XX @@ void qemu_init(int argc, char **argv) } case QEMU_OPTION_monitor: default_monitor = 0; - if (strncmp(optarg, "none", 4)) { + if (g_strcmp0(optarg, "none")) { monitor_parse(optarg, "readline", false); } break; -- 2.54.0
Fixes: 89aafcf2a793 ("trace: remove code that depends on setting vcpu") Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- hmp-commands-info.hx | 6 +++--- hmp-commands.hx | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index XXXXXXX..XXXXXXX 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx @@ -XXX,XX +XXX,XX @@ ERST { .name = "trace-events", - .args_type = "name:s?,vcpu:i?", - .params = "[name] [vcpu]", + .args_type = "name:s?", + .params = "[name]", .help = "show available trace-events & their state " - "(name: event name pattern; vcpu: vCPU to query, default is any)", + "(name: event name pattern)", .cmd = hmp_info_trace_events, .command_completion = info_trace_events_completion, }, diff --git a/hmp-commands.hx b/hmp-commands.hx index XXXXXXX..XXXXXXX 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -XXX,XX +XXX,XX @@ ERST { .name = "trace-event", - .args_type = "name:s,option:b,vcpu:i?", - .params = "name on|off [vcpu]", - .help = "changes status of a specific trace event " - "(vcpu: vCPU to set, default is all)", + .args_type = "name:s,option:b", + .params = "name on|off", + .help = "changes status of a specific trace event", .cmd = hmp_trace_event, .command_completion = trace_event_completion, }, -- 2.54.0
The `snapshot-file` argument for `snapshot_blkdev` is mandatory. Correct the `args_type` definition to reflect this. Fixes: 6106e2492fe ("qapi: Convert blockdev_snapshot_sync") Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- hmp-commands.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index XXXXXXX..XXXXXXX 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -XXX,XX +XXX,XX @@ ERST { .name = "snapshot_blkdev", - .args_type = "reuse:-n,device:B,snapshot-file:s?,format:s?", + .args_type = "reuse:-n,device:B,snapshot-file:s,format:s?", .params = "[-n] device [new-image-file] [format]", .help = "initiates a live snapshot\n\t\t\t" "of device. If a new image file is specified, the\n\t\t\t" -- 2.54.0
Replace monitor_printf() error reporting with the standard **errp pattern. Drop the Monitor *mon parameter and return bool to indicate success, improving the function usage from non-HMP contexts. Update the KVM MCE injection path and hmp_mce() accordingly. Notes: - we may want to print the error in KVM path too - multiple error prints are now accumulated with error hints Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- target/i386/cpu.h | 4 ++-- target/i386/helper.c | 49 ++++++++++++++++++++++++++++--------------------- target/i386/kvm/kvm.c | 4 ++-- target/i386/monitor.c | 6 ++++-- 4 files changed, 36 insertions(+), 27 deletions(-) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -XXX,XX +XXX,XX @@ void do_cpu_init(X86CPU *cpu); #define MCE_INJECT_BROADCAST 1 #define MCE_INJECT_UNCOND_AO 2 -void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank, +bool cpu_x86_inject_mce(X86CPU *cpu, int bank, uint64_t status, uint64_t mcg_status, uint64_t addr, - uint64_t misc, int flags); + uint64_t misc, int flags, Error **errp); uint32_t cpu_cc_compute_all(CPUX86State *env1); diff --git a/target/i386/helper.c b/target/i386/helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -XXX,XX +XXX,XX @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "qapi/qapi-events-run-state.h" #include "cpu.h" #include "exec/cputlb.h" @@ -XXX,XX +XXX,XX @@ #ifndef CONFIG_USER_ONLY #include "system/hw_accel.h" #include "system/memory.h" -#include "monitor/monitor.h" #include "kvm/kvm_i386.h" #endif #include "qemu/log.h" @@ -XXX,XX +XXX,XX @@ out: } typedef struct MCEInjectionParams { - Monitor *mon; + GString *err; int bank; uint64_t status; uint64_t mcg_status; @@ -XXX,XX +XXX,XX @@ static void do_inject_x86_mce(CPUState *cs, run_on_cpu_data data) * reporting is disabled */ if ((cenv->mcg_cap & MCG_CTL_P) && cenv->mcg_ctl != ~(uint64_t)0) { - monitor_printf(params->mon, - "CPU %d: Uncorrected error reporting disabled\n", - cs->cpu_index); + g_string_append_printf(params->err, + "CPU %d: Uncorrected error reporting disabled\n", + cs->cpu_index); return; } @@ -XXX,XX +XXX,XX @@ static void do_inject_x86_mce(CPUState *cs, run_on_cpu_data data) * reporting is disabled for the bank */ if (banks[0] != ~(uint64_t)0) { - monitor_printf(params->mon, - "CPU %d: Uncorrected error reporting disabled for" - " bank %d\n", - cs->cpu_index, params->bank); + g_string_append_printf(params->err, + "CPU %d: Uncorrected error reporting disabled for bank %d\n", + cs->cpu_index, params->bank); return; } @@ -XXX,XX +XXX,XX @@ static void do_inject_x86_mce(CPUState *cs, run_on_cpu_data data) if (need_reset) { emit_guest_memory_failure(MEMORY_FAILURE_ACTION_RESET, ar, recursive); - monitor_printf(params->mon, "%s", msg); + g_string_append_printf(params->err, "%s\n", msg); qemu_log_mask(CPU_LOG_RESET, "%s\n", msg); qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); return; @@ -XXX,XX +XXX,XX @@ static void do_inject_x86_mce(CPUState *cs, run_on_cpu_data data) emit_guest_memory_failure(MEMORY_FAILURE_ACTION_INJECT, ar, recursive); } -void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank, +bool cpu_x86_inject_mce(X86CPU *cpu, int bank, uint64_t status, uint64_t mcg_status, uint64_t addr, - uint64_t misc, int flags) + uint64_t misc, int flags, Error **errp) { + ERRP_GUARD(); CPUState *cs = CPU(cpu); CPUX86State *cenv = &cpu->env; + g_autoptr(GString) err = g_string_new(NULL); MCEInjectionParams params = { - .mon = mon, + .err = err, .bank = bank, .status = status, .mcg_status = mcg_status, @@ -XXX,XX +XXX,XX @@ void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank, unsigned bank_num = cenv->mcg_cap & 0xff; if (!cenv->mcg_cap) { - monitor_printf(mon, "MCE injection not supported\n"); - return; + error_setg(errp, "MCE injection not supported"); + return false; } if (bank >= bank_num) { - monitor_printf(mon, "Invalid MCE bank number\n"); - return; + error_setg(errp, "Invalid MCE bank number"); + return false; } if (!(status & MCI_STATUS_VAL)) { - monitor_printf(mon, "Invalid MCE status code\n"); - return; + error_setg(errp, "Invalid MCE status code"); + return false; } if ((flags & MCE_INJECT_BROADCAST) && !cpu_x86_support_mca_broadcast(cenv)) { - monitor_printf(mon, "Guest CPU does not support MCA broadcast\n"); - return; + error_setg(errp, "Guest CPU does not support MCA broadcast"); + return false; } run_on_cpu(cs, do_inject_x86_mce, RUN_ON_CPU_HOST_PTR(¶ms)); @@ -XXX,XX +XXX,XX @@ void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank, run_on_cpu(other_cs, do_inject_x86_mce, RUN_ON_CPU_HOST_PTR(¶ms)); } } + if (params.err->len) { + error_setg(errp, "Failed to inject MCE"); + error_append_hint(errp, "%s", params.err->str); + return false; + } + return true; } static inline target_ulong get_memio_eip(CPUX86State *env) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index XXXXXXX..XXXXXXX 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -XXX,XX +XXX,XX @@ static void kvm_mce_inject(X86CPU *cpu, hwaddr paddr, int code) flags = 0; } - cpu_x86_inject_mce(NULL, cpu, 9, status, mcg_status, paddr, - (MCM_ADDR_PHYS << 6) | 0xc, flags); + cpu_x86_inject_mce(cpu, 9, status, mcg_status, paddr, + (MCM_ADDR_PHYS << 6) | 0xc, flags, NULL); } static void emit_hypervisor_memory_failure(MemoryFailureAction action, bool ar) diff --git a/target/i386/monitor.c b/target/i386/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/target/i386/monitor.c +++ b/target/i386/monitor.c @@ -XXX,XX +XXX,XX @@ void hmp_mce(Monitor *mon, const QDict *qdict) uint64_t addr = qdict_get_int(qdict, "addr"); uint64_t misc = qdict_get_int(qdict, "misc"); int flags = MCE_INJECT_UNCOND_AO; + Error *err = NULL; if (qdict_get_try_bool(qdict, "broadcast", false)) { flags |= MCE_INJECT_BROADCAST; @@ -XXX,XX +XXX,XX @@ void hmp_mce(Monitor *mon, const QDict *qdict) cs = qemu_get_cpu(cpu_index); if (cs != NULL) { cpu = X86_CPU(cs); - cpu_x86_inject_mce(mon, cpu, bank, status, mcg_status, addr, misc, - flags); + cpu_x86_inject_mce(cpu, bank, status, mcg_status, addr, misc, + flags, &err); + hmp_handle_error(mon, err); } } -- 2.54.0
Rather than silently doing nothing. Suggested-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- target/i386/monitor.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/i386/monitor.c b/target/i386/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/target/i386/monitor.c +++ b/target/i386/monitor.c @@ -XXX,XX +XXX,XX @@ void hmp_mce(Monitor *mon, const QDict *qdict) flags |= MCE_INJECT_BROADCAST; } cs = qemu_get_cpu(cpu_index); - if (cs != NULL) { + if (cs) { cpu = X86_CPU(cs); cpu_x86_inject_mce(cpu, bank, status, mcg_status, addr, misc, flags, &err); - hmp_handle_error(mon, err); + } else { + error_setg(&err, "Invalid CPU %d", cpu_index); } + hmp_handle_error(mon, err); } -- 2.54.0
The function is now used by SEV code path. Move it to physmem.c rather than hmp-cmds.c. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- include/monitor/monitor.h | 2 -- include/system/memory.h | 2 ++ monitor/hmp-cmds.c | 31 ------------------------------- system/physmem.c | 31 +++++++++++++++++++++++++++++++ 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index XXXXXXX..XXXXXXX 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -XXX,XX +XXX,XX @@ int monitor_get_cpu_index(Monitor *mon); int monitor_puts_locked(Monitor *mon, const char *str); void monitor_flush_locked(Monitor *mon); -void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, uint64_t size, Error **errp); - void monitor_read_command(MonitorHMP *mon, int show_prompt); int monitor_read_password(MonitorHMP *mon, ReadLineFunc *readline_func, void *opaque); diff --git a/include/system/memory.h b/include/system/memory.h index XXXXXXX..XXXXXXX 100644 --- a/include/system/memory.h +++ b/include/system/memory.h @@ -XXX,XX +XXX,XX @@ bool ram_block_discard_is_required(void); void ram_block_add_cpr_blocker(RAMBlock *rb, Error **errp); void ram_block_del_cpr_blocker(RAMBlock *rb); +void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, uint64_t size, Error **errp); + #endif diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -XXX,XX +XXX,XX @@ void hmp_physical_memory_dump(Monitor *mon, const QDict *qdict) memory_dump(mon, count, format, size, addr, true); } -void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, uint64_t size, Error **errp) -{ - Int128 gpa_region_size; - MemoryRegionSection mrs = memory_region_find(get_system_memory(), - addr, size); - - if (!mrs.mr) { - error_setg(errp, - "No memory is mapped at address 0x%" HWADDR_PRIx, addr); - return NULL; - } - - if (!memory_region_is_ram(mrs.mr) && !memory_region_is_romd(mrs.mr)) { - error_setg(errp, - "Memory at address 0x%" HWADDR_PRIx " is not RAM", addr); - memory_region_unref(mrs.mr); - return NULL; - } - - gpa_region_size = int128_make64(size); - if (int128_lt(mrs.size, gpa_region_size)) { - error_setg(errp, "Size of memory region at 0x%" HWADDR_PRIx - " exceeded.", addr); - memory_region_unref(mrs.mr); - return NULL; - } - - *p_mr = mrs.mr; - return qemu_map_ram_ptr(mrs.mr->ram_block, mrs.offset_within_region); -} - void hmp_gpa2hva(Monitor *mon, const QDict *qdict) { hwaddr addr = qdict_get_int(qdict, "addr"); diff --git a/system/physmem.c b/system/physmem.c index XXXXXXX..XXXXXXX 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -XXX,XX +XXX,XX @@ void ram_block_del_cpr_blocker(RAMBlock *rb) { migrate_del_blocker(&rb->cpr_blocker); } + +void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, uint64_t size, Error **errp) +{ + Int128 gpa_region_size; + MemoryRegionSection mrs = memory_region_find(get_system_memory(), + addr, size); + + if (!mrs.mr) { + error_setg(errp, + "No memory is mapped at address 0x%" HWADDR_PRIx, addr); + return NULL; + } + + if (!memory_region_is_ram(mrs.mr) && !memory_region_is_romd(mrs.mr)) { + error_setg(errp, + "Memory at address 0x%" HWADDR_PRIx " is not RAM", addr); + memory_region_unref(mrs.mr); + return NULL; + } + + gpa_region_size = int128_make64(size); + if (int128_lt(mrs.size, gpa_region_size)) { + error_setg(errp, "Size of memory region at 0x%" HWADDR_PRIx + " exceeded.", addr); + memory_region_unref(mrs.mr); + return NULL; + } + + *p_mr = mrs.mr; + return qemu_map_ram_ptr(mrs.mr->ram_block, mrs.offset_within_region); +} -- 2.54.0
Reviewed-by: Eric Farman <farman@linux.ibm.com> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- hw/s390x/s390-virtio-ccw.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -XXX,XX +XXX,XX @@ static void s390_nmi(NMIState *n, int cpu_index, Error **errp) { CPUState *cs = qemu_get_cpu(cpu_index); + if (!cs) { + error_setg(errp, "CPU %d does not exist", cpu_index); + return; + } + s390_cpu_restart(S390_CPU(cs)); } -- 2.54.0
Use first_cpu directly instead of going through monitor_get_cpu_index(), as this is HMP-territory. QMP doesn't have a `cpu` command, we should add arguments instead when needed. Update the inject-nmi doc to accurately describe per-architecture NMI delivery. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- qapi/machine.json | 5 +++-- system/cpus.c | 7 +++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/qapi/machine.json b/qapi/machine.json index XXXXXXX..XXXXXXX 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -XXX,XX +XXX,XX @@ ## # @inject-nmi: # -# Injects a Non-Maskable Interrupt into the default CPU (x86/s390) or -# all CPUs (ppc64). The command fails when the guest doesn't support +# Injects a Non-Maskable Interrupt into the virtual machine. The NMI +# is delivered to all vCPUs (x86, hppa, ppc64) or to the first vCPU +# (s390). The command fails when the guest doesn't support # injecting. # # Since: 0.14 diff --git a/system/cpus.c b/system/cpus.c index XXXXXXX..XXXXXXX 100644 --- a/system/cpus.c +++ b/system/cpus.c @@ -XXX,XX +XXX,XX @@ exit: void qmp_inject_nmi(Error **errp) { - nmi_monitor_handle(monitor_get_cpu_index(monitor_cur()), errp); + int cpu_index = UNASSIGNED_CPU_INDEX; + if (first_cpu) { + cpu_index = first_cpu->cpu_index; + } + nmi_monitor_handle(cpu_index, errp); } - -- 2.54.0
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- hmp-commands.hx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index XXXXXXX..XXXXXXX 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -XXX,XX +XXX,XX @@ ERST .cmd = hmp_nmi, }, SRST -``nmi`` *cpu* - Inject an NMI on the default CPU (x86/s390) or all CPUs (ppc64). +``nmi`` + Inject an NMI on the associated monitor vCPU (``cpu`` command, on s390x) or + all vCPUs (on other architectures). ERST { -- 2.54.0
mon_cpu_path and reset_seen are only used by HMP monitors; move them from the base Monitor struct into MonitorHMP to properly encapsulate HMP-specific state. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- monitor/monitor-internal.h | 4 ++-- monitor/hmp-cmds.c | 17 ++++++++++------- monitor/hmp.c | 5 +++-- monitor/monitor.c | 16 +++++++++++----- 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index XXXXXXX..XXXXXXX 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -XXX,XX +XXX,XX @@ struct Monitor { bool skip_flush; bool use_io_thread; - char *mon_cpu_path; QTAILQ_ENTRY(Monitor) entry; /* @@ -XXX,XX +XXX,XX @@ struct Monitor { GString *outbuf; guint out_watch; int mux_out; - int reset_seen; }; struct MonitorHMP { @@ -XXX,XX +XXX,XX @@ struct MonitorHMP { * These members can be safely accessed without locks. */ ReadLineState *rs; + char *mon_cpu_path; + int reset_seen; }; typedef struct { diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -XXX,XX +XXX,XX @@ void hmp_dumpdtb(Monitor *mon, const QDict *qdict) /* Set the current CPU defined by the user. Callers must hold BQL. */ int monitor_set_cpu(Monitor *mon, int cpu_index) { + assert(!monitor_is_qmp(mon)); + MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); CPUState *cpu; cpu = qemu_get_cpu(cpu_index); if (cpu == NULL) { return -1; } - g_free(mon->mon_cpu_path); - mon->mon_cpu_path = object_get_canonical_path(OBJECT(cpu)); + g_free(hmp_mon->mon_cpu_path); + hmp_mon->mon_cpu_path = object_get_canonical_path(OBJECT(cpu)); return 0; } /* Callers must hold BQL. */ static CPUState *mon_get_cpu_sync(Monitor *mon, bool synchronize) { + MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); CPUState *cpu = NULL; - if (mon->mon_cpu_path) { - cpu = (CPUState *) object_resolve_path_type(mon->mon_cpu_path, + if (hmp_mon->mon_cpu_path) { + cpu = (CPUState *) object_resolve_path_type(hmp_mon->mon_cpu_path, TYPE_CPU, NULL); if (!cpu) { - g_free(mon->mon_cpu_path); - mon->mon_cpu_path = NULL; + g_free(hmp_mon->mon_cpu_path); + hmp_mon->mon_cpu_path = NULL; } } - if (!mon->mon_cpu_path) { + if (!hmp_mon->mon_cpu_path) { if (!first_cpu) { return NULL; } diff --git a/monitor/hmp.c b/monitor/hmp.c index XXXXXXX..XXXXXXX 100644 --- a/monitor/hmp.c +++ b/monitor/hmp.c @@ -XXX,XX +XXX,XX @@ static void monitor_read(void *opaque, const uint8_t *buf, int size) static void monitor_event(void *opaque, QEMUChrEvent event) { Monitor *mon = opaque; + MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); switch (event) { case CHR_EVENT_MUX_IN: @@ -XXX,XX +XXX,XX @@ static void monitor_event(void *opaque, QEMUChrEvent event) case CHR_EVENT_MUX_OUT: qemu_mutex_lock(&mon->mon_lock); if (!mon->mux_out) { - if (mon->reset_seen && !mon->suspend_cnt) { + if (hmp_mon->reset_seen && !mon->suspend_cnt) { monitor_puts_locked(mon, "\n"); } else { monitor_flush_locked(mon); @@ -XXX,XX +XXX,XX @@ static void monitor_event(void *opaque, QEMUChrEvent event) monitor_printf(mon, "QEMU %s monitor - type 'help' for more " "information\n", QEMU_VERSION); qemu_mutex_lock(&mon->mon_lock); - mon->reset_seen = 1; + hmp_mon->reset_seen = 1; if (!mon->mux_out) { /* Suspend-resume forces the prompt to be printed. */ monitor_suspend(mon); diff --git a/monitor/monitor.c b/monitor/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -XXX,XX +XXX,XX @@ static void monitor_accept_input(void *opaque) Monitor *mon = opaque; qemu_mutex_lock(&mon->mon_lock); - if (!monitor_is_qmp(mon) && mon->reset_seen) { + if (!monitor_is_qmp(mon)) { MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); assert(hmp_mon->rs); - readline_restart(hmp_mon->rs); + bool reset_seen = hmp_mon->reset_seen; + if (reset_seen) { + readline_restart(hmp_mon->rs); + } qemu_mutex_unlock(&mon->mon_lock); - readline_show_prompt(hmp_mon->rs); + if (reset_seen) { + readline_show_prompt(hmp_mon->rs); + } } else { qemu_mutex_unlock(&mon->mon_lock); } @@ -XXX,XX +XXX,XX @@ void monitor_data_init(Monitor *mon, bool is_qmp, bool skip_flush, void monitor_data_destroy(Monitor *mon) { - g_free(mon->mon_cpu_path); qemu_chr_fe_deinit(&mon->chr, false); if (monitor_is_qmp(mon)) { monitor_data_destroy_qmp(container_of(mon, MonitorQMP, common)); } else { - readline_free(container_of(mon, MonitorHMP, common)->rs); + MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); + readline_free(hmp_mon->rs); + g_free(hmp_mon->mon_cpu_path); } g_string_free(mon->outbuf, true); qemu_mutex_destroy(&mon->mon_lock); -- 2.54.0
Replace the human-monitor-command based version test with the native QMP query-version command, which returns structured version data. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/functional/generic/test_version.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/functional/generic/test_version.py b/tests/functional/generic/test_version.py index XXXXXXX..XXXXXXX 100755 --- a/tests/functional/generic/test_version.py +++ b/tests/functional/generic/test_version.py @@ -XXX,XX +XXX,XX @@ class Version(QemuSystemTest): - def test_qmp_human_info_version(self): + def test_qmp_query_version(self): self.set_machine('none') self.vm.add_args('-nodefaults') self.vm.launch() - res = self.vm.cmd('human-monitor-command', - command_line='info version') - self.assertRegex(res, r'^(\d+\.\d+\.\d)') + res = self.vm.cmd('query-version') + version = res['qemu'] + self.assertIsInstance(version['major'], int) + self.assertIsInstance(version['minor'], int) + self.assertIsInstance(version['micro'], int) if __name__ == '__main__': QemuSystemTest.main() -- 2.54.0
Add a QMP command to query user-mode network stack (slirp) connection states, providing a structured alternative to "info usernet" HMP. The new command returns a list of UsernetInfo, with hub-id, hub-name, and connection info for each slirp stack. It is marked unstable as it is meant for debugging. Rewrite hmp_info_usernet() as a thin wrapper over qmp_x_query_usernet() so the HMP and QMP paths share the same implementation. This is part of the effort to decouple HMP from QEMU core. Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com> --- qapi/net.json | 44 ++++++++++++++++++++++++++++++++++++++++++++ net/slirp.c | 34 ++++++++++++++++++++++++++++------ 2 files changed, 72 insertions(+), 6 deletions(-) diff --git a/qapi/net.json b/qapi/net.json index XXXXXXX..XXXXXXX 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -XXX,XX +XXX,XX @@ ## { 'event': 'NETDEV_VHOST_USER_DISCONNECTED', 'data': { 'netdev-id': 'str' } } + +## +# @UsernetInfo: +# +# Information about a user-mode network stack (slirp). +# +# @hub-id: The hub id, if available. +# +# @hub-name: The name of the hub. +# +# @info: Network information from slirp. +# +# Since: 11.1 +## +{ 'struct': 'UsernetInfo', + 'data': { + '*hub-id': 'int', + 'hub-name': 'str', + 'info': 'str' }, + 'if': 'CONFIG_SLIRP' } + +## +# @x-query-usernet: +# +# Query user-mode network stack connection states. +# +# Features: +# +# @unstable: This command is meant for debugging. +# +# Returns: list of user-mode network stack information. +# +# Since: 11.1 +# +# .. qmp-example:: +# +# -> { "execute": "x-query-usernet" } +# <- { "return": [ { "hub-id": 0, "hub-name": "vnet", +# "info": "..." } ] } +## +{ 'command': 'x-query-usernet', + 'returns': ['UsernetInfo'], + 'if': 'CONFIG_SLIRP', + 'features': [ 'unstable' ] } diff --git a/net/slirp.c b/net/slirp.c index XXXXXXX..XXXXXXX 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -XXX,XX +XXX,XX @@ #include "system/system.h" #include "qemu/cutils.h" #include "qapi/error.h" +#include "qapi/qapi-commands-net.h" #include "qobject/qdict.h" #include "util.h" #include "migration/register.h" @@ -XXX,XX +XXX,XX @@ static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp) return -1; } -void hmp_info_usernet(Monitor *mon, const QDict *qdict) +UsernetInfoList *qmp_x_query_usernet(Error **errp) { + UsernetInfoList *head = NULL, **tail = &head; SlirpState *s; QTAILQ_FOREACH(s, &slirp_stacks, entry) { + UsernetInfo *ui = g_new0(UsernetInfo, 1); int id; - bool got_hub_id = net_hub_id_for_client(&s->nc, &id) == 0; - char *info = slirp_connection_info(s->slirp); + + if (net_hub_id_for_client(&s->nc, &id) == 0) { + ui->has_hub_id = true; + ui->hub_id = id; + } + ui->hub_name = g_strdup(s->nc.name); + ui->info = slirp_connection_info(s->slirp); + + QAPI_LIST_APPEND(tail, ui); + } + + return head; +} + +void hmp_info_usernet(Monitor *mon, const QDict *qdict) +{ + g_autoptr(UsernetInfoList) list = NULL; + UsernetInfoList *entry; + + list = qmp_x_query_usernet(&error_abort); + for (entry = list; entry; entry = entry->next) { + UsernetInfo *ui = entry->value; monitor_printf(mon, "Hub %d (%s):\n%s", - got_hub_id ? id : -1, - s->nc.name, info); - g_free(info); + ui->has_hub_id ? (int)ui->hub_id : -1, + ui->hub_name, ui->info); } } -- 2.54.0
Replace human-monitor-command "info usernet" calls with the structured x-query-usernet QMP command in get_usernet_hostfwd_port() and the VM test runner boot path. Since x-query-usernet returns a list of UsernetInfo entries, callers now iterate over the result and extract the port from each entry's "info" field. Also switch get_info_usernet_hostfwd_port() from split('\r\n') to splitlines(), since QMP strings use \n rather than the HMP monitor's \r\n line endings. Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com> --- python/qemu/utils/__init__.py | 5 +++-- tests/functional/qemu_test/utils.py | 8 ++++++-- tests/vm/basevm.py | 13 ++++++++----- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/python/qemu/utils/__init__.py b/python/qemu/utils/__init__.py index XXXXXXX..XXXXXXX 100644 --- a/python/qemu/utils/__init__.py +++ b/python/qemu/utils/__init__.py @@ -XXX,XX +XXX,XX @@ def get_info_usernet_hostfwd_port(info_usernet_output: str) -> Optional[int]: """ Returns the port given to the hostfwd parameter via info usernet - :param info_usernet_output: output generated by hmp command "info usernet" + :param info_usernet_output: output generated by "info usernet" or + the "info" field from x-query-usernet :return: the port number allocated by the hostfwd option """ - for line in info_usernet_output.split('\r\n'): + for line in info_usernet_output.splitlines(): regex = r'TCP.HOST_FORWARD.*127\.0\.0\.1\s+(\d+)\s+10\.' match = re.search(regex, line) if match is not None: diff --git a/tests/functional/qemu_test/utils.py b/tests/functional/qemu_test/utils.py index XXXXXXX..XXXXXXX 100644 --- a/tests/functional/qemu_test/utils.py +++ b/tests/functional/qemu_test/utils.py @@ -XXX,XX +XXX,XX @@ def get_usernet_hostfwd_port(vm): - res = vm.cmd('human-monitor-command', command_line='info usernet') - return get_info_usernet_hostfwd_port(res) + res = vm.cmd('x-query-usernet') + for entry in res: + port = get_info_usernet_hostfwd_port(entry['info']) + if port is not None: + return port + return None def pow2ceil(x): """ diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index XXXXXXX..XXXXXXX 100644 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -XXX,XX +XXX,XX @@ def boot(self, img, extra_args=[]): self._guest = guest # Init console so we can start consuming the chars. self.console_init() - usernet_info = guest.cmd("human-monitor-command", - command_line="info usernet") - self.ssh_port = get_info_usernet_hostfwd_port(usernet_info) + res = guest.cmd("x-query-usernet") + for entry in res: + port = get_info_usernet_hostfwd_port(entry['info']) + if port is not None: + self.ssh_port = port + break if not self.ssh_port: - raise Exception("Cannot find ssh port from 'info usernet':\n%s" % \ - usernet_info) + raise Exception("Cannot find ssh port from" + " 'x-query-usernet': %s" % res) def console_init(self, timeout = None): if timeout == None: -- 2.54.0
The pnv-xive2-test and pnv-host-i2c-test pass "-serial mon:stdio" but never use HMP commands. The "mon:" chardev prefix creates an HMP monitor mux, which fails when HMP is disabled. Other pnv tests (e.g. pnv-spi-seeprom-test) don't specify -serial at all. Drop the unnecessary -serial mon:stdio option. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qtest/pnv-host-i2c-test.c | 2 +- tests/qtest/pnv-xive2-test.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qtest/pnv-host-i2c-test.c b/tests/qtest/pnv-host-i2c-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/pnv-host-i2c-test.c +++ b/tests/qtest/pnv-host-i2c-test.c @@ -XXX,XX +XXX,XX @@ static void test_host_i2c(const void *data) } qts = qtest_initf("-M %s -smp %d,cores=1,threads=%d -nographic " - "-nodefaults -serial mon:stdio -S " + "-nodefaults -S " "-d guest_errors", machine, SMT, SMT); diff --git a/tests/qtest/pnv-xive2-test.c b/tests/qtest/pnv-xive2-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/pnv-xive2-test.c +++ b/tests/qtest/pnv-xive2-test.c @@ -XXX,XX +XXX,XX @@ static void test_xive(void) QTestState *qts; qts = qtest_initf("-M powernv10 -smp %d,cores=1,threads=%d -nographic " - "-nodefaults -serial mon:stdio -S " + "-nodefaults -S " "-d guest_errors -trace '*xive*'", SMT, SMT); init_xive(qts); -- 2.54.0
The test was using 'human-monitor-command' (which requires HMP) to verify that an integer 'id' is echoed back on failure. Replace with 'query-name' for the success case and 'block_resize' (missing required args) for the failure case, so the test works regardless of HMP availability. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qtest/qmp-test.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/qtest/qmp-test.c b/tests/qtest/qmp-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/qmp-test.c +++ b/tests/qtest/qmp-test.c @@ -XXX,XX +XXX,XX @@ static void test_qmp_protocol(void) g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, "cookie#1"); qobject_unref(resp); - /* Test command failure with 'id' */ - resp = qtest_qmp(qts, "{ 'execute': 'human-monitor-command', 'id': 2 }"); + /* Test integer 'id' is echoed back on success */ + resp = qtest_qmp(qts, "{ 'execute': 'query-name', 'id': 2 }"); g_assert_cmpint(qdict_get_int(resp, "id"), ==, 2); + qobject_unref(resp); + + /* Test integer 'id' is echoed back on failure */ + resp = qtest_qmp(qts, "{ 'execute': 'block_resize', 'id': 3 }"); + g_assert_cmpint(qdict_get_int(resp, "id"), ==, 3); qmp_expect_error_and_unref(resp, "GenericError"); qtest_quit(qts); -- 2.54.0
Convert the three test functions that relied on HMP "info numa" to use QMP "query-cpus-fast" instead, verifying each CPU's node-id through the structured response. Add a check_cpu_node() helper for the per-CPU assertions. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qtest/numa-test.c | 63 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/tests/qtest/numa-test.c b/tests/qtest/numa-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/numa-test.c +++ b/tests/qtest/numa-test.c @@ -XXX,XX +XXX,XX @@ static char *make_cli(const GString *generic_cli, const char *test_cli) return g_strdup_printf("%s %s", generic_cli->str, test_cli); } +static void check_cpu_node(QTestState *qts, int cpu_idx, int expected_node) +{ + QDict *resp; + QList *cpus; + QListEntry *e; + bool found = false; + + resp = qtest_qmp(qts, "{ 'execute': 'query-cpus-fast' }"); + g_assert(resp); + g_assert(qdict_haskey(resp, "return")); + cpus = qdict_get_qlist(resp, "return"); + g_assert(cpus); + + QLIST_FOREACH_ENTRY(cpus, e) { + QDict *cpu = qobject_to(QDict, qlist_entry_obj(e)); + int64_t idx = qdict_get_int(cpu, "cpu-index"); + if (idx == cpu_idx) { + QDict *props = qdict_get_qdict(cpu, "props"); + g_assert(qdict_haskey(props, "node-id")); + g_assert_cmpint(qdict_get_int(props, "node-id"), ==, expected_node); + found = true; + break; + } + } + g_assert(found); + qobject_unref(resp); +} + static void test_mon_explicit(const void *data) { QTestState *qts; - g_autofree char *s = NULL; g_autofree char *cli = NULL; + int i; cli = make_cli(data, "-machine smp.cpus=8 -numa node,nodeid=0,memdev=ram,cpus=0-3 " "-numa node,nodeid=1,cpus=4-7"); qts = qtest_init(cli); - s = qtest_hmp(qts, "info numa"); - g_assert(strstr(s, "node 0 cpus: 0 1 2 3")); - g_assert(strstr(s, "node 1 cpus: 4 5 6 7")); + for (i = 0; i < 4; i++) { + check_cpu_node(qts, i, 0); + } + for (i = 4; i < 8; i++) { + check_cpu_node(qts, i, 1); + } qtest_quit(qts); } @@ -XXX,XX +XXX,XX @@ static void test_mon_explicit(const void *data) static void test_def_cpu_split(const void *data) { QTestState *qts; - g_autofree char *s = NULL; g_autofree char *cli = NULL; + int even_cpus[] = {0, 2, 4, 6}; + int odd_cpus[] = {1, 3, 5, 7}; + int i; cli = make_cli(data, "-machine smp.cpus=8,smp.sockets=8 " "-numa node,memdev=ram -numa node"); qts = qtest_init(cli); - s = qtest_hmp(qts, "info numa"); - g_assert(strstr(s, "node 0 cpus: 0 2 4 6")); - g_assert(strstr(s, "node 1 cpus: 1 3 5 7")); + for (i = 0; i < 4; i++) { + check_cpu_node(qts, even_cpus[i], 0); + check_cpu_node(qts, odd_cpus[i], 1); + } qtest_quit(qts); } @@ -XXX,XX +XXX,XX @@ static void test_def_cpu_split(const void *data) static void test_mon_partial(const void *data) { QTestState *qts; - g_autofree char *s = NULL; g_autofree char *cli = NULL; + int node0_cpus[] = {0, 1, 2, 3, 6, 7}; + int node1_cpus[] = {4, 5}; + int i; cli = make_cli(data, "-machine smp.cpus=8 " "-numa node,nodeid=0,memdev=ram,cpus=0-1 " "-numa node,nodeid=1,cpus=4-5 "); qts = qtest_init(cli); - s = qtest_hmp(qts, "info numa"); - g_assert(strstr(s, "node 0 cpus: 0 1 2 3 6 7")); - g_assert(strstr(s, "node 1 cpus: 4 5")); + for (i = 0; i < 6; i++) { + check_cpu_node(qts, node0_cpus[i], 0); + } + for (i = 0; i < 2; i++) { + check_cpu_node(qts, node1_cpus[i], 1); + } qtest_quit(qts); } -- 2.54.0
The test_cdrom_param() function uses qtest_hmp() to run "info block", which depends on the human-monitor-command QMP endpoint. Replace it with the QMP query-block command so the test works when HMP is disabled (-Dhmp=disabled). Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qtest/cdrom-test.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/tests/qtest/cdrom-test.c b/tests/qtest/cdrom-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/cdrom-test.c +++ b/tests/qtest/cdrom-test.c @@ -XXX,XX +XXX,XX @@ #include "libqtest.h" #include "boot-sector.h" #include "qobject/qdict.h" +#include "qobject/qlist.h" static char isoimage[] = "cdrom-boot-iso-XXXXXX"; @@ -XXX,XX +XXX,XX @@ cleanup: /** * Check that at least the -cdrom parameter is basically working, i.e. we can - * see the filename of the ISO image in the output of "info block" afterwards + * see the filename of the ISO image in the output of "query-block" afterwards */ static void test_cdrom_param(gconstpointer data) { QTestState *qts; - char *resp; + QDict *response; + QList *ret; + QListEntry *entry; + bool found = false; qts = qtest_initf("-M %s -cdrom %s", (const char *)data, isoimage); - resp = qtest_hmp(qts, "info block"); - g_assert(strstr(resp, isoimage) != 0); - g_free(resp); + response = qtest_qmp(qts, "{'execute': 'query-block'}"); + g_assert(response && qdict_haskey(response, "return")); + ret = qdict_get_qlist(response, "return"); + + QLIST_FOREACH_ENTRY(ret, entry) { + QDict *entry_dict = qobject_to(QDict, entry->value); + QDict *inserted = qdict_get_qdict(entry_dict, "inserted"); + if (inserted) { + const char *file = qdict_get_str(inserted, "file"); + if (file && strstr(file, isoimage)) { + found = true; + break; + } + } + } + + g_assert(found); + qobject_unref(response); qtest_quit(qts); } -- 2.54.0
Replace "info qom-tree" with recursive qom-list walk. Disable HMP-only code paths, info qtree, kinda duplicating the test. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qtest/device-introspect-test.c | 111 +++++++++++++++++++++++++++-------- 1 file changed, 88 insertions(+), 23 deletions(-) diff --git a/tests/qtest/device-introspect-test.c b/tests/qtest/device-introspect-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/device-introspect-test.c +++ b/tests/qtest/device-introspect-test.c @@ -XXX,XX +XXX,XX @@ */ /* - * Covers QMP device-list-properties and HMP device_add help. We - * currently don't check that their output makes sense, only that QEMU - * survives. Useful since we've had an astounding number of crash - * bugs around here. + * Covers QMP device-list-properties and HMP device_add help (if + * CONFIG_HMP). We currently don't check that the output makes sense, + * only that QEMU survives. Useful since we've had an astounding + * number of crash bugs around here. */ #include "qemu/osdep.h" @@ -XXX,XX +XXX,XX @@ static QList *device_type_list(QTestState *qts, bool abstract) return qom_list_types(qts, "device", abstract); } +/* + * Recursively walk the QOM composition tree via qom-list and build a + * string representation. This serves two purposes: detecting dangling + * pointers (qom-list would crash QEMU) and detecting leaked objects + * (by comparing the output before and after device introspection). + */ +static void qom_tree_walk(QTestState *qts, const char *path, GString *result) +{ + QDict *resp; + QList *list; + QListEntry *e; + GList *children = NULL; + + resp = qtest_qmp(qts, "{'execute': 'qom-list'," + " 'arguments': {'path': %s}}", path); + g_assert(qdict_haskey(resp, "return")); + list = qdict_get_qlist(resp, "return"); + + QLIST_FOREACH_ENTRY(list, e) { + QDict *prop = qobject_to(QDict, qlist_entry_obj(e)); + const char *type = qdict_get_str(prop, "type"); + if (g_str_has_prefix(type, "child<")) { + const char *name = qdict_get_str(prop, "name"); + children = g_list_prepend(children, g_strdup(name)); + } + } + + children = g_list_sort_with_data(children, (GCompareDataFunc)g_strcmp0, + NULL); + + for (GList *l = children; l; l = l->next) { + const char *name = l->data; + g_autofree char *child_path = (!strcmp(path, "/")) + ? g_strdup_printf("/%s", name) + : g_strdup_printf("%s/%s", path, name); + + g_string_append_printf(result, "%s\n", child_path); + qom_tree_walk(qts, child_path, result); + } + + g_list_free_full(children, g_free); + qobject_unref(resp); +} + +static char *qom_tree_str(QTestState *qts) +{ + GString *result = g_string_new(""); + qom_tree_walk(qts, "/", result); + return g_string_free(result, FALSE); +} + static void test_one_device(QTestState *qts, const char *type) { QDict *resp; - char *help, *escaped; - GRegex *comma; g_test_message("Testing device '%s'", type); @@ -XXX,XX +XXX,XX @@ static void test_one_device(QTestState *qts, const char *type) type); qobject_unref(resp); - comma = g_regex_new(",", 0, 0, NULL); - escaped = g_regex_replace_literal(comma, type, -1, 0, ",,", 0, NULL); - g_regex_unref(comma); +#ifdef CONFIG_HMP + { + g_autofree char *escaped = NULL; + g_autoptr(GRegex) comma = NULL; - help = qtest_hmp(qts, "device_add \"%s,help\"", escaped); - g_free(help); - g_free(escaped); + comma = g_regex_new(",", 0, 0, NULL); + escaped = g_regex_replace_literal(comma, type, -1, 0, ",,", 0, NULL); + g_free(qtest_hmp(qts, "device_add \"%s,help\"", escaped)); + } +#endif } static void test_device_intro_list(void) { QList *types; - char *help; QTestState *qts; qts = qtest_init(common_args); @@ -XXX,XX +XXX,XX @@ static void test_device_intro_list(void) types = device_type_list(qts, true); qobject_unref(types); - help = qtest_hmp(qts, "device_add help"); - g_free(help); +#ifdef CONFIG_HMP + { + g_free(qtest_hmp(qts, "device_add help")); + } +#endif qtest_quit(qts); } @@ -XXX,XX +XXX,XX @@ static void test_qom_list_fields(void) static void test_device_intro_none(void) { QTestState *qts = qtest_init(common_args); - g_autofree char *qom_tree_start = qtest_hmp(qts, "info qom-tree"); + g_autofree char *qom_tree_start = qom_tree_str(qts); g_autofree char *qom_tree_end = NULL; +#ifdef CONFIG_HMP g_autofree char *qtree_start = qtest_hmp(qts, "info qtree"); g_autofree char *qtree_end = NULL; +#endif test_one_device(qts, "nonexistent"); /* Make sure that really nothing changed in the trees */ - qom_tree_end = qtest_hmp(qts, "info qom-tree"); + qom_tree_end = qom_tree_str(qts); g_assert_cmpstr(qom_tree_start, ==, qom_tree_end); +#ifdef CONFIG_HMP qtree_end = qtest_hmp(qts, "info qtree"); g_assert_cmpstr(qtree_start, ==, qtree_end); +#endif qtest_quit(qts); } @@ -XXX,XX +XXX,XX @@ static void test_device_intro_none(void) static void test_device_intro_abstract(void) { QTestState *qts = qtest_init(common_args); - g_autofree char *qom_tree_start = qtest_hmp(qts, "info qom-tree"); + g_autofree char *qom_tree_start = qom_tree_str(qts); g_autofree char *qom_tree_end = NULL; +#ifdef CONFIG_HMP g_autofree char *qtree_start = qtest_hmp(qts, "info qtree"); g_autofree char *qtree_end = NULL; +#endif test_one_device(qts, "device"); /* Make sure that really nothing changed in the trees */ - qom_tree_end = qtest_hmp(qts, "info qom-tree"); + qom_tree_end = qom_tree_str(qts); g_assert_cmpstr(qom_tree_start, ==, qom_tree_end); +#ifdef CONFIG_HMP qtree_end = qtest_hmp(qts, "info qtree"); g_assert_cmpstr(qtree_start, ==, qtree_end); +#endif qtest_quit(qts); } @@ -XXX,XX +XXX,XX @@ static void test_device_intro_concrete(const void *args) QListEntry *entry; const char *type; QTestState *qts = qtest_init(args); - g_autofree char *qom_tree_start = qtest_hmp(qts, "info qom-tree"); + g_autofree char *qom_tree_start = qom_tree_str(qts); g_autofree char *qom_tree_end = NULL; +#ifdef CONFIG_HMP g_autofree char *qtree_start = qtest_hmp(qts, "info qtree"); g_autofree char *qtree_end = NULL; +#endif types = device_type_list(qts, false); @@ -XXX,XX +XXX,XX @@ static void test_device_intro_concrete(const void *args) /* * Some devices leave dangling pointers in QOM behind. - * "info qom-tree" or "info qtree" have a good chance at crashing then. + * Walking the QOM tree via qom-list has a good chance at crashing then. * Also make sure that the tree did not change. */ - qom_tree_end = qtest_hmp(qts, "info qom-tree"); + qom_tree_end = qom_tree_str(qts); g_assert_cmpstr(qom_tree_start, ==, qom_tree_end); - +#ifdef CONFIG_HMP qtree_end = qtest_hmp(qts, "info qtree"); g_assert_cmpstr(qtree_start, ==, qtree_end); +#endif qobject_unref(types); qtest_quit(qts); -- 2.54.0
After nbd-server-remove with mode=hard and an active client, the export is removed from the NBD export list synchronously but remains in the block export list until async cleanup completes (via blk_exp_delete_bh bottom-half). A subsequent nbd-server-remove call may find the export still in the block list with user_owned=false, returning "already shutting down" instead of "not found". Accept both error messages in assertExportNotFound, since both indicate the export is no longer usable. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qemu-iotests/205 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/qemu-iotests/205 b/tests/qemu-iotests/205 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/205 +++ b/tests/qemu-iotests/205 @@ -XXX,XX +XXX,XX @@ class TestNbdServerRemove(iotests.QMPTestCase): def assertExportNotFound(self, name): result = self.vm.qmp('nbd-server-remove', name=name) - self.assert_qmp(result, 'error/desc', "Export 'exp' is not found") + desc = result.get('error', {}).get('desc', '') + self.assertIn(desc, ("Export '%s' is not found" % name, + "Export '%s' is already shutting down" % name)) def assertExistingClients(self, result): self.assert_qmp(result, 'error/desc', "export 'exp' still in use") -- 2.54.0
Add a structured x-query-network QMP command that returns network configuration as a NetworkInfo struct with pre-grouped hub information and a flat list of non-hub clients. Each hub includes its ports with inlined peer client info, and each client includes attached netfilter details. Refactor hmp_info_network() to consume only the QMP result instead of directly accessing internal net_clients state. This decouples HMP from internal data structures, making it possible to remove HMP support without losing programmatic network introspection. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- qapi/net.json | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++ include/net/net.h | 3 +- net/hub.h | 4 +- net/hub.c | 29 +++++++------ net/net-hmp-cmds.c | 59 +++++++++++++++++++------- net/net.c | 70 +++++++++++++++++++++++------- 6 files changed, 243 insertions(+), 44 deletions(-) diff --git a/qapi/net.json b/qapi/net.json index XXXXXXX..XXXXXXX 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -XXX,XX +XXX,XX @@ 'returns': ['UsernetInfo'], 'if': 'CONFIG_SLIRP', 'features': [ 'unstable' ] } + +## +# @NetFilterInfo: +# +# Information about a netfilter attached to a network client. +# +# @name: filter object name (QOM path component) +# +# @type: QOM type name (e.g. "filter-mirror") +# +# @info: filter properties as comma-separated key=value pairs +# (excluding @type) +# +# Since: 11.1 +## +{ 'struct': 'NetFilterInfo', + 'data': { + 'name': 'str', + 'type': 'str', + 'info': 'str' } } + +## +# @NetworkClientInfo: +# +# Information about a network client. +# +# @name: unique network client identifier +# +# @queue-index: index of this queue (0 for single-queue clients) +# +# @type: network client driver type +# +# @info-str: driver-specific formatted information string (e.g. +# "model=e1000,macaddr=52:54:00:12:34:56") +# +# @peer: the connected peer client (always a leaf; the peer's own +# peer field is never populated) +# +# @filters: attached netfilters +# +# Since: 11.1 +## +{ 'struct': 'NetworkClientInfo', + 'data': { + 'name': 'str', + 'queue-index': 'uint32', + 'type': 'NetClientDriver', + 'info-str': 'str', + '*peer': 'NetworkClientInfo', + 'filters': ['NetFilterInfo'] } } + +## +# @NetHubPortInfo: +# +# Information about a hub port. +# +# @name: hub port identifier +# +# @peer: the network client connected through this port +# +# Since: 11.1 +## +{ 'struct': 'NetHubPortInfo', + 'data': { + 'name': 'str', + '*peer': 'NetworkClientInfo' } } + +## +# @NetHubInfo: +# +# Information about a network hub. +# +# @id: hub identifier +# +# @ports: list of ports on this hub +# +# Since: 11.1 +## +{ 'struct': 'NetHubInfo', + 'data': { + 'id': 'int', + 'ports': ['NetHubPortInfo'] } } + +## +# @NetworkInfo: +# +# Information about the network configuration. +# +# @hubs: network hubs and their ports +# +# @clients: network clients not associated with a hub +# +# Since: 11.1 +## +{ 'struct': 'NetworkInfo', + 'data': { + 'hubs': ['NetHubInfo'], + 'clients': ['NetworkClientInfo'] } } + +## +# @x-query-network: +# +# Query the network configuration including hubs and clients. +# +# Features: +# +# @unstable: This command is meant for debugging. +# +# Returns: @NetworkInfo describing hubs and clients. +# +# Since: 11.1 +# +# .. qmp-example:: +# +# -> { "execute": "x-query-network" } +# <- { "return": { "clients": [ { "name": "st0", +# "queue-index": 0, "type": "stream", +# "info-str": "listening" } ] } } +## +{ 'command': 'x-query-network', + 'returns': 'NetworkInfo', + 'features': [ 'unstable' ] } diff --git a/include/net/net.h b/include/net/net.h index XXXXXXX..XXXXXXX 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -XXX,XX +XXX,XX @@ DeviceState *qemu_create_nic_device(const char *typename, bool match_default, void qemu_create_nic_bus_devices(BusState *bus, const char *parent_type, const char *default_model, const char *alias, const char *alias_target); -void print_net_client(Monitor *mon, NetClientState *nc); void net_socket_rs_init(SocketReadState *rs, SocketReadStateFinalize *finalize, bool vnet_hdr); @@ -XXX,XX +XXX,XX @@ void netdev_add(QemuOpts *opts, Error **errp); int net_hub_id_for_client(NetClientState *nc, int *id); +NetworkClientInfo *net_client_info(NetClientState *nc); + #define DEFAULT_NETWORK_SCRIPT CONFIG_SYSCONFDIR "/qemu-ifup" #define DEFAULT_NETWORK_DOWN_SCRIPT CONFIG_SYSCONFDIR "/qemu-ifdown" #define DEFAULT_BRIDGE_HELPER CONFIG_QEMU_HELPERDIR "/qemu-bridge-helper" diff --git a/net/hub.h b/net/hub.h index XXXXXXX..XXXXXXX 100644 --- a/net/hub.h +++ b/net/hub.h @@ -XXX,XX +XXX,XX @@ #ifndef NET_HUB_H #define NET_HUB_H +#include "qapi/qapi-types-net.h" + NetClientState *net_hub_add_port(int hub_id, const char *name, NetClientState *hubpeer); -void net_hub_info(Monitor *mon); void net_hub_check_clients(void); bool net_hub_flush(NetClientState *nc); +NetHubInfoList *net_hub_query_info(void); #endif /* NET_HUB_H */ diff --git a/net/hub.c b/net/hub.c index XXXXXXX..XXXXXXX 100644 --- a/net/hub.c +++ b/net/hub.c @@ -XXX,XX +XXX,XX @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "monitor/monitor.h" +#include "qapi/util.h" #include "net/net.h" #include "clients.h" #include "hub.h" @@ -XXX,XX +XXX,XX @@ NetClientState *net_hub_add_port(int hub_id, const char *name, return &port->nc; } -/** - * Print hub configuration - */ -void net_hub_info(Monitor *mon) +NetHubInfoList *net_hub_query_info(void) { + NetHubInfoList *head = NULL, **tail = &head; NetHub *hub; - NetHubPort *port; QLIST_FOREACH(hub, &hubs, next) { - monitor_printf(mon, "hub %d\n", hub->id); + NetHubInfo *hi = g_new0(NetHubInfo, 1); + NetHubPortInfoList **ptail = &hi->ports; + NetHubPort *port; + + hi->id = hub->id; + QLIST_FOREACH(port, &hub->ports, next) { - monitor_printf(mon, " \\ %s", port->nc.name); + NetHubPortInfo *pi = g_new0(NetHubPortInfo, 1); + pi->name = g_strdup(port->nc.name); if (port->nc.peer) { - monitor_printf(mon, ": "); - print_net_client(mon, port->nc.peer); - } else { - monitor_printf(mon, "\n"); + pi->peer = net_client_info(port->nc.peer); } + QAPI_LIST_APPEND(ptail, pi); } + + QAPI_LIST_APPEND(tail, hi); } + + return head; } /** diff --git a/net/net-hmp-cmds.c b/net/net-hmp-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/net/net-hmp-cmds.c +++ b/net/net-hmp-cmds.c @@ -XXX,XX +XXX,XX @@ #include "monitor/hmp-completion.h" #include "monitor/monitor.h" #include "net/net.h" -#include "net/hub.h" #include "qapi/clone-visitor.h" #include "qapi/qapi-commands-net.h" #include "qapi/qapi-visit-net.h" +#include "qapi/error.h" #include "qobject/qdict.h" #include "qemu/config-file.h" #include "qemu/help_option.h" #include "qemu/option.h" -void hmp_info_network(Monitor *mon, const QDict *qdict) +static void hmp_print_client_info(Monitor *mon, NetworkClientInfo *ci) { - NetClientState *nc, *peer; - NetClientDriver type; + NetFilterInfoList *f; + + monitor_printf(mon, "%s: index=%" PRIu32 ",type=%s,%s\n", + ci->name, ci->queue_index, + NetClientDriver_str(ci->type), ci->info_str); + if (ci->filters) { + monitor_printf(mon, "filters:\n"); + for (f = ci->filters; f; f = f->next) { + monitor_printf(mon, " - %s: type=%s%s%s\n", + f->value->name, f->value->type, + f->value->info[0] ? "," : "", f->value->info); + } + } +} - net_hub_info(mon); +void hmp_info_network(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + g_autoptr(NetworkInfo) info = qmp_x_query_network(&err); + NetHubInfoList *h; + NetworkClientInfoList *entry; - QTAILQ_FOREACH(nc, &net_clients, next) { - peer = nc->peer; - type = nc->info->type; + if (hmp_handle_error(mon, err)) { + return; + } - /* Skip if already printed in hub info */ - if (net_hub_id_for_client(nc, NULL) == 0) { - continue; + for (h = info->hubs; h; h = h->next) { + NetHubPortInfoList *p; + + monitor_printf(mon, "hub %d\n", (int)h->value->id); + for (p = h->value->ports; p; p = p->next) { + if (p->value->peer) { + monitor_printf(mon, " \\ %s: ", p->value->name); + hmp_print_client_info(mon, p->value->peer); + } else { + monitor_printf(mon, " \\ %s\n", p->value->name); + } } + } + + for (entry = info->clients; entry; entry = entry->next) { + NetworkClientInfo *ci = entry->value; - if (!peer || type == NET_CLIENT_DRIVER_NIC) { - print_net_client(mon, nc); + if (!ci->peer || ci->type == NET_CLIENT_DRIVER_NIC) { + hmp_print_client_info(mon, ci); } /* else it's a netdev connected to a NIC, printed with the NIC */ - if (peer && type == NET_CLIENT_DRIVER_NIC) { + if (ci->peer && ci->type == NET_CLIENT_DRIVER_NIC) { monitor_printf(mon, " \\ "); - print_net_client(mon, peer); + hmp_print_client_info(mon, ci->peer); } } } diff --git a/net/net.c b/net/net.c index XXXXXXX..XXXXXXX 100644 --- a/net/net.c +++ b/net/net.c @@ -XXX,XX +XXX,XX @@ void qmp_netdev_del(const char *id, Error **errp) } } -static void netfilter_print_info(Monitor *mon, NetFilterState *nf) +static char *netfilter_get_info_str(NetFilterState *nf) { char *str; ObjectProperty *prop; ObjectPropertyIterator iter; Visitor *v; + GString *buf = g_string_new(NULL); - /* generate info str */ object_property_iter_init(&iter, OBJECT(nf)); while ((prop = object_property_iter_next(&iter))) { if (!strcmp(prop->name, "type")) { @@ -XXX,XX +XXX,XX @@ static void netfilter_print_info(Monitor *mon, NetFilterState *nf) object_property_get(OBJECT(nf), prop->name, v, NULL); visit_complete(v, &str); visit_free(v); - monitor_printf(mon, ",%s=%s", prop->name, str); + if (buf->len > 0) { + g_string_append_c(buf, ','); + } + g_string_append_printf(buf, "%s=%s", prop->name, str); g_free(str); } - monitor_printf(mon, "\n"); + + return g_string_free(buf, false); } -void print_net_client(Monitor *mon, NetClientState *nc) +static NetworkClientInfo *net_client_info_no_peer(NetClientState *nc) { + NetworkClientInfo *info = g_new0(NetworkClientInfo, 1); NetFilterState *nf; - monitor_printf(mon, "%s: index=%d,type=%s,%s\n", nc->name, - nc->queue_index, - NetClientDriver_str(nc->info->type), - nc->info_str); + info->name = g_strdup(nc->name); + info->queue_index = nc->queue_index; + info->type = nc->info->type; + info->info_str = g_strdup(nc->info_str); + if (!QTAILQ_EMPTY(&nc->filters)) { - monitor_printf(mon, "filters:\n"); + NetFilterInfoList **ftail = &info->filters; + QTAILQ_FOREACH(nf, &nc->filters, next) { + NetFilterInfo *fi = g_new0(NetFilterInfo, 1); + fi->name = g_strdup( + object_get_canonical_path_component(OBJECT(nf))); + fi->type = g_strdup(object_get_typename(OBJECT(nf))); + fi->info = netfilter_get_info_str(nf); + QAPI_LIST_APPEND(ftail, fi); + } } - QTAILQ_FOREACH(nf, &nc->filters, next) { - monitor_printf(mon, " - %s: type=%s", - object_get_canonical_path_component(OBJECT(nf)), - object_get_typename(OBJECT(nf))); - netfilter_print_info(mon, nf); + + return info; +} + +NetworkClientInfo *net_client_info(NetClientState *nc) +{ + NetworkClientInfo *info = net_client_info_no_peer(nc); + + if (nc->peer) { + info->peer = net_client_info_no_peer(nc->peer); } + + return info; +} + +NetworkInfo *qmp_x_query_network(Error **errp) +{ + NetworkInfo *info = g_new0(NetworkInfo, 1); + NetworkClientInfoList **tail = &info->clients; + NetClientState *nc; + + info->hubs = net_hub_query_info(); + + QTAILQ_FOREACH(nc, &net_clients, next) { + /* Skip if already gathered in hub info */ + if (net_hub_id_for_client(nc, NULL) == 0) { + continue; + } + QAPI_LIST_APPEND(tail, net_client_info(nc)); + } + + return info; } RxFilterInfoList *qmp_query_rx_filter(const char *name, Error **errp) -- 2.54.0
Replace the HMP "info network" text parsing with the structured x-query-network QMP command. This makes the test assertions more robust by matching individual fields (info-str) instead of parsing the full HMP line format. The EXPECT_STATE macro now takes an explicit netdev id argument to look up the client by name in the QMP response. The strrchr truncation is made NULL-safe: if the truncation character is not found, the full string is compared (and the final g_assert_cmpstr will catch mismatches). While at it, fix the pre-existing duplicate "qemu/sockets.h" include, and reorder includes. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qtest/netdev-socket.c | 143 +++++++++++++++++++++++++------------------- 1 file changed, 82 insertions(+), 61 deletions(-) diff --git a/tests/qtest/netdev-socket.c b/tests/qtest/netdev-socket.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/netdev-socket.c +++ b/tests/qtest/netdev-socket.c @@ -XXX,XX +XXX,XX @@ */ #include "qemu/osdep.h" -#include "qemu/sockets.h" #include <glib/gstdio.h> #include "../unit/socket-helpers.h" #include "libqtest.h" -#include "qobject/qstring.h" -#include "qemu/sockets.h" -#include "qapi/qobject-input-visitor.h" #include "qapi/qapi-visit-sockets.h" +#include "qapi/qobject-input-visitor.h" +#include "qemu/sockets.h" +#include "qobject/qdict.h" +#include "qobject/qlist.h" +#include "qobject/qstring.h" #define CONNECTION_TIMEOUT 60 -#define EXPECT_STATE(q, e, t) \ -do { \ - char *resp = NULL; \ - g_test_timer_start(); \ - do { \ - g_free(resp); \ - resp = qtest_hmp(q, "info network"); \ - if (t) { \ - strrchr(resp, t)[0] = 0; \ - } \ - if (g_str_equal(resp, e)) { \ - break; \ - } \ - } while (g_test_timer_elapsed() < CONNECTION_TIMEOUT); \ - g_assert_cmpstr(resp, ==, e); \ - g_free(resp); \ +/* + * Only checks info-str; type is implicit from the netdev created by each test + */ +static char *query_net_info_str(QTestState *q, const char *name) +{ + QDict *ret; + QList *clients; + QListEntry *entry; + + ret = qtest_qmp_assert_success_ref(q, "{'execute': 'x-query-network'}"); + clients = qdict_get_qlist(ret, "clients"); + g_assert_nonnull(clients); + + QLIST_FOREACH_ENTRY(clients, entry) { + QDict *client = qobject_to(QDict, qlist_entry_obj(entry)); + if (g_str_equal(qdict_get_str(client, "name"), name)) { + char *info = g_strdup(qdict_get_str(client, "info-str")); + qobject_unref(ret); + return info; + } + } + + g_assert_not_reached(); +} + +#define EXPECT_STATE(q, id, e, t) \ +do { \ + char *info = NULL; \ + g_test_timer_start(); \ + do { \ + g_free(info); \ + info = query_net_info_str(q, id); \ + if (t) { \ + char *p = strrchr(info, t); \ + if (p) { \ + p[0] = 0; \ + } \ + } \ + if (g_str_equal(info, e)) { \ + break; \ + } \ + } while (g_test_timer_elapsed() < CONNECTION_TIMEOUT); \ + g_assert_cmpstr(info, ==, e); \ + g_free(info); \ } while (0) static gchar *tmpdir; @@ -XXX,XX +XXX,XX @@ static void test_stream_inet_ipv4(void) "addr.ipv4=on,addr.ipv6=off," "addr.host=127.0.0.1,addr.port=%d", port); - EXPECT_STATE(qts0, "st0: index=0,type=stream,listening\r\n", 0); + EXPECT_STATE(qts0, "st0", "listening", 0); qts1 = qtest_initf("-nodefaults -M none " "-netdev stream,server=false,id=st0,addr.type=inet," "addr.ipv4=on,addr.ipv6=off," "addr.host=127.0.0.1,addr.port=%d", port); - expect = g_strdup_printf("st0: index=0,type=stream,tcp:127.0.0.1:%d\r\n", - port); - EXPECT_STATE(qts1, expect, 0); + expect = g_strdup_printf("tcp:127.0.0.1:%d", port); + EXPECT_STATE(qts1, "st0", expect, 0); g_free(expect); /* the port is unknown, check only the address */ - EXPECT_STATE(qts0, "st0: index=0,type=stream,tcp:127.0.0.1", ':'); + EXPECT_STATE(qts0, "st0", "tcp:127.0.0.1", ':'); qtest_quit(qts1); qtest_quit(qts0); @@ -XXX,XX +XXX,XX @@ static void test_stream_unix_reconnect(void) "-netdev stream,id=st0,server=true,addr.type=unix," "addr.path=%s", path); - EXPECT_STATE(qts0, "st0: index=0,type=stream,listening\r\n", 0); + EXPECT_STATE(qts0, "st0", "listening", 0); qts1 = qtest_initf("-nodefaults -M none " "-netdev stream,server=false,id=st0,addr.type=unix," @@ -XXX,XX +XXX,XX @@ static void test_stream_inet_ipv6(void) "addr.ipv4=off,addr.ipv6=on," "addr.host=::1,addr.port=%d", port); - EXPECT_STATE(qts0, "st0: index=0,type=stream,listening\r\n", 0); + EXPECT_STATE(qts0, "st0", "listening", 0); qts1 = qtest_initf("-nodefaults -M none " "-netdev stream,server=false,id=st0,addr.type=inet," "addr.ipv4=off,addr.ipv6=on," "addr.host=::1,addr.port=%d", port); - expect = g_strdup_printf("st0: index=0,type=stream,tcp:::1:%d\r\n", - port); - EXPECT_STATE(qts1, expect, 0); + expect = g_strdup_printf("tcp:::1:%d", port); + EXPECT_STATE(qts1, "st0", expect, 0); g_free(expect); /* the port is unknown, check only the address */ - EXPECT_STATE(qts0, "st0: index=0,type=stream,tcp:::1", ':'); + EXPECT_STATE(qts0, "st0", "tcp:::1", ':'); qtest_quit(qts1); qtest_quit(qts0); @@ -XXX,XX +XXX,XX @@ static void test_stream_unix(void) "addr.type=unix,addr.path=%s,", path); - EXPECT_STATE(qts0, "st0: index=0,type=stream,listening\r\n", 0); + EXPECT_STATE(qts0, "st0", "listening", 0); qts1 = qtest_initf("-nodefaults -M none " "-netdev stream,id=st0,server=false," "addr.type=unix,addr.path=%s", path); - expect = g_strdup_printf("st0: index=0,type=stream,unix:%s\r\n", path); - EXPECT_STATE(qts1, expect, 0); - EXPECT_STATE(qts0, expect, 0); + expect = g_strdup_printf("unix:%s", path); + EXPECT_STATE(qts1, "st0", expect, 0); + EXPECT_STATE(qts0, "st0", expect, 0); g_free(expect); g_free(path); @@ -XXX,XX +XXX,XX @@ static void test_stream_unix_abstract(void) "addr.abstract=on", path); - EXPECT_STATE(qts0, "st0: index=0,type=stream,listening\r\n", 0); + EXPECT_STATE(qts0, "st0", "listening", 0); qts1 = qtest_initf("-nodefaults -M none " "-netdev stream,id=st0,server=false," "addr.type=unix,addr.path=%s,addr.abstract=on", path); - expect = g_strdup_printf("st0: index=0,type=stream,unix:%s\r\n", path); - EXPECT_STATE(qts1, expect, 0); - EXPECT_STATE(qts0, expect, 0); + expect = g_strdup_printf("unix:%s", path); + EXPECT_STATE(qts1, "st0", expect, 0); + EXPECT_STATE(qts0, "st0", expect, 0); g_free(expect); g_free(path); @@ -XXX,XX +XXX,XX @@ static void test_stream_fd(void) "-netdev stream,id=st0,addr.type=fd,addr.str=%d", sock[0]); - EXPECT_STATE(qts0, "st0: index=0,type=stream,unix:\r\n", 0); + EXPECT_STATE(qts0, "st0", "unix:", 0); qts1 = qtest_initf("-nodefaults -M none " "-netdev stream,id=st0,addr.type=fd,addr.str=%d", sock[1]); - EXPECT_STATE(qts1, "st0: index=0,type=stream,unix:\r\n", 0); - EXPECT_STATE(qts0, "st0: index=0,type=stream,unix:\r\n", 0); + EXPECT_STATE(qts1, "st0", "unix:", 0); + EXPECT_STATE(qts0, "st0", "unix:", 0); qtest_quit(qts1); qtest_quit(qts0); @@ -XXX,XX +XXX,XX @@ static void test_dgram_inet(void) "remote.type=inet,remote.host=127.0.0.1,remote.port=%d", port[0], port[1]); - expect = g_strdup_printf("st0: index=0,type=dgram," - "udp=127.0.0.1:%d/127.0.0.1:%d\r\n", + expect = g_strdup_printf("udp=127.0.0.1:%d/127.0.0.1:%d", port[0], port[1]); - EXPECT_STATE(qts0, expect, 0); + EXPECT_STATE(qts0, "st0", expect, 0); g_free(expect); qts1 = qtest_initf("-nodefaults -M none " @@ -XXX,XX +XXX,XX @@ static void test_dgram_inet(void) "remote.type=inet,remote.host=127.0.0.1,remote.port=%d", port[1], port[0]); - expect = g_strdup_printf("st0: index=0,type=dgram," - "udp=127.0.0.1:%d/127.0.0.1:%d\r\n", + expect = g_strdup_printf("udp=127.0.0.1:%d/127.0.0.1:%d", port[1], port[0]); - EXPECT_STATE(qts1, expect, 0); + EXPECT_STATE(qts1, "st0", expect, 0); g_free(expect); qtest_quit(qts1); @@ -XXX,XX +XXX,XX @@ static void test_dgram_mcast(void) "-netdev dgram,id=st0," "remote.type=inet,remote.host=230.0.0.1,remote.port=1234"); - EXPECT_STATE(qts, "st0: index=0,type=dgram,mcast=230.0.0.1:1234\r\n", 0); + EXPECT_STATE(qts, "st0", "mcast=230.0.0.1:1234", 0); qtest_quit(qts); } @@ -XXX,XX +XXX,XX @@ static void test_dgram_unix(void) "remote.type=unix,remote.path=%s", path0, path1); - expect = g_strdup_printf("st0: index=0,type=dgram,udp=%s:%s\r\n", - path0, path1); - EXPECT_STATE(qts0, expect, 0); + expect = g_strdup_printf("udp=%s:%s", path0, path1); + EXPECT_STATE(qts0, "st0", expect, 0); g_free(expect); qts1 = qtest_initf("-nodefaults -M none " @@ -XXX,XX +XXX,XX @@ static void test_dgram_unix(void) "remote.type=unix,remote.path=%s", path1, path0); - - expect = g_strdup_printf("st0: index=0,type=dgram,udp=%s:%s\r\n", - path1, path0); - EXPECT_STATE(qts1, expect, 0); + expect = g_strdup_printf("udp=%s:%s", path1, path0); + EXPECT_STATE(qts1, "st0", expect, 0); g_free(expect); unlink(path0); @@ -XXX,XX +XXX,XX @@ static void test_dgram_fd(void) "-netdev dgram,id=st0,local.type=fd,local.str=%d", sv[0]); - expect = g_strdup_printf("st0: index=0,type=dgram,fd=%d unix\r\n", sv[0]); - EXPECT_STATE(qts0, expect, 0); + expect = g_strdup_printf("fd=%d unix", sv[0]); + EXPECT_STATE(qts0, "st0", expect, 0); g_free(expect); qts1 = qtest_initf("-nodefaults -M none " "-netdev dgram,id=st0,local.type=fd,local.str=%d", sv[1]); - - expect = g_strdup_printf("st0: index=0,type=dgram,fd=%d unix\r\n", sv[1]); - EXPECT_STATE(qts1, expect, 0); + expect = g_strdup_printf("fd=%d unix", sv[1]); + EXPECT_STATE(qts1, "st0", expect, 0); g_free(expect); qtest_quit(qts1); -- 2.54.0
Convert the qemu-io command infrastructure to use QEMU's Error API (Error **errp) for error propagation instead of printing directly to stdout/stderr via printf/fprintf. The cfunc_t typedef, all ~35 command functions, the dispatcher chain (command/init_check_command/qemuio_command), and helper functions (parse_pattern, create_iovec, qemu_io_alloc_from_file) all gain an Error **errp parameter. Async completion callbacks (aio_read_done, aio_write_done, aio_discard_done) use error_report() since they have no Error path back to the caller. Update tests: - error_report_err() prepends qemu-io: prefix - copy-before-write: check the HMP return value, rather than stdio - other tests: update to check JSON {"return": "Error: error text"} Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- include/qemu-io.h | 4 +- block/monitor/block-hmp-cmds.c | 2 +- qemu-io-cmds.c | 414 +++++++++++++------------ qemu-io.c | 17 +- tests/qemu-iotests/004.out | 20 +- tests/qemu-iotests/021.out | 60 ++-- tests/qemu-iotests/026.out | 228 +++++++------- tests/qemu-iotests/060.out | 44 ++- tests/qemu-iotests/071.out | 10 +- tests/qemu-iotests/072.out | 2 +- tests/qemu-iotests/080.out | 4 +- tests/qemu-iotests/081.out | 2 +- tests/qemu-iotests/083.out | 36 +-- tests/qemu-iotests/089.out | 4 +- tests/qemu-iotests/114.out | 2 +- tests/qemu-iotests/134.out | 2 +- tests/qemu-iotests/137.out | 2 +- tests/qemu-iotests/153.out | 12 +- tests/qemu-iotests/171 | 2 +- tests/qemu-iotests/171.out | 68 ++-- tests/qemu-iotests/205 | 2 +- tests/qemu-iotests/214.out | 2 +- tests/qemu-iotests/220.out | 2 +- tests/qemu-iotests/225.out | 4 +- tests/qemu-iotests/244.out | 12 +- tests/qemu-iotests/249.out | 6 +- tests/qemu-iotests/271.out | 14 +- tests/qemu-iotests/289.out | 2 +- tests/qemu-iotests/305.out | 2 +- tests/qemu-iotests/307.out | 2 +- tests/qemu-iotests/tests/backup-discard-source | 4 +- tests/qemu-iotests/tests/copy-before-write | 66 ++-- tests/qemu-iotests/tests/file-io-error.out | 2 +- tests/qemu-iotests/tests/image-fleecing.out | 12 +- tests/qemu-iotests/tests/inactive-node-nbd.out | 8 +- 35 files changed, 552 insertions(+), 523 deletions(-) diff --git a/include/qemu-io.h b/include/qemu-io.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu-io.h +++ b/include/qemu-io.h @@ -XXX,XX +XXX,XX @@ * Operate on @blk using @argc/@argv as the command's arguments, and * return 0 on success or negative errno on failure. */ -typedef int (*cfunc_t)(BlockBackend *blk, int argc, char **argv); +typedef int (*cfunc_t)(BlockBackend *blk, int argc, char **argv, Error **errp); typedef void (*helpfunc_t)(void); @@ -XXX,XX +XXX,XX @@ typedef struct cmdinfo { extern bool qemuio_misalign; -int qemuio_command(BlockBackend *blk, const char *cmd); +int qemuio_command(BlockBackend *blk, const char *cmd, Error **errp); void qemuio_add_command(const cmdinfo_t *ci); void qemuio_command_usage(const cmdinfo_t *ci); diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/block/monitor/block-hmp-cmds.c +++ b/block/monitor/block-hmp-cmds.c @@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict) * extended, possibly resulting in a read-only guest device keeping write * permissions. Ugly, but it appears to be the lesser evil. */ - qemuio_command(blk, command); + qemuio_command(blk, command, &err); fail: blk_unref(local_blk); diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -XXX,XX +XXX,XX @@ void qemuio_command_usage(const cmdinfo_t *ci) printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline); } -static int init_check_command(BlockBackend *blk, const cmdinfo_t *ct) +static int init_check_command(BlockBackend *blk, const cmdinfo_t *ct, + Error **errp) { if (ct->flags & CMD_FLAG_GLOBAL) { return 1; } if (!(ct->flags & CMD_NOFILE_OK) && !blk) { - fprintf(stderr, "no file open, try 'help open'\n"); + error_setg(errp, "no file open, try 'help open'"); return 0; } return 1; } static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc, - char **argv) + char **argv, Error **errp) { char *cmd = argv[0]; - if (!init_check_command(blk, ct)) { + if (!init_check_command(blk, ct, errp)) { return -EINVAL; } if (argc - 1 < ct->argmin || (ct->argmax != -1 && argc - 1 > ct->argmax)) { if (ct->argmax == -1) { - fprintf(stderr, - "bad argument count %d to %s, expected at least %d arguments\n", - argc-1, cmd, ct->argmin); + error_setg(errp, + "bad argument count %d to %s," + " expected at least %d arguments", + argc - 1, cmd, ct->argmin); } else if (ct->argmin == ct->argmax) { - fprintf(stderr, - "bad argument count %d to %s, expected %d arguments\n", - argc-1, cmd, ct->argmin); + error_setg(errp, + "bad argument count %d to %s, expected %d arguments", + argc - 1, cmd, ct->argmin); } else { - fprintf(stderr, - "bad argument count %d to %s, expected between %d and %d arguments\n", - argc-1, cmd, ct->argmin, ct->argmax); + error_setg(errp, + "bad argument count %d to %s," + " expected between %d and %d arguments", + argc - 1, cmd, ct->argmin, ct->argmax); } return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc, if (ct->perm & ~orig_perm) { uint64_t new_perm; - Error *local_err = NULL; int ret; new_perm = orig_perm | ct->perm; - ret = blk_set_perm(blk, new_perm, orig_shared_perm, &local_err); + ret = blk_set_perm(blk, new_perm, orig_shared_perm, errp); if (ret < 0) { - error_report_err(local_err); return ret; } } } qemu_reset_optind(); - return ct->cfunc(blk, argc, argv); + return ct->cfunc(blk, argc, argv, errp); } static const cmdinfo_t *find_command(const char *cmd) @@ -XXX,XX +XXX,XX @@ static int64_t cvtnum(const char *s) return value; } -static void print_cvtnum_err(int64_t rc, const char *arg) +static void set_cvtnum_err(int64_t rc, const char *arg, Error **errp) { switch (rc) { case -EINVAL: - printf("Parsing error: non-numeric argument," - " or extraneous/unrecognized suffix -- %s\n", arg); + error_setg(errp, "Parsing error: non-numeric argument," + " or extraneous/unrecognized suffix -- %s", arg); break; case -ERANGE: - printf("Parsing error: argument too large -- %s\n", arg); + error_setg(errp, "Parsing error: argument too large -- %s", arg); break; default: - printf("Parsing error: %s\n", arg); + error_setg(errp, "Parsing error: %s", arg); } } @@ -XXX,XX +XXX,XX @@ static void timestr(struct timespec *tv, char *ts, size_t size, int format) * Because the pattern is used as an argument to memset it must evaluate * to an unsigned integer that fits into a single byte. */ -static int parse_pattern(const char *arg) +static int parse_pattern(const char *arg, Error **errp) { char *endptr = NULL; long pattern; pattern = strtol(arg, &endptr, 0); if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') { - printf("%s is not a valid pattern byte\n", arg); + error_setg(errp, "%s is not a valid pattern byte", arg); return -1; } @@ -XXX,XX +XXX,XX @@ static void qemu_io_free(BlockBackend *blk, void *p, size_t len, * NULL on error */ static void *qemu_io_alloc_from_file(BlockBackend *blk, size_t len, - const char *file_name, bool register_buf) + const char *file_name, bool register_buf, + Error **errp) { size_t alloc_len = len + (qemuio_misalign ? MISALIGN_OFFSET : 0); char *alloc_buf, *buf, *end; @@ -XXX,XX +XXX,XX @@ static void *qemu_io_alloc_from_file(BlockBackend *blk, size_t len, int pattern_len; if (!f) { - perror(file_name); + error_setg_errno(errp, errno, "%s", file_name); return NULL; } @@ -XXX,XX +XXX,XX @@ static void *qemu_io_alloc_from_file(BlockBackend *blk, size_t len, pattern_len = fread(buf, 1, len, f); if (ferror(f)) { - perror(file_name); + error_setg_errno(errp, errno, "%s", file_name); goto error; } if (pattern_len == 0) { - fprintf(stderr, "%s: file is empty\n", file_name); + error_setg(errp, "%s: file is empty", file_name); goto error; } @@ -XXX,XX +XXX,XX @@ static void print_report(const char *op, struct timespec *t, int64_t offset, */ static void * create_iovec(BlockBackend *blk, QEMUIOVector *qiov, char **argv, int nr_iov, - int pattern, bool register_buf) + int pattern, bool register_buf, Error **errp) { size_t *sizes = g_new0(size_t, nr_iov); size_t count = 0; @@ -XXX,XX +XXX,XX @@ create_iovec(BlockBackend *blk, QEMUIOVector *qiov, char **argv, int nr_iov, len = cvtnum(arg); if (len < 0) { - print_cvtnum_err(len, arg); + set_cvtnum_err(len, arg, errp); goto fail; } if (len > BDRV_REQUEST_MAX_BYTES) { - printf("Argument '%s' exceeds maximum size %" PRIu64 "\n", arg, - (uint64_t)BDRV_REQUEST_MAX_BYTES); + error_setg(errp, "Argument '%s' exceeds maximum size %" PRIu64, + arg, (uint64_t)BDRV_REQUEST_MAX_BYTES); goto fail; } if (count > BDRV_REQUEST_MAX_BYTES - len) { - printf("The total number of bytes exceed the maximum size %" PRIu64 - "\n", (uint64_t)BDRV_REQUEST_MAX_BYTES); + error_setg(errp, + "The total number of bytes exceed the maximum size %" + PRIu64, (uint64_t)BDRV_REQUEST_MAX_BYTES); goto fail; } @@ -XXX,XX +XXX,XX @@ static void read_help(void) "\n"); } -static int read_f(BlockBackend *blk, int argc, char **argv); +static int read_f(BlockBackend *blk, int argc, char **argv, Error **errp); static const cmdinfo_t read_cmd = { .name = "read", @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t read_cmd = { .help = read_help, }; -static int read_f(BlockBackend *blk, int argc, char **argv) +static int read_f(BlockBackend *blk, int argc, char **argv, Error **errp) { struct timespec t1, t2; bool Cflag = false, qflag = false, vflag = false; @@ -XXX,XX +XXX,XX @@ static int read_f(BlockBackend *blk, int argc, char **argv) lflag = true; pattern_count = cvtnum(optarg); if (pattern_count < 0) { - print_cvtnum_err(pattern_count, optarg); + set_cvtnum_err(pattern_count, optarg, errp); return pattern_count; } break; @@ -XXX,XX +XXX,XX @@ static int read_f(BlockBackend *blk, int argc, char **argv) break; case 'P': Pflag = true; - pattern = parse_pattern(optarg); + pattern = parse_pattern(optarg, errp); if (pattern < 0) { return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int read_f(BlockBackend *blk, int argc, char **argv) sflag = true; pattern_offset = cvtnum(optarg); if (pattern_offset < 0) { - print_cvtnum_err(pattern_offset, optarg); + set_cvtnum_err(pattern_offset, optarg, errp); return pattern_offset; } break; @@ -XXX,XX +XXX,XX @@ static int read_f(BlockBackend *blk, int argc, char **argv) offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } optind++; count = cvtnum(argv[optind]); if (count < 0) { - print_cvtnum_err(count, argv[optind]); + set_cvtnum_err(count, argv[optind], errp); return count; } else if (count > BDRV_REQUEST_MAX_BYTES) { - printf("length cannot exceed %" PRIu64 ", given %s\n", - (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]); + error_setg(errp, "length cannot exceed %" PRIu64 ", given %s", + (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]); return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int read_f(BlockBackend *blk, int argc, char **argv) } if ((pattern_count < 0) || (pattern_count + pattern_offset > count)) { - printf("pattern verification range exceeds end of read data\n"); + error_setg(errp, "pattern verification range exceeds end of read data"); return -EINVAL; } if (bflag) { if (!QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)) { - printf("%" PRId64 " is not a sector-aligned value for 'offset'\n", - offset); + error_setg(errp, + "%" PRId64 " is not a sector-aligned value for 'offset'", + offset); return -EINVAL; } if (!QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE)) { - printf("%"PRId64" is not a sector-aligned value for 'count'\n", - count); + error_setg(errp, + "%" PRId64 " is not a sector-aligned value for 'count'", + count); return -EINVAL; } if (flags & BDRV_REQ_REGISTERED_BUF) { - printf("I/O buffer registration is not supported when reading " - "from vmstate\n"); + error_setg(errp, "I/O buffer registration is not supported when" + " reading from vmstate"); return -EINVAL; } } @@ -XXX,XX +XXX,XX @@ static int read_f(BlockBackend *blk, int argc, char **argv) clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { - printf("read failed: %s\n", strerror(-ret)); + error_setg(errp, "read failed: %s", strerror(-ret)); goto out; } cnt = ret; @@ -XXX,XX +XXX,XX @@ static int read_f(BlockBackend *blk, int argc, char **argv) void *cmp_buf = g_malloc(pattern_count); memset(cmp_buf, pattern, pattern_count); if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) { - printf("Pattern verification failed at offset %" - PRId64 ", %"PRId64" bytes\n", - offset + pattern_offset, pattern_count); + error_setg(errp, "Pattern verification failed at offset %" + PRId64 ", %" PRId64 " bytes", + offset + pattern_offset, pattern_count); ret = -EINVAL; } g_free(cmp_buf); @@ -XXX,XX +XXX,XX @@ static void readv_help(void) "\n"); } -static int readv_f(BlockBackend *blk, int argc, char **argv); +static int readv_f(BlockBackend *blk, int argc, char **argv, Error **errp); static const cmdinfo_t readv_cmd = { .name = "readv", @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t readv_cmd = { .help = readv_help, }; -static int readv_f(BlockBackend *blk, int argc, char **argv) +static int readv_f(BlockBackend *blk, int argc, char **argv, Error **errp) { struct timespec t1, t2; bool Cflag = false, qflag = false, vflag = false; @@ -XXX,XX +XXX,XX @@ static int readv_f(BlockBackend *blk, int argc, char **argv) break; case 'P': Pflag = true; - pattern = parse_pattern(optarg); + pattern = parse_pattern(optarg, errp); if (pattern < 0) { return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int readv_f(BlockBackend *blk, int argc, char **argv) offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } optind++; nr_iov = argc - optind; buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, 0xab, - flags & BDRV_REQ_REGISTERED_BUF); + flags & BDRV_REQ_REGISTERED_BUF, errp); if (buf == NULL) { return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int readv_f(BlockBackend *blk, int argc, char **argv) clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { - printf("readv failed: %s\n", strerror(-ret)); + error_setg(errp, "readv failed: %s", strerror(-ret)); goto out; } cnt = ret; @@ -XXX,XX +XXX,XX @@ static int readv_f(BlockBackend *blk, int argc, char **argv) void *cmp_buf = g_malloc(qiov.size); memset(cmp_buf, pattern, qiov.size); if (memcmp(buf, cmp_buf, qiov.size)) { - printf("Pattern verification failed at offset %" - PRId64 ", %zu bytes\n", offset, qiov.size); + error_setg(errp, "Pattern verification failed at offset %" + PRId64 ", %zu bytes", offset, qiov.size); ret = -EINVAL; } g_free(cmp_buf); @@ -XXX,XX +XXX,XX @@ static void write_help(void) "\n"); } -static int write_f(BlockBackend *blk, int argc, char **argv); +static int write_f(BlockBackend *blk, int argc, char **argv, Error **errp); static const cmdinfo_t write_cmd = { .name = "write", @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t write_cmd = { .help = write_help, }; -static int write_f(BlockBackend *blk, int argc, char **argv) +static int write_f(BlockBackend *blk, int argc, char **argv, Error **errp) { struct timespec t1, t2; bool Cflag = false, qflag = false, bflag = false; @@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv) break; case 'P': Pflag = true; - pattern = parse_pattern(optarg); + pattern = parse_pattern(optarg, errp); if (pattern < 0) { return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv) } if (bflag && zflag) { - printf("-b and -z cannot be specified at the same time\n"); + error_setg(errp, "-b and -z cannot be specified at the same time"); return -EINVAL; } if ((flags & BDRV_REQ_FUA) && (bflag || cflag)) { - printf("-f and -b or -c cannot be specified at the same time\n"); + error_setg(errp, + "-f and -b or -c cannot be specified at the same time"); return -EINVAL; } if ((flags & BDRV_REQ_NO_FALLBACK) && !zflag) { - printf("-n requires -z to be specified\n"); + error_setg(errp, "-n requires -z to be specified"); return -EINVAL; } if ((flags & BDRV_REQ_MAY_UNMAP) && !zflag) { - printf("-u requires -z to be specified\n"); + error_setg(errp, "-u requires -z to be specified"); return -EINVAL; } if (zflag + Pflag + sflag > 1) { - printf("Only one of -z, -P, and -s " - "can be specified at the same time\n"); + error_setg(errp, "Only one of -z, -P, and -s " + "can be specified at the same time"); return -EINVAL; } offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } optind++; count = cvtnum(argv[optind]); if (count < 0) { - print_cvtnum_err(count, argv[optind]); + set_cvtnum_err(count, argv[optind], errp); return count; } else if (count > BDRV_REQUEST_MAX_BYTES && !(flags & BDRV_REQ_NO_FALLBACK)) { - printf("length cannot exceed %" PRIu64 " without -n, given %s\n", - (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]); + error_setg(errp, + "length cannot exceed %" PRIu64 " without -n, given %s", + (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]); return -EINVAL; } if (bflag || cflag) { if (!QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)) { - printf("%" PRId64 " is not a sector-aligned value for 'offset'\n", - offset); + error_setg(errp, + "%" PRId64 " is not a sector-aligned value for 'offset'", + offset); return -EINVAL; } if (!QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE)) { - printf("%"PRId64" is not a sector-aligned value for 'count'\n", - count); + error_setg(errp, + "%" PRId64 " is not a sector-aligned value for 'count'", + count); return -EINVAL; } } if (zflag) { if (flags & BDRV_REQ_REGISTERED_BUF) { - printf("cannot combine zero write with registered I/O buffer\n"); + error_setg(errp, + "cannot combine zero write with registered I/O buffer"); return -EINVAL; } } else { if (sflag) { buf = qemu_io_alloc_from_file(blk, count, file_name, - flags & BDRV_REQ_REGISTERED_BUF); + flags & BDRV_REQ_REGISTERED_BUF, + errp); if (!buf) { return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv) clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { - printf("write failed: %s\n", strerror(-ret)); + error_setg(errp, "write failed: %s", strerror(-ret)); goto out; } cnt = ret; @@ -XXX,XX +XXX,XX @@ writev_help(void) "\n"); } -static int writev_f(BlockBackend *blk, int argc, char **argv); +static int writev_f(BlockBackend *blk, int argc, char **argv, Error **errp); static const cmdinfo_t writev_cmd = { .name = "writev", @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t writev_cmd = { .help = writev_help, }; -static int writev_f(BlockBackend *blk, int argc, char **argv) +static int writev_f(BlockBackend *blk, int argc, char **argv, Error **errp) { struct timespec t1, t2; bool Cflag = false, qflag = false; @@ -XXX,XX +XXX,XX @@ static int writev_f(BlockBackend *blk, int argc, char **argv) flags |= BDRV_REQ_REGISTERED_BUF; break; case 'P': - pattern = parse_pattern(optarg); + pattern = parse_pattern(optarg, errp); if (pattern < 0) { return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int writev_f(BlockBackend *blk, int argc, char **argv) offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } optind++; nr_iov = argc - optind; buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern, - flags & BDRV_REQ_REGISTERED_BUF); + flags & BDRV_REQ_REGISTERED_BUF, errp); if (buf == NULL) { return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int writev_f(BlockBackend *blk, int argc, char **argv) clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { - printf("writev failed: %s\n", strerror(-ret)); + error_setg(errp, "writev failed: %s", strerror(-ret)); goto out; } cnt = ret; @@ -XXX,XX +XXX,XX @@ static void aio_write_done(void *opaque, int ret) if (ret < 0) { - printf("aio_write failed: %s\n", strerror(-ret)); + error_report("aio_write failed: %s", strerror(-ret)); block_acct_failed(blk_get_stats(ctx->blk), &ctx->acct); goto out; } @@ -XXX,XX +XXX,XX @@ static void aio_read_done(void *opaque, int ret) clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { - printf("readv failed: %s\n", strerror(-ret)); + error_report("readv failed: %s", strerror(-ret)); block_acct_failed(blk_get_stats(ctx->blk), &ctx->acct); goto out; } @@ -XXX,XX +XXX,XX @@ static void aio_read_done(void *opaque, int ret) memset(cmp_buf, ctx->pattern, ctx->qiov.size); if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) { - printf("Pattern verification failed at offset %" - PRId64 ", %zu bytes\n", ctx->offset, ctx->qiov.size); + error_report("Pattern verification failed at offset %" + PRId64 ", %zu bytes", ctx->offset, ctx->qiov.size); } g_free(cmp_buf); } @@ -XXX,XX +XXX,XX @@ static void aio_read_help(void) "\n"); } -static int aio_read_f(BlockBackend *blk, int argc, char **argv); +static int aio_read_f(BlockBackend *blk, int argc, char **argv, Error **errp); static const cmdinfo_t aio_read_cmd = { .name = "aio_read", @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t aio_read_cmd = { .help = aio_read_help, }; -static int aio_read_f(BlockBackend *blk, int argc, char **argv) +static int aio_read_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int nr_iov, c; struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); @@ -XXX,XX +XXX,XX @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv) break; case 'P': ctx->Pflag = true; - ctx->pattern = parse_pattern(optarg); + ctx->pattern = parse_pattern(optarg, errp); if (ctx->pattern < 0) { g_free(ctx); return -EINVAL; @@ -XXX,XX +XXX,XX @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv) ctx->offset = cvtnum(argv[optind]); if (ctx->offset < 0) { int ret = ctx->offset; - print_cvtnum_err(ret, argv[optind]); + set_cvtnum_err(ret, argv[optind], errp); g_free(ctx); return ret; } @@ -XXX,XX +XXX,XX @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv) nr_iov = argc - optind; ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, 0xab, - ctx->flags & BDRV_REQ_REGISTERED_BUF); + ctx->flags & BDRV_REQ_REGISTERED_BUF, errp); if (ctx->buf == NULL) { block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_READ); g_free(ctx); @@ -XXX,XX +XXX,XX @@ static void aio_write_help(void) "\n"); } -static int aio_write_f(BlockBackend *blk, int argc, char **argv); +static int aio_write_f(BlockBackend *blk, int argc, char **argv, Error **errp); static const cmdinfo_t aio_write_cmd = { .name = "aio_write", @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t aio_write_cmd = { .help = aio_write_help, }; -static int aio_write_f(BlockBackend *blk, int argc, char **argv) +static int aio_write_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int nr_iov, c; int pattern = 0xcd; @@ -XXX,XX +XXX,XX @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) ctx->flags |= BDRV_REQ_MAY_UNMAP; break; case 'P': - pattern = parse_pattern(optarg); + pattern = parse_pattern(optarg, errp); if (pattern < 0) { g_free(ctx); return -EINVAL; @@ -XXX,XX +XXX,XX @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) } if (ctx->zflag && optind != argc - 2) { - printf("-z supports only a single length parameter\n"); + error_setg(errp, "-z supports only a single length parameter"); g_free(ctx); return -EINVAL; } if ((ctx->flags & BDRV_REQ_MAY_UNMAP) && !ctx->zflag) { - printf("-u requires -z to be specified\n"); + error_setg(errp, "-u requires -z to be specified"); g_free(ctx); return -EINVAL; } if (ctx->zflag && ctx->Pflag) { - printf("-z and -P cannot be specified at the same time\n"); + error_setg(errp, "-z and -P cannot be specified at the same time"); g_free(ctx); return -EINVAL; } if (ctx->zflag && (ctx->flags & BDRV_REQ_REGISTERED_BUF)) { - printf("cannot combine zero write with registered I/O buffer\n"); + error_setg(errp, + "cannot combine zero write with registered I/O buffer"); g_free(ctx); return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) ctx->offset = cvtnum(argv[optind]); if (ctx->offset < 0) { int ret = ctx->offset; - print_cvtnum_err(ret, argv[optind]); + set_cvtnum_err(ret, argv[optind], errp); g_free(ctx); return ret; } @@ -XXX,XX +XXX,XX @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) if (ctx->zflag) { int64_t count = cvtnum(argv[optind]); if (count < 0) { - print_cvtnum_err(count, argv[optind]); + set_cvtnum_err(count, argv[optind], errp); g_free(ctx); return count; } @@ -XXX,XX +XXX,XX @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) } else { nr_iov = argc - optind; ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, - pattern, ctx->flags & BDRV_REQ_REGISTERED_BUF); + pattern, + ctx->flags & BDRV_REQ_REGISTERED_BUF, errp); if (ctx->buf == NULL) { block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_WRITE); g_free(ctx); @@ -XXX,XX +XXX,XX @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) return 0; } -static int aio_flush_f(BlockBackend *blk, int argc, char **argv) +static int aio_flush_f(BlockBackend *blk, int argc, char **argv, Error **errp) { BlockAcctCookie cookie; block_acct_start(blk_get_stats(blk), &cookie, 0, BLOCK_ACCT_FLUSH); @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t aio_flush_cmd = { .oneline = "completes all outstanding aio requests" }; -static int flush_f(BlockBackend *blk, int argc, char **argv) +static int flush_f(BlockBackend *blk, int argc, char **argv, Error **errp) { return blk_flush(blk); } @@ -XXX,XX +XXX,XX @@ static inline int64_t tosector(int64_t bytes) return bytes >> BDRV_SECTOR_BITS; } -static int zone_report_f(BlockBackend *blk, int argc, char **argv) +static int zone_report_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int ret; int64_t offset; @@ -XXX,XX +XXX,XX @@ static int zone_report_f(BlockBackend *blk, int argc, char **argv) ++optind; offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } ++optind; val = cvtnum(argv[optind]); if (val < 0) { - print_cvtnum_err(val, argv[optind]); + set_cvtnum_err(val, argv[optind], errp); return val; } if (val > UINT_MAX) { - printf("Number of zones must be less than 2^32\n"); + error_setg(errp, "Number of zones must be less than 2^32"); return -ERANGE; } nr_zones = val; @@ -XXX,XX +XXX,XX @@ static int zone_report_f(BlockBackend *blk, int argc, char **argv) zones = g_new(BlockZoneDescriptor, nr_zones); ret = blk_zone_report(blk, offset, &nr_zones, zones); if (ret < 0) { - printf("zone report failed: %s\n", strerror(-ret)); + error_setg(errp, "zone report failed: %s", strerror(-ret)); } else { for (int i = 0; i < nr_zones; ++i) { printf("start: 0x%" PRIx64 ", len 0x%" PRIx64 ", " @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t zone_report_cmd = { .oneline = "report zone information", }; -static int zone_open_f(BlockBackend *blk, int argc, char **argv) +static int zone_open_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int ret; int64_t offset, len; ++optind; offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } ++optind; len = cvtnum(argv[optind]); if (len < 0) { - print_cvtnum_err(len, argv[optind]); + set_cvtnum_err(len, argv[optind], errp); return len; } ret = blk_zone_mgmt(blk, BLK_ZO_OPEN, offset, len); if (ret < 0) { - printf("zone open failed: %s\n", strerror(-ret)); + error_setg(errp, "zone open failed: %s", strerror(-ret)); } return ret; } @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t zone_open_cmd = { .oneline = "explicit open a range of zones in zone block device", }; -static int zone_close_f(BlockBackend *blk, int argc, char **argv) +static int zone_close_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int ret; int64_t offset, len; ++optind; offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } ++optind; len = cvtnum(argv[optind]); if (len < 0) { - print_cvtnum_err(len, argv[optind]); + set_cvtnum_err(len, argv[optind], errp); return len; } ret = blk_zone_mgmt(blk, BLK_ZO_CLOSE, offset, len); if (ret < 0) { - printf("zone close failed: %s\n", strerror(-ret)); + error_setg(errp, "zone close failed: %s", strerror(-ret)); } return ret; } @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t zone_close_cmd = { .oneline = "close a range of zones in zone block device", }; -static int zone_finish_f(BlockBackend *blk, int argc, char **argv) +static int zone_finish_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int ret; int64_t offset, len; ++optind; offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } ++optind; len = cvtnum(argv[optind]); if (len < 0) { - print_cvtnum_err(len, argv[optind]); + set_cvtnum_err(len, argv[optind], errp); return len; } ret = blk_zone_mgmt(blk, BLK_ZO_FINISH, offset, len); if (ret < 0) { - printf("zone finish failed: %s\n", strerror(-ret)); + error_setg(errp, "zone finish failed: %s", strerror(-ret)); } return ret; } @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t zone_finish_cmd = { .oneline = "finish a range of zones in zone block device", }; -static int zone_reset_f(BlockBackend *blk, int argc, char **argv) +static int zone_reset_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int ret; int64_t offset, len; ++optind; offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } ++optind; len = cvtnum(argv[optind]); if (len < 0) { - print_cvtnum_err(len, argv[optind]); + set_cvtnum_err(len, argv[optind], errp); return len; } ret = blk_zone_mgmt(blk, BLK_ZO_RESET, offset, len); if (ret < 0) { - printf("zone reset failed: %s\n", strerror(-ret)); + error_setg(errp, "zone reset failed: %s", strerror(-ret)); } return ret; } @@ -XXX,XX +XXX,XX @@ static int do_aio_zone_append(BlockBackend *blk, QEMUIOVector *qiov, return async_ret < 0 ? async_ret : 1; } -static int zone_append_f(BlockBackend *blk, int argc, char **argv) +static int zone_append_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int ret; bool pflag = false; @@ -XXX,XX +XXX,XX @@ static int zone_append_f(BlockBackend *blk, int argc, char **argv) offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } optind++; nr_iov = argc - optind; buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern, - flags & BDRV_REQ_REGISTERED_BUF); + flags & BDRV_REQ_REGISTERED_BUF, errp); if (buf == NULL) { return -EINVAL; } ret = do_aio_zone_append(blk, &qiov, &offset, flags, &total); if (ret < 0) { - printf("zone append failed: %s\n", strerror(-ret)); + error_setg(errp, "zone append failed: %s", strerror(-ret)); goto out; } @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t zone_append_cmd = { .oneline = "append write a number of bytes at a specified offset", }; -static int truncate_f(BlockBackend *blk, int argc, char **argv); +static int truncate_f(BlockBackend *blk, int argc, char **argv, Error **errp); static const cmdinfo_t truncate_cmd = { .name = "truncate", .altname = "t", @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t truncate_cmd = { .oneline = "truncates the current file at the given offset", }; -static int truncate_f(BlockBackend *blk, int argc, char **argv) +static int truncate_f(BlockBackend *blk, int argc, char **argv, Error **errp) { - Error *local_err = NULL; int64_t offset; int c, ret; PreallocMode prealloc = PREALLOC_MODE_OFF; @@ -XXX,XX +XXX,XX @@ static int truncate_f(BlockBackend *blk, int argc, char **argv) prealloc = qapi_enum_parse(&PreallocMode_lookup, optarg, PREALLOC_MODE__MAX, NULL); if (prealloc == PREALLOC_MODE__MAX) { - error_report("Invalid preallocation mode '%s'", optarg); + error_setg(errp, "Invalid preallocation mode '%s'", optarg); return -EINVAL; } break; @@ -XXX,XX +XXX,XX @@ static int truncate_f(BlockBackend *blk, int argc, char **argv) offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[1]); + set_cvtnum_err(offset, argv[1], errp); return offset; } @@ -XXX,XX +XXX,XX @@ static int truncate_f(BlockBackend *blk, int argc, char **argv) * exact=true. It is better to err on the "emit more errors" side * than to be overly permissive. */ - ret = blk_truncate(blk, offset, false, prealloc, 0, &local_err); + ret = blk_truncate(blk, offset, false, prealloc, 0, errp); if (ret < 0) { - error_report_err(local_err); return ret; } return 0; } -static int length_f(BlockBackend *blk, int argc, char **argv) +static int length_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int64_t size; char s1[64]; size = blk_getlength(blk); if (size < 0) { - printf("getlength: %s\n", strerror(-size)); + error_setg(errp, "getlength: %s", strerror(-size)); return size; } @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t length_cmd = { }; -static int info_f(BlockBackend *blk, int argc, char **argv) +static int info_f(BlockBackend *blk, int argc, char **argv, Error **errp) { + ERRP_GUARD(); BlockDriverState *bs = blk_bs(blk); BlockDriverInfo bdi; ImageInfoSpecific *spec_info; - Error *local_err = NULL; char s1[64], s2[64]; int ret; @@ -XXX,XX +XXX,XX @@ static int info_f(BlockBackend *blk, int argc, char **argv) printf("cluster size: %s\n", s1); printf("vm state offset: %s\n", s2); - spec_info = bdrv_get_specific_info(bs, &local_err); - if (local_err) { - error_report_err(local_err); + spec_info = bdrv_get_specific_info(bs, errp); + if (*errp) { return -EIO; } if (spec_info) { @@ -XXX,XX +XXX,XX @@ static void discard_help(void) "\n"); } -static int discard_f(BlockBackend *blk, int argc, char **argv); +static int discard_f(BlockBackend *blk, int argc, char **argv, Error **errp); static const cmdinfo_t discard_cmd = { .name = "discard", @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t discard_cmd = { .help = discard_help, }; -static int discard_f(BlockBackend *blk, int argc, char **argv) +static int discard_f(BlockBackend *blk, int argc, char **argv, Error **errp) { struct timespec t1, t2; bool Cflag = false, qflag = false; @@ -XXX,XX +XXX,XX @@ static int discard_f(BlockBackend *blk, int argc, char **argv) offset = cvtnum(argv[optind]); if (offset < 0) { - print_cvtnum_err(offset, argv[optind]); + set_cvtnum_err(offset, argv[optind], errp); return offset; } optind++; bytes = cvtnum(argv[optind]); if (bytes < 0) { - print_cvtnum_err(bytes, argv[optind]); + set_cvtnum_err(bytes, argv[optind], errp); return bytes; } else if (bytes > BDRV_REQUEST_MAX_BYTES) { - printf("length cannot exceed %"PRIu64", given %s\n", - (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]); + error_setg(errp, "length cannot exceed %" PRIu64 ", given %s", + (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]); return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int discard_f(BlockBackend *blk, int argc, char **argv) clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { - printf("discard failed: %s\n", strerror(-ret)); + error_setg(errp, "discard failed: %s", strerror(-ret)); return ret; } @@ -XXX,XX +XXX,XX @@ static void aio_discard_help(void) "\n"); } -static int aio_discard_f(BlockBackend *blk, int argc, char **argv); +static int aio_discard_f(BlockBackend *blk, int argc, char **argv, + Error **errp); static const cmdinfo_t aio_discard_cmd = { .name = "aio_discard", @@ -XXX,XX +XXX,XX @@ static void aio_discard_done(void *opaque, int ret) clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { - printf("aio_discard failed: %s\n", strerror(-ret)); + error_report("aio_discard failed: %s", strerror(-ret)); block_acct_failed(blk_get_stats(ctx->blk), &ctx->acct); goto out; } @@ -XXX,XX +XXX,XX @@ out: g_free(ctx); } -static int aio_discard_f(BlockBackend *blk, int argc, char **argv) +static int aio_discard_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int c, ret; int64_t count; @@ -XXX,XX +XXX,XX @@ static int aio_discard_f(BlockBackend *blk, int argc, char **argv) ctx->offset = cvtnum(argv[optind]); if (ctx->offset < 0) { ret = ctx->offset; - print_cvtnum_err(ret, argv[optind]); + set_cvtnum_err(ret, argv[optind], errp); g_free(ctx); return ret; } @@ -XXX,XX +XXX,XX @@ static int aio_discard_f(BlockBackend *blk, int argc, char **argv) count = cvtnum(argv[optind]); if (count < 0) { - print_cvtnum_err(count, argv[optind]); + set_cvtnum_err(count, argv[optind], errp); g_free(ctx); return count; } @@ -XXX,XX +XXX,XX @@ static int aio_discard_f(BlockBackend *blk, int argc, char **argv) return 0; } -static int alloc_f(BlockBackend *blk, int argc, char **argv) +static int alloc_f(BlockBackend *blk, int argc, char **argv, Error **errp) { BlockDriverState *bs = blk_bs(blk); int64_t offset, start, remaining, count; @@ -XXX,XX +XXX,XX @@ static int alloc_f(BlockBackend *blk, int argc, char **argv) start = offset = cvtnum(argv[1]); if (offset < 0) { - print_cvtnum_err(offset, argv[1]); + set_cvtnum_err(offset, argv[1], errp); return offset; } if (argc == 3) { count = cvtnum(argv[2]); if (count < 0) { - print_cvtnum_err(count, argv[2]); + set_cvtnum_err(count, argv[2], errp); return count; } } else { @@ -XXX,XX +XXX,XX @@ static int alloc_f(BlockBackend *blk, int argc, char **argv) while (remaining) { ret = bdrv_is_allocated(bs, offset, remaining, &num); if (ret < 0) { - printf("is_allocated failed: %s\n", strerror(-ret)); + error_setg(errp, "is_allocated failed: %s", strerror(-ret)); return ret; } offset += num; @@ -XXX,XX +XXX,XX @@ static int map_is_allocated(BlockDriverState *bs, int64_t offset, return firstret; } -static int map_f(BlockBackend *blk, int argc, char **argv) +static int map_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int64_t offset, bytes; char s1[64], s2[64]; @@ -XXX,XX +XXX,XX @@ static int map_f(BlockBackend *blk, int argc, char **argv) offset = 0; bytes = blk_getlength(blk); if (bytes < 0) { - error_report("Failed to query image length: %s", strerror(-bytes)); + error_setg(errp, "Failed to query image length: %s", strerror(-bytes)); return bytes; } while (bytes) { ret = map_is_allocated(blk_bs(blk), offset, bytes, &num); if (ret < 0) { - error_report("Failed to get allocation status: %s", strerror(-ret)); + error_setg(errp, "Failed to get allocation status: %s", + strerror(-ret)); return ret; } else if (!num) { - error_report("Unexpected end of image"); + error_setg(errp, "Unexpected end of image"); return -EIO; } @@ -XXX,XX +XXX,XX @@ static void reopen_help(void) "\n"); } -static int reopen_f(BlockBackend *blk, int argc, char **argv); +static int reopen_f(BlockBackend *blk, int argc, char **argv, Error **errp); static QemuOptsList reopen_opts = { .name = "reopen", @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t reopen_cmd = { .help = reopen_help, }; -static int reopen_f(BlockBackend *blk, int argc, char **argv) +static int reopen_f(BlockBackend *blk, int argc, char **argv, Error **errp) { BlockDriverState *bs = blk_bs(blk); QemuOpts *qopts; @@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) bool writethrough = !blk_enable_write_cache(blk); bool has_rw_option = false; bool has_cache_option = false; - Error *local_err = NULL; while ((c = getopt(argc, argv, "c:o:rw")) != -1) { switch (c) { case 'c': if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) { - error_report("Invalid cache option: %s", optarg); + error_setg(errp, "Invalid cache option: %s", optarg); return -EINVAL; } has_cache_option = true; @@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) break; case 'r': if (has_rw_option) { - error_report("Only one -r/-w option may be given"); + error_setg(errp, "Only one -r/-w option may be given"); return -EINVAL; } flags &= ~BDRV_O_RDWR; @@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) break; case 'w': if (has_rw_option) { - error_report("Only one -r/-w option may be given"); + error_setg(errp, "Only one -r/-w option may be given"); return -EINVAL; } flags |= BDRV_O_RDWR; @@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) if (!writethrough != blk_enable_write_cache(blk) && blk_get_attached_dev(blk)) { - error_report("Cannot change cache.writeback: Device attached"); + error_setg(errp, "Cannot change cache.writeback: Device attached"); qemu_opts_reset(&reopen_opts); return -EBUSY; } @@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) if (qdict_haskey(opts, BDRV_OPT_READ_ONLY)) { if (has_rw_option) { - error_report("Cannot set both -r/-w and '" BDRV_OPT_READ_ONLY "'"); + error_setg(errp, + "Cannot set both -r/-w and '" BDRV_OPT_READ_ONLY "'"); qobject_unref(opts); return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) if (qdict_haskey(opts, BDRV_OPT_CACHE_DIRECT) || qdict_haskey(opts, BDRV_OPT_CACHE_NO_FLUSH)) { if (has_cache_option) { - error_report("Cannot set both -c and the cache options"); + error_setg(errp, "Cannot set both -c and the cache options"); qobject_unref(opts); return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) qdict_put_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, flags & BDRV_O_NO_FLUSH); } - bdrv_reopen(bs, opts, true, &local_err); - - if (local_err) { - error_report_err(local_err); + if (bdrv_reopen(bs, opts, true, errp) < 0) { return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) return 0; } -static int break_f(BlockBackend *blk, int argc, char **argv) +static int break_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int ret; ret = bdrv_debug_breakpoint(blk_bs(blk), argv[1], argv[2]); if (ret < 0) { - printf("Could not set breakpoint: %s\n", strerror(-ret)); + error_setg(errp, "Could not set breakpoint: %s", strerror(-ret)); return ret; } return 0; } -static int remove_break_f(BlockBackend *blk, int argc, char **argv) +static int remove_break_f(BlockBackend *blk, int argc, char **argv, + Error **errp) { int ret; ret = bdrv_debug_remove_breakpoint(blk_bs(blk), argv[1]); if (ret < 0) { - printf("Could not remove breakpoint %s: %s\n", argv[1], strerror(-ret)); + error_setg(errp, "Could not remove breakpoint %s: %s", + argv[1], strerror(-ret)); return ret; } @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t remove_break_cmd = { .oneline = "remove a breakpoint by tag", }; -static int resume_f(BlockBackend *blk, int argc, char **argv) +static int resume_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int ret; ret = bdrv_debug_resume(blk_bs(blk), argv[1]); if (ret < 0) { - printf("Could not resume request: %s\n", strerror(-ret)); + error_setg(errp, "Could not resume request: %s", strerror(-ret)); return ret; } @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t resume_cmd = { .oneline = "resumes the request tagged as tag", }; -static int wait_break_f(BlockBackend *blk, int argc, char **argv) +static int wait_break_f(BlockBackend *blk, int argc, char **argv, Error **errp) { while (!bdrv_debug_is_suspended(blk_bs(blk), argv[1])) { aio_poll(blk_get_aio_context(blk), true); @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t wait_break_cmd = { .oneline = "waits for the suspension of a request", }; -static int abort_f(BlockBackend *blk, int argc, char **argv) +static int abort_f(BlockBackend *blk, int argc, char **argv, Error **errp) { abort(); } @@ -XXX,XX +XXX,XX @@ static void sigraise_help(void) "\n", SIGTERM); } -static int sigraise_f(BlockBackend *blk, int argc, char **argv); +static int sigraise_f(BlockBackend *blk, int argc, char **argv, Error **errp); static const cmdinfo_t sigraise_cmd = { .name = "sigraise", @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t sigraise_cmd = { .help = sigraise_help, }; -static int sigraise_f(BlockBackend *blk, int argc, char **argv) +static int sigraise_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int64_t sig = cvtnum(argv[1]); if (sig < 0) { - print_cvtnum_err(sig, argv[1]); + set_cvtnum_err(sig, argv[1], errp); return sig; } else if (sig > NSIG) { - printf("signal argument '%s' is too large to be a valid signal\n", - argv[1]); + error_setg(errp, + "signal argument '%s' is too large to be a valid signal", + argv[1]); return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static void sleep_cb(void *opaque) *expired = true; } -static int sleep_f(BlockBackend *blk, int argc, char **argv) +static int sleep_f(BlockBackend *blk, int argc, char **argv, Error **errp) { char *endptr; long ms; @@ -XXX,XX +XXX,XX @@ static int sleep_f(BlockBackend *blk, int argc, char **argv) ms = strtol(argv[1], &endptr, 0); if (ms < 0 || *endptr != '\0') { - printf("%s is not a valid number\n", argv[1]); + error_setg(errp, "%s is not a valid number", argv[1]); return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static void help_all(void) printf("\nUse 'help commandname' for extended help.\n"); } -static int help_f(BlockBackend *blk, int argc, char **argv) +static int help_f(BlockBackend *blk, int argc, char **argv, Error **errp) { const cmdinfo_t *ct; @@ -XXX,XX +XXX,XX @@ static int help_f(BlockBackend *blk, int argc, char **argv) ct = find_command(argv[1]); if (ct == NULL) { - printf("command %s not found\n", argv[1]); + error_setg(errp, "command %s not found", argv[1]); return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t help_cmd = { * Called with aio context of blk acquired. Or with qemu_get_aio_context() * context acquired if blk is NULL. */ -int qemuio_command(BlockBackend *blk, const char *cmd) +int qemuio_command(BlockBackend *blk, const char *cmd, Error **errp) { char *input; const cmdinfo_t *ct; @@ -XXX,XX +XXX,XX @@ int qemuio_command(BlockBackend *blk, const char *cmd) if (c) { ct = find_command(v[0]); if (ct) { - ret = command(blk, ct, c, v); + ret = command(blk, ct, c, v, errp); } else { - fprintf(stderr, "command \"%s\" not found\n", v[0]); + error_setg(errp, "command \"%s\" not found", v[0]); ret = -EINVAL; } } diff --git a/qemu-io.c b/qemu-io.c index XXXXXXX..XXXXXXX 100644 --- a/qemu-io.c +++ b/qemu-io.c @@ -XXX,XX +XXX,XX @@ static int get_eof_char(void) #endif } -static int close_f(BlockBackend *blk, int argc, char **argv) +static int close_f(BlockBackend *blk, int argc, char **argv, Error **errp) { blk_unref(qemuio_blk); qemuio_blk = NULL; @@ -XXX,XX +XXX,XX @@ static void open_help(void) "\n"); } -static int open_f(BlockBackend *blk, int argc, char **argv); +static int open_f(BlockBackend *blk, int argc, char **argv, Error **errp); static const cmdinfo_t open_cmd = { .name = "open", @@ -XXX,XX +XXX,XX @@ static QemuOptsList empty_opts = { }, }; -static int open_f(BlockBackend *blk, int argc, char **argv) +static int open_f(BlockBackend *blk, int argc, char **argv, Error **errp) { int flags = BDRV_O_UNMAP; int readonly = 0; @@ -XXX,XX +XXX,XX @@ static int open_f(BlockBackend *blk, int argc, char **argv) return 0; } -static int quit_f(BlockBackend *blk, int argc, char **argv) +static int quit_f(BlockBackend *blk, int argc, char **argv, Error **errp) { quit_qemu_io = true; return 0; @@ -XXX,XX +XXX,XX @@ static void prep_fetchline(void *opaque) static int do_qemuio_command(const char *cmd) { - return qemuio_command(qemuio_blk, cmd); + Error *local_err = NULL; + int ret; + + ret = qemuio_command(qemuio_blk, cmd, &local_err); + if (local_err) { + error_report_err(local_err); + } + return ret; } static int command_loop(void) diff --git a/tests/qemu-iotests/004.out b/tests/qemu-iotests/004.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/004.out +++ b/tests/qemu-iotests/004.out @@ -XXX,XX +XXX,XX @@ wrote 1048576/1048576 bytes at offset 133169152 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) write into image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write at image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write past image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error pwrite past image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error writev past image boundary -writev failed: Input/output error +qemu-io: writev failed: Input/output error read before image boundary read 1048576/1048576 bytes at offset 133169152 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read into image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error read at image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error read past image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error pread past image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error readv past image boundary -readv failed: Input/output error +qemu-io: readv failed: Input/output error *** done diff --git a/tests/qemu-iotests/021.out b/tests/qemu-iotests/021.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/021.out +++ b/tests/qemu-iotests/021.out @@ -XXX,XX +XXX,XX @@ QA output created by 021 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 == testing writev -P -1 == --1 is not a valid pattern byte +qemu-io: -1 is not a valid pattern byte == testing read -P -1 == --1 is not a valid pattern byte +qemu-io: -1 is not a valid pattern byte == testing write -P -1 == --1 is not a valid pattern byte +qemu-io: -1 is not a valid pattern byte == testing readv -P -1 == --1 is not a valid pattern byte +qemu-io: -1 is not a valid pattern byte == testing aio_read -P -1 == --1 is not a valid pattern byte +qemu-io: -1 is not a valid pattern byte == testing aio_write -P -1 == --1 is not a valid pattern byte +qemu-io: -1 is not a valid pattern byte == testing writev -P 300 == -300 is not a valid pattern byte +qemu-io: 300 is not a valid pattern byte == testing read -P 300 == -300 is not a valid pattern byte +qemu-io: 300 is not a valid pattern byte == testing write -P 300 == -300 is not a valid pattern byte +qemu-io: 300 is not a valid pattern byte == testing readv -P 300 == -300 is not a valid pattern byte +qemu-io: 300 is not a valid pattern byte == testing aio_read -P 300 == -300 is not a valid pattern byte +qemu-io: 300 is not a valid pattern byte == testing aio_write -P 300 == -300 is not a valid pattern byte +qemu-io: 300 is not a valid pattern byte == testing writev -P 12m == -12m is not a valid pattern byte +qemu-io: 12m is not a valid pattern byte == testing read -P 12m == -12m is not a valid pattern byte +qemu-io: 12m is not a valid pattern byte == testing write -P 12m == -12m is not a valid pattern byte +qemu-io: 12m is not a valid pattern byte == testing readv -P 12m == -12m is not a valid pattern byte +qemu-io: 12m is not a valid pattern byte == testing aio_read -P 12m == -12m is not a valid pattern byte +qemu-io: 12m is not a valid pattern byte == testing aio_write -P 12m == -12m is not a valid pattern byte +qemu-io: 12m is not a valid pattern byte == testing writev -P 4k == -4k is not a valid pattern byte +qemu-io: 4k is not a valid pattern byte == testing read -P 4k == -4k is not a valid pattern byte +qemu-io: 4k is not a valid pattern byte == testing write -P 4k == -4k is not a valid pattern byte +qemu-io: 4k is not a valid pattern byte == testing readv -P 4k == -4k is not a valid pattern byte +qemu-io: 4k is not a valid pattern byte == testing aio_read -P 4k == -4k is not a valid pattern byte +qemu-io: 4k is not a valid pattern byte == testing aio_write -P 4k == -4k is not a valid pattern byte +qemu-io: 4k is not a valid pattern byte == testing writev -P route66 == -route66 is not a valid pattern byte +qemu-io: route66 is not a valid pattern byte == testing read -P route66 == -route66 is not a valid pattern byte +qemu-io: route66 is not a valid pattern byte == testing write -P route66 == -route66 is not a valid pattern byte +qemu-io: route66 is not a valid pattern byte == testing readv -P route66 == -route66 is not a valid pattern byte +qemu-io: route66 is not a valid pattern byte == testing aio_read -P route66 == -route66 is not a valid pattern byte +qemu-io: route66 is not a valid pattern byte == testing aio_write -P route66 == -route66 is not a valid pattern byte +qemu-io: route66 is not a valid pattern byte *** done diff --git a/tests/qemu-iotests/026.out b/tests/qemu-iotests/026.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/026.out +++ b/tests/qemu-iotests/026.out @@ -XXX,XX +XXX,XX @@ Errors while writing 128 kB Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_update; errno: 5; imm: off; once: on; write -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_update; errno: 5; imm: off; once: on; write -b -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_update; errno: 5; imm: off; once: off; write +qemu-io: write failed: Input/output error qemu-io: Failed to flush the L2 table cache: Input/output error qemu-io: Failed to flush the refcount block cache: Input/output error -write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_update; errno: 5; imm: off; once: off; write -b +qemu-io: write failed: Input/output error qemu-io: Failed to flush the L2 table cache: Input/output error qemu-io: Failed to flush the refcount block cache: Input/output error -write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_update; errno: 28; imm: off; once: on; write -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_update; errno: 28; imm: off; once: on; write -b -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_update; errno: 28; imm: off; once: off; write +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_update; errno: 28; imm: off; once: off; write -b +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_load; errno: 5; imm: off; once: on; write wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -write failed: Input/output error -read failed: Input/output error +qemu-io: write failed: Input/output error +qemu-io: read failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_load; errno: 5; imm: off; once: on; write -b wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -write failed: Input/output error -read failed: Input/output error +qemu-io: write failed: Input/output error +qemu-io: read failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_load; errno: 5; imm: off; once: off; write wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -write failed: Input/output error -read failed: Input/output error +qemu-io: write failed: Input/output error +qemu-io: read failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_load; errno: 5; imm: off; once: off; write -b wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -write failed: Input/output error -read failed: Input/output error +qemu-io: write failed: Input/output error +qemu-io: read failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_load; errno: 28; imm: off; once: on; write wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -write failed: No space left on device -read failed: No space left on device +qemu-io: write failed: No space left on device +qemu-io: read failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_load; errno: 28; imm: off; once: on; write -b wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -write failed: No space left on device -read failed: No space left on device +qemu-io: write failed: No space left on device +qemu-io: read failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_load; errno: 28; imm: off; once: off; write wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -write failed: No space left on device -read failed: No space left on device +qemu-io: write failed: No space left on device +qemu-io: read failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_load; errno: 28; imm: off; once: off; write -b wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -write failed: No space left on device -read failed: No space left on device +qemu-io: write failed: No space left on device +qemu-io: read failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 5; imm: off; once: on; write -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 5; imm: off; once: on; write -b -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 5; imm: off; once: off; write +qemu-io: write failed: Input/output error qemu-io: Failed to flush the L2 table cache: Input/output error qemu-io: Failed to flush the refcount block cache: Input/output error -write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 5; imm: off; once: off; write -b +qemu-io: write failed: Input/output error qemu-io: Failed to flush the L2 table cache: Input/output error qemu-io: Failed to flush the refcount block cache: Input/output error -write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 28; imm: off; once: on; write -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 28; imm: off; once: on; write -b -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 28; imm: off; once: off; write +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 28; imm: off; once: off; write -b +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_alloc_write; errno: 5; imm: off; once: on; write -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_alloc_write; errno: 5; imm: off; once: on; write -b -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_alloc_write; errno: 5; imm: off; once: off; write +qemu-io: write failed: Input/output error qemu-io: Failed to flush the L2 table cache: Input/output error qemu-io: Failed to flush the refcount block cache: Input/output error -write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_alloc_write; errno: 5; imm: off; once: off; write -b +qemu-io: write failed: Input/output error qemu-io: Failed to flush the L2 table cache: Input/output error qemu-io: Failed to flush the refcount block cache: Input/output error -write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_alloc_write; errno: 28; imm: off; once: on; write -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_alloc_write; errno: 28; imm: off; once: on; write -b -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_alloc_write; errno: 28; imm: off; once: off; write +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_alloc_write; errno: 28; imm: off; once: off; write -b +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: write_aio; errno: 5; imm: off; once: on; write -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: write_aio; errno: 5; imm: off; once: on; write -b -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: write_aio; errno: 5; imm: off; once: off; write +qemu-io: write failed: Input/output error qemu-io: Failed to flush the L2 table cache: Input/output error qemu-io: Failed to flush the refcount block cache: Input/output error -write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: write_aio; errno: 5; imm: off; once: off; write -b +qemu-io: write failed: Input/output error qemu-io: Failed to flush the L2 table cache: Input/output error qemu-io: Failed to flush the refcount block cache: Input/output error -write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: write_aio; errno: 28; imm: off; once: on; write -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: write_aio; errno: 28; imm: off; once: on; write -b -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: write_aio; errno: 28; imm: off; once: off; write +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: write_aio; errno: 28; imm: off; once: off; write -b +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_load; errno: 5; imm: off; once: on; write -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_load; errno: 5; imm: off; once: on; write -b -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_load; errno: 5; imm: off; once: off; write +qemu-io: write failed: Input/output error qemu-io: Failed to flush the L2 table cache: Input/output error qemu-io: Failed to flush the refcount block cache: Input/output error -write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_load; errno: 5; imm: off; once: off; write -b +qemu-io: write failed: Input/output error qemu-io: Failed to flush the L2 table cache: Input/output error qemu-io: Failed to flush the refcount block cache: Input/output error -write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_load; errno: 28; imm: off; once: on; write -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_load; errno: 28; imm: off; once: on; write -b -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_load; errno: 28; imm: off; once: off; write +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_load; errno: 28; imm: off; once: off; write -b +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_update_part; errno: 5; imm: off; once: on; write -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_update_part; errno: 5; imm: off; once: on; write -b -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_update_part; errno: 5; imm: off; once: off; write +qemu-io: write failed: Input/output error qemu-io: Failed to flush the L2 table cache: Input/output error qemu-io: Failed to flush the refcount block cache: Input/output error -write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_update_part; errno: 5; imm: off; once: off; write -b +qemu-io: write failed: Input/output error qemu-io: Failed to flush the L2 table cache: Input/output error qemu-io: Failed to flush the refcount block cache: Input/output error -write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_update_part; errno: 28; imm: off; once: on; write -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_update_part; errno: 28; imm: off; once: on; write -b -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_update_part; errno: 28; imm: off; once: off; write +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_update_part; errno: 28; imm: off; once: off; write -b +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc; errno: 5; imm: off; once: on; write -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc; errno: 5; imm: off; once: on; write -b -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc; errno: 5; imm: off; once: off; write +qemu-io: write failed: Input/output error qemu-io: Failed to flush the L2 table cache: Input/output error qemu-io: Failed to flush the refcount block cache: Input/output error -write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc; errno: 5; imm: off; once: off; write -b +qemu-io: write failed: Input/output error qemu-io: Failed to flush the L2 table cache: Input/output error qemu-io: Failed to flush the refcount block cache: Input/output error -write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc; errno: 28; imm: off; once: on; write -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc; errno: 28; imm: off; once: on; write -b -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc; errno: 28; imm: off; once: off; write +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc; errno: 28; imm: off; once: off; write -b +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: cluster_alloc; errno: 5; imm: off; once: on; write -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: cluster_alloc; errno: 5; imm: off; once: on; write -b -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: cluster_alloc; errno: 5; imm: off; once: off; write -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: cluster_alloc; errno: 5; imm: off; once: off; write -b -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: cluster_alloc; errno: 28; imm: off; once: on; write -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: cluster_alloc; errno: 28; imm: off; once: on; write -b -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: cluster_alloc; errno: 28; imm: off; once: off; write -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: cluster_alloc; errno: 28; imm: off; once: off; write -b -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. === Refcount table growth tests === @@ -XXX,XX +XXX,XX @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc_hookup; errno: 28; imm: off; once: on; write -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc_hookup; errno: 28; imm: off; once: on; write -b -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc_hookup; errno: 28; imm: off; once: off; write +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc_hookup; errno: 28; imm: off; once: off; write -b +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc_write; errno: 28; imm: off; once: on; write -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc_write; errno: 28; imm: off; once: on; write -b -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc_write; errno: 28; imm: off; once: off; write +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc_write; errno: 28; imm: off; once: off; write -b +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: on; write -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: on; write -b -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: off; write +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: off; write -b +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc_write_table; errno: 28; imm: off; once: on; write -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc_write_table; errno: 28; imm: off; once: on; write -b -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc_write_table; errno: 28; imm: off; once: off; write +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc_write_table; errno: 28; imm: off; once: off; write -b +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc_switch_table; errno: 28; imm: off; once: on; write -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc_switch_table; errno: 28; imm: off; once: on; write -b -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc_switch_table; errno: 28; imm: off; once: off; write +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc_switch_table; errno: 28; imm: off; once: off; write -b +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. === L1 growth tests === @@ -XXX,XX +XXX,XX @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_grow_alloc_table; errno: 5; imm: off; once: on -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_grow_alloc_table; errno: 5; imm: off; once: off -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_grow_alloc_table; errno: 28; imm: off; once: on -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_grow_alloc_table; errno: 28; imm: off; once: off -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_grow_write_table; errno: 5; imm: off; once: on -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_grow_write_table; errno: 5; imm: off; once: off +qemu-io: write failed: Input/output error qemu-io: Failed to flush the L2 table cache: Input/output error qemu-io: Failed to flush the refcount block cache: Input/output error -write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_grow_write_table; errno: 28; imm: off; once: on -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_grow_write_table; errno: 28; imm: off; once: off +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_grow_activate_table; errno: 5; imm: off; once: on -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_grow_activate_table; errno: 5; imm: off; once: off +qemu-io: write failed: Input/output error qemu-io: Failed to flush the L2 table cache: Input/output error qemu-io: Failed to flush the refcount block cache: Input/output error -write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_grow_activate_table; errno: 28; imm: off; once: on -write failed: No space left on device +qemu-io: write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_grow_activate_table; errno: 28; imm: off; once: off +qemu-io: write failed: No space left on device qemu-io: Failed to flush the L2 table cache: No space left on device qemu-io: Failed to flush the refcount block cache: No space left on device -write failed: No space left on device No errors were found on the image. === Avoid cluster leaks after temporary failure === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -write failed: Input/output error +qemu-io: write failed: Input/output error wrote 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) No errors were found on the image. @@ -XXX,XX +XXX,XX @@ wrote 1024/1024 bytes at offset 0 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 1024/1024 bytes at offset 0 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. *** done diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/060.out +++ b/tests/qemu-iotests/060.out @@ -XXX,XX +XXX,XX @@ ERROR cluster 3 refcount=1 reference=3 Data may be corrupted, or further writes to the image may corrupt it. incompatible_features [] qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with active L1 table); further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error incompatible_features [1] image: TEST_DIR/t.IMGFMT file format: IMGFMT @@ -XXX,XX +XXX,XX @@ Format specific information: corrupt: true extended l2: false qemu-io: can't open device TEST_DIR/t.IMGFMT: IMGFMT: Image is corrupt; cannot be opened read/write -no file open, try 'help open' +qemu-io: no file open, try 'help open' read 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -XXX,XX +XXX,XX @@ ERROR cluster 2 refcount=1 reference=2 Data may be corrupted, or further writes to the image may corrupt it. incompatible_features [] qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with refcount block); further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error incompatible_features [1] ERROR refcount block 0 refcount=2 ERROR cluster 2 refcount=1 reference=2 @@ -XXX,XX +XXX,XX @@ Data may be corrupted, or further writes to the image may corrupt it. This means waste of disk space, but no harm to data. incompatible_features [] qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with inactive L2 table); further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error incompatible_features [1] ERROR cluster 4 refcount=1 reference=2 Leaked cluster 9 refcount=1 reference=0 @@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 0 wrote 65536/65536 bytes at offset 536870912 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with active L2 table); further corruption events will be suppressed +qemu-io: write failed: Input/output error +qemu-io: aio_write failed: No medium found blkdebug: Suspended request '0' -write failed: Input/output error blkdebug: Resuming request '0' -aio_write failed: No medium found === Testing unallocated image header === @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with qcow2_header); further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error === Testing unaligned L1 entry === @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Marking image as corrupt: L2 table offset 0x42a00 unaligned (L1 index: 0); further corruption events will be suppressed -read failed: Input/output error +qemu-io: read failed: Input/output error Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Marking image as corrupt: Cluster allocation offset 0x52a00 unaligned (L2 offset: 0x40000, L2 index: 0); further corruption events will be suppressed -read failed: Input/output error +qemu-io: read failed: Input/output error === Testing unaligned pre-allocated zero cluster === @@ -XXX,XX +XXX,XX @@ qemu-img: Failed to turn zero into data clusters: Input/output error Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 qcow2: Marking image as corrupt: Refblock offset 0x22a00 unaligned (reftable index: 0); further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error === Testing non-fatal corruption on freeing === @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Image is corrupt: Cluster allocation offset 0x52a00 unaligned (L2 offset: 0x40000, L2 index: 0); further non-fatal corruption events will be suppressed -read failed: Input/output error -read failed: Input/output error +qemu-io: read failed: Input/output error +qemu-io: read failed: Input/output error === Testing non-fatal and then fatal corruption report === @@ -XXX,XX +XXX,XX @@ wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Image is corrupt: Cannot free unaligned cluster 0x52a00; further non-fatal corruption events will be suppressed qcow2: Marking image as corrupt: Cluster allocation offset 0x62a00 unaligned (L2 offset: 0x40000, L2 index: 0x1); further corruption events will be suppressed +qemu-io: read failed: Input/output error discard 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read failed: Input/output error === Testing empty refcount table === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with refcount table); further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error ERROR cluster 0 refcount=0 reference=1 ERROR cluster 1 refcount=0 reference=1 ERROR cluster 3 refcount=0 reference=1 @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Marking image as corrupt: Preventing invalid allocation of refcount block at offset 0; further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error ERROR cluster 0 refcount=0 reference=1 ERROR cluster 1 refcount=0 reference=1 ERROR cluster 3 refcount=0 reference=1 @@ -XXX,XX +XXX,XX @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 qcow2: Marking image as corrupt: Preventing invalid allocation of L2 table at offset 0; further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error ERROR cluster 0 refcount=0 reference=1 ERROR cluster 1 refcount=0 reference=1 ERROR cluster 2 refcount=0 reference=1 @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 wrote 65536/65536 bytes at offset 65536 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Marking image as corrupt: Preventing invalid allocation of compressed cluster at offset 0; further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error ERROR cluster 0 refcount=0 reference=1 ERROR cluster 1 refcount=0 reference=1 ERROR cluster 2 refcount=0 reference=1 @@ -XXX,XX +XXX,XX @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 qcow2: Marking image as corrupt: Preventing invalid allocation of L2 table at offset 0; further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error === Testing dirty corrupt image === @@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 0 discard 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Marking image as corrupt: Preallocated zero cluster offset 0x2a00 unaligned (guest offset: 0); further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error --- Repairing --- Repairing offset=2a00: Preallocated cluster is not properly aligned; L2 entry corrupted. The following inconsistencies were found and repaired: @@ -XXX,XX +XXX,XX @@ wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Marking image as corrupt: Refblock offset 0x2a00 unaligned (reftable index: 0); further corruption events will be suppressed qcow2_free_clusters failed: Input/output error -discard failed: No medium found +qemu-io: discard failed: No medium found --- Repairing --- ERROR refcount block 0 is not cluster aligned; refcount table entry corrupted qcow2: Marking image as corrupt: Refblock offset 0x2a00 unaligned (reftable index: 0); further corruption events will be suppressed @@ -XXX,XX +XXX,XX @@ qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps QMP_VERSION {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_IMAGE_CORRUPTED", "data": {"device": "none0", "msg": "Preventing invalid write on metadata (overlaps with refcount table)", "offset": 65536, "node-name": "drive", "fatal": true, "size": 65536}} -write failed: Input/output error -{"return": ""} +{"return": "Error: write failed: Input/output error\r\n"} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} {"return": {}} @@ -XXX,XX +XXX,XX @@ QMP_VERSION {"return": {}} qcow2: Image is corrupt: L2 table offset 0x2a2a2a00 unaligned (L1 index: 0); further non-fatal corruption events will be suppressed {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_IMAGE_CORRUPTED", "data": {"device": "", "msg": "L2 table offset 0x2a2a2a00 unaligned (L1 index: 0)", "node-name": "drive", "fatal": false}} -{"return": ""} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} {"return": {}} diff --git a/tests/qemu-iotests/071.out b/tests/qemu-iotests/071.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/071.out +++ b/tests/qemu-iotests/071.out @@ -XXX,XX +XXX,XX @@ blkverify: read offset=0 bytes=512 contents mismatch at offset 0 === Testing blkdebug through filename === -read failed: Input/output error +qemu-io: read failed: Input/output error === Testing blkdebug through file blockref === -read failed: Input/output error +qemu-io: read failed: Input/output error === Testing blkdebug on existing block device === @@ -XXX,XX +XXX,XX @@ QMP_VERSION {"return": {}} {"return": {}} {"return": {}} -read failed: Input/output error -{"return": ""} +{"return": "Error: read failed: Input/output error\r\n"} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} {"return": {}} @@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) {"return": ""} -read failed: Input/output error -{"return": ""} +{"return": "Error: read failed: Input/output error\r\n"} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} QEMU_PROG: Failed to flush the L2 table cache: Input/output error QEMU_PROG: Failed to flush the refcount block cache: Input/output error diff --git a/tests/qemu-iotests/072.out b/tests/qemu-iotests/072.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/072.out +++ b/tests/qemu-iotests/072.out @@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 512 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 512/512 bytes at offset 1024 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Pattern verification failed at offset 0, 512 bytes +qemu-io: Pattern verification failed at offset 0, 512 bytes read 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) *** done diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/080.out +++ b/tests/qemu-iotests/080.out @@ -XXX,XX +XXX,XX @@ wrote 512/512 bytes at offset 0 qemu-img: Failed to load snapshot: Snapshot L1 table offset invalid qemu-img: Snapshot L1 table offset invalid qemu-img: Failed to turn zero into data clusters: Invalid argument +qemu-io: write failed: Invalid argument qemu-io: Failed to flush the refcount block cache: Invalid argument -write failed: Invalid argument qemu-img: Snapshot L1 table offset invalid qemu-img: Could not apply snapshot 'test': Failed to load snapshot: Invalid argument qemu-img: Could not delete snapshot 'test': Snapshot L1 table offset invalid @@ -XXX,XX +XXX,XX @@ wrote 512/512 bytes at offset 0 qemu-img: Failed to load snapshot: Snapshot L1 table too large qemu-img: Snapshot L1 table too large qemu-img: Failed to turn zero into data clusters: File too large +qemu-io: write failed: File too large qemu-io: Failed to flush the refcount block cache: File too large -write failed: File too large qemu-img: Snapshot L1 table too large qemu-img: Could not apply snapshot 'test': Failed to load snapshot: File too large qemu-img: Could not delete snapshot 'test': Snapshot L1 table too large diff --git a/tests/qemu-iotests/081.out b/tests/qemu-iotests/081.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/081.out +++ b/tests/qemu-iotests/081.out @@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 0 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == checking that quorum is broken == -read failed: Input/output error +qemu-io: read failed: Input/output error == checking the blkverify mode with broken content == quorum: offset=0 bytes=10485760 contents mismatch at offset 0 diff --git a/tests/qemu-iotests/083.out b/tests/qemu-iotests/083.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/083.out +++ b/tests/qemu-iotests/083.out @@ -XXX,XX +XXX,XX @@ qemu-io: can't open device nbd+tcp://127.0.0.1:PORT/foo === Check disconnect after neg2 === -read failed: Input/output error +qemu-io: read failed: Input/output error === Check disconnect 8 neg2 === @@ -XXX,XX +XXX,XX @@ qemu-io: can't open device nbd+tcp://127.0.0.1:PORT/foo === Check disconnect before request === -read failed: Input/output error +qemu-io: read failed: Input/output error === Check disconnect after request === -read failed: Input/output error +qemu-io: read failed: Input/output error === Check disconnect before reply === -read failed: Input/output error +qemu-io: read failed: Input/output error === Check disconnect after reply === -read failed: Input/output error +qemu-io: read failed: Input/output error === Check disconnect 4 reply === -read failed: Input/output error +qemu-io: read failed: Input/output error === Check disconnect 8 reply === -read failed: Input/output error +qemu-io: read failed: Input/output error === Check disconnect before data === -read failed: Input/output error +qemu-io: read failed: Input/output error === Check disconnect after data === @@ -XXX,XX +XXX,XX @@ qemu-io: can't open device nbd+tcp://127.0.0.1:PORT/ === Check disconnect after neg-classic === -read failed: Input/output error +qemu-io: read failed: Input/output error === Check disconnect before neg1 === @@ -XXX,XX +XXX,XX @@ qemu-io: can't open device nbd+unix:///foo?socket=SOCK_DIR/nbd.sock === Check disconnect after neg2 === -read failed: Input/output error +qemu-io: read failed: Input/output error === Check disconnect 8 neg2 === @@ -XXX,XX +XXX,XX @@ qemu-io: can't open device nbd+unix:///foo?socket=SOCK_DIR/nbd.sock === Check disconnect before request === -read failed: Input/output error +qemu-io: read failed: Input/output error === Check disconnect after request === -read failed: Input/output error +qemu-io: read failed: Input/output error === Check disconnect before reply === -read failed: Input/output error +qemu-io: read failed: Input/output error === Check disconnect after reply === -read failed: Input/output error +qemu-io: read failed: Input/output error === Check disconnect 4 reply === -read failed: Input/output error +qemu-io: read failed: Input/output error === Check disconnect 8 reply === -read failed: Input/output error +qemu-io: read failed: Input/output error === Check disconnect before data === -read failed: Input/output error +qemu-io: read failed: Input/output error === Check disconnect after data === @@ -XXX,XX +XXX,XX @@ qemu-io: can't open device nbd+unix:///?socket=SOCK_DIR/nbd.sock === Check disconnect after neg-classic === -read failed: Input/output error +qemu-io: read failed: Input/output error *** done diff --git a/tests/qemu-iotests/089.out b/tests/qemu-iotests/089.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/089.out +++ b/tests/qemu-iotests/089.out @@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 512 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 512/512 bytes at offset 1024 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Pattern verification failed at offset 0, 512 bytes +qemu-io: Pattern verification failed at offset 0, 512 bytes read 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 0 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 wrote 512/512 bytes at offset 229376 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read failed: Input/output error +qemu-io: read failed: Input/output error === Testing qemu-img info output === diff --git a/tests/qemu-iotests/114.out b/tests/qemu-iotests/114.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/114.out +++ b/tests/qemu-iotests/114.out @@ -XXX,XX +XXX,XX @@ cluster_size: 65536 backing file: TEST_DIR/t.IMGFMT.base backing file format: foo qemu-io: can't open device TEST_DIR/t.qcow2: Could not open backing file: Unknown driver 'foo' -no file open, try 'help open' +qemu-io: no file open, try 'help open' read 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qemu-img: Could not change the backing file to 'TEST_DIR/t.qcow2.base': backing format must be specified diff --git a/tests/qemu-iotests/134.out b/tests/qemu-iotests/134.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/134.out +++ b/tests/qemu-iotests/134.out @@ -XXX,XX +XXX,XX @@ read 134217728/134217728 bytes at offset 0 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == verify pattern failure with wrong password == -Pattern verification failed at offset 0, 134217728 bytes +qemu-io: Pattern verification failed at offset 0, 134217728 bytes read 134217728/134217728 bytes at offset 0 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) *** done diff --git a/tests/qemu-iotests/137.out b/tests/qemu-iotests/137.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/137.out +++ b/tests/qemu-iotests/137.out @@ -XXX,XX +XXX,XX @@ OK: Dirty bit not set Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 qemu-io: Parameter 'lazy-refcounts' expects 'on' or 'off' qcow2: Marking image as corrupt: Preventing invalid allocation of L2 table at offset 0; further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error *** done diff --git a/tests/qemu-iotests/153.out b/tests/qemu-iotests/153.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/153.out +++ b/tests/qemu-iotests/153.out @@ -XXX,XX +XXX,XX @@ Is another process using the image [TEST_DIR/t.qcow2]? _qemu_io_wrapper -c open TEST_DIR/t.qcow2 -c read 0 512 qemu-io: can't open device TEST_DIR/t.qcow2: Failed to get "write" lock Is another process using the image [TEST_DIR/t.qcow2]? -no file open, try 'help open' +qemu-io: no file open, try 'help open' _qemu_io_wrapper -c open -r TEST_DIR/t.qcow2 -c read 0 512 qemu-io: can't open device TEST_DIR/t.qcow2: Failed to get shared "write" lock Is another process using the image [TEST_DIR/t.qcow2]? -no file open, try 'help open' +qemu-io: no file open, try 'help open' _qemu_img_wrapper info TEST_DIR/t.qcow2 qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get shared "write" lock @@ -XXX,XX +XXX,XX @@ _qemu_io_wrapper -U -r -c read 0 512 TEST_DIR/t.qcow2 _qemu_io_wrapper -c open -U TEST_DIR/t.qcow2 -c read 0 512 qemu-io: can't open device TEST_DIR/t.qcow2: force-share=on can only be used with read-only images -no file open, try 'help open' +qemu-io: no file open, try 'help open' _qemu_io_wrapper -c open -r -U TEST_DIR/t.qcow2 -c read 0 512 @@ -XXX,XX +XXX,XX @@ _qemu_io_wrapper -r -c read 0 512 TEST_DIR/t.qcow2 _qemu_io_wrapper -c open TEST_DIR/t.qcow2 -c read 0 512 qemu-io: can't open device TEST_DIR/t.qcow2: Failed to get "write" lock Is another process using the image [TEST_DIR/t.qcow2]? -no file open, try 'help open' +qemu-io: no file open, try 'help open' _qemu_io_wrapper -c open -r TEST_DIR/t.qcow2 -c read 0 512 @@ -XXX,XX +XXX,XX @@ _qemu_io_wrapper -U -r -c read 0 512 TEST_DIR/t.qcow2 _qemu_io_wrapper -c open -U TEST_DIR/t.qcow2 -c read 0 512 qemu-io: can't open device TEST_DIR/t.qcow2: force-share=on can only be used with read-only images -no file open, try 'help open' +qemu-io: no file open, try 'help open' _qemu_io_wrapper -c open -r -U TEST_DIR/t.qcow2 -c read 0 512 @@ -XXX,XX +XXX,XX @@ _qemu_io_wrapper -U -r -c read 0 512 TEST_DIR/t.qcow2 _qemu_io_wrapper -c open -U TEST_DIR/t.qcow2 -c read 0 512 qemu-io: can't open device TEST_DIR/t.qcow2: force-share=on can only be used with read-only images -no file open, try 'help open' +qemu-io: no file open, try 'help open' _qemu_io_wrapper -c open -r -U TEST_DIR/t.qcow2 -c read 0 512 diff --git a/tests/qemu-iotests/171 b/tests/qemu-iotests/171 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/171 +++ b/tests/qemu-iotests/171 @@ -XXX,XX +XXX,XX @@ img_offset=512 img_size=512 _make_test_img $size ( -$QEMU_IO "$(img_json)" <<EOT +$QEMU_IO "$(img_json)" 2>&1 <<EOT write -P 0x0a 0 512 write -P 0x0a 511 1 write -P 0x0a 512 1 diff --git a/tests/qemu-iotests/171.out b/tests/qemu-iotests/171.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/171.out +++ b/tests/qemu-iotests/171.out @@ -XXX,XX +XXX,XX @@ wrote 1/1 bytes at offset 3583 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) write across image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write at image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write after image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error writev before/after image boundary -writev failed: Input/output error +qemu-io: writev failed: Input/output error read before image boundary read 1/1 bytes at offset 3583 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read across image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error read at image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error read after image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error readv before/after image boundary -readv failed: Input/output error +qemu-io: readv failed: Input/output error fill image with pattern wrote 4096/4096 bytes at offset 0 @@ -XXX,XX +XXX,XX @@ read 4/4 bytes at offset 510 4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) write zeroes across image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write zeroes at image boundary and check wrote 2/2 bytes at offset 3582 @@ -XXX,XX +XXX,XX @@ wrote 2/2 bytes at offset 3582 00000ffe: 00 00 .. read 2/2 bytes at offset 4094 2 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read failed: Input/output error +qemu-io: read failed: Input/output error fill image with pattern wrote 4096/4096 bytes at offset 0 @@ -XXX,XX +XXX,XX @@ read 4/4 bytes at offset 510 4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) discard across image boundary -discard failed: Input/output error +qemu-io: discard failed: Input/output error discard at image boundary and check discard 2/2 bytes at offset 3582 @@ -XXX,XX +XXX,XX @@ discard 2/2 bytes at offset 3582 00000ffe: 00 00 .. read 2/2 bytes at offset 4094 2 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read failed: Input/output error +qemu-io: read failed: Input/output error == test 'offset' and 'size' options == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4096 @@ -XXX,XX +XXX,XX @@ wrote 1/1 bytes at offset 2047 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) write across image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write at image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write after image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error writev before/after image boundary -writev failed: Input/output error +qemu-io: writev failed: Input/output error read before image boundary read 1/1 bytes at offset 2047 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read across image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error read at image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error read after image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error readv before/after image boundary -readv failed: Input/output error +qemu-io: readv failed: Input/output error fill image with pattern wrote 4096/4096 bytes at offset 0 @@ -XXX,XX +XXX,XX @@ read 4/4 bytes at offset 510 4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) write zeroes across image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write zeroes at image boundary and check wrote 2/2 bytes at offset 2046 @@ -XXX,XX +XXX,XX @@ read 4/4 bytes at offset 510 4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) discard across image boundary -discard failed: Input/output error +qemu-io: discard failed: Input/output error discard at image boundary and check discard 2/2 bytes at offset 2046 @@ -XXX,XX +XXX,XX @@ wrote 1/1 bytes at offset 2047 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) write across image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write at image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write after image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error writev before/after image boundary -writev failed: Input/output error +qemu-io: writev failed: Input/output error read before image boundary read 1/1 bytes at offset 2047 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read across image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error read at image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error read after image boundary -read failed: Input/output error +qemu-io: read failed: Input/output error readv before/after image boundary -readv failed: Input/output error +qemu-io: readv failed: Input/output error fill image with pattern wrote 4096/4096 bytes at offset 0 @@ -XXX,XX +XXX,XX @@ read 4/4 bytes at offset 8 4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) write zeroes across image boundary -write failed: Input/output error +qemu-io: write failed: Input/output error write zeroes at image boundary and check wrote 2/2 bytes at offset 2046 @@ -XXX,XX +XXX,XX @@ read 4/4 bytes at offset 8 4 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) discard across image boundary -discard failed: Input/output error +qemu-io: discard failed: Input/output error discard at image boundary and check discard 2/2 bytes at offset 2046 @@ -XXX,XX +XXX,XX @@ wrote 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 1/1 bytes at offset 511 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -write failed: Input/output error +qemu-io: write failed: Input/output error wrote 1024/1024 bytes at offset 0 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 1/1 bytes at offset 1023 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -write failed: Input/output error +qemu-io: write failed: Input/output error checking boundaries 000001fe: 00 00 0a 0a .... read 4/4 bytes at offset 510 diff --git a/tests/qemu-iotests/205 b/tests/qemu-iotests/205 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/205 +++ b/tests/qemu-iotests/205 @@ -XXX,XX +XXX,XX @@ class TestNbdServerRemove(iotests.QMPTestCase): def assertReadFailed(self, qemu_io_output): self.assertEqual(filter_qemu_io(qemu_io_output).strip(), - 'read failed: Input/output error') + 'qemu-io: read failed: Input/output error') def assertConnectFailed(self, qemu_io_output): self.assertEqual(filter_qemu_io(qemu_io_output).strip(), diff --git a/tests/qemu-iotests/214.out b/tests/qemu-iotests/214.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/214.out +++ b/tests/qemu-iotests/214.out @@ -XXX,XX +XXX,XX @@ wrote 2097152/2097152 bytes at offset 0 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 2097152/2097152 bytes at offset 2097152 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read failed: Input/output error +qemu-io: read failed: Input/output error No errors were found on the image. read 4194304/4194304 bytes at offset 0 4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) diff --git a/tests/qemu-iotests/220.out b/tests/qemu-iotests/220.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/220.out +++ b/tests/qemu-iotests/220.out @@ -XXX,XX +XXX,XX @@ wrote 2097152/2097152 bytes at offset 37748736 No errors were found on the image. image size 39845888 == Trying to write compressed cluster == -write failed: File too large +qemu-io: write failed: File too large image size 562949957615616 == Writing normal cluster == wrote 2097152/2097152 bytes at offset 0 diff --git a/tests/qemu-iotests/225.out b/tests/qemu-iotests/225.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/225.out +++ b/tests/qemu-iotests/225.out @@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 0 QEMU X.Y.Z monitor - type 'help' for more information (qemu) qemu-io overlay "read 0 512" -read failed: Invalid argument +Error: read failed: Invalid argument === Testing non-VMDK backing image === QEMU X.Y.Z monitor - type 'help' for more information (qemu) qemu-io overlay "read 0 512" -read failed: Invalid argument +Error: read failed: Invalid argument *** done diff --git a/tests/qemu-iotests/244.out b/tests/qemu-iotests/244.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/244.out +++ b/tests/qemu-iotests/244.out @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0 read 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qemu-io: can't open device TEST_DIR/t.qcow2: Could not open 'inexistent': No such file or directory -no file open, try 'help open' +qemu-io: no file open, try 'help open' Data file required, but without data file name in the image: qemu-io: can't open device TEST_DIR/t.qcow2: 'data-file' is required for this image -no file open, try 'help open' +qemu-io: no file open, try 'help open' read 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qemu-io: can't open device TEST_DIR/t.qcow2: Could not open 'inexistent': No such file or directory -no file open, try 'help open' +qemu-io: no file open, try 'help open' Setting data-file for an image with internal data: Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 qemu-io: can't open device TEST_DIR/t.qcow2: 'data-file' can only be set for images with an external data file -no file open, try 'help open' +qemu-io: no file open, try 'help open' qemu-io: can't open device TEST_DIR/t.qcow2: Could not open 'inexistent': No such file or directory -no file open, try 'help open' +qemu-io: no file open, try 'help open' === Conflicting features === @@ -XXX,XX +XXX,XX @@ qemu-img: error while writing at byte 0: Operation not supported Convert uncompressed, then write compressed data manually: Images are identical. -write failed: Operation not supported +qemu-io: write failed: Operation not supported No errors were found on the image. Take an internal snapshot: diff --git a/tests/qemu-iotests/249.out b/tests/qemu-iotests/249.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/249.out +++ b/tests/qemu-iotests/249.out @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t. { 'execute': 'human-monitor-command', 'arguments': {'command-line': 'qemu-io none0 "aio_write 0 2k"'}} -{"return": "Block node is read-onlyrn"} +{"return": "Error: Block node is read-onlyrn"} === Run block-commit on base using an invalid filter node name @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t. { 'execute': 'human-monitor-command', 'arguments': {'command-line': 'qemu-io none0 "aio_write 0 2k"'}} -{"return": "Block node is read-onlyrn"} +{"return": "Error: Block node is read-onlyrn"} === Run block-commit on base using the default filter node name @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t. { 'execute': 'human-monitor-command', 'arguments': {'command-line': 'qemu-io none0 "aio_write 0 2k"'}} -{"return": "Block node is read-onlyrn"} +{"return": "Error: Block node is read-onlyrn"} *** done diff --git a/tests/qemu-iotests/271.out b/tests/qemu-iotests/271.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/271.out +++ b/tests/qemu-iotests/271.out @@ -XXX,XX +XXX,XX @@ L2 entry #0: 0x8000000000050001 0000000000000001 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 L2 entry #1: 0x8000000000060000 00000001ffffffff qcow2: Marking image as corrupt: Invalid cluster entry found (L2 offset: 0x40000, L2 index: 0x1); further corruption events will be suppressed -read failed: Input/output error +qemu-io: read failed: Input/output error ### Corrupted L2 entries - read test (unallocated) ### @@ -XXX,XX +XXX,XX @@ L2 entry #0: 0x0000000000000001 0000000000000000 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 L2 entry #0: 0x0000000000000000 0000000000000001 qcow2: Marking image as corrupt: Invalid cluster entry found (L2 offset: 0x40000, L2 index: 0); further corruption events will be suppressed -read failed: Input/output error +qemu-io: read failed: Input/output error # Both 'subcluster is zero' and 'subcluster is allocated' bits set Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 L2 entry #1: 0x0000000000000000 0000000100000001 qcow2: Marking image as corrupt: Invalid cluster entry found (L2 offset: 0x40000, L2 index: 0x1); further corruption events will be suppressed -read failed: Input/output error +qemu-io: read failed: Input/output error ### Compressed cluster with subcluster bitmap != 0 - read test ### @@ -XXX,XX +XXX,XX @@ L2 entry #0: 0x8000000000050001 0000000000000001 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 L2 entry #1: 0x8000000000060000 00000001ffffffff qcow2: Marking image as corrupt: Invalid cluster entry found (L2 offset: 0x40000, L2 index: 0x1); further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error ### Corrupted L2 entries - write test (unallocated) ### @@ -XXX,XX +XXX,XX @@ L2 entry #0: 0x8000000000060000 0000000000000001 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 L2 entry #0: 0x0000000000000000 0000000000000001 qcow2: Marking image as corrupt: Invalid cluster entry found (L2 offset: 0x40000, L2 index: 0); further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error # Both 'subcluster is zero' and 'subcluster is allocated' bits set Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 L2 entry #1: 0x0000000000000000 0000000100000001 qcow2: Marking image as corrupt: Invalid cluster entry found (L2 offset: 0x40000, L2 index: 0x1); further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error ### Compressed cluster with subcluster bitmap != 0 - write test ### @@ -XXX,XX +XXX,XX @@ Double checking the fixed image now... 1 errors were found on the image. Data may be corrupted, or further writes to the image may corrupt it. qcow2: Marking image as corrupt: Cluster allocation offset 0x50200 unaligned (L2 offset: 0x40000, L2 index: 0); further corruption events will be suppressed -read failed: Input/output error +qemu-io: read failed: Input/output error # Corrupted L2 entry, no allocated subclusters # Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw Repairing offset=50200: Preallocated cluster is not properly aligned; L2 entry corrupted. diff --git a/tests/qemu-iotests/289.out b/tests/qemu-iotests/289.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/289.out +++ b/tests/qemu-iotests/289.out @@ -XXX,XX +XXX,XX @@ QA output created by 289 === Avoid freeing external data clusters on failure === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65536 data_file=TEST_DIR/t.IMGFMT.data_file -write failed: Input/output error +qemu-io: write failed: Input/output error No errors were found on the image. *** done diff --git a/tests/qemu-iotests/305.out b/tests/qemu-iotests/305.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/305.out +++ b/tests/qemu-iotests/305.out @@ -XXX,XX +XXX,XX @@ discard 1024/1024 bytes at offset 125952 ### Corrupt the offset of the second refcount block ### Try to allocate the discarded clusters again qcow2: Marking image as corrupt: Refblock offset 0x20600 unaligned (reftable index: 0x1); further corruption events will be suppressed -write failed: Input/output error +qemu-io: write failed: Input/output error *** done diff --git a/tests/qemu-iotests/307.out b/tests/qemu-iotests/307.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/307.out +++ b/tests/qemu-iotests/307.out @@ -XXX,XX +XXX,XX @@ exports available: 1 {"error": {"class": "GenericError", "desc": "export 'export1' still in use"}} {"execute": "block-export-del", "arguments": {"id": "export1", "mode": "hard"}} {"return": {}} -read failed: Input/output error +qemu-io: read failed: Input/output error {"execute": "query-block-exports", "arguments": {}} {"return": []} diff --git a/tests/qemu-iotests/tests/backup-discard-source b/tests/qemu-iotests/tests/backup-discard-source index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/tests/backup-discard-source +++ b/tests/qemu-iotests/tests/backup-discard-source @@ -XXX,XX +XXX,XX @@ class TestBackup(iotests.QMPTestCase): def tearDown(self): # That should fail, because region is discarded - self.vm.hmp_qemu_io('access', 'read 0 1M') + result = self.vm.hmp_qemu_io('access', 'read 0 1M') self.vm.shutdown() - self.assertTrue('read failed: Permission denied' in self.vm.get_log()) + self.assertIn('read failed: Permission denied', result['return']) # Final check that temp image is empty mapping = qemu_img_map(temp_img) diff --git a/tests/qemu-iotests/tests/copy-before-write b/tests/qemu-iotests/tests/copy-before-write index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/tests/copy-before-write +++ b/tests/qemu-iotests/tests/copy-before-write @@ -XXX,XX +XXX,XX @@ class TestCbwError(iotests.QMPTestCase): result = self.vm.qmp('human-monitor-command', command_line='qemu-io cbw "write 0 1M"') - self.assert_qmp(result, 'return', '') + write_res = result['return'] result = self.vm.qmp('human-monitor-command', command_line='qemu-io access "read 0 1M"') - self.assert_qmp(result, 'return', '') + read_res = result['return'] self.vm.shutdown() log = self.vm.get_log() log = iotests.filter_qtest(log) log = iotests.filter_qemu_io(log) - return log + return log, write_res, read_res def do_cbw_error_via_blockdev_backup(self, on_cbw_error=None): self.vm.cmd('blockdev-add', { @@ -XXX,XX +XXX,XX @@ class TestCbwError(iotests.QMPTestCase): result = self.vm.qmp('human-monitor-command', command_line='qemu-io cbw "write 0 1M"') - self.assert_qmp(result, 'return', '') + write_res = result['return'] result = self.vm.qmp('human-monitor-command', command_line='qemu-io access "read 0 1M"') - self.assert_qmp(result, 'return', '') + read_res = result['return'] self.vm.shutdown() log = self.vm.get_log() log = iotests.filter_qemu_io(log) - return log + return log, write_res, read_res def test_break_snapshot_on_cbw_error(self): """break-snapshot behavior: Guest write succeed, but further snapshot-read fails, as snapshot is broken. """ - log = self.do_cbw_error('break-snapshot') + log, write_res, read_res = self.do_cbw_error('break-snapshot') + self.assertEqual(write_res, '') + self.assertIn('read failed: Permission denied', read_res) self.assertEqual(log, """\ wrote 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read failed: Permission denied """) def test_break_guest_write_on_cbw_error(self): @@ -XXX,XX +XXX,XX @@ read failed: Permission denied Guest write fails, but snapshot-access continues working and further snapshot-read succeeds. """ - log = self.do_cbw_error('break-guest-write') + log, write_res, read_res = self.do_cbw_error('break-guest-write') + self.assertIn('write failed: Input/output error', write_res) + self.assertEqual(read_res, '') self.assertEqual(log, """\ -write failed: Input/output error read 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) """) @@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 0 """Ensure CBW filter accepts break-snapshot policy specified in blockdev-backup QMP command. """ - log = self.do_cbw_error_via_blockdev_backup('break-snapshot') + log, write_res, read_res = \ + self.do_cbw_error_via_blockdev_backup('break-snapshot') + self.assertEqual(write_res, '') + self.assertIn('read failed: Permission denied', read_res) self.assertEqual(log, """\ wrote 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read failed: Permission denied """) def test_break_guest_write_policy_forwarding(self): """Ensure CBW filter accepts break-guest-write policy specified in blockdev-backup QMP command. """ - log = self.do_cbw_error_via_blockdev_backup('break-guest-write') + log, write_res, read_res = \ + self.do_cbw_error_via_blockdev_backup('break-guest-write') + self.assertIn('write failed: Input/output error', write_res) + self.assertEqual(read_res, '') self.assertEqual(log, """\ -write failed: Input/output error read 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) """) @@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 0 """Ensure break-guest-write policy is used by default when on-cbw-error is not explicitly specified. """ - log = self.do_cbw_error_via_blockdev_backup() + log, write_res, read_res = \ + self.do_cbw_error_via_blockdev_backup() + self.assertIn('write failed: Input/output error', write_res) + self.assertEqual(read_res, '') self.assertEqual(log, """\ -write failed: Input/output error read 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) """) @@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 0 result = self.vm.qmp('human-monitor-command', command_line='qemu-io cbw "write 0 512K"') - self.assert_qmp(result, 'return', '') + write1_res = result['return'] # We need second write to trigger throttling result = self.vm.qmp('human-monitor-command', command_line='qemu-io cbw "write 512K 512K"') - self.assert_qmp(result, 'return', '') + write2_res = result['return'] result = self.vm.qmp('human-monitor-command', command_line='qemu-io access "read 0 1M"') - self.assert_qmp(result, 'return', '') + read_res = result['return'] self.vm.shutdown() log = self.vm.get_log() log = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', log) log = re.sub(r'\[I \+\d+\.\d+\] CLOSED\n?$', '', log) log = iotests.filter_qemu_io(log) - return log + return log, write1_res, write2_res, read_res def test_timeout_break_guest(self): - log = self.do_cbw_timeout('break-guest-write') + log, write1_res, write2_res, read_res = \ + self.do_cbw_timeout('break-guest-write') + self.assertEqual(write1_res, '') # macOS and FreeBSD tend to represent ETIMEDOUT as # "Operation timed out", when Linux prefer # "Connection timed out" - log = log.replace('Operation timed out', - 'Connection timed out') + write2_res = write2_res.replace('Operation timed out', + 'Connection timed out') + self.assertIn('write failed: Connection timed out', write2_res) + self.assertEqual(read_res, '') self.assertEqual(log, """\ wrote 524288/524288 bytes at offset 0 512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -write failed: Connection timed out read 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) """) def test_timeout_break_snapshot(self): - log = self.do_cbw_timeout('break-snapshot') + log, write1_res, write2_res, read_res = \ + self.do_cbw_timeout('break-snapshot') + self.assertEqual(write1_res, '') + self.assertEqual(write2_res, '') + self.assertIn('read failed: Permission denied', read_res) self.assertEqual(log, """\ wrote 524288/524288 bytes at offset 0 512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 524288/524288 bytes at offset 524288 512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read failed: Permission denied """) diff --git a/tests/qemu-iotests/tests/file-io-error.out b/tests/qemu-iotests/tests/file-io-error.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/tests/file-io-error.out +++ b/tests/qemu-iotests/tests/file-io-error.out @@ -XXX,XX +XXX,XX @@ QA output created by file-io-error }} {"return": {}} -write failed: Input/output error +qemu-io: write failed: Input/output error {'execute': 'block-export-del', 'arguments': {'id': 'exp0'}} diff --git a/tests/qemu-iotests/tests/image-fleecing.out b/tests/qemu-iotests/tests/image-fleecing.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/tests/image-fleecing.out +++ b/tests/qemu-iotests/tests/image-fleecing.out @@ -XXX,XX +XXX,XX @@ read -P0xd5 1M 64k read -P0xdc 32M 64k read -P0xcd 0x3ff0000 64k read -P0 0x00f8000 32k -read failed: Invalid argument +qemu-io: read failed: Invalid argument read -P0 0x2010000 32k -read failed: Invalid argument +qemu-io: read failed: Invalid argument read -P0 0x3fe0000 64k -read failed: Invalid argument +qemu-io: read failed: Invalid argument --- Testing COW --- @@ -XXX,XX +XXX,XX @@ read -P0xd5 1M 64k read -P0xdc 32M 64k read -P0xcd 0x3ff0000 64k read -P0 0x00f8000 32k -read failed: Invalid argument +qemu-io: read failed: Invalid argument read -P0 0x2010000 32k -read failed: Invalid argument +qemu-io: read failed: Invalid argument read -P0 0x3fe0000 64k -read failed: Invalid argument +qemu-io: read failed: Invalid argument --- Cleanup --- diff --git a/tests/qemu-iotests/tests/inactive-node-nbd.out b/tests/qemu-iotests/tests/inactive-node-nbd.out index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/tests/inactive-node-nbd.out +++ b/tests/qemu-iotests/tests/inactive-node-nbd.out @@ -XXX,XX +XXX,XX @@ target-fmt active: True read 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -write failed: Operation not permitted +qemu-io: write failed: Operation not permitted -write failed: Operation not permitted +qemu-io: write failed: Operation not permitted -write failed: Operation not permitted +qemu-io: write failed: Operation not permitted -discard failed: Operation not permitted +qemu-io: discard failed: Operation not permitted qemu-io: Failed to get allocation status: Operation not permitted -- 2.54.0
Add a "qemu-io" command to the qtest protocol so that tests can issue block layer I/O commands without going through the HMP monitor's "human-monitor-command" QMP, or use QMP at all. Unfortunately, many tests will prefer to use QMP as they also monitor and log other events. It's easier if it is pipelined in the same stream. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qtest/libqtest.h | 11 +++++++++++ system/qtest.c | 14 ++++++++++++++ tests/qtest/libqtest.c | 14 ++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/libqtest.h +++ b/tests/qtest/libqtest.h @@ -XXX,XX +XXX,XX @@ char *qtest_hmp(QTestState *s, const char *fmt, ...) G_GNUC_PRINTF(2, 3); char *qtest_vhmp(QTestState *s, const char *fmt, va_list ap) G_GNUC_PRINTF(2, 0); +/** + * qtest_qemu_io: + * @s: #QTestState instance to operate on. + * @device: block device node-name or BlockBackend name. + * @fmt: qemu-io command to send, formats arguments like sprintf(). + * + * Send a qemu-io command via the qtest protocol. + */ +void qtest_qemu_io(QTestState *s, const char *device, + const char *fmt, ...) G_GNUC_PRINTF(3, 4); + void qtest_module_load(QTestState *s, const char *prefix, const char *libname); /** diff --git a/system/qtest.c b/system/qtest.c index XXXXXXX..XXXXXXX 100644 --- a/system/qtest.c +++ b/system/qtest.c @@ -XXX,XX +XXX,XX @@ #include "qom/object_interfaces.h" #include "qom/qom-qobject.h" #include "qobject/qobject.h" +#include "qapi-commands-block.h" #define MAX_IRQ 256 @@ -XXX,XX +XXX,XX @@ static void qtest_process_command(CharFrontend *chr, gchar **words) } g_slist_free(list); qtest_send(chr, "OK\n"); + } else if (strcmp(words[0], "qemu-io") == 0) { + const char *io_dev; + g_autofree char *io_cmd = NULL; + Error *err = NULL; + + g_assert(words[1] && words[2]); + io_dev = words[1]; + io_cmd = g_strjoinv(" ", &words[2]); + + qmp_x_qemu_io(io_dev, NULL, io_cmd, &err); + qtest_sendf(chr, err ? "FAIL %s\n" : "OK\n", + err ? error_get_pretty(err) : NULL); + error_free(err); } else if (process_command_cb && process_command_cb(chr, words)) { /* Command got consumed by the callback handler */ } else { diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -XXX,XX +XXX,XX @@ char *qtest_hmp(QTestState *s, const char *fmt, ...) return ret; } +void qtest_qemu_io(QTestState *s, const char *device, + const char *fmt, ...) +{ + va_list ap; + g_autofree char *cmd = NULL; + + va_start(ap, fmt); + cmd = g_strdup_vprintf(fmt, ap); + va_end(ap); + + qtest_sendf(s, "qemu-io %s %s\n", device, cmd); + qtest_rsp(s); +} + const char *qtest_get_arch(void) { /* -- 2.54.0
Depend on the previous commit to be accepted. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qtest/ide-test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qtest/ide-test.c b/tests/qtest/ide-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/ide-test.c +++ b/tests/qtest/ide-test.c @@ -XXX,XX +XXX,XX @@ static void test_flush(void) make_dirty(qts, 0); /* Delay the completion of the flush request until we explicitly do it */ - g_free(qtest_hmp(qts, "qemu-io ide0-hd0 \"break flush_to_os A\"")); + qtest_qemu_io(qts, "ide0-hd0", "break flush_to_os A"); /* FLUSH CACHE command on device 0*/ qpci_io_writeb(dev, ide_bar, reg_device, 0); @@ -XXX,XX +XXX,XX @@ static void test_flush(void) assert_bit_clear(data, DF | ERR | DRQ); /* Complete the command */ - g_free(qtest_hmp(qts, "qemu-io ide0-hd0 \"resume A\"")); + qtest_qemu_io(qts, "ide0-hd0", "resume A"); /* Check registers */ data = qpci_io_readb(dev, ide_bar, reg_device); -- 2.54.0
Add an x-qemu-io QMP command that runs qemu-io commands on block devices. The command accepts a device name (block backend name, node-name, or qdev ID) and a qemu-io command string. Refactor hmp_qemu_io() to be a thin wrapper around the new QMP command, following the standard HMP-over-QMP pattern used by other block commands. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- qapi/block.json | 34 ++++++++++++++++++ block/monitor/block-hmp-cmds.c | 60 ++------------------------------ block/monitor/qmp-cmds.c | 79 ++++++++++++++++++++++++++++++++++++++++++ block/monitor/meson.build | 1 + 4 files changed, 117 insertions(+), 57 deletions(-) diff --git a/qapi/block.json b/qapi/block.json index XXXXXXX..XXXXXXX 100644 --- a/qapi/block.json +++ b/qapi/block.json @@ -XXX,XX +XXX,XX @@ '*boundaries-zap': ['uint64'], '*boundaries-flush': ['uint64'] }, 'allow-preconfig': true } + +## +# @x-qemu-io: +# +# Run a qemu-io command on a block device. Take either a block +# backend name or a qdev ID to identify the device. +# +# @device: the block backend name, node-name to run the +# command on. +# +# @qdev: the qdev ID of the block device to run the +# command on. +# +# @command: the qemu-io command string to execute. +# +# Features: +# +# @unstable: This command is for testing only. +# +# Since: 11.1 +# +# .. qmp-example:: +# +# -> { "execute": "x-qemu-io", +# "arguments": { "device": "virtio0", +# "command": "read 0 512" } } +# <- { "return": {} } +## +{ 'command': 'x-qemu-io', + 'data': { '*device': 'str', + '*qdev': 'str', + 'command': 'str' }, + 'features': [ 'unstable' ], + 'allow-preconfig': true } diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/block/monitor/block-hmp-cmds.c +++ b/block/monitor/block-hmp-cmds.c @@ -XXX,XX +XXX,XX @@ #include "block/qapi.h" #include "block/block_int.h" #include "block/block-hmp-cmds.h" -#include "qemu-io.h" static void hmp_drive_add_node(Monitor *mon, const char *optstr) { @@ -XXX,XX +XXX,XX @@ void hmp_eject(Monitor *mon, const QDict *qdict) void hmp_qemu_io(Monitor *mon, const QDict *qdict) { - BlockBackend *blk = NULL; - BlockDriverState *bs = NULL; - BlockBackend *local_blk = NULL; bool qdev = qdict_get_try_bool(qdict, "qdev", false); const char *device = qdict_get_str(qdict, "device"); const char *command = qdict_get_str(qdict, "command"); Error *err = NULL; - int ret; - - if (qdev) { - blk = blk_by_qdev_id(device, &err); - if (!blk) { - goto fail; - } - } else { - blk = blk_by_name(device); - if (!blk) { - bs = bdrv_lookup_bs(NULL, device, &err); - if (!bs) { - goto fail; - } - } - } - - if (bs) { - blk = local_blk = blk_new(bdrv_get_aio_context(bs), 0, BLK_PERM_ALL); - ret = blk_insert_bs(blk, bs, &err); - if (ret < 0) { - goto fail; - } - } - - /* - * Notably absent: Proper permission management. This is sad, but it seems - * almost impossible to achieve without changing the semantics and thereby - * limiting the use cases of the qemu-io HMP command. - * - * In an ideal world we would unconditionally create a new BlockBackend for - * qemuio_command(), but we have commands like 'reopen' and want them to - * take effect on the exact BlockBackend whose name the user passed instead - * of just on a temporary copy of it. - * - * Another problem is that deleting the temporary BlockBackend involves - * draining all requests on it first, but some qemu-iotests cases want to - * issue multiple aio_read/write requests and expect them to complete in - * the background while the monitor has already returned. - * - * This is also what prevents us from saving the original permissions and - * restoring them later: We can't revoke permissions until all requests - * have completed, and we don't know when that is nor can we really let - * anything else run before we have revoken them to avoid race conditions. - * - * What happens now is that command() in qemu-io-cmds.c can extend the - * permissions if necessary for the qemu-io command. And they simply stay - * extended, possibly resulting in a read-only guest device keeping write - * permissions. Ugly, but it appears to be the lesser evil. - */ - qemuio_command(blk, command, &err); -fail: - blk_unref(local_blk); + qmp_x_qemu_io(qdev ? NULL : device, + qdev ? device : NULL, + command, &err); hmp_handle_error(mon, err); } diff --git a/block/monitor/qmp-cmds.c b/block/monitor/qmp-cmds.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/block/monitor/qmp-cmds.c @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "qemu/osdep.h" + +#include "system/block-backend.h" +#include "block/block_int.h" +#include "qapi/qapi-commands-block.h" +#include "qapi/error.h" +#include "qemu-io.h" + +void qmp_x_qemu_io(const char *device, const char *qdev, + const char *command, Error **errp) +{ + BlockBackend *blk = NULL; + BlockBackend *local_blk = NULL; + BlockDriverState *bs = NULL; + int ret; + + if (!device && !qdev) { + error_setg(errp, "Must specify either device or qdev"); + return; + } + if (qdev && device) { + error_setg(errp, "Cannot specify both qdev and device"); + return; + } + + if (qdev) { + blk = blk_by_qdev_id(qdev, errp); + if (!blk) { + return; + } + } else { + blk = blk_by_name(device); + if (!blk) { + bs = bdrv_lookup_bs(NULL, device, errp); + if (!bs) { + return; + } + } + } + + if (bs) { + blk = local_blk = blk_new(bdrv_get_aio_context(bs), 0, BLK_PERM_ALL); + ret = blk_insert_bs(blk, bs, errp); + if (ret < 0) { + goto fail; + } + } + + /* + * Notably absent: Proper permission management. This is sad, but it seems + * almost impossible to achieve without changing the semantics and thereby + * limiting the use cases of the qemu-io command. + * + * In an ideal world we would unconditionally create a new BlockBackend for + * qemuio_command(), but we have commands like 'reopen' and want them to + * take effect on the exact BlockBackend whose name the user passed instead + * of just on a temporary copy of it. + * + * Another problem is that deleting the temporary BlockBackend involves + * draining all requests on it first, but some qemu-iotests cases want to + * issue multiple aio_read/write requests and expect them to complete in + * the background while the monitor has already returned. + * + * This is also what prevents us from saving the original permissions and + * restoring them later: We can't revoke permissions until all requests + * have completed, and we don't know when that is nor can we really let + * anything else run before we have revoken them to avoid race conditions. + * + * What happens now is that command() in qemu-io-cmds.c can extend the + * permissions if necessary for the qemu-io command. And they simply stay + * extended, possibly resulting in a read-only guest device keeping write + * permissions. Ugly, but it appears to be the lesser evil. + */ + qemuio_command(blk, command, errp); + +fail: + blk_unref(local_blk); +} diff --git a/block/monitor/meson.build b/block/monitor/meson.build index XXXXXXX..XXXXXXX 100644 --- a/block/monitor/meson.build +++ b/block/monitor/meson.build @@ -XXX,XX +XXX,XX @@ system_ss.add(files('block-hmp-cmds.c')) block_ss.add(files('bitmap-qmp-cmds.c')) +system_ss.add(files('qmp-cmds.c')) -- 2.54.0
Add qmp_qemu_io() method as a QMP counterpart to hmp_qemu_io(), using the x-qemu-io QMP command instead of human-monitor-command. The x-qemu-io command takes separate 'device' (or 'qdev') and 'command' arguments, and returns the error string. Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com> --- tests/qemu-iotests/iotests.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -XXX,XX +XXX,XX @@ def hmp_qemu_io(self, drive: str, cmd: str, d = '-d ' if qdev else '' return self.hmp(f'qemu-io {d}{drive} "{cmd}"', use_log=use_log) + def qmp_qemu_io(self, drive: str, cmd: str, + use_log: bool = False, qdev: bool = False) -> str: + """Write to a given drive using the x-qemu-io QMP command""" + kwargs: Dict[str, Any] = {'command': cmd} + if qdev: + kwargs['qdev'] = drive + else: + kwargs['device'] = drive + if use_log: + res = self.qmp_log('x-qemu-io', **kwargs) + else: + res = self.qmp('x-qemu-io', **kwargs) + return res.get('error', {}).get('desc', '') + def flatten_qmp_object(self, obj, output=None, basestr=''): if output is None: output = {} -- 2.54.0
Convert pause_drive() and resume_drive() to use x-qemu-io directly instead of routing through hmp(). Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/qemu-iotests/iotests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -XXX,XX +XXX,XX @@ def pause_drive(self, drive: str, event: Optional[str] = None) -> None: self.pause_drive(drive, "read_aio") self.pause_drive(drive, "write_aio") return - self.hmp(f'qemu-io {drive} "break {event} bp_{drive}"') + self.qmp_qemu_io(drive, f'break {event} bp_{drive}') def resume_drive(self, drive: str) -> None: """Resume drive r/w operations""" - self.hmp(f'qemu-io {drive} "remove_break bp_{drive}"') + self.qmp_qemu_io(drive, f'remove_break bp_{drive}') def hmp_qemu_io(self, drive: str, cmd: str, use_log: bool = False, qdev: bool = False) -> QMPMessage: -- 2.54.0
Add an option to enable/disable HMP support, default to true. The following commits are going to make --disable-hmp gradually working. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- meson.build | 4 ++++ meson_options.txt | 2 ++ scripts/meson-buildoptions.sh | 3 +++ 3 files changed, 9 insertions(+) diff --git a/meson.build b/meson.build index XXXXXXX..XXXXXXX 100644 --- a/meson.build +++ b/meson.build @@ -XXX,XX +XXX,XX @@ have_vhost_net = have_vhost_net_kernel or have_vhost_net_user or have_vhost_net_ have_tcg = get_option('tcg').allowed() and (have_system or have_user) +have_hmp = get_option('hmp') \ + .disable_auto_if(not have_system) \ + .allowed() have_tools = get_option('tools') \ .disable_auto_if(not have_system) \ .allowed() @@ -XXX,XX +XXX,XX @@ endif config_host_data = configuration_data() config_host_data.set('CONFIG_HAVE_RUST', have_rust) +config_host_data.set('CONFIG_HMP', have_hmp) audio_drivers_selected = [] if have_system audio_drivers_available = { diff --git a/meson_options.txt b/meson_options.txt index XXXXXXX..XXXXXXX 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -XXX,XX +XXX,XX @@ option('cfi', type: 'boolean', value: false, description: 'Control-Flow Integrity (CFI)') option('cfi_debug', type: 'boolean', value: false, description: 'Verbose errors in case of CFI violation') +option('hmp', type : 'feature', value : 'auto', + description: 'HMP monitor support') option('multiprocess', type: 'feature', value: 'auto', description: 'Out of process device emulation support') option('relocatable', type : 'boolean', value : true, diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index XXXXXXX..XXXXXXX 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -XXX,XX +XXX,XX @@ meson_options_help() { printf "%s\n" ' gtk GTK+ user interface' printf "%s\n" ' guest-agent Build QEMU Guest Agent' printf "%s\n" ' guest-agent-msi Build MSI package for the QEMU Guest Agent' + printf "%s\n" ' hmp HMP monitor support' printf "%s\n" ' hv-balloon hv-balloon driver (requires Glib 2.68+ GTree API)' printf "%s\n" ' hvf HVF acceleration support' printf "%s\n" ' iconv Font glyph conversion support' @@ -XXX,XX +XXX,XX @@ _meson_option_parse() { --disable-guest-agent-msi) printf "%s" -Dguest_agent_msi=disabled ;; --enable-hexagon-idef-parser) printf "%s" -Dhexagon_idef_parser=true ;; --disable-hexagon-idef-parser) printf "%s" -Dhexagon_idef_parser=false ;; + --enable-hmp) printf "%s" -Dhmp=enabled ;; + --disable-hmp) printf "%s" -Dhmp=disabled ;; --enable-hv-balloon) printf "%s" -Dhv_balloon=enabled ;; --disable-hv-balloon) printf "%s" -Dhv_balloon=disabled ;; --enable-hvf) printf "%s" -Dhvf=enabled ;; -- 2.54.0
When QEMU is built without HMP support, reject '-monitor' (which requests readline/HMP mode) early in monitor_init_opts() with a clear error message directing users to '-qmp' instead. Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com> --- monitor/monitor.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/monitor/monitor.c b/monitor/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -XXX,XX +XXX,XX @@ int monitor_init_opts(QemuOpts *opts, Error **errp) MonitorOptions *options; int ret; +#ifndef CONFIG_HMP + const char *mode = qemu_opt_get(opts, "mode"); + /* readline is HMP.. */ + if (mode && g_str_equal(mode, "readline")) { + error_setg(errp, "HMP monitor is not available," + " use '-qmp' instead of '-monitor'"); + return -1; + } +#endif + v = opts_visitor_new(opts); visit_type_MonitorOptions(v, NULL, &options, errp); visit_free(v); -- 2.54.0
Add runtime detection of HMP availability so tests gracefully skip instead of failing when QEMU is built without HMP support. For qtests (drive_del-test), use compile-time #ifndef CONFIG_HMP guards. For bash iotests, add _require_hmp() to common.rc that probes QEMU. For Python iotests, add _verify_hmp() and a require_hmp parameter threaded through execute_setup_common()/main()/script_initialize()/ script_main(). An earlier version of this series did an almost-complete conversion of the tests to QMP. However, this made the series even longer. I decided to post-pone it for now. Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com> --- tests/qtest/drive_del-test.c | 25 ++++++++++++++++++++++ tests/qemu-iotests/028 | 1 + tests/qemu-iotests/045 | 3 ++- tests/qemu-iotests/051 | 1 + tests/qemu-iotests/056 | 3 ++- tests/qemu-iotests/060 | 1 + tests/qemu-iotests/068 | 1 + tests/qemu-iotests/071 | 1 + tests/qemu-iotests/081 | 1 + tests/qemu-iotests/091 | 1 + tests/qemu-iotests/093 | 3 ++- tests/qemu-iotests/102 | 1 + tests/qemu-iotests/117 | 1 + tests/qemu-iotests/119 | 1 + tests/qemu-iotests/120 | 1 + tests/qemu-iotests/124 | 3 ++- tests/qemu-iotests/130 | 1 + tests/qemu-iotests/132 | 3 ++- tests/qemu-iotests/136 | 3 ++- tests/qemu-iotests/142 | 1 + tests/qemu-iotests/145 | 1 + tests/qemu-iotests/146 | 1 + tests/qemu-iotests/148 | 3 ++- tests/qemu-iotests/151 | 3 ++- tests/qemu-iotests/152 | 3 ++- tests/qemu-iotests/153 | 1 + tests/qemu-iotests/156 | 1 + tests/qemu-iotests/157 | 1 + tests/qemu-iotests/161 | 1 + tests/qemu-iotests/165 | 3 ++- tests/qemu-iotests/172 | 1 + tests/qemu-iotests/181 | 1 + tests/qemu-iotests/185 | 1 + tests/qemu-iotests/186 | 1 + tests/qemu-iotests/192 | 1 + tests/qemu-iotests/201 | 1 + tests/qemu-iotests/216 | 3 ++- tests/qemu-iotests/225 | 1 + tests/qemu-iotests/232 | 1 + tests/qemu-iotests/236 | 3 ++- tests/qemu-iotests/245 | 3 ++- tests/qemu-iotests/246 | 3 ++- tests/qemu-iotests/249 | 1 + tests/qemu-iotests/254 | 3 ++- tests/qemu-iotests/255 | 3 ++- tests/qemu-iotests/257 | 3 ++- tests/qemu-iotests/260 | 3 ++- tests/qemu-iotests/264 | 3 ++- tests/qemu-iotests/267 | 1 + tests/qemu-iotests/274 | 3 ++- tests/qemu-iotests/280 | 1 + tests/qemu-iotests/281 | 3 ++- tests/qemu-iotests/283 | 1 + tests/qemu-iotests/286 | 1 + tests/qemu-iotests/298 | 3 ++- tests/qemu-iotests/300 | 3 ++- tests/qemu-iotests/304 | 3 ++- tests/qemu-iotests/310 | 3 ++- tests/qemu-iotests/common.rc | 8 +++++++ tests/qemu-iotests/iotests.py | 14 +++++++++++- tests/qemu-iotests/tests/backup-discard-source | 3 ++- tests/qemu-iotests/tests/copy-before-write | 3 ++- tests/qemu-iotests/tests/image-fleecing | 3 ++- tests/qemu-iotests/tests/iothreads-create | 3 ++- tests/qemu-iotests/tests/luks-detached-header | 3 ++- .../tests/migrate-bitmaps-postcopy-test | 3 ++- tests/qemu-iotests/tests/migrate-bitmaps-test | 3 ++- tests/qemu-iotests/tests/mirror-change-copy-mode | 3 ++- tests/qemu-iotests/tests/mirror-ready-cancel-error | 3 ++- tests/qemu-iotests/tests/qcow2-internal-snapshots | 1 + tests/qemu-iotests/tests/qsd-migrate | 3 ++- tests/qemu-iotests/tests/reopen-file | 3 ++- tests/qemu-iotests/tests/write-zeroes-unmap | 1 + 73 files changed, 152 insertions(+), 37 deletions(-) diff --git a/tests/qtest/drive_del-test.c b/tests/qtest/drive_del-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/drive_del-test.c +++ b/tests/qtest/drive_del-test.c @@ -XXX,XX +XXX,XX @@ static void test_drive_without_dev(void) { QTestState *qts; +#ifndef CONFIG_HMP + g_test_skip("HMP not enabled"); + return; +#endif + /* Start with an empty drive */ qts = qtest_init("-drive if=none,id=drive0 -M none"); @@ -XXX,XX +XXX,XX @@ static void test_after_failed_device_add(void) QDict *response; QTestState *qts; +#ifndef CONFIG_HMP + g_test_skip("HMP not enabled"); + return; +#endif + if (!has_device_builtin("virtio-blk")) { g_test_skip("Device virtio-blk is not available"); return; @@ -XXX,XX +XXX,XX @@ static void test_drive_del_device_del(void) { QTestState *qts; +#ifndef CONFIG_HMP + g_test_skip("HMP not enabled"); + return; +#endif + if (!has_device_builtin("virtio-scsi")) { g_test_skip("Device virtio-scsi is not available"); return; @@ -XXX,XX +XXX,XX @@ static void test_drive_add_device_add_and_del(void) const char *arch = qtest_get_arch(); const char *machine_addition = ""; +#ifndef CONFIG_HMP + g_test_skip("HMP not enabled"); + return; +#endif + if (!has_device_builtin("virtio-blk")) { g_test_skip("Device virtio-blk is not available"); return; @@ -XXX,XX +XXX,XX @@ static void test_drive_add_device_add_and_del_q35(void) { QTestState *qts; +#ifndef CONFIG_HMP + g_test_skip("HMP not enabled"); + return; +#endif + if (!has_device_builtin("virtio-blk")) { g_test_skip("Device virtio-blk is not available"); return; diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/028 +++ b/tests/qemu-iotests/028 @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 qed _supported_proto file fuse _supported_os Linux +_require_hmp # Choose a size that is not necessarily a cluster size multiple for image # formats that use clusters. This will ensure that the base image doesn't end diff --git a/tests/qemu-iotests/045 b/tests/qemu-iotests/045 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/045 +++ b/tests/qemu-iotests/045 @@ -XXX,XX +XXX,XX @@ class TestSCMFd(iotests.QMPTestCase): if __name__ == '__main__': iotests.main(supported_fmts=['raw'], - supported_protocols=['file']) + supported_protocols=['file'], + require_hmp=True) diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/051 +++ b/tests/qemu-iotests/051 @@ -XXX,XX +XXX,XX @@ _supported_proto file _unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file \ compression_type _require_drivers nbd +_require_hmp if [ "$QEMU_DEFAULT_MACHINE" = "pc" ]; then _require_devices lsi53c895a diff --git a/tests/qemu-iotests/056 b/tests/qemu-iotests/056 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/056 +++ b/tests/qemu-iotests/056 @@ -XXX,XX +XXX,XX @@ class BackupTest(iotests.QMPTestCase): if __name__ == '__main__': iotests.main(supported_fmts=['qcow2', 'qed'], - supported_protocols=['file']) + supported_protocols=['file'], + require_hmp=True) diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/060 +++ b/tests/qemu-iotests/060 @@ -XXX,XX +XXX,XX @@ _unsupported_imgopts 'compat=0.10' data_file \ # The repair process will create a large file - so check for availability first _require_large_file 64G +_require_hmp rt_offset=65536 # 0x10000 (XXX: just an assumption) rb_offset=131072 # 0x20000 (XXX: just an assumption) diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/068 +++ b/tests/qemu-iotests/068 @@ -XXX,XX +XXX,XX @@ _supported_proto generic # Internal snapshots are (currently) impossible with refcount_bits=1, # and generally impossible with external data files _unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]' data_file +_require_hmp IMG_SIZE=128K diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/071 +++ b/tests/qemu-iotests/071 @@ -XXX,XX +XXX,XX @@ _require_drivers blkdebug blkverify # blkdebug can only inject errors on bs->file, not on the data_file, # so this test does not work with external data files _unsupported_imgopts data_file +_require_hmp do_run_qemu() { diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/081 +++ b/tests/qemu-iotests/081 @@ -XXX,XX +XXX,XX @@ _supported_proto file _supported_os Linux _require_drivers quorum _require_devices virtio-scsi +_require_hmp do_run_qemu() { diff --git a/tests/qemu-iotests/091 b/tests/qemu-iotests/091 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/091 +++ b/tests/qemu-iotests/091 @@ -XXX,XX +XXX,XX @@ _supported_fmt qcow2 _supported_proto file fuse _supported_os Linux _supported_cache_modes writethrough none writeback +_require_hmp _default_cache_mode none writeback size=1G diff --git a/tests/qemu-iotests/093 b/tests/qemu-iotests/093 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/093 +++ b/tests/qemu-iotests/093 @@ -XXX,XX +XXX,XX @@ class ThrottleTestRemovableMedia(iotests.QMPTestCase): if __name__ == '__main__': if 'null-co' not in iotests.supported_formats(): iotests.notrun('null-co driver support missing') - iotests.main(supported_fmts=["raw"]) + iotests.main(supported_fmts=["raw"], + require_hmp=True) diff --git a/tests/qemu-iotests/102 b/tests/qemu-iotests/102 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/102 +++ b/tests/qemu-iotests/102 @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto file fuse +_require_hmp IMG_SIZE=64K diff --git a/tests/qemu-iotests/117 b/tests/qemu-iotests/117 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/117 +++ b/tests/qemu-iotests/117 @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto file fuse +_require_hmp _make_test_img 64k diff --git a/tests/qemu-iotests/119 b/tests/qemu-iotests/119 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/119 +++ b/tests/qemu-iotests/119 @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt raw _supported_proto nbd _supported_os Linux +_require_hmp _make_test_img 64M # This should not crash diff --git a/tests/qemu-iotests/120 b/tests/qemu-iotests/120 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/120 +++ b/tests/qemu-iotests/120 @@ -XXX,XX +XXX,XX @@ _supported_fmt generic _supported_proto file fuse _unsupported_fmt luks _require_drivers raw +_require_hmp _make_test_img 64M diff --git a/tests/qemu-iotests/124 b/tests/qemu-iotests/124 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/124 +++ b/tests/qemu-iotests/124 @@ -XXX,XX +XXX,XX @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase): if __name__ == '__main__': iotests.main(supported_fmts=['qcow2'], - supported_protocols=['file']) + supported_protocols=['file'], + require_hmp=True) diff --git a/tests/qemu-iotests/130 b/tests/qemu-iotests/130 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/130 +++ b/tests/qemu-iotests/130 @@ -XXX,XX +XXX,XX @@ _supported_proto file _supported_os Linux # We are going to use lazy-refcounts _unsupported_imgopts 'compat=0.10' +_require_hmp qemu_comm_method="monitor" diff --git a/tests/qemu-iotests/132 b/tests/qemu-iotests/132 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/132 +++ b/tests/qemu-iotests/132 @@ -XXX,XX +XXX,XX @@ class TestSingleDrive(iotests.QMPTestCase): if __name__ == '__main__': iotests.main(supported_fmts=['raw', 'qcow2'], - supported_protocols=['file']) + supported_protocols=['file'], + require_hmp=True) diff --git a/tests/qemu-iotests/136 b/tests/qemu-iotests/136 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/136 +++ b/tests/qemu-iotests/136 @@ -XXX,XX +XXX,XX @@ class BlockDeviceStatsTestCoroutine(BlockDeviceStatsTestCase): if __name__ == '__main__': if 'null-co' not in iotests.supported_formats(): iotests.notrun('null-co driver support missing') - iotests.main(supported_fmts=["raw"]) + iotests.main(supported_fmts=["raw"], + require_hmp=True) diff --git a/tests/qemu-iotests/142 b/tests/qemu-iotests/142 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/142 +++ b/tests/qemu-iotests/142 @@ -XXX,XX +XXX,XX @@ _supported_proto file # We test all cache modes anyway, but O_DIRECT needs to be supported _default_cache_mode none _supported_cache_modes none directsync +_require_hmp do_run_qemu() { diff --git a/tests/qemu-iotests/145 b/tests/qemu-iotests/145 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/145 +++ b/tests/qemu-iotests/145 @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt generic _supported_proto generic +_require_hmp _make_test_img 1M diff --git a/tests/qemu-iotests/146 b/tests/qemu-iotests/146 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/146 +++ b/tests/qemu-iotests/146 @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt vpc _supported_proto file _supported_os Linux +_require_hmp qemu_comm_method="monitor" diff --git a/tests/qemu-iotests/148 b/tests/qemu-iotests/148 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/148 +++ b/tests/qemu-iotests/148 @@ -XXX,XX +XXX,XX @@ class TestFifoQuorumEvents(TestQuorumEvents): if __name__ == '__main__': iotests.verify_quorum() iotests.main(supported_fmts=["raw"], - supported_protocols=["file"]) + supported_protocols=["file"], + require_hmp=True) diff --git a/tests/qemu-iotests/151 b/tests/qemu-iotests/151 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/151 +++ b/tests/qemu-iotests/151 @@ -XXX,XX +XXX,XX @@ class TestHighThrottledWithNbdExport(TestThrottledWithNbdExportBase): if __name__ == '__main__': iotests.main(supported_fmts=['qcow2', 'raw'], - supported_protocols=['file']) + supported_protocols=['file'], + require_hmp=True) diff --git a/tests/qemu-iotests/152 b/tests/qemu-iotests/152 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/152 +++ b/tests/qemu-iotests/152 @@ -XXX,XX +XXX,XX @@ class TestUnaligned(iotests.QMPTestCase): if __name__ == '__main__': iotests.main(supported_fmts=['raw', 'qcow2'], - supported_protocols=['file']) + supported_protocols=['file'], + require_hmp=True) diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/153 +++ b/tests/qemu-iotests/153 @@ -XXX,XX +XXX,XX @@ _check_ofd || _notrun "OFD lock not available" _supported_fmt qcow2 _supported_proto file +_require_hmp _run_cmd() { diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/156 +++ b/tests/qemu-iotests/156 @@ -XXX,XX +XXX,XX @@ _supported_fmt qcow2 qed _supported_proto file # Copying files around with cp does not work with external data files _unsupported_imgopts data_file +_require_hmp # Create source disk TEST_IMG="$TEST_IMG.backing" _make_test_img 1M diff --git a/tests/qemu-iotests/157 b/tests/qemu-iotests/157 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/157 +++ b/tests/qemu-iotests/157 @@ -XXX,XX +XXX,XX @@ _supported_fmt generic _supported_proto file _require_devices virtio-blk +_require_hmp do_run_qemu() { diff --git a/tests/qemu-iotests/161 b/tests/qemu-iotests/161 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/161 +++ b/tests/qemu-iotests/161 @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 qed _supported_proto file fuse _supported_os Linux +_require_hmp IMG_SIZE=1M diff --git a/tests/qemu-iotests/165 b/tests/qemu-iotests/165 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/165 +++ b/tests/qemu-iotests/165 @@ -XXX,XX +XXX,XX @@ class TestPersistentDirtyBitmap(iotests.QMPTestCase): if __name__ == '__main__': iotests.main(supported_fmts=['qcow2'], supported_protocols=['file'], - unsupported_imgopts=['compat']) + unsupported_imgopts=['compat'], + require_hmp=True) diff --git a/tests/qemu-iotests/172 b/tests/qemu-iotests/172 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/172 +++ b/tests/qemu-iotests/172 @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto file _supported_os Linux +_require_hmp if [ "$QEMU_DEFAULT_MACHINE" != "pc" ]; then _notrun "Requires a PC machine" diff --git a/tests/qemu-iotests/181 b/tests/qemu-iotests/181 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/181 +++ b/tests/qemu-iotests/181 @@ -XXX,XX +XXX,XX @@ _supported_fmt generic _unsupported_fmt qcow vdi vhdx vmdk vpc vvfat parallels _supported_proto generic _supported_os Linux +_require_hmp _flaky_test https://gitlab.com/qemu-project/qemu/-/work_items/3515 diff --git a/tests/qemu-iotests/185 b/tests/qemu-iotests/185 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/185 +++ b/tests/qemu-iotests/185 @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto file _supported_os Linux +_require_hmp _flaky_test https://gitlab.com/qemu-project/qemu/-/issues/3270 size=$((64 * 1048576)) diff --git a/tests/qemu-iotests/186 b/tests/qemu-iotests/186 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/186 +++ b/tests/qemu-iotests/186 @@ -XXX,XX +XXX,XX @@ _supported_fmt qcow2 _supported_proto file fuse _require_drivers null-co _require_devices virtio-scsi-pci +_require_hmp if [ "$QEMU_DEFAULT_MACHINE" != "pc" ]; then _notrun "Requires a PC machine" diff --git a/tests/qemu-iotests/192 b/tests/qemu-iotests/192 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/192 +++ b/tests/qemu-iotests/192 @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt generic _supported_proto file +_require_hmp if [ "$QEMU_DEFAULT_MACHINE" != "pc" ]; then _notrun "Requires a PC machine" diff --git a/tests/qemu-iotests/201 b/tests/qemu-iotests/201 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/201 +++ b/tests/qemu-iotests/201 @@ -XXX,XX +XXX,XX @@ _supported_os Linux # Internal snapshots are (currently) impossible with refcount_bits=1, # and generally impossible with external data files _unsupported_imgopts 'refcount_bits=1[^0-9]' data_file +_require_hmp size=64M _make_test_img $size diff --git a/tests/qemu-iotests/216 b/tests/qemu-iotests/216 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/216 +++ b/tests/qemu-iotests/216 @@ -XXX,XX +XXX,XX @@ from iotests import log, qemu_img, qemu_io # Need backing file support iotests.script_initialize(supported_fmts=['qcow2', 'qcow', 'qed', 'vmdk'], - supported_platforms=['linux']) + supported_platforms=['linux'], + require_hmp=True) log('') log('=== Copy-on-read across nodes ===') diff --git a/tests/qemu-iotests/225 b/tests/qemu-iotests/225 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/225 +++ b/tests/qemu-iotests/225 @@ -XXX,XX +XXX,XX @@ _supported_os Linux _unsupported_imgopts "subformat=monolithicFlat" \ "subformat=twoGbMaxExtentFlat" \ "subformat=twoGbMaxExtentSparse" +_require_hmp TEST_IMG="$TEST_IMG.base" _make_test_img 1M TEST_IMG="$TEST_IMG.not_base" _make_test_img 1M diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/232 +++ b/tests/qemu-iotests/232 @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt generic _supported_proto file _supported_os Linux +_require_hmp do_run_qemu() { diff --git a/tests/qemu-iotests/236 b/tests/qemu-iotests/236 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/236 +++ b/tests/qemu-iotests/236 @@ -XXX,XX +XXX,XX @@ import iotests from iotests import log -iotests.script_initialize(supported_fmts=['generic']) +iotests.script_initialize(supported_fmts=['generic'], + require_hmp=True) size = 64 * 1024 * 1024 granularity = 64 * 1024 diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/245 +++ b/tests/qemu-iotests/245 @@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase): if __name__ == '__main__': iotests.activate_logging() iotests.main(supported_fmts=["qcow2"], - supported_protocols=["file"]) + supported_protocols=["file"], + require_hmp=True) diff --git a/tests/qemu-iotests/246 b/tests/qemu-iotests/246 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/246 +++ b/tests/qemu-iotests/246 @@ -XXX,XX +XXX,XX @@ import iotests from iotests import log iotests.script_initialize(supported_fmts=['qcow2'], - unsupported_imgopts=['compat']) + unsupported_imgopts=['compat'], + require_hmp=True) size = 64 * 1024 * 1024 * 1024 gran_small = 32 * 1024 gran_large = 128 * 1024 diff --git a/tests/qemu-iotests/249 b/tests/qemu-iotests/249 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/249 +++ b/tests/qemu-iotests/249 @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 qed _supported_proto file fuse _supported_os Linux +_require_hmp IMG_SIZE=1M diff --git a/tests/qemu-iotests/254 b/tests/qemu-iotests/254 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/254 +++ b/tests/qemu-iotests/254 @@ -XXX,XX +XXX,XX @@ import iotests from iotests import qemu_img_create, file_path, log iotests.script_initialize(supported_fmts=['qcow2'], - unsupported_imgopts=['compat']) + unsupported_imgopts=['compat'], + require_hmp=True) disk, top = file_path('disk', 'top') size = 1024 * 1024 diff --git a/tests/qemu-iotests/255 b/tests/qemu-iotests/255 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/255 +++ b/tests/qemu-iotests/255 @@ -XXX,XX +XXX,XX @@ import iotests from iotests import imgfmt -iotests.script_initialize(supported_fmts=['qcow2']) +iotests.script_initialize(supported_fmts=['qcow2'], + require_hmp=True) iotests.log('Finishing a commit job with background reads') iotests.log('============================================') diff --git a/tests/qemu-iotests/257 b/tests/qemu-iotests/257 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/257 +++ b/tests/qemu-iotests/257 @@ -XXX,XX +XXX,XX @@ def main(): if __name__ == '__main__': iotests.script_main(main, supported_fmts=['qcow2'], - supported_protocols=['file']) + supported_protocols=['file'], + require_hmp=True) diff --git a/tests/qemu-iotests/260 b/tests/qemu-iotests/260 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/260 +++ b/tests/qemu-iotests/260 @@ -XXX,XX +XXX,XX @@ from iotests import qemu_img_create, file_path, log, filter_qmp_event iotests.script_initialize( supported_fmts=['qcow2'], - unsupported_imgopts=['compat'] + unsupported_imgopts=['compat'], + require_hmp=True, ) base, top = file_path('base', 'top') diff --git a/tests/qemu-iotests/264 b/tests/qemu-iotests/264 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/264 +++ b/tests/qemu-iotests/264 @@ -XXX,XX +XXX,XX @@ class TestNbdReconnect(iotests.QMPTestCase): if __name__ == '__main__': - iotests.main(supported_fmts=['qcow2']) + iotests.main(supported_fmts=['qcow2'], + require_hmp=True) diff --git a/tests/qemu-iotests/267 b/tests/qemu-iotests/267 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/267 +++ b/tests/qemu-iotests/267 @@ -XXX,XX +XXX,XX @@ _require_drivers copy-on-read _unsupported_imgopts 'refcount_bits=1[^0-9]' data_file _require_devices virtio-blk +_require_hmp do_run_qemu() { diff --git a/tests/qemu-iotests/274 b/tests/qemu-iotests/274 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/274 +++ b/tests/qemu-iotests/274 @@ -XXX,XX +XXX,XX @@ import iotests iotests.script_initialize(supported_fmts=['qcow2'], supported_platforms=['linux'], - unsupported_imgopts=['refcount_bits', 'compat']) + unsupported_imgopts=['refcount_bits', 'compat'], + require_hmp=True) size_short = 1 * 1024 * 1024 size_long = 2 * 1024 * 1024 diff --git a/tests/qemu-iotests/280 b/tests/qemu-iotests/280 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/280 +++ b/tests/qemu-iotests/280 @@ -XXX,XX +XXX,XX @@ iotests.script_initialize( supported_fmts=['qcow2'], supported_protocols=['file'], supported_platforms=['linux'], + require_hmp=True, ) with iotests.FilePath('base') as base_path , \ diff --git a/tests/qemu-iotests/281 b/tests/qemu-iotests/281 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/281 +++ b/tests/qemu-iotests/281 @@ -XXX,XX +XXX,XX @@ class TestYieldingAndTimers(iotests.QMPTestCase): if __name__ == '__main__': iotests.main(supported_fmts=['qcow2'], supported_protocols=['file'], - unsupported_imgopts=['compat']) + unsupported_imgopts=['compat'], + require_hmp=True) diff --git a/tests/qemu-iotests/283 b/tests/qemu-iotests/283 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/283 +++ b/tests/qemu-iotests/283 @@ -XXX,XX +XXX,XX @@ import iotests # The test is unrelated to formats, restrict it to qcow2 to avoid extra runs iotests.script_initialize( supported_fmts=['qcow2'], + require_hmp=True, ) size = 1024 * 1024 diff --git a/tests/qemu-iotests/286 b/tests/qemu-iotests/286 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/286 +++ b/tests/qemu-iotests/286 @@ -XXX,XX +XXX,XX @@ _supported_proto file fuse # Internal snapshots are (currently) impossible with refcount_bits=1, # and generally impossible with external data files _unsupported_imgopts 'refcount_bits=1[^0-9]' data_file +_require_hmp _make_test_img 64M diff --git a/tests/qemu-iotests/298 b/tests/qemu-iotests/298 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/298 +++ b/tests/qemu-iotests/298 @@ -XXX,XX +XXX,XX @@ class TestTruncate(iotests.QMPTestCase): if __name__ == '__main__': - iotests.main(supported_fmts=['qcow2'], required_fmts=['preallocate']) + iotests.main(supported_fmts=['qcow2'], required_fmts=['preallocate'], + require_hmp=True) diff --git a/tests/qemu-iotests/300 b/tests/qemu-iotests/300 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/300 +++ b/tests/qemu-iotests/300 @@ -XXX,XX +XXX,XX @@ class TestAliasTransformMigration(TestDirtyBitmapMigration): self.verify_dest_error(None) if __name__ == '__main__': - iotests.main(supported_protocols=['file']) + iotests.main(supported_protocols=['file'], + require_hmp=True) diff --git a/tests/qemu-iotests/304 b/tests/qemu-iotests/304 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/304 +++ b/tests/qemu-iotests/304 @@ -XXX,XX +XXX,XX @@ import iotests from iotests import qemu_img_create, qemu_img_log, file_path iotests.script_initialize(supported_fmts=['qcow2'], - supported_protocols=['file']) + supported_protocols=['file'], + require_hmp=True) test_img = file_path('test.qcow2') target_img = file_path('target.qcow2') diff --git a/tests/qemu-iotests/310 b/tests/qemu-iotests/310 index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/310 +++ b/tests/qemu-iotests/310 @@ -XXX,XX +XXX,XX @@ from iotests import log, qemu_img, qemu_io # Need backing file support iotests.script_initialize(supported_fmts=['qcow2'], - supported_platforms=['linux']) + supported_platforms=['linux'], + require_hmp=True) log('') log('=== Copy-on-read across nodes ===') diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -XXX,XX +XXX,XX @@ _require_drivers() done } +_require_hmp() +{ + if echo quit | $QEMU -M none -display none -monitor stdio 2>&1 | + grep -q "HMP monitor is not available"; then + _notrun "HMP monitor not available" + fi +} + # Check that we have a file system that allows huge (but very sparse) files # _require_large_file() diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index XXXXXXX..XXXXXXX 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -XXX,XX +XXX,XX @@ def _verify_formats(required_formats: Sequence[str] = ()) -> None: notrun(f'formats {usf_list} are not whitelisted') +def _verify_hmp() -> None: + args = [qemu_prog] + qemu_opts + ['-M', 'none', '-monitor', 'stdio'] + with subprocess.Popen(args, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + universal_newlines=True) as subp: + out, _ = subp.communicate('quit\n') + if 'HMP monitor is not available' in out: + notrun('HMP monitor not available') + def _verify_virtio_blk() -> None: out = qemu_pipe('-M', 'none', '-device', 'help') if 'virtio-blk' not in out: @@ -XXX,XX +XXX,XX @@ def execute_setup_common(supported_fmts: Sequence[str] = (), supported_protocols: Sequence[str] = (), unsupported_protocols: Sequence[str] = (), required_fmts: Sequence[str] = (), - unsupported_imgopts: Sequence[str] = ()) -> bool: + unsupported_imgopts: Sequence[str] = (), + require_hmp: bool = False) -> bool: """ Perform necessary setup for either script-style or unittest-style tests. @@ -XXX,XX +XXX,XX @@ def execute_setup_common(supported_fmts: Sequence[str] = (), _verify_formats(required_fmts) _verify_virtio_blk() _verify_imgopts(unsupported_imgopts) + if require_hmp: + _verify_hmp() return debug diff --git a/tests/qemu-iotests/tests/backup-discard-source b/tests/qemu-iotests/tests/backup-discard-source index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/tests/backup-discard-source +++ b/tests/qemu-iotests/tests/backup-discard-source @@ -XXX,XX +XXX,XX @@ class TestBackup(iotests.QMPTestCase): if __name__ == '__main__': iotests.main(supported_fmts=['qcow2'], - supported_protocols=['file']) + supported_protocols=['file'], + require_hmp=True) diff --git a/tests/qemu-iotests/tests/copy-before-write b/tests/qemu-iotests/tests/copy-before-write index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/tests/copy-before-write +++ b/tests/qemu-iotests/tests/copy-before-write @@ -XXX,XX +XXX,XX @@ wrote 524288/524288 bytes at offset 524288 if __name__ == '__main__': iotests.main(supported_fmts=['qcow2'], supported_protocols=['file'], - required_fmts=['copy-before-write']) + required_fmts=['copy-before-write'], + require_hmp=True) diff --git a/tests/qemu-iotests/tests/image-fleecing b/tests/qemu-iotests/tests/image-fleecing index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/tests/image-fleecing +++ b/tests/qemu-iotests/tests/image-fleecing @@ -XXX,XX +XXX,XX @@ iotests.script_initialize( supported_fmts=['qcow2'], supported_platforms=['linux'], required_fmts=['copy-before-write'], - unsupported_imgopts=['compat'] + unsupported_imgopts=['compat'], + require_hmp=True, ) patterns = [('0x5d', '0', '64k'), diff --git a/tests/qemu-iotests/tests/iothreads-create b/tests/qemu-iotests/tests/iothreads-create index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/tests/iothreads-create +++ b/tests/qemu-iotests/tests/iothreads-create @@ -XXX,XX +XXX,XX @@ import asyncio import iotests iotests.script_initialize(supported_fmts=['qcow2', 'qcow', 'qed', 'vdi', - 'vmdk', 'parallels']) + 'vmdk', 'parallels'], + require_hmp=True) iotests.verify_virtio_scsi_pci_or_ccw() with iotests.FilePath('disk.img') as img_path, \ diff --git a/tests/qemu-iotests/tests/luks-detached-header b/tests/qemu-iotests/tests/luks-detached-header index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/tests/luks-detached-header +++ b/tests/qemu-iotests/tests/luks-detached-header @@ -XXX,XX +XXX,XX @@ class TestDetachedLUKSHeader(QMPTestCase): if __name__ == "__main__": # Test image creation and I/O - iotests.main(supported_fmts=["luks"], supported_protocols=["file"]) + iotests.main(supported_fmts=["luks"], supported_protocols=["file"], + require_hmp=True) diff --git a/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test b/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test +++ b/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test @@ -XXX,XX +XXX,XX @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): if __name__ == '__main__': iotests.main(supported_fmts=['qcow2'], - unsupported_imgopts=['compat']) + unsupported_imgopts=['compat'], + require_hmp=True) diff --git a/tests/qemu-iotests/tests/migrate-bitmaps-test b/tests/qemu-iotests/tests/migrate-bitmaps-test index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/tests/migrate-bitmaps-test +++ b/tests/qemu-iotests/tests/migrate-bitmaps-test @@ -XXX,XX +XXX,XX @@ def main() -> None: iotests.main( supported_fmts=['qcow2'], supported_protocols=['file'], - unsupported_imgopts=['compat'] + unsupported_imgopts=['compat'], + require_hmp=True, ) diff --git a/tests/qemu-iotests/tests/mirror-change-copy-mode b/tests/qemu-iotests/tests/mirror-change-copy-mode index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/tests/mirror-change-copy-mode +++ b/tests/qemu-iotests/tests/mirror-change-copy-mode @@ -XXX,XX +XXX,XX @@ class TestMirrorChangeCopyMode(iotests.QMPTestCase): if __name__ == '__main__': iotests.main(supported_fmts=['qcow2', 'raw'], - supported_protocols=['file']) + supported_protocols=['file'], + require_hmp=True) diff --git a/tests/qemu-iotests/tests/mirror-ready-cancel-error b/tests/qemu-iotests/tests/mirror-ready-cancel-error index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/tests/mirror-ready-cancel-error +++ b/tests/qemu-iotests/tests/mirror-ready-cancel-error @@ -XXX,XX +XXX,XX @@ if __name__ == '__main__': # LUKS would require special key-secret handling in add_blockdevs() iotests.main(supported_fmts=['generic'], unsupported_fmts=['luks'], - supported_protocols=['file']) + supported_protocols=['file'], + require_hmp=True) diff --git a/tests/qemu-iotests/tests/qcow2-internal-snapshots b/tests/qemu-iotests/tests/qcow2-internal-snapshots index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/tests/qcow2-internal-snapshots +++ b/tests/qemu-iotests/tests/qcow2-internal-snapshots @@ -XXX,XX +XXX,XX @@ _supported_proto file # Internal snapshots are (currently) impossible with refcount_bits=1, # and generally impossible with external data files _unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]' data_file +_require_hmp IMG_SIZE=64M diff --git a/tests/qemu-iotests/tests/qsd-migrate b/tests/qemu-iotests/tests/qsd-migrate index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/tests/qsd-migrate +++ b/tests/qemu-iotests/tests/qsd-migrate @@ -XXX,XX +XXX,XX @@ from iotests import filter_qemu_io, filter_qtest iotests.script_initialize(supported_fmts=['qcow2', 'qed', 'raw'], supported_protocols=['file'], - supported_platforms=['linux']) + supported_platforms=['linux'], + require_hmp=True) with iotests.FilePath('disk.img') as path, \ iotests.FilePath('nbd-src.sock', base_dir=iotests.sock_dir) as nbd_src, \ diff --git a/tests/qemu-iotests/tests/reopen-file b/tests/qemu-iotests/tests/reopen-file index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/tests/reopen-file +++ b/tests/qemu-iotests/tests/reopen-file @@ -XXX,XX +XXX,XX @@ if __name__ == '__main__': # Must support creating images and reopen iotests.main(supported_fmts=['qcow', 'qcow2', 'qed', 'raw', 'vdi', 'vhdx', 'vmdk', 'vpc'], - supported_protocols=['file']) + supported_protocols=['file'], + require_hmp=True) diff --git a/tests/qemu-iotests/tests/write-zeroes-unmap b/tests/qemu-iotests/tests/write-zeroes-unmap index XXXXXXX..XXXXXXX 100755 --- a/tests/qemu-iotests/tests/write-zeroes-unmap +++ b/tests/qemu-iotests/tests/write-zeroes-unmap @@ -XXX,XX +XXX,XX @@ _supported_fmt raw _supported_proto file _supported_os Linux _require_disk_usage +_require_hmp create_test_image() { _make_test_img -f $IMGFMT 1m -- 2.54.0
Guard calls to monitor_vprintf in error-report and qemu-print so they compile without HMP. When CONFIG_HMP is not set, error_vprintf_mon falls back directly to stderr and qemu_vfprintf returns -1 for NULL streams. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tests/unit/test-util-sockets.c | 4 +++- tools/qemu-vnc/stubs.c | 2 ++ util/error-report.c | 8 +++++--- util/qemu-print.c | 6 ++++++ 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/unit/test-util-sockets.c b/tests/unit/test-util-sockets.c index XXXXXXX..XXXXXXX 100644 --- a/tests/unit/test-util-sockets.c +++ b/tests/unit/test-util-sockets.c @@ -XXX,XX +XXX,XX @@ int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp) */ Monitor *monitor_cur(void) { return cur_mon; } Monitor *monitor_set_cur(Coroutine *co, Monitor *mon) { abort(); } -int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { abort(); } bool monitor_cur_is_qmp(void) { abort(); }; +#ifdef CONFIG_HMP +int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { abort(); } +#endif #ifndef _WIN32 static void test_socket_fd_pass_name_good(void) diff --git a/tools/qemu-vnc/stubs.c b/tools/qemu-vnc/stubs.c index XXXXXXX..XXXXXXX 100644 --- a/tools/qemu-vnc/stubs.c +++ b/tools/qemu-vnc/stubs.c @@ -XXX,XX +XXX,XX @@ Monitor *monitor_set_cur(Coroutine *co, Monitor *mon) return NULL; } +#ifdef CONFIG_HMP int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { return -1; } +#endif /* * Link-time stubs for VMState symbols referenced by VNC code. diff --git a/util/error-report.c b/util/error-report.c index XXXXXXX..XXXXXXX 100644 --- a/util/error-report.c +++ b/util/error-report.c @@ -XXX,XX +XXX,XX @@ error_vprintf_mon(Monitor *cur_mon, const char *fmt, va_list ap) * IOW this will only print if in HMP, otherwise we * fallback to stderr for QMP / no-monitor scenarios. */ +#ifdef CONFIG_HMP int ret = monitor_vprintf(cur_mon, fmt, ap); - if (ret == -1) { - ret = vfprintf(stderr, fmt, ap); + if (ret != -1) { + return ret; } - return ret; +#endif + return vfprintf(stderr, fmt, ap); } /* diff --git a/util/qemu-print.c b/util/qemu-print.c index XXXXXXX..XXXXXXX 100644 --- a/util/qemu-print.c +++ b/util/qemu-print.c @@ -XXX,XX +XXX,XX @@ */ int qemu_vprintf(const char *fmt, va_list ap) { +#ifdef CONFIG_HMP Monitor *cur_mon = monitor_cur(); if (cur_mon) { return monitor_vprintf(cur_mon, fmt, ap); } +#endif return vprintf(fmt, ap); } @@ -XXX,XX +XXX,XX @@ int qemu_printf(const char *fmt, ...) int qemu_vfprintf(FILE *stream, const char *fmt, va_list ap) { if (!stream) { +#ifdef CONFIG_HMP return monitor_vprintf(monitor_cur(), fmt, ap); +#else + return -1; +#endif } return vfprintf(stream, fmt, ap); } -- 2.54.0
Make the 'readline' value of MonitorMode and the 'human-monitor-command' command conditional on CONFIG_HMP, so they are only available when HMP support is compiled in. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- qapi/control.json | 4 +++- qapi/misc.json | 3 ++- monitor/monitor.c | 8 +++++++- monitor/qmp-cmds.c | 2 ++ 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/qapi/control.json b/qapi/control.json index XXXXXXX..XXXXXXX 100644 --- a/qapi/control.json +++ b/qapi/control.json @@ -XXX,XX +XXX,XX @@ # # Since: 5.0 ## -{ 'enum': 'MonitorMode', 'data': [ 'readline', 'control' ] } +{ 'enum': 'MonitorMode', 'data': [ + { 'name': 'readline', 'if': 'CONFIG_HMP' }, + 'control' ] } ## # @MonitorOptions: diff --git a/qapi/misc.json b/qapi/misc.json index XXXXXXX..XXXXXXX 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -XXX,XX +XXX,XX @@ { 'command': 'human-monitor-command', 'data': {'command-line': 'str', '*cpu-index': 'int'}, 'returns': 'str', - 'features': [ 'savevm-monitor-nodes' ] } + 'features': [ 'savevm-monitor-nodes' ], + 'if': 'CONFIG_HMP' } ## # @getfd: diff --git a/monitor/monitor.c b/monitor/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -XXX,XX +XXX,XX @@ int monitor_init(MonitorOptions *opts, bool allow_hmp, Error **errp) } if (!opts->has_mode) { - opts->mode = allow_hmp ? MONITOR_MODE_READLINE : MONITOR_MODE_CONTROL; + opts->mode = +#ifdef CONFIG_HMP + allow_hmp ? MONITOR_MODE_READLINE : +#endif + MONITOR_MODE_CONTROL; } switch (opts->mode) { case MONITOR_MODE_CONTROL: monitor_init_qmp(chr, opts->pretty, errp); break; +#ifdef CONFIG_HMP case MONITOR_MODE_READLINE: if (!allow_hmp) { error_setg(errp, "Only QMP is supported"); @@ -XXX,XX +XXX,XX @@ int monitor_init(MonitorOptions *opts, bool allow_hmp, Error **errp) } monitor_init_hmp(chr, true, errp); break; +#endif /* CONFIG_HMP */ default: g_assert_not_reached(); } diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/monitor/qmp-cmds.c +++ b/monitor/qmp-cmds.c @@ -XXX,XX +XXX,XX @@ void qmp_add_client(const char *protocol, const char *fdname, } } +#ifdef CONFIG_HMP char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index, int64_t cpu_index, Error **errp) { @@ -XXX,XX +XXX,XX @@ out: monitor_data_destroy(&hmp.common); return output; } +#endif /* CONFIG_HMP */ static void __attribute__((__constructor__)) monitor_init_qmp_commands(void) { -- 2.54.0
- disable default monitor when HMP is not available - hide 'readline' from -mon help text - error out on mux chardev monitor when no HMP - skip HMP monitor terminal for gdb, return E01 for 'qRcmd' remote commands Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- chardev/char.c | 7 +++++++ gdbstub/system.c | 8 ++++++++ system/vl.c | 4 ++++ qemu-options.hx | 6 +++++- 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/chardev/char.c b/chardev/char.c index XXXXXXX..XXXXXXX 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -XXX,XX +XXX,XX @@ static Chardev *qemu_chr_new_from_name(const char *label, const char *filename, if (qemu_opt_get_bool(opts, "mux", 0)) { assert(permit_mux_mon); +#ifdef CONFIG_HMP monitor_init_hmp(chr, true, &err); if (err) { error_report_err(err); @@ -XXX,XX +XXX,XX @@ static Chardev *qemu_chr_new_from_name(const char *label, const char *filename, chr = NULL; goto out; } +#else + error_report("HMP monitor is disabled"); + object_unparent(OBJECT(chr)); + chr = NULL; + goto out; +#endif } out: diff --git a/gdbstub/system.c b/gdbstub/system.c index XXXXXXX..XXXXXXX 100644 --- a/gdbstub/system.c +++ b/gdbstub/system.c @@ -XXX,XX +XXX,XX @@ bool gdbserver_start(const char *device, Error **errp) qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL); +#ifdef CONFIG_HMP /* Initialize a monitor terminal for gdb */ mon_chr = qemu_chardev_new(NULL, TYPE_CHARDEV_GDB, NULL, NULL, &error_abort); monitor_init_hmp(mon_chr, false, &error_abort); +#else + mon_chr = NULL; +#endif } else { qemu_chr_fe_deinit(&gdbserver_system_state.chr, true); mon_chr = gdbserver_system_state.mon_chr; @@ -XXX,XX +XXX,XX @@ void gdb_handle_query_rcmd(GArray *params, void *ctx) len = len / 2; gdb_hextomem(gdbserver_state.mem_buf, gdb_get_cmd_param(params, 0)->data, len); g_byte_array_append(gdbserver_state.mem_buf, &zero, 1); +#ifdef CONFIG_HMP qemu_chr_be_write(gdbserver_system_state.mon_chr, gdbserver_state.mem_buf->data, gdbserver_state.mem_buf->len); gdb_put_packet("OK"); +#else + gdb_put_packet("E01"); +#endif } /* diff --git a/system/vl.c b/system/vl.c index XXXXXXX..XXXXXXX 100644 --- a/system/vl.c +++ b/system/vl.c @@ -XXX,XX +XXX,XX @@ static int has_defaults = 1; static int default_audio = 1; static int default_serial = 1; static int default_parallel = 1; +#ifdef CONFIG_HMP static int default_monitor = 1; +#else +static int default_monitor; /* false */ +#endif static int default_floppy = 1; static int default_cdrom = 1; static bool auto_create_sdcard = true; diff --git a/qemu-options.hx b/qemu-options.hx index XXXXXXX..XXXXXXX 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -XXX,XX +XXX,XX @@ SRST ERST DEF("mon", HAS_ARG, QEMU_OPTION_mon, \ - "-mon [chardev=]name[,mode=readline|control][,pretty=on|off]\n", QEMU_ARCH_ALL) + "-mon [chardev=]name[,mode=" +#ifdef CONFIG_HMP + "readline|" +#endif + "control][,pretty=on|off]\n", QEMU_ARCH_ALL) SRST ``-mon [chardev=]name[,mode=readline|control][,pretty=on|off]`` Set up a monitor connected to the chardev ``name``. -- 2.54.0
Add #ifdef CONFIG_HMP around all hmp_* function implementations and their HMP-only helpers across subsystems. This covers monitor_register_hmp* callers, hmp_info_* handlers, and HMP-only helper functions like slirp_lookup. To link succesfully, use empty cmds tables in hmp-cmds.c (to be removed once meson build-sys is updated with !hmp support later in the series) Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- accel/accel-system.c | 2 ++ accel/tcg/monitor.c | 2 ++ hw/i386/kvm/xen-stubs.c | 2 ++ hw/i386/kvm/xen_evtchn.c | 3 ++- hw/i386/sgx.c | 2 ++ hw/misc/mos6522-stub.c | 2 ++ hw/misc/mos6522.c | 2 ++ hw/pci/pci-stub.c | 2 ++ hw/s390x/s390-skeys.c | 2 ++ hw/s390x/s390-stattrib.c | 4 ++++ hw/uefi/ovmf-log.c | 2 ++ hw/usb/host-libusb.c | 6 ++++++ migration/dirtyrate.c | 2 ++ monitor/hmp-cmds.c | 5 +++++ net/slirp.c | 7 ++++++- replay/replay-debugging.c | 8 ++++++++ replay/stubs-system.c | 6 ++++++ system/dirtylimit.c | 6 ++++++ system/qdev-monitor.c | 4 ++++ target/i386/cpu-apic.c | 2 ++ target/i386/monitor.c | 3 +++ target/i386/sev.c | 2 ++ target/m68k/monitor.c | 2 ++ target/ppc/monitor.c | 2 ++ target/riscv/monitor.c | 3 +++ target/sh4/monitor.c | 2 ++ target/sparc/monitor.c | 2 ++ target/xtensa/monitor.c | 2 ++ 28 files changed, 87 insertions(+), 2 deletions(-) diff --git a/accel/accel-system.c b/accel/accel-system.c index XXXXXXX..XXXXXXX 100644 --- a/accel/accel-system.c +++ b/accel/accel-system.c @@ -XXX,XX +XXX,XX @@ void accel_init_ops_interfaces(AccelClass *ac) static void accel_ops_class_init(ObjectClass *oc, const void *data) { +#ifdef CONFIG_HMP monitor_register_hmp_info_hrt("accel", qmp_x_accel_stats); +#endif } static const TypeInfo accel_ops_type_info = { diff --git a/accel/tcg/monitor.c b/accel/tcg/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/accel/tcg/monitor.c +++ b/accel/tcg/monitor.c @@ -XXX,XX +XXX,XX @@ HumanReadableText *qmp_x_query_jit(Error **errp) return human_readable_text_from_str(buf); } +#ifdef CONFIG_HMP static void hmp_tcg_register(void) { monitor_register_hmp_info_hrt("jit", qmp_x_query_jit); } type_init(hmp_tcg_register); +#endif diff --git a/hw/i386/kvm/xen-stubs.c b/hw/i386/kvm/xen-stubs.c index XXXXXXX..XXXXXXX 100644 --- a/hw/i386/kvm/xen-stubs.c +++ b/hw/i386/kvm/xen-stubs.c @@ -XXX,XX +XXX,XX @@ void xen_primary_console_set_be_port(uint16_t port) { } +#ifdef CONFIG_HMP void hmp_xen_event_list(Monitor *mon, const QDict *qdict) { monitor_printf(mon, "XEN emulation is not available in this QEMU\n"); @@ -XXX,XX +XXX,XX @@ void hmp_xen_event_inject(Monitor *mon, const QDict *qdict) { monitor_printf(mon, "XEN emulation is not available in this QEMU\n"); } +#endif diff --git a/hw/i386/kvm/xen_evtchn.c b/hw/i386/kvm/xen_evtchn.c index XXXXXXX..XXXXXXX 100644 --- a/hw/i386/kvm/xen_evtchn.c +++ b/hw/i386/kvm/xen_evtchn.c @@ -XXX,XX +XXX,XX @@ void qmp_xen_event_inject(uint32_t port, Error **errp) } } +#ifdef CONFIG_HMP void hmp_xen_event_list(Monitor *mon, const QDict *qdict) { EvtchnInfoList *iter, *info_list; @@ -XXX,XX +XXX,XX @@ void hmp_xen_event_inject(Monitor *mon, const QDict *qdict) monitor_printf(mon, "Delivered port %d\n", port); } } - +#endif diff --git a/hw/i386/sgx.c b/hw/i386/sgx.c index XXXXXXX..XXXXXXX 100644 --- a/hw/i386/sgx.c +++ b/hw/i386/sgx.c @@ -XXX,XX +XXX,XX @@ SgxInfo *qmp_query_sgx(Error **errp) return info; } +#ifdef CONFIG_HMP void hmp_info_sgx(Monitor *mon, const QDict *qdict) { Error *err = NULL; @@ -XXX,XX +XXX,XX @@ void hmp_info_sgx(Monitor *mon, const QDict *qdict) monitor_printf(mon, "total size=%" PRIu64 "\n", size); } +#endif bool check_sgx_support(void) { diff --git a/hw/misc/mos6522-stub.c b/hw/misc/mos6522-stub.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/mos6522-stub.c +++ b/hw/misc/mos6522-stub.c @@ -XXX,XX +XXX,XX @@ #include "monitor/monitor.h" #include "monitor/hmp.h" +#ifdef CONFIG_HMP void hmp_info_via(Monitor *mon, const QDict *qdict) { monitor_printf(mon, "MOS6522 VIA is not available in this QEMU\n"); } +#endif diff --git a/hw/misc/mos6522.c b/hw/misc/mos6522.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/mos6522.c +++ b/hw/misc/mos6522.c @@ -XXX,XX +XXX,XX @@ void mos6522_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) } } +#ifdef CONFIG_HMP static int qmp_x_query_via_foreach(Object *obj, void *opaque) { GString *buf = opaque; @@ -XXX,XX +XXX,XX @@ void hmp_info_via(Monitor *mon, const QDict *qdict) } monitor_puts(mon, info->human_readable_text); } +#endif /* CONFIG_HMP */ static const MemoryRegionOps mos6522_ops = { .read = mos6522_read, diff --git a/hw/pci/pci-stub.c b/hw/pci/pci-stub.c index XXXXXXX..XXXXXXX 100644 --- a/hw/pci/pci-stub.c +++ b/hw/pci/pci-stub.c @@ -XXX,XX +XXX,XX @@ PciInfoList *qmp_query_pci(Error **errp) return NULL; } +#ifdef CONFIG_HMP void hmp_info_pci(Monitor *mon, const QDict *qdict) { } @@ -XXX,XX +XXX,XX @@ void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict) { monitor_printf(mon, "PCI devices not supported\n"); } +#endif /* kvm-all wants this */ MSIMessage pci_get_msi_message(PCIDevice *dev, int vector) diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-skeys.c +++ b/hw/s390x/s390-skeys.c @@ -XXX,XX +XXX,XX @@ static void write_keys(FILE *f, uint8_t *keys, uint64_t startgfn, } } +#ifdef CONFIG_HMP void hmp_info_skeys(Monitor *mon, const QDict *qdict) { S390SKeysState *ss = s390_get_skeys_device(); @@ -XXX,XX +XXX,XX @@ void hmp_dump_skeys(Monitor *mon, const QDict *qdict) error_report_err(err); } } +#endif void s390_qmp_dump_skeys(const char *filename, Error **errp) { diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-stattrib.c +++ b/hw/s390x/s390-stattrib.c @@ -XXX,XX +XXX,XX @@ #define STATTR_FLAG_ERROR 0x04ULL #define STATTR_FLAG_DONE 0x08ULL +#ifdef CONFIG_HMP static S390StAttribState *s390_get_stattrib_device(void) { S390StAttribState *sas; @@ -XXX,XX +XXX,XX @@ static S390StAttribState *s390_get_stattrib_device(void) assert(sas); return sas; } +#endif void s390_stattrib_init(void) { @@ -XXX,XX +XXX,XX @@ void s390_stattrib_init(void) /* Console commands: */ +#ifdef CONFIG_HMP void hmp_migrationmode(Monitor *mon, const QDict *qdict) { S390StAttribState *sas = s390_get_stattrib_device(); @@ -XXX,XX +XXX,XX @@ void hmp_info_cmma(Monitor *mon, const QDict *qdict) out: g_free(vals); } +#endif /* Migration support: */ diff --git a/hw/uefi/ovmf-log.c b/hw/uefi/ovmf-log.c index XXXXXXX..XXXXXXX 100644 --- a/hw/uefi/ovmf-log.c +++ b/hw/uefi/ovmf-log.c @@ -XXX,XX +XXX,XX @@ FirmwareLog *qmp_query_firmware_log(bool have_max_size, uint64_t max_size, return ret; } +#ifdef CONFIG_HMP void hmp_info_firmware_log(Monitor *mon, const QDict *qdict) { g_autofree gchar *log_esc = NULL; @@ -XXX,XX +XXX,XX @@ void hmp_info_firmware_log(Monitor *mon, const QDict *qdict) log_esc = g_strescape((gchar *)log_out, "\r\n"); monitor_printf(mon, "%s\n", log_esc); } +#endif diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index XXXXXXX..XXXXXXX 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -XXX,XX +XXX,XX @@ static void usb_host_attach_kernel(USBHostDevice *s); # define HAVE_SUPER_PLUS 1 #endif +#ifdef CONFIG_HMP static const char *speed_name[] = { [LIBUSB_SPEED_UNKNOWN] = "?", [LIBUSB_SPEED_LOW] = "1.5", @@ -XXX,XX +XXX,XX @@ static const char *speed_name[] = { [LIBUSB_SPEED_SUPER_PLUS] = "5000+", #endif }; +#endif static const unsigned int speed_map[] = { [LIBUSB_SPEED_LOW] = USB_SPEED_LOW, @@ -XXX,XX +XXX,XX @@ module_kconfig(USB); static void usb_host_register_types(void) { type_register_static(&usb_host_dev_info); +#ifdef CONFIG_HMP monitor_register_hmp("usbhost", true, hmp_info_usbhost); +#endif } type_init(usb_host_register_types) @@ -XXX,XX +XXX,XX @@ static void usb_host_auto_check(void *unused) timer_mod(usb_auto_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 2000); } +#ifdef CONFIG_HMP void hmp_info_usbhost(Monitor *mon, const QDict *qdict) { libusb_device **devs = NULL; @@ -XXX,XX +XXX,XX @@ void hmp_info_usbhost(Monitor *mon, const QDict *qdict) } libusb_free_device_list(devs, 1); } +#endif diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c index XXXXXXX..XXXXXXX 100644 --- a/migration/dirtyrate.c +++ b/migration/dirtyrate.c @@ -XXX,XX +XXX,XX @@ struct DirtyRateInfo *qmp_query_dirty_rate(bool has_calc_time_unit, has_calc_time_unit ? calc_time_unit : TIME_UNIT_SECOND); } +#ifdef CONFIG_HMP void hmp_info_dirty_rate(Monitor *mon, const QDict *qdict) { DirtyRateInfo *info = query_dirty_rate_info(TIME_UNIT_SECOND); @@ -XXX,XX +XXX,XX @@ void hmp_calc_dirty_rate(Monitor *mon, const QDict *qdict) " seconds\n", sec); monitor_printf(mon, "[Please use 'info dirty_rate' to check results]\n"); } +#endif diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -XXX,XX +XXX,XX @@ #include "disas/disas.h" /* Please update hmp-commands.hx when adding or changing commands */ +#ifdef CONFIG_HMP static HMPCommand hmp_info_cmds[] = { #include "hmp-commands-info.h" { NULL, NULL, }, @@ -XXX,XX +XXX,XX @@ static HMPCommand hmp_cmds[] = { #include "hmp-commands.h" { NULL, NULL, }, }; +#else +static HMPCommand hmp_info_cmds[] = { { NULL, NULL, }, }; +static HMPCommand hmp_cmds[] = { { NULL, NULL, }, }; +#endif HMPCommand *hmp_cmds_for_target(bool info_command) { diff --git a/net/slirp.c b/net/slirp.c index XXXXXXX..XXXXXXX 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -XXX,XX +XXX,XX @@ error: return -1; } +#ifdef CONFIG_HMP static SlirpState *slirp_lookup(Monitor *mon, const char *id) { if (id) { @@ -XXX,XX +XXX,XX @@ void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict) fail_syntax: monitor_printf(mon, "invalid format\n"); } +#endif static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp) { @@ -XXX,XX +XXX,XX @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp) return -1; } +#ifdef CONFIG_HMP void hmp_hostfwd_add(Monitor *mon, const QDict *qdict) { const char *redir_str; @@ -XXX,XX +XXX,XX @@ void hmp_hostfwd_add(Monitor *mon, const QDict *qdict) error_report_err(err); } } - } +#endif #if defined(CONFIG_SMBD_COMMAND) @@ -XXX,XX +XXX,XX @@ UsernetInfoList *qmp_x_query_usernet(Error **errp) return head; } +#ifdef CONFIG_HMP void hmp_info_usernet(Monitor *mon, const QDict *qdict) { g_autoptr(UsernetInfoList) list = NULL; @@ -XXX,XX +XXX,XX @@ void hmp_info_usernet(Monitor *mon, const QDict *qdict) ui->hub_name, ui->info); } } +#endif static void net_init_slirp_configs_host(const NetdevUserHostForwardList *fwd) diff --git a/replay/replay-debugging.c b/replay/replay-debugging.c index XXXXXXX..XXXXXXX 100644 --- a/replay/replay-debugging.c +++ b/replay/replay-debugging.c @@ -XXX,XX +XXX,XX @@ bool replay_running_debug(void) return replay_is_debugging; } +#ifdef CONFIG_HMP void hmp_info_replay(Monitor *mon, const QDict *qdict) { if (replay_mode == REPLAY_MODE_NONE) { @@ -XXX,XX +XXX,XX @@ void hmp_info_replay(Monitor *mon, const QDict *qdict) replay_get_filename(), replay_get_current_icount()); } } +#endif ReplayInfo *qmp_query_replay(Error **errp) { @@ -XXX,XX +XXX,XX @@ void qmp_replay_break(int64_t icount, Error **errp) } } +#ifdef CONFIG_HMP void hmp_replay_break(Monitor *mon, const QDict *qdict) { int64_t icount = qdict_get_try_int(qdict, "icount", -1LL); @@ -XXX,XX +XXX,XX @@ void hmp_replay_break(Monitor *mon, const QDict *qdict) return; } } +#endif void qmp_replay_delete_break(Error **errp) { @@ -XXX,XX +XXX,XX @@ void qmp_replay_delete_break(Error **errp) } } +#ifdef CONFIG_HMP void hmp_replay_delete_break(Monitor *mon, const QDict *qdict) { Error *err = NULL; @@ -XXX,XX +XXX,XX @@ void hmp_replay_delete_break(Monitor *mon, const QDict *qdict) return; } } +#endif static char *replay_find_nearest_snapshot(int64_t icount, int64_t *snapshot_icount) @@ -XXX,XX +XXX,XX @@ void qmp_replay_seek(int64_t icount, Error **errp) replay_seek(icount, replay_stop_vm, errp); } +#ifdef CONFIG_HMP void hmp_replay_seek(Monitor *mon, const QDict *qdict) { int64_t icount = qdict_get_try_int(qdict, "icount", -1LL); @@ -XXX,XX +XXX,XX @@ void hmp_replay_seek(Monitor *mon, const QDict *qdict) return; } } +#endif static void replay_stop_vm_debug(void *opaque) { diff --git a/replay/stubs-system.c b/replay/stubs-system.c index XXXXXXX..XXXXXXX 100644 --- a/replay/stubs-system.c +++ b/replay/stubs-system.c @@ -XXX,XX +XXX,XX @@ void replay_vmstate_init(void) #include "qapi/error.h" #include "qemu/error-report.h" +#ifdef CONFIG_HMP void hmp_info_replay(Monitor *mon, const QDict *qdict) { error_report("replay support not available"); } + void hmp_replay_break(Monitor *mon, const QDict *qdict) { error_report("replay support not available"); } + void hmp_replay_delete_break(Monitor *mon, const QDict *qdict) { error_report("replay support not available"); } + void hmp_replay_seek(Monitor *mon, const QDict *qdict) { error_report("replay support not available"); } +#endif + ReplayInfo *qmp_query_replay(Error **errp) { error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND, diff --git a/system/dirtylimit.c b/system/dirtylimit.c index XXXXXXX..XXXXXXX 100644 --- a/system/dirtylimit.c +++ b/system/dirtylimit.c @@ -XXX,XX +XXX,XX @@ void qmp_cancel_vcpu_dirty_limit(bool has_cpu_index, dirtylimit_state_unlock(); } +#ifdef CONFIG_HMP void hmp_cancel_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) { int64_t cpu_index = qdict_get_try_int(qdict, "cpu_index", -1); @@ -XXX,XX +XXX,XX @@ void hmp_cancel_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) monitor_printf(mon, "[Please use 'info vcpu_dirty_limit' to query " "dirty limit for virtual CPU]\n"); } +#endif void qmp_set_vcpu_dirty_limit(bool has_cpu_index, int64_t cpu_index, @@ -XXX,XX +XXX,XX @@ void qmp_set_vcpu_dirty_limit(bool has_cpu_index, dirtylimit_state_unlock(); } +#ifdef CONFIG_HMP void hmp_set_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) { int64_t dirty_rate = qdict_get_int(qdict, "dirty_rate"); @@ -XXX,XX +XXX,XX @@ void hmp_set_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) out: hmp_handle_error(mon, err); } +#endif /* Return the max throttle time of each virtual CPU */ uint64_t dirtylimit_throttle_time_per_round(void) @@ -XXX,XX +XXX,XX @@ struct DirtyLimitInfoList *qmp_query_vcpu_dirty_limit(Error **errp) return dirtylimit_query_all(); } +#ifdef CONFIG_HMP void hmp_info_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) { DirtyLimitInfoList *info; @@ -XXX,XX +XXX,XX @@ void hmp_info_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) info->value->current_rate); } } +#endif diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c index XXXXXXX..XXXXXXX 100644 --- a/system/qdev-monitor.c +++ b/system/qdev-monitor.c @@ -XXX,XX +XXX,XX @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) return ret; } +#ifdef CONFIG_HMP #define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__) static void qdev_print_props(Monitor *mon, DeviceState *dev, DeviceClass *dc, @@ -XXX,XX +XXX,XX @@ void hmp_info_qdm(Monitor *mon, const QDict *qdict) { qdev_print_devinfos(true); } +#endif /* CONFIG_HMP */ void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp) { @@ -XXX,XX +XXX,XX @@ void qmp_device_sync_config(const char *id, Error **errp) qdev_sync_config(dev, errp); } +#ifdef CONFIG_HMP void hmp_device_add(Monitor *mon, const QDict *qdict) { Error *err = NULL; @@ -XXX,XX +XXX,XX @@ void hmp_device_del(Monitor *mon, const QDict *qdict) qmp_device_del(id, &err); hmp_handle_error(mon, err); } +#endif void device_add_completion(ReadLineState *rs, int nb_args, const char *str) { diff --git a/target/i386/cpu-apic.c b/target/i386/cpu-apic.c index XXXXXXX..XXXXXXX 100644 --- a/target/i386/cpu-apic.c +++ b/target/i386/cpu-apic.c @@ -XXX,XX +XXX,XX @@ void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) } } +#ifdef CONFIG_HMP void hmp_info_local_apic(Monitor *mon, const QDict *qdict) { CPUState *cs; @@ -XXX,XX +XXX,XX @@ void hmp_info_local_apic(Monitor *mon, const QDict *qdict) } x86_cpu_dump_local_apic_state(cs, CPU_DUMP_FPU); } +#endif diff --git a/target/i386/monitor.c b/target/i386/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/target/i386/monitor.c +++ b/target/i386/monitor.c @@ -XXX,XX +XXX,XX @@ #include "qapi/qapi-commands-misc.h" #include "system/memory.h" +#ifdef CONFIG_HMP + /* Perform linear address sign extension */ static hwaddr addr_canonical(CPUArchState *env, hwaddr addr) { @@ -XXX,XX +XXX,XX @@ void hmp_mce(Monitor *mon, const QDict *qdict) } hmp_handle_error(mon, err); } +#endif diff --git a/target/i386/sev.c b/target/i386/sev.c index XXXXXXX..XXXXXXX 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -XXX,XX +XXX,XX @@ SevInfo *qmp_query_sev(Error **errp) return info; } +#ifdef CONFIG_HMP void hmp_info_sev(Monitor *mon, const QDict *qdict) { SevInfo *info = sev_get_info(); @@ -XXX,XX +XXX,XX @@ void hmp_info_sev(Monitor *mon, const QDict *qdict) out: qapi_free_SevInfo(info); } +#endif static int sev_get_pdh_info(int fd, guchar **pdh, size_t *pdh_len, guchar **cert_chain, diff --git a/target/m68k/monitor.c b/target/m68k/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/target/m68k/monitor.c +++ b/target/m68k/monitor.c @@ -XXX,XX +XXX,XX @@ #include "monitor/hmp.h" #include "monitor/monitor.h" +#ifdef CONFIG_HMP void hmp_info_tlb(Monitor *mon, const QDict *qdict) { CPUArchState *env1 = mon_get_cpu_env(mon); @@ -XXX,XX +XXX,XX @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict) dump_mmu(env1); } +#endif diff --git a/target/ppc/monitor.c b/target/ppc/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/target/ppc/monitor.c +++ b/target/ppc/monitor.c @@ -XXX,XX +XXX,XX @@ #include "monitor/hmp.h" #include "cpu.h" +#ifdef CONFIG_HMP void hmp_info_tlb(Monitor *mon, const QDict *qdict) { CPUArchState *env1 = mon_get_cpu_env(mon); @@ -XXX,XX +XXX,XX @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict) } dump_mmu(env1); } +#endif diff --git a/target/riscv/monitor.c b/target/riscv/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/monitor.c +++ b/target/riscv/monitor.c @@ -XXX,XX +XXX,XX @@ #define PTE_HEADER_DELIMITER "-------- ---------------- -------- -------\n" #endif +#ifdef CONFIG_HMP + /* Perform linear address sign extension */ static target_ulong addr_canonical(int va_bits, target_ulong addr) { @@ -XXX,XX +XXX,XX @@ void hmp_info_mem(Monitor *mon, const QDict *qdict) mem_info_svxx(mon, env); } +#endif /* CONFIG_HMP */ static bool reg_is_ulong_integer(CPURISCVState *env, const char *name, target_ulong *val, bool is_gprh) diff --git a/target/sh4/monitor.c b/target/sh4/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/target/sh4/monitor.c +++ b/target/sh4/monitor.c @@ -XXX,XX +XXX,XX @@ #include "monitor/monitor.h" #include "monitor/hmp.h" +#ifdef CONFIG_HMP static void print_tlb(Monitor *mon, int idx, tlb_t *tlb) { monitor_printf(mon, " tlb%i:\t" @@ -XXX,XX +XXX,XX @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict) for (i = 0 ; i < UTLB_SIZE ; i++) print_tlb (mon, i, &env->utlb[i]); } +#endif diff --git a/target/sparc/monitor.c b/target/sparc/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/target/sparc/monitor.c +++ b/target/sparc/monitor.c @@ -XXX,XX +XXX,XX @@ #include "monitor/hmp.h" +#ifdef CONFIG_HMP void hmp_info_tlb(Monitor *mon, const QDict *qdict) { CPUArchState *env1 = mon_get_cpu_env(mon); @@ -XXX,XX +XXX,XX @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict) } dump_mmu(env1); } +#endif diff --git a/target/xtensa/monitor.c b/target/xtensa/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/target/xtensa/monitor.c +++ b/target/xtensa/monitor.c @@ -XXX,XX +XXX,XX @@ #include "monitor/monitor.h" #include "monitor/hmp.h" +#ifdef CONFIG_HMP void hmp_info_tlb(Monitor *mon, const QDict *qdict) { CPUArchState *env1 = mon_get_cpu_env(mon); @@ -XXX,XX +XXX,XX @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict) } dump_mmu(env1); } +#endif -- 2.54.0
Guard SysemuCPUOps::monitor_defs field and the per-target MonitorDef arrays with CONFIG_HMP. These tables are only used by HMP 'print' and 'info registers' commands. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- include/hw/core/sysemu-cpu-ops.h | 2 ++ monitor/hmp.c | 4 +++- target/i386/cpu.c | 4 ++++ target/m68k/cpu.c | 4 ++++ target/sparc/cpu.c | 5 +++-- 5 files changed, 16 insertions(+), 3 deletions(-) diff --git a/include/hw/core/sysemu-cpu-ops.h b/include/hw/core/sysemu-cpu-ops.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/core/sysemu-cpu-ops.h +++ b/include/hw/core/sysemu-cpu-ops.h @@ -XXX,XX +XXX,XX @@ typedef struct SysemuCPUOps { */ int (*monitor_get_register)(CPUState *cs, const char *name, int64_t *pval); +#ifdef CONFIG_HMP /** * @monitor_defs: Array of MonitorDef entries. This field is legacy, * use @gdb_core_xml_file to dump registers instead. */ const MonitorDef *monitor_defs; +#endif /** * @legacy_vmsd: Legacy state for migration. diff --git a/monitor/hmp.c b/monitor/hmp.c index XXXXXXX..XXXXXXX 100644 --- a/monitor/hmp.c +++ b/monitor/hmp.c @@ -XXX,XX +XXX,XX @@ void monitor_register_hmp_info_hrt(const char *name, static int get_monitor_def(Monitor *mon, int64_t *pval, const char *name) { CPUState *cs = mon_get_cpu(mon); - const MonitorDef *md; + const MonitorDef *md = NULL; void *ptr; if (cs == NULL) { return -1; } +#ifdef CONFIG_HMP md = cs->cc->sysemu_ops->monitor_defs; +#endif if (md == NULL) { return -1; } diff --git a/target/i386/cpu.c b/target/i386/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -XXX,XX +XXX,XX @@ static const Property x86_cpu_properties[] = { #ifndef CONFIG_USER_ONLY +#ifdef CONFIG_HMP static int64_t monitor_get_pc(Monitor *mon, const struct MonitorDef *md, int offset) { @@ -XXX,XX +XXX,XX @@ static const MonitorDef x86_monitor_defs[] = { { NULL }, #undef SEG }; +#endif #include "hw/core/sysemu-cpu-ops.h" @@ -XXX,XX +XXX,XX @@ static const struct SysemuCPUOps i386_sysemu_ops = { .write_elf64_note = x86_cpu_write_elf64_note, .write_elf32_qemunote = x86_cpu_write_elf32_qemunote, .write_elf64_qemunote = x86_cpu_write_elf64_qemunote, +#ifdef CONFIG_HMP .monitor_defs = x86_monitor_defs, +#endif .legacy_vmsd = &vmstate_x86_cpu, }; #endif diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_m68k_cpu = { }, }; +#ifdef CONFIG_HMP static const MonitorDef m68k_monitor_defs[] = { { "ssp", offsetof(CPUM68KState, sp[0]) }, { "usp", offsetof(CPUM68KState, sp[1]) }, @@ -XXX,XX +XXX,XX @@ static const MonitorDef m68k_monitor_defs[] = { { "mmusr", offsetof(CPUM68KState, mmu.mmusr) }, { NULL }, }; +#endif #include "hw/core/sysemu-cpu-ops.h" static const struct SysemuCPUOps m68k_sysemu_ops = { .has_work = m68k_cpu_has_work, .get_phys_addr_debug = m68k_cpu_get_phys_addr_debug, +#ifdef CONFIG_HMP .monitor_defs = m68k_monitor_defs, +#endif }; #endif /* !CONFIG_USER_ONLY */ diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -XXX,XX +XXX,XX @@ static const Property sparc_cpu_properties[] = { #ifdef TARGET_SPARC64 #include "monitor/hmp.h" - +#ifdef CONFIG_HMP static const MonitorDef sparc64_monitor_defs[] = { { "asi", offsetof(CPUSPARCState, asi) }, { "pstate", offsetof(CPUSPARCState, pstate) }, @@ -XXX,XX +XXX,XX @@ static const MonitorDef sparc64_monitor_defs[] = { { NULL }, }; #endif +#endif #include "hw/core/sysemu-cpu-ops.h" @@ -XXX,XX +XXX,XX @@ static const struct SysemuCPUOps sparc_sysemu_ops = { .has_work = sparc_cpu_has_work, .get_phys_addr_debug = sparc_cpu_get_phys_addr_debug, .legacy_vmsd = &vmstate_sparc_cpu, -#if defined(TARGET_SPARC64) +#if defined(TARGET_SPARC64) && defined(CONFIG_HMP) .monitor_defs = sparc64_monitor_defs, #endif }; -- 2.54.0
The print_dev callback is only used by HMP 'info qtree'. Guard the field in BusClass, all implementations, and the caller with CONFIG_HMP. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- include/hw/core/qdev.h | 2 ++ hw/char/virtio-serial-bus.c | 6 ++++++ hw/core/sysbus.c | 6 ++++++ hw/misc/auxbus.c | 16 +++++++++++----- hw/pci/pci-hmp-cmds.c | 2 ++ hw/pci/pci.c | 2 ++ hw/usb/bus.c | 6 ++++++ hw/xen/xen-bus.c | 4 ++++ 8 files changed, 39 insertions(+), 5 deletions(-) diff --git a/include/hw/core/qdev.h b/include/hw/core/qdev.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/core/qdev.h +++ b/include/hw/core/qdev.h @@ -XXX,XX +XXX,XX @@ DECLARE_OBJ_CHECKERS(BusState, BusClass, struct BusClass { ObjectClass parent_class; +#ifdef CONFIG_HMP /* FIXME first arg should be BusState */ void (*print_dev)(Monitor *mon, DeviceState *dev, int indent); +#endif /* * Return a newly allocated string containing the path of the * device on this bus. diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -XXX,XX +XXX,XX @@ static int virtio_serial_load_device(VirtIODevice *vdev, QEMUFile *f, return 0; } +#ifdef CONFIG_HMP static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent); +#endif static const Property virtser_props[] = { DEFINE_PROP_UINT32("nr", VirtIOSerialPort, id, VIRTIO_CONSOLE_BAD_ID), @@ -XXX,XX +XXX,XX @@ static const Property virtser_props[] = { static void virtser_bus_class_init(ObjectClass *klass, const void *data) { +#ifdef CONFIG_HMP BusClass *k = BUS_CLASS(klass); k->print_dev = virtser_bus_dev_print; +#endif } static const TypeInfo virtser_bus_info = { @@ -XXX,XX +XXX,XX @@ static const TypeInfo virtser_bus_info = { .class_init = virtser_bus_class_init, }; +#ifdef CONFIG_HMP static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent) { VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(qdev); @@ -XXX,XX +XXX,XX @@ static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent) port->host_connected ? "on" : "off", port->throttled ? "on" : "off"); } +#endif /* This function is only used if a port id is not provided by the user */ static uint32_t find_free_port_id(VirtIOSerial *vser) diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/core/sysbus.c +++ b/hw/core/sysbus.c @@ -XXX,XX +XXX,XX @@ #include "monitor/monitor.h" #include "system/address-spaces.h" +#ifdef CONFIG_HMP static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent); +#endif static char *sysbus_get_fw_dev_path(DeviceState *dev); typedef struct SysBusFind { @@ -XXX,XX +XXX,XX @@ static void system_bus_class_init(ObjectClass *klass, const void *data) { BusClass *k = BUS_CLASS(klass); +#ifdef CONFIG_HMP k->print_dev = sysbus_dev_print; +#endif k->get_fw_dev_path = sysbus_get_fw_dev_path; } @@ -XXX,XX +XXX,XX @@ bool sysbus_realize_and_unref(SysBusDevice *dev, Error **errp) return qdev_realize_and_unref(DEVICE(dev), sysbus_get_default(), errp); } +#ifdef CONFIG_HMP static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent) { SysBusDevice *s = SYS_BUS_DEVICE(dev); @@ -XXX,XX +XXX,XX @@ static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent) indent, "", s->mmio[i].addr, size); } } +#endif static char *sysbus_get_fw_dev_path(DeviceState *dev) { diff --git a/hw/misc/auxbus.c b/hw/misc/auxbus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/auxbus.c +++ b/hw/misc/auxbus.c @@ -XXX,XX +XXX,XX @@ } while (0) +#ifdef CONFIG_HMP static void aux_slave_dev_print(Monitor *mon, DeviceState *dev, int indent); +#endif static inline I2CBus *aux_bridge_get_i2c_bus(AUXTOI2CState *bridge); /* aux-bus implementation (internal not public) */ static void aux_bus_class_init(ObjectClass *klass, const void *data) { +#ifdef CONFIG_HMP BusClass *k = BUS_CLASS(klass); /* AUXSlave has an MMIO so we need to change the way we print information * in monitor. */ k->print_dev = aux_slave_dev_print; +#endif } AUXBus *aux_bus_init(DeviceState *parent, const char *name) @@ -XXX,XX +XXX,XX @@ void aux_map_slave(AUXSlave *aux_dev, hwaddr addr) memory_region_add_subregion(bus->aux_io, addr, aux_dev->mmio); } -static bool aux_bus_is_bridge(AUXBus *bus, DeviceState *dev) -{ - return (dev == DEVICE(bus->bridge)); -} - I2CBus *aux_get_i2c_bus(AUXBus *bus) { return aux_bridge_get_i2c_bus(bus->bridge); @@ -XXX,XX +XXX,XX @@ static const TypeInfo aux_to_i2c_type_info = { }; /* aux-slave implementation */ +#ifdef CONFIG_HMP +static bool aux_bus_is_bridge(AUXBus *bus, DeviceState *dev) +{ + return (dev == DEVICE(bus->bridge)); +} + static void aux_slave_dev_print(Monitor *mon, DeviceState *dev, int indent) { AUXBus *bus = AUX_BUS(qdev_get_parent_bus(dev)); @@ -XXX,XX +XXX,XX @@ static void aux_slave_dev_print(Monitor *mon, DeviceState *dev, int indent) object_property_get_uint(OBJECT(s->mmio), "addr", NULL), memory_region_size(s->mmio)); } +#endif void aux_init_mmio(AUXSlave *aux_slave, MemoryRegion *mmio) { diff --git a/hw/pci/pci-hmp-cmds.c b/hw/pci/pci-hmp-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/hw/pci/pci-hmp-cmds.c +++ b/hw/pci/pci-hmp-cmds.c @@ -XXX,XX +XXX,XX @@ void hmp_info_pci(Monitor *mon, const QDict *qdict) qapi_free_PciInfoList(info_list); } +#ifdef CONFIG_HMP void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent) { PCIDevice *d = (PCIDevice *)dev; @@ -XXX,XX +XXX,XX @@ void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent) r->addr, r->addr + r->size - 1); } } +#endif void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict) { diff --git a/hw/pci/pci.c b/hw/pci/pci.c index XXXXXXX..XXXXXXX 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -XXX,XX +XXX,XX @@ static void pci_bus_class_init(ObjectClass *klass, const void *data) ResettableClass *rc = RESETTABLE_CLASS(klass); FWCfgDataGeneratorClass *fwgc = FW_CFG_DATA_GENERATOR_CLASS(klass); +#ifdef CONFIG_HMP k->print_dev = pcibus_dev_print; +#endif k->get_dev_path = pcibus_get_dev_path; k->get_fw_dev_path = pcibus_get_fw_dev_path; k->realize = pci_bus_realize; diff --git a/hw/usb/bus.c b/hw/usb/bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -XXX,XX +XXX,XX @@ #include "trace.h" #include "qemu/cutils.h" +#ifdef CONFIG_HMP static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent); +#endif static char *usb_get_dev_path(DeviceState *dev); static char *usb_get_fw_dev_path(DeviceState *qdev); @@ -XXX,XX +XXX,XX @@ static void usb_bus_class_init(ObjectClass *klass, const void *data) BusClass *k = BUS_CLASS(klass); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); +#ifdef CONFIG_HMP k->print_dev = usb_bus_dev_print; +#endif k->get_dev_path = usb_get_dev_path; k->get_fw_dev_path = usb_get_fw_dev_path; hc->unplug = qdev_simple_device_unplug_cb; @@ -XXX,XX +XXX,XX @@ static const char *usb_speed(unsigned int speed) return txt[speed]; } +#ifdef CONFIG_HMP static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent) { USBDevice *dev = USB_DEVICE(qdev); @@ -XXX,XX +XXX,XX @@ static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent) usb_speed(dev->speed), dev->product_desc, dev->attached ? ", attached" : ""); } +#endif static char *usb_get_dev_path(DeviceState *qdev) { diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -XXX,XX +XXX,XX @@ abort: qemu_xen_xs_transaction_end(xenbus->xsh, tid, true); } +#ifdef CONFIG_HMP static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent) { XenDevice *xendev = XEN_DEVICE(dev); @@ -XXX,XX +XXX,XX @@ static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent) monitor_printf(mon, "%*sname = '%s' frontend_id = %u\n", indent, "", xendev->name, xendev->frontend_id); } +#endif static char *xen_bus_get_dev_path(DeviceState *dev) { @@ -XXX,XX +XXX,XX @@ static void xen_bus_class_init(ObjectClass *class, const void *data) BusClass *bus_class = BUS_CLASS(class); HotplugHandlerClass *hotplug_class = HOTPLUG_HANDLER_CLASS(class); +#ifdef CONFIG_HMP bus_class->print_dev = xen_bus_print_dev; +#endif bus_class->get_dev_path = xen_bus_get_dev_path; bus_class->realize = xen_bus_realize; bus_class->unrealize = xen_bus_unrealize; -- 2.54.0
Exclude all *-hmp-cmds.c files and HMP-only source files from the build when HMP is disabled. Also conditionalise the hmp-commands.hx header generation and the test-hmp qtest. Drop the transient #ifdef CONFIG_HMP, no longer needed. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- meson.build | 2 +- hw/pci/pci-hmp-cmds.c | 2 -- monitor/hmp.c | 2 -- audio/meson.build | 4 +++- backends/meson.build | 5 ++++- block/monitor/meson.build | 4 +++- chardev/meson.build | 5 ++++- disas/meson.build | 4 +++- dump/meson.build | 5 ++++- hw/core/meson.build | 5 +++-- hw/i386/meson.build | 4 +++- hw/net/meson.build | 4 +++- hw/pci/meson.build | 4 +++- hw/virtio/meson.build | 4 +++- migration/meson.build | 4 +++- monitor/meson.build | 9 +++++++-- net/meson.build | 4 +++- qom/meson.build | 4 +++- stats/meson.build | 5 ++++- stubs/meson.build | 12 +++++++----- system/meson.build | 9 +++++++-- tests/qtest/meson.build | 8 +++++++- trace/meson.build | 5 ++++- ui/meson.build | 4 +++- 24 files changed, 85 insertions(+), 33 deletions(-) diff --git a/meson.build b/meson.build index XXXXXXX..XXXXXXX 100644 --- a/meson.build +++ b/meson.build @@ -XXX,XX +XXX,XX @@ hx_headers = [ ['qemu-options.hx', 'qemu-options.def'], ['qemu-img-cmds.hx', 'qemu-img-cmds.h'], ] -if have_system +if have_system and have_hmp hx_headers += [ ['hmp-commands.hx', 'hmp-commands.h'], ['hmp-commands-info.hx', 'hmp-commands-info.h'], diff --git a/hw/pci/pci-hmp-cmds.c b/hw/pci/pci-hmp-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/hw/pci/pci-hmp-cmds.c +++ b/hw/pci/pci-hmp-cmds.c @@ -XXX,XX +XXX,XX @@ void hmp_info_pci(Monitor *mon, const QDict *qdict) qapi_free_PciInfoList(info_list); } -#ifdef CONFIG_HMP void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent) { PCIDevice *d = (PCIDevice *)dev; @@ -XXX,XX +XXX,XX @@ void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent) r->addr, r->addr + r->size - 1); } } -#endif void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict) { diff --git a/monitor/hmp.c b/monitor/hmp.c index XXXXXXX..XXXXXXX 100644 --- a/monitor/hmp.c +++ b/monitor/hmp.c @@ -XXX,XX +XXX,XX @@ static int get_monitor_def(Monitor *mon, int64_t *pval, const char *name) if (cs == NULL) { return -1; } -#ifdef CONFIG_HMP md = cs->cc->sysemu_ops->monitor_defs; -#endif if (md == NULL) { return -1; } diff --git a/audio/meson.build b/audio/meson.build index XXXXXXX..XXXXXXX 100644 --- a/audio/meson.build +++ b/audio/meson.build @@ -XXX,XX +XXX,XX @@ audio_ss.add(files( )) # deprecated since v10.2, to be removed -system_ss.add(files('audio-hmp-cmds.c', 'wavcapture.c')) +if have_hmp + system_ss.add(files('audio-hmp-cmds.c', 'wavcapture.c')) +endif audio_modules = {} foreach m : [ diff --git a/backends/meson.build b/backends/meson.build index XXXXXXX..XXXXXXX 100644 --- a/backends/meson.build +++ b/backends/meson.build @@ -XXX,XX +XXX,XX @@ system_ss.add([files( 'cryptodev-builtin.c', - 'cryptodev-hmp-cmds.c', 'cryptodev.c', 'hostmem-ram.c', 'hostmem.c', @@ -XXX,XX +XXX,XX @@ system_ss.add([files( 'confidential-guest-support.c', ), numa]) +if have_hmp + system_ss.add(files('cryptodev-hmp-cmds.c')) +endif + if host_os != 'windows' system_ss.add(files('rng-random.c')) if host_os != 'emscripten' diff --git a/block/monitor/meson.build b/block/monitor/meson.build index XXXXXXX..XXXXXXX 100644 --- a/block/monitor/meson.build +++ b/block/monitor/meson.build @@ -XXX,XX +XXX,XX @@ -system_ss.add(files('block-hmp-cmds.c')) +if have_hmp + system_ss.add(files('block-hmp-cmds.c')) +endif block_ss.add(files('bitmap-qmp-cmds.c')) system_ss.add(files('qmp-cmds.c')) diff --git a/chardev/meson.build b/chardev/meson.build index XXXXXXX..XXXXXXX 100644 --- a/chardev/meson.build +++ b/chardev/meson.build @@ -XXX,XX +XXX,XX @@ endif chardev_ss = chardev_ss.apply({}) system_ss.add(files( - 'char-hmp-cmds.c', 'msmouse.c', 'wctablet.c', 'testdev.c')) +if have_hmp + system_ss.add(files('char-hmp-cmds.c')) +endif + chardev_modules = {} if brlapi.found() diff --git a/disas/meson.build b/disas/meson.build index XXXXXXX..XXXXXXX 100644 --- a/disas/meson.build +++ b/disas/meson.build @@ -XXX,XX +XXX,XX @@ common_ss.add(when: 'CONFIG_TCG', if_true: files( 'objdump.c' )) common_ss.add(files('disas-common.c')) -system_ss.add(files('disas-mon.c')) +if have_hmp + system_ss.add(files('disas-mon.c')) +endif specific_ss.add(capstone) diff --git a/dump/meson.build b/dump/meson.build index XXXXXXX..XXXXXXX 100644 --- a/dump/meson.build +++ b/dump/meson.build @@ -XXX,XX +XXX,XX @@ -system_ss.add([files('dump.c', 'dump-hmp-cmds.c'), snappy, lzo]) +system_ss.add([files('dump.c'), snappy, lzo]) +if have_hmp + system_ss.add(files('dump-hmp-cmds.c')) +endif specific_ss.add(when: 'CONFIG_WINDUMP', if_true: files('win_dump-x86.c')) system_ss.add(when: 'CONFIG_WINDUMP', if_false: files('win_dump-stubs.c')) diff --git a/hw/core/meson.build b/hw/core/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/core/meson.build +++ b/hw/core/meson.build @@ -XXX,XX +XXX,XX @@ system_ss.add(when: 'CONFIG_SPLIT_IRQ', if_true: files('split-irq.c')) system_ss.add(when: 'CONFIG_XILINX_AXI', if_true: files('stream.c')) system_ss.add(when: 'CONFIG_PLATFORM_BUS', if_true: files('sysbus-fdt.c')) system_ss.add(when: 'CONFIG_EIF', if_true: [files('eif.c'), zlib, libcbor, gnutls]) - system_ss.add(files( 'cpu-system.c', 'fw-path-provider.c', 'hotplug.c', 'loader.c', - 'machine-hmp-cmds.c', 'machine-qmp-cmds.c', 'machine.c', 'nmi.c', @@ -XXX,XX +XXX,XX @@ system_ss.add(files( 'vm-change-state-handler.c', 'clock-vmstate.c', )) +if have_hmp + system_ss.add(files('machine-hmp-cmds.c')) +endif user_ss.add(files( 'cpu-user.c', 'qdev-user.c', diff --git a/hw/i386/meson.build b/hw/i386/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/i386/meson.build +++ b/hw/i386/meson.build @@ -XXX,XX +XXX,XX @@ i386_ss.add(when: 'CONFIG_VTD', if_true: files('intel_iommu.c')) i386_ss.add(when: 'CONFIG_VTD_ACCEL', if_true: files('intel_iommu_accel.c')) i386_ss.add(when: 'CONFIG_SGX', if_true: files('sgx-epc.c','sgx.c'), if_false: files('sgx-stub.c')) -stub_ss.add(files('sgx-hmp-stub.c')) +if have_hmp + stub_ss.add(files('sgx-hmp-stub.c')) +endif i386_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-common.c')) i386_ss.add(when: 'CONFIG_PC', if_true: files( diff --git a/hw/net/meson.build b/hw/net/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/net/meson.build +++ b/hw/net/meson.build @@ -XXX,XX +XXX,XX @@ system_ss.add(when: 'CONFIG_ROCKER', if_true: files( 'rocker/rocker_world.c', )) stub_ss.add(files('rocker/rocker-stubs.c')) -system_ss.add(files('rocker/rocker-hmp-cmds.c')) +if have_hmp + system_ss.add(files('rocker/rocker-hmp-cmds.c')) +endif subdir('can') diff --git a/hw/pci/meson.build b/hw/pci/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/pci/meson.build +++ b/hw/pci/meson.build @@ -XXX,XX +XXX,XX @@ pci_ss.add(files( 'pci.c', 'pci_bridge.c', 'pci_host.c', - 'pci-hmp-cmds.c', 'pci-qmp-cmds.c', 'pcie_sriov.c', 'shpc.c', 'slotid_cap.c' )) +if have_hmp + pci_ss.add(files('pci-hmp-cmds.c')) +endif # The functions in these modules can be used by devices too. Since we # allow plugging PCIe devices into PCI buses, include them even if # CONFIG_PCI_EXPRESS=n. diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/virtio/meson.build +++ b/hw/virtio/meson.build @@ -XXX,XX +XXX,XX @@ stub_ss.add(files('vhost-user-stub.c')) stub_ss.add(files('virtio-stub.c')) stub_ss.add(files('virtio-md-stubs.c')) -system_ss.add(files('virtio-hmp-cmds.c')) +if have_hmp + system_ss.add(files('virtio-hmp-cmds.c')) +endif system_ss.add(when: 'CONFIG_ACPI', if_true: files('virtio-acpi.c')) diff --git a/migration/meson.build b/migration/meson.build index XXXXXXX..XXXXXXX 100644 --- a/migration/meson.build +++ b/migration/meson.build @@ -XXX,XX +XXX,XX @@ system_ss.add(files( 'socket.c', 'tls.c', ), gnutls, zlib) -system_ss.add([spice_headers, files('migration-hmp-cmds.c'), spice]) +if have_hmp + system_ss.add([spice_headers, files('migration-hmp-cmds.c'), spice]) +endif if get_option('replication').allowed() system_ss.add(files('colo-failover.c', 'colo.c', 'multifd-colo.c')) diff --git a/monitor/meson.build b/monitor/meson.build index XXXXXXX..XXXXXXX 100644 --- a/monitor/meson.build +++ b/monitor/meson.build @@ -XXX,XX +XXX,XX @@ qmp_ss.add(files('monitor.c', 'qmp.c', 'qmp-cmds-control.c')) system_ss.add(files( 'fds.c', - 'hmp-cmds.c', - 'hmp.c', 'qemu-config-qmp.c', 'qmp-cmds.c', )) + +if have_hmp + system_ss.add(files( + 'hmp-cmds.c', + 'hmp.c', + )) +endif diff --git a/net/meson.build b/net/meson.build index XXXXXXX..XXXXXXX 100644 --- a/net/meson.build +++ b/net/meson.build @@ -XXX,XX +XXX,XX @@ system_ss.add(files( 'filter-mirror.c', 'filter.c', 'hub.c', - 'net-hmp-cmds.c', 'net.c', 'queue.c', 'socket.c', @@ -XXX,XX +XXX,XX @@ system_ss.add(files( 'stream_data.c', 'util.c', )) +if have_hmp + system_ss.add(files('net-hmp-cmds.c')) +endif if get_option('replication').allowed() or \ get_option('colo_proxy').allowed() diff --git a/qom/meson.build b/qom/meson.build index XXXXXXX..XXXXXXX 100644 --- a/qom/meson.build +++ b/qom/meson.build @@ -XXX,XX +XXX,XX @@ if have_system endif qmp_ss.add(files('qom-qmp-cmds.c')) -system_ss.add(files('qom-hmp-cmds.c')) +if have_hmp + system_ss.add(files('qom-hmp-cmds.c')) +endif diff --git a/stats/meson.build b/stats/meson.build index XXXXXXX..XXXXXXX 100644 --- a/stats/meson.build +++ b/stats/meson.build @@ -1 +1,4 @@ -system_ss.add(files('stats-hmp-cmds.c', 'stats-qmp-cmds.c')) +system_ss.add(files('stats-qmp-cmds.c')) +if have_hmp + system_ss.add(files('stats-hmp-cmds.c')) +endif diff --git a/stubs/meson.build b/stubs/meson.build index XXXXXXX..XXXXXXX 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -XXX,XX +XXX,XX @@ if have_system stub_ss.add(files('qmp-cpu.c')) stub_ss.add(files('qmp-cpu-s390x.c')) stub_ss.add(files('qmp-cpu-s390x-kvm.c')) - stub_ss.add(files('hmp-cmd-info_mem.c')) - stub_ss.add(files('hmp-cmd-info_sev.c')) - stub_ss.add(files('hmp-cmd-info_tlb.c')) - stub_ss.add(files('hmp-cmds-hw-s390x.c')) - stub_ss.add(files('hmp-cmds-target-i386.c')) + if have_hmp + stub_ss.add(files('hmp-cmd-info_mem.c')) + stub_ss.add(files('hmp-cmd-info_sev.c')) + stub_ss.add(files('hmp-cmd-info_tlb.c')) + stub_ss.add(files('hmp-cmds-hw-s390x.c')) + stub_ss.add(files('hmp-cmds-target-i386.c')) + endif endif if have_system or have_user diff --git a/system/meson.build b/system/meson.build index XXXXXXX..XXXXXXX 100644 --- a/system/meson.build +++ b/system/meson.build @@ -XXX,XX +XXX,XX @@ system_ss.add(files( 'qtest.c', 'rtc.c', 'runstate-action.c', - 'runstate-hmp-cmds.c', 'runstate.c', - 'tpm-hmp-cmds.c', 'watchpoint.c', )) +if have_hmp + system_ss.add(files( + 'runstate-hmp-cmds.c', + 'tpm-hmp-cmds.c', + )) +endif + if have_tpm system_ss.add(files('tpm.c')) endif diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -XXX,XX +XXX,XX @@ qtests_generic = [ 'qmp-test', 'qmp-cmd-test', 'qom-test', - 'test-hmp', +] +if have_hmp + qtests_generic += [ + 'test-hmp', + ] +endif +qtests_generic += [ 'qos-test', 'readconfig-test', 'netdev-socket', diff --git a/trace/meson.build b/trace/meson.build index XXXXXXX..XXXXXXX 100644 --- a/trace/meson.build +++ b/trace/meson.build @@ -XXX,XX +XXX,XX @@ -system_ss.add(files('control-target.c', 'trace-hmp-cmds.c')) +system_ss.add(files('control-target.c')) +if have_hmp + system_ss.add(files('trace-hmp-cmds.c')) +endif trace_rs_targets = [] trace_events_files = [] foreach item : [ '.' ] + trace_events_subdirs + qapi_trace_events diff --git a/ui/meson.build b/ui/meson.build index XXXXXXX..XXXXXXX 100644 --- a/ui/meson.build +++ b/ui/meson.build @@ -XXX,XX +XXX,XX @@ system_ss.add(png) system_ss.add(files( 'input-barrier.c', 'input.c', - 'ui-hmp-cmds.c', 'ui-qmp-cmds.c', 'util.c', )) +if have_hmp + system_ss.add(files('ui-hmp-cmds.c')) +endif system_ss.add(ui) system_ss.add(when: pixman, if_true: files('console-vc.c'), if_false: files('console-vc-stubs.c')) if dbus_display -- 2.54.0
Guard monitor_uses_readline() and monitor_is_hmp_non_interactive() with CONFIG_HMP, providing a stub returning false when HMP is disabled. Also guard the HMP code paths in monitor_accept_input() and monitor_data_destroy() that reference MonitorHMP fields. Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com> --- monitor/monitor.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/monitor/monitor.c b/monitor/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -XXX,XX +XXX,XX @@ bool monitor_cur_is_qmp(void) return cur_mon && monitor_is_qmp(cur_mon); } +#ifdef CONFIG_HMP /** * Is @mon is using readline? * Note: not all HMP monitors use readline, e.g., gdbserver has a @@ -XXX,XX +XXX,XX @@ static inline bool monitor_is_hmp_non_interactive(const Monitor *mon) return !monitor_uses_readline(container_of(mon, MonitorHMP, common)); } +#else +static inline bool monitor_is_hmp_non_interactive(const Monitor *mon) +{ + return false; +} +#endif static gboolean monitor_unblocked(void *do_not_use, GIOCondition cond, void *opaque) @@ -XXX,XX +XXX,XX @@ static void monitor_accept_input(void *opaque) { Monitor *mon = opaque; +#ifdef CONFIG_HMP qemu_mutex_lock(&mon->mon_lock); if (!monitor_is_qmp(mon)) { MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); @@ -XXX,XX +XXX,XX @@ static void monitor_accept_input(void *opaque) } else { qemu_mutex_unlock(&mon->mon_lock); } +#endif qemu_chr_fe_accept_input(&mon->chr); } @@ -XXX,XX +XXX,XX @@ void monitor_data_destroy(Monitor *mon) if (monitor_is_qmp(mon)) { monitor_data_destroy_qmp(container_of(mon, MonitorQMP, common)); } else { +#ifdef CONFIG_HMP MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); readline_free(hmp_mon->rs); g_free(hmp_mon->mon_cpu_path); +#endif } g_string_free(mon->outbuf, true); qemu_mutex_destroy(&mon->mon_lock); -- 2.54.0
Now that all callers of HMP-specific monitor APIs have been guarded by prior patches, wrap the public declarations and their definitions with CONFIG_HMP: - monitor.h: guard monitor_vprintf/printf/printc, monitor_init_hmp, monitor_read_command/password, and monitor_register_hmp* - monitor.c: guard monitor_vprintf/printf/printc definitions - stubs/monitor-core.c: guard monitor_vprintf stub - stubs/monitor-internal.c: guard monitor_init_hmp stub Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com> --- include/monitor/monitor.h | 11 +++++++++++ monitor/monitor.c | 2 ++ stubs/monitor-core.c | 2 ++ stubs/monitor-internal.c | 2 ++ 4 files changed, 17 insertions(+) diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index XXXXXXX..XXXXXXX 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -XXX,XX +XXX,XX @@ bool monitor_cur_is_qmp(void); void monitor_init_globals(void); void monitor_init_globals_core(void); void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp); +#ifdef CONFIG_HMP void monitor_init_hmp(Chardev *chr, bool use_readline, Error **errp); +#endif int monitor_init(MonitorOptions *opts, bool allow_hmp, Error **errp); int monitor_init_opts(QemuOpts *opts, Error **errp); void monitor_cleanup(void); @@ -XXX,XX +XXX,XX @@ int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp); int monitor_fd_param(Monitor *mon, const char *fdname, Error **errp); int monitor_puts(Monitor *mon, const char *str); + +#ifdef CONFIG_HMP int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) G_GNUC_PRINTF(2, 0); int monitor_printf(Monitor *mon, const char *fmt, ...) G_GNUC_PRINTF(2, 3); void monitor_printc(Monitor *mon, int ch); +#endif + void monitor_flush(Monitor *mon); int monitor_get_cpu_index(Monitor *mon); int monitor_puts_locked(Monitor *mon, const char *str); void monitor_flush_locked(Monitor *mon); + +#ifdef CONFIG_HMP void monitor_read_command(MonitorHMP *mon, int show_prompt); int monitor_read_password(MonitorHMP *mon, ReadLineFunc *readline_func, void *opaque); +#endif AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id, const char *opaque, Error **errp); int monitor_fdset_dup_fd_add(int64_t fdset_id, int flags, Error **errp); void monitor_fdset_dup_fd_remove(int dup_fd); +#ifdef CONFIG_HMP void monitor_register_hmp(const char *name, bool info, void (*cmd)(Monitor *mon, const QDict *qdict)); void monitor_register_hmp_info_hrt(const char *name, HumanReadableText *(*handler)(Error **errp)); +#endif #endif /* MONITOR_H */ diff --git a/monitor/monitor.c b/monitor/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -XXX,XX +XXX,XX @@ int monitor_puts(Monitor *mon, const char *str) return monitor_puts_locked(mon, str); } +#ifdef CONFIG_HMP int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { char *buf; @@ -XXX,XX +XXX,XX @@ void monitor_printc(Monitor *mon, int c) } monitor_printf(mon, "'"); } +#endif static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = { /* Limit guest-triggerable events to 1 per second */ diff --git a/stubs/monitor-core.c b/stubs/monitor-core.c index XXXXXXX..XXXXXXX 100644 --- a/stubs/monitor-core.c +++ b/stubs/monitor-core.c @@ -XXX,XX +XXX,XX @@ void qapi_event_emit(QAPIEvent event, QDict *qdict) { } +#ifdef CONFIG_HMP int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { /* @@ -XXX,XX +XXX,XX @@ int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) } return -1; } +#endif diff --git a/stubs/monitor-internal.c b/stubs/monitor-internal.c index XXXXXXX..XXXXXXX 100644 --- a/stubs/monitor-internal.c +++ b/stubs/monitor-internal.c @@ -XXX,XX +XXX,XX @@ int monitor_get_fd(Monitor *mon, const char *name, Error **errp) return -1; } +#ifdef CONFIG_HMP void monitor_init_hmp(Chardev *chr, bool use_readline, Error **errp) { } +#endif -- 2.54.0