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 <[email protected]> --- 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
