aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--audio/audio_int.h4
-rw-r--r--block/iscsi.c2
-rw-r--r--block/nbd-client.c9
-rw-r--r--blockdev-nbd.c10
-rwxr-xr-xconfigure5
-rw-r--r--hw/intc/xics_kvm.c1
-rw-r--r--hw/intc/xics_spapr.c1
-rw-r--r--hw/ppc/spapr_irq.c1
-rw-r--r--include/block/nbd.h31
-rw-r--r--include/hw/arm/pxa.h1
-rw-r--r--include/hw/char/serial.h4
-rw-r--r--include/hw/devices.h1
-rw-r--r--include/hw/i2c/smbus.h2
-rw-r--r--include/hw/i386/pc.h4
-rw-r--r--include/hw/ide/ahci.h4
-rw-r--r--include/hw/input/ps2.h2
-rw-r--r--include/hw/pcmcia.h4
-rw-r--r--include/hw/ppc/spapr.h5
-rw-r--r--include/hw/ppc/spapr_xive.h2
-rw-r--r--include/hw/ppc/xics.h7
-rw-r--r--include/hw/ppc/xics_spapr.h37
-rw-r--r--include/hw/virtio/virtio-net.h5
-rw-r--r--include/qemu/compiler.h4
-rw-r--r--include/qemu/typedefs.h13
-rw-r--r--include/sysemu/bt.h4
-rw-r--r--include/ui/console.h24
-rw-r--r--include/ui/qemu-pixman.h10
-rw-r--r--linux-user/qemu.h6
-rw-r--r--nbd/client.c761
-rw-r--r--nbd/server.c24
-rw-r--r--nbd/trace-events17
-rw-r--r--pc-bios/efi-e1000.rombin240128 -> 240128 bytes
-rw-r--r--pc-bios/efi-e1000e.rombin240128 -> 240128 bytes
-rw-r--r--pc-bios/efi-eepro100.rombin240128 -> 240128 bytes
-rw-r--r--pc-bios/efi-ne2k_pci.rombin238080 -> 238592 bytes
-rw-r--r--pc-bios/efi-pcnet.rombin238080 -> 238592 bytes
-rw-r--r--pc-bios/efi-rtl8139.rombin241664 -> 242688 bytes
-rw-r--r--pc-bios/efi-virtio.rombin242176 -> 242688 bytes
-rw-r--r--pc-bios/efi-vmxnet3.rombin236032 -> 236032 bytes
-rw-r--r--qemu-nbd.c224
-rw-r--r--qemu-nbd.texi119
-rw-r--r--qemu-seccomp.c3
m---------roms/ipxe0
-rwxr-xr-xscripts/texi2pod.pl2
-rw-r--r--target/ppc/cpu.h9
-rw-r--r--tests/Makefile.include23
-rw-r--r--tests/boot-order-test.c59
-rw-r--r--tests/endianness-test.c329
-rw-r--r--tests/hexloader-test.c2
-rw-r--r--tests/pnv-xscom-test.c29
-rwxr-xr-xtests/qemu-iotests/2232
-rw-r--r--tests/qemu-iotests/223.out20
-rwxr-xr-xtests/qemu-iotests/23330
-rw-r--r--tests/qemu-iotests/233.out19
55 files changed, 1259 insertions, 618 deletions
diff --git a/Makefile b/Makefile
index c9bdb67274..4219624fa0 100644
--- a/Makefile
+++ b/Makefile
@@ -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) {
diff --git a/configure b/configure
index 12fd34f30b..de768e2343 100755
--- a/configure
+++ b/configure
@@ -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
index 4da9de33da..6f088d41dd 100644
--- a/pc-bios/efi-e1000.rom
+++ b/pc-bios/efi-e1000.rom
Binary files differ
diff --git a/pc-bios/efi-e1000e.rom b/pc-bios/efi-e1000e.rom
index c2474a8fab..f536bdbd45 100644
--- a/pc-bios/efi-e1000e.rom
+++ b/pc-bios/efi-e1000e.rom
Binary files differ
diff --git a/pc-bios/efi-eepro100.rom b/pc-bios/efi-eepro100.rom
index 7950faf7cd..64d8891485 100644
--- a/pc-bios/efi-eepro100.rom
+++ b/pc-bios/efi-eepro100.rom
Binary files differ
diff --git a/pc-bios/efi-ne2k_pci.rom b/pc-bios/efi-ne2k_pci.rom
index 30edb1392a..02ad0cb505 100644
--- a/pc-bios/efi-ne2k_pci.rom
+++ b/pc-bios/efi-ne2k_pci.rom
Binary files differ
diff --git a/pc-bios/efi-pcnet.rom b/pc-bios/efi-pcnet.rom
index 23057c5724..88d25fa625 100644
--- a/pc-bios/efi-pcnet.rom
+++ b/pc-bios/efi-pcnet.rom
Binary files differ
diff --git a/pc-bios/efi-rtl8139.rom b/pc-bios/efi-rtl8139.rom
index beb9301839..53f125e3bb 100644
--- a/pc-bios/efi-rtl8139.rom
+++ b/pc-bios/efi-rtl8139.rom
Binary files differ
diff --git a/pc-bios/efi-virtio.rom b/pc-bios/efi-virtio.rom
index f4de5957ec..a87321e928 100644
--- a/pc-bios/efi-virtio.rom
+++ b/pc-bios/efi-virtio.rom
Binary files differ
diff --git a/pc-bios/efi-vmxnet3.rom b/pc-bios/efi-vmxnet3.rom
index 7501477ea6..d017cafe22 100644
--- a/pc-bios/efi-vmxnet3.rom
+++ b/pc-bios/efi-vmxnet3.rom
Binary files differ
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