[PATCH 11/13] virtio_balloon: unaccept free reporting ranges

From: Kevin Loughlin

Date: Mon Oct 26 2026 - 22:58:11 EST


In confidential computing guests with dynamic unaccepted memory
transitions, configure the free page reporting order to
unaccepted_memory_order(). Invoke mark_memory_unaccepted() on each
scatterlist range in virtballoon_free_page_report() before adding the
scatterlist to reporting_vq and kicking the host.

Unaccepting the pages prior to virtqueue_add_inbuf() and virtqueue_kick()
guarantees that the guest finishes PVALIDATE(validate=false) before the
host VMM can observe the reporting request in the virtqueue ring and
punch a hole in guest_memfd, eliminating any race where the guest
re-allocates and re-accepts a page before a deferred host hole-punch
executes.

Signed-off-by: Kevin Loughlin <kevinloughlin@xxxxxxxxxx>
---
drivers/virtio/virtio_balloon.c | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index d162c162b496..e10bd792ef7c 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -213,7 +213,26 @@ 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 unused;
+ int err;
+
+ if (virtballoon_cc_needs_state_transition()) {
+ unsigned long unit_size = PAGE_SIZE << unaccepted_memory_order();
+ struct scatterlist *sgl;
+ unsigned int i;
+
+ for_each_sg(sg, sgl, nents, i) {
+ if (WARN_ON_ONCE(!IS_ALIGNED(sg_phys(sgl), unit_size) ||
+ !IS_ALIGNED(sgl->length, unit_size)))
+ return -EINVAL;
+ }
+ for_each_sg(sg, sgl, nents, i) {
+ err = mark_memory_unaccepted(sg_phys(sgl), sgl->length);
+ if (err)
+ return err;
+ cond_resched();
+ }
+ }

/* We should always be able to add these buffers to an empty queue. */
err = virtqueue_add_inbuf(vq, sg, nents, vb, GFP_NOWAIT);
@@ -1142,8 +1161,11 @@ static int virtballoon_probe(struct virtio_device *vdev)
* host's base page size. However, it needs more work to report
* that value. The hard-coded order would be fine currently.
*/
+ if (virtballoon_cc_needs_state_transition())
+ vb->pr_dev_info.order = unaccepted_memory_order();
#if defined(CONFIG_ARM64) && defined(CONFIG_ARM64_64K_PAGES)
- vb->pr_dev_info.order = 5;
+ else
+ vb->pr_dev_info.order = 5;
#endif

vb->pr_dev_info.capacity = capacity;
--
2.56.0.307.g5fe7bd680c-goog