|
| 1 | +From b90e190a95c256d6ef0d7ed5ad42649decfdb6e0 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Jack Thomson <jackabt@amazon.com> |
| 3 | +Date: Mon, 19 Jan 2026 15:42:36 +0000 |
| 4 | +Subject: [PATCH] virtio_balloon: Support wait on ACK for hinting |
| 5 | + |
| 6 | +This RFC patch adds a new virtio feature for the virtio-balloon driver |
| 7 | +during free page hinting, which will wait on device ack before |
| 8 | +committing the range to the free_page_list. The reason for the change is |
| 9 | +it allows the device to modify this range without it being reclaimed |
| 10 | +from the free_page_list before the ack is sent. As expected, testing |
| 11 | +shows this adds overhead to the hinting run duration, increasing it by |
| 12 | +~30% with our Firecracker setup. Currently free page hinting is used |
| 13 | +mainly for live migration, but this would open it up for a new use-case. |
| 14 | + |
| 15 | +We would like to leverage this with MADV_DONTNEED to reduce RSS of a |
| 16 | +guest. We'd like to use hinting because of the flexibility of control it |
| 17 | +brings compared to reporting, allowing memory to be reclaimed in |
| 18 | +deterministic periods. The traditional balloon device was tested to be |
| 19 | +much slower when compared to hinting for these workloads. Currently, |
| 20 | +without this synchronization, hinted pages may be reclaimed from the |
| 21 | +free list before the device finishes processing them, making hinting |
| 22 | +unsuitable for this use-case. |
| 23 | + |
| 24 | +Signed-off-by: Jack Thomson <jackabt@amazon.com> |
| 25 | +--- |
| 26 | + drivers/virtio/virtio_balloon.c | 19 ++++++++++++++++--- |
| 27 | + include/uapi/linux/virtio_balloon.h | 1 + |
| 28 | + 2 files changed, 17 insertions(+), 3 deletions(-) |
| 29 | + |
| 30 | +diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c |
| 31 | +index fba0d8c5dcdf..d9fffefa4a05 100644 |
| 32 | +--- a/drivers/virtio/virtio_balloon.c |
| 33 | ++++ b/drivers/virtio/virtio_balloon.c |
| 34 | +@@ -575,7 +575,8 @@ static int init_vqs(struct virtio_balloon *vb) |
| 35 | + |
| 36 | + if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) { |
| 37 | + names[VIRTIO_BALLOON_VQ_FREE_PAGE] = "free_page_vq"; |
| 38 | +- callbacks[VIRTIO_BALLOON_VQ_FREE_PAGE] = NULL; |
| 39 | ++ if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_HINT_WAIT_ON_ACK)) |
| 40 | ++ callbacks[VIRTIO_BALLOON_VQ_FREE_PAGE] = balloon_ack; |
| 41 | + } |
| 42 | + |
| 43 | + if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_REPORTING)) { |
| 44 | +@@ -648,8 +649,11 @@ static int send_cmd_id_start(struct virtio_balloon *vb) |
| 45 | + virtio_balloon_cmd_id_received(vb)); |
| 46 | + sg_init_one(&sg, &vb->cmd_id_active, sizeof(vb->cmd_id_active)); |
| 47 | + err = virtqueue_add_outbuf(vq, &sg, 1, &vb->cmd_id_active, GFP_KERNEL); |
| 48 | +- if (!err) |
| 49 | ++ if (!err) { |
| 50 | + virtqueue_kick(vq); |
| 51 | ++ if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_HINT_WAIT_ON_ACK)) |
| 52 | ++ wait_event(vb->acked, virtqueue_get_buf(vq, &unused)); |
| 53 | ++ } |
| 54 | + return err; |
| 55 | + } |
| 56 | + |
| 57 | +@@ -665,8 +669,11 @@ static int send_cmd_id_stop(struct virtio_balloon *vb) |
| 58 | + |
| 59 | + sg_init_one(&sg, &vb->cmd_id_stop, sizeof(vb->cmd_id_stop)); |
| 60 | + err = virtqueue_add_outbuf(vq, &sg, 1, &vb->cmd_id_stop, GFP_KERNEL); |
| 61 | +- if (!err) |
| 62 | ++ if (!err) { |
| 63 | + virtqueue_kick(vq); |
| 64 | ++ if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_HINT_WAIT_ON_ACK)) |
| 65 | ++ wait_event(vb->acked, virtqueue_get_buf(vq, &unused)); |
| 66 | ++ } |
| 67 | + return err; |
| 68 | + } |
| 69 | + |
| 70 | +@@ -702,6 +709,8 @@ static int get_free_page_and_send(struct virtio_balloon *vb) |
| 71 | + return err; |
| 72 | + } |
| 73 | + virtqueue_kick(vq); |
| 74 | ++ if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_HINT_WAIT_ON_ACK)) |
| 75 | ++ wait_event(vb->acked, virtqueue_get_buf(vq, &unused)); |
| 76 | + spin_lock_irq(&vb->free_page_list_lock); |
| 77 | + balloon_page_push(&vb->free_page_list, page); |
| 78 | + vb->num_free_page_blocks++; |
| 79 | +@@ -1152,6 +1161,9 @@ static int virtballoon_validate(struct virtio_device *vdev) |
| 80 | + else if (!virtio_has_feature(vdev, VIRTIO_BALLOON_F_PAGE_POISON)) |
| 81 | + __virtio_clear_bit(vdev, VIRTIO_BALLOON_F_REPORTING); |
| 82 | + |
| 83 | ++ if (!virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) |
| 84 | ++ __virtio_clear_bit(vdev, VIRTIO_BALLOON_F_HINT_WAIT_ON_ACK); |
| 85 | ++ |
| 86 | + __virtio_clear_bit(vdev, VIRTIO_F_ACCESS_PLATFORM); |
| 87 | + return 0; |
| 88 | + } |
| 89 | +@@ -1163,6 +1175,7 @@ static unsigned int features[] = { |
| 90 | + VIRTIO_BALLOON_F_FREE_PAGE_HINT, |
| 91 | + VIRTIO_BALLOON_F_PAGE_POISON, |
| 92 | + VIRTIO_BALLOON_F_REPORTING, |
| 93 | ++ VIRTIO_BALLOON_F_HINT_WAIT_ON_ACK, |
| 94 | + }; |
| 95 | + |
| 96 | + static struct virtio_driver virtio_balloon_driver = { |
| 97 | +diff --git a/include/uapi/linux/virtio_balloon.h b/include/uapi/linux/virtio_balloon.h |
| 98 | +index ddaa45e723c4..1705d9191f7e 100644 |
| 99 | +--- a/include/uapi/linux/virtio_balloon.h |
| 100 | ++++ b/include/uapi/linux/virtio_balloon.h |
| 101 | +@@ -37,6 +37,7 @@ |
| 102 | + #define VIRTIO_BALLOON_F_FREE_PAGE_HINT 3 /* VQ to report free pages */ |
| 103 | + #define VIRTIO_BALLOON_F_PAGE_POISON 4 /* Guest is using page poisoning */ |
| 104 | + #define VIRTIO_BALLOON_F_REPORTING 5 /* Page reporting virtqueue */ |
| 105 | ++#define VIRTIO_BALLOON_F_HINT_WAIT_ON_ACK 6 /* Page hinting waits on device ack */ |
| 106 | + |
| 107 | + /* Size of a PFN in the balloon interface. */ |
| 108 | + #define VIRTIO_BALLOON_PFN_SHIFT 12 |
| 109 | +-- |
| 110 | +2.51.0 |
| 111 | + |
0 commit comments