diff options
55 files changed, 1259 insertions, 618 deletions
@@ -860,6 +860,8 @@ docs/interop/qemu-qmp-ref.dvi docs/interop/qemu-qmp-ref.html \ docs/interop/qemu-qmp-ref.txt docs/interop/qemu-qmp-ref.7: \ docs/interop/qemu-qmp-ref.texi docs/interop/qemu-qmp-qapi.texi +$(filter %.1 %.7 %.8,$(DOCS)): scripts/texi2pod.pl + # Reports/Analysis %/coverage-report.html: diff --git a/audio/audio_int.h b/audio/audio_int.h index 244b454012..6c451b995c 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -191,7 +191,7 @@ struct SWVoiceCap { QLIST_ENTRY (SWVoiceCap) entries; }; -struct AudioState { +typedef struct AudioState { struct audio_driver *drv; void *drv_opaque; @@ -203,7 +203,7 @@ struct AudioState { int nb_hw_voices_out; int nb_hw_voices_in; int vm_running; -}; +} AudioState; extern const struct mixeng_volume nominal_volume; diff --git a/block/iscsi.c b/block/iscsi.c index a7e8c1ffaf..ff473206e6 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -49,7 +49,9 @@ /* Conflict between scsi/utils.h and libiscsi! :( */ #define SCSI_XFER_NONE ISCSI_XFER_NONE #include <iscsi/iscsi.h> +#define inline __attribute__((gnu_inline)) /* required for libiscsi v1.9.0 */ #include <iscsi/scsi-lowlevel.h> +#undef inline #undef SCSI_XFER_NONE QEMU_BUILD_BUG_ON((int)SCSI_XFER_NONE != (int)ISCSI_XFER_NONE); diff --git a/block/nbd-client.c b/block/nbd-client.c index ef32075971..813539676d 100644 --- a/block/nbd-client.c +++ b/block/nbd-client.c @@ -249,11 +249,11 @@ static int nbd_parse_blockstatus_payload(NBDClientSession *client, } context_id = payload_advance32(&payload); - if (client->info.meta_base_allocation_id != context_id) { + if (client->info.context_id != context_id) { error_setg(errp, "Protocol error: unexpected context id %d for " "NBD_REPLY_TYPE_BLOCK_STATUS, when negotiated context " "id is %d", context_id, - client->info.meta_base_allocation_id); + client->info.context_id); return -EINVAL; } @@ -999,10 +999,11 @@ int nbd_client_init(BlockDriverState *bs, client->info.structured_reply = true; client->info.base_allocation = true; client->info.x_dirty_bitmap = g_strdup(x_dirty_bitmap); - ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), export, - tlscreds, hostname, + client->info.name = g_strdup(export ?: ""); + ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), tlscreds, hostname, &client->ioc, &client->info, errp); g_free(client->info.x_dirty_bitmap); + g_free(client->info.name); if (ret < 0) { logout("Failed to negotiate with the NBD server\n"); return ret; diff --git a/blockdev-nbd.c b/blockdev-nbd.c index c76d5416b9..d73ac1b026 100644 --- a/blockdev-nbd.c +++ b/blockdev-nbd.c @@ -146,6 +146,7 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name, BlockDriverState *bs = NULL; BlockBackend *on_eject_blk; NBDExport *exp; + int64_t len; if (!nbd_server) { error_setg(errp, "NBD server not running"); @@ -168,6 +169,13 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name, return; } + len = bdrv_getlength(bs); + if (len < 0) { + error_setg_errno(errp, -len, + "Failed to determine the NBD export's length"); + return; + } + if (!has_writable) { writable = false; } @@ -175,7 +183,7 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name, writable = false; } - exp = nbd_export_new(bs, 0, -1, name, NULL, bitmap, + exp = nbd_export_new(bs, 0, len, name, NULL, bitmap, writable ? 0 : NBD_FLAG_READ_ONLY, NULL, false, on_eject_blk, errp); if (!exp) { @@ -107,6 +107,9 @@ update_cxxflags() { -Wstrict-prototypes|-Wmissing-prototypes|-Wnested-externs|\ -Wold-style-declaration|-Wold-style-definition|-Wredundant-decls) ;; + -std=gnu99) + QEMU_CXXFLAGS=${QEMU_CXXFLAGS:+$QEMU_CXXFLAGS }"-std=gnu++98" + ;; *) QEMU_CXXFLAGS=${QEMU_CXXFLAGS:+$QEMU_CXXFLAGS }$arg ;; @@ -584,7 +587,7 @@ ARFLAGS="${ARFLAGS-rv}" # left shift of signed integers is well defined and has the expected # 2s-complement style results. (Both clang and gcc agree that it # provides these semantics.) -QEMU_CFLAGS="-fno-strict-aliasing -fno-common -fwrapv $QEMU_CFLAGS" +QEMU_CFLAGS="-fno-strict-aliasing -fno-common -fwrapv -std=gnu99 $QEMU_CFLAGS" QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS" QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS" QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS" diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index ac94594b19..dff1330050 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -34,6 +34,7 @@ #include "sysemu/kvm.h" #include "hw/ppc/spapr.h" #include "hw/ppc/xics.h" +#include "hw/ppc/xics_spapr.h" #include "kvm_ppc.h" #include "qemu/config-file.h" #include "qemu/error-report.h" diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c index 9c1a90d709..de6cc15b64 100644 --- a/hw/intc/xics_spapr.c +++ b/hw/intc/xics_spapr.c @@ -32,6 +32,7 @@ #include "qemu/timer.h" #include "hw/ppc/spapr.h" #include "hw/ppc/xics.h" +#include "hw/ppc/xics_spapr.h" #include "hw/ppc/fdt.h" #include "qapi/visitor.h" diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 5fce72fe0f..1da7a32348 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -14,6 +14,7 @@ #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_xive.h" #include "hw/ppc/xics.h" +#include "hw/ppc/xics_spapr.h" #include "sysemu/kvm.h" #include "trace.h" diff --git a/include/block/nbd.h b/include/block/nbd.h index 1971b55789..4faf394e34 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2017 Red Hat, Inc. + * Copyright (C) 2016-2019 Red Hat, Inc. * Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws> * * Network Block Device @@ -263,26 +263,39 @@ struct NBDExportInfo { bool request_sizes; char *x_dirty_bitmap; + /* Set by client before nbd_receive_negotiate(), or by server results + * during nbd_receive_export_list() */ + char *name; /* must be non-NULL */ + /* In-out fields, set by client before nbd_receive_negotiate() and * updated by server results during nbd_receive_negotiate() */ bool structured_reply; bool base_allocation; /* base:allocation context for NBD_CMD_BLOCK_STATUS */ - /* Set by server results during nbd_receive_negotiate() */ + /* Set by server results during nbd_receive_negotiate() and + * nbd_receive_export_list() */ uint64_t size; uint16_t flags; uint32_t min_block; uint32_t opt_block; uint32_t max_block; - uint32_t meta_base_allocation_id; + uint32_t context_id; + + /* Set by server results during nbd_receive_export_list() */ + char *description; + int n_contexts; + char **contexts; }; typedef struct NBDExportInfo NBDExportInfo; -int nbd_receive_negotiate(QIOChannel *ioc, const char *name, - QCryptoTLSCreds *tlscreds, const char *hostname, - QIOChannel **outioc, NBDExportInfo *info, - Error **errp); +int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + const char *hostname, QIOChannel **outioc, + NBDExportInfo *info, Error **errp); +void nbd_free_export_list(NBDExportInfo *info, int count); +int nbd_receive_export_list(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + const char *hostname, NBDExportInfo **info, + Error **errp); int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info, Error **errp); int nbd_send_request(QIOChannel *ioc, NBDRequest *request); @@ -294,8 +307,8 @@ int nbd_errno_to_system_errno(int err); typedef struct NBDExport NBDExport; typedef struct NBDClient NBDClient; -NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size, - const char *name, const char *description, +NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, + uint64_t size, const char *name, const char *desc, const char *bitmap, uint16_t nbdflags, void (*close)(NBDExport *), bool writethrough, BlockBackend *on_eject_blk, Error **errp); diff --git a/include/hw/arm/pxa.h b/include/hw/arm/pxa.h index 0df1199caa..f6dfb5c0cf 100644 --- a/include/hw/arm/pxa.h +++ b/include/hw/arm/pxa.h @@ -12,6 +12,7 @@ #include "exec/memory.h" #include "target/arm/cpu-qom.h" +#include "hw/pcmcia.h" /* Interrupt numbers */ # define PXA2XX_PIC_SSP3 0 diff --git a/include/hw/char/serial.h b/include/hw/char/serial.h index 0acfbbc382..abd5cf71a9 100644 --- a/include/hw/char/serial.h +++ b/include/hw/char/serial.h @@ -35,7 +35,7 @@ #define UART_FIFO_LENGTH 16 /* 16550A Fifo Length */ -struct SerialState { +typedef struct SerialState { uint16_t divider; uint8_t rbr; /* receive register */ uint8_t thr; /* transmit holding register */ @@ -77,7 +77,7 @@ struct SerialState { QEMUTimer *modem_status_poll; MemoryRegion io; -}; +} SerialState; extern const VMStateDescription vmstate_serial; extern const MemoryRegionOps serial_io_ops; diff --git a/include/hw/devices.h b/include/hw/devices.h index 0e27feb0c2..b5f1662225 100644 --- a/include/hw/devices.h +++ b/include/hw/devices.h @@ -4,6 +4,7 @@ /* Devices that have nowhere better to go. */ #include "hw/hw.h" +#include "ui/console.h" /* smc91c111.c */ void smc91c111_init(NICInfo *, uint32_t, qemu_irq); diff --git a/include/hw/i2c/smbus.h b/include/hw/i2c/smbus.h index d8b1b9ee81..5c61c05999 100644 --- a/include/hw/i2c/smbus.h +++ b/include/hw/i2c/smbus.h @@ -35,6 +35,8 @@ #define SMBUS_DEVICE_GET_CLASS(obj) \ OBJECT_GET_CLASS(SMBusDeviceClass, (obj), TYPE_SMBUS_DEVICE) +typedef struct SMBusDevice SMBusDevice; + typedef struct SMBusDeviceClass { I2CSlaveClass parent_class; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 0abbe45637..882fd8dfd2 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -96,7 +96,7 @@ struct PCMachineState { * way we can use 1GByte pages in the host. * */ -struct PCMachineClass { +typedef struct PCMachineClass { /*< private >*/ MachineClass parent_class; @@ -133,7 +133,7 @@ struct PCMachineClass { /* use DMA capable linuxboot option rom */ bool linuxboot_dma_enabled; -}; +} PCMachineClass; #define TYPE_PC_MACHINE "generic-pc-machine" #define PC_MACHINE(obj) \ diff --git a/include/hw/ide/ahci.h b/include/hw/ide/ahci.h index b7bb2b02d6..b44e3000cf 100644 --- a/include/hw/ide/ahci.h +++ b/include/hw/ide/ahci.h @@ -73,13 +73,13 @@ typedef struct SysbusAHCIState { #define ALLWINNER_AHCI_MMIO_OFF 0x80 #define ALLWINNER_AHCI_MMIO_SIZE 0x80 -struct AllwinnerAHCIState { +typedef struct AllwinnerAHCIState { /*< private >*/ SysbusAHCIState parent_obj; /*< public >*/ MemoryRegion mmio; uint32_t regs[ALLWINNER_AHCI_MMIO_SIZE/4]; -}; +} AllwinnerAHCIState; #endif /* HW_IDE_AHCI_H */ diff --git a/include/hw/input/ps2.h b/include/hw/input/ps2.h index 213aa16aa3..b60455d4f6 100644 --- a/include/hw/input/ps2.h +++ b/include/hw/input/ps2.h @@ -31,6 +31,8 @@ #define PS2_MOUSE_BUTTON_SIDE 0x08 #define PS2_MOUSE_BUTTON_EXTRA 0x10 +typedef struct PS2State PS2State; + /* ps2.c */ void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg); void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg); diff --git a/include/hw/pcmcia.h b/include/hw/pcmcia.h index 79cac9c761..1b4080764f 100644 --- a/include/hw/pcmcia.h +++ b/include/hw/pcmcia.h @@ -18,13 +18,13 @@ typedef struct PCMCIASocket { #define PCMCIA_CARD_CLASS(cls) \ OBJECT_CLASS_CHECK(PCMCIACardClass, cls, TYPE_PCMCIA_CARD) -struct PCMCIACardState { +typedef struct PCMCIACardState { /*< private >*/ DeviceState parent_obj; /*< public >*/ PCMCIASocket *slot; -}; +} PCMCIACardState; typedef struct PCMCIACardClass { /*< private >*/ diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 9e01a5a12e..a947a0a0dc 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -8,15 +8,16 @@ #include "hw/mem/pc-dimm.h" #include "hw/ppc/spapr_ovec.h" #include "hw/ppc/spapr_irq.h" +#include "hw/ppc/spapr_xive.h" /* For sPAPRXive */ +#include "hw/ppc/xics.h" /* For ICSState */ struct VIOsPAPRBus; struct sPAPRPHBState; struct sPAPRNVRAM; + typedef struct sPAPREventLogEntry sPAPREventLogEntry; typedef struct sPAPREventSource sPAPREventSource; typedef struct sPAPRPendingHPT sPAPRPendingHPT; -typedef struct ICSState ICSState; -typedef struct sPAPRXive sPAPRXive; #define HPTE64_V_HPTE_DIRTY 0x0000000000000040ULL #define SPAPR_ENTRY_POINT 0x100 diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h index 7fdc250574..9bec9192e4 100644 --- a/include/hw/ppc/spapr_xive.h +++ b/include/hw/ppc/spapr_xive.h @@ -41,8 +41,6 @@ bool spapr_xive_irq_claim(sPAPRXive *xive, uint32_t lisn, bool lsi); bool spapr_xive_irq_free(sPAPRXive *xive, uint32_t lisn); void spapr_xive_pic_print_info(sPAPRXive *xive, Monitor *mon); -typedef struct sPAPRMachineState sPAPRMachineState; - void spapr_xive_hcall_init(sPAPRMachineState *spapr); void spapr_dt_xive(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt, uint32_t phandle); diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index 07508cbd21..fad786e8b2 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -200,13 +200,6 @@ void ics_pic_print_info(ICSState *ics, Monitor *mon); void ics_resend(ICSState *ics); void icp_resend(ICPState *ss); -typedef struct sPAPRMachineState sPAPRMachineState; - -void spapr_dt_xics(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt, - uint32_t phandle); -int xics_kvm_init(sPAPRMachineState *spapr, Error **errp); -void xics_spapr_init(sPAPRMachineState *spapr); - Object *icp_create(Object *cpu, const char *type, XICSFabric *xi, Error **errp); diff --git a/include/hw/ppc/xics_spapr.h b/include/hw/ppc/xics_spapr.h new file mode 100644 index 0000000000..b1ab27d022 --- /dev/null +++ b/include/hw/ppc/xics_spapr.h @@ -0,0 +1,37 @@ +/* + * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator + * + * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics + * + * Copyright (c) 2010, 2011 David Gibson, IBM Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef XICS_SPAPR_H +#define XICS_SPAPR_H + +#include "hw/ppc/spapr.h" + +void spapr_dt_xics(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt, + uint32_t phandle); +int xics_kvm_init(sPAPRMachineState *spapr, Error **errp); +void xics_spapr_init(sPAPRMachineState *spapr); + +#endif /* XICS_SPAPR_H */ diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index c7ec1a755f..bd662752d2 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -106,7 +106,6 @@ typedef struct VirtioNetRscSeg { NetClientState *nc; } VirtioNetRscSeg; -struct VirtIONet; typedef struct VirtIONet VirtIONet; /* Chain is divided by protocol(ipv4/v6) and NetClientInfo */ @@ -136,7 +135,7 @@ typedef struct VirtIONetQueue { struct VirtIONet *n; } VirtIONetQueue; -typedef struct VirtIONet { +struct VirtIONet { VirtIODevice parent_obj; uint8_t mac[ETH_ALEN]; uint16_t status; @@ -186,7 +185,7 @@ typedef struct VirtIONet { int announce_counter; bool needs_vnet_hdr_swap; bool mtu_bypass_backend; -} VirtIONet; +}; void virtio_net_set_netclient_name(VirtIONet *n, const char *name, const char *type); diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h index 2d8f507c73..296b2fd572 100644 --- a/include/qemu/compiler.h +++ b/include/qemu/compiler.h @@ -113,6 +113,10 @@ #define GCC_FMT_ATTR(n, m) #endif +#ifndef __has_warning +#define __has_warning(x) 0 /* compatibility with non-clang compilers */ +#endif + #ifndef __has_feature #define __has_feature(x) 0 /* compatibility with non-clang compilers */ #endif diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 741935fe36..5d1a2d8329 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -8,8 +8,6 @@ typedef struct AdapterInfo AdapterInfo; typedef struct AddressSpace AddressSpace; typedef struct AioContext AioContext; -typedef struct AllwinnerAHCIState AllwinnerAHCIState; -typedef struct AudioState AudioState; typedef struct BdrvDirtyBitmap BdrvDirtyBitmap; typedef struct BdrvDirtyBitmapIter BdrvDirtyBitmapIter; typedef struct BlockBackend BlockBackend; @@ -26,8 +24,6 @@ typedef struct DeviceListener DeviceListener; typedef struct DeviceState DeviceState; typedef struct DirtyBitmapSnapshot DirtyBitmapSnapshot; typedef struct DisplayChangeListener DisplayChangeListener; -typedef struct DisplayState DisplayState; -typedef struct DisplaySurface DisplaySurface; typedef struct DriveInfo DriveInfo; typedef struct Error Error; typedef struct EventNotifier EventNotifier; @@ -36,7 +32,6 @@ typedef struct FWCfgEntry FWCfgEntry; typedef struct FWCfgIoState FWCfgIoState; typedef struct FWCfgMemState FWCfgMemState; typedef struct FWCfgState FWCfgState; -typedef struct HCIInfo HCIInfo; typedef struct HVFX86EmulatorState HVFX86EmulatorState; typedef struct I2CBus I2CBus; typedef struct I2SCodec I2SCodec; @@ -56,7 +51,6 @@ typedef struct MigrationIncomingState MigrationIncomingState; typedef struct MigrationState MigrationState; typedef struct Monitor Monitor; typedef struct MonitorDef MonitorDef; -typedef struct MouseTransformInfo MouseTransformInfo; typedef struct MSIMessage MSIMessage; typedef struct NetClientState NetClientState; typedef struct NetFilterState NetFilterState; @@ -76,19 +70,14 @@ typedef struct PCIExpressDevice PCIExpressDevice; typedef struct PCIExpressHost PCIExpressHost; typedef struct PCIHostDeviceAddress PCIHostDeviceAddress; typedef struct PCIHostState PCIHostState; -typedef struct PCMachineClass PCMachineClass; typedef struct PCMachineState PCMachineState; -typedef struct PCMCIACardState PCMCIACardState; -typedef struct PixelFormat PixelFormat; typedef struct PostcopyDiscardState PostcopyDiscardState; typedef struct Property Property; typedef struct PropertyInfo PropertyInfo; -typedef struct PS2State PS2State; typedef struct QBool QBool; typedef struct QDict QDict; typedef struct QEMUBH QEMUBH; typedef struct QemuConsole QemuConsole; -typedef struct QemuDmaBuf QemuDmaBuf; typedef struct QEMUFile QEMUFile; typedef struct QemuLockable QemuLockable; typedef struct QemuMutex QemuMutex; @@ -107,9 +96,7 @@ typedef struct QObject QObject; typedef struct QString QString; typedef struct RAMBlock RAMBlock; typedef struct Range Range; -typedef struct SerialState SerialState; typedef struct SHPCDevice SHPCDevice; -typedef struct SMBusDevice SMBusDevice; typedef struct SSIBus SSIBus; typedef struct uWireSlave uWireSlave; typedef struct VirtIODevice VirtIODevice; diff --git a/include/sysemu/bt.h b/include/sysemu/bt.h index ddb05cd109..2fd8c0f14b 100644 --- a/include/sysemu/bt.h +++ b/include/sysemu/bt.h @@ -3,7 +3,7 @@ /* BT HCI info */ -struct HCIInfo { +typedef struct HCIInfo { int (*bdaddr_set)(struct HCIInfo *hci, const uint8_t *bd_addr); void (*cmd_send)(struct HCIInfo *hci, const uint8_t *data, int len); void (*sco_send)(struct HCIInfo *hci, const uint8_t *data, int len); @@ -11,7 +11,7 @@ struct HCIInfo { void *opaque; void (*evt_recv)(void *opaque, const uint8_t *data, int len); void (*acl_recv)(void *opaque, const uint8_t *data, int len); -}; +} HCIInfo; /* bt-host.c */ struct HCIInfo *bt_host_hci(const char *id); diff --git a/include/ui/console.h b/include/ui/console.h index 853fcf4eb7..fef900db76 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -65,13 +65,13 @@ void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry); void kbd_put_ledstate(int ledstate); -struct MouseTransformInfo { +typedef struct MouseTransformInfo { /* Touchscreen resolution */ int x; int y; /* Calibration values as used/generated by tslib */ int a[7]; -}; +} MouseTransformInfo; void hmp_mouse_set(Monitor *mon, const QDict *qdict); @@ -121,17 +121,7 @@ struct QemuConsoleClass { #define QEMU_ALLOCATED_FLAG 0x01 -struct PixelFormat { - uint8_t bits_per_pixel; - uint8_t bytes_per_pixel; - uint8_t depth; /* color depth in bits */ - uint32_t rmask, gmask, bmask, amask; - uint8_t rshift, gshift, bshift, ashift; - uint8_t rmax, gmax, bmax, amax; - uint8_t rbits, gbits, bbits, abits; -}; - -struct DisplaySurface { +typedef struct DisplaySurface { pixman_format_code_t format; pixman_image_t *image; uint8_t flags; @@ -140,7 +130,7 @@ struct DisplaySurface { GLenum gltype; GLuint texture; #endif -}; +} DisplaySurface; typedef struct QemuUIInfo { /* geometry */ @@ -179,7 +169,7 @@ struct QEMUGLParams { int minor_ver; }; -struct QemuDmaBuf { +typedef struct QemuDmaBuf { int fd; uint32_t width; uint32_t height; @@ -187,7 +177,9 @@ struct QemuDmaBuf { uint32_t fourcc; uint32_t texture; bool y0_top; -}; +} QemuDmaBuf; + +typedef struct DisplayState DisplayState; typedef struct DisplayChangeListenerOps { const char *dpy_name; diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h index b7c82d17fc..0668109305 100644 --- a/include/ui/qemu-pixman.h +++ b/include/ui/qemu-pixman.h @@ -53,6 +53,16 @@ /* -------------------------------------------------------------------- */ +typedef struct PixelFormat { + uint8_t bits_per_pixel; + uint8_t bytes_per_pixel; + uint8_t depth; /* color depth in bits */ + uint32_t rmask, gmask, bmask, amask; + uint8_t rshift, gshift, bshift, ashift; + uint8_t rmax, gmax, bmax, amax; + uint8_t rbits, gbits, bbits, abits; +} PixelFormat; + PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format); pixman_format_code_t qemu_default_pixman_format(int bpp, bool native_endian); pixman_format_code_t qemu_drm_format_to_pixman(uint32_t drm_format); diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 069df8f1f9..ef400cb78a 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -474,17 +474,13 @@ static inline int access_ok(int type, abi_ulong addr, abi_ulong size) * functions than host-endian unaligned load/store plus tswapN. * - The pragmas are necessary only to silence a clang false-positive * warning: see https://bugs.llvm.org/show_bug.cgi?id=39113 . - * - We have to disable -Wpragmas warnings to avoid a complaint about - * an unknown warning type from older compilers that don't know about - * -Waddress-of-packed-member. * - gcc has bugs in its _Pragma() support in some versions, eg * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83256 -- so we only * include the warning-suppression pragmas for clang */ -#ifdef __clang__ +#if defined(__clang__) && __has_warning("-Waddress-of-packed-member") #define PRAGMA_DISABLE_PACKED_WARNING \ _Pragma("GCC diagnostic push"); \ - _Pragma("GCC diagnostic ignored \"-Wpragmas\""); \ _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"") #define PRAGMA_REENABLE_PACKED_WARNING \ diff --git a/nbd/client.c b/nbd/client.c index f625c207c5..8a083c2f42 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -21,6 +21,7 @@ #include "qapi/error.h" #include "trace.h" #include "nbd-internal.h" +#include "qemu/cutils.h" /* Definitions for opaque data types */ @@ -234,18 +235,24 @@ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply, return result; } -/* Process another portion of the NBD_OPT_LIST reply. Set *@match if - * the current reply matches @want or if the server does not support - * NBD_OPT_LIST, otherwise leave @match alone. Return 0 if iteration - * is complete, positive if more replies are expected, or negative - * with @errp set if an unrecoverable error occurred. */ -static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, +/* nbd_receive_list: + * Process another portion of the NBD_OPT_LIST reply, populating any + * name received into *@name. If @description is non-NULL, and the + * server provided a description, that is also populated. The caller + * must eventually call g_free() on success. + * Returns 1 if name and description were set and iteration must continue, + * 0 if iteration is complete (including if OPT_LIST unsupported), + * -1 with @errp set if an unrecoverable error occurred. + */ +static int nbd_receive_list(QIOChannel *ioc, char **name, char **description, Error **errp) { + int ret = -1; NBDOptionReply reply; uint32_t len; uint32_t namelen; - char name[NBD_MAX_NAME_SIZE + 1]; + char *local_name = NULL; + char *local_desc = NULL; int error; if (nbd_receive_option_reply(ioc, NBD_OPT_LIST, &reply, errp) < 0) { @@ -253,9 +260,6 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, } error = nbd_handle_reply_err(ioc, &reply, errp); if (error <= 0) { - /* The server did not support NBD_OPT_LIST, so set *match on - * the assumption that any name will be accepted. */ - *match = true; return error; } len = reply.length; @@ -292,45 +296,54 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, nbd_send_opt_abort(ioc); return -1; } - if (namelen != strlen(want)) { - if (nbd_drop(ioc, len, errp) < 0) { - error_prepend(errp, - "failed to skip export name with wrong length: "); - nbd_send_opt_abort(ioc); - return -1; - } - return 1; - } - assert(namelen < sizeof(name)); - if (nbd_read(ioc, name, namelen, errp) < 0) { + local_name = g_malloc(namelen + 1); + if (nbd_read(ioc, local_name, namelen, errp) < 0) { error_prepend(errp, "failed to read export name: "); nbd_send_opt_abort(ioc); - return -1; + goto out; } - name[namelen] = '\0'; + local_name[namelen] = '\0'; len -= namelen; - if (nbd_drop(ioc, len, errp) < 0) { - error_prepend(errp, "failed to read export description: "); - nbd_send_opt_abort(ioc); - return -1; + if (len) { + local_desc = g_malloc(len + 1); + if (nbd_read(ioc, local_desc, len, errp) < 0) { + error_prepend(errp, "failed to read export description: "); + nbd_send_opt_abort(ioc); + goto out; + } + local_desc[len] = '\0'; } - if (!strcmp(name, want)) { - *match = true; + + trace_nbd_receive_list(local_name, local_desc ?: ""); + *name = local_name; + local_name = NULL; + if (description) { + *description = local_desc; + local_desc = NULL; } - return 1; + ret = 1; + + out: + g_free(local_name); + g_free(local_desc); + return ret; } -/* Returns -1 if NBD_OPT_GO proves the export @wantname cannot be - * used, 0 if NBD_OPT_GO is unsupported (fall back to NBD_OPT_LIST and +/* + * nbd_opt_info_or_go: + * Send option for NBD_OPT_INFO or NBD_OPT_GO and parse the reply. + * Returns -1 if the option proves the export @info->name cannot be + * used, 0 if the option is unsupported (fall back to NBD_OPT_LIST and * NBD_OPT_EXPORT_NAME in that case), and > 0 if the export is good to - * go (with @info populated). */ -static int nbd_opt_go(QIOChannel *ioc, const char *wantname, - NBDExportInfo *info, Error **errp) + * go (with the rest of @info populated). + */ +static int nbd_opt_info_or_go(QIOChannel *ioc, uint32_t opt, + NBDExportInfo *info, Error **errp) { NBDOptionReply reply; - uint32_t len = strlen(wantname); + uint32_t len = strlen(info->name); uint16_t type; int error; char *buf; @@ -340,16 +353,17 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname, * flags still 0 is a witness of a broken server. */ info->flags = 0; - trace_nbd_opt_go_start(wantname); + assert(opt == NBD_OPT_GO || opt == NBD_OPT_INFO); + trace_nbd_opt_info_go_start(nbd_opt_lookup(opt), info->name); buf = g_malloc(4 + len + 2 + 2 * info->request_sizes + 1); stl_be_p(buf, len); - memcpy(buf + 4, wantname, len); + memcpy(buf + 4, info->name, len); /* At most one request, everything else up to server */ stw_be_p(buf + 4 + len, info->request_sizes); if (info->request_sizes) { stw_be_p(buf + 4 + len + 2, NBD_INFO_BLOCK_SIZE); } - error = nbd_send_option_request(ioc, NBD_OPT_GO, + error = nbd_send_option_request(ioc, opt, 4 + len + 2 + 2 * info->request_sizes, buf, errp); g_free(buf); @@ -358,7 +372,7 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname, } while (1) { - if (nbd_receive_option_reply(ioc, NBD_OPT_GO, &reply, errp) < 0) { + if (nbd_receive_option_reply(ioc, opt, &reply, errp) < 0) { return -1; } error = nbd_handle_reply_err(ioc, &reply, errp); @@ -368,8 +382,10 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname, len = reply.length; if (reply.type == NBD_REP_ACK) { - /* Server is done sending info and moved into transmission - phase, but make sure it sent flags */ + /* + * Server is done sending info, and moved into transmission + * phase for NBD_OPT_GO, but make sure it sent flags + */ if (len) { error_setg(errp, "server sent invalid NBD_REP_ACK"); return -1; @@ -378,7 +394,7 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname, error_setg(errp, "broken server omitted NBD_INFO_EXPORT"); return -1; } - trace_nbd_opt_go_success(); + trace_nbd_opt_info_go_success(nbd_opt_lookup(opt)); return 1; } if (reply.type != NBD_REP_INFO) { @@ -472,12 +488,12 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname, nbd_send_opt_abort(ioc); return -1; } - trace_nbd_opt_go_info_block_size(info->min_block, info->opt_block, - info->max_block); + trace_nbd_opt_info_block_size(info->min_block, info->opt_block, + info->max_block); break; default: - trace_nbd_opt_go_info_unknown(type, nbd_info_lookup(type)); + trace_nbd_opt_info_unknown(type, nbd_info_lookup(type)); if (nbd_drop(ioc, len, errp) < 0) { error_prepend(errp, "Failed to read info payload: "); nbd_send_opt_abort(ioc); @@ -493,7 +509,8 @@ static int nbd_receive_query_exports(QIOChannel *ioc, const char *wantname, Error **errp) { - bool foundExport = false; + bool list_empty = true; + bool found_export = false; trace_nbd_receive_query_exports_start(wantname); if (nbd_send_option_request(ioc, NBD_OPT_LIST, 0, NULL, errp) < 0) { @@ -501,14 +518,25 @@ static int nbd_receive_query_exports(QIOChannel *ioc, } while (1) { - int ret = nbd_receive_list(ioc, wantname, &foundExport, errp); + char *name; + int ret = nbd_receive_list(ioc, &name, NULL, errp); if (ret < 0) { /* Server gave unexpected reply */ return -1; } else if (ret == 0) { /* Done iterating. */ - if (!foundExport) { + if (list_empty) { + /* + * We don't have enough context to tell a server that + * sent an empty list apart from a server that does + * not support the list command; but as this function + * is just used to trigger a nicer error message + * before trying NBD_OPT_EXPORT_NAME, assume the + * export is available. + */ + return 0; + } else if (!found_export) { error_setg(errp, "No export with name '%s' available", wantname); nbd_send_opt_abort(ioc); @@ -517,6 +545,11 @@ static int nbd_receive_query_exports(QIOChannel *ioc, trace_nbd_receive_query_exports_success(wantname); return 0; } + list_empty = false; + if (!strcmp(name, wantname)) { + found_export = true; + } + g_free(name); } } @@ -605,51 +638,67 @@ static QIOChannel *nbd_receive_starttls(QIOChannel *ioc, return QIO_CHANNEL(tioc); } -/* nbd_negotiate_simple_meta_context: - * Set one meta context. Simple means that reply must contain zero (not - * negotiated) or one (negotiated) contexts. More contexts would be considered - * as a protocol error. It's also implied that meta-data query equals queried - * context name, so, if server replies with something different than @context, - * it is considered an error too. - * return 1 for successful negotiation, context_id is set - * 0 if operation is unsupported, - * -1 with errp set for any other error +/* + * nbd_send_meta_query: + * Send 0 or 1 set/list meta context queries. + * Return 0 on success, -1 with errp set for any error */ -static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, - const char *export, - const char *context, - uint32_t *context_id, - Error **errp) +static int nbd_send_meta_query(QIOChannel *ioc, uint32_t opt, + const char *export, const char *query, + Error **errp) { int ret; - NBDOptionReply reply; - uint32_t received_id = 0; - bool received = false; uint32_t export_len = strlen(export); - uint32_t context_len = strlen(context); - uint32_t data_len = sizeof(export_len) + export_len + - sizeof(uint32_t) + /* number of queries */ - sizeof(context_len) + context_len; - char *data = g_malloc(data_len); - char *p = data; - - trace_nbd_opt_meta_request(context, export); + uint32_t queries = !!query; + uint32_t query_len = 0; + uint32_t data_len; + char *data; + char *p; + + data_len = sizeof(export_len) + export_len + sizeof(queries); + if (query) { + query_len = strlen(query); + data_len += sizeof(query_len) + query_len; + } else { + assert(opt == NBD_OPT_LIST_META_CONTEXT); + } + p = data = g_malloc(data_len); + + trace_nbd_opt_meta_request(nbd_opt_lookup(opt), query ?: "(all)", export); stl_be_p(p, export_len); memcpy(p += sizeof(export_len), export, export_len); - stl_be_p(p += export_len, 1); - stl_be_p(p += sizeof(uint32_t), context_len); - memcpy(p += sizeof(context_len), context, context_len); + stl_be_p(p += export_len, queries); + if (query) { + stl_be_p(p += sizeof(queries), query_len); + memcpy(p += sizeof(query_len), query, query_len); + } - ret = nbd_send_option_request(ioc, NBD_OPT_SET_META_CONTEXT, data_len, data, - errp); + ret = nbd_send_option_request(ioc, opt, data_len, data, errp); g_free(data); - if (ret < 0) { - return ret; - } + return ret; +} - if (nbd_receive_option_reply(ioc, NBD_OPT_SET_META_CONTEXT, &reply, - errp) < 0) - { +/* + * nbd_receive_one_meta_context: + * Called in a loop to receive and trace one set/list meta context reply. + * Pass non-NULL @name or @id to collect results back to the caller, which + * must eventually call g_free(). + * return 1 if name is set and iteration must continue, + * 0 if iteration is complete (including if option is unsupported), + * -1 with errp set for any error + */ +static int nbd_receive_one_meta_context(QIOChannel *ioc, + uint32_t opt, + char **name, + uint32_t *id, + Error **errp) +{ + int ret; + NBDOptionReply reply; + char *local_name = NULL; + uint32_t local_id; + + if (nbd_receive_option_reply(ioc, opt, &reply, errp) < 0) { return -1; } @@ -658,29 +707,92 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, return ret; } - if (reply.type == NBD_REP_META_CONTEXT) { - char *name; - - if (reply.length != sizeof(received_id) + context_len) { - error_setg(errp, "Failed to negotiate meta context '%s', server " - "answered with unexpected length %" PRIu32, context, - reply.length); + if (reply.type == NBD_REP_ACK) { + if (reply.length != 0) { + error_setg(errp, "Unexpected length to ACK response"); nbd_send_opt_abort(ioc); return -1; } + return 0; + } else if (reply.type != NBD_REP_META_CONTEXT) { + error_setg(errp, "Unexpected reply type %u (%s), expected %u (%s)", + reply.type, nbd_rep_lookup(reply.type), + NBD_REP_META_CONTEXT, nbd_rep_lookup(NBD_REP_META_CONTEXT)); + nbd_send_opt_abort(ioc); + return -1; + } - if (nbd_read(ioc, &received_id, sizeof(received_id), errp) < 0) { - return -1; - } - received_id = be32_to_cpu(received_id); + if (reply.length <= sizeof(local_id) || + reply.length > NBD_MAX_BUFFER_SIZE) { + error_setg(errp, "Failed to negotiate meta context, server " + "answered with unexpected length %" PRIu32, + reply.length); + nbd_send_opt_abort(ioc); + return -1; + } - reply.length -= sizeof(received_id); - name = g_malloc(reply.length + 1); - if (nbd_read(ioc, name, reply.length, errp) < 0) { - g_free(name); - return -1; - } - name[reply.length] = '\0'; + if (nbd_read(ioc, &local_id, sizeof(local_id), errp) < 0) { + return -1; + } + local_id = be32_to_cpu(local_id); + + reply.length -= sizeof(local_id); + local_name = g_malloc(reply.length + 1); + if (nbd_read(ioc, local_name, reply.length, errp) < 0) { + g_free(local_name); + return -1; + } + local_name[reply.length] = '\0'; + trace_nbd_opt_meta_reply(nbd_opt_lookup(opt), local_name, local_id); + + if (name) { + *name = local_name; + } else { + g_free(local_name); + } + if (id) { + *id = local_id; + } + return 1; +} + +/* + * nbd_negotiate_simple_meta_context: + * Request the server to set the meta context for export @info->name + * using @info->x_dirty_bitmap with a fallback to "base:allocation", + * setting @info->context_id to the resulting id. Fail if the server + * responds with more than one context or with a context different + * than the query. + * return 1 for successful negotiation, + * 0 if operation is unsupported, + * -1 with errp set for any other error + */ +static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, + NBDExportInfo *info, + Error **errp) +{ + /* + * TODO: Removing the x_dirty_bitmap hack will mean refactoring + * this function to request and store ids for multiple contexts + * (both base:allocation and a dirty bitmap), at which point this + * function should lose the term _simple. + */ + int ret; + const char *context = info->x_dirty_bitmap ?: "base:allocation"; + bool received = false; + char *name = NULL; + + if (nbd_send_meta_query(ioc, NBD_OPT_SET_META_CONTEXT, + info->name, context, errp) < 0) { + return -1; + } + + ret = nbd_receive_one_meta_context(ioc, NBD_OPT_SET_META_CONTEXT, + &name, &info->context_id, errp); + if (ret < 0) { + return -1; + } + if (ret == 1) { if (strcmp(context, name)) { error_setg(errp, "Failed to negotiate meta context '%s', server " "answered with different context '%s'", context, @@ -690,84 +802,115 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, return -1; } g_free(name); - - trace_nbd_opt_meta_reply(context, received_id); received = true; - /* receive NBD_REP_ACK */ - if (nbd_receive_option_reply(ioc, NBD_OPT_SET_META_CONTEXT, &reply, - errp) < 0) - { + ret = nbd_receive_one_meta_context(ioc, NBD_OPT_SET_META_CONTEXT, + NULL, NULL, errp); + if (ret < 0) { return -1; } - - ret = nbd_handle_reply_err(ioc, &reply, errp); - if (ret <= 0) { - return ret; - } } - - if (reply.type != NBD_REP_ACK) { - error_setg(errp, "Unexpected reply type %u (%s), expected %u (%s)", - reply.type, nbd_rep_lookup(reply.type), - NBD_REP_ACK, nbd_rep_lookup(NBD_REP_ACK)); + if (ret != 0) { + error_setg(errp, "Server answered with more than one context"); nbd_send_opt_abort(ioc); return -1; } - if (reply.length) { - error_setg(errp, "Unexpected length to ACK response"); - nbd_send_opt_abort(ioc); + return received; +} + +/* + * nbd_list_meta_contexts: + * Request the server to list all meta contexts for export @info->name. + * return 0 if list is complete (even if empty), + * -1 with errp set for any error + */ +static int nbd_list_meta_contexts(QIOChannel *ioc, + NBDExportInfo *info, + Error **errp) +{ + int ret; + int seen_any = false; + int seen_qemu = false; + + if (nbd_send_meta_query(ioc, NBD_OPT_LIST_META_CONTEXT, + info->name, NULL, errp) < 0) { return -1; } - if (received) { - *context_id = received_id; - return 1; + while (1) { + char *context; + + ret = nbd_receive_one_meta_context(ioc, NBD_OPT_LIST_META_CONTEXT, + &context, NULL, errp); + if (ret == 0 && seen_any && !seen_qemu) { + /* + * Work around qemu 3.0 bug: the server forgot to send + * "qemu:" replies to 0 queries. If we saw at least one + * reply (probably base:allocation), but none of them were + * qemu:, then run a more specific query to make sure. + */ + seen_qemu = true; + if (nbd_send_meta_query(ioc, NBD_OPT_LIST_META_CONTEXT, + info->name, "qemu:", errp) < 0) { + return -1; + } + continue; + } + if (ret <= 0) { + return ret; + } + seen_any = true; + seen_qemu |= strstart(context, "qemu:", NULL); + info->contexts = g_renew(char *, info->contexts, ++info->n_contexts); + info->contexts[info->n_contexts - 1] = context; } - - return 0; } -int nbd_receive_negotiate(QIOChannel *ioc, const char *name, - QCryptoTLSCreds *tlscreds, const char *hostname, - QIOChannel **outioc, NBDExportInfo *info, - Error **errp) +/* + * nbd_start_negotiate: + * Start the handshake to the server. After a positive return, the server + * is ready to accept additional NBD_OPT requests. + * Returns: negative errno: failure talking to server + * 0: server is oldstyle, must call nbd_negotiate_finish_oldstyle + * 1: server is newstyle, but can only accept EXPORT_NAME + * 2: server is newstyle, but lacks structured replies + * 3: server is newstyle and set up for structured replies + */ +static int nbd_start_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + const char *hostname, QIOChannel **outioc, + bool structured_reply, bool *zeroes, + Error **errp) { uint64_t magic; - int rc; - bool zeroes = true; - bool structured_reply = info->structured_reply; - bool base_allocation = info->base_allocation; - trace_nbd_receive_negotiate(tlscreds, hostname ? hostname : "<null>"); - - info->structured_reply = false; - info->base_allocation = false; - rc = -EINVAL; + trace_nbd_start_negotiate(tlscreds, hostname ? hostname : "<null>"); + if (zeroes) { + *zeroes = true; + } if (outioc) { *outioc = NULL; } if (tlscreds && !outioc) { error_setg(errp, "Output I/O channel required for TLS"); - goto fail; + return -EINVAL; } if (nbd_read(ioc, &magic, sizeof(magic), errp) < 0) { error_prepend(errp, "Failed to read initial magic: "); - goto fail; + return -EINVAL; } magic = be64_to_cpu(magic); trace_nbd_receive_negotiate_magic(magic); if (magic != NBD_INIT_MAGIC) { error_setg(errp, "Bad initial magic received: 0x%" PRIx64, magic); - goto fail; + return -EINVAL; } if (nbd_read(ioc, &magic, sizeof(magic), errp) < 0) { error_prepend(errp, "Failed to read server magic: "); - goto fail; + return -EINVAL; } magic = be64_to_cpu(magic); trace_nbd_receive_negotiate_magic(magic); @@ -779,7 +922,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, if (nbd_read(ioc, &globalflags, sizeof(globalflags), errp) < 0) { error_prepend(errp, "Failed to read server flags: "); - goto fail; + return -EINVAL; } globalflags = be16_to_cpu(globalflags); trace_nbd_receive_negotiate_server_flags(globalflags); @@ -788,136 +931,316 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, clientflags |= NBD_FLAG_C_FIXED_NEWSTYLE; } if (globalflags & NBD_FLAG_NO_ZEROES) { - zeroes = false; + if (zeroes) { + *zeroes = false; + } clientflags |= NBD_FLAG_C_NO_ZEROES; } /* client requested flags */ clientflags = cpu_to_be32(clientflags); if (nbd_write(ioc, &clientflags, sizeof(clientflags), errp) < 0) { error_prepend(errp, "Failed to send clientflags field: "); - goto fail; + return -EINVAL; } if (tlscreds) { if (fixedNewStyle) { *outioc = nbd_receive_starttls(ioc, tlscreds, hostname, errp); if (!*outioc) { - goto fail; + return -EINVAL; } ioc = *outioc; } else { error_setg(errp, "Server does not support STARTTLS"); - goto fail; + return -EINVAL; } } - if (!name) { - trace_nbd_receive_negotiate_default_name(); - name = ""; - } if (fixedNewStyle) { - int result; + int result = 0; if (structured_reply) { result = nbd_request_simple_option(ioc, NBD_OPT_STRUCTURED_REPLY, errp); if (result < 0) { - goto fail; + return -EINVAL; } - info->structured_reply = result == 1; } + return 2 + result; + } else { + return 1; + } + } else if (magic == NBD_CLIENT_MAGIC) { + if (tlscreds) { + error_setg(errp, "Server does not support STARTTLS"); + return -EINVAL; + } + return 0; + } else { + error_setg(errp, "Bad server magic received: 0x%" PRIx64, magic); + return -EINVAL; + } +} - if (info->structured_reply && base_allocation) { - result = nbd_negotiate_simple_meta_context( - ioc, name, info->x_dirty_bitmap ?: "base:allocation", - &info->meta_base_allocation_id, errp); - if (result < 0) { - goto fail; - } - info->base_allocation = result == 1; - } +/* + * nbd_negotiate_finish_oldstyle: + * Populate @info with the size and export flags from an oldstyle server, + * but does not consume 124 bytes of reserved zero padding. + * Returns 0 on success, -1 with @errp set on failure + */ +static int nbd_negotiate_finish_oldstyle(QIOChannel *ioc, NBDExportInfo *info, + Error **errp) +{ + uint32_t oldflags; + + if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) { + error_prepend(errp, "Failed to read export length: "); + return -EINVAL; + } + info->size = be64_to_cpu(info->size); + + if (nbd_read(ioc, &oldflags, sizeof(oldflags), errp) < 0) { + error_prepend(errp, "Failed to read export flags: "); + return -EINVAL; + } + oldflags = be32_to_cpu(oldflags); + if (oldflags & ~0xffff) { + error_setg(errp, "Unexpected export flags %0x" PRIx32, oldflags); + return -EINVAL; + } + info->flags = oldflags; + return 0; +} + +/* + * nbd_receive_negotiate: + * Connect to server, complete negotiation, and move into transmission phase. + * Returns: negative errno: failure talking to server + * 0: server is connected + */ +int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + const char *hostname, QIOChannel **outioc, + NBDExportInfo *info, Error **errp) +{ + int result; + bool zeroes; + bool base_allocation = info->base_allocation; + + assert(info->name); + trace_nbd_receive_negotiate_name(info->name); + + result = nbd_start_negotiate(ioc, tlscreds, hostname, outioc, + info->structured_reply, &zeroes, errp); - /* Try NBD_OPT_GO first - if it works, we are done (it - * also gives us a good message if the server requires - * TLS). If it is not available, fall back to - * NBD_OPT_LIST for nicer error messages about a missing - * export, then use NBD_OPT_EXPORT_NAME. */ - result = nbd_opt_go(ioc, name, info, errp); + info->structured_reply = false; + info->base_allocation = false; + if (tlscreds && *outioc) { + ioc = *outioc; + } + + switch (result) { + case 3: /* newstyle, with structured replies */ + info->structured_reply = true; + if (base_allocation) { + result = nbd_negotiate_simple_meta_context(ioc, info, errp); if (result < 0) { - goto fail; - } - if (result > 0) { - return 0; - } - /* Check our desired export is present in the - * server export list. Since NBD_OPT_EXPORT_NAME - * cannot return an error message, running this - * query gives us better error reporting if the - * export name is not available. - */ - if (nbd_receive_query_exports(ioc, name, errp) < 0) { - goto fail; + return -EINVAL; } + info->base_allocation = result == 1; + } + /* fall through */ + case 2: /* newstyle, try OPT_GO */ + /* Try NBD_OPT_GO first - if it works, we are done (it + * also gives us a good message if the server requires + * TLS). If it is not available, fall back to + * NBD_OPT_LIST for nicer error messages about a missing + * export, then use NBD_OPT_EXPORT_NAME. */ + result = nbd_opt_info_or_go(ioc, NBD_OPT_GO, info, errp); + if (result < 0) { + return -EINVAL; + } + if (result > 0) { + return 0; } + /* Check our desired export is present in the + * server export list. Since NBD_OPT_EXPORT_NAME + * cannot return an error message, running this + * query gives us better error reporting if the + * export name is not available. + */ + if (nbd_receive_query_exports(ioc, info->name, errp) < 0) { + return -EINVAL; + } + /* fall through */ + case 1: /* newstyle, but limited to EXPORT_NAME */ /* write the export name request */ - if (nbd_send_option_request(ioc, NBD_OPT_EXPORT_NAME, -1, name, + if (nbd_send_option_request(ioc, NBD_OPT_EXPORT_NAME, -1, info->name, errp) < 0) { - goto fail; + return -EINVAL; } /* Read the response */ if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) { error_prepend(errp, "Failed to read export length: "); - goto fail; + return -EINVAL; } info->size = be64_to_cpu(info->size); if (nbd_read(ioc, &info->flags, sizeof(info->flags), errp) < 0) { error_prepend(errp, "Failed to read export flags: "); - goto fail; + return -EINVAL; } info->flags = be16_to_cpu(info->flags); - } else if (magic == NBD_CLIENT_MAGIC) { - uint32_t oldflags; + break; + case 0: /* oldstyle, parse length and flags */ + if (*info->name) { + error_setg(errp, "Server does not support non-empty export names"); + return -EINVAL; + } + if (nbd_negotiate_finish_oldstyle(ioc, info, errp) < 0) { + return -EINVAL; + } + break; + default: + return result; + } + + trace_nbd_receive_negotiate_size_flags(info->size, info->flags); + if (zeroes && nbd_drop(ioc, 124, errp) < 0) { + error_prepend(errp, "Failed to read reserved block: "); + return -EINVAL; + } + return 0; +} + +/* Clean up result of nbd_receive_export_list */ +void nbd_free_export_list(NBDExportInfo *info, int count) +{ + int i, j; - if (name) { - error_setg(errp, "Server does not support export names"); - goto fail; + if (!info) { + return; + } + + for (i = 0; i < count; i++) { + g_free(info[i].name); + g_free(info[i].description); + for (j = 0; j < info[i].n_contexts; j++) { + g_free(info[i].contexts[j]); } - if (tlscreds) { - error_setg(errp, "Server does not support STARTTLS"); - goto fail; + g_free(info[i].contexts); + } + g_free(info); +} + +/* + * nbd_receive_export_list: + * Query details about a server's exports, then disconnect without + * going into transmission phase. Return a count of the exports listed + * in @info by the server, or -1 on error. Caller must free @info using + * nbd_free_export_list(). + */ +int nbd_receive_export_list(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + const char *hostname, NBDExportInfo **info, + Error **errp) +{ + int result; + int count = 0; + int i; + int rc; + int ret = -1; + NBDExportInfo *array = NULL; + QIOChannel *sioc = NULL; + + *info = NULL; + result = nbd_start_negotiate(ioc, tlscreds, hostname, &sioc, true, NULL, + errp); + if (tlscreds && sioc) { + ioc = sioc; + } + + switch (result) { + case 2: + case 3: + /* newstyle - use NBD_OPT_LIST to populate array, then try + * NBD_OPT_INFO on each array member. If structured replies + * are enabled, also try NBD_OPT_LIST_META_CONTEXT. */ + if (nbd_send_option_request(ioc, NBD_OPT_LIST, 0, NULL, errp) < 0) { + goto out; + } + while (1) { + char *name; + char *desc; + + rc = nbd_receive_list(ioc, &name, &desc, errp); + if (rc < 0) { + goto out; + } else if (rc == 0) { + break; + } + array = g_renew(NBDExportInfo, array, ++count); + memset(&array[count - 1], 0, sizeof(*array)); + array[count - 1].name = name; + array[count - 1].description = desc; + array[count - 1].structured_reply = result == 3; } - if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) { - error_prepend(errp, "Failed to read export length: "); - goto fail; + for (i = 0; i < count; i++) { + array[i].request_sizes = true; + rc = nbd_opt_info_or_go(ioc, NBD_OPT_INFO, &array[i], errp); + if (rc < 0) { + goto out; + } else if (rc == 0) { + /* + * Pointless to try rest of loop. If OPT_INFO doesn't work, + * it's unlikely that meta contexts work either + */ + break; + } + + if (result == 3 && + nbd_list_meta_contexts(ioc, &array[i], errp) < 0) { + goto out; + } } - info->size = be64_to_cpu(info->size); - if (nbd_read(ioc, &oldflags, sizeof(oldflags), errp) < 0) { - error_prepend(errp, "Failed to read export flags: "); - goto fail; + /* Send NBD_OPT_ABORT as a courtesy before hanging up */ + nbd_send_opt_abort(ioc); + break; + case 1: /* newstyle, but limited to EXPORT_NAME */ + error_setg(errp, "Server does not support export lists"); + /* We can't even send NBD_OPT_ABORT, so merely hang up */ + goto out; + case 0: /* oldstyle, parse length and flags */ + array = g_new0(NBDExportInfo, 1); + array->name = g_strdup(""); + count = 1; + + if (nbd_negotiate_finish_oldstyle(ioc, array, errp) < 0) { + goto out; } - oldflags = be32_to_cpu(oldflags); - if (oldflags & ~0xffff) { - error_setg(errp, "Unexpected export flags %0x" PRIx32, oldflags); - goto fail; + + /* Send NBD_CMD_DISC as a courtesy to the server, but ignore all + * errors now that we have the information we wanted. */ + if (nbd_drop(ioc, 124, NULL) == 0) { + NBDRequest request = { .type = NBD_CMD_DISC }; + + nbd_send_request(ioc, &request); } - info->flags = oldflags; - } else { - error_setg(errp, "Bad server magic received: 0x%" PRIx64, magic); - goto fail; + break; + default: + goto out; } - trace_nbd_receive_negotiate_size_flags(info->size, info->flags); - if (zeroes && nbd_drop(ioc, 124, errp) < 0) { - error_prepend(errp, "Failed to read reserved block: "); - goto fail; - } - rc = 0; + *info = array; + array = NULL; + ret = count; -fail: - return rc; + out: + qio_channel_shutdown(ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); + qio_channel_close(ioc, NULL); + object_unref(OBJECT(sioc)); + nbd_free_export_list(array, count); + return ret; } #ifdef __linux__ diff --git a/nbd/server.c b/nbd/server.c index 6b136019f8..cb0d5634fa 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -77,8 +77,8 @@ struct NBDExport { BlockBackend *blk; char *name; char *description; - off_t dev_offset; - off_t size; + uint64_t dev_offset; + uint64_t size; uint16_t nbdflags; QTAILQ_HEAD(, NBDClient) clients; QTAILQ_ENTRY(NBDExport) next; @@ -1455,8 +1455,8 @@ static void nbd_eject_notifier(Notifier *n, void *data) nbd_export_close(exp); } -NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size, - const char *name, const char *description, +NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, + uint64_t size, const char *name, const char *desc, const char *bitmap, uint16_t nbdflags, void (*close)(NBDExport *), bool writethrough, BlockBackend *on_eject_blk, Error **errp) @@ -1495,17 +1495,13 @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size, exp->refcount = 1; QTAILQ_INIT(&exp->clients); exp->blk = blk; + assert(dev_offset <= INT64_MAX); exp->dev_offset = dev_offset; exp->name = g_strdup(name); - exp->description = g_strdup(description); + exp->description = g_strdup(desc); exp->nbdflags = nbdflags; - exp->size = size < 0 ? blk_getlength(blk) : size; - if (exp->size < 0) { - error_setg_errno(errp, -exp->size, - "Failed to determine the NBD export's length"); - goto fail; - } - exp->size -= exp->size % BDRV_SECTOR_SIZE; + assert(size <= INT64_MAX - dev_offset); + exp->size = QEMU_ALIGN_DOWN(size, BDRV_SECTOR_SIZE); if (bitmap) { BdrvDirtyBitmap *bm = NULL; @@ -2134,10 +2130,10 @@ static int nbd_co_receive_request(NBDRequestData *req, NBDRequest *request, return -EROFS; } if (request->from > client->exp->size || - request->from + request->len > client->exp->size) { + request->len > client->exp->size - request->from) { error_setg(errp, "operation past EOF; From: %" PRIu64 ", Len: %" PRIu32 ", Size: %" PRIu64, request->from, request->len, - (uint64_t)client->exp->size); + client->exp->size); return (request->type == NBD_CMD_WRITE || request->type == NBD_CMD_WRITE_ZEROES) ? -ENOSPC : -EINVAL; } diff --git a/nbd/trace-events b/nbd/trace-events index 5492042acb..7f10ebd4e0 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -3,20 +3,21 @@ nbd_send_option_request(uint32_t opt, const char *name, uint32_t len) "Sending o nbd_receive_option_reply(uint32_t option, const char *optname, uint32_t type, const char *typename, uint32_t length) "Received option reply %" PRIu32" (%s), type %" PRIu32" (%s), len %" PRIu32 nbd_server_error_msg(uint32_t err, const char *type, const char *msg) "server reported error 0x%" PRIx32 " (%s) with additional message: %s" nbd_reply_err_unsup(uint32_t option, const char *name) "server doesn't understand request %" PRIu32 " (%s), attempting fallback" -nbd_opt_go_start(const char *name) "Attempting NBD_OPT_GO for export '%s'" -nbd_opt_go_success(void) "Export is good to go" -nbd_opt_go_info_unknown(int info, const char *name) "Ignoring unknown info %d (%s)" -nbd_opt_go_info_block_size(uint32_t minimum, uint32_t preferred, uint32_t maximum) "Block sizes are 0x%" PRIx32 ", 0x%" PRIx32 ", 0x%" PRIx32 +nbd_receive_list(const char *name, const char *desc) "export list includes '%s', description '%s'" +nbd_opt_info_go_start(const char *opt, const char *name) "Attempting %s for export '%s'" +nbd_opt_info_go_success(const char *opt) "Export is ready after %s request" +nbd_opt_info_unknown(int info, const char *name) "Ignoring unknown info %d (%s)" +nbd_opt_info_block_size(uint32_t minimum, uint32_t preferred, uint32_t maximum) "Block sizes are 0x%" PRIx32 ", 0x%" PRIx32 ", 0x%" PRIx32 nbd_receive_query_exports_start(const char *wantname) "Querying export list for '%s'" nbd_receive_query_exports_success(const char *wantname) "Found desired export name '%s'" nbd_receive_starttls_new_client(void) "Setting up TLS" nbd_receive_starttls_tls_handshake(void) "Starting TLS handshake" -nbd_opt_meta_request(const char *context, const char *export) "Requesting to set meta context %s for export %s" -nbd_opt_meta_reply(const char *context, uint32_t id) "Received mapping of context %s to id %" PRIu32 -nbd_receive_negotiate(void *tlscreds, const char *hostname) "Receiving negotiation tlscreds=%p hostname=%s" +nbd_opt_meta_request(const char *optname, const char *context, const char *export) "Requesting %s %s for export %s" +nbd_opt_meta_reply(const char *optname, const char *context, uint32_t id) "Received %s mapping of %s to id %" PRIu32 +nbd_start_negotiate(void *tlscreds, const char *hostname) "Receiving negotiation tlscreds=%p hostname=%s" nbd_receive_negotiate_magic(uint64_t magic) "Magic is 0x%" PRIx64 nbd_receive_negotiate_server_flags(uint32_t globalflags) "Global flags are 0x%" PRIx32 -nbd_receive_negotiate_default_name(void) "Using default NBD export name \"\"" +nbd_receive_negotiate_name(const char *name) "Requesting NBD export name '%s'" nbd_receive_negotiate_size_flags(uint64_t size, uint16_t flags) "Size is %" PRIu64 ", export flags 0x%" PRIx16 nbd_init_set_socket(void) "Setting NBD socket" nbd_init_set_block_size(unsigned long block_size) "Setting block size to %lu" diff --git a/pc-bios/efi-e1000.rom b/pc-bios/efi-e1000.rom Binary files differindex 4da9de33da..6f088d41dd 100644 --- a/pc-bios/efi-e1000.rom +++ b/pc-bios/efi-e1000.rom diff --git a/pc-bios/efi-e1000e.rom b/pc-bios/efi-e1000e.rom Binary files differindex c2474a8fab..f536bdbd45 100644 --- a/pc-bios/efi-e1000e.rom +++ b/pc-bios/efi-e1000e.rom diff --git a/pc-bios/efi-eepro100.rom b/pc-bios/efi-eepro100.rom Binary files differindex 7950faf7cd..64d8891485 100644 --- a/pc-bios/efi-eepro100.rom +++ b/pc-bios/efi-eepro100.rom diff --git a/pc-bios/efi-ne2k_pci.rom b/pc-bios/efi-ne2k_pci.rom Binary files differindex 30edb1392a..02ad0cb505 100644 --- a/pc-bios/efi-ne2k_pci.rom +++ b/pc-bios/efi-ne2k_pci.rom diff --git a/pc-bios/efi-pcnet.rom b/pc-bios/efi-pcnet.rom Binary files differindex 23057c5724..88d25fa625 100644 --- a/pc-bios/efi-pcnet.rom +++ b/pc-bios/efi-pcnet.rom diff --git a/pc-bios/efi-rtl8139.rom b/pc-bios/efi-rtl8139.rom Binary files differindex beb9301839..53f125e3bb 100644 --- a/pc-bios/efi-rtl8139.rom +++ b/pc-bios/efi-rtl8139.rom diff --git a/pc-bios/efi-virtio.rom b/pc-bios/efi-virtio.rom Binary files differindex f4de5957ec..a87321e928 100644 --- a/pc-bios/efi-virtio.rom +++ b/pc-bios/efi-virtio.rom diff --git a/pc-bios/efi-vmxnet3.rom b/pc-bios/efi-vmxnet3.rom Binary files differindex 7501477ea6..d017cafe22 100644 --- a/pc-bios/efi-vmxnet3.rom +++ b/pc-bios/efi-vmxnet3.rom diff --git a/qemu-nbd.c b/qemu-nbd.c index 51b55f2e06..1f7b2a03f5 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -76,7 +76,8 @@ static void usage(const char *name) { (printf) ( "Usage: %s [OPTIONS] FILE\n" -"QEMU Disk Network Block Device Server\n" +" or: %s -L [OPTIONS]\n" +"QEMU Disk Network Block Device Utility\n" "\n" " -h, --help display this help and exit\n" " -V, --version output version information and exit\n" @@ -98,6 +99,7 @@ static void usage(const char *name) " -B, --bitmap=NAME expose a persistent dirty bitmap\n" "\n" "General purpose options:\n" +" -L, --list list exports available from another NBD server\n" " --object type,id=ID,... define an object such as 'secret' for providing\n" " passwords and/or encryption keys\n" " --tls-creds=ID use id of an earlier --object to provide TLS\n" @@ -131,7 +133,7 @@ static void usage(const char *name) " --image-opts treat FILE as a full set of image options\n" "\n" QEMU_HELP_BOTTOM "\n" - , name, NBD_DEFAULT_PORT, "DEVICE"); + , name, name, NBD_DEFAULT_PORT, "DEVICE"); } static void version(const char *name) @@ -176,7 +178,7 @@ static void read_partition(uint8_t *p, struct partition_record *r) } static int find_partition(BlockBackend *blk, int partition, - off_t *offset, off_t *size) + uint64_t *offset, uint64_t *size) { struct partition_record mbr[4]; uint8_t data[MBR_SIZE]; @@ -243,6 +245,91 @@ static void termsig_handler(int signum) } +static int qemu_nbd_client_list(SocketAddress *saddr, QCryptoTLSCreds *tls, + const char *hostname) +{ + int ret = EXIT_FAILURE; + int rc; + Error *err = NULL; + QIOChannelSocket *sioc; + NBDExportInfo *list; + int i, j; + + sioc = qio_channel_socket_new(); + if (qio_channel_socket_connect_sync(sioc, saddr, &err) < 0) { + error_report_err(err); + return EXIT_FAILURE; + } + rc = nbd_receive_export_list(QIO_CHANNEL(sioc), tls, hostname, &list, + &err); + if (rc < 0) { + if (err) { + error_report_err(err); + } + goto out; + } + printf("exports available: %d\n", rc); + for (i = 0; i < rc; i++) { + printf(" export: '%s'\n", list[i].name); + if (list[i].description && *list[i].description) { + printf(" description: %s\n", list[i].description); + } + if (list[i].flags & NBD_FLAG_HAS_FLAGS) { + printf(" size: %" PRIu64 "\n", list[i].size); + printf(" flags: 0x%x (", list[i].flags); + if (list[i].flags & NBD_FLAG_READ_ONLY) { + printf(" readonly"); + } + if (list[i].flags & NBD_FLAG_SEND_FLUSH) { + printf(" flush"); + } + if (list[i].flags & NBD_FLAG_SEND_FUA) { + printf(" fua"); + } + if (list[i].flags & NBD_FLAG_ROTATIONAL) { + printf(" rotational"); + } + if (list[i].flags & NBD_FLAG_SEND_TRIM) { + printf(" trim"); + } + if (list[i].flags & NBD_FLAG_SEND_WRITE_ZEROES) { + printf(" zeroes"); + } + if (list[i].flags & NBD_FLAG_SEND_DF) { + printf(" df"); + } + if (list[i].flags & NBD_FLAG_CAN_MULTI_CONN) { + printf(" multi"); + } + if (list[i].flags & NBD_FLAG_SEND_RESIZE) { + printf(" resize"); + } + if (list[i].flags & NBD_FLAG_SEND_CACHE) { + printf(" cache"); + } + printf(" )\n"); + } + if (list[i].min_block) { + printf(" min block: %u\n", list[i].min_block); + printf(" opt block: %u\n", list[i].opt_block); + printf(" max block: %u\n", list[i].max_block); + } + if (list[i].n_contexts) { + printf(" available meta contexts: %d\n", list[i].n_contexts); + for (j = 0; j < list[i].n_contexts; j++) { + printf(" %s\n", list[i].contexts[j]); + } + } + } + nbd_free_export_list(list, rc); + + ret = EXIT_SUCCESS; + out: + object_unref(OBJECT(sioc)); + return ret; +} + + #if HAVE_NBD_DEVICE static void *show_parts(void *arg) { @@ -264,7 +351,7 @@ static void *show_parts(void *arg) static void *nbd_client_thread(void *arg) { char *device = arg; - NBDExportInfo info = { .request_sizes = false, }; + NBDExportInfo info = { .request_sizes = false, .name = g_strdup("") }; QIOChannelSocket *sioc; int fd; int ret; @@ -279,7 +366,7 @@ static void *nbd_client_thread(void *arg) goto out; } - ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), NULL, + ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), NULL, NULL, NULL, &info, &local_error); if (ret < 0) { if (local_error) { @@ -318,6 +405,7 @@ static void *nbd_client_thread(void *arg) } close(fd); object_unref(OBJECT(sioc)); + g_free(info.name); kill(getpid(), SIGTERM); return (void *) EXIT_SUCCESS; @@ -326,6 +414,7 @@ out_fd: out_socket: object_unref(OBJECT(sioc)); out: + g_free(info.name); kill(getpid(), SIGTERM); return (void *) EXIT_FAILURE; } @@ -423,7 +512,8 @@ static QemuOptsList qemu_object_opts = { -static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp) +static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, bool list, + Error **errp) { Object *obj; QCryptoTLSCreds *creds; @@ -443,10 +533,18 @@ static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp) return NULL; } - if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { - error_setg(errp, - "Expecting TLS credentials with a server endpoint"); - return NULL; + if (list) { + if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) { + error_setg(errp, + "Expecting TLS credentials with a client endpoint"); + return NULL; + } + } else { + if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { + error_setg(errp, + "Expecting TLS credentials with a server endpoint"); + return NULL; + } } object_ref(obj); return creds; @@ -469,7 +567,8 @@ static void setup_address_and_port(const char **address, const char **port) static const char *socket_activation_validate_opts(const char *device, const char *sockpath, const char *address, - const char *port) + const char *port, + bool list) { if (device != NULL) { return "NBD device can't be set when using socket activation"; @@ -487,6 +586,10 @@ static const char *socket_activation_validate_opts(const char *device, return "TCP port number can't be set when using socket activation"; } + if (list) { + return "List mode is incompatible with socket activation"; + } + return NULL; } @@ -500,17 +603,17 @@ int main(int argc, char **argv) { BlockBackend *blk; BlockDriverState *bs; - off_t dev_offset = 0; + uint64_t dev_offset = 0; uint16_t nbdflags = 0; bool disconnect = false; const char *bindto = NULL; const char *port = NULL; char *sockpath = NULL; char *device = NULL; - off_t fd_size; + int64_t fd_size; QemuOpts *sn_opts = NULL; const char *sn_id_or_name = NULL; - const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:D:B:"; + const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:D:B:L"; struct option lopt[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, @@ -523,6 +626,7 @@ int main(int argc, char **argv) { "bitmap", required_argument, NULL, 'B' }, { "connect", required_argument, NULL, 'c' }, { "disconnect", no_argument, NULL, 'd' }, + { "list", no_argument, NULL, 'L' }, { "snapshot", no_argument, NULL, 's' }, { "load-snapshot", required_argument, NULL, 'l' }, { "nocache", no_argument, NULL, 'n' }, @@ -546,9 +650,8 @@ int main(int argc, char **argv) }; int ch; int opt_ind = 0; - char *end; int flags = BDRV_O_RDWR; - int partition = -1; + int partition = 0; int ret = 0; bool seen_cache = false; bool seen_discard = false; @@ -558,7 +661,7 @@ int main(int argc, char **argv) Error *local_err = NULL; BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF; QDict *options = NULL; - const char *export_name = ""; /* Default export name */ + const char *export_name = NULL; /* defaults to "" later for server mode */ const char *export_description = NULL; const char *bitmap = NULL; const char *tlscredsid = NULL; @@ -566,6 +669,7 @@ int main(int argc, char **argv) bool writethrough = true; char *trace_file = NULL; bool fork_process = false; + bool list = false; int old_stderr = -1; unsigned socket_activation; @@ -660,13 +764,8 @@ int main(int argc, char **argv) port = optarg; break; case 'o': - dev_offset = strtoll (optarg, &end, 0); - if (*end) { - error_report("Invalid offset `%s'", optarg); - exit(EXIT_FAILURE); - } - if (dev_offset < 0) { - error_report("Offset must be positive `%s'", optarg); + if (qemu_strtou64(optarg, NULL, 0, &dev_offset) < 0) { + error_report("Invalid offset '%s'", optarg); exit(EXIT_FAILURE); } break; @@ -688,13 +787,9 @@ int main(int argc, char **argv) flags &= ~BDRV_O_RDWR; break; case 'P': - partition = strtol(optarg, &end, 0); - if (*end) { - error_report("Invalid partition `%s'", optarg); - exit(EXIT_FAILURE); - } - if (partition < 1 || partition > 8) { - error_report("Invalid partition %d", partition); + if (qemu_strtoi(optarg, NULL, 0, &partition) < 0 || + partition < 1 || partition > 8) { + error_report("Invalid partition '%s'", optarg); exit(EXIT_FAILURE); } break; @@ -715,15 +810,11 @@ int main(int argc, char **argv) device = optarg; break; case 'e': - shared = strtol(optarg, &end, 0); - if (*end) { + if (qemu_strtoi(optarg, NULL, 0, &shared) < 0 || + shared < 1) { error_report("Invalid shared device number '%s'", optarg); exit(EXIT_FAILURE); } - if (shared < 1) { - error_report("Shared device number must be greater than 0"); - exit(EXIT_FAILURE); - } break; case 'f': fmt = optarg; @@ -772,13 +863,33 @@ int main(int argc, char **argv) case QEMU_NBD_OPT_FORK: fork_process = true; break; + case 'L': + list = true; + break; } } - if ((argc - optind) != 1) { + if (list) { + if (argc != optind) { + error_report("List mode is incompatible with a file name"); + exit(EXIT_FAILURE); + } + if (export_name || export_description || dev_offset || partition || + device || disconnect || fmt || sn_id_or_name || bitmap || + seen_aio || seen_discard || seen_cache) { + error_report("List mode is incompatible with per-device settings"); + exit(EXIT_FAILURE); + } + if (fork_process) { + error_report("List mode is incompatible with forking"); + exit(EXIT_FAILURE); + } + } else if ((argc - optind) != 1) { error_report("Invalid number of arguments"); error_printf("Try `%s --help' for more information.\n", argv[0]); exit(EXIT_FAILURE); + } else if (!export_name) { + export_name = ""; } qemu_opts_foreach(&qemu_object_opts, @@ -797,7 +908,8 @@ int main(int argc, char **argv) } else { /* Using socket activation - check user didn't use -p etc. */ const char *err_msg = socket_activation_validate_opts(device, sockpath, - bindto, port); + bindto, port, + list); if (err_msg != NULL) { error_report("%s", err_msg); exit(EXIT_FAILURE); @@ -820,7 +932,7 @@ int main(int argc, char **argv) error_report("TLS is not supported with a host device"); exit(EXIT_FAILURE); } - tlscreds = nbd_get_tls_creds(tlscredsid, &local_err); + tlscreds = nbd_get_tls_creds(tlscredsid, list, &local_err); if (local_err) { error_report("Failed to get TLS creds %s", error_get_pretty(local_err)); @@ -828,6 +940,11 @@ int main(int argc, char **argv) } } + if (list) { + saddr = nbd_build_socket_address(sockpath, bindto, port); + return qemu_nbd_client_list(saddr, tlscreds, bindto); + } + #if !HAVE_NBD_DEVICE if (disconnect || device) { error_report("Kernel /dev/nbdN support not available"); @@ -1005,20 +1122,37 @@ int main(int argc, char **argv) } if (dev_offset >= fd_size) { - error_report("Offset (%lld) has to be smaller than the image size " - "(%lld)", - (long long int)dev_offset, (long long int)fd_size); + error_report("Offset (%" PRIu64 ") has to be smaller than the image " + "size (%" PRId64 ")", dev_offset, fd_size); exit(EXIT_FAILURE); } fd_size -= dev_offset; - if (partition != -1) { - ret = find_partition(blk, partition, &dev_offset, &fd_size); + if (partition) { + uint64_t limit; + + if (dev_offset) { + error_report("Cannot request partition and offset together"); + exit(EXIT_FAILURE); + } + ret = find_partition(blk, partition, &dev_offset, &limit); if (ret < 0) { error_report("Could not find partition %d: %s", partition, strerror(-ret)); exit(EXIT_FAILURE); } + /* + * MBR partition limits are (32-bit << 9); this assert lets + * the compiler know that we can't overflow 64 bits. + */ + assert(dev_offset + limit >= dev_offset); + if (dev_offset + limit > fd_size) { + error_report("Discovered partition %d at offset %" PRIu64 + " size %" PRIu64 ", but size exceeds file length %" + PRId64, partition, dev_offset, limit, fd_size); + exit(EXIT_FAILURE); + } + fd_size = limit; } export = nbd_export_new(bs, dev_offset, fd_size, export_name, diff --git a/qemu-nbd.texi b/qemu-nbd.texi index 96b1546006..386bece468 100644 --- a/qemu-nbd.texi +++ b/qemu-nbd.texi @@ -2,6 +2,8 @@ @c man begin SYNOPSIS @command{qemu-nbd} [OPTION]... @var{filename} +@command{qemu-nbd} @option{-L} [OPTION]... + @command{qemu-nbd} @option{-d} @var{dev} @c man end @end example @@ -10,11 +12,19 @@ Export a QEMU disk image using the NBD protocol. +Other uses: +@itemize +@item +Bind a /dev/nbdX block device to a QEMU server (on Linux). +@item +As a client to query exports of a remote NBD server. +@end itemize + @c man end @c man begin OPTIONS @var{filename} is a disk image filename, or a set of block -driver options if @var{--image-opts} is specified. +driver options if @option{--image-opts} is specified. @var{dev} is an NBD device. @@ -25,26 +35,29 @@ See the @code{qemu(1)} manual page for full details of the properties supported. The common object types that it makes sense to define are the @code{secret} object, which is used to supply passwords and/or encryption keys, and the @code{tls-creds} object, which is used to supply TLS -credentials for the qemu-nbd server. +credentials for the qemu-nbd server or client. @item -p, --port=@var{port} -The TCP port to listen on (default @samp{10809}) +The TCP port to listen on as a server, or connect to as a client +(default @samp{10809}). @item -o, --offset=@var{offset} -The offset into the image +The offset into the image. @item -b, --bind=@var{iface} -The interface to bind to (default @samp{0.0.0.0}) +The interface to bind to as a server, or connect to as a client +(default @samp{0.0.0.0}). @item -k, --socket=@var{path} -Use a unix socket with path @var{path} +Use a unix socket with path @var{path}. @item --image-opts Treat @var{filename} as a set of image options, instead of a plain filename. If this flag is specified, the @var{-f} flag should not be used, instead the '@code{format=}' option should be set. @item -f, --format=@var{fmt} Force the use of the block driver for format @var{fmt} instead of -auto-detecting +auto-detecting. @item -r, --read-only -Export the disk as read-only +Export the disk as read-only. @item -P, --partition=@var{num} -Only expose partition @var{num} +Only expose MBR partition @var{num}. Understands physical partitions +1-4 and logical partitions 5-8. @item -B, --bitmap=@var{name} If @var{filename} has a qcow2 persistent bitmap @var{name}, expose that bitmap via the ``qemu:dirty-bitmap:@var{name}'' context @@ -52,7 +65,7 @@ accessible through NBD_OPT_SET_META_CONTEXT. @item -s, --snapshot Use @var{filename} as an external snapshot, create a temporary file with backing_file=@var{filename}, redirect the write to -the temporary one +the temporary one. @item -l, --load-snapshot=@var{snapshot_param} Load an internal snapshot inside @var{filename} and export it as an read-only device, @var{snapshot_param} format is @@ -76,31 +89,38 @@ driver-specific optimized zero write commands. @var{detect-zeroes} is one of converts a zero write to an unmap operation and can only be used if @var{discard} is set to @samp{unmap}. The default is @samp{off}. @item -c, --connect=@var{dev} -Connect @var{filename} to NBD device @var{dev} +Connect @var{filename} to NBD device @var{dev} (Linux only). @item -d, --disconnect -Disconnect the device @var{dev} +Disconnect the device @var{dev} (Linux only). @item -e, --shared=@var{num} -Allow up to @var{num} clients to share the device (default @samp{1}) +Allow up to @var{num} clients to share the device (default +@samp{1}). Safe for readers, but for now, consistency is not +guaranteed between multiple writers. @item -t, --persistent -Don't exit on the last connection +Don't exit on the last connection. @item -x, --export-name=@var{name} -Set the NBD volume export name. This switches the server to use -the new style NBD protocol negotiation +Set the NBD volume export name (default of a zero-length string). @item -D, --description=@var{description} Set the NBD volume export description, as a human-readable -string. Requires the use of @option{-x} +string. +@item -L, --list +Connect as a client and list all details about the exports exposed by +a remote NBD server. This enables list mode, and is incompatible +with options that change behavior related to a specific export (such as +@option{--export-name}, @option{--offset}, ...). @item --tls-creds=ID Enable mandatory TLS encryption for the server by setting the ID of the TLS credentials object previously created with the --object -option. +option; or provide the credentials needed for connecting as a client +in list mode. @item --fork Fork off the server process and exit the parent once the server is running. @item -v, --verbose -Display extra debugging information +Display extra debugging information. @item -h, --help -Display this help and exit +Display this help and exit. @item -V, --version -Display version information and exit +Display version information and exit. @item -T, --trace [[enable=]@var{pattern}][,events=@var{file}][,file=@var{file}] @findex --trace @include qemu-option-trace.texi @@ -108,6 +128,63 @@ Display version information and exit @c man end +@c man begin EXAMPLES +Start a server listening on port 10809 that exposes only the +guest-visible contents of a qcow2 file, with no TLS encryption, and +with the default export name (an empty string). The command is +one-shot, and will block until the first successful client +disconnects: + +@example +qemu-nbd -f qcow2 file.qcow2 +@end example + +Start a long-running server listening with encryption on port 10810, +and require clients to have a correct X.509 certificate to connect to +a 1 megabyte subset of a raw file, using the export name 'subset': + +@example +qemu-nbd \ + --object tls-creds-x509,id=tls0,endpoint=server,dir=/path/to/qemutls \ + --tls-creds tls0 -t -x subset -p 10810 \ + --image-opts driver=raw,offset=1M,size=1M,file.driver=file,file.filename=file.raw +@end example + +Serve a read-only copy of just the first MBR partition of a guest +image over a Unix socket with as many as 5 simultaneous readers, with +a persistent process forked as a daemon: + +@example +qemu-nbd --fork --persistent --shared=5 --socket=/path/to/sock \ + --partition=1 --read-only --format=qcow2 file.qcow2 +@end example + +Expose the guest-visible contents of a qcow2 file via a block device +/dev/nbd0 (and possibly creating /dev/nbd0p1 and friends for +partitions found within), then disconnect the device when done. +Access to bind qemu-nbd to an /dev/nbd device generally requires root +privileges, and may also require the execution of @code{modprobe nbd} +to enable the kernel NBD client module. @emph{CAUTION}: Do not use +this method to mount filesystems from an untrusted guest image - a +malicious guest may have prepared the image to attempt to trigger +kernel bugs in partition probing or file system mounting. + +@example +qemu-nbd -c /dev/nbd0 -f qcow2 file.qcow2 +qemu-nbd -d /dev/nbd0 +@end example + +Query a remote server to see details about what export(s) it is +serving on port 10809, and authenticating via PSK: + +@example +qemu-nbd \ + --object tls-creds-psk,id=tls0,dir=/tmp/keys,username=eblake,endpoint=client \ + --tls-creds tls0 -L -b remote.example.com +@end example + +@c man end + @ignore @setfilename qemu-nbd diff --git a/qemu-seccomp.c b/qemu-seccomp.c index 5c73e6ad05..36d5829831 100644 --- a/qemu-seccomp.c +++ b/qemu-seccomp.c @@ -41,7 +41,8 @@ struct QemuSeccompSyscall { }; const struct scmp_arg_cmp sched_setscheduler_arg[] = { - SCMP_A1(SCMP_CMP_NE, SCHED_IDLE) + /* was SCMP_A1(SCMP_CMP_NE, SCHED_IDLE), but expanded due to GCC 4.x bug */ + { .arg = 1, .op = SCMP_CMP_NE, .datum_a = SCHED_IDLE } }; static const struct QemuSeccompSyscall blacklist[] = { diff --git a/roms/ipxe b/roms/ipxe -Subproject 0600d3ae94f93efd10fc6b3c7420a9557a3a167 +Subproject de4565cbe76ea9f7913a01f331be3ee901bb6e1 diff --git a/scripts/texi2pod.pl b/scripts/texi2pod.pl index 39ce584a32..839b7917cf 100755 --- a/scripts/texi2pod.pl +++ b/scripts/texi2pod.pl @@ -398,7 +398,7 @@ $sects{NAME} = "$fn \- $tl\n"; $sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES}; for $sect (qw(NAME SYNOPSIS DESCRIPTION OPTIONS ENVIRONMENT FILES - BUGS NOTES FOOTNOTES SEEALSO AUTHOR COPYRIGHT)) { + BUGS NOTES FOOTNOTES EXAMPLES SEEALSO AUTHOR COPYRIGHT)) { if(exists $sects{$sect}) { $head = $sect; $head =~ s/SEEALSO/SEE ALSO/; diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 486abaf99b..a62ff60414 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1177,8 +1177,9 @@ do { \ typedef struct PPCVirtualHypervisor PPCVirtualHypervisor; typedef struct PPCVirtualHypervisorClass PPCVirtualHypervisorClass; -typedef struct XiveTCTX XiveTCTX; -typedef struct ICPState ICPState; + +struct XiveTCTX; +struct ICPState; /** * PowerPCCPU: @@ -1197,8 +1198,8 @@ struct PowerPCCPU { int vcpu_id; uint32_t compat_pvr; PPCVirtualHypervisor *vhyp; - ICPState *icp; - XiveTCTX *tctx; + struct ICPState *icp; + struct XiveTCTX *tctx; void *machine_data; int32_t node_id; /* NUMA node this CPU belongs to */ PPCHash64Options *hash64_opts; diff --git a/tests/Makefile.include b/tests/Makefile.include index 5e6b2c7058..4eea38ae99 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -167,13 +167,13 @@ check-qtest-pci-$(CONFIG_NE2000_PCI) += tests/ne2000-test$(EXESUF) check-qtest-pci-$(CONFIG_NVME_PCI) += tests/nvme-test$(EXESUF) check-qtest-pci-$(CONFIG_AC97) += tests/ac97-test$(EXESUF) check-qtest-pci-$(CONFIG_ES1370) += tests/es1370-test$(EXESUF) -check-qtest-pci-y += $(check-qtest-virtio-y) +check-qtest-pci-$(CONFIG_VIRTIO) += $(check-qtest-virtio-y) check-qtest-pci-$(CONFIG_IPACK) += tests/tpci200-test$(EXESUF) check-qtest-pci-$(CONFIG_IPACK) += $(check-qtest-ipack-y) -check-qtest-pci-y += tests/display-vga-test$(EXESUF) +check-qtest-pci-$(CONFIG_VGA) += tests/display-vga-test$(EXESUF) check-qtest-pci-$(CONFIG_HDA) += tests/intel-hda-test$(EXESUF) check-qtest-pci-$(CONFIG_IVSHMEM_DEVICE) += tests/ivshmem-test$(EXESUF) -check-qtest-pci-y += tests/megasas-test$(EXESUF) +check-qtest-pci-$(CONFIG_MEGASAS_SCSI_PCI) += tests/megasas-test$(EXESUF) check-qtest-i386-$(CONFIG_ISA_TESTDEV) = tests/endianness-test$(EXESUF) check-qtest-i386-y += tests/fdc-test$(EXESUF) @@ -185,9 +185,9 @@ check-qtest-i386-y += tests/bios-tables-test$(EXESUF) check-qtest-i386-$(CONFIG_SGA) += tests/boot-serial-test$(EXESUF) check-qtest-i386-$(CONFIG_SLIRP) += tests/pxe-test$(EXESUF) check-qtest-i386-y += tests/rtc-test$(EXESUF) -check-qtest-i386-y += tests/ipmi-kcs-test$(EXESUF) +check-qtest-i386-$(CONFIG_ISA_IPMI_KCS) += tests/ipmi-kcs-test$(EXESUF) # Disabled temporarily as it fails intermittently especially under NetBSD VM -# check-qtest-i386-y += tests/ipmi-bt-test$(EXESUF) +# check-qtest-i386-$(CONFIG_ISA_IPMI_BT) += tests/ipmi-bt-test$(EXESUF) check-qtest-i386-y += tests/i440fx-test$(EXESUF) check-qtest-i386-y += tests/fw_cfg-test$(EXESUF) check-qtest-i386-y += tests/drive_del-test$(EXESUF) @@ -250,22 +250,22 @@ check-qtest-ppc-y += tests/boot-order-test$(EXESUF) check-qtest-ppc-y += tests/prom-env-test$(EXESUF) check-qtest-ppc-y += tests/drive_del-test$(EXESUF) check-qtest-ppc-y += tests/boot-serial-test$(EXESUF) -check-qtest-ppc-y += tests/m48t59-test$(EXESUF) +check-qtest-ppc-$(CONFIG_M48T59) += tests/m48t59-test$(EXESUF) check-qtest-ppc64-y += $(check-qtest-ppc-y) -check-qtest-ppc64-y += tests/spapr-phb-test$(EXESUF) -check-qtest-ppc64-y += tests/pnv-xscom-test$(EXESUF) +check-qtest-ppc64-$(CONFIG_PSERIES) += tests/spapr-phb-test$(EXESUF) +check-qtest-ppc64-$(CONFIG_POWERNV) += tests/pnv-xscom-test$(EXESUF) check-qtest-ppc64-y += tests/migration-test$(EXESUF) -check-qtest-ppc64-y += tests/rtas-test$(EXESUF) +check-qtest-ppc64-$(CONFIG_PSERIES) += tests/rtas-test$(EXESUF) check-qtest-ppc64-$(CONFIG_SLIRP) += tests/pxe-test$(EXESUF) check-qtest-ppc64-$(CONFIG_USB_OHCI) += tests/usb-hcd-ohci-test$(EXESUF) check-qtest-ppc64-$(CONFIG_USB_UHCI) += tests/usb-hcd-uhci-test$(EXESUF) check-qtest-ppc64-$(CONFIG_USB_XHCI_NEC) += tests/usb-hcd-xhci-test$(EXESUF) -check-qtest-ppc64-y += $(check-qtest-virtio-y) +check-qtest-ppc64-$(CONFIG_VIRTIO) += $(check-qtest-virtio-y) check-qtest-ppc64-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF) check-qtest-ppc64-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF) check-qtest-ppc64-$(CONFIG_RTL8139_PCI) += tests/test-filter-redirector$(EXESUF) -check-qtest-ppc64-y += tests/display-vga-test$(EXESUF) +check-qtest-ppc64-$(CONFIG_VGA) += tests/display-vga-test$(EXESUF) check-qtest-ppc64-y += tests/numa-test$(EXESUF) check-qtest-ppc64-$(CONFIG_IVSHMEM_DEVICE) += tests/ivshmem-test$(EXESUF) check-qtest-ppc64-y += tests/cpu-plug-test$(EXESUF) @@ -748,7 +748,6 @@ tests/qom-test$(EXESUF): tests/qom-test.o tests/test-hmp$(EXESUF): tests/test-hmp.o tests/machine-none-test$(EXESUF): tests/machine-none-test.o tests/drive_del-test$(EXESUF): tests/drive_del-test.o $(libqos-virtio-obj-y) -tests/qdev-monitor-test$(EXESUF): tests/qdev-monitor-test.o $(libqos-pc-obj-y) tests/nvme-test$(EXESUF): tests/nvme-test.o $(libqos-pc-obj-y) tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o diff --git a/tests/boot-order-test.c b/tests/boot-order-test.c index c60ebcf9d9..a725bce729 100644 --- a/tests/boot-order-test.c +++ b/tests/boot-order-test.c @@ -17,7 +17,7 @@ #include "standard-headers/linux/qemu_fw_cfg.h" /* TODO actually test the results and get rid of this */ -#define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__)) +#define qmp_discard_response(qs, ...) qobject_unref(qtest_qmp(qs, __VA_ARGS__)) typedef struct { const char *args; @@ -27,31 +27,30 @@ typedef struct { static void test_a_boot_order(const char *machine, const char *test_args, - uint64_t (*read_boot_order)(void), + uint64_t (*read_boot_order)(QTestState *), uint64_t expected_boot, uint64_t expected_reboot) { uint64_t actual; + QTestState *qts; - global_qtest = qtest_initf("-nodefaults%s%s %s", - machine ? " -M " : "", - machine ?: "", - test_args); - actual = read_boot_order(); + qts = qtest_initf("-nodefaults%s%s %s", machine ? " -M " : "", + machine ?: "", test_args); + actual = read_boot_order(qts); g_assert_cmphex(actual, ==, expected_boot); - qmp_discard_response("{ 'execute': 'system_reset' }"); + qmp_discard_response(qts, "{ 'execute': 'system_reset' }"); /* * system_reset only requests reset. We get a RESET event after * the actual reset completes. Need to wait for that. */ - qmp_eventwait("RESET"); - actual = read_boot_order(); + qtest_qmp_eventwait(qts, "RESET"); + actual = read_boot_order(qts); g_assert_cmphex(actual, ==, expected_reboot); - qtest_quit(global_qtest); + qtest_quit(qts); } static void test_boot_orders(const char *machine, - uint64_t (*read_boot_order)(void), + uint64_t (*read_boot_order)(QTestState *), const boot_order_test *tests) { int i; @@ -64,16 +63,16 @@ static void test_boot_orders(const char *machine, } } -static uint8_t read_mc146818(uint16_t port, uint8_t reg) +static uint8_t read_mc146818(QTestState *qts, uint16_t port, uint8_t reg) { - outb(port, reg); - return inb(port + 1); + qtest_outb(qts, port, reg); + return qtest_inb(qts, port + 1); } -static uint64_t read_boot_order_pc(void) +static uint64_t read_boot_order_pc(QTestState *qts) { - uint8_t b1 = read_mc146818(0x70, 0x38); - uint8_t b2 = read_mc146818(0x70, 0x3d); + uint8_t b1 = read_mc146818(qts, 0x70, 0x38); + uint8_t b2 = read_mc146818(qts, 0x70, 0x3d); return b1 | (b2 << 8); } @@ -109,16 +108,16 @@ static void test_pc_boot_order(void) test_boot_orders(NULL, read_boot_order_pc, test_cases_pc); } -static uint8_t read_m48t59(uint64_t addr, uint16_t reg) +static uint8_t read_m48t59(QTestState *qts, uint64_t addr, uint16_t reg) { - writeb(addr, reg & 0xff); - writeb(addr + 1, reg >> 8); - return readb(addr + 3); + qtest_writeb(qts, addr, reg & 0xff); + qtest_writeb(qts, addr + 1, reg >> 8); + return qtest_readb(qts, addr + 3); } -static uint64_t read_boot_order_prep(void) +static uint64_t read_boot_order_prep(QTestState *qts) { - return read_m48t59(0x80000000 + 0x74, 0x34); + return read_m48t59(qts, 0x80000000 + 0x74, 0x34); } static const boot_order_test test_cases_prep[] = { @@ -133,9 +132,9 @@ static void test_prep_boot_order(void) test_boot_orders("prep", read_boot_order_prep, test_cases_prep); } -static uint64_t read_boot_order_pmac(void) +static uint64_t read_boot_order_pmac(QTestState *qts) { - QFWCFG *fw_cfg = mm_fw_cfg_init(global_qtest, 0xf0000510); + QFWCFG *fw_cfg = mm_fw_cfg_init(qts, 0xf0000510); return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE); } @@ -158,9 +157,9 @@ static void test_pmac_newworld_boot_order(void) test_boot_orders("mac99", read_boot_order_pmac, test_cases_fw_cfg); } -static uint64_t read_boot_order_sun4m(void) +static uint64_t read_boot_order_sun4m(QTestState *qts) { - QFWCFG *fw_cfg = mm_fw_cfg_init(global_qtest, 0xd00000510ULL); + QFWCFG *fw_cfg = mm_fw_cfg_init(qts, 0xd00000510ULL); return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE); } @@ -170,9 +169,9 @@ static void test_sun4m_boot_order(void) test_boot_orders("SS-5", read_boot_order_sun4m, test_cases_fw_cfg); } -static uint64_t read_boot_order_sun4u(void) +static uint64_t read_boot_order_sun4u(QTestState *qts) { - QFWCFG *fw_cfg = io_fw_cfg_init(global_qtest, 0x510); + QFWCFG *fw_cfg = io_fw_cfg_init(qts, 0x510); return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE); } diff --git a/tests/endianness-test.c b/tests/endianness-test.c index 48680cd131..58527952a5 100644 --- a/tests/endianness-test.c +++ b/tests/endianness-test.c @@ -48,65 +48,68 @@ static const TestCase test_cases[] = { {} }; -static uint8_t isa_inb(const TestCase *test, uint16_t addr) +static uint8_t isa_inb(QTestState *qts, const TestCase *test, uint16_t addr) { uint8_t value; if (test->isa_base == -1) { - value = inb(addr); + value = qtest_inb(qts, addr); } else { - value = readb(test->isa_base + addr); + value = qtest_readb(qts, test->isa_base + addr); } return value; } -static uint16_t isa_inw(const TestCase *test, uint16_t addr) +static uint16_t isa_inw(QTestState *qts, const TestCase *test, uint16_t addr) { uint16_t value; if (test->isa_base == -1) { - value = inw(addr); + value = qtest_inw(qts, addr); } else { - value = readw(test->isa_base + addr); + value = qtest_readw(qts, test->isa_base + addr); } return test->bswap ? bswap16(value) : value; } -static uint32_t isa_inl(const TestCase *test, uint16_t addr) +static uint32_t isa_inl(QTestState *qts, const TestCase *test, uint16_t addr) { uint32_t value; if (test->isa_base == -1) { - value = inl(addr); + value = qtest_inl(qts, addr); } else { - value = readl(test->isa_base + addr); + value = qtest_readl(qts, test->isa_base + addr); } return test->bswap ? bswap32(value) : value; } -static void isa_outb(const TestCase *test, uint16_t addr, uint8_t value) +static void isa_outb(QTestState *qts, const TestCase *test, uint16_t addr, + uint8_t value) { if (test->isa_base == -1) { - outb(addr, value); + qtest_outb(qts, addr, value); } else { - writeb(test->isa_base + addr, value); + qtest_writeb(qts, test->isa_base + addr, value); } } -static void isa_outw(const TestCase *test, uint16_t addr, uint16_t value) +static void isa_outw(QTestState *qts, const TestCase *test, uint16_t addr, + uint16_t value) { value = test->bswap ? bswap16(value) : value; if (test->isa_base == -1) { - outw(addr, value); + qtest_outw(qts, addr, value); } else { - writew(test->isa_base + addr, value); + qtest_writew(qts, test->isa_base + addr, value); } } -static void isa_outl(const TestCase *test, uint16_t addr, uint32_t value) +static void isa_outl(QTestState *qts, const TestCase *test, uint16_t addr, + uint32_t value) { value = test->bswap ? bswap32(value) : value; if (test->isa_base == -1) { - outl(addr, value); + qtest_outl(qts, addr, value); } else { - writel(test->isa_base + addr, value); + qtest_writel(qts, test->isa_base + addr, value); } } @@ -114,161 +117,161 @@ static void isa_outl(const TestCase *test, uint16_t addr, uint32_t value) static void test_endianness(gconstpointer data) { const TestCase *test = data; - - global_qtest = qtest_initf("-M %s%s%s -device pc-testdev", - test->machine, - test->superio ? " -device " : "", - test->superio ?: ""); - isa_outl(test, 0xe0, 0x87654321); - g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321); - g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765); - g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321); - g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87); - g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x65); - g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x43); - g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x21); - - isa_outw(test, 0xe2, 0x8866); - g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x88664321); - g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8866); - g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321); - g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x88); - g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x66); - g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x43); - g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x21); - - isa_outw(test, 0xe0, 0x4422); - g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x88664422); - g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8866); - g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4422); - g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x88); - g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x66); - g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x44); - g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x22); - - isa_outb(test, 0xe3, 0x87); - g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87664422); - g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8766); - g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87); - g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x66); - g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x44); - g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x22); - - isa_outb(test, 0xe2, 0x65); - g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654422); - g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765); - g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4422); - g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87); - g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x65); - g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x44); - g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x22); - - isa_outb(test, 0xe1, 0x43); - g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654322); - g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765); - g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4322); - g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87); - g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x65); - g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x43); - g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x22); - - isa_outb(test, 0xe0, 0x21); - g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321); - g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765); - g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321); - g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87); - g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x65); - g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x43); - g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x21); - qtest_quit(global_qtest); + QTestState *qts; + + qts = qtest_initf("-M %s%s%s -device pc-testdev", test->machine, + test->superio ? " -device " : "", + test->superio ?: ""); + isa_outl(qts, test, 0xe0, 0x87654321); + g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654321); + g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765); + g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321); + g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x87); + g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x65); + g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x43); + g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x21); + + isa_outw(qts, test, 0xe2, 0x8866); + g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x88664321); + g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8866); + g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321); + g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x88); + g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x66); + g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x43); + g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x21); + + isa_outw(qts, test, 0xe0, 0x4422); + g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x88664422); + g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8866); + g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4422); + g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x88); + g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x66); + g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x44); + g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x22); + + isa_outb(qts, test, 0xe3, 0x87); + g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87664422); + g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8766); + g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x87); + g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x66); + g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x44); + g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x22); + + isa_outb(qts, test, 0xe2, 0x65); + g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654422); + g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765); + g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4422); + g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x87); + g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x65); + g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x44); + g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x22); + + isa_outb(qts, test, 0xe1, 0x43); + g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654322); + g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765); + g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4322); + g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x87); + g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x65); + g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x43); + g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x22); + + isa_outb(qts, test, 0xe0, 0x21); + g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654321); + g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765); + g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321); + g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x87); + g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x65); + g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x43); + g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x21); + qtest_quit(qts); } static void test_endianness_split(gconstpointer data) { const TestCase *test = data; - - global_qtest = qtest_initf("-M %s%s%s -device pc-testdev", - test->machine, - test->superio ? " -device " : "", - test->superio ?: ""); - isa_outl(test, 0xe8, 0x87654321); - g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321); - g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765); - g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321); - - isa_outw(test, 0xea, 0x8866); - g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x88664321); - g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8866); - g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321); - - isa_outw(test, 0xe8, 0x4422); - g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x88664422); - g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8866); - g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4422); - - isa_outb(test, 0xeb, 0x87); - g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87664422); - g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8766); - - isa_outb(test, 0xea, 0x65); - g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654422); - g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765); - g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4422); - - isa_outb(test, 0xe9, 0x43); - g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654322); - g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765); - g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4322); - - isa_outb(test, 0xe8, 0x21); - g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321); - g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765); - g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321); - qtest_quit(global_qtest); + QTestState *qts; + + qts = qtest_initf("-M %s%s%s -device pc-testdev", test->machine, + test->superio ? " -device " : "", + test->superio ?: ""); + isa_outl(qts, test, 0xe8, 0x87654321); + g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654321); + g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765); + g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321); + + isa_outw(qts, test, 0xea, 0x8866); + g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x88664321); + g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8866); + g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321); + + isa_outw(qts, test, 0xe8, 0x4422); + g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x88664422); + g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8866); + g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4422); + + isa_outb(qts, test, 0xeb, 0x87); + g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87664422); + g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8766); + + isa_outb(qts, test, 0xea, 0x65); + g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654422); + g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765); + g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4422); + + isa_outb(qts, test, 0xe9, 0x43); + g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654322); + g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765); + g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4322); + + isa_outb(qts, test, 0xe8, 0x21); + g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654321); + g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765); + g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321); + qtest_quit(qts); } static void test_endianness_combine(gconstpointer data) { const TestCase *test = data; - - global_qtest = qtest_initf("-M %s%s%s -device pc-testdev", - test->machine, - test->superio ? " -device " : "", - test->superio ?: ""); - isa_outl(test, 0xe0, 0x87654321); - g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87654321); - g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8765); - g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4321); - - isa_outw(test, 0xe2, 0x8866); - g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x88664321); - g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8866); - g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4321); - - isa_outw(test, 0xe0, 0x4422); - g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x88664422); - g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8866); - g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4422); - - isa_outb(test, 0xe3, 0x87); - g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87664422); - g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8766); - - isa_outb(test, 0xe2, 0x65); - g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87654422); - g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8765); - g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4422); - - isa_outb(test, 0xe1, 0x43); - g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87654322); - g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8765); - g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4322); - - isa_outb(test, 0xe0, 0x21); - g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87654321); - g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8765); - g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4321); - qtest_quit(global_qtest); + QTestState *qts; + + qts = qtest_initf("-M %s%s%s -device pc-testdev", test->machine, + test->superio ? " -device " : "", + test->superio ?: ""); + isa_outl(qts, test, 0xe0, 0x87654321); + g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x87654321); + g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8765); + g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4321); + + isa_outw(qts, test, 0xe2, 0x8866); + g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x88664321); + g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8866); + g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4321); + + isa_outw(qts, test, 0xe0, 0x4422); + g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x88664422); + g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8866); + g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4422); + + isa_outb(qts, test, 0xe3, 0x87); + g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x87664422); + g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8766); + + isa_outb(qts, test, 0xe2, 0x65); + g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x87654422); + g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8765); + g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4422); + + isa_outb(qts, test, 0xe1, 0x43); + g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x87654322); + g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8765); + g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4322); + + isa_outb(qts, test, 0xe0, 0x21); + g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x87654321); + g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8765); + g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4321); + qtest_quit(qts); } int main(int argc, char **argv) diff --git a/tests/hexloader-test.c b/tests/hexloader-test.c index 834ed52c22..8b7aa2d72d 100644 --- a/tests/hexloader-test.c +++ b/tests/hexloader-test.c @@ -23,7 +23,7 @@ static void hex_loader_test(void) const unsigned int base_addr = 0x00010000; QTestState *s = qtest_initf( - "-M vexpress-a9 -nographic -device loader,file=tests/data/hex-loader/test.hex"); + "-M vexpress-a9 -device loader,file=tests/data/hex-loader/test.hex"); for (i = 0; i < 256; ++i) { uint8_t val = qtest_readb(s, base_addr + i); diff --git a/tests/pnv-xscom-test.c b/tests/pnv-xscom-test.c index 70f4c84d1b..974f8da5b2 100644 --- a/tests/pnv-xscom-test.c +++ b/tests/pnv-xscom-test.c @@ -63,14 +63,15 @@ static uint64_t pnv_xscom_addr(const PnvChip *chip, uint32_t pcba) return addr; } -static uint64_t pnv_xscom_read(const PnvChip *chip, uint32_t pcba) +static uint64_t pnv_xscom_read(QTestState *qts, const PnvChip *chip, + uint32_t pcba) { - return readq(pnv_xscom_addr(chip, pcba)); + return qtest_readq(qts, pnv_xscom_addr(chip, pcba)); } -static void test_xscom_cfam_id(const PnvChip *chip) +static void test_xscom_cfam_id(QTestState *qts, const PnvChip *chip) { - uint64_t f000f = pnv_xscom_read(chip, 0xf000f); + uint64_t f000f = pnv_xscom_read(qts, chip, 0xf000f); g_assert_cmphex(f000f, ==, chip->cfam_id); } @@ -78,11 +79,11 @@ static void test_xscom_cfam_id(const PnvChip *chip) static void test_cfam_id(const void *data) { const PnvChip *chip = data; + QTestState *qts; - global_qtest = qtest_initf("-M powernv,accel=tcg -cpu %s", - chip->cpu_model); - test_xscom_cfam_id(chip); - qtest_quit(global_qtest); + qts = qtest_initf("-M powernv,accel=tcg -cpu %s", chip->cpu_model); + test_xscom_cfam_id(qts, chip); + qtest_quit(qts); } @@ -94,7 +95,7 @@ static void test_cfam_id(const void *data) #define PNV_XSCOM_EX_DTS_RESULT0 0x50000 -static void test_xscom_core(const PnvChip *chip) +static void test_xscom_core(QTestState *qts, const PnvChip *chip) { uint32_t first_core_dts0 = PNV_XSCOM_EX_DTS_RESULT0; uint64_t dts0; @@ -105,7 +106,7 @@ static void test_xscom_core(const PnvChip *chip) first_core_dts0 |= PNV_XSCOM_P9_EC_BASE(chip->first_core); } - dts0 = pnv_xscom_read(chip, first_core_dts0); + dts0 = pnv_xscom_read(qts, chip, first_core_dts0); g_assert_cmphex(dts0, ==, 0x26f024f023f0000ull); } @@ -113,11 +114,11 @@ static void test_xscom_core(const PnvChip *chip) static void test_core(const void *data) { const PnvChip *chip = data; + QTestState *qts; - global_qtest = qtest_initf("-M powernv,accel=tcg -cpu %s", - chip->cpu_model); - test_xscom_core(chip); - qtest_quit(global_qtest); + qts = qtest_initf("-M powernv,accel=tcg -cpu %s", chip->cpu_model); + test_xscom_core(qts, chip); + qtest_quit(qts); } static void add_test(const char *name, void (*test)(const void *data)) diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223 index 773892dbe6..f120a01646 100755 --- a/tests/qemu-iotests/223 +++ b/tests/qemu-iotests/223 @@ -127,6 +127,7 @@ _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-start", _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-start", "arguments":{"addr":{"type":"unix", "data":{"path":"'"$TEST_DIR/nbd"1'"}}}}' "error" # Attempt second server +$QEMU_NBD_PROG -L -k "$TEST_DIR/nbd" _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", "arguments":{"device":"n", "bitmap":"b"}}' "return" _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", @@ -142,6 +143,7 @@ _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", "arguments":{"device":"n", "name":"n2", "writable":true, "bitmap":"b2"}}' "return" +$QEMU_NBD_PROG -L -k "$TEST_DIR/nbd" echo echo "=== Contrast normal status to large granularity dirty-bitmap ===" diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out index 0de5240a75..6476b77ba2 100644 --- a/tests/qemu-iotests/223.out +++ b/tests/qemu-iotests/223.out @@ -30,12 +30,32 @@ wrote 2097152/2097152 bytes at offset 2097152 {"error": {"class": "GenericError", "desc": "NBD server not running"}} {"return": {}} {"error": {"class": "GenericError", "desc": "NBD server already running"}} +exports available: 0 {"return": {}} {"error": {"class": "GenericError", "desc": "Cannot find device=nosuch nor node_name=nosuch"}} {"error": {"class": "GenericError", "desc": "NBD server already has export named 'n'"}} {"error": {"class": "GenericError", "desc": "Enabled bitmap 'b2' incompatible with readonly export"}} {"error": {"class": "GenericError", "desc": "Bitmap 'b3' is not found"}} {"return": {}} +exports available: 2 + export: 'n' + size: 4194304 + flags: 0x4ef ( readonly flush fua trim zeroes df cache ) + min block: 512 + opt block: 4096 + max block: 33554432 + available meta contexts: 2 + base:allocation + qemu:dirty-bitmap:b + export: 'n2' + size: 4194304 + flags: 0x4ed ( flush fua trim zeroes df cache ) + min block: 512 + opt block: 4096 + max block: 33554432 + available meta contexts: 2 + base:allocation + qemu:dirty-bitmap:b2 === Contrast normal status to large granularity dirty-bitmap === diff --git a/tests/qemu-iotests/233 b/tests/qemu-iotests/233 index 1814efe333..fc345a1a46 100755 --- a/tests/qemu-iotests/233 +++ b/tests/qemu-iotests/233 @@ -2,7 +2,7 @@ # # Test NBD TLS certificate / authorization integration # -# Copyright (C) 2018 Red Hat, Inc. +# Copyright (C) 2018-2019 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -30,6 +30,7 @@ _cleanup() { nbd_server_stop _cleanup_test_img + rm -f "$TEST_DIR/server.log" tls_x509_cleanup } trap "_cleanup; exit \$status" 0 1 2 3 15 @@ -66,12 +67,14 @@ $QEMU_IO -c 'w -P 0x11 1m 1m' "$TEST_IMG" | _filter_qemu_io echo echo "== check TLS client to plain server fails ==" -nbd_server_start_tcp_socket -f $IMGFMT "$TEST_IMG" +nbd_server_start_tcp_socket -f $IMGFMT "$TEST_IMG" 2> "$TEST_DIR/server.log" -$QEMU_IMG info --image-opts \ - --object tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0 \ +obj=tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0 +$QEMU_IMG info --image-opts --object $obj \ driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \ 2>&1 | sed "s/$nbd_tcp_port/PORT/g" +$QEMU_NBD_PROG -L -b $nbd_tcp_addr -p $nbd_tcp_port --object $obj \ + --tls-creds=tls0 nbd_server_stop @@ -81,23 +84,28 @@ echo "== check plain client to TLS server fails ==" nbd_server_start_tcp_socket \ --object tls-creds-x509,dir=${tls_dir}/server1,endpoint=server,id=tls0,verify-peer=yes \ --tls-creds tls0 \ - -f $IMGFMT "$TEST_IMG" + -f $IMGFMT "$TEST_IMG" 2>> "$TEST_DIR/server.log" $QEMU_IMG info nbd://localhost:$nbd_tcp_port 2>&1 | sed "s/$nbd_tcp_port/PORT/g" +$QEMU_NBD_PROG -L -b $nbd_tcp_addr -p $nbd_tcp_port echo echo "== check TLS works ==" -$QEMU_IMG info --image-opts \ - --object tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0 \ +obj=tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0 +$QEMU_IMG info --image-opts --object $obj \ driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \ 2>&1 | sed "s/$nbd_tcp_port/PORT/g" +$QEMU_NBD_PROG -L -b $nbd_tcp_addr -p $nbd_tcp_port --object $obj \ + --tls-creds=tls0 echo echo "== check TLS with different CA fails ==" -$QEMU_IMG info --image-opts \ - --object tls-creds-x509,dir=${tls_dir}/client2,endpoint=client,id=tls0 \ +obj=tls-creds-x509,dir=${tls_dir}/client2,endpoint=client,id=tls0 +$QEMU_IMG info --image-opts --object $obj \ driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \ 2>&1 | sed "s/$nbd_tcp_port/PORT/g" +$QEMU_NBD_PROG -L -b $nbd_tcp_addr -p $nbd_tcp_port --object $obj \ + --tls-creds=tls0 echo echo "== perform I/O over TLS ==" @@ -109,6 +117,10 @@ $QEMU_IO -c 'r -P 0x11 1m 1m' -c 'w -P 0x22 1m 1m' --image-opts \ $QEMU_IO -f $IMGFMT -r -U -c 'r -P 0x22 1m 1m' "$TEST_IMG" | _filter_qemu_io +echo +echo "== final server log ==" +cat "$TEST_DIR/server.log" + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/233.out b/tests/qemu-iotests/233.out index 5f416721b0..6d45f3b230 100644 --- a/tests/qemu-iotests/233.out +++ b/tests/qemu-iotests/233.out @@ -15,20 +15,33 @@ wrote 1048576/1048576 bytes at offset 1048576 == check TLS client to plain server fails == qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': Denied by server for option 5 (starttls) server reported: TLS not configured +qemu-nbd: Denied by server for option 5 (starttls) +server reported: TLS not configured == check plain client to TLS server fails == qemu-img: Could not open 'nbd://localhost:PORT': TLS negotiation required before option 8 (structured reply) server reported: Option 0x8 not permitted before TLS +qemu-nbd: TLS negotiation required before option 8 (structured reply) +server reported: Option 0x8 not permitted before TLS == check TLS works == image: nbd://127.0.0.1:PORT file format: nbd virtual size: 64M (67108864 bytes) disk size: unavailable +exports available: 1 + export: '' + size: 67108864 + flags: 0x4ed ( flush fua trim zeroes df cache ) + min block: 512 + opt block: 4096 + max block: 33554432 + available meta contexts: 1 + base:allocation == check TLS with different CA fails == -qemu-nbd: option negotiation failed: Verify failed: No certificate was found. qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': The certificate hasn't got a known issuer +qemu-nbd: The certificate hasn't got a known issuer == perform I/O over TLS == read 1048576/1048576 bytes at offset 1048576 @@ -37,4 +50,8 @@ wrote 1048576/1048576 bytes at offset 1048576 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 1048576/1048576 bytes at offset 1048576 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== final server log == +qemu-nbd: option negotiation failed: Verify failed: No certificate was found. +qemu-nbd: option negotiation failed: Verify failed: No certificate was found. *** done |