* [PATCH v2 2/2] virtio_balloon: submit reported pages as individual buffers
[not found] <32e21059adb6cb1fd08c3f4426a313c77cf450ec.1793057483.git.mst@redhat.com>
@ 2026-10-26 23:53 ` Michael S. Tsirkin
2026-10-27 9:26 ` Ruben Hakobyan
0 siblings, 1 reply; 8+ messages in thread
From: Michael S. Tsirkin @ 2026-10-26 23:53 UTC (permalink / raw)
To: linux-kernel
Cc: Jason Wang, Xuan Zhuo, Eugenio Pérez, virtualization,
Ruben Hakobyan, Alexander Duyck, David Hildenbrand, Miguel Ojeda,
Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
Andrew Morton, rust-for-linux
The virtio_balloon driver reports a scatter-gather list of free pages
to the VMM so it may discard unused pages.
For an arm64 kernel with 64 KiB pages, the default reporting and
allocation orders allow entries ranging from 2 MiB to 512 MiB. If the
report contains a sufficient number of large entries, we will end up
with a descriptor chain that represents over 4 GiB of memory. This
violates virtio spec, which says:
Drivers MUST NOT add a descriptor chain longer than $2^{32}$ bytes in total;
Specifically, submitting $2^{32}$ or more breaks Rust-VMM.
Submit each reported page as a separate virtqueue buffer instead of one
buffer with an sg list of all pages. This also avoids indirect
descriptor allocation (kmalloc in the reporting path).
To avoid multiple buffers causing interrupt storms, keep callbacks
disabled while we wait for an event.
TODO: as an alternative, keep using virtqueue_enable_cb_delayed
but add buffers after there's space in the ring.
Note: if the virtqueue is broken, wait_event on
virtqueue_get_buf hangs. This is a pre-existing issue:
the old single-buffer code had the same hang.
Reported-by: Ruben Hakobyan <hruben@meta.com>
Cc: Ruben Hakobyan <hruben@meta.com>
Fixes: b0c504f15471 ("virtio-balloon: add support for providing free page reports to host")
Cc: Alexander Duyck <alexander.h.duyck@linux.intel.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
Notes (changelog):
changes since v1:
keep callbacks disabled while draining: get_buf re-arms the used
event for the next buffer, reintroducing an interrupt per page.
Disable the reporting vq callbacks at probe, and only arm the
delayed callback to wait.
drivers/virtio/virtio_balloon.c | 59 +++++++++++++++++++++++++--------
1 file changed, 45 insertions(+), 14 deletions(-)
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index f6c2dff33f8a..b88b463488e0 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -202,25 +202,53 @@ static int virtballoon_free_page_report(struct page_reporting_dev_info *pr_dev_i
struct virtio_balloon *vb =
container_of(pr_dev_info, struct virtio_balloon, pr_dev_info);
struct virtqueue *vq = vb->reporting_vq;
- unsigned int unused, err;
+ unsigned int i, err = 0;
/* We should always be able to add these buffers to an empty queue. */
- err = virtqueue_add_inbuf(vq, sg, nents, vb, GFP_NOWAIT);
+ for (i = 0; i < nents; i++) {
+ struct scatterlist one;
- /*
- * In the extremely unlikely case that something has occurred and we
- * are able to trigger an error we will simply display a warning
- * and exit without actually processing the pages.
- */
- if (WARN_ON_ONCE(err))
- return err;
+ sg_init_table(&one, 1);
+ sg_set_page(&one, sg_page(&sg[i]), sg[i].length,
+ sg[i].offset);
+ err = virtqueue_add_inbuf(vq, &one, 1, &sg[i], GFP_NOWAIT);
- virtqueue_kick(vq);
+ /*
+ * In the extremely unlikely case that something has occurred
+ * and we are able to trigger an error we will simply display
+ * a warning and exit without actually processing the pages.
+ */
+ if (WARN_ON_ONCE(err)) {
+ nents = i;
+ break;
+ }
+ }
- /* When host has read buffer, this completes via balloon_ack */
- wait_event(vb->acked, virtqueue_get_buf(vq, &unused));
+ if (nents) {
+ unsigned int unused;
- return 0;
+ virtqueue_kick(vq);
+
+ /* When host has read buffer, this completes via balloon_ack. */
+ i = 0;
+ wait_event(vb->acked, ({
+ for (;;) {
+ virtqueue_disable_cb(vq);
+ while (virtqueue_get_buf(vq, &unused))
+ i++;
+
+ /* Stop waiting if device used all that we added. */
+ if (i >= nents)
+ break;
+
+ if (virtqueue_enable_cb_delayed_max(vq))
+ break;
+ }
+ i >= nents;
+ }));
+ }
+
+ return err;
}
static void set_page_pfns(struct virtio_balloon *vb,
@@ -635,8 +663,11 @@ static int init_vqs(struct virtio_balloon *vb)
if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
vb->free_page_vq = vqs[VIRTIO_BALLOON_VQ_FREE_PAGE];
- if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_REPORTING))
+ if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_REPORTING)) {
vb->reporting_vq = vqs[VIRTIO_BALLOON_VQ_REPORTING];
+ /* We re-enable callbacks after add, when we want them. */
+ virtqueue_disable_cb(vb->reporting_vq);
+ }
return 0;
}
--
MST
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v2 2/2] virtio_balloon: submit reported pages as individual buffers
2026-10-26 23:53 ` [PATCH v2 2/2] virtio_balloon: submit reported pages as individual buffers Michael S. Tsirkin
@ 2026-10-27 9:26 ` Ruben Hakobyan
2026-10-27 10:34 ` Michael S. Tsirkin
0 siblings, 1 reply; 8+ messages in thread
From: Ruben Hakobyan @ 2026-10-27 9:26 UTC (permalink / raw)
To: Michael S . Tsirkin
Cc: Jason Wang, Xuan Zhuo, Eugenio Pérez, virtualization,
Alexander Duyck, David Hildenbrand, Miguel Ojeda, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Danilo Krummrich, Andrew Morton,
linux-kernel, rust-for-linux
On Mon, Oct 26, 2026 at 11:53 PM Michael S. Tsirkin <mst@redhat.com> wrote:
> The virtio_balloon driver reports a scatter-gather list of free pages
> to the VMM so it may discard unused pages.
>
> For an arm64 kernel with 64 KiB pages, the default reporting and
> allocation orders allow entries ranging from 2 MiB to 512 MiB. If the
> report contains a sufficient number of large entries, we will end up
> with a descriptor chain that represents over 4 GiB of memory. This
> violates virtio spec, which says:
> Drivers MUST NOT add a descriptor chain longer than $2^{32}$ bytes in total;
>
> Specifically, submitting $2^{32}$ or more breaks Rust-VMM.
>
> Submit each reported page as a separate virtqueue buffer instead of one
> buffer with an sg list of all pages. This also avoids indirect
> descriptor allocation (kmalloc in the reporting path).
>
> To avoid multiple buffers causing interrupt storms, keep callbacks
> disabled while we wait for an event.
>
> TODO: as an alternative, keep using virtqueue_enable_cb_delayed
> but add buffers after there's space in the ring.
>
> Note: if the virtqueue is broken, wait_event on
> virtqueue_get_buf hangs. This is a pre-existing issue:
> the old single-buffer code had the same hang.
>
> Reported-by: Ruben Hakobyan <hruben@meta.com>
> Cc: Ruben Hakobyan <hruben@meta.com>
> Fixes: b0c504f15471 ("virtio-balloon: add support for providing free page reports to host")
> Cc: Alexander Duyck <alexander.h.duyck@linux.intel.com>
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> ---
>
> Notes (changelog):
> changes since v1:
> keep callbacks disabled while draining: get_buf re-arms the used
> event for the next buffer, reintroducing an interrupt per page.
> Disable the reporting vq callbacks at probe, and only arm the
> delayed callback to wait.
>
Thanks for the patches! I think sashiko-bot found some issues on broken
queues in the first patch that are worth looking into for correctness.
Other than that, I tested the "normal path" on QEMU and Cloud Hypervisor,
both on 4 KiB and 64 KiB guests, and this works correctly.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 2/2] virtio_balloon: submit reported pages as individual buffers
2026-10-27 9:26 ` Ruben Hakobyan
@ 2026-10-27 10:34 ` Michael S. Tsirkin
2026-10-27 12:32 ` Ruben Hakobyan
0 siblings, 1 reply; 8+ messages in thread
From: Michael S. Tsirkin @ 2026-10-27 10:34 UTC (permalink / raw)
To: Ruben Hakobyan
Cc: Jason Wang, Xuan Zhuo, Eugenio Pérez, virtualization,
Alexander Duyck, David Hildenbrand, Miguel Ojeda, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Danilo Krummrich, Andrew Morton,
linux-kernel, rust-for-linux
On Tue, Oct 27, 2026 at 02:26:33AM -0700, Ruben Hakobyan wrote:
> On Mon, Oct 26, 2026 at 11:53 PM Michael S. Tsirkin <mst@redhat.com> wrote:
> > The virtio_balloon driver reports a scatter-gather list of free pages
> > to the VMM so it may discard unused pages.
> >
> > For an arm64 kernel with 64 KiB pages, the default reporting and
> > allocation orders allow entries ranging from 2 MiB to 512 MiB. If the
> > report contains a sufficient number of large entries, we will end up
> > with a descriptor chain that represents over 4 GiB of memory. This
> > violates virtio spec, which says:
> > Drivers MUST NOT add a descriptor chain longer than $2^{32}$ bytes in total;
> >
> > Specifically, submitting $2^{32}$ or more breaks Rust-VMM.
> >
> > Submit each reported page as a separate virtqueue buffer instead of one
> > buffer with an sg list of all pages. This also avoids indirect
> > descriptor allocation (kmalloc in the reporting path).
> >
> > To avoid multiple buffers causing interrupt storms, keep callbacks
> > disabled while we wait for an event.
> >
> > TODO: as an alternative, keep using virtqueue_enable_cb_delayed
> > but add buffers after there's space in the ring.
> >
> > Note: if the virtqueue is broken, wait_event on
> > virtqueue_get_buf hangs. This is a pre-existing issue:
> > the old single-buffer code had the same hang.
> >
> > Reported-by: Ruben Hakobyan <hruben@meta.com>
> > Cc: Ruben Hakobyan <hruben@meta.com>
> > Fixes: b0c504f15471 ("virtio-balloon: add support for providing free page reports to host")
> > Cc: Alexander Duyck <alexander.h.duyck@linux.intel.com>
> > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > ---
> >
> > Notes (changelog):
> > changes since v1:
> > keep callbacks disabled while draining: get_buf re-arms the used
> > event for the next buffer, reintroducing an interrupt per page.
> > Disable the reporting vq callbacks at probe, and only arm the
> > delayed callback to wait.
> >
>
> Thanks for the patches! I think sashiko-bot found some issues on broken
> queues in the first patch that are worth looking into for correctness.
Surprise removal of the balloon? Nope, it's a pre-existing issue that
it's broken. Besides it's not really practical, no one removes
the balloon - no need.
> Other than that, I tested the "normal path" on QEMU and Cloud Hypervisor,
> both on 4 KiB and 64 KiB guests, and this works correctly.
Thanks a lot! Can you pls confirm whether the performance is about the
same/better/worse?
--
MST
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 2/2] virtio_balloon: submit reported pages as individual buffers
2026-10-27 10:34 ` Michael S. Tsirkin
@ 2026-10-27 12:32 ` Ruben Hakobyan
2026-10-27 12:40 ` Michael S. Tsirkin
0 siblings, 1 reply; 8+ messages in thread
From: Ruben Hakobyan @ 2026-10-27 12:32 UTC (permalink / raw)
To: Michael S . Tsirkin
Cc: Jason Wang, Xuan Zhuo, Eugenio Pérez, virtualization,
Alexander Duyck, David Hildenbrand, Miguel Ojeda, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Danilo Krummrich, Andrew Morton,
linux-kernel, rust-for-linux
On Tue, Oct 27, 2026 at 10:35 AM Michael S. Tsirkin <mst@redhat.com> wrote:
> On Tue, Oct 27, 2026 at 02:26:33AM -0700, Ruben Hakobyan wrote:
> > On Mon, Oct 26, 2026 at 11:53 PM Michael S. Tsirkin <mst@redhat.com> wrote:
> > > The virtio_balloon driver reports a scatter-gather list of free pages
> > > to the VMM so it may discard unused pages.
> > >
> > > For an arm64 kernel with 64 KiB pages, the default reporting and
> > > allocation orders allow entries ranging from 2 MiB to 512 MiB. If the
> > > report contains a sufficient number of large entries, we will end up
> > > with a descriptor chain that represents over 4 GiB of memory. This
> > > violates virtio spec, which says:
> > > Drivers MUST NOT add a descriptor chain longer than $2^{32}$ bytes in total;
> > >
> > > Specifically, submitting $2^{32}$ or more breaks Rust-VMM.
> > >
> > > Submit each reported page as a separate virtqueue buffer instead of one
> > > buffer with an sg list of all pages. This also avoids indirect
> > > descriptor allocation (kmalloc in the reporting path).
> > >
> > > To avoid multiple buffers causing interrupt storms, keep callbacks
> > > disabled while we wait for an event.
> > >
> > > TODO: as an alternative, keep using virtqueue_enable_cb_delayed
> > > but add buffers after there's space in the ring.
> > >
> > > Note: if the virtqueue is broken, wait_event on
> > > virtqueue_get_buf hangs. This is a pre-existing issue:
> > > the old single-buffer code had the same hang.
> > >
> > > Reported-by: Ruben Hakobyan <hruben@meta.com>
> > > Cc: Ruben Hakobyan <hruben@meta.com>
> > > Fixes: b0c504f15471 ("virtio-balloon: add support for providing free page reports to host")
> > > Cc: Alexander Duyck <alexander.h.duyck@linux.intel.com>
> > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > > ---
> > >
> > > Notes (changelog):
> > > changes since v1:
> > > keep callbacks disabled while draining: get_buf re-arms the used
> > > event for the next buffer, reintroducing an interrupt per page.
> > > Disable the reporting vq callbacks at probe, and only arm the
> > > delayed callback to wait.
> > >
> >
> > Thanks for the patches! I think sashiko-bot found some issues on broken
> > queues in the first patch that are worth looking into for correctness.
>
> Surprise removal of the balloon? Nope, it's a pre-existing issue that
> it's broken. Besides it's not really practical, no one removes
> the balloon - no need.
Fair point about that. But I meant the broken queue check.
In virtqueue_enable_cb_delayed() there is:
```
/*
* When the device is broken there is no point in polling used->idx,
* the backend will never update it. Return true to let callers
* exit their cleanup loops instead of spinning forever.
*/
if (unlikely(vq->broken))
return true;
```
But virtqueue_enable_cb_delayed_max() doesn't have this. So I was just
thinking the same reasoning should apply here?
>
> > Other than that, I tested the "normal path" on QEMU and Cloud Hypervisor,
> > both on 4 KiB and 64 KiB guests, and this works correctly.
>
> Thanks a lot! Can you pls confirm whether the performance is about the
> same/better/worse?
From my tests on QEMU, CPU time was about the same as my original patch
and unmodified Linux.
To bring a concrete example, with these patches it took ~437 ms of CPU to
reclaim a whole 8 GiB with 4 KiB pages (vs ~434 ms on unmodified Linux).
With 64 KiB pages, it averaged 121 ms CPU (vs ~112 ms with my original
patch).
(I tested this on Nvidia Grace)
>
> --
> MST
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 2/2] virtio_balloon: submit reported pages as individual buffers
2026-10-27 12:32 ` Ruben Hakobyan
@ 2026-10-27 12:40 ` Michael S. Tsirkin
2026-10-27 14:39 ` Ruben Hakobyan
0 siblings, 1 reply; 8+ messages in thread
From: Michael S. Tsirkin @ 2026-10-27 12:40 UTC (permalink / raw)
To: Ruben Hakobyan
Cc: Jason Wang, Xuan Zhuo, Eugenio Pérez, virtualization,
Alexander Duyck, David Hildenbrand, Miguel Ojeda, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Danilo Krummrich, Andrew Morton,
linux-kernel, rust-for-linux
On Tue, Oct 27, 2026 at 05:32:04AM -0700, Ruben Hakobyan wrote:
> On Tue, Oct 27, 2026 at 10:35 AM Michael S. Tsirkin <mst@redhat.com> wrote:
> > On Tue, Oct 27, 2026 at 02:26:33AM -0700, Ruben Hakobyan wrote:
> > > On Mon, Oct 26, 2026 at 11:53 PM Michael S. Tsirkin <mst@redhat.com> wrote:
> > > > The virtio_balloon driver reports a scatter-gather list of free pages
> > > > to the VMM so it may discard unused pages.
> > > >
> > > > For an arm64 kernel with 64 KiB pages, the default reporting and
> > > > allocation orders allow entries ranging from 2 MiB to 512 MiB. If the
> > > > report contains a sufficient number of large entries, we will end up
> > > > with a descriptor chain that represents over 4 GiB of memory. This
> > > > violates virtio spec, which says:
> > > > Drivers MUST NOT add a descriptor chain longer than $2^{32}$ bytes in total;
> > > >
> > > > Specifically, submitting $2^{32}$ or more breaks Rust-VMM.
> > > >
> > > > Submit each reported page as a separate virtqueue buffer instead of one
> > > > buffer with an sg list of all pages. This also avoids indirect
> > > > descriptor allocation (kmalloc in the reporting path).
> > > >
> > > > To avoid multiple buffers causing interrupt storms, keep callbacks
> > > > disabled while we wait for an event.
> > > >
> > > > TODO: as an alternative, keep using virtqueue_enable_cb_delayed
> > > > but add buffers after there's space in the ring.
> > > >
> > > > Note: if the virtqueue is broken, wait_event on
> > > > virtqueue_get_buf hangs. This is a pre-existing issue:
> > > > the old single-buffer code had the same hang.
> > > >
> > > > Reported-by: Ruben Hakobyan <hruben@meta.com>
> > > > Cc: Ruben Hakobyan <hruben@meta.com>
> > > > Fixes: b0c504f15471 ("virtio-balloon: add support for providing free page reports to host")
> > > > Cc: Alexander Duyck <alexander.h.duyck@linux.intel.com>
> > > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > > > ---
> > > >
> > > > Notes (changelog):
> > > > changes since v1:
> > > > keep callbacks disabled while draining: get_buf re-arms the used
> > > > event for the next buffer, reintroducing an interrupt per page.
> > > > Disable the reporting vq callbacks at probe, and only arm the
> > > > delayed callback to wait.
> > > >
> > >
> > > Thanks for the patches! I think sashiko-bot found some issues on broken
> > > queues in the first patch that are worth looking into for correctness.
> >
> > Surprise removal of the balloon? Nope, it's a pre-existing issue that
> > it's broken. Besides it's not really practical, no one removes
> > the balloon - no need.
>
> Fair point about that. But I meant the broken queue check.
> In virtqueue_enable_cb_delayed() there is:
> ```
> /*
> * When the device is broken there is no point in polling used->idx,
> * the backend will never update it. Return true to let callers
> * exit their cleanup loops instead of spinning forever.
> */
> if (unlikely(vq->broken))
> return true;
> ```
>
> But virtqueue_enable_cb_delayed_max() doesn't have this. So I was just
> thinking the same reasoning should apply here?
It's broken there, too. E.g. what is the "cleanup loop" in balloon?
> >
> > > Other than that, I tested the "normal path" on QEMU and Cloud Hypervisor,
> > > both on 4 KiB and 64 KiB guests, and this works correctly.
> >
> > Thanks a lot! Can you pls confirm whether the performance is about the
> > same/better/worse?
>
> >From my tests on QEMU, CPU time was about the same as my original patch
> and unmodified Linux.
>
> To bring a concrete example, with these patches it took ~437 ms of CPU to
> reclaim a whole 8 GiB with 4 KiB pages (vs ~434 ms on unmodified Linux).
OK so that's just noise, there's no difference.
>
> With 64 KiB pages, it averaged 121 ms CPU (vs ~112 ms with my original
> patch).
Is this measurable, or also noise?
>
> (I tested this on Nvidia Grace)
Thanks!
> >
> > --
> > MST
> >
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 2/2] virtio_balloon: submit reported pages as individual buffers
2026-10-27 12:40 ` Michael S. Tsirkin
@ 2026-10-27 14:39 ` Ruben Hakobyan
2026-10-27 19:17 ` Michael S. Tsirkin
0 siblings, 1 reply; 8+ messages in thread
From: Ruben Hakobyan @ 2026-10-27 14:39 UTC (permalink / raw)
To: Michael S . Tsirkin
Cc: Jason Wang, Xuan Zhuo, Eugenio Pérez, virtualization,
Alexander Duyck, David Hildenbrand, Miguel Ojeda, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Danilo Krummrich, Andrew Morton,
linux-kernel, rust-for-linux
On Tue, Oct 27, 2026 at 12:40 PM Michael S. Tsirkin <mst@redhat.com> wrote:
> On Tue, Oct 27, 2026 at 05:32:04AM -0700, Ruben Hakobyan wrote:
> > On Tue, Oct 27, 2026 at 10:35 AM Michael S. Tsirkin <mst@redhat.com> wrote:
> > > On Tue, Oct 27, 2026 at 02:26:33AM -0700, Ruben Hakobyan wrote:
> > > > On Mon, Oct 26, 2026 at 11:53 PM Michael S. Tsirkin <mst@redhat.com> wrote:
> > > > > The virtio_balloon driver reports a scatter-gather list of free pages
> > > > > to the VMM so it may discard unused pages.
> > > > >
> > > > > For an arm64 kernel with 64 KiB pages, the default reporting and
> > > > > allocation orders allow entries ranging from 2 MiB to 512 MiB. If the
> > > > > report contains a sufficient number of large entries, we will end up
> > > > > with a descriptor chain that represents over 4 GiB of memory. This
> > > > > violates virtio spec, which says:
> > > > > Drivers MUST NOT add a descriptor chain longer than $2^{32}$ bytes in total;
> > > > >
> > > > > Specifically, submitting $2^{32}$ or more breaks Rust-VMM.
> > > > >
> > > > > Submit each reported page as a separate virtqueue buffer instead of one
> > > > > buffer with an sg list of all pages. This also avoids indirect
> > > > > descriptor allocation (kmalloc in the reporting path).
> > > > >
> > > > > To avoid multiple buffers causing interrupt storms, keep callbacks
> > > > > disabled while we wait for an event.
> > > > >
> > > > > TODO: as an alternative, keep using virtqueue_enable_cb_delayed
> > > > > but add buffers after there's space in the ring.
> > > > >
> > > > > Note: if the virtqueue is broken, wait_event on
> > > > > virtqueue_get_buf hangs. This is a pre-existing issue:
> > > > > the old single-buffer code had the same hang.
> > > > >
> > > > > Reported-by: Ruben Hakobyan <hruben@meta.com>
> > > > > Cc: Ruben Hakobyan <hruben@meta.com>
> > > > > Fixes: b0c504f15471 ("virtio-balloon: add support for providing free page reports to host")
> > > > > Cc: Alexander Duyck <alexander.h.duyck@linux.intel.com>
> > > > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > > > > ---
> > > > >
> > > > > Notes (changelog):
> > > > > changes since v1:
> > > > > keep callbacks disabled while draining: get_buf re-arms the used
> > > > > event for the next buffer, reintroducing an interrupt per page.
> > > > > Disable the reporting vq callbacks at probe, and only arm the
> > > > > delayed callback to wait.
> > > > >
> > > >
> > > > Thanks for the patches! I think sashiko-bot found some issues on broken
> > > > queues in the first patch that are worth looking into for correctness.
> > >
> > > Surprise removal of the balloon? Nope, it's a pre-existing issue that
> > > it's broken. Besides it's not really practical, no one removes
> > > the balloon - no need.
> >
> > Fair point about that. But I meant the broken queue check.
> > In virtqueue_enable_cb_delayed() there is:
> > ```
> > /*
> > * When the device is broken there is no point in polling used->idx,
> > * the backend will never update it. Return true to let callers
> > * exit their cleanup loops instead of spinning forever.
> > */
> > if (unlikely(vq->broken))
> > return true;
> > ```
> >
> > But virtqueue_enable_cb_delayed_max() doesn't have this. So I was just
> > thinking the same reasoning should apply here?
>
> It's broken there, too. E.g. what is the "cleanup loop" in balloon?
The loop in virtballoon_free_page_report():
```
wait_event(vb->acked, ({
for (;;) {
virtqueue_disable_cb(vq);
while (virtqueue_get_buf(vq, &unused))
i++;
/* Stop waiting if device used all that we added. */
if (i >= nents)
break;
if (virtqueue_enable_cb_delayed_max(vq))
break;
}
i >= nents;
}));
```
For a broken queue, you could exit the for loop early and avoid busy looping.
It still hangs, but I think it can sleep rather than busy loop?
Anyway, I'm not sure how practical a broken queue is, so I don't have a
strong opinion.
>
> > >
> > > > Other than that, I tested the "normal path" on QEMU and Cloud Hypervisor,
> > > > both on 4 KiB and 64 KiB guests, and this works correctly.
> > >
> > > Thanks a lot! Can you pls confirm whether the performance is about the
> > > same/better/worse?
> >
> > >From my tests on QEMU, CPU time was about the same as my original patch
> > and unmodified Linux.
> >
> > To bring a concrete example, with these patches it took ~437 ms of CPU to
> > reclaim a whole 8 GiB with 4 KiB pages (vs ~434 ms on unmodified Linux).
>
> OK so that's just noise, there's no difference.
>
> >
> > With 64 KiB pages, it averaged 121 ms CPU (vs ~112 ms with my original
> > patch).
>
> Is this measurable, or also noise?
>
> >
> > (I tested this on Nvidia Grace)
>
>
> Thanks!
Thanks, yeah I agree and my point was that performance looks on par.
I just wanted to share some concrete numbers of what I've tested.
>
> > >
> > > --
> > > MST
> > >
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 2/2] virtio_balloon: submit reported pages as individual buffers
2026-10-27 14:39 ` Ruben Hakobyan
@ 2026-10-27 19:17 ` Michael S. Tsirkin
2026-10-28 15:06 ` Ruben Hakobyan
0 siblings, 1 reply; 8+ messages in thread
From: Michael S. Tsirkin @ 2026-10-27 19:17 UTC (permalink / raw)
To: Ruben Hakobyan
Cc: Jason Wang, Xuan Zhuo, Eugenio Pérez, virtualization,
Alexander Duyck, David Hildenbrand, Miguel Ojeda, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Danilo Krummrich, Andrew Morton,
linux-kernel, rust-for-linux
On Tue, Oct 27, 2026 at 07:39:57AM -0700, Ruben Hakobyan wrote:
> On Tue, Oct 27, 2026 at 12:40 PM Michael S. Tsirkin <mst@redhat.com> wrote:
> > On Tue, Oct 27, 2026 at 05:32:04AM -0700, Ruben Hakobyan wrote:
> > > On Tue, Oct 27, 2026 at 10:35 AM Michael S. Tsirkin <mst@redhat.com> wrote:
> > > > On Tue, Oct 27, 2026 at 02:26:33AM -0700, Ruben Hakobyan wrote:
> > > > > On Mon, Oct 26, 2026 at 11:53 PM Michael S. Tsirkin <mst@redhat.com> wrote:
> > > > > > The virtio_balloon driver reports a scatter-gather list of free pages
> > > > > > to the VMM so it may discard unused pages.
> > > > > >
> > > > > > For an arm64 kernel with 64 KiB pages, the default reporting and
> > > > > > allocation orders allow entries ranging from 2 MiB to 512 MiB. If the
> > > > > > report contains a sufficient number of large entries, we will end up
> > > > > > with a descriptor chain that represents over 4 GiB of memory. This
> > > > > > violates virtio spec, which says:
> > > > > > Drivers MUST NOT add a descriptor chain longer than $2^{32}$ bytes in total;
> > > > > >
> > > > > > Specifically, submitting $2^{32}$ or more breaks Rust-VMM.
> > > > > >
> > > > > > Submit each reported page as a separate virtqueue buffer instead of one
> > > > > > buffer with an sg list of all pages. This also avoids indirect
> > > > > > descriptor allocation (kmalloc in the reporting path).
> > > > > >
> > > > > > To avoid multiple buffers causing interrupt storms, keep callbacks
> > > > > > disabled while we wait for an event.
> > > > > >
> > > > > > TODO: as an alternative, keep using virtqueue_enable_cb_delayed
> > > > > > but add buffers after there's space in the ring.
> > > > > >
> > > > > > Note: if the virtqueue is broken, wait_event on
> > > > > > virtqueue_get_buf hangs. This is a pre-existing issue:
> > > > > > the old single-buffer code had the same hang.
> > > > > >
> > > > > > Reported-by: Ruben Hakobyan <hruben@meta.com>
> > > > > > Cc: Ruben Hakobyan <hruben@meta.com>
> > > > > > Fixes: b0c504f15471 ("virtio-balloon: add support for providing free page reports to host")
> > > > > > Cc: Alexander Duyck <alexander.h.duyck@linux.intel.com>
> > > > > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > > > > > ---
> > > > > >
> > > > > > Notes (changelog):
> > > > > > changes since v1:
> > > > > > keep callbacks disabled while draining: get_buf re-arms the used
> > > > > > event for the next buffer, reintroducing an interrupt per page.
> > > > > > Disable the reporting vq callbacks at probe, and only arm the
> > > > > > delayed callback to wait.
> > > > > >
> > > > >
> > > > > Thanks for the patches! I think sashiko-bot found some issues on broken
> > > > > queues in the first patch that are worth looking into for correctness.
> > > >
> > > > Surprise removal of the balloon? Nope, it's a pre-existing issue that
> > > > it's broken. Besides it's not really practical, no one removes
> > > > the balloon - no need.
> > >
> > > Fair point about that. But I meant the broken queue check.
> > > In virtqueue_enable_cb_delayed() there is:
> > > ```
> > > /*
> > > * When the device is broken there is no point in polling used->idx,
> > > * the backend will never update it. Return true to let callers
> > > * exit their cleanup loops instead of spinning forever.
> > > */
> > > if (unlikely(vq->broken))
> > > return true;
> > > ```
> > >
> > > But virtqueue_enable_cb_delayed_max() doesn't have this. So I was just
> > > thinking the same reasoning should apply here?
> >
> > It's broken there, too. E.g. what is the "cleanup loop" in balloon?
>
> The loop in virtballoon_free_page_report():
> ```
> wait_event(vb->acked, ({
> for (;;) {
> virtqueue_disable_cb(vq);
> while (virtqueue_get_buf(vq, &unused))
> i++;
>
> /* Stop waiting if device used all that we added. */
> if (i >= nents)
> break;
>
> if (virtqueue_enable_cb_delayed_max(vq))
> break;
> }
> i >= nents;
> }));
> ```
>
> For a broken queue, you could exit the for loop early and avoid busy looping.
> It still hangs, but I think it can sleep rather than busy loop?
>
> Anyway, I'm not sure how practical a broken queue is, so I don't have a
> strong opinion.
Maybe add the broken queue check explicitly then, then it does
not need to hang:
if (virtqueue_is_broken(vq))
i = nents;
but the issue is what if queue gets broken while we are waiting.
> >
> > > >
> > > > > Other than that, I tested the "normal path" on QEMU and Cloud Hypervisor,
> > > > > both on 4 KiB and 64 KiB guests, and this works correctly.
> > > >
> > > > Thanks a lot! Can you pls confirm whether the performance is about the
> > > > same/better/worse?
> > >
> > > >From my tests on QEMU, CPU time was about the same as my original patch
> > > and unmodified Linux.
> > >
> > > To bring a concrete example, with these patches it took ~437 ms of CPU to
> > > reclaim a whole 8 GiB with 4 KiB pages (vs ~434 ms on unmodified Linux).
> >
> > OK so that's just noise, there's no difference.
> >
> > >
> > > With 64 KiB pages, it averaged 121 ms CPU (vs ~112 ms with my original
> > > patch).
> >
> > Is this measurable, or also noise?
> >
> > >
> > > (I tested this on Nvidia Grace)
> >
> >
> > Thanks!
>
> Thanks, yeah I agree and my point was that performance looks on par.
> I just wanted to share some concrete numbers of what I've tested.
Thanks a lot!
> >
> > > >
> > > > --
> > > > MST
> > > >
> >
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 2/2] virtio_balloon: submit reported pages as individual buffers
2026-10-27 19:17 ` Michael S. Tsirkin
@ 2026-10-28 15:06 ` Ruben Hakobyan
0 siblings, 0 replies; 8+ messages in thread
From: Ruben Hakobyan @ 2026-10-28 15:06 UTC (permalink / raw)
To: Michael S . Tsirkin
Cc: Jason Wang, Xuan Zhuo, Eugenio Pérez, virtualization,
Alexander Duyck, David Hildenbrand, Miguel Ojeda, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Danilo Krummrich, Andrew Morton,
linux-kernel, rust-for-linux
On Tue, Oct 27, 2026 at 7:17 PM Michael S. Tsirkin <mst@redhat.com> wrote:
> On Tue, Oct 27, 2026 at 07:39:57AM -0700, Ruben Hakobyan wrote:
> > On Tue, Oct 27, 2026 at 12:40 PM Michael S. Tsirkin <mst@redhat.com> wrote:
> > > On Tue, Oct 27, 2026 at 05:32:04AM -0700, Ruben Hakobyan wrote:
> > > > On Tue, Oct 27, 2026 at 10:35 AM Michael S. Tsirkin <mst@redhat.com> wrote:
> > > > > On Tue, Oct 27, 2026 at 02:26:33AM -0700, Ruben Hakobyan wrote:
> > > > > > On Mon, Oct 26, 2026 at 11:53 PM Michael S. Tsirkin <mst@redhat.com> wrote:
> > > > > > > The virtio_balloon driver reports a scatter-gather list of free pages
> > > > > > > to the VMM so it may discard unused pages.
> > > > > > >
> > > > > > > For an arm64 kernel with 64 KiB pages, the default reporting and
> > > > > > > allocation orders allow entries ranging from 2 MiB to 512 MiB. If the
> > > > > > > report contains a sufficient number of large entries, we will end up
> > > > > > > with a descriptor chain that represents over 4 GiB of memory. This
> > > > > > > violates virtio spec, which says:
> > > > > > > Drivers MUST NOT add a descriptor chain longer than $2^{32}$ bytes in total;
> > > > > > >
> > > > > > > Specifically, submitting $2^{32}$ or more breaks Rust-VMM.
> > > > > > >
> > > > > > > Submit each reported page as a separate virtqueue buffer instead of one
> > > > > > > buffer with an sg list of all pages. This also avoids indirect
> > > > > > > descriptor allocation (kmalloc in the reporting path).
> > > > > > >
> > > > > > > To avoid multiple buffers causing interrupt storms, keep callbacks
> > > > > > > disabled while we wait for an event.
> > > > > > >
> > > > > > > TODO: as an alternative, keep using virtqueue_enable_cb_delayed
> > > > > > > but add buffers after there's space in the ring.
> > > > > > >
> > > > > > > Note: if the virtqueue is broken, wait_event on
> > > > > > > virtqueue_get_buf hangs. This is a pre-existing issue:
> > > > > > > the old single-buffer code had the same hang.
> > > > > > >
> > > > > > > Reported-by: Ruben Hakobyan <hruben@meta.com>
> > > > > > > Cc: Ruben Hakobyan <hruben@meta.com>
> > > > > > > Fixes: b0c504f15471 ("virtio-balloon: add support for providing free page reports to host")
> > > > > > > Cc: Alexander Duyck <alexander.h.duyck@linux.intel.com>
> > > > > > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > > > > > > ---
> > > > > > >
> > > > > > > Notes (changelog):
> > > > > > > changes since v1:
> > > > > > > keep callbacks disabled while draining: get_buf re-arms the used
> > > > > > > event for the next buffer, reintroducing an interrupt per page.
> > > > > > > Disable the reporting vq callbacks at probe, and only arm the
> > > > > > > delayed callback to wait.
> > > > > > >
> > > > > >
> > > > > > Thanks for the patches! I think sashiko-bot found some issues on broken
> > > > > > queues in the first patch that are worth looking into for correctness.
> > > > >
> > > > > Surprise removal of the balloon? Nope, it's a pre-existing issue that
> > > > > it's broken. Besides it's not really practical, no one removes
> > > > > the balloon - no need.
> > > >
> > > > Fair point about that. But I meant the broken queue check.
> > > > In virtqueue_enable_cb_delayed() there is:
> > > > ```
> > > > /*
> > > > * When the device is broken there is no point in polling used->idx,
> > > > * the backend will never update it. Return true to let callers
> > > > * exit their cleanup loops instead of spinning forever.
> > > > */
> > > > if (unlikely(vq->broken))
> > > > return true;
> > > > ```
> > > >
> > > > But virtqueue_enable_cb_delayed_max() doesn't have this. So I was just
> > > > thinking the same reasoning should apply here?
> > >
> > > It's broken there, too. E.g. what is the "cleanup loop" in balloon?
> >
> > The loop in virtballoon_free_page_report():
> > ```
> > wait_event(vb->acked, ({
> > for (;;) {
> > virtqueue_disable_cb(vq);
> > while (virtqueue_get_buf(vq, &unused))
> > i++;
> >
> > /* Stop waiting if device used all that we added. */
> > if (i >= nents)
> > break;
> >
> > if (virtqueue_enable_cb_delayed_max(vq))
> > break;
> > }
> > i >= nents;
> > }));
> > ```
> >
> > For a broken queue, you could exit the for loop early and avoid busy looping.
> > It still hangs, but I think it can sleep rather than busy loop?
> >
> > Anyway, I'm not sure how practical a broken queue is, so I don't have a
> > strong opinion.
>
> Maybe add the broken queue check explicitly then, then it does
> not need to hang:
>
> if (virtqueue_is_broken(vq))
> i = nents;
>
Ah yeah, indeed that would avoid the hang on the broken queue.
>
> but the issue is what if queue gets broken while we are waiting.
>
Hmm, yeah I see. I guess that's already outside of scope here.
>
> > >
> > > > >
> > > > > > Other than that, I tested the "normal path" on QEMU and Cloud Hypervisor,
> > > > > > both on 4 KiB and 64 KiB guests, and this works correctly.
> > > > >
> > > > > Thanks a lot! Can you pls confirm whether the performance is about the
> > > > > same/better/worse?
> > > >
> > > > >From my tests on QEMU, CPU time was about the same as my original patch
> > > > and unmodified Linux.
> > > >
> > > > To bring a concrete example, with these patches it took ~437 ms of CPU to
> > > > reclaim a whole 8 GiB with 4 KiB pages (vs ~434 ms on unmodified Linux).
> > >
> > > OK so that's just noise, there's no difference.
> > >
> > > >
> > > > With 64 KiB pages, it averaged 121 ms CPU (vs ~112 ms with my original
> > > > patch).
> > >
> > > Is this measurable, or also noise?
> > >
> > > >
> > > > (I tested this on Nvidia Grace)
> > >
> > >
> > > Thanks!
> >
> > Thanks, yeah I agree and my point was that performance looks on par.
> > I just wanted to share some concrete numbers of what I've tested.
>
> Thanks a lot!
Thanks again for the patches and for looking into this!
>
> > >
> > > > >
> > > > > --
> > > > > MST
> > > > >
> > >
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-10-28 15:06 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <32e21059adb6cb1fd08c3f4426a313c77cf450ec.1793057483.git.mst@redhat.com>
2026-10-26 23:53 ` [PATCH v2 2/2] virtio_balloon: submit reported pages as individual buffers Michael S. Tsirkin
2026-10-27 9:26 ` Ruben Hakobyan
2026-10-27 10:34 ` Michael S. Tsirkin
2026-10-27 12:32 ` Ruben Hakobyan
2026-10-27 12:40 ` Michael S. Tsirkin
2026-10-27 14:39 ` Ruben Hakobyan
2026-10-27 19:17 ` Michael S. Tsirkin
2026-10-28 15:06 ` Ruben Hakobyan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox