From 46795cf2e2f643ace9454822022ba8b1e9c0cf61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 13 Jan 2018 23:04:11 -0300 Subject: qdev: add helpers to be more explicit when using abstract QOM parent functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QOM API learning curve is quite hard, in particular when devices inherit from abstract parent. To be more explicit about when a device class change the parent hooks, add few helpers hoping a device class_init() will be easier to understand. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180114020412.26160-3-f4bug@amsat.org> Reviewed-by: Laurent Vivier Signed-off-by: Paolo Bonzini --- hw/core/qdev.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'hw') diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 2456035..11f8a27 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -1075,6 +1075,30 @@ static void device_class_init(ObjectClass *class, void *data) dc->user_creatable = true; } +void device_class_set_parent_reset(DeviceClass *dc, + DeviceReset dev_reset, + DeviceReset *parent_reset) +{ + *parent_reset = dc->reset; + dc->reset = dev_reset; +} + +void device_class_set_parent_realize(DeviceClass *dc, + DeviceRealize dev_realize, + DeviceRealize *parent_realize) +{ + *parent_realize = dc->realize; + dc->realize = dev_realize; +} + +void device_class_set_parent_unrealize(DeviceClass *dc, + DeviceUnrealize dev_unrealize, + DeviceUnrealize *parent_unrealize) +{ + *parent_unrealize = dc->unrealize; + dc->unrealize = dev_unrealize; +} + void device_reset(DeviceState *dev) { DeviceClass *klass = DEVICE_GET_CLASS(dev); -- cgit v1.1 From bf853881690db8bbd1de39e4be580310a9cb0ebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 13 Jan 2018 23:04:12 -0300 Subject: qdev: use device_class_set_parent_realize/unrealize/reset() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit changes generated using the following Coccinelle patch: @@ type DeviceParentClass; DeviceParentClass *pc; DeviceClass *dc; identifier parent_fn; identifier child_fn; @@ ( +device_class_set_parent_realize(dc, child_fn, &pc->parent_fn); -pc->parent_fn = dc->realize; ... -dc->realize = child_fn; | +device_class_set_parent_unrealize(dc, child_fn, &pc->parent_fn); -pc->parent_fn = dc->unrealize; ... -dc->unrealize = child_fn; | +device_class_set_parent_reset(dc, child_fn, &pc->parent_fn); -pc->parent_fn = dc->reset; ... -dc->reset = child_fn; ) Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180114020412.26160-4-f4bug@amsat.org> Reviewed-by: Marcel Apfelbaum Acked-by: David Gibson Acked-by: Cornelia Huck Reviewed-by: Laurent Vivier Signed-off-by: Paolo Bonzini --- hw/i386/kvm/i8254.c | 4 ++-- hw/i386/kvm/i8259.c | 3 +-- hw/input/adb-kbd.c | 4 ++-- hw/input/adb-mouse.c | 4 ++-- hw/intc/arm_gic.c | 3 +-- hw/intc/arm_gic_kvm.c | 7 +++---- hw/intc/arm_gicv3.c | 3 +-- hw/intc/arm_gicv3_its_kvm.c | 3 +-- hw/intc/arm_gicv3_kvm.c | 7 +++---- hw/intc/i8259.c | 3 +-- hw/net/vmxnet3.c | 4 ++-- hw/pci-bridge/gen_pcie_root_port.c | 3 +-- hw/scsi/vmw_pvscsi.c | 4 ++-- hw/timer/i8254.c | 3 +-- hw/vfio/amd-xgbe.c | 4 ++-- hw/vfio/calxeda-xgmac.c | 4 ++-- hw/virtio/virtio-pci.c | 4 ++-- 17 files changed, 29 insertions(+), 38 deletions(-) (limited to 'hw') diff --git a/hw/i386/kvm/i8254.c b/hw/i386/kvm/i8254.c index 521a584..13f20f4 100644 --- a/hw/i386/kvm/i8254.c +++ b/hw/i386/kvm/i8254.c @@ -315,8 +315,8 @@ static void kvm_pit_class_init(ObjectClass *klass, void *data) PITCommonClass *k = PIT_COMMON_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); - kpc->parent_realize = dc->realize; - dc->realize = kvm_pit_realizefn; + device_class_set_parent_realize(dc, kvm_pit_realizefn, + &kpc->parent_realize); k->set_channel_gate = kvm_pit_set_gate; k->get_channel_info = kvm_pit_get_channel_info; dc->reset = kvm_pit_reset; diff --git a/hw/i386/kvm/i8259.c b/hw/i386/kvm/i8259.c index b91e980..05394cd 100644 --- a/hw/i386/kvm/i8259.c +++ b/hw/i386/kvm/i8259.c @@ -142,8 +142,7 @@ static void kvm_i8259_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); dc->reset = kvm_pic_reset; - kpc->parent_realize = dc->realize; - dc->realize = kvm_pic_realize; + device_class_set_parent_realize(dc, kvm_pic_realize, &kpc->parent_realize); k->pre_save = kvm_pic_get; k->post_load = kvm_pic_put; } diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c index 354f56e..266aed1 100644 --- a/hw/input/adb-kbd.c +++ b/hw/input/adb-kbd.c @@ -374,8 +374,8 @@ static void adb_kbd_class_init(ObjectClass *oc, void *data) ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc); ADBKeyboardClass *akc = ADB_KEYBOARD_CLASS(oc); - akc->parent_realize = dc->realize; - dc->realize = adb_kbd_realizefn; + device_class_set_parent_realize(dc, adb_kbd_realizefn, + &akc->parent_realize); set_bit(DEVICE_CATEGORY_INPUT, dc->categories); adc->devreq = adb_kbd_request; diff --git a/hw/input/adb-mouse.c b/hw/input/adb-mouse.c index c900423..47e88fa 100644 --- a/hw/input/adb-mouse.c +++ b/hw/input/adb-mouse.c @@ -228,8 +228,8 @@ static void adb_mouse_class_init(ObjectClass *oc, void *data) ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc); ADBMouseClass *amc = ADB_MOUSE_CLASS(oc); - amc->parent_realize = dc->realize; - dc->realize = adb_mouse_realizefn; + device_class_set_parent_realize(dc, adb_mouse_realizefn, + &amc->parent_realize); set_bit(DEVICE_CATEGORY_INPUT, dc->categories); adc->devreq = adb_mouse_request; diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 724bc9f..ea0323f 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -1461,8 +1461,7 @@ static void arm_gic_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); ARMGICClass *agc = ARM_GIC_CLASS(klass); - agc->parent_realize = dc->realize; - dc->realize = arm_gic_realize; + device_class_set_parent_realize(dc, arm_gic_realize, &agc->parent_realize); } static const TypeInfo arm_gic_info = { diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index ae095d0..6f467e6 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -591,10 +591,9 @@ static void kvm_arm_gic_class_init(ObjectClass *klass, void *data) agcc->pre_save = kvm_arm_gic_get; agcc->post_load = kvm_arm_gic_put; - kgc->parent_realize = dc->realize; - kgc->parent_reset = dc->reset; - dc->realize = kvm_arm_gic_realize; - dc->reset = kvm_arm_gic_reset; + device_class_set_parent_realize(dc, kvm_arm_gic_realize, + &kgc->parent_realize); + device_class_set_parent_reset(dc, kvm_arm_gic_reset, &kgc->parent_reset); } static const TypeInfo kvm_arm_gic_info = { diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c index f0c967b..479c667 100644 --- a/hw/intc/arm_gicv3.c +++ b/hw/intc/arm_gicv3.c @@ -385,8 +385,7 @@ static void arm_gicv3_class_init(ObjectClass *klass, void *data) ARMGICv3Class *agc = ARM_GICV3_CLASS(klass); agcc->post_load = arm_gicv3_post_load; - agc->parent_realize = dc->realize; - dc->realize = arm_gic_realize; + device_class_set_parent_realize(dc, arm_gic_realize, &agc->parent_realize); } static const TypeInfo arm_gicv3_info = { diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c index bf290b8..eea6a73 100644 --- a/hw/intc/arm_gicv3_its_kvm.c +++ b/hw/intc/arm_gicv3_its_kvm.c @@ -245,11 +245,10 @@ static void kvm_arm_its_class_init(ObjectClass *klass, void *data) dc->realize = kvm_arm_its_realize; dc->props = kvm_arm_its_props; - ic->parent_reset = dc->reset; + device_class_set_parent_reset(dc, kvm_arm_its_reset, &ic->parent_reset); icc->send_msi = kvm_its_send_msi; icc->pre_save = kvm_arm_its_pre_save; icc->post_load = kvm_arm_its_post_load; - dc->reset = kvm_arm_its_reset; } static const TypeInfo kvm_arm_its_info = { diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 481fe54..ec37177 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -795,10 +795,9 @@ static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data) agcc->pre_save = kvm_arm_gicv3_get; agcc->post_load = kvm_arm_gicv3_put; - kgc->parent_realize = dc->realize; - kgc->parent_reset = dc->reset; - dc->realize = kvm_arm_gicv3_realize; - dc->reset = kvm_arm_gicv3_reset; + device_class_set_parent_realize(dc, kvm_arm_gicv3_realize, + &kgc->parent_realize); + device_class_set_parent_reset(dc, kvm_arm_gicv3_reset, &kgc->parent_reset); } static const TypeInfo kvm_arm_gicv3_info = { diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c index 1602255..76f3d87 100644 --- a/hw/intc/i8259.c +++ b/hw/intc/i8259.c @@ -443,8 +443,7 @@ static void i8259_class_init(ObjectClass *klass, void *data) PICClass *k = PIC_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); - k->parent_realize = dc->realize; - dc->realize = pic_realize; + device_class_set_parent_realize(dc, pic_realize, &k->parent_realize); dc->reset = pic_reset; } diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 0654d59..3648630 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -2664,8 +2664,8 @@ static void vmxnet3_class_init(ObjectClass *class, void *data) c->class_id = PCI_CLASS_NETWORK_ETHERNET; c->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE; c->subsystem_id = PCI_DEVICE_ID_VMWARE_VMXNET3; - vc->parent_dc_realize = dc->realize; - dc->realize = vmxnet3_realize; + device_class_set_parent_realize(dc, vmxnet3_realize, + &vc->parent_dc_realize); dc->desc = "VMWare Paravirtualized Ethernet v3"; dc->reset = vmxnet3_qdev_reset; dc->vmsd = &vmstate_vmxnet3; diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c index 0e2f2e8..3dbacc6 100644 --- a/hw/pci-bridge/gen_pcie_root_port.c +++ b/hw/pci-bridge/gen_pcie_root_port.c @@ -137,8 +137,7 @@ static void gen_rp_dev_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_rp_dev; dc->props = gen_rp_props; - rpc->parent_realize = dc->realize; - dc->realize = gen_rp_realize; + device_class_set_parent_realize(dc, gen_rp_realize, &rpc->parent_realize); rpc->aer_vector = gen_rp_aer_vector; rpc->interrupts_init = gen_rp_interrupts_init; diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index 27749c0..a3a019e 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -1284,8 +1284,8 @@ static void pvscsi_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_VMWARE_PVSCSI; k->class_id = PCI_CLASS_STORAGE_SCSI; k->subsystem_id = 0x1000; - pvs_k->parent_dc_realize = dc->realize; - dc->realize = pvscsi_realize; + device_class_set_parent_realize(dc, pvscsi_realize, + &pvs_k->parent_dc_realize); dc->reset = pvscsi_reset; dc->vmsd = &vmstate_pvscsi; dc->props = pvscsi_properties; diff --git a/hw/timer/i8254.c b/hw/timer/i8254.c index dbc4a0b..1057850 100644 --- a/hw/timer/i8254.c +++ b/hw/timer/i8254.c @@ -358,8 +358,7 @@ static void pit_class_initfn(ObjectClass *klass, void *data) PITCommonClass *k = PIT_COMMON_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); - pc->parent_realize = dc->realize; - dc->realize = pit_realizefn; + device_class_set_parent_realize(dc, pit_realizefn, &pc->parent_realize); k->set_channel_gate = pit_set_channel_gate; k->get_channel_info = pit_get_channel_info_common; k->post_load = pit_post_load; diff --git a/hw/vfio/amd-xgbe.c b/hw/vfio/amd-xgbe.c index fab196c..0c4ec4b 100644 --- a/hw/vfio/amd-xgbe.c +++ b/hw/vfio/amd-xgbe.c @@ -34,8 +34,8 @@ static void vfio_amd_xgbe_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); VFIOAmdXgbeDeviceClass *vcxc = VFIO_AMD_XGBE_DEVICE_CLASS(klass); - vcxc->parent_realize = dc->realize; - dc->realize = amd_xgbe_realize; + device_class_set_parent_realize(dc, amd_xgbe_realize, + &vcxc->parent_realize); dc->desc = "VFIO AMD XGBE"; dc->vmsd = &vfio_platform_amd_xgbe_vmstate; /* Supported by TYPE_VIRT_MACHINE */ diff --git a/hw/vfio/calxeda-xgmac.c b/hw/vfio/calxeda-xgmac.c index 7bb17af..24cee6d 100644 --- a/hw/vfio/calxeda-xgmac.c +++ b/hw/vfio/calxeda-xgmac.c @@ -34,8 +34,8 @@ static void vfio_calxeda_xgmac_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); VFIOCalxedaXgmacDeviceClass *vcxc = VFIO_CALXEDA_XGMAC_DEVICE_CLASS(klass); - vcxc->parent_realize = dc->realize; - dc->realize = calxeda_xgmac_realize; + device_class_set_parent_realize(dc, calxeda_xgmac_realize, + &vcxc->parent_realize); dc->desc = "VFIO Calxeda XGMAC"; dc->vmsd = &vfio_platform_calxeda_xgmac_vmstate; /* Supported by TYPE_VIRT_MACHINE */ diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 9ae10f0..c20537f 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1907,8 +1907,8 @@ static void virtio_pci_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; k->revision = VIRTIO_PCI_ABI_VERSION; k->class_id = PCI_CLASS_OTHERS; - vpciklass->parent_dc_realize = dc->realize; - dc->realize = virtio_pci_dc_realize; + device_class_set_parent_realize(dc, virtio_pci_dc_realize, + &vpciklass->parent_dc_realize); dc->reset = virtio_pci_reset; } -- cgit v1.1 From c6caae553c65475009dc18fdae0c89a1a1d7b427 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Thu, 18 Jan 2018 10:52:45 +0800 Subject: scsi-generic: Simplify error handling code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Coverity doesn't like the ignored return value introduced in 9d3b155186c278 (hw/block: Fix the return type), and other callers are converted already in ceff3e1f01. This one was added lately in d9bcd6f7f23a and missed the train. Do it now. Signed-off-by: Fam Zheng Message-Id: <20180118025245.13042-1-famz@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-generic.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'hw') diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index ba70c0d..7414fe2 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -482,7 +482,6 @@ static void scsi_generic_realize(SCSIDevice *s, Error **errp) int rc; int sg_version; struct sg_scsi_id scsiid; - Error *local_err = NULL; if (!s->conf.blk) { error_setg(errp, "drive property not set"); @@ -516,11 +515,9 @@ static void scsi_generic_realize(SCSIDevice *s, Error **errp) error_setg(errp, "SG_GET_SCSI_ID ioctl failed"); return; } - blkconf_apply_backend_options(&s->conf, - blk_is_read_only(s->conf.blk), - true, &local_err); - if (local_err) { - error_propagate(errp, local_err); + if (!blkconf_apply_backend_options(&s->conf, + blk_is_read_only(s->conf.blk), + true, errp)) { return; } -- cgit v1.1 From 50876ead08531686275e6fe1999a2d80c7450d67 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 22 Jan 2018 16:27:33 +0100 Subject: i2c: Add a CONFIG_I2C master switch to the configuration files The i2c core and the at24c EEPROM should only be compiled and linked on the machines that support i2c. Otherwise it's quite strange to see the at24c-eeprom to be "available" on qemu-system-s390x for example. Signed-off-by: Thomas Huth Message-Id: <1516634853-15883-1-git-send-email-thuth@redhat.com> Signed-off-by: Paolo Bonzini --- hw/i2c/Makefile.objs | 2 +- hw/nvram/Makefile.objs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs index 0594dea..37cacde 100644 --- a/hw/i2c/Makefile.objs +++ b/hw/i2c/Makefile.objs @@ -1,4 +1,4 @@ -common-obj-y += core.o smbus.o smbus_eeprom.o +common-obj-$(CONFIG_I2C) += core.o smbus.o smbus_eeprom.o common-obj-$(CONFIG_DDC) += i2c-ddc.o common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o common-obj-$(CONFIG_ACPI_X86) += smbus_ich9.o diff --git a/hw/nvram/Makefile.objs b/hw/nvram/Makefile.objs index 0f4ee71..a912d25 100644 --- a/hw/nvram/Makefile.objs +++ b/hw/nvram/Makefile.objs @@ -1,6 +1,6 @@ common-obj-$(CONFIG_DS1225Y) += ds1225y.o common-obj-y += eeprom93xx.o -common-obj-y += eeprom_at24c.o +common-obj-$(CONFIG_I2C) += eeprom_at24c.o common-obj-y += fw_cfg.o common-obj-y += chrp_nvram.o common-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o -- cgit v1.1 From 6c549dc14113a8a389ef6cf8c9078df66e208ebd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 16 Jan 2018 16:11:50 +0100 Subject: exynos4210: workaround UBSAN compilation error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gcc 5.4.0-6ubuntu1~16.04.5 build with UBSAN enabled error: CC hw/display/exynos4210_fimd.o /home/petmay01/linaro/qemu-for-merges/hw/display/exynos4210_fimd.c: In function ‘fimd_get_buffer_id’: /home/petmay01/linaro/qemu-for-merges/hw/display/exynos4210_fimd.c:1105:5: error: case label does not reduce to an integer constant case FIMD_WINCON_BUF2_STAT: Because FIMD_WINCON_BUF2_STAT case contains an integer overflow, use U suffix to get the unsigned type. Signed-off-by: Marc-André Lureau Message-Id: <20180116151152.4040-2-marcandre.lureau@redhat.com> Signed-off-by: Paolo Bonzini --- hw/display/exynos4210_fimd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c index fd0b2be..86e37e9 100644 --- a/hw/display/exynos4210_fimd.c +++ b/hw/display/exynos4210_fimd.c @@ -98,7 +98,7 @@ #define FIMD_WINCON_BUFSTATUS ((1 << 21) | (1 << 31)) #define FIMD_WINCON_BUF0_STAT ((0 << 21) | (0 << 31)) #define FIMD_WINCON_BUF1_STAT ((1 << 21) | (0 << 31)) -#define FIMD_WINCON_BUF2_STAT ((0 << 21) | (1 << 31)) +#define FIMD_WINCON_BUF2_STAT ((0 << 21) | (1U << 31)) #define FIMD_WINCON_BUFSELECT ((1 << 20) | (1 << 30)) #define FIMD_WINCON_BUF0_SEL ((0 << 20) | (0 << 30)) #define FIMD_WINCON_BUF1_SEL ((1 << 20) | (0 << 30)) -- cgit v1.1 From 0750b060216de69ed1f14bc08181bf4ad27fc622 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Mon, 22 Jan 2018 14:02:41 +0800 Subject: vhost: add traces for memory listeners Trace these operations on two memory listeners. It helps to verify the new memory listener fix, and good to keep them there. Signed-off-by: Peter Xu Message-Id: <20180122060244.29368-2-peterx@redhat.com> Acked-by: Michael S. Tsirkin Reviewed-by: Paolo Bonzini Signed-off-by: Paolo Bonzini --- hw/virtio/trace-events | 6 ++++++ hw/virtio/vhost.c | 7 +++++++ 2 files changed, 13 insertions(+) (limited to 'hw') diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 775461a..2b8f81e 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -25,3 +25,9 @@ virtio_balloon_handle_output(const char *name, uint64_t gpa) "section name: %s g virtio_balloon_get_config(uint32_t num_pages, uint32_t actual) "num_pages: %d actual: %d" virtio_balloon_set_config(uint32_t actual, uint32_t oldactual) "actual: %d oldactual: %d" virtio_balloon_to_target(uint64_t target, uint32_t num_pages) "balloon target: 0x%"PRIx64" num_pages: %d" + +# hw/virtio/vhost.c +vhost_region_add(void *p, const char *mr) "dev %p mr %s" +vhost_region_del(void *p, const char *mr) "dev %p mr %s" +vhost_iommu_region_add(void *p, const char *mr) "dev %p mr %s" +vhost_iommu_region_del(void *p, const char *mr) "dev %p mr %s" diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 386aef8..c4f654c 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -27,6 +27,7 @@ #include "hw/virtio/virtio-access.h" #include "migration/blocker.h" #include "sysemu/dma.h" +#include "trace.h" /* enabled until disconnected backend stabilizes */ #define _VHOST_DEBUG 1 @@ -687,6 +688,7 @@ static void vhost_region_add(MemoryListener *listener, return; } + trace_vhost_region_add(dev, section->mr->name ?: NULL); ++dev->n_mem_sections; dev->mem_sections = g_renew(MemoryRegionSection, dev->mem_sections, dev->n_mem_sections); @@ -706,6 +708,7 @@ static void vhost_region_del(MemoryListener *listener, return; } + trace_vhost_region_del(dev, section->mr->name ?: NULL); vhost_set_memory(listener, section, false); memory_region_unref(section->mr); for (i = 0; i < dev->n_mem_sections; ++i) { @@ -743,6 +746,8 @@ static void vhost_iommu_region_add(MemoryListener *listener, return; } + trace_vhost_iommu_region_add(dev, section->mr->name ?: NULL); + iommu = g_malloc0(sizeof(*iommu)); end = int128_add(int128_make64(section->offset_within_region), section->size); @@ -771,6 +776,8 @@ static void vhost_iommu_region_del(MemoryListener *listener, return; } + trace_vhost_iommu_region_del(dev, section->mr->name ?: NULL); + QLIST_FOREACH(iommu, &dev->iommu_list, iommu_next) { if (iommu->mr == section->mr && iommu->n.start == section->offset_within_region) { -- cgit v1.1 From 369686267a4612d4000a1b67720c7f0aedd27539 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Mon, 22 Jan 2018 14:02:43 +0800 Subject: vfio: listener unregister before unset container After next patch, listener unregister will need the container to be alive. Let's move this unregister phase to be before unset container, since that operation will free the backend container in kernel, otherwise we'll get these after next patch: qemu-system-x86_64: VFIO_UNMAP_DMA: -22 qemu-system-x86_64: vfio_dma_unmap(0x559bf53a4590, 0x0, 0xa0000) = -22 (Invalid argument) Signed-off-by: Peter Xu Message-Id: <20180122060244.29368-4-peterx@redhat.com> Reviewed-by: Paolo Bonzini Acked-by: Alex Williamson Signed-off-by: Paolo Bonzini --- hw/vfio/common.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'hw') diff --git a/hw/vfio/common.c b/hw/vfio/common.c index b77be3a..76cf28d 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1161,19 +1161,27 @@ static void vfio_disconnect_container(VFIOGroup *group) { VFIOContainer *container = group->container; + QLIST_REMOVE(group, container_next); + group->container = NULL; + + /* + * Explicitly release the listener first before unset container, + * since unset may destroy the backend container if it's the last + * group. + */ + if (QLIST_EMPTY(&container->group_list)) { + vfio_listener_release(container); + } + if (ioctl(group->fd, VFIO_GROUP_UNSET_CONTAINER, &container->fd)) { error_report("vfio: error disconnecting group %d from container", group->groupid); } - QLIST_REMOVE(group, container_next); - group->container = NULL; - if (QLIST_EMPTY(&container->group_list)) { VFIOAddressSpace *space = container->space; VFIOGuestIOMMU *giommu, *tmp; - vfio_listener_release(container); QLIST_REMOVE(container, next); QLIST_FOREACH_SAFE(giommu, &container->giommu_list, giommu_next, tmp) { -- cgit v1.1 From d25836cafd7508090d211e97acfc0abc5ae88daa Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Mon, 22 Jan 2018 14:02:44 +0800 Subject: memory: do explicit cleanup when remove listeners When unregister memory listeners, we should call, e.g., region_del() (and possibly other undo operations) on every existing memory region sections there, otherwise we may leak resources that are held during the region_add(). This patch undo the stuff for the listeners, which emulates the case when the address space is set from current to an empty state. I found this problem when debugging a refcount leak issue that leads to a device unplug event lost (please see the "Bug:" line below). In that case, the leakage of resource is the PCI BAR memory region refcount. And since memory regions are not keeping their own refcount but onto their owners, so the vfio-pci device's (who is the owner of the PCI BAR memory regions) refcount is leaked, and event missing. We had encountered similar issues before and fixed in other way (ee4c112846, "vhost: Release memory references on cleanup"). This patch can be seen as a more high-level fix of similar problems that are caused by the resource leaks from memory listeners. So now we can remove the explicit unref of memory regions since that'll be done altogether during unregistering of listeners now. Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1531393 Signed-off-by: Peter Xu Message-Id: <20180122060244.29368-5-peterx@redhat.com> Reviewed-by: Paolo Bonzini Signed-off-by: Paolo Bonzini --- hw/virtio/vhost.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'hw') diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index c4f654c..d16c0c8 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1368,10 +1368,6 @@ void vhost_dev_cleanup(struct vhost_dev *hdev) if (hdev->mem) { /* those are only safe after successful init */ memory_listener_unregister(&hdev->memory_listener); - for (i = 0; i < hdev->n_mem_sections; ++i) { - MemoryRegionSection *section = &hdev->mem_sections[i]; - memory_region_unref(section->mr); - } QLIST_REMOVE(hdev, entry); } if (hdev->migration_blocker) { -- cgit v1.1 From e6a354be6ea0a52f5921f230a91518625247af82 Mon Sep 17 00:00:00 2001 From: Ladi Prosek Date: Mon, 11 Dec 2017 08:21:07 +0100 Subject: ivshmem: Don't update non-existent MSI routes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As of commit 660c97eef6f8 ("ivshmem: use kvm irqfd for msi notifications"), QEMU crashes with: kvm_irqchip_commit_routes: Assertion `ret == 0' failed. if the ivshmem device is configured with more vectors than what the server supports. This is caused by the ivshmem_vector_unmask() being called on vectors that have not been initialized by ivshmem_add_kvm_msi_virq(). This commit fixes it by adding a simple check to the mask and unmask callbacks. Note that the opposite mismatch, if the server supplies more vectors than what the device is configured for, is already handled and leads to output like: Too many eventfd received, device has 1 vectors To reproduce the assert, run: ivshmem-server -n 0 and QEMU with: -device ivshmem-doorbell,chardev=iv -chardev socket,path=/tmp/ivshmem_socket,id=iv then load the Windows driver, at the time of writing available at: https://github.com/virtio-win/kvm-guest-drivers-windows/tree/master/ivshmem The issue is believed to have been masked by other guest drivers, notably Linux ones, not enabling MSI-X on the device. Fixes: 660c97eef6f8 ("ivshmem: use kvm irqfd for msi notifications") Signed-off-by: Ladi Prosek Reviewed-by: Marc-André Lureau Reviewed-by: Markus Armbruster Message-Id: <20171211072110.9058-2-lprosek@redhat.com> Signed-off-by: Paolo Bonzini --- hw/misc/ivshmem.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 4919011..0b471d9 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -316,6 +316,10 @@ static int ivshmem_vector_unmask(PCIDevice *dev, unsigned vector, int ret; IVSHMEM_DPRINTF("vector unmask %p %d\n", dev, vector); + if (!v->pdev) { + error_report("ivshmem: vector %d route does not exist", vector); + return -EINVAL; + } ret = kvm_irqchip_update_msi_route(kvm_state, v->virq, msg, dev); if (ret < 0) { @@ -330,12 +334,16 @@ static void ivshmem_vector_mask(PCIDevice *dev, unsigned vector) { IVShmemState *s = IVSHMEM_COMMON(dev); EventNotifier *n = &s->peers[s->vm_id].eventfds[vector]; + MSIVector *v = &s->msi_vectors[vector]; int ret; IVSHMEM_DPRINTF("vector mask %p %d\n", dev, vector); + if (!v->pdev) { + error_report("ivshmem: vector %d route does not exist", vector); + return; + } - ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, - s->msi_vectors[vector].virq); + ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, v->virq); if (ret != 0) { error_report("remove_irqfd_notifier_gsi failed"); } -- cgit v1.1 From 089fd80376196adc0274a53eb9729c3ef7ee5ae7 Mon Sep 17 00:00:00 2001 From: Ladi Prosek Date: Mon, 11 Dec 2017 08:21:08 +0100 Subject: ivshmem: Always remove irqfd notifiers As of commit 660c97eef6f8 ("ivshmem: use kvm irqfd for msi notifications"), QEMU crashes with: ivshmem: msix_set_vector_notifiers failed msix_unset_vector_notifiers: Assertion `dev->msix_vector_use_notifier && dev->msix_vector_release_notifier' failed. if MSI-X is repeatedly enabled and disabled on the ivshmem device, for example by loading and unloading the Windows ivshmem driver. This is because msix_unset_vector_notifiers() doesn't call any of the release notifier callbacks since MSI-X is already disabled at that point (msix_enabled() returning false is how this transition is detected in the first place). Thus ivshmem_vector_mask() doesn't run and when MSI-X is subsequently enabled again ivshmem_vector_unmask() fails. This is fixed by keeping track of unmasked vectors and making sure that ivshmem_vector_mask() always runs on MSI-X disable. Fixes: 660c97eef6f8 ("ivshmem: use kvm irqfd for msi notifications") Signed-off-by: Ladi Prosek Reviewed-by: Markus Armbruster Message-Id: <20171211072110.9058-3-lprosek@redhat.com> Signed-off-by: Paolo Bonzini --- hw/misc/ivshmem.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) (limited to 'hw') diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 0b471d9..95e85e4 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -76,6 +76,7 @@ typedef struct Peer { typedef struct MSIVector { PCIDevice *pdev; int virq; + bool unmasked; } MSIVector; typedef struct IVShmemState { @@ -320,6 +321,7 @@ static int ivshmem_vector_unmask(PCIDevice *dev, unsigned vector, error_report("ivshmem: vector %d route does not exist", vector); return -EINVAL; } + assert(!v->unmasked); ret = kvm_irqchip_update_msi_route(kvm_state, v->virq, msg, dev); if (ret < 0) { @@ -327,7 +329,13 @@ static int ivshmem_vector_unmask(PCIDevice *dev, unsigned vector, } kvm_irqchip_commit_routes(kvm_state); - return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, v->virq); + ret = kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, v->virq); + if (ret < 0) { + return ret; + } + v->unmasked = true; + + return 0; } static void ivshmem_vector_mask(PCIDevice *dev, unsigned vector) @@ -342,11 +350,14 @@ static void ivshmem_vector_mask(PCIDevice *dev, unsigned vector) error_report("ivshmem: vector %d route does not exist", vector); return; } + assert(v->unmasked); ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, v->virq); - if (ret != 0) { + if (ret < 0) { error_report("remove_irqfd_notifier_gsi failed"); + return; } + v->unmasked = false; } static void ivshmem_vector_poll(PCIDevice *dev, @@ -816,11 +827,20 @@ static void ivshmem_disable_irqfd(IVShmemState *s) PCIDevice *pdev = PCI_DEVICE(s); int i; + msix_unset_vector_notifiers(pdev); + for (i = 0; i < s->peers[s->vm_id].nb_eventfds; i++) { + /* + * MSI-X is already disabled here so msix_unset_vector_notifiers() + * didn't call our release notifier. Do it now to keep our masks and + * unmasks balanced. + */ + if (s->msi_vectors[i].unmasked) { + ivshmem_vector_mask(pdev, i); + } ivshmem_remove_kvm_msi_virq(s, i); } - msix_unset_vector_notifiers(pdev); } static void ivshmem_write_config(PCIDevice *pdev, uint32_t address, -- cgit v1.1 From 0b88dd942073e7e65f095551d60be5dc0c8e1413 Mon Sep 17 00:00:00 2001 From: Ladi Prosek Date: Mon, 11 Dec 2017 08:21:09 +0100 Subject: ivshmem: Improve MSI irqfd error handling Adds a rollback path to ivshmem_enable_irqfd() and fixes ivshmem_disable_irqfd() to bail if irqfd has not been enabled. To reproduce, run: ivshmem-server -n 0 and QEMU with: -device ivshmem-doorbell,chardev=iv -chardev socket,path=/tmp/ivshmem_socket,id=iv then load, unload, and load again the Windows driver, at the time of writing available at: https://github.com/virtio-win/kvm-guest-drivers-windows/tree/master/ivshmem The issue is believed to have been masked by other guest drivers, notably Linux ones, not enabling MSI-X on the device. Signed-off-by: Ladi Prosek Reviewed-by: Markus Armbruster Message-Id: <20171211072110.9058-4-lprosek@redhat.com> Signed-off-by: Paolo Bonzini --- hw/misc/ivshmem.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) (limited to 'hw') diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 95e85e4..fe1d8d1 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -785,6 +785,20 @@ static int ivshmem_setup_interrupts(IVShmemState *s, Error **errp) return 0; } +static void ivshmem_remove_kvm_msi_virq(IVShmemState *s, int vector) +{ + IVSHMEM_DPRINTF("ivshmem_remove_kvm_msi_virq vector:%d\n", vector); + + if (s->msi_vectors[vector].pdev == NULL) { + return; + } + + /* it was cleaned when masked in the frontend. */ + kvm_irqchip_release_virq(kvm_state, s->msi_vectors[vector].virq); + + s->msi_vectors[vector].pdev = NULL; +} + static void ivshmem_enable_irqfd(IVShmemState *s) { PCIDevice *pdev = PCI_DEVICE(s); @@ -796,7 +810,7 @@ static void ivshmem_enable_irqfd(IVShmemState *s) ivshmem_add_kvm_msi_virq(s, i, &err); if (err) { error_report_err(err); - /* TODO do we need to handle the error? */ + goto undo; } } @@ -805,21 +819,14 @@ static void ivshmem_enable_irqfd(IVShmemState *s) ivshmem_vector_mask, ivshmem_vector_poll)) { error_report("ivshmem: msix_set_vector_notifiers failed"); + goto undo; } -} + return; -static void ivshmem_remove_kvm_msi_virq(IVShmemState *s, int vector) -{ - IVSHMEM_DPRINTF("ivshmem_remove_kvm_msi_virq vector:%d\n", vector); - - if (s->msi_vectors[vector].pdev == NULL) { - return; +undo: + while (--i >= 0) { + ivshmem_remove_kvm_msi_virq(s, i); } - - /* it was cleaned when masked in the frontend. */ - kvm_irqchip_release_virq(kvm_state, s->msi_vectors[vector].virq); - - s->msi_vectors[vector].pdev = NULL; } static void ivshmem_disable_irqfd(IVShmemState *s) @@ -827,6 +834,10 @@ static void ivshmem_disable_irqfd(IVShmemState *s) PCIDevice *pdev = PCI_DEVICE(s); int i; + if (!pdev->msix_vector_use_notifier) { + return; + } + msix_unset_vector_notifiers(pdev); for (i = 0; i < s->peers[s->vm_id].nb_eventfds; i++) { -- cgit v1.1 From a40227911c4cac4ac2551c57058d220baae4e91f Mon Sep 17 00:00:00 2001 From: Ladi Prosek Date: Mon, 11 Dec 2017 08:21:10 +0100 Subject: ivshmem: Disable irqfd on device reset The effects of ivshmem_enable_irqfd() was not undone on device reset. This manifested as: ivshmem_add_kvm_msi_virq: Assertion `!s->msi_vectors[vector].pdev' failed. when irqfd was enabled before reset and then enabled again after reset, making ivshmem_enable_irqfd() run for the second time. To reproduce, run: ivshmem-server and QEMU with: -device ivshmem-doorbell,chardev=iv -chardev socket,path=/tmp/ivshmem_socket,id=iv then install the Windows driver, at the time of writing available at: https://github.com/virtio-win/kvm-guest-drivers-windows/tree/master/ivshmem and crash-reboot the guest by inducing a BSOD. Signed-off-by: Ladi Prosek Message-Id: <20171211072110.9058-5-lprosek@redhat.com> Signed-off-by: Paolo Bonzini --- hw/misc/ivshmem.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'hw') diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index fe1d8d1..16f0370 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -757,10 +757,14 @@ static void ivshmem_msix_vector_use(IVShmemState *s) } } +static void ivshmem_disable_irqfd(IVShmemState *s); + static void ivshmem_reset(DeviceState *d) { IVShmemState *s = IVSHMEM_COMMON(d); + ivshmem_disable_irqfd(s); + s->intrstatus = 0; s->intrmask = 0; if (ivshmem_has_feature(s, IVSHMEM_MSI)) { -- cgit v1.1 From 0f2956f9159e4aecc9f4de6b8412a1d1ac5a2da0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 1 Feb 2018 14:27:51 +0100 Subject: memfd: add error argument, instead of perror() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will allow callers to silence error report when the call is allowed to failed. Signed-off-by: Marc-André Lureau Message-Id: <20180201132757.23063-2-marcandre.lureau@redhat.com> Signed-off-by: Paolo Bonzini --- hw/virtio/vhost.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index d16c0c8..338e439 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -330,6 +330,7 @@ static uint64_t vhost_get_log_size(struct vhost_dev *dev) static struct vhost_log *vhost_log_alloc(uint64_t size, bool share) { + Error *err = NULL; struct vhost_log *log; uint64_t logsize = size * sizeof(*(log->log)); int fd = -1; @@ -338,7 +339,12 @@ static struct vhost_log *vhost_log_alloc(uint64_t size, bool share) if (share) { log->log = qemu_memfd_alloc("vhost-log", logsize, F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL, - &fd); + &fd, &err); + if (err) { + error_report_err(err); + g_free(log); + return NULL; + } memset(log->log, 0, logsize); } else { log->log = g_malloc0(logsize); -- cgit v1.1