Skip to content

Commit b12fbc3

Browse files
David Stevensmstsirkin
authored andcommitted
virtio_balloon: stay awake while adjusting balloon
A virtio_balloon's parent device may be configured so that a configuration change interrupt is a wakeup event. Extend the processing of such a wakeup event until the balloon finishes inflating or deflating by calling pm_stay_awake/pm_relax in the virtio_balloon driver. Note that these calls are no-ops if the parent device doesn't support wakeup events or if the wakeup events are not enabled. This change allows the guest to use system power states such as s2idle without running the risk the virtio_balloon's cooperative memory management becoming unresponsive to the host's requests. Tested-by: Theodore Ts'o <tytso@mit.edu> Signed-off-by: David Stevens <stevensd@chromium.org> Signed-off-by: Theodore Ts'o <tytso@mit.edu> Message-Id: <20240110021925.1137333-1-stevensd@google.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
1 parent c271fcd commit b12fbc3

1 file changed

Lines changed: 47 additions & 10 deletions

File tree

drivers/virtio/virtio_balloon.c

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@ struct virtio_balloon {
119119
/* Free page reporting device */
120120
struct virtqueue *reporting_vq;
121121
struct page_reporting_dev_info pr_dev_info;
122+
123+
/* State for keeping the wakeup_source active while adjusting the balloon */
124+
spinlock_t adjustment_lock;
125+
bool adjustment_signal_pending;
126+
bool adjustment_in_progress;
122127
};
123128

124129
static const struct virtio_device_id id_table[] = {
@@ -437,15 +442,39 @@ static void virtio_balloon_queue_free_page_work(struct virtio_balloon *vb)
437442
queue_work(vb->balloon_wq, &vb->report_free_page_work);
438443
}
439444

445+
static void start_update_balloon_size(struct virtio_balloon *vb)
446+
{
447+
unsigned long flags;
448+
449+
spin_lock_irqsave(&vb->adjustment_lock, flags);
450+
vb->adjustment_signal_pending = true;
451+
if (!vb->adjustment_in_progress) {
452+
vb->adjustment_in_progress = true;
453+
pm_stay_awake(vb->vdev->dev.parent);
454+
}
455+
spin_unlock_irqrestore(&vb->adjustment_lock, flags);
456+
457+
queue_work(system_freezable_wq, &vb->update_balloon_size_work);
458+
}
459+
460+
static void end_update_balloon_size(struct virtio_balloon *vb)
461+
{
462+
spin_lock_irq(&vb->adjustment_lock);
463+
if (!vb->adjustment_signal_pending && vb->adjustment_in_progress) {
464+
vb->adjustment_in_progress = false;
465+
pm_relax(vb->vdev->dev.parent);
466+
}
467+
spin_unlock_irq(&vb->adjustment_lock);
468+
}
469+
440470
static void virtballoon_changed(struct virtio_device *vdev)
441471
{
442472
struct virtio_balloon *vb = vdev->priv;
443473
unsigned long flags;
444474

445475
spin_lock_irqsave(&vb->stop_update_lock, flags);
446476
if (!vb->stop_update) {
447-
queue_work(system_freezable_wq,
448-
&vb->update_balloon_size_work);
477+
start_update_balloon_size(vb);
449478
virtio_balloon_queue_free_page_work(vb);
450479
}
451480
spin_unlock_irqrestore(&vb->stop_update_lock, flags);
@@ -476,19 +505,25 @@ static void update_balloon_size_func(struct work_struct *work)
476505

477506
vb = container_of(work, struct virtio_balloon,
478507
update_balloon_size_work);
479-
diff = towards_target(vb);
480508

481-
if (!diff)
482-
return;
509+
spin_lock_irq(&vb->adjustment_lock);
510+
vb->adjustment_signal_pending = false;
511+
spin_unlock_irq(&vb->adjustment_lock);
483512

484-
if (diff > 0)
485-
diff -= fill_balloon(vb, diff);
486-
else
487-
diff += leak_balloon(vb, -diff);
488-
update_balloon_size(vb);
513+
diff = towards_target(vb);
514+
515+
if (diff) {
516+
if (diff > 0)
517+
diff -= fill_balloon(vb, diff);
518+
else
519+
diff += leak_balloon(vb, -diff);
520+
update_balloon_size(vb);
521+
}
489522

490523
if (diff)
491524
queue_work(system_freezable_wq, work);
525+
else
526+
end_update_balloon_size(vb);
492527
}
493528

494529
static int init_vqs(struct virtio_balloon *vb)
@@ -992,6 +1027,8 @@ static int virtballoon_probe(struct virtio_device *vdev)
9921027
goto out_unregister_oom;
9931028
}
9941029

1030+
spin_lock_init(&vb->adjustment_lock);
1031+
9951032
virtio_device_ready(vdev);
9961033

9971034
if (towards_target(vb))

0 commit comments

Comments
 (0)