aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/virtio
diff options
context:
space:
mode:
authorAmit Shah <amit.shah@redhat.com>2011-12-22 06:28:35 -0500
committerRusty Russell <rusty@rustcorp.com.au>2012-01-12 00:14:47 -0500
commite562966dbaf49e7804097cd991e5d3a8934fc148 (patch)
tree08d1b0bda7ddf76d9cce26c1a340ac86de541033 /drivers/virtio
parentbe91c33dd15eff6b0dffc60cee4c8042e75493d2 (diff)
virtio: balloon: Add freeze, restore handlers to support S4
Handling balloon hibernate / restore is tricky. If the balloon was inflated before going into the hibernation state, upon resume, the host will not have any memory of that. Any pages that were passed on to the host earlier would most likely be invalid, and the host will have to re-balloon to the previous value to get in the pre-hibernate state. So the only sane thing for the guest to do here is to discard all the pages that were put in the balloon. When to discard the pages is the next question. One solution is to deflate the balloon just before writing the image to the disk (in the freeze() PM callback). However, asking for pages from the host just to discard them immediately after seems wasteful of resources. Hence, it makes sense to do this by just fudging our counters soon after wakeup. This means we don't deflate the balloon before sleep, and also don't put unnecessary pressure on the host. This also helps in the thaw case: if the freeze fails for whatever reason, the balloon should continue to remain in the inflated state. This was tested by issuing 'swapoff -a' and trying to go into the S4 state. That fails, and the balloon stays inflated, as expected. Both the host and the guest are happy. Finally, in the restore() callback, we empty the list of pages that were previously given off to the host, add the appropriate number of pages to the totalram_pages counter, reset the num_pages counter to 0, and all is fine. As a last step, delete the vqs on the freeze callback to prepare for hibernation, and re-create them in the restore and thaw callbacks to resume normal operation. The kthread doesn't race with any operations here, since it's frozen before the freeze() call and is thawed after the thaw() and restore() callbacks, so we're safe with that. Signed-off-by: Amit Shah <amit.shah@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/virtio')
-rw-r--r--drivers/virtio/virtio_balloon.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 3368cb6ef193..95aeedf198f8 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -364,6 +364,48 @@ static void __devexit virtballoon_remove(struct virtio_device *vdev)
364 kfree(vb); 364 kfree(vb);
365} 365}
366 366
367#ifdef CONFIG_PM
368static int virtballoon_freeze(struct virtio_device *vdev)
369{
370 /*
371 * The kthread is already frozen by the PM core before this
372 * function is called.
373 */
374
375 /* Ensure we don't get any more requests from the host */
376 vdev->config->reset(vdev);
377 vdev->config->del_vqs(vdev);
378 return 0;
379}
380
381static int virtballoon_thaw(struct virtio_device *vdev)
382{
383 return init_vqs(vdev->priv);
384}
385
386static int virtballoon_restore(struct virtio_device *vdev)
387{
388 struct virtio_balloon *vb = vdev->priv;
389 struct page *page, *page2;
390
391 /* We're starting from a clean slate */
392 vb->num_pages = 0;
393
394 /*
395 * If a request wasn't complete at the time of freezing, this
396 * could have been set.
397 */
398 vb->need_stats_update = 0;
399
400 /* We don't have these pages in the balloon anymore! */
401 list_for_each_entry_safe(page, page2, &vb->pages, lru) {
402 list_del(&page->lru);
403 totalram_pages++;
404 }
405 return init_vqs(vdev->priv);
406}
407#endif
408
367static unsigned int features[] = { 409static unsigned int features[] = {
368 VIRTIO_BALLOON_F_MUST_TELL_HOST, 410 VIRTIO_BALLOON_F_MUST_TELL_HOST,
369 VIRTIO_BALLOON_F_STATS_VQ, 411 VIRTIO_BALLOON_F_STATS_VQ,
@@ -378,6 +420,11 @@ static struct virtio_driver virtio_balloon_driver = {
378 .probe = virtballoon_probe, 420 .probe = virtballoon_probe,
379 .remove = __devexit_p(virtballoon_remove), 421 .remove = __devexit_p(virtballoon_remove),
380 .config_changed = virtballoon_changed, 422 .config_changed = virtballoon_changed,
423#ifdef CONFIG_PM
424 .freeze = virtballoon_freeze,
425 .restore = virtballoon_restore,
426 .thaw = virtballoon_thaw,
427#endif
381}; 428};
382 429
383static int __init init(void) 430static int __init init(void)