[PATCH][kvmtool] virtio/pci: Correctly handle MSI-X masking while MSI-X is disabled

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Since Linux commit 7d5ec3d36123 ("PCI/MSI: Mask all unused MSI-X
entries"), kvmtool segfaults when the guest boots and tries to
disable all the MSI-X entries of a virtio device while MSI-X itself
is disabled.

What Linux does is seems perfectly correct. However, kvmtool uses
a different decoding depending on whether MSI-X is enabled for
this device or not. Which seems pretty wrong.

Cure the problem by removing the check against MSI-X being enabled,
and simplify the whole logic which looked a bit odd. With this,
Linux is back booting as a kvmtool guest with MSI-X.

Cc: Andre Przywara <Andre.Przywara@xxxxxxx>
Cc: Alexandru Elisei <alexandru.elisei@xxxxxxx>
Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
Cc: Will Deacon <will@xxxxxxxxxx>
Signed-off-by: Marc Zyngier <maz@xxxxxxxxxx>
---
 include/kvm/virtio.h |  2 +-
 virtio/core.c        | 12 ++++--------
 virtio/pci.c         |  7 ++-----
 3 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/include/kvm/virtio.h b/include/kvm/virtio.h
index 3a311f54..7047d36f 100644
--- a/include/kvm/virtio.h
+++ b/include/kvm/virtio.h
@@ -166,7 +166,7 @@ u16 virt_queue__get_head_iov(struct virt_queue *vq, struct iovec iov[],
 u16 virt_queue__get_inout_iov(struct kvm *kvm, struct virt_queue *queue,
 			      struct iovec in_iov[], struct iovec out_iov[],
 			      u16 *in, u16 *out);
-int virtio__get_dev_specific_field(int offset, bool msix, u32 *config_off);
+int virtio__get_dev_specific_field(int offset, u32 *config_off);
 
 enum virtio_trans {
 	VIRTIO_PCI,
diff --git a/virtio/core.c b/virtio/core.c
index 90a661d1..afb09e90 100644
--- a/virtio/core.c
+++ b/virtio/core.c
@@ -169,16 +169,12 @@ void virtio_exit_vq(struct kvm *kvm, struct virtio_device *vdev,
 	memset(vq, 0, sizeof(*vq));
 }
 
-int virtio__get_dev_specific_field(int offset, bool msix, u32 *config_off)
+int virtio__get_dev_specific_field(int offset, u32 *config_off)
 {
-	if (msix) {
-		if (offset < 4)
-			return VIRTIO_PCI_O_MSIX;
-		else
-			offset -= 4;
-	}
+	if (offset < 24)
+		return VIRTIO_PCI_O_MSIX;
 
-	*config_off = offset;
+	*config_off = offset - 24;
 
 	return VIRTIO_PCI_O_CONFIG;
 }
diff --git a/virtio/pci.c b/virtio/pci.c
index eb91f512..2a6e41f1 100644
--- a/virtio/pci.c
+++ b/virtio/pci.c
@@ -112,9 +112,7 @@ static bool virtio_pci__specific_data_in(struct kvm *kvm, struct virtio_device *
 {
 	u32 config_offset;
 	struct virtio_pci *vpci = vdev->virtio;
-	int type = virtio__get_dev_specific_field(offset - 20,
-							virtio_pci__msix_enabled(vpci),
-							&config_offset);
+	int type = virtio__get_dev_specific_field(offset, &config_offset);
 	if (type == VIRTIO_PCI_O_MSIX) {
 		switch (offset) {
 		case VIRTIO_MSI_CONFIG_VECTOR:
@@ -208,8 +206,7 @@ static bool virtio_pci__specific_data_out(struct kvm *kvm, struct virtio_device
 	struct virtio_pci *vpci = vdev->virtio;
 	u32 config_offset, vec;
 	int gsi;
-	int type = virtio__get_dev_specific_field(offset - 20, virtio_pci__msix_enabled(vpci),
-							&config_offset);
+	int type = virtio__get_dev_specific_field(offset, &config_offset);
 	if (type == VIRTIO_PCI_O_MSIX) {
 		switch (offset) {
 		case VIRTIO_MSI_CONFIG_VECTOR:
-- 
2.30.2




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux