* [PATCH 2/2] virtio_balloon: submit reported pages as individual buffers [not found] <ad6a530f49c4a0e182112a73789e31b5e91f3bb7.1793026707.git.mst@redhat.com> @ 2026-10-26 15:09 ` Michael S. Tsirkin 2026-10-26 16:00 ` Michael S. Tsirkin 0 siblings, 1 reply; 2+ messages in thread From: Michael S. Tsirkin @ 2026-10-26 15:09 UTC (permalink / raw) To: linux-kernel Cc: Jason Wang, Xuan Zhuo, Eugenio Pérez, virtualization, Ruben Hakobyan, David Hildenbrand, Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, 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. 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> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> --- Lightly tested. Ruben, could you pls help test? drivers/virtio/virtio_balloon.c | 48 ++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index f6c2dff33f8a..363519fa890d 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -202,25 +202,47 @@ 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) { + virtqueue_kick(vq); - return 0; + /* When host has read buffer, this completes via balloon_ack. + * We report pages as individual buffers, so arm the callback + * to only interrupt once all the queued buffers have been + * used: otherwise we would get one interrupt per page. + */ + for (i = 0; i < nents; i++) { + unsigned int unused; + + virtqueue_enable_cb_delayed_max(vq); + wait_event(vb->acked, + virtqueue_get_buf(vq, &unused)); + virtqueue_disable_cb(vq); + } + } + + return err; } static void set_page_pfns(struct virtio_balloon *vb, -- MST ^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH 2/2] virtio_balloon: submit reported pages as individual buffers 2026-10-26 15:09 ` [PATCH 2/2] virtio_balloon: submit reported pages as individual buffers Michael S. Tsirkin @ 2026-10-26 16:00 ` Michael S. Tsirkin 0 siblings, 0 replies; 2+ messages in thread From: Michael S. Tsirkin @ 2026-10-26 16:00 UTC (permalink / raw) To: linux-kernel Cc: Jason Wang, Xuan Zhuo, Eugenio Pérez, virtualization, Ruben Hakobyan, David Hildenbrand, Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, rust-for-linux On Mon, Oct 26, 2026 at 11:09:59AM -0400, Michael S. Tsirkin 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. > > 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> > Signed-off-by: Michael S. Tsirkin <mst@redhat.com> brown paperbag post,forgot to commit. > --- > > Lightly tested. Ruben, could you pls help test? > > drivers/virtio/virtio_balloon.c | 48 ++++++++++++++++++++++++--------- > 1 file changed, 35 insertions(+), 13 deletions(-) > > diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c > index f6c2dff33f8a..363519fa890d 100644 > --- a/drivers/virtio/virtio_balloon.c > +++ b/drivers/virtio/virtio_balloon.c > @@ -202,25 +202,47 @@ 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) { > + virtqueue_kick(vq); > > - return 0; > + /* When host has read buffer, this completes via balloon_ack. > + * We report pages as individual buffers, so arm the callback > + * to only interrupt once all the queued buffers have been > + * used: otherwise we would get one interrupt per page. > + */ > + for (i = 0; i < nents; i++) { > + unsigned int unused; > + > + virtqueue_enable_cb_delayed_max(vq); > + wait_event(vb->acked, > + virtqueue_get_buf(vq, &unused)); > + virtqueue_disable_cb(vq); > + } > + } > + > + return err; > } > > static void set_page_pfns(struct virtio_balloon *vb, > -- > MST > ^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-10-26 16:00 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <ad6a530f49c4a0e182112a73789e31b5e91f3bb7.1793026707.git.mst@redhat.com>
2026-10-26 15:09 ` [PATCH 2/2] virtio_balloon: submit reported pages as individual buffers Michael S. Tsirkin
2026-10-26 16:00 ` Michael S. Tsirkin
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox