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:
Peter Maydell 2014-09-18 20:02:00 +01:00
commit 10e11f4d2b
15 changed files with 236 additions and 75 deletions

View File

@ -169,6 +169,7 @@ static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)
if (b->opened) { if (b->opened) {
error_set(errp, QERR_PERMISSION_DENIED); error_set(errp, QERR_PERMISSION_DENIED);
} else { } else {
g_free(s->chr_name);
s->chr_name = g_strdup(value); s->chr_name = g_strdup(value);
} }
} }

9
configure vendored
View File

@ -2716,6 +2716,12 @@ for i in $glib_modules; do
fi fi
done 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 # SHA command probe for modules
if test "$modules" = yes; then if test "$modules" = yes; then
@ -4586,6 +4592,9 @@ if test "$bluez" = "yes" ; then
echo "CONFIG_BLUEZ=y" >> $config_host_mak echo "CONFIG_BLUEZ=y" >> $config_host_mak
echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
fi 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 echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
if test "$gtk" = "yes" ; then if test "$gtk" = "yes" ; then
echo "CONFIG_GTK=y" >> $config_host_mak echo "CONFIG_GTK=y" >> $config_host_mak

View File

@ -24,6 +24,7 @@ static void machine_set_accel(Object *obj, const char *value, Error **errp)
{ {
MachineState *ms = MACHINE(obj); MachineState *ms = MACHINE(obj);
g_free(ms->accel);
ms->accel = g_strdup(value); 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); MachineState *ms = MACHINE(obj);
g_free(ms->kernel_filename);
ms->kernel_filename = g_strdup(value); 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); MachineState *ms = MACHINE(obj);
g_free(ms->initrd_filename);
ms->initrd_filename = g_strdup(value); 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); MachineState *ms = MACHINE(obj);
g_free(ms->kernel_cmdline);
ms->kernel_cmdline = g_strdup(value); 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); MachineState *ms = MACHINE(obj);
g_free(ms->dtb);
ms->dtb = g_strdup(value); 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); MachineState *ms = MACHINE(obj);
g_free(ms->dumpdtb);
ms->dumpdtb = g_strdup(value); 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); MachineState *ms = MACHINE(obj);
g_free(ms->dt_compatible);
ms->dt_compatible = g_strdup(value); 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); MachineState *ms = MACHINE(obj);
g_free(ms->firmware);
ms->firmware = g_strdup(value); ms->firmware = g_strdup(value);
} }

View File

@ -388,28 +388,12 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
static int qdev_add_one_global(QemuOpts *opts, void *opaque) static int qdev_add_one_global(QemuOpts *opts, void *opaque)
{ {
GlobalProperty *g; GlobalProperty *g;
ObjectClass *oc;
g = g_malloc0(sizeof(*g)); g = g_malloc0(sizeof(*g));
g->driver = qemu_opt_get(opts, "driver"); g->driver = qemu_opt_get(opts, "driver");
g->property = qemu_opt_get(opts, "property"); g->property = qemu_opt_get(opts, "property");
g->value = qemu_opt_get(opts, "value"); g->value = qemu_opt_get(opts, "value");
oc = object_class_dynamic_cast(object_class_by_name(g->driver), g->user_provided = true;
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;
}
qdev_prop_register_global(g); qdev_prop_register_global(g);
return 0; return 0;
} }

View File

@ -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; GlobalProperty *prop;
int ret = 0; int ret = 0;
QTAILQ_FOREACH(prop, &global_props, next) { 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; continue;
} }
ret = 1;
error_report("Warning: \"-global %s.%s=%s\" not used",
prop->driver, prop->property, prop->value);
} }
return ret; return ret;
} }
@ -983,7 +999,7 @@ void qdev_prop_set_globals_for_type(DeviceState *dev, const char *typename,
if (strcmp(typename, prop->driver) != 0) { if (strcmp(typename, prop->driver) != 0) {
continue; continue;
} }
prop->not_used = false; prop->used = true;
object_property_parse(OBJECT(dev), prop->value, prop->property, &err); object_property_parse(OBJECT(dev), prop->value, prop->property, &err);
if (err != NULL) { if (err != NULL) {
error_propagate(errp, err); error_propagate(errp, err);

View File

@ -72,8 +72,10 @@
#define DPRINTF(fmt, ...) #define DPRINTF(fmt, ...)
#endif #endif
/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */ /* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables
unsigned acpi_data_size = 0x20000; * (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) void pc_set_legacy_acpi_data_size(void)
{ {
acpi_data_size = 0x10000; acpi_data_size = 0x10000;

View File

@ -163,11 +163,11 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
if (r < 0) { if (r < 0) {
goto fail; 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 (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) { if (~net->dev.features & net->dev.backend_features) {
fprintf(stderr, "vhost lacks feature mask %" PRIu64 fprintf(stderr, "vhost lacks feature mask %" PRIu64
" for backend\n", " for backend\n",

View File

@ -1125,8 +1125,6 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
return num_packets; return num_packets;
} }
assert(vdev->vm_running);
if (q->async_tx.elem.out_num) { if (q->async_tx.elem.out_num) {
virtio_queue_set_notification(q->tx_vq, 0); virtio_queue_set_notification(q->tx_vq, 0);
return num_packets; return num_packets;

View File

@ -86,9 +86,6 @@
* 12 is historical, and due to x86 page size. */ * 12 is historical, and due to x86 page size. */
#define VIRTIO_PCI_QUEUE_ADDR_SHIFT 12 #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, static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
VirtIOPCIProxy *dev); 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); msix_unuse_all_vectors(&proxy->pci_dev);
} }
/* Linux before 2.6.34 sets the device as OK without enabling /* Linux before 2.6.34 drives the device without enabling
the PCI device bus master bit. In this case we need to disable the PCI device bus master bit. Enable it automatically
some safety checks. */ for the guest. This is a PCI spec violation but so is
if ((val & VIRTIO_CONFIG_S_DRIVER_OK) && initiating DMA with bus master bit clear. */
!(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) { if (val == (VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER)) {
proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG; pci_default_write_config(&proxy->pci_dev, PCI_COMMAND,
proxy->pci_dev.config[PCI_COMMAND] |
PCI_COMMAND_MASTER, 1);
} }
break; break;
case VIRTIO_MSI_CONFIG_VECTOR: 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); VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 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); pci_default_write_config(pci_dev, address, val, len);
if (range_covers_byte(address, len, PCI_COMMAND) && if (range_covers_byte(address, len, PCI_COMMAND) &&
!(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER) && !(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_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); VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
if (running) { if (running) {
/* Try to find out if the guest has bus master disabled, but is /* Linux before 2.6.34 drives the device without enabling
in ready state. Then we have a buggy guest OS. */ the PCI device bus master bit. Enable it automatically
if ((vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) && for the guest. This is a PCI spec violation but so is
!(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) { initiating DMA with bus master bit clear.
proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG; 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); virtio_pci_start_ioeventfd(proxy);
} else { } else {
@ -1030,7 +1042,6 @@ static void virtio_pci_reset(DeviceState *qdev)
virtio_pci_stop_ioeventfd(proxy); virtio_pci_stop_ioeventfd(proxy);
virtio_bus_reset(bus); virtio_bus_reset(bus);
msix_unuse_all_vectors(&proxy->pci_dev); msix_unuse_all_vectors(&proxy->pci_dev);
proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
} }
static Property virtio_pci_properties[] = { static Property virtio_pci_properties[] = {

View File

@ -1108,10 +1108,7 @@ static void virtio_vmstate_change(void *opaque, int running, RunState state)
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
bool backend_run = running && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK); bool backend_run = running && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK);
vdev->vm_running = running;
if (running) {
vdev->vm_running = running;
}
if (backend_run) { if (backend_run) {
virtio_set_status(vdev, vdev->status); virtio_set_status(vdev, vdev->status);
@ -1124,10 +1121,6 @@ static void virtio_vmstate_change(void *opaque, int running, RunState state)
if (!backend_run) { if (!backend_run) {
virtio_set_status(vdev, vdev->status); virtio_set_status(vdev, vdev->status);
} }
if (!running) {
vdev->vm_running = running;
}
} }
void virtio_init(VirtIODevice *vdev, const char *name, void virtio_init(VirtIODevice *vdev, const char *name,

View File

@ -242,16 +242,16 @@ struct PropertyInfo {
/** /**
* GlobalProperty: * GlobalProperty:
* @not_used: Track use of a global property. Defaults to false in all C99 * @user_provided: Set to true if property comes from user-provided config
* struct initializations. * (command-line or config file).
* * @used: Set to true if property was used when initializing a device.
* This prevents reports of .compat_props when they are not used.
*/ */
typedef struct GlobalProperty { typedef struct GlobalProperty {
const char *driver; const char *driver;
const char *property; const char *property;
const char *value; const char *value;
bool not_used; bool user_provided;
bool used;
QTAILQ_ENTRY(GlobalProperty) next; QTAILQ_ENTRY(GlobalProperty) next;
} GlobalProperty; } GlobalProperty;

View File

@ -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(GlobalProperty *prop);
void qdev_prop_register_global_list(GlobalProperty *props); 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(DeviceState *dev, Error **errp);
void qdev_prop_set_globals_for_type(DeviceState *dev, const char *typename, void qdev_prop_set_globals_for_type(DeviceState *dev, const char *typename,
Error **errp); Error **errp);

View File

@ -58,7 +58,7 @@ check-unit-y += tests/test-int128$(EXESUF)
# all code tested by test-int128 is inside int128.h # all code tested by test-int128 is inside int128.h
gcov-files-test-int128-y = gcov-files-test-int128-y =
check-unit-y += tests/test-bitops$(EXESUF) 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) check-unit-y += tests/check-qom-interface$(EXESUF)
gcov-files-check-qom-interface-y = qom/object.c gcov-files-check-qom-interface-y = qom/object.c
check-unit-$(CONFIG_POSIX) += tests/test-vmstate$(EXESUF) check-unit-$(CONFIG_POSIX) += tests/test-vmstate$(EXESUF)

View File

@ -65,7 +65,7 @@ static const TypeInfo static_prop_type = {
}; };
/* Test simple static property setting to default value */ /* Test simple static property setting to default value */
static void test_static_prop(void) static void test_static_prop_subprocess(void)
{ {
MyType *mt; MyType *mt;
@ -75,8 +75,16 @@ static void test_static_prop(void)
g_assert_cmpuint(mt->prop1, ==, PROP_DEFAULT); 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 */ /* Test setting of static property using global properties */
static void test_static_globalprop(void) static void test_static_globalprop_subprocess(void)
{ {
MyType *mt; MyType *mt;
static GlobalProperty props[] = { static GlobalProperty props[] = {
@ -93,10 +101,21 @@ static void test_static_globalprop(void)
g_assert_cmpuint(mt->prop2, ==, PROP_DEFAULT); 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 TYPE_DYNAMIC_PROPS "dynamic-prop-type"
#define DYNAMIC_TYPE(obj) \ #define DYNAMIC_TYPE(obj) \
OBJECT_CHECK(MyType, (obj), TYPE_DYNAMIC_PROPS) 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, static void prop1_accessor(Object *obj,
Visitor *v, Visitor *v,
void *opaque, void *opaque,
@ -143,14 +162,56 @@ static const TypeInfo dynamic_prop_type = {
.class_init = dynamic_class_init, .class_init = dynamic_class_init,
}; };
/* Test setting of static property using global properties */ static void hotplug_class_init(ObjectClass *oc, void *data)
static void test_dynamic_globalprop(void) {
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; MyType *mt;
static GlobalProperty props[] = { static GlobalProperty props[] = {
{ TYPE_DYNAMIC_PROPS, "prop1", "101" }, { TYPE_DYNAMIC_PROPS, "prop1", "101", true },
{ TYPE_DYNAMIC_PROPS, "prop2", "102" }, { TYPE_DYNAMIC_PROPS, "prop2", "102", true },
{ TYPE_DYNAMIC_PROPS"-bad", "prop3", "103", 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; int all_used;
@ -162,8 +223,67 @@ static void test_dynamic_globalprop(void)
g_assert_cmpuint(mt->prop1, ==, 101); g_assert_cmpuint(mt->prop1, ==, 101);
g_assert_cmpuint(mt->prop2, ==, 102); 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_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) int main(int argc, char **argv)
@ -173,10 +293,29 @@ int main(int argc, char **argv)
module_call_init(MODULE_INIT_QOM); module_call_init(MODULE_INIT_QOM);
type_register_static(&static_prop_type); type_register_static(&static_prop_type);
type_register_static(&dynamic_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/default/subprocess",
g_test_add_func("/qdev/properties/static/global", test_static_globalprop); test_static_prop_subprocess);
g_test_add_func("/qdev/properties/dynamic/global", test_dynamic_globalprop); 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(); g_test_run();

2
vl.c
View File

@ -4542,7 +4542,7 @@ int main(int argc, char **argv, char **envp)
} }
} }
qdev_prop_check_global(); qdev_prop_check_globals();
if (vmstate_dump_file) { if (vmstate_dump_file) {
/* dump and exit */ /* dump and exit */
dump_vmstate_json_to_file(vmstate_dump_file); dump_vmstate_json_to_file(vmstate_dump_file);