Skip to contentSkip to conversation

virtio-balloon: make it spec compliant

PATCH In review Michael S. Tsirkin 6 participants 16 messages Jul 10, 2024 – Jul 16, 2024

Subsystems (8)
lore
Share & tools
lore

Michael S. Tsirkin

author maintainer
#0 lore raw

v2 cover virtio-balloon: make it spec compliant

Currently, if VIRTIO_BALLOON_F_FREE_PAGE_HINT is off but VIRTIO_BALLOON_F_REPORTING is on, then the reporting vq gets number 3 while spec says it's number 4.
It happens to work because the qemu virtio pci driver is *also* out of spec.

To fix:
1. add vq4 as per spec
2. to help out the buggy qemu driver, if finding vqs fail, try with vq3 as reporting.

Fixes b0c504f15471 ("virtio-balloon: add support for providing free page reports to host")
Cc "Alexander Duyck" <[email protected]>

Changes from v1:
rebased on vhost tip

Michael S. Tsirkin (2):
virtio_balloon: add work around for out of spec QEMU
virtio: fix vq # for balloon

 arch/um/drivers/virtio_uml.c           |  4 ++--
 drivers/remoteproc/remoteproc_virtio.c |  4 ++--
 drivers/s390/virtio/virtio_ccw.c       |  4 ++--
 drivers/virtio/virtio_balloon.c        | 19 +++++++++++++++++--
 drivers/virtio/virtio_mmio.c           |  4 ++--
 drivers/virtio/virtio_pci_common.c     | 11 ++++++++---
 drivers/virtio/virtio_vdpa.c           |  4 ++--
 7 files changed, 35 insertions(+), 15 deletions(-)
Signature · 1 line
MST
author maintainer
#1 lore raw

PATCH v2 1/2 virtio_balloon: add work around for out of spec QEMU

QEMU implemented the configuration

	VIRTIO_BALLOON_F_REPORTING && ! VIRTIO_BALLOON_F_FREE_PAGE_HINT

incorrectly: it then uses vq3 for reporting, spec says it is always 4.

This is masked by a corresponding bug in driver:
add a work around as I'm going to try and fix the driver bug.

Message-ID: <[email protected]>

Fixes b0c504f15471 ("virtio-balloon: add support for providing free page reports to host")
Cc "Alexander Duyck" <[email protected]>
---
 drivers/virtio/virtio_balloon.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)
drivers/virtio/virtio_balloon.c +17 -2
index 54469277ca30..eebeab863697 100644
@@ -589,8 +589,23 @@ static int init_vqs(struct virtio_balloon *vb)
 
 	err = virtio_find_vqs(vb->vdev, VIRTIO_BALLOON_VQ_MAX, vqs,
 			      vqs_info, NULL);
-	if (err)
-		return err;
+	if (err) {
+		/*
+		 * Try to work around QEMU bug which since 2020 confused vq numbers
+		 * when VIRTIO_BALLOON_F_REPORTING but not
+		 * VIRTIO_BALLOON_F_FREE_PAGE_HINT are offered.
+		 */
+		if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_REPORTING) &&
+		    !virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) {
+			vqs_info[VIRTIO_BALLOON_VQ_FREE_PAGE].name = "reporting_vq";
+			vqs_info[VIRTIO_BALLOON_VQ_FREE_PAGE].callback = balloon_ack;
+			err = virtio_find_vqs(vb->vdev,
+					      VIRTIO_BALLOON_VQ_REPORTING, vqs_info, NULL);
+		}
+
+		if (err)
+			return err;
+	}
 
 	vb->inflate_vq = vqs[VIRTIO_BALLOON_VQ_INFLATE];
 	vb->deflate_vq = vqs[VIRTIO_BALLOON_VQ_DEFLATE];
Signature · 1 line
MST
#2 lore raw

Re: [PATCH v2 1/2] virtio_balloon: add work around for out of spec QEMU

kernel test robot noticed the following build errors:

Hi Michael,

kernel test robot noticed the following build errors:

[auto build test ERROR on next-20240710]
[cannot apply to uml/next remoteproc/rproc-next s390/features linus/master uml/fixes v6.10-rc7 v6.10-rc6 v6.10-rc5 v6.10-rc7] [If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Michael-S-Tsirkin/virtio_balloon-add-work-around-for-out-of-spec-QEMU/20240711-004346
base:   next-20240710
patch link:    https://lore.kernel.org/r/19d916257b76148f89de7386389eeb7267b1b61c.1720611677.git.mst%40redhat.com
patch subject: [PATCH v2 1/2] virtio_balloon: add work around for out of spec QEMU
config: i386-randconfig-005-20240711 (https://download.01.org/0day-ci/archive/20240711/[email protected]/config)
compiler: clang version 18.1.5 (https://github.com/llvm/llvm-project 617a15a9eac96088ae5e9134248d8236e34b91b1)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240711/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

>> drivers/virtio/virtio_balloon.c:603:55: error: too few arguments to function call, expected 5, have 4
     602 |                         err = virtio_find_vqs(vb->vdev,
         |                               ~~~~~~~~~~~~~~~
     603 |                                               VIRTIO_BALLOON_VQ_REPORTING, vqs_info, NULL);
         |                                                                                          ^
   include/linux/virtio_config.h:225:5: note: 'virtio_find_vqs' declared here
     225 | int virtio_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
         |     ^               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     226 |                     struct virtqueue *vqs[],
         |                     ~~~~~~~~~~~~~~~~~~~~~~~~
     227 |                     struct virtqueue_info vqs_info[],
         |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     228 |                     struct irq_affinity *desc)
         |                     ~~~~~~~~~~~~~~~~~~~~~~~~~

1 error generated.

vim +603 drivers/virtio/virtio_balloon.c

560
561 static int init_vqs(struct virtio_balloon *vb)
562 {
563 struct virtqueue_info vqs_info[VIRTIO_BALLOON_VQ_MAX] = {};
564 struct virtqueue *vqs[VIRTIO_BALLOON_VQ_MAX];
565 int err;
566
567 /*
568 * Inflateq and deflateq are used unconditionally. The names[]
569 * will be NULL if the related feature is not enabled, which will
570 * cause no allocation for the corresponding virtqueue in find_vqs.
571 */
572 vqs_info[VIRTIO_BALLOON_VQ_INFLATE].callback = balloon_ack;
573 vqs_info[VIRTIO_BALLOON_VQ_INFLATE].name = "inflate";
574 vqs_info[VIRTIO_BALLOON_VQ_DEFLATE].callback = balloon_ack;
575 vqs_info[VIRTIO_BALLOON_VQ_DEFLATE].name = "deflate";
576
577 if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ)) {
578 vqs_info[VIRTIO_BALLOON_VQ_STATS].name = "stats";
579 vqs_info[VIRTIO_BALLOON_VQ_STATS].callback = stats_request;
580 }
581
582 if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
583 vqs_info[VIRTIO_BALLOON_VQ_FREE_PAGE].name = "free_page_vq";
584
585 if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_REPORTING)) {
586 vqs_info[VIRTIO_BALLOON_VQ_REPORTING].name = "reporting_vq";
587 vqs_info[VIRTIO_BALLOON_VQ_REPORTING].callback = balloon_ack;
588 }
589
590 err = virtio_find_vqs(vb->vdev, VIRTIO_BALLOON_VQ_MAX, vqs,
591 vqs_info, NULL);
592 if (err) {
593 /*
594 * Try to work around QEMU bug which since 2020 confused vq numbers
595 * when VIRTIO_BALLOON_F_REPORTING but not
596 * VIRTIO_BALLOON_F_FREE_PAGE_HINT are offered.
597 */
598 if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_REPORTING) &&
599 !virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) {
600 vqs_info[VIRTIO_BALLOON_VQ_FREE_PAGE].name = "reporting_vq";
601 vqs_info[VIRTIO_BALLOON_VQ_FREE_PAGE].callback = balloon_ack;
602 err = virtio_find_vqs(vb->vdev,

 > 603						      VIRTIO_BALLOON_VQ_REPORTING, vqs_info, NULL);

604 }
605
606 if (err)
607 return err;
608 }
609
610 vb->inflate_vq = vqs[VIRTIO_BALLOON_VQ_INFLATE];
611 vb->deflate_vq = vqs[VIRTIO_BALLOON_VQ_DEFLATE];
612 if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ)) {
613 struct scatterlist sg;
614 unsigned int num_stats;
615 vb->stats_vq = vqs[VIRTIO_BALLOON_VQ_STATS];
616
617 /*
618 * Prime this virtqueue with one buffer so the hypervisor can
619 * use it to signal us later (it can't be broken yet!).
620 */
621 num_stats = update_balloon_stats(vb);
622
623 sg_init_one(&sg, vb->stats, sizeof(vb->stats[0]) * num_stats);
624 err = virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb,
625 GFP_KERNEL);
626 if (err) {
627 dev_warn(&vb->vdev->dev, "%s: add stat_vq failed\n",
628 __func__);
629 return err;
630 }
631 virtqueue_kick(vb->stats_vq);
632 }
633
634 if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
635 vb->free_page_vq = vqs[VIRTIO_BALLOON_VQ_FREE_PAGE];
636
637 if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_REPORTING))
638 vb->reporting_vq = vqs[VIRTIO_BALLOON_VQ_REPORTING];
639
640 return 0;
641 }
642

Signature · 2 lines
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
author maintainer
#3 lore raw

PATCH v2 2/2 virtio: fix vq # for balloon

In reply to Michael S. Tsirkin

virtio balloon communicates to the core that in some configurations vq #s are non-contiguous by setting name pointer to NULL.

Unfortunately, core then turned around and just made them contiguous again. Result is that driver is out of spec.

Implement what the API was supposed to do
in the 1st place. Compatibility with buggy hypervisors is handled inside virtio-balloon, which is the only driver making use of this facility, so far.

Message-ID: <[email protected]>

Fixes b0c504f15471 ("virtio-balloon: add support for providing free page reports to host")
Cc "Alexander Duyck" <[email protected]>
---
 arch/um/drivers/virtio_uml.c           |  4 ++--
 drivers/remoteproc/remoteproc_virtio.c |  4 ++--
 drivers/s390/virtio/virtio_ccw.c       |  4 ++--
 drivers/virtio/virtio_mmio.c           |  4 ++--
 drivers/virtio/virtio_pci_common.c     | 11 ++++++++---
 drivers/virtio/virtio_vdpa.c           |  4 ++--
 6 files changed, 18 insertions(+), 13 deletions(-)
arch/um/drivers/virtio_uml.c +2 -2
index 2b6e701776b6..c903e4959f51 100644
@@ -1019,7 +1019,7 @@ static int vu_find_vqs(struct virtio_device *vdev, unsigned nvqs,
 		       struct irq_affinity *desc)
 {
 	struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev);
-	int i, queue_idx = 0, rc;
+	int i, rc;
 	struct virtqueue *vq;
 
 	/* not supported for now */
@@ -1038,7 +1038,7 @@ static int vu_find_vqs(struct virtio_device *vdev, unsigned nvqs,
 			continue;
 		}
 
-		vqs[i] = vu_setup_vq(vdev, queue_idx++, vqi->callback,
+		vqs[i] = vu_setup_vq(vdev, i, vqi->callback,
 				     vqi->name, vqi->ctx);
 		if (IS_ERR(vqs[i])) {
 			rc = PTR_ERR(vqs[i]);
drivers/remoteproc/remoteproc_virtio.c +2 -2
index d3f39009b28e..1019b2825c26 100644
@@ -185,7 +185,7 @@ static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
 				 struct virtqueue_info vqs_info[],
 				 struct irq_affinity *desc)
 {
-	int i, ret, queue_idx = 0;
+	int i, ret;
 
 	for (i = 0; i < nvqs; ++i) {
 		struct virtqueue_info *vqi = &vqs_info[i];
@@ -195,7 +195,7 @@ static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
 			continue;
 		}
 
-		vqs[i] = rp_find_vq(vdev, queue_idx++, vqi->callback,
+		vqs[i] = rp_find_vq(vdev, i, vqi->callback,
 				    vqi->name, vqi->ctx);
 		if (IS_ERR(vqs[i])) {
 			ret = PTR_ERR(vqs[i]);
drivers/s390/virtio/virtio_ccw.c +2 -2
index 62eca9419ad7..82a3440bbabb 100644
@@ -694,7 +694,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
 {
 	struct virtio_ccw_device *vcdev = to_vc_device(vdev);
 	dma64_t *indicatorp = NULL;
-	int ret, i, queue_idx = 0;
+	int ret, i;
 	struct ccw1 *ccw;
 	dma32_t indicatorp_dma = 0;
 
@@ -710,7 +710,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
 			continue;
 		}
 
-		vqs[i] = virtio_ccw_setup_vq(vdev, queue_idx++, vqi->callback,
+		vqs[i] = virtio_ccw_setup_vq(vdev, i, vqi->callback,
 					     vqi->name, vqi->ctx, ccw);
 		if (IS_ERR(vqs[i])) {
 			ret = PTR_ERR(vqs[i]);
drivers/virtio/virtio_mmio.c +2 -2
index 90e784e7b721..db6a0366f082 100644
@@ -494,7 +494,7 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
 {
 	struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
 	int irq = platform_get_irq(vm_dev->pdev, 0);
-	int i, err, queue_idx = 0;
+	int i, err;
 
 	if (irq < 0)
 		return irq;
@@ -515,7 +515,7 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
 			continue;
 		}
 
-		vqs[i] = vm_setup_vq(vdev, queue_idx++, vqi->callback,
+		vqs[i] = vm_setup_vq(vdev, i, vqi->callback,
 				     vqi->name, vqi->ctx);
 		if (IS_ERR(vqs[i])) {
 			vm_del_vqs(vdev);
drivers/virtio/virtio_pci_common.c +8 -3
index 7d82facafd75..fa606e7321ad 100644
@@ -293,7 +293,7 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs,
 	struct virtio_pci_device *vp_dev = to_vp_device(vdev);
 	struct virtqueue_info *vqi;
 	u16 msix_vec;
-	int i, err, nvectors, allocated_vectors, queue_idx = 0;
+	int i, err, nvectors, allocated_vectors;
 
 	vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL);
 	if (!vp_dev->vqs)
@@ -332,7 +332,7 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs,
 			msix_vec = allocated_vectors++;
 		else
 			msix_vec = VP_MSIX_VQ_VECTOR;
-		vqs[i] = vp_setup_vq(vdev, queue_idx++, vqi->callback,
+		vqs[i] = vp_setup_vq(vdev, i, vqi->callback,
 				     vqi->name, vqi->ctx, msix_vec);
 		if (IS_ERR(vqs[i])) {
 			err = PTR_ERR(vqs[i]);
@@ -368,7 +368,7 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs,
 			    struct virtqueue_info vqs_info[])
 {
 	struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-	int i, err, queue_idx = 0;
+	int i, err;
 
 	vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL);
 	if (!vp_dev->vqs)
@@ -388,8 +388,13 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs,
 			vqs[i] = NULL;
 			continue;
 		}
+<<<<<<< HEAD
 		vqs[i] = vp_setup_vq(vdev, queue_idx++, vqi->callback,
 				     vqi->name, vqi->ctx,
+=======
+		vqs[i] = vp_setup_vq(vdev, i, callbacks[i], names[i],
+				     ctx ? ctx[i] : false,
+>>>>>>> f814759f80b7... virtio: fix vq # for balloon
 				     VIRTIO_MSI_NO_VECTOR);
 		if (IS_ERR(vqs[i])) {
 			err = PTR_ERR(vqs[i]);
drivers/virtio/virtio_vdpa.c +2 -2
index 7364bd53e38d..149e893583e9 100644
@@ -368,7 +368,7 @@ static int virtio_vdpa_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
 	struct cpumask *masks;
 	struct vdpa_callback cb;
 	bool has_affinity = desc && ops->set_vq_affinity;
-	int i, err, queue_idx = 0;
+	int i, err;
 
 	if (has_affinity) {
 		masks = create_affinity_masks(nvqs, desc ? desc : &default_affd);
@@ -384,7 +384,7 @@ static int virtio_vdpa_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
 			continue;
 		}
 
-		vqs[i] = virtio_vdpa_setup_vq(vdev, queue_idx++, vqi->callback,
+		vqs[i] = virtio_vdpa_setup_vq(vdev, i, vqi->callback,
 					      vqi->name, vqi->ctx);
 		if (IS_ERR(vqs[i])) {
 			err = PTR_ERR(vqs[i]);
Signature · 1 line
MST
maintainer Reviewed-by on v2 2/2
#4 lore raw

Re: [PATCH v2 2/2] virtio: fix vq # for balloon

Quoted 13 lines · Michael S. Tsirkin

virtio balloon communicates to the core that in some configurations vq #s are non-contiguous by setting name pointer to NULL.

Unfortunately, core then turned around and just made them contiguous again. Result is that driver is out of spec.

Implement what the API was supposed to do
in the 1st place. Compatibility with buggy hypervisors is handled inside virtio-balloon, which is the only driver making use of this facility, so far.

Quoted 7 lines

Message-ID: <[email protected]>

Fixes b0c504f15471 ("virtio-balloon: add support for providing free page reports to host")
Cc "Alexander Duyck" <[email protected]>
---
 arch/um/drivers/virtio_uml.c           |  4 ++--
 drivers/remoteproc/remoteproc_virtio.c |  4 ++--
Quoted 164 lines
 drivers/s390/virtio/virtio_ccw.c       |  4 ++--
 drivers/virtio/virtio_mmio.c           |  4 ++--
 drivers/virtio/virtio_pci_common.c     | 11 ++++++++---
 drivers/virtio/virtio_vdpa.c           |  4 ++--
 6 files changed, 18 insertions(+), 13 deletions(-)
arch/um/drivers/virtio_uml.c +2 -2
index 2b6e701776b6..c903e4959f51 100644
@@ -1019,7 +1019,7 @@ static int vu_find_vqs(struct virtio_device *vdev, unsigned nvqs,
                       struct irq_affinity *desc)
 {
        struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev);
-       int i, queue_idx = 0, rc;
+       int i, rc;
        struct virtqueue *vq;
 
        /* not supported for now */
@@ -1038,7 +1038,7 @@ static int vu_find_vqs(struct virtio_device *vdev, unsigned nvqs,
                        continue;
                }
 
-               vqs[i] = vu_setup_vq(vdev, queue_idx++, vqi->callback,
+               vqs[i] = vu_setup_vq(vdev, i, vqi->callback,
                                     vqi->name, vqi->ctx);
                if (IS_ERR(vqs[i])) {
                        rc = PTR_ERR(vqs[i]);
drivers/remoteproc/remoteproc_virtio.c +2 -2
index d3f39009b28e..1019b2825c26 100644
@@ -185,7 +185,7 @@ static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
                                 struct virtqueue_info vqs_info[],
                                 struct irq_affinity *desc)
 {
-       int i, ret, queue_idx = 0;
+       int i, ret;
 
        for (i = 0; i < nvqs; ++i) {
                struct virtqueue_info *vqi = &vqs_info[i];
@@ -195,7 +195,7 @@ static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
                        continue;
                }
 
-               vqs[i] = rp_find_vq(vdev, queue_idx++, vqi->callback,
+               vqs[i] = rp_find_vq(vdev, i, vqi->callback,
                                    vqi->name, vqi->ctx);
                if (IS_ERR(vqs[i])) {
                        ret = PTR_ERR(vqs[i]);
drivers/s390/virtio/virtio_ccw.c +2 -2
index 62eca9419ad7..82a3440bbabb 100644
@@ -694,7 +694,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
 {
        struct virtio_ccw_device *vcdev = to_vc_device(vdev);
        dma64_t *indicatorp = NULL;
-       int ret, i, queue_idx = 0;
+       int ret, i;
        struct ccw1 *ccw;
        dma32_t indicatorp_dma = 0;
 
@@ -710,7 +710,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
                        continue;
                }
 
-               vqs[i] = virtio_ccw_setup_vq(vdev, queue_idx++, vqi->callback,
+               vqs[i] = virtio_ccw_setup_vq(vdev, i, vqi->callback,
                                             vqi->name, vqi->ctx, ccw);
                if (IS_ERR(vqs[i])) {
                        ret = PTR_ERR(vqs[i]);
drivers/virtio/virtio_mmio.c +2 -2
index 90e784e7b721..db6a0366f082 100644
@@ -494,7 +494,7 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
 {
        struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
        int irq = platform_get_irq(vm_dev->pdev, 0);
-       int i, err, queue_idx = 0;
+       int i, err;
 
        if (irq < 0)
                return irq;
@@ -515,7 +515,7 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
                        continue;
                }
 
-               vqs[i] = vm_setup_vq(vdev, queue_idx++, vqi->callback,
+               vqs[i] = vm_setup_vq(vdev, i, vqi->callback,
                                     vqi->name, vqi->ctx);
                if (IS_ERR(vqs[i])) {
                        vm_del_vqs(vdev);
drivers/virtio/virtio_pci_common.c +8 -3
index 7d82facafd75..fa606e7321ad 100644
@@ -293,7 +293,7 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs,
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
        struct virtqueue_info *vqi;
        u16 msix_vec;
-       int i, err, nvectors, allocated_vectors, queue_idx = 0;
+       int i, err, nvectors, allocated_vectors;
 
        vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL);
        if (!vp_dev->vqs)
@@ -332,7 +332,7 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs,
                        msix_vec = allocated_vectors++;
                else
                        msix_vec = VP_MSIX_VQ_VECTOR;
-               vqs[i] = vp_setup_vq(vdev, queue_idx++, vqi->callback,
+               vqs[i] = vp_setup_vq(vdev, i, vqi->callback,
                                     vqi->name, vqi->ctx, msix_vec);
                if (IS_ERR(vqs[i])) {
                        err = PTR_ERR(vqs[i]);
@@ -368,7 +368,7 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs,
                            struct virtqueue_info vqs_info[])
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-       int i, err, queue_idx = 0;
+       int i, err;
 
        vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL);
        if (!vp_dev->vqs)
@@ -388,8 +388,13 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs,
                        vqs[i] = NULL;
                        continue;
                }
+<<<<<<< HEAD
                vqs[i] = vp_setup_vq(vdev, queue_idx++, vqi->callback,
                                     vqi->name, vqi->ctx,
+=======
+               vqs[i] = vp_setup_vq(vdev, i, callbacks[i], names[i],
+                                    ctx ? ctx[i] : false,
+>>>>>>> f814759f80b7... virtio: fix vq # for balloon
                                     VIRTIO_MSI_NO_VECTOR);
                if (IS_ERR(vqs[i])) {
                        err = PTR_ERR(vqs[i]);
drivers/virtio/virtio_vdpa.c +2 -3
index 7364bd53e38d..149e893583e9 100644
@@ -368,7 +368,7 @@ static int virtio_vdpa_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
        struct cpumask *masks;
        struct vdpa_callback cb;
        bool has_affinity = desc && ops->set_vq_affinity;
-       int i, err, queue_idx = 0;
+       int i, err;
 
        if (has_affinity) {
                masks = create_affinity_masks(nvqs, desc ? desc : &default_affd);
@@ -384,7 +384,7 @@ static int virtio_vdpa_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
                        continue;
                }
 
-               vqs[i] = virtio_vdpa_setup_vq(vdev, queue_idx++, vqi->callback,
+               vqs[i] = virtio_vdpa_setup_vq(vdev, i, vqi->callback,
                                              vqi->name, vqi->ctx);
                if (IS_ERR(vqs[i])) {
                        err = PTR_ERR(vqs[i]);
--

MST

#5 lore raw

Re: [PATCH v2 2/2] virtio: fix vq # for balloon

In reply to Michael S. Tsirkin
Quoted 7 lines · Michael S. Tsirkin

virtio balloon communicates to the core that in some configurations vq #s are non-contiguous by setting name pointer to NULL.

Unfortunately, core then turned around and just made them contiguous again. Result is that driver is out of spec.

Thanks for fixing this - I think the overall approach of the patch looks good.

Quoted 4 lines

Implement what the API was supposed to do
in the 1st place. Compatibility with buggy hypervisors is handled inside virtio-balloon, which is the only driver making use of this facility, so far.

In addition to virtio-balloon, I believe the same problem also affects the virtio-fs device, since queue 1 is only supposed to be present if VIRTIO_FS_F_NOTIFICATION is negotiated, and the request queues are meant to be queue indexes 2 and up. From a look at the Linux driver (virtio_fs.c), it appears like it never acks VIRTIO_FS_F_NOTIFICATION and assumes that request queues start at index 1 rather than 2, which looks out of spec to me, but the current device implementations (that I am aware of, anyway) are also broken in the same way, so it ends up working today. Queue numbering in a spec-compliant device and the current Linux driver would mismatch; what the driver considers to be the first request queue (index 1) would be ignored by the device since queue index 1 has no function if F_NOTIFICATION isn't negotiated.

[...]

Quoted 32 lines
drivers/virtio/virtio_pci_common.c +3 -3
index 7d82facafd75..fa606e7321ad 100644
@@ -293,7 +293,7 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs,
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
        struct virtqueue_info *vqi;
        u16 msix_vec;
-       int i, err, nvectors, allocated_vectors, queue_idx = 0;
+       int i, err, nvectors, allocated_vectors;
 
        vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL);
        if (!vp_dev->vqs)
@@ -332,7 +332,7 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs,
                        msix_vec = allocated_vectors++;
                else
                        msix_vec = VP_MSIX_VQ_VECTOR;
-               vqs[i] = vp_setup_vq(vdev, queue_idx++, vqi->callback,
+               vqs[i] = vp_setup_vq(vdev, i, vqi->callback,
                                     vqi->name, vqi->ctx, msix_vec);
                if (IS_ERR(vqs[i])) {
                        err = PTR_ERR(vqs[i]);
@@ -368,7 +368,7 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs,
                            struct virtqueue_info vqs_info[])
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-       int i, err, queue_idx = 0;
+       int i, err;
 
        vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL);
        if (!vp_dev->vqs)

drivers/virtio/virtio_pci_common.c static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs, · line 397

Quoted 10 lines
drivers/virtio/virtio_pci_common.c +5 -0
@@ -388,8 +388,13 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs,
                        vqs[i] = NULL;
                        continue;
                }
+<<<<<<< HEAD
                vqs[i] = vp_setup_vq(vdev, queue_idx++, vqi->callback,
                                     vqi->name, vqi->ctx,
+=======
+               vqs[i] = vp_setup_vq(vdev, i, callbacks[i], names[i],
+                                    ctx ? ctx[i] : false,
+>>>>>>> f814759f80b7... virtio: fix vq # for balloon

This still has merge markers in it.

Thanks,
-- Daniel

author maintainer
#6 lore raw

Re: [PATCH v2 2/2] virtio: fix vq # for balloon

Quoted 16 lines · Daniel Verkamp
Quoted 7 lines · Michael S. Tsirkin

virtio balloon communicates to the core that in some configurations vq #s are non-contiguous by setting name pointer to NULL.

Unfortunately, core then turned around and just made them contiguous again. Result is that driver is out of spec.

Thanks for fixing this - I think the overall approach of the patch looks good.

Quoted 4 lines

Implement what the API was supposed to do
in the 1st place. Compatibility with buggy hypervisors is handled inside virtio-balloon, which is the only driver making use of this facility, so far.

Quoted 12 lines

In addition to virtio-balloon, I believe the same problem also affects the virtio-fs device, since queue 1 is only supposed to be present if VIRTIO_FS_F_NOTIFICATION is negotiated, and the request queues are meant to be queue indexes 2 and up. From a look at the Linux driver (virtio_fs.c), it appears like it never acks VIRTIO_FS_F_NOTIFICATION and assumes that request queues start at index 1 rather than 2, which looks out of spec to me, but the current device implementations (that I am aware of, anyway) are also broken in the same way, so it ends up working today. Queue numbering in a spec-compliant device and the current Linux driver would mismatch; what the driver considers to be the first request queue (index 1) would be ignored by the device since queue index 1 has no function if F_NOTIFICATION isn't negotiated.

Oh, thanks a lot for pointing this out!

I see so this patch is no good as is, we need to add a workaround for virtio-fs first.

QEMU workaround is simple - just add an extra queue. But I did not reasearch how this would interact with vhost-user.

From driver POV, I guess we could just ignore queue # 1 - would that be ok or does it have performance implications?
Or do what I did for balloon here: try with spec compliant #s first, if that fails then assume it's the spec issue and shift by 1.

Quoted 48 lines

[...]

Quoted 32 lines
drivers/virtio/virtio_pci_common.c +3 -3
index 7d82facafd75..fa606e7321ad 100644
@@ -293,7 +293,7 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs,
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
        struct virtqueue_info *vqi;
        u16 msix_vec;
-       int i, err, nvectors, allocated_vectors, queue_idx = 0;
+       int i, err, nvectors, allocated_vectors;
 
        vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL);
        if (!vp_dev->vqs)
@@ -332,7 +332,7 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs,
                        msix_vec = allocated_vectors++;
                else
                        msix_vec = VP_MSIX_VQ_VECTOR;
-               vqs[i] = vp_setup_vq(vdev, queue_idx++, vqi->callback,
+               vqs[i] = vp_setup_vq(vdev, i, vqi->callback,
                                     vqi->name, vqi->ctx, msix_vec);
                if (IS_ERR(vqs[i])) {
                        err = PTR_ERR(vqs[i]);
@@ -368,7 +368,7 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs,
                            struct virtqueue_info vqs_info[])
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-       int i, err, queue_idx = 0;
+       int i, err;
 
        vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL);
        if (!vp_dev->vqs)

drivers/virtio/virtio_pci_common.c static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs, · line 397

Quoted 10 lines
drivers/virtio/virtio_pci_common.c +5 -0
@@ -388,8 +388,13 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs,
                        vqs[i] = NULL;
                        continue;
                }
+<<<<<<< HEAD
                vqs[i] = vp_setup_vq(vdev, queue_idx++, vqi->callback,
                                     vqi->name, vqi->ctx,
+=======
+               vqs[i] = vp_setup_vq(vdev, i, callbacks[i], names[i],
+                                    ctx ? ctx[i] : false,
+>>>>>>> f814759f80b7... virtio: fix vq # for balloon

This still has merge markers in it.

Thanks,
-- Daniel

#7 lore raw

Re: [PATCH v2 2/2] virtio: fix vq # for balloon

Quoted 34 lines · Michael S. Tsirkin
Quoted 16 lines · Daniel Verkamp
Quoted 7 lines · Michael S. Tsirkin

virtio balloon communicates to the core that in some configurations vq #s are non-contiguous by setting name pointer to NULL.

Unfortunately, core then turned around and just made them contiguous again. Result is that driver is out of spec.

Thanks for fixing this - I think the overall approach of the patch looks good.

Quoted 4 lines

Implement what the API was supposed to do
in the 1st place. Compatibility with buggy hypervisors is handled inside virtio-balloon, which is the only driver making use of this facility, so far.

Quoted 12 lines

In addition to virtio-balloon, I believe the same problem also affects the virtio-fs device, since queue 1 is only supposed to be present if VIRTIO_FS_F_NOTIFICATION is negotiated, and the request queues are meant to be queue indexes 2 and up. From a look at the Linux driver (virtio_fs.c), it appears like it never acks VIRTIO_FS_F_NOTIFICATION and assumes that request queues start at index 1 rather than 2, which looks out of spec to me, but the current device implementations (that I am aware of, anyway) are also broken in the same way, so it ends up working today. Queue numbering in a spec-compliant device and the current Linux driver would mismatch; what the driver considers to be the first request queue (index 1) would be ignored by the device since queue index 1 has no function if F_NOTIFICATION isn't negotiated.

Oh, thanks a lot for pointing this out!

Quoted 8 lines

I see so this patch is no good as is, we need to add a workaround for virtio-fs first.

QEMU workaround is simple - just add an extra queue. But I did not reasearch how this would interact with vhost-user.

From driver POV, I guess we could just ignore queue # 1 - would that be ok or does it have performance implications?

As a driver workaround for non-compliant devices, I think ignoring the first request queue would be a reasonable approach if the device's config advertises num_request_queues > 1. Unfortunately, both virtiofsd and crosvm's virtio-fs device have hard-coded num_request_queues =1, so this won't help with those existing devices. Maybe there are other devices that we would need to consider as well; commit 529395d2ae64 ("virtio-fs: add multi-queue support") quotes benchmarks that seem to be from a different virtio-fs implementation that does support multiple request queues, so the workaround could possibly be used there.

Quoted 2 lines

Or do what I did for balloon here: try with spec compliant #s first, if that fails then assume it's the spec issue and shift by 1.

If there is a way to "guess and check" without breaking spec-compliant devices, that sounds reasonable too; however, I'm not sure how this would work out in practice: an existing non-compliant device may fail to start if the driver tries to enable queue index 2 when it only supports one request queue, and a spec-compliant device would probably balk if the driver tries to enable queue 1 but does not negotiate VIRTIO_FS_F_NOTIFICATION. If there's a way to reset and retry the whole virtio device initialization process if a device fails like this, then maybe it's feasible. (Or can the driver tweak the virtqueue configuration and try to set DRIVER_OK repeatedly until it works? It's not clear to me if this is allowed by the spec, or what device implementations actually do in practice in this scenario.)

Thanks,
-- Daniel

author maintainer
#8 lore raw

Re: [PATCH v2 2/2] virtio: fix vq # for balloon

Quoted 41 lines · Daniel Verkamp
Quoted 40 lines · Michael S. Tsirkin
Quoted 16 lines · Daniel Verkamp
Quoted 7 lines · Michael S. Tsirkin

virtio balloon communicates to the core that in some configurations vq #s are non-contiguous by setting name pointer to NULL.

Unfortunately, core then turned around and just made them contiguous again. Result is that driver is out of spec.

Thanks for fixing this - I think the overall approach of the patch looks good.

Quoted 4 lines

Implement what the API was supposed to do
in the 1st place. Compatibility with buggy hypervisors is handled inside virtio-balloon, which is the only driver making use of this facility, so far.

Quoted 12 lines

In addition to virtio-balloon, I believe the same problem also affects the virtio-fs device, since queue 1 is only supposed to be present if VIRTIO_FS_F_NOTIFICATION is negotiated, and the request queues are meant to be queue indexes 2 and up. From a look at the Linux driver (virtio_fs.c), it appears like it never acks VIRTIO_FS_F_NOTIFICATION and assumes that request queues start at index 1 rather than 2, which looks out of spec to me, but the current device implementations (that I am aware of, anyway) are also broken in the same way, so it ends up working today. Queue numbering in a spec-compliant device and the current Linux driver would mismatch; what the driver considers to be the first request queue (index 1) would be ignored by the device since queue index 1 has no function if F_NOTIFICATION isn't negotiated.

Oh, thanks a lot for pointing this out!

I see so this patch is no good as is, we need to add a workaround for virtio-fs first.

QEMU workaround is simple - just add an extra queue. But I did not reasearch how this would interact with vhost-user.

Quoted 8 lines
Quoted 2 lines

From driver POV, I guess we could just ignore queue # 1 - would that be ok or does it have performance implications?

As a driver workaround for non-compliant devices, I think ignoring the first request queue would be a reasonable approach if the device's config advertises num_request_queues > 1. Unfortunately, both virtiofsd and crosvm's virtio-fs device have hard-coded num_request_queues =1, so this won't help with those existing devices.

Do they care what the vq # is though?
We could do some magic to translate VQ #s in qemu.

Quoted 6 lines

Maybe there are other devices that we would need to consider as well; commit 529395d2ae64 ("virtio-fs: add multi-queue support") quotes benchmarks that seem to be from a different virtio-fs implementation that does support multiple request queues, so the workaround could possibly be used there.

Quoted 8 lines
Quoted 2 lines

Or do what I did for balloon here: try with spec compliant #s first, if that fails then assume it's the spec issue and shift by 1.

If there is a way to "guess and check" without breaking spec-compliant devices, that sounds reasonable too; however, I'm not sure how this would work out in practice: an existing non-compliant device may fail to start if the driver tries to enable queue index 2 when it only supports one request queue,

You don't try to enable queue - driver starts by checking queue size. The way my patch works is that it assumes a non existing queue has size 0 if not available.

This was actually a documented way to check for PCI and MMIO:
Read the virtqueue size from queue_size. This controls how big the virtqueue is (see 2.6 Virtqueues). If this field is 0, the virtqueue does not exist.
MMIO:

	If the returned value is zero (0x0) the queue is not available.

unfortunately not for CCW, but I guess CCW implementations outside of QEMU are uncommon enough that we can assume it's the same?

To me the above is also a big hint that drivers are allowed to query size for queues that do not exist.

Quoted 11 lines

and a spec-compliant device would probably
balk if the driver tries to enable queue 1 but does not negotiate VIRTIO_FS_F_NOTIFICATION. If there's a way to reset and retry the whole virtio device initialization process if a device fails like this, then maybe it's feasible. (Or can the driver tweak the virtqueue configuration and try to set DRIVER_OK repeatedly until it works? It's not clear to me if this is allowed by the spec, or what device implementations actually do in practice in this scenario.)

Thanks,
-- Daniel

My patch starts with a spec compliant behaviour. If that fails, try non-compliant one as a fallback.

Signature · 1 line
MST
#9 lore raw

Re: [PATCH v2 2/2] virtio: fix vq # for balloon

Quoted 79 lines · Michael S. Tsirkin
Quoted 41 lines · Daniel Verkamp
Quoted 40 lines · Michael S. Tsirkin
Quoted 16 lines · Daniel Verkamp
Quoted 7 lines · Michael S. Tsirkin

virtio balloon communicates to the core that in some configurations vq #s are non-contiguous by setting name pointer to NULL.

Unfortunately, core then turned around and just made them contiguous again. Result is that driver is out of spec.

Thanks for fixing this - I think the overall approach of the patch looks good.

Quoted 4 lines

Implement what the API was supposed to do
in the 1st place. Compatibility with buggy hypervisors is handled inside virtio-balloon, which is the only driver making use of this facility, so far.

Quoted 12 lines

In addition to virtio-balloon, I believe the same problem also affects the virtio-fs device, since queue 1 is only supposed to be present if VIRTIO_FS_F_NOTIFICATION is negotiated, and the request queues are meant to be queue indexes 2 and up. From a look at the Linux driver (virtio_fs.c), it appears like it never acks VIRTIO_FS_F_NOTIFICATION and assumes that request queues start at index 1 rather than 2, which looks out of spec to me, but the current device implementations (that I am aware of, anyway) are also broken in the same way, so it ends up working today. Queue numbering in a spec-compliant device and the current Linux driver would mismatch; what the driver considers to be the first request queue (index 1) would be ignored by the device since queue index 1 has no function if F_NOTIFICATION isn't negotiated.

Oh, thanks a lot for pointing this out!

I see so this patch is no good as is, we need to add a workaround for virtio-fs first.

QEMU workaround is simple - just add an extra queue. But I did not reasearch how this would interact with vhost-user.

Quoted 8 lines
Quoted 2 lines

From driver POV, I guess we could just ignore queue # 1 - would that be ok or does it have performance implications?

As a driver workaround for non-compliant devices, I think ignoring the first request queue would be a reasonable approach if the device's config advertises num_request_queues > 1. Unfortunately, both virtiofsd and crosvm's virtio-fs device have hard-coded num_request_queues =1, so this won't help with those existing devices.

Do they care what the vq # is though?
We could do some magic to translate VQ #s in qemu.

Quoted 6 lines

Maybe there are other devices that we would need to consider as well; commit 529395d2ae64 ("virtio-fs: add multi-queue support") quotes benchmarks that seem to be from a different virtio-fs implementation that does support multiple request queues, so the workaround could possibly be used there.

Quoted 8 lines
Quoted 2 lines

Or do what I did for balloon here: try with spec compliant #s first, if that fails then assume it's the spec issue and shift by 1.

If there is a way to "guess and check" without breaking spec-compliant devices, that sounds reasonable too; however, I'm not sure how this would work out in practice: an existing non-compliant device may fail to start if the driver tries to enable queue index 2 when it only supports one request queue,

You don't try to enable queue - driver starts by checking queue size. The way my patch works is that it assumes a non existing queue has size 0 if not available.

This was actually a documented way to check for PCI and MMIO:
Read the virtqueue size from queue_size. This controls how big the virtqueue is (see 2.6 Virtqueues). If this field is 0, the virtqueue does not exist.
MMIO:

Quoted 8 lines
        If the returned value is zero (0x0) the queue is not available.

unfortunately not for CCW, but I guess CCW implementations outside of QEMU are uncommon enough that we can assume it's the same?

To me the above is also a big hint that drivers are allowed to query size for queues that do not exist.

Ah, that makes total sense - detecting queue presence by non-zero queue size sounds good to me, and it should work in the normal virtio device case.

I am not sure about vhost-user, since there is no way for the front-end to ask the back-end for a queue's size; the confusingly named VHOST_USER_SET_VRING_NUM allows the front-end to configure the size of a queue, but there's no corresponding GET message.

Quoted 9 lines
Quoted 9 lines

and a spec-compliant device would probably
balk if the driver tries to enable queue 1 but does not negotiate VIRTIO_FS_F_NOTIFICATION. If there's a way to reset and retry the whole virtio device initialization process if a device fails like this, then maybe it's feasible. (Or can the driver tweak the virtqueue configuration and try to set DRIVER_OK repeatedly until it works? It's not clear to me if this is allowed by the spec, or what device implementations actually do in practice in this scenario.)

Quoted 5 lines
Quoted 2 lines

Thanks,
-- Daniel

My patch starts with a spec compliant behaviour. If that fails, try non-compliant one as a fallback.

Got it, that sounds reasonable to me given the explanation above.

Thanks,
-- Daniel

author maintainer
#10 lore raw

Re: [PATCH v2 2/2] virtio: fix vq # for balloon

Quoted 89 lines · Daniel Verkamp
Quoted 79 lines · Michael S. Tsirkin
Quoted 41 lines · Daniel Verkamp
Quoted 40 lines · Michael S. Tsirkin
Quoted 16 lines · Daniel Verkamp
Quoted 7 lines · Michael S. Tsirkin

virtio balloon communicates to the core that in some configurations vq #s are non-contiguous by setting name pointer to NULL.

Unfortunately, core then turned around and just made them contiguous again. Result is that driver is out of spec.

Thanks for fixing this - I think the overall approach of the patch looks good.

Quoted 4 lines

Implement what the API was supposed to do
in the 1st place. Compatibility with buggy hypervisors is handled inside virtio-balloon, which is the only driver making use of this facility, so far.

Quoted 12 lines

In addition to virtio-balloon, I believe the same problem also affects the virtio-fs device, since queue 1 is only supposed to be present if VIRTIO_FS_F_NOTIFICATION is negotiated, and the request queues are meant to be queue indexes 2 and up. From a look at the Linux driver (virtio_fs.c), it appears like it never acks VIRTIO_FS_F_NOTIFICATION and assumes that request queues start at index 1 rather than 2, which looks out of spec to me, but the current device implementations (that I am aware of, anyway) are also broken in the same way, so it ends up working today. Queue numbering in a spec-compliant device and the current Linux driver would mismatch; what the driver considers to be the first request queue (index 1) would be ignored by the device since queue index 1 has no function if F_NOTIFICATION isn't negotiated.

Oh, thanks a lot for pointing this out!

I see so this patch is no good as is, we need to add a workaround for virtio-fs first.

QEMU workaround is simple - just add an extra queue. But I did not reasearch how this would interact with vhost-user.

Quoted 8 lines
Quoted 2 lines

From driver POV, I guess we could just ignore queue # 1 - would that be ok or does it have performance implications?

As a driver workaround for non-compliant devices, I think ignoring the first request queue would be a reasonable approach if the device's config advertises num_request_queues > 1. Unfortunately, both virtiofsd and crosvm's virtio-fs device have hard-coded num_request_queues =1, so this won't help with those existing devices.

Do they care what the vq # is though?
We could do some magic to translate VQ #s in qemu.

Quoted 6 lines

Maybe there are other devices that we would need to consider as well; commit 529395d2ae64 ("virtio-fs: add multi-queue support") quotes benchmarks that seem to be from a different virtio-fs implementation that does support multiple request queues, so the workaround could possibly be used there.

Quoted 8 lines
Quoted 2 lines

Or do what I did for balloon here: try with spec compliant #s first, if that fails then assume it's the spec issue and shift by 1.

If there is a way to "guess and check" without breaking spec-compliant devices, that sounds reasonable too; however, I'm not sure how this would work out in practice: an existing non-compliant device may fail to start if the driver tries to enable queue index 2 when it only supports one request queue,

You don't try to enable queue - driver starts by checking queue size. The way my patch works is that it assumes a non existing queue has size 0 if not available.

This was actually a documented way to check for PCI and MMIO:
Read the virtqueue size from queue_size. This controls how big the virtqueue is (see 2.6 Virtqueues). If this field is 0, the virtqueue does not exist.
MMIO:

Quoted 8 lines
        If the returned value is zero (0x0) the queue is not available.

unfortunately not for CCW, but I guess CCW implementations outside of QEMU are uncommon enough that we can assume it's the same?

To me the above is also a big hint that drivers are allowed to query size for queues that do not exist.

Quoted 8 lines

Ah, that makes total sense - detecting queue presence by non-zero queue size sounds good to me, and it should work in the normal virtio device case.

I am not sure about vhost-user, since there is no way for the front-end to ask the back-end for a queue's size; the confusingly named VHOST_USER_SET_VRING_NUM allows the front-end to configure the size of a queue, but there's no corresponding GET message.

So for vhost user I would assume it is non spec compliant and qemu remaps queue numbers?
And can add a backend feature for supporting VHOST_USER_GET_VRING_NUM and with that, also require that backends are spec compliant?
And again, qemu can remap queue numbers.

Quoted 19 lines
Quoted 9 lines
Quoted 9 lines

and a spec-compliant device would probably
balk if the driver tries to enable queue 1 but does not negotiate VIRTIO_FS_F_NOTIFICATION. If there's a way to reset and retry the whole virtio device initialization process if a device fails like this, then maybe it's feasible. (Or can the driver tweak the virtqueue configuration and try to set DRIVER_OK repeatedly until it works? It's not clear to me if this is allowed by the spec, or what device implementations actually do in practice in this scenario.)

Quoted 5 lines
Quoted 2 lines

Thanks,
-- Daniel

My patch starts with a spec compliant behaviour. If that fails, try non-compliant one as a fallback.

Got it, that sounds reasonable to me given the explanation above.

Thanks,
-- Daniel

author maintainer
#11 lore raw

Re: [PATCH v2 2/2] virtio: fix vq # for balloon

In reply to Daniel Verkamp
Quoted 75 lines · Daniel Verkamp
Quoted 7 lines · Michael S. Tsirkin

virtio balloon communicates to the core that in some configurations vq #s are non-contiguous by setting name pointer to NULL.

Unfortunately, core then turned around and just made them contiguous again. Result is that driver is out of spec.

Thanks for fixing this - I think the overall approach of the patch looks good.

Quoted 4 lines

Implement what the API was supposed to do
in the 1st place. Compatibility with buggy hypervisors is handled inside virtio-balloon, which is the only driver making use of this facility, so far.

In addition to virtio-balloon, I believe the same problem also affects the virtio-fs device, since queue 1 is only supposed to be present if VIRTIO_FS_F_NOTIFICATION is negotiated, and the request queues are meant to be queue indexes 2 and up. From a look at the Linux driver (virtio_fs.c), it appears like it never acks VIRTIO_FS_F_NOTIFICATION and assumes that request queues start at index 1 rather than 2, which looks out of spec to me, but the current device implementations (that I am aware of, anyway) are also broken in the same way, so it ends up working today. Queue numbering in a spec-compliant device and the current Linux driver would mismatch; what the driver considers to be the first request queue (index 1) would be ignored by the device since queue index 1 has no function if F_NOTIFICATION isn't negotiated.

[...]

Quoted 32 lines
drivers/virtio/virtio_pci_common.c +3 -3
index 7d82facafd75..fa606e7321ad 100644
@@ -293,7 +293,7 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs,
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
        struct virtqueue_info *vqi;
        u16 msix_vec;
-       int i, err, nvectors, allocated_vectors, queue_idx = 0;
+       int i, err, nvectors, allocated_vectors;
 
        vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL);
        if (!vp_dev->vqs)
@@ -332,7 +332,7 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs,
                        msix_vec = allocated_vectors++;
                else
                        msix_vec = VP_MSIX_VQ_VECTOR;
-               vqs[i] = vp_setup_vq(vdev, queue_idx++, vqi->callback,
+               vqs[i] = vp_setup_vq(vdev, i, vqi->callback,
                                     vqi->name, vqi->ctx, msix_vec);
                if (IS_ERR(vqs[i])) {
                        err = PTR_ERR(vqs[i]);
@@ -368,7 +368,7 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs,
                            struct virtqueue_info vqs_info[])
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-       int i, err, queue_idx = 0;
+       int i, err;
 
        vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL);
        if (!vp_dev->vqs)

drivers/virtio/virtio_pci_common.c static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs, · line 397

Quoted 10 lines
drivers/virtio/virtio_pci_common.c +5 -0
@@ -388,8 +388,13 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs,
                        vqs[i] = NULL;
                        continue;
                }
+<<<<<<< HEAD
                vqs[i] = vp_setup_vq(vdev, queue_idx++, vqi->callback,
                                     vqi->name, vqi->ctx,
+=======
+               vqs[i] = vp_setup_vq(vdev, i, callbacks[i], names[i],
+                                    ctx ? ctx[i] : false,
+>>>>>>> f814759f80b7... virtio: fix vq # for balloon

This still has merge markers in it.

Quoted 2 lines

Thanks,
-- Daniel

ouch forgot to commit ;)

#12 lore raw

Re: [PATCH v2 2/2] virtio: fix vq # for balloon

In reply to Michael S. Tsirkin
kernel test robot noticed the following build errors:

Hi Michael,

kernel test robot noticed the following build errors:

[auto build test ERROR on next-20240710]
[cannot apply to uml/next remoteproc/rproc-next s390/features linus/master uml/fixes v6.10-rc7 v6.10-rc6 v6.10-rc5 v6.10-rc7] [If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Michael-S-Tsirkin/virtio_balloon-add-work-around-for-out-of-spec-QEMU/20240711-004346
base:   next-20240710
patch link:    https://lore.kernel.org/r/3d655be73ce220f176b2c163839d83699f8faf43.1720611677.git.mst%40redhat.com
patch subject: [PATCH v2 2/2] virtio: fix vq # for balloon
config: i386-randconfig-014-20240711 (https://download.01.org/0day-ci/archive/20240711/[email protected]/config)
compiler: clang version 18.1.5 (https://github.com/llvm/llvm-project 617a15a9eac96088ae5e9134248d8236e34b91b1)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240711/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

>> drivers/virtio/virtio_pci_common.c:391:1: error: version control conflict marker in file
     391 | <<<<<<< HEAD
         | ^
>> drivers/virtio/virtio_pci_common.c:392:30: error: use of undeclared identifier 'queue_idx'
     392 |                 vqs[i] = vp_setup_vq(vdev, queue_idx++, vqi->callback,
         |                                            ^

2 errors generated.

vim +391 drivers/virtio/virtio_pci_common.c

365
366 static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs,
367 struct virtqueue *vqs[],
368 struct virtqueue_info vqs_info[])
369 {
370 struct virtio_pci_device *vp_dev = to_vp_device(vdev);
371 int i, err;
372
373 vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL);
374 if (!vp_dev->vqs)
375 return -ENOMEM;
376
377 err = request_irq(vp_dev->pci_dev->irq, vp_interrupt, IRQF_SHARED,
378 dev_name(&vdev->dev), vp_dev);
379 if (err)
380 goto out_del_vqs;
381
382 vp_dev->intx_enabled = 1;
383 vp_dev->per_vq_vectors = false;
384 for (i = 0; i < nvqs; ++i) {
385 struct virtqueue_info *vqi = &vqs_info[i];
386
387 if (!vqi->name) {
388 vqs[i] = NULL;
389 continue;
390 }

 > 391	<<<<<<< HEAD
 > 392			vqs[i] = vp_setup_vq(vdev, queue_idx++, vqi->callback,

393 vqi->name, vqi->ctx,
394 =======
395 vqs[i] = vp_setup_vq(vdev, i, callbacks[i], names[i],
396 ctx ? ctx[i] : false,
397 >>>>>>> f814759f80b7... virtio: fix vq # for balloon
398 VIRTIO_MSI_NO_VECTOR);
399 if (IS_ERR(vqs[i])) {
400 err = PTR_ERR(vqs[i]);
401 goto out_del_vqs;
402 }
403 }
404
405 return 0;
406 out_del_vqs:
407 vp_del_vqs(vdev);
408 return err;
409 }
410

Signature · 2 lines
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
maintainer Acked-by on v2 2/2
#13 lore raw

Re: [PATCH v2 2/2] virtio: fix vq # for balloon

In reply to Michael S. Tsirkin
Quoted 12 lines · On Wed, 10 Jul 2024 07:42:46 -0400 "Michael S. Tsirkin" <[email protected]> wrote:
drivers/s390/virtio/virtio_ccw.c +1 -1
@@ -694,7 +694,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
 {
 	struct virtio_ccw_device *vcdev = to_vc_device(vdev);
 	dma64_t *indicatorp = NULL;
-	int ret, i, queue_idx = 0;
+	int ret, i;
 	struct ccw1 *ccw;
 	dma32_t indicatorp_dma = 0;
 

drivers/s390/virtio/virtio_ccw.c static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, · line 716

Quoted 8 lines
drivers/s390/virtio/virtio_ccw.c +1 -1
@@ -710,7 +710,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
 			continue;
 		}
 
-		vqs[i] = virtio_ccw_setup_vq(vdev, queue_idx++, vqi->callback,
+		vqs[i] = virtio_ccw_setup_vq(vdev, i, vqi->callback,
 					     vqi->name, vqi->ctx, ccw);
 		if (IS_ERR(vqs[i])) {
 			ret = PTR_ERR(vqs[i]);
#14 lore raw
In reply to Michael S. Tsirkin
Quoted 11 lines · Michael S. Tsirkin

Currently, if VIRTIO_BALLOON_F_FREE_PAGE_HINT is off but VIRTIO_BALLOON_F_REPORTING is on, then the reporting vq gets number 3 while spec says it's number 4.
It happens to work because the qemu virtio pci driver is *also* out of spec.

To fix:
1. add vq4 as per spec
2. to help out the buggy qemu driver, if finding vqs fail, try with vq3 as reporting.

Quoted 8 lines
Fixes b0c504f15471 ("virtio-balloon: add support for providing free page reports to host")
Cc "Alexander Duyck" <[email protected]>

Changes from v1:
rebased on vhost tip

Looks like you missed to include acks from me and Jason.

Signature · 3 lines
Cheers,

David / dhildenb
author maintainer
#15 lore raw
Quoted 17 lines · David Hildenbrand
Quoted 16 lines · Michael S. Tsirkin

Currently, if VIRTIO_BALLOON_F_FREE_PAGE_HINT is off but VIRTIO_BALLOON_F_REPORTING is on, then the reporting vq gets number 3 while spec says it's number 4.
It happens to work because the qemu virtio pci driver is *also* out of spec.

To fix:
1. add vq4 as per spec
2. to help out the buggy qemu driver, if finding vqs fail, try with vq3 as reporting.

Fixes b0c504f15471 ("virtio-balloon: add support for providing free page reports to host")
Cc "Alexander Duyck" <[email protected]>
Quoted 10 lines
Quoted 3 lines

Changes from v1:
rebased on vhost tip

Looks like you missed to include acks from me and Jason.

Signature · 3 lines
Cheers,

David / dhildenb

indeed they are on lore but not in the mbox, weird. fixed - thanks for pointing this out.