diff options
-rw-r--r-- | drivers/virtio/virtio_balloon.c | 52 | ||||
-rw-r--r-- | include/uapi/linux/virtio_balloon.h | 1 |
2 files changed, 53 insertions, 0 deletions
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index ff71fdcf3345..50c5f42d7a9f 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
30 | #include <linux/balloon_compaction.h> | 30 | #include <linux/balloon_compaction.h> |
31 | #include <linux/oom.h> | ||
31 | 32 | ||
32 | /* | 33 | /* |
33 | * Balloon device works in 4K page units. So each page is pointed to by | 34 | * Balloon device works in 4K page units. So each page is pointed to by |
@@ -36,6 +37,12 @@ | |||
36 | */ | 37 | */ |
37 | #define VIRTIO_BALLOON_PAGES_PER_PAGE (unsigned)(PAGE_SIZE >> VIRTIO_BALLOON_PFN_SHIFT) | 38 | #define VIRTIO_BALLOON_PAGES_PER_PAGE (unsigned)(PAGE_SIZE >> VIRTIO_BALLOON_PFN_SHIFT) |
38 | #define VIRTIO_BALLOON_ARRAY_PFNS_MAX 256 | 39 | #define VIRTIO_BALLOON_ARRAY_PFNS_MAX 256 |
40 | #define OOM_VBALLOON_DEFAULT_PAGES 256 | ||
41 | #define VIRTBALLOON_OOM_NOTIFY_PRIORITY 80 | ||
42 | |||
43 | static int oom_pages = OOM_VBALLOON_DEFAULT_PAGES; | ||
44 | module_param(oom_pages, int, S_IRUSR | S_IWUSR); | ||
45 | MODULE_PARM_DESC(oom_pages, "pages to free on OOM"); | ||
39 | 46 | ||
40 | struct virtio_balloon | 47 | struct virtio_balloon |
41 | { | 48 | { |
@@ -71,6 +78,9 @@ struct virtio_balloon | |||
71 | /* Memory statistics */ | 78 | /* Memory statistics */ |
72 | int need_stats_update; | 79 | int need_stats_update; |
73 | struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR]; | 80 | struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR]; |
81 | |||
82 | /* To register callback in oom notifier call chain */ | ||
83 | struct notifier_block nb; | ||
74 | }; | 84 | }; |
75 | 85 | ||
76 | static struct virtio_device_id id_table[] = { | 86 | static struct virtio_device_id id_table[] = { |
@@ -290,6 +300,38 @@ static void update_balloon_size(struct virtio_balloon *vb) | |||
290 | &actual); | 300 | &actual); |
291 | } | 301 | } |
292 | 302 | ||
303 | /* | ||
304 | * virtballoon_oom_notify - release pages when system is under severe | ||
305 | * memory pressure (called from out_of_memory()) | ||
306 | * @self : notifier block struct | ||
307 | * @dummy: not used | ||
308 | * @parm : returned - number of freed pages | ||
309 | * | ||
310 | * The balancing of memory by use of the virtio balloon should not cause | ||
311 | * the termination of processes while there are pages in the balloon. | ||
312 | * If virtio balloon manages to release some memory, it will make the | ||
313 | * system return and retry the allocation that forced the OOM killer | ||
314 | * to run. | ||
315 | */ | ||
316 | static int virtballoon_oom_notify(struct notifier_block *self, | ||
317 | unsigned long dummy, void *parm) | ||
318 | { | ||
319 | struct virtio_balloon *vb; | ||
320 | unsigned long *freed; | ||
321 | unsigned num_freed_pages; | ||
322 | |||
323 | vb = container_of(self, struct virtio_balloon, nb); | ||
324 | if (!virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) | ||
325 | return NOTIFY_OK; | ||
326 | |||
327 | freed = parm; | ||
328 | num_freed_pages = leak_balloon(vb, oom_pages); | ||
329 | update_balloon_size(vb); | ||
330 | *freed += num_freed_pages; | ||
331 | |||
332 | return NOTIFY_OK; | ||
333 | } | ||
334 | |||
293 | static int balloon(void *_vballoon) | 335 | static int balloon(void *_vballoon) |
294 | { | 336 | { |
295 | struct virtio_balloon *vb = _vballoon; | 337 | struct virtio_balloon *vb = _vballoon; |
@@ -446,6 +488,12 @@ static int virtballoon_probe(struct virtio_device *vdev) | |||
446 | if (err) | 488 | if (err) |
447 | goto out_free_vb; | 489 | goto out_free_vb; |
448 | 490 | ||
491 | vb->nb.notifier_call = virtballoon_oom_notify; | ||
492 | vb->nb.priority = VIRTBALLOON_OOM_NOTIFY_PRIORITY; | ||
493 | err = register_oom_notifier(&vb->nb); | ||
494 | if (err < 0) | ||
495 | goto out_oom_notify; | ||
496 | |||
449 | vb->thread = kthread_run(balloon, vb, "vballoon"); | 497 | vb->thread = kthread_run(balloon, vb, "vballoon"); |
450 | if (IS_ERR(vb->thread)) { | 498 | if (IS_ERR(vb->thread)) { |
451 | err = PTR_ERR(vb->thread); | 499 | err = PTR_ERR(vb->thread); |
@@ -455,6 +503,8 @@ static int virtballoon_probe(struct virtio_device *vdev) | |||
455 | return 0; | 503 | return 0; |
456 | 504 | ||
457 | out_del_vqs: | 505 | out_del_vqs: |
506 | unregister_oom_notifier(&vb->nb); | ||
507 | out_oom_notify: | ||
458 | vdev->config->del_vqs(vdev); | 508 | vdev->config->del_vqs(vdev); |
459 | out_free_vb: | 509 | out_free_vb: |
460 | kfree(vb); | 510 | kfree(vb); |
@@ -479,6 +529,7 @@ static void virtballoon_remove(struct virtio_device *vdev) | |||
479 | { | 529 | { |
480 | struct virtio_balloon *vb = vdev->priv; | 530 | struct virtio_balloon *vb = vdev->priv; |
481 | 531 | ||
532 | unregister_oom_notifier(&vb->nb); | ||
482 | kthread_stop(vb->thread); | 533 | kthread_stop(vb->thread); |
483 | remove_common(vb); | 534 | remove_common(vb); |
484 | kfree(vb); | 535 | kfree(vb); |
@@ -518,6 +569,7 @@ static int virtballoon_restore(struct virtio_device *vdev) | |||
518 | static unsigned int features[] = { | 569 | static unsigned int features[] = { |
519 | VIRTIO_BALLOON_F_MUST_TELL_HOST, | 570 | VIRTIO_BALLOON_F_MUST_TELL_HOST, |
520 | VIRTIO_BALLOON_F_STATS_VQ, | 571 | VIRTIO_BALLOON_F_STATS_VQ, |
572 | VIRTIO_BALLOON_F_DEFLATE_ON_OOM, | ||
521 | }; | 573 | }; |
522 | 574 | ||
523 | static struct virtio_driver virtio_balloon_driver = { | 575 | static struct virtio_driver virtio_balloon_driver = { |
diff --git a/include/uapi/linux/virtio_balloon.h b/include/uapi/linux/virtio_balloon.h index 5e26f61b5df5..be40f7059e93 100644 --- a/include/uapi/linux/virtio_balloon.h +++ b/include/uapi/linux/virtio_balloon.h | |||
@@ -31,6 +31,7 @@ | |||
31 | /* The feature bitmap for virtio balloon */ | 31 | /* The feature bitmap for virtio balloon */ |
32 | #define VIRTIO_BALLOON_F_MUST_TELL_HOST 0 /* Tell before reclaiming pages */ | 32 | #define VIRTIO_BALLOON_F_MUST_TELL_HOST 0 /* Tell before reclaiming pages */ |
33 | #define VIRTIO_BALLOON_F_STATS_VQ 1 /* Memory Stats virtqueue */ | 33 | #define VIRTIO_BALLOON_F_STATS_VQ 1 /* Memory Stats virtqueue */ |
34 | #define VIRTIO_BALLOON_F_DEFLATE_ON_OOM 2 /* Deflate balloon on OOM */ | ||
34 | 35 | ||
35 | /* Size of a PFN in the balloon interface. */ | 36 | /* Size of a PFN in the balloon interface. */ |
36 | #define VIRTIO_BALLOON_PFN_SHIFT 12 | 37 | #define VIRTIO_BALLOON_PFN_SHIFT 12 |