mirror of https://gitee.com/openkylin/qemu.git
pci, pc, virtio, misc bugfixes
A bunch of bugfixes - some of these will make sense for 2.1.2 I put Cc: qemu-stable included where appropriate. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJUGyniAAoJECgfDbjSjVRpxg0H/j4jSEWHm/4uKSly6W4MXxhN LghE5iAaO3awU88RiRPW/m/g6sagD9RuQAHteHkvyZ6py/li0IFvLtl66OczeSgc rnM2n9MeYfi5Q05T+ygjqYY2ynosYhrI4iPmsnKqbqLi+WWwQHFKuYKNcNmQjmJu Sg4KDz+W4p5j/pMUZdgf4lse3PaLXoMy4IA1HC8U1WmwvyNLZrPRTXhFn1hFbxU6 Rf604wz6gkAFvwizt2SoRMOIF4w0meCKemY1wqcwOeDWqP6Bj76RnRCrVR06AgnX ngVsrP5SrWymqwFUP9ZpeNdBOQSxXE3zT1cE6JU3/KUvTBs6Eur4Dnz7g2mPb8I= =nHHz -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging pci, pc, virtio, misc bugfixes A bunch of bugfixes - some of these will make sense for 2.1.2 I put Cc: qemu-stable included where appropriate. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Thu 18 Sep 2014 19:52:18 BST using RSA key ID D28D5469 # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" * remotes/mst/tags/for_upstream: pc: leave more space for BIOS allocations virtio-pci: fix migration for pci bus master vhost-user: fix VIRTIO_NET_F_MRG_RXBUF negotiation virtio-pci: enable bus master for old guests Revert "virtio: don't call device on !vm_running" virtio-net: drop assert on vm stop Revert "rng-egd: remove redundant free" qdev: Move global validation to a single function qdev: Rename qdev_prop_check_global() to qdev_prop_check_globals() test-qdev-global-props: Test handling of hotpluggable and non-device types test-qdev-global-props: Initialize not_used=true for all props test-qdev-global-props: Run tests on subprocess tests: disable global props test for old glib test-qdev-global-props: Trivial comment fix hw/machine: Free old values of string properties Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
10e11f4d2b
|
@ -169,6 +169,7 @@ static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)
|
|||
if (b->opened) {
|
||||
error_set(errp, QERR_PERMISSION_DENIED);
|
||||
} else {
|
||||
g_free(s->chr_name);
|
||||
s->chr_name = g_strdup(value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2716,6 +2716,12 @@ for i in $glib_modules; do
|
|||
fi
|
||||
done
|
||||
|
||||
# g_test_trap_subprocess added in 2.38. Used by some tests.
|
||||
glib_subprocess=yes
|
||||
if ! $pkg_config --atleast-version=2.38 glib-2.0; then
|
||||
glib_subprocess=no
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# SHA command probe for modules
|
||||
if test "$modules" = yes; then
|
||||
|
@ -4586,6 +4592,9 @@ if test "$bluez" = "yes" ; then
|
|||
echo "CONFIG_BLUEZ=y" >> $config_host_mak
|
||||
echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
|
||||
fi
|
||||
if test "glib_subprocess" = "yes" ; then
|
||||
echo "CONFIG_HAS_GLIB_SUBPROCESS_TESTS=y" >> $config_host_mak
|
||||
fi
|
||||
echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
|
||||
if test "$gtk" = "yes" ; then
|
||||
echo "CONFIG_GTK=y" >> $config_host_mak
|
||||
|
|
|
@ -24,6 +24,7 @@ static void machine_set_accel(Object *obj, const char *value, Error **errp)
|
|||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
g_free(ms->accel);
|
||||
ms->accel = g_strdup(value);
|
||||
}
|
||||
|
||||
|
@ -79,6 +80,7 @@ static void machine_set_kernel(Object *obj, const char *value, Error **errp)
|
|||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
g_free(ms->kernel_filename);
|
||||
ms->kernel_filename = g_strdup(value);
|
||||
}
|
||||
|
||||
|
@ -93,6 +95,7 @@ static void machine_set_initrd(Object *obj, const char *value, Error **errp)
|
|||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
g_free(ms->initrd_filename);
|
||||
ms->initrd_filename = g_strdup(value);
|
||||
}
|
||||
|
||||
|
@ -107,6 +110,7 @@ static void machine_set_append(Object *obj, const char *value, Error **errp)
|
|||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
g_free(ms->kernel_cmdline);
|
||||
ms->kernel_cmdline = g_strdup(value);
|
||||
}
|
||||
|
||||
|
@ -121,6 +125,7 @@ static void machine_set_dtb(Object *obj, const char *value, Error **errp)
|
|||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
g_free(ms->dtb);
|
||||
ms->dtb = g_strdup(value);
|
||||
}
|
||||
|
||||
|
@ -135,6 +140,7 @@ static void machine_set_dumpdtb(Object *obj, const char *value, Error **errp)
|
|||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
g_free(ms->dumpdtb);
|
||||
ms->dumpdtb = g_strdup(value);
|
||||
}
|
||||
|
||||
|
@ -176,6 +182,7 @@ static void machine_set_dt_compatible(Object *obj, const char *value, Error **er
|
|||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
g_free(ms->dt_compatible);
|
||||
ms->dt_compatible = g_strdup(value);
|
||||
}
|
||||
|
||||
|
@ -232,6 +239,7 @@ static void machine_set_firmware(Object *obj, const char *value, Error **errp)
|
|||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
g_free(ms->firmware);
|
||||
ms->firmware = g_strdup(value);
|
||||
}
|
||||
|
||||
|
|
|
@ -388,28 +388,12 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
|
|||
static int qdev_add_one_global(QemuOpts *opts, void *opaque)
|
||||
{
|
||||
GlobalProperty *g;
|
||||
ObjectClass *oc;
|
||||
|
||||
g = g_malloc0(sizeof(*g));
|
||||
g->driver = qemu_opt_get(opts, "driver");
|
||||
g->property = qemu_opt_get(opts, "property");
|
||||
g->value = qemu_opt_get(opts, "value");
|
||||
oc = object_class_dynamic_cast(object_class_by_name(g->driver),
|
||||
TYPE_DEVICE);
|
||||
if (oc) {
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
if (dc->hotpluggable) {
|
||||
/* If hotpluggable then skip not_used checking. */
|
||||
g->not_used = false;
|
||||
} else {
|
||||
/* Maybe a typo. */
|
||||
g->not_used = true;
|
||||
}
|
||||
} else {
|
||||
/* Maybe a typo. */
|
||||
g->not_used = true;
|
||||
}
|
||||
g->user_provided = true;
|
||||
qdev_prop_register_global(g);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -955,19 +955,35 @@ void qdev_prop_register_global_list(GlobalProperty *props)
|
|||
}
|
||||
}
|
||||
|
||||
int qdev_prop_check_global(void)
|
||||
int qdev_prop_check_globals(void)
|
||||
{
|
||||
GlobalProperty *prop;
|
||||
int ret = 0;
|
||||
|
||||
QTAILQ_FOREACH(prop, &global_props, next) {
|
||||
if (!prop->not_used) {
|
||||
ObjectClass *oc;
|
||||
DeviceClass *dc;
|
||||
if (prop->used) {
|
||||
continue;
|
||||
}
|
||||
if (!prop->user_provided) {
|
||||
continue;
|
||||
}
|
||||
oc = object_class_by_name(prop->driver);
|
||||
oc = object_class_dynamic_cast(oc, TYPE_DEVICE);
|
||||
if (!oc) {
|
||||
error_report("Warning: global %s.%s has invalid class name",
|
||||
prop->driver, prop->property);
|
||||
ret = 1;
|
||||
continue;
|
||||
}
|
||||
dc = DEVICE_CLASS(oc);
|
||||
if (!dc->hotpluggable && !prop->used) {
|
||||
error_report("Warning: global %s.%s=%s not used",
|
||||
prop->driver, prop->property, prop->value);
|
||||
ret = 1;
|
||||
continue;
|
||||
}
|
||||
ret = 1;
|
||||
error_report("Warning: \"-global %s.%s=%s\" not used",
|
||||
prop->driver, prop->property, prop->value);
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -983,7 +999,7 @@ void qdev_prop_set_globals_for_type(DeviceState *dev, const char *typename,
|
|||
if (strcmp(typename, prop->driver) != 0) {
|
||||
continue;
|
||||
}
|
||||
prop->not_used = false;
|
||||
prop->used = true;
|
||||
object_property_parse(OBJECT(dev), prop->value, prop->property, &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
|
|
|
@ -72,8 +72,10 @@
|
|||
#define DPRINTF(fmt, ...)
|
||||
#endif
|
||||
|
||||
/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */
|
||||
unsigned acpi_data_size = 0x20000;
|
||||
/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables
|
||||
* (128K) and other BIOS datastructures (less than 4K reported to be used at
|
||||
* the moment, 32K should be enough for a while). */
|
||||
unsigned acpi_data_size = 0x20000 + 0x8000;
|
||||
void pc_set_legacy_acpi_data_size(void)
|
||||
{
|
||||
acpi_data_size = 0x10000;
|
||||
|
|
|
@ -163,11 +163,11 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
|
|||
if (r < 0) {
|
||||
goto fail;
|
||||
}
|
||||
if (!qemu_has_vnet_hdr_len(options->net_backend,
|
||||
sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
|
||||
net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
|
||||
}
|
||||
if (backend_kernel) {
|
||||
if (!qemu_has_vnet_hdr_len(options->net_backend,
|
||||
sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
|
||||
net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
|
||||
}
|
||||
if (~net->dev.features & net->dev.backend_features) {
|
||||
fprintf(stderr, "vhost lacks feature mask %" PRIu64
|
||||
" for backend\n",
|
||||
|
|
|
@ -1125,8 +1125,6 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
|
|||
return num_packets;
|
||||
}
|
||||
|
||||
assert(vdev->vm_running);
|
||||
|
||||
if (q->async_tx.elem.out_num) {
|
||||
virtio_queue_set_notification(q->tx_vq, 0);
|
||||
return num_packets;
|
||||
|
|
|
@ -86,9 +86,6 @@
|
|||
* 12 is historical, and due to x86 page size. */
|
||||
#define VIRTIO_PCI_QUEUE_ADDR_SHIFT 12
|
||||
|
||||
/* Flags track per-device state like workarounds for quirks in older guests. */
|
||||
#define VIRTIO_PCI_FLAG_BUS_MASTER_BUG (1 << 0)
|
||||
|
||||
static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
|
||||
VirtIOPCIProxy *dev);
|
||||
|
||||
|
@ -314,12 +311,14 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
|||
msix_unuse_all_vectors(&proxy->pci_dev);
|
||||
}
|
||||
|
||||
/* Linux before 2.6.34 sets the device as OK without enabling
|
||||
the PCI device bus master bit. In this case we need to disable
|
||||
some safety checks. */
|
||||
if ((val & VIRTIO_CONFIG_S_DRIVER_OK) &&
|
||||
!(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
|
||||
proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
|
||||
/* Linux before 2.6.34 drives the device without enabling
|
||||
the PCI device bus master bit. Enable it automatically
|
||||
for the guest. This is a PCI spec violation but so is
|
||||
initiating DMA with bus master bit clear. */
|
||||
if (val == (VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER)) {
|
||||
pci_default_write_config(&proxy->pci_dev, PCI_COMMAND,
|
||||
proxy->pci_dev.config[PCI_COMMAND] |
|
||||
PCI_COMMAND_MASTER, 1);
|
||||
}
|
||||
break;
|
||||
case VIRTIO_MSI_CONFIG_VECTOR:
|
||||
|
@ -470,13 +469,18 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
|
|||
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
|
||||
uint8_t cmd = proxy->pci_dev.config[PCI_COMMAND];
|
||||
|
||||
pci_default_write_config(pci_dev, address, val, len);
|
||||
|
||||
if (range_covers_byte(address, len, PCI_COMMAND) &&
|
||||
!(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER) &&
|
||||
!(proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG)) {
|
||||
(cmd & PCI_COMMAND_MASTER)) {
|
||||
/* Bus driver disables bus mastering - make it act
|
||||
* as a kind of reset to render the device quiescent. */
|
||||
virtio_pci_stop_ioeventfd(proxy);
|
||||
virtio_set_status(vdev, vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
|
||||
virtio_reset(vdev);
|
||||
msix_unuse_all_vectors(&proxy->pci_dev);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -885,11 +889,19 @@ static void virtio_pci_vmstate_change(DeviceState *d, bool running)
|
|||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
|
||||
if (running) {
|
||||
/* Try to find out if the guest has bus master disabled, but is
|
||||
in ready state. Then we have a buggy guest OS. */
|
||||
if ((vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) &&
|
||||
!(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
|
||||
proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
|
||||
/* Linux before 2.6.34 drives the device without enabling
|
||||
the PCI device bus master bit. Enable it automatically
|
||||
for the guest. This is a PCI spec violation but so is
|
||||
initiating DMA with bus master bit clear.
|
||||
Note: this only makes a difference when migrating
|
||||
across QEMU versions from an old QEMU, as for new QEMU
|
||||
bus master and driver bits are always in sync.
|
||||
TODO: consider enabling conditionally for compat machine types. */
|
||||
if (vdev->status & (VIRTIO_CONFIG_S_ACKNOWLEDGE |
|
||||
VIRTIO_CONFIG_S_DRIVER)) {
|
||||
pci_default_write_config(&proxy->pci_dev, PCI_COMMAND,
|
||||
proxy->pci_dev.config[PCI_COMMAND] |
|
||||
PCI_COMMAND_MASTER, 1);
|
||||
}
|
||||
virtio_pci_start_ioeventfd(proxy);
|
||||
} else {
|
||||
|
@ -1030,7 +1042,6 @@ static void virtio_pci_reset(DeviceState *qdev)
|
|||
virtio_pci_stop_ioeventfd(proxy);
|
||||
virtio_bus_reset(bus);
|
||||
msix_unuse_all_vectors(&proxy->pci_dev);
|
||||
proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
|
||||
}
|
||||
|
||||
static Property virtio_pci_properties[] = {
|
||||
|
|
|
@ -1108,10 +1108,7 @@ static void virtio_vmstate_change(void *opaque, int running, RunState state)
|
|||
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
|
||||
bool backend_run = running && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK);
|
||||
|
||||
if (running) {
|
||||
vdev->vm_running = running;
|
||||
}
|
||||
vdev->vm_running = running;
|
||||
|
||||
if (backend_run) {
|
||||
virtio_set_status(vdev, vdev->status);
|
||||
|
@ -1124,10 +1121,6 @@ static void virtio_vmstate_change(void *opaque, int running, RunState state)
|
|||
if (!backend_run) {
|
||||
virtio_set_status(vdev, vdev->status);
|
||||
}
|
||||
|
||||
if (!running) {
|
||||
vdev->vm_running = running;
|
||||
}
|
||||
}
|
||||
|
||||
void virtio_init(VirtIODevice *vdev, const char *name,
|
||||
|
|
|
@ -242,16 +242,16 @@ struct PropertyInfo {
|
|||
|
||||
/**
|
||||
* GlobalProperty:
|
||||
* @not_used: Track use of a global property. Defaults to false in all C99
|
||||
* struct initializations.
|
||||
*
|
||||
* This prevents reports of .compat_props when they are not used.
|
||||
* @user_provided: Set to true if property comes from user-provided config
|
||||
* (command-line or config file).
|
||||
* @used: Set to true if property was used when initializing a device.
|
||||
*/
|
||||
typedef struct GlobalProperty {
|
||||
const char *driver;
|
||||
const char *property;
|
||||
const char *value;
|
||||
bool not_used;
|
||||
bool user_provided;
|
||||
bool used;
|
||||
QTAILQ_ENTRY(GlobalProperty) next;
|
||||
} GlobalProperty;
|
||||
|
||||
|
|
|
@ -177,7 +177,7 @@ void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value);
|
|||
|
||||
void qdev_prop_register_global(GlobalProperty *prop);
|
||||
void qdev_prop_register_global_list(GlobalProperty *props);
|
||||
int qdev_prop_check_global(void);
|
||||
int qdev_prop_check_globals(void);
|
||||
void qdev_prop_set_globals(DeviceState *dev, Error **errp);
|
||||
void qdev_prop_set_globals_for_type(DeviceState *dev, const char *typename,
|
||||
Error **errp);
|
||||
|
|
|
@ -58,7 +58,7 @@ check-unit-y += tests/test-int128$(EXESUF)
|
|||
# all code tested by test-int128 is inside int128.h
|
||||
gcov-files-test-int128-y =
|
||||
check-unit-y += tests/test-bitops$(EXESUF)
|
||||
check-unit-y += tests/test-qdev-global-props$(EXESUF)
|
||||
check-unit-$(CONFIG_HAS_GLIB_SUBPROCESS_TESTS) += tests/test-qdev-global-props$(EXESUF)
|
||||
check-unit-y += tests/check-qom-interface$(EXESUF)
|
||||
gcov-files-check-qom-interface-y = qom/object.c
|
||||
check-unit-$(CONFIG_POSIX) += tests/test-vmstate$(EXESUF)
|
||||
|
|
|
@ -65,7 +65,7 @@ static const TypeInfo static_prop_type = {
|
|||
};
|
||||
|
||||
/* Test simple static property setting to default value */
|
||||
static void test_static_prop(void)
|
||||
static void test_static_prop_subprocess(void)
|
||||
{
|
||||
MyType *mt;
|
||||
|
||||
|
@ -75,8 +75,16 @@ static void test_static_prop(void)
|
|||
g_assert_cmpuint(mt->prop1, ==, PROP_DEFAULT);
|
||||
}
|
||||
|
||||
static void test_static_prop(void)
|
||||
{
|
||||
g_test_trap_subprocess("/qdev/properties/static/default/subprocess", 0, 0);
|
||||
g_test_trap_assert_passed();
|
||||
g_test_trap_assert_stderr("");
|
||||
g_test_trap_assert_stdout("");
|
||||
}
|
||||
|
||||
/* Test setting of static property using global properties */
|
||||
static void test_static_globalprop(void)
|
||||
static void test_static_globalprop_subprocess(void)
|
||||
{
|
||||
MyType *mt;
|
||||
static GlobalProperty props[] = {
|
||||
|
@ -93,10 +101,21 @@ static void test_static_globalprop(void)
|
|||
g_assert_cmpuint(mt->prop2, ==, PROP_DEFAULT);
|
||||
}
|
||||
|
||||
static void test_static_globalprop(void)
|
||||
{
|
||||
g_test_trap_subprocess("/qdev/properties/static/global/subprocess", 0, 0);
|
||||
g_test_trap_assert_passed();
|
||||
g_test_trap_assert_stderr("");
|
||||
g_test_trap_assert_stdout("");
|
||||
}
|
||||
|
||||
#define TYPE_DYNAMIC_PROPS "dynamic-prop-type"
|
||||
#define DYNAMIC_TYPE(obj) \
|
||||
OBJECT_CHECK(MyType, (obj), TYPE_DYNAMIC_PROPS)
|
||||
|
||||
#define TYPE_UNUSED_HOTPLUG "hotplug-type"
|
||||
#define TYPE_UNUSED_NOHOTPLUG "nohotplug-type"
|
||||
|
||||
static void prop1_accessor(Object *obj,
|
||||
Visitor *v,
|
||||
void *opaque,
|
||||
|
@ -143,14 +162,56 @@ static const TypeInfo dynamic_prop_type = {
|
|||
.class_init = dynamic_class_init,
|
||||
};
|
||||
|
||||
/* Test setting of static property using global properties */
|
||||
static void test_dynamic_globalprop(void)
|
||||
static void hotplug_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = NULL;
|
||||
dc->hotpluggable = true;
|
||||
}
|
||||
|
||||
static const TypeInfo hotplug_type = {
|
||||
.name = TYPE_UNUSED_HOTPLUG,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_size = sizeof(MyType),
|
||||
.instance_init = dynamic_instance_init,
|
||||
.class_init = hotplug_class_init,
|
||||
};
|
||||
|
||||
static void nohotplug_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = NULL;
|
||||
dc->hotpluggable = false;
|
||||
}
|
||||
|
||||
static const TypeInfo nohotplug_type = {
|
||||
.name = TYPE_UNUSED_NOHOTPLUG,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_size = sizeof(MyType),
|
||||
.instance_init = dynamic_instance_init,
|
||||
.class_init = nohotplug_class_init,
|
||||
};
|
||||
|
||||
#define TYPE_NONDEVICE "nondevice-type"
|
||||
|
||||
static const TypeInfo nondevice_type = {
|
||||
.name = TYPE_NONDEVICE,
|
||||
.parent = TYPE_OBJECT,
|
||||
};
|
||||
|
||||
/* Test setting of dynamic properties using global properties */
|
||||
static void test_dynamic_globalprop_subprocess(void)
|
||||
{
|
||||
MyType *mt;
|
||||
static GlobalProperty props[] = {
|
||||
{ TYPE_DYNAMIC_PROPS, "prop1", "101" },
|
||||
{ TYPE_DYNAMIC_PROPS, "prop2", "102" },
|
||||
{ TYPE_DYNAMIC_PROPS, "prop1", "101", true },
|
||||
{ TYPE_DYNAMIC_PROPS, "prop2", "102", true },
|
||||
{ TYPE_DYNAMIC_PROPS"-bad", "prop3", "103", true },
|
||||
{ TYPE_UNUSED_HOTPLUG, "prop4", "104", true },
|
||||
{ TYPE_UNUSED_NOHOTPLUG, "prop5", "105", true },
|
||||
{ TYPE_NONDEVICE, "prop6", "106", true },
|
||||
{}
|
||||
};
|
||||
int all_used;
|
||||
|
@ -162,8 +223,67 @@ static void test_dynamic_globalprop(void)
|
|||
|
||||
g_assert_cmpuint(mt->prop1, ==, 101);
|
||||
g_assert_cmpuint(mt->prop2, ==, 102);
|
||||
all_used = qdev_prop_check_global();
|
||||
all_used = qdev_prop_check_globals();
|
||||
g_assert_cmpuint(all_used, ==, 1);
|
||||
g_assert(props[0].used);
|
||||
g_assert(props[1].used);
|
||||
g_assert(!props[2].used);
|
||||
g_assert(!props[3].used);
|
||||
g_assert(!props[4].used);
|
||||
g_assert(!props[5].used);
|
||||
}
|
||||
|
||||
static void test_dynamic_globalprop(void)
|
||||
{
|
||||
g_test_trap_subprocess("/qdev/properties/dynamic/global/subprocess", 0, 0);
|
||||
g_test_trap_assert_passed();
|
||||
g_test_trap_assert_stderr_unmatched("*prop1*");
|
||||
g_test_trap_assert_stderr_unmatched("*prop2*");
|
||||
g_test_trap_assert_stderr("*Warning: global dynamic-prop-type-bad.prop3 has invalid class name\n*");
|
||||
g_test_trap_assert_stderr_unmatched("*prop4*");
|
||||
g_test_trap_assert_stderr("*Warning: global nohotplug-type.prop5=105 not used\n*");
|
||||
g_test_trap_assert_stderr("*Warning: global nondevice-type.prop6 has invalid class name\n*");
|
||||
g_test_trap_assert_stdout("");
|
||||
}
|
||||
|
||||
/* Test setting of dynamic properties using user_provided=false properties */
|
||||
static void test_dynamic_globalprop_nouser_subprocess(void)
|
||||
{
|
||||
MyType *mt;
|
||||
static GlobalProperty props[] = {
|
||||
{ TYPE_DYNAMIC_PROPS, "prop1", "101" },
|
||||
{ TYPE_DYNAMIC_PROPS, "prop2", "102" },
|
||||
{ TYPE_DYNAMIC_PROPS"-bad", "prop3", "103" },
|
||||
{ TYPE_UNUSED_HOTPLUG, "prop4", "104" },
|
||||
{ TYPE_UNUSED_NOHOTPLUG, "prop5", "105" },
|
||||
{ TYPE_NONDEVICE, "prop6", "106" },
|
||||
{}
|
||||
};
|
||||
int all_used;
|
||||
|
||||
qdev_prop_register_global_list(props);
|
||||
|
||||
mt = DYNAMIC_TYPE(object_new(TYPE_DYNAMIC_PROPS));
|
||||
qdev_init_nofail(DEVICE(mt));
|
||||
|
||||
g_assert_cmpuint(mt->prop1, ==, 101);
|
||||
g_assert_cmpuint(mt->prop2, ==, 102);
|
||||
all_used = qdev_prop_check_globals();
|
||||
g_assert_cmpuint(all_used, ==, 0);
|
||||
g_assert(props[0].used);
|
||||
g_assert(props[1].used);
|
||||
g_assert(!props[2].used);
|
||||
g_assert(!props[3].used);
|
||||
g_assert(!props[4].used);
|
||||
g_assert(!props[5].used);
|
||||
}
|
||||
|
||||
static void test_dynamic_globalprop_nouser(void)
|
||||
{
|
||||
g_test_trap_subprocess("/qdev/properties/dynamic/global/nouser/subprocess", 0, 0);
|
||||
g_test_trap_assert_passed();
|
||||
g_test_trap_assert_stderr("");
|
||||
g_test_trap_assert_stdout("");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
@ -173,10 +293,29 @@ int main(int argc, char **argv)
|
|||
module_call_init(MODULE_INIT_QOM);
|
||||
type_register_static(&static_prop_type);
|
||||
type_register_static(&dynamic_prop_type);
|
||||
type_register_static(&hotplug_type);
|
||||
type_register_static(&nohotplug_type);
|
||||
type_register_static(&nondevice_type);
|
||||
|
||||
g_test_add_func("/qdev/properties/static/default", test_static_prop);
|
||||
g_test_add_func("/qdev/properties/static/global", test_static_globalprop);
|
||||
g_test_add_func("/qdev/properties/dynamic/global", test_dynamic_globalprop);
|
||||
g_test_add_func("/qdev/properties/static/default/subprocess",
|
||||
test_static_prop_subprocess);
|
||||
g_test_add_func("/qdev/properties/static/default",
|
||||
test_static_prop);
|
||||
|
||||
g_test_add_func("/qdev/properties/static/global/subprocess",
|
||||
test_static_globalprop_subprocess);
|
||||
g_test_add_func("/qdev/properties/static/global",
|
||||
test_static_globalprop);
|
||||
|
||||
g_test_add_func("/qdev/properties/dynamic/global/subprocess",
|
||||
test_dynamic_globalprop_subprocess);
|
||||
g_test_add_func("/qdev/properties/dynamic/global",
|
||||
test_dynamic_globalprop);
|
||||
|
||||
g_test_add_func("/qdev/properties/dynamic/global/nouser/subprocess",
|
||||
test_dynamic_globalprop_nouser_subprocess);
|
||||
g_test_add_func("/qdev/properties/dynamic/global/nouser",
|
||||
test_dynamic_globalprop_nouser);
|
||||
|
||||
g_test_run();
|
||||
|
||||
|
|
Loading…
Reference in New Issue