Merge tag 'virtio-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 17 Dec 2014 18:37:56 +0000 (10:37 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 17 Dec 2014 18:37:56 +0000 (10:37 -0800)
Pull virtio updates from Rusty Russell:
 "A balloon enhancement, and a minor race-on-module-unload theoretical
  bug which doesn't merit cc: stable.

  All the exciting stuff went via MST this cycle"

* tag 'virtio-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux:
  virtio_balloon: free some memory from balloon on OOM
  virtio_balloon: return the amount of freed memory from leak_balloon()
  virtio_blk: fix race at module removal
  virtio: Fix comment typo 'CONFIG_S_FAILED'

drivers/virtio/virtio_balloon.c
include/linux/virtio.h
include/uapi/linux/virtio_balloon.h

index c9703d4..50c5f42 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/balloon_compaction.h>
+#include <linux/oom.h>
 
 /*
  * Balloon device works in 4K page units.  So each page is pointed to by
  */
 #define VIRTIO_BALLOON_PAGES_PER_PAGE (unsigned)(PAGE_SIZE >> VIRTIO_BALLOON_PFN_SHIFT)
 #define VIRTIO_BALLOON_ARRAY_PFNS_MAX 256
+#define OOM_VBALLOON_DEFAULT_PAGES 256
+#define VIRTBALLOON_OOM_NOTIFY_PRIORITY 80
+
+static int oom_pages = OOM_VBALLOON_DEFAULT_PAGES;
+module_param(oom_pages, int, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(oom_pages, "pages to free on OOM");
 
 struct virtio_balloon
 {
@@ -71,6 +78,9 @@ struct virtio_balloon
        /* Memory statistics */
        int need_stats_update;
        struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
+
+       /* To register callback in oom notifier call chain */
+       struct notifier_block nb;
 };
 
 static struct virtio_device_id id_table[] = {
@@ -168,8 +178,9 @@ static void release_pages_by_pfn(const u32 pfns[], unsigned int num)
        }
 }
 
-static void leak_balloon(struct virtio_balloon *vb, size_t num)
+static unsigned leak_balloon(struct virtio_balloon *vb, size_t num)
 {
+       unsigned num_freed_pages;
        struct page *page;
        struct balloon_dev_info *vb_dev_info = &vb->vb_dev_info;
 
@@ -186,6 +197,7 @@ static void leak_balloon(struct virtio_balloon *vb, size_t num)
                vb->num_pages -= VIRTIO_BALLOON_PAGES_PER_PAGE;
        }
 
+       num_freed_pages = vb->num_pfns;
        /*
         * Note that if
         * virtio_has_feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
@@ -195,6 +207,7 @@ static void leak_balloon(struct virtio_balloon *vb, size_t num)
                tell_host(vb, vb->deflate_vq);
        mutex_unlock(&vb->balloon_lock);
        release_pages_by_pfn(vb->pfns, vb->num_pfns);
+       return num_freed_pages;
 }
 
 static inline void update_stat(struct virtio_balloon *vb, int idx,
@@ -287,6 +300,38 @@ static void update_balloon_size(struct virtio_balloon *vb)
                      &actual);
 }
 
+/*
+ * virtballoon_oom_notify - release pages when system is under severe
+ *                         memory pressure (called from out_of_memory())
+ * @self : notifier block struct
+ * @dummy: not used
+ * @parm : returned - number of freed pages
+ *
+ * The balancing of memory by use of the virtio balloon should not cause
+ * the termination of processes while there are pages in the balloon.
+ * If virtio balloon manages to release some memory, it will make the
+ * system return and retry the allocation that forced the OOM killer
+ * to run.
+ */
+static int virtballoon_oom_notify(struct notifier_block *self,
+                                 unsigned long dummy, void *parm)
+{
+       struct virtio_balloon *vb;
+       unsigned long *freed;
+       unsigned num_freed_pages;
+
+       vb = container_of(self, struct virtio_balloon, nb);
+       if (!virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM))
+               return NOTIFY_OK;
+
+       freed = parm;
+       num_freed_pages = leak_balloon(vb, oom_pages);
+       update_balloon_size(vb);
+       *freed += num_freed_pages;
+
+       return NOTIFY_OK;
+}
+
 static int balloon(void *_vballoon)
 {
        struct virtio_balloon *vb = _vballoon;
@@ -443,6 +488,12 @@ static int virtballoon_probe(struct virtio_device *vdev)
        if (err)
                goto out_free_vb;
 
+       vb->nb.notifier_call = virtballoon_oom_notify;
+       vb->nb.priority = VIRTBALLOON_OOM_NOTIFY_PRIORITY;
+       err = register_oom_notifier(&vb->nb);
+       if (err < 0)
+               goto out_oom_notify;
+
        vb->thread = kthread_run(balloon, vb, "vballoon");
        if (IS_ERR(vb->thread)) {
                err = PTR_ERR(vb->thread);
@@ -452,6 +503,8 @@ static int virtballoon_probe(struct virtio_device *vdev)
        return 0;
 
 out_del_vqs:
+       unregister_oom_notifier(&vb->nb);
+out_oom_notify:
        vdev->config->del_vqs(vdev);
 out_free_vb:
        kfree(vb);
@@ -476,6 +529,7 @@ static void virtballoon_remove(struct virtio_device *vdev)
 {
        struct virtio_balloon *vb = vdev->priv;
 
+       unregister_oom_notifier(&vb->nb);
        kthread_stop(vb->thread);
        remove_common(vb);
        kfree(vb);
@@ -515,6 +569,7 @@ static int virtballoon_restore(struct virtio_device *vdev)
 static unsigned int features[] = {
        VIRTIO_BALLOON_F_MUST_TELL_HOST,
        VIRTIO_BALLOON_F_STATS_VQ,
+       VIRTIO_BALLOON_F_DEFLATE_ON_OOM,
 };
 
 static struct virtio_driver virtio_balloon_driver = {
index d09e093..28f0e65 100644 (file)
@@ -81,7 +81,7 @@ void *virtqueue_get_used(struct virtqueue *vq);
 /**
  * virtio_device - representation of a device using virtio
  * @index: unique position on the virtio bus
- * @failed: saved value for CONFIG_S_FAILED bit (for restore)
+ * @failed: saved value for VIRTIO_CONFIG_S_FAILED bit (for restore)
  * @config_enabled: configuration change reporting enabled
  * @config_change_pending: configuration change reported while disabled
  * @config_lock: protects configuration change reporting
index 5e26f61..be40f70 100644 (file)
@@ -31,6 +31,7 @@
 /* The feature bitmap for virtio balloon */
 #define VIRTIO_BALLOON_F_MUST_TELL_HOST        0 /* Tell before reclaiming pages */
 #define VIRTIO_BALLOON_F_STATS_VQ      1 /* Memory Stats virtqueue */
+#define VIRTIO_BALLOON_F_DEFLATE_ON_OOM        2 /* Deflate balloon on OOM */
 
 /* Size of a PFN in the balloon interface. */
 #define VIRTIO_BALLOON_PFN_SHIFT 12