aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaushaniya Maksudova <rmaksudova@parallels.com>2014-11-09 18:06:29 -0500
committerRusty Russell <rusty@rustcorp.com.au>2014-11-11 01:39:58 -0500
commit5a10b7dbf904bfe01bb9fcc6298f7df09eed77d5 (patch)
treecd8f823828105f03c4ae7149217f827f3d82c39d
parent1fd9c67203af91977bf3b964ff3744cf74fc6f3f (diff)
virtio_balloon: free some memory from balloon on OOM
Excessive virtio_balloon inflation can cause invocation of OOM-killer, when Linux is under severe memory pressure. Various mechanisms are responsible for correct virtio_balloon memory management. Nevertheless it is often the case that these control tools does not have enough time to react on fast changing memory load. As a result OS runs out of memory and invokes OOM-killer. The balancing of memory by use of the virtio balloon should not cause the termination of processes while there are pages in the balloon. Now there is no way for virtio balloon driver to free some memory at the last moment before some process will be get killed by OOM-killer. This does not provide a security breach as balloon itself is running inside guest OS and is working in the cooperation with the host. Thus some improvements from guest side should be considered as normal. To solve the problem, introduce a virtio_balloon callback which is expected to be called from the oom notifier call chain in out_of_memory() function. If virtio balloon could release some memory, it will make the system to return and retry the allocation that forced the out of memory killer to run. Allocate virtio feature bit for this: it is not set by default, the the guest will not deflate virtio balloon on OOM without explicit permission from host. Signed-off-by: Raushaniya Maksudova <rmaksudova@parallels.com> Signed-off-by: Denis V. Lunev <den@openvz.org> Acked-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r--drivers/virtio/virtio_balloon.c52
-rw-r--r--include/uapi/linux/virtio_balloon.h1
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
43static int oom_pages = OOM_VBALLOON_DEFAULT_PAGES;
44module_param(oom_pages, int, S_IRUSR | S_IWUSR);
45MODULE_PARM_DESC(oom_pages, "pages to free on OOM");
39 46
40struct virtio_balloon 47struct 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
76static struct virtio_device_id id_table[] = { 86static 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 */
316static 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
293static int balloon(void *_vballoon) 335static 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
457out_del_vqs: 505out_del_vqs:
506 unregister_oom_notifier(&vb->nb);
507out_oom_notify:
458 vdev->config->del_vqs(vdev); 508 vdev->config->del_vqs(vdev);
459out_free_vb: 509out_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)
518static unsigned int features[] = { 569static 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
523static struct virtio_driver virtio_balloon_driver = { 575static 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