]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - drivers/virtio/virtio_balloon.c
virtio: drop thaw PM operation
[linux-2.6.git] / drivers / virtio / virtio_balloon.c
index bfec7c29486df963c16c2f3a1f292242eedc09eb..05f0a80818a2b1c202e2d5104ced13b9802287d0 100644 (file)
@@ -1,4 +1,5 @@
-/* Virtio balloon implementation, inspired by Dor Loar and Marcelo
+/*
+ * Virtio balloon implementation, inspired by Dor Laor and Marcelo
  * Tosatti's implementations.
  *
  *  Copyright 2008 Rusty Russell IBM Corporation
@@ -17,7 +18,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
-//#define DEBUG
+
 #include <linux/virtio.h>
 #include <linux/virtio_balloon.h>
 #include <linux/swap.h>
@@ -25,6 +26,7 @@
 #include <linux/freezer.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/module.h>
 
 struct virtio_balloon
 {
@@ -40,9 +42,6 @@ struct virtio_balloon
        /* Waiting for host to ack the pages we released. */
        struct completion acked;
 
-       /* Do we have to tell Host *before* we reuse pages? */
-       bool tell_host_first;
-
        /* The pages we've told the Host we're not using. */
        unsigned int num_pages;
        struct list_head pages;
@@ -75,7 +74,7 @@ static void balloon_ack(struct virtqueue *vq)
        struct virtio_balloon *vb;
        unsigned int len;
 
-       vb = vq->vq_ops->get_buf(vq, &len);
+       vb = virtqueue_get_buf(vq, &len);
        if (vb)
                complete(&vb->acked);
 }
@@ -89,9 +88,9 @@ static void tell_host(struct virtio_balloon *vb, struct virtqueue *vq)
        init_completion(&vb->acked);
 
        /* We should always be able to add one buffer to an empty queue. */
-       if (vq->vq_ops->add_buf(vq, &sg, 1, 0, vb) < 0)
+       if (virtqueue_add_buf(vq, &sg, 1, 0, vb, GFP_KERNEL) < 0)
                BUG();
-       vq->vq_ops->kick(vq);
+       virtqueue_kick(vq);
 
        /* When host has read buffer, this completes via balloon_ack */
        wait_for_completion(&vb->acked);
@@ -151,13 +150,13 @@ static void leak_balloon(struct virtio_balloon *vb, size_t num)
                vb->num_pages--;
        }
 
-       if (vb->tell_host_first) {
-               tell_host(vb, vb->deflate_vq);
-               release_pages_by_pfn(vb->pfns, vb->num_pfns);
-       } else {
-               release_pages_by_pfn(vb->pfns, vb->num_pfns);
-               tell_host(vb, vb->deflate_vq);
-       }
+       /*
+        * Note that if
+        * virtio_has_feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
+        * is true, we *have* to do it in this order
+        */
+       tell_host(vb, vb->deflate_vq);
+       release_pages_by_pfn(vb->pfns, vb->num_pfns);
 }
 
 static inline void update_stat(struct virtio_balloon *vb, int idx,
@@ -204,7 +203,7 @@ static void stats_request(struct virtqueue *vq)
        struct virtio_balloon *vb;
        unsigned int len;
 
-       vb = vq->vq_ops->get_buf(vq, &len);
+       vb = virtqueue_get_buf(vq, &len);
        if (!vb)
                return;
        vb->need_stats_update = 1;
@@ -221,9 +220,9 @@ static void stats_handle_request(struct virtio_balloon *vb)
 
        vq = vb->stats_vq;
        sg_init_one(&sg, vb->stats, sizeof(vb->stats));
-       if (vq->vq_ops->add_buf(vq, &sg, 1, 0, vb) < 0)
+       if (virtqueue_add_buf(vq, &sg, 1, 0, vb, GFP_KERNEL) < 0)
                BUG();
-       vq->vq_ops->kick(vq);
+       virtqueue_kick(vq);
 }
 
 static void virtballoon_changed(struct virtio_device *vdev)
@@ -276,32 +275,21 @@ static int balloon(void *_vballoon)
        return 0;
 }
 
-static int virtballoon_probe(struct virtio_device *vdev)
+static int init_vqs(struct virtio_balloon *vb)
 {
-       struct virtio_balloon *vb;
        struct virtqueue *vqs[3];
        vq_callback_t *callbacks[] = { balloon_ack, balloon_ack, stats_request };
        const char *names[] = { "inflate", "deflate", "stats" };
        int err, nvqs;
 
-       vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL);
-       if (!vb) {
-               err = -ENOMEM;
-               goto out;
-       }
-
-       INIT_LIST_HEAD(&vb->pages);
-       vb->num_pages = 0;
-       init_waitqueue_head(&vb->config_change);
-       vb->vdev = vdev;
-       vb->need_stats_update = 0;
-
-       /* We expect two virtqueues: inflate and deflate,
-        * and optionally stat. */
+       /*
+        * We expect two virtqueues: inflate and deflate, and
+        * optionally stat.
+        */
        nvqs = virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ) ? 3 : 2;
-       err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names);
+       err = vb->vdev->config->find_vqs(vb->vdev, nvqs, vqs, callbacks, names);
        if (err)
-               goto out_free_vb;
+               return err;
 
        vb->inflate_vq = vqs[0];
        vb->deflate_vq = vqs[1];
@@ -314,21 +302,41 @@ static int virtballoon_probe(struct virtio_device *vdev)
                 * use it to signal us later.
                 */
                sg_init_one(&sg, vb->stats, sizeof vb->stats);
-               if (vb->stats_vq->vq_ops->add_buf(vb->stats_vq,
-                                                 &sg, 1, 0, vb) < 0)
+               if (virtqueue_add_buf(vb->stats_vq, &sg, 1, 0, vb, GFP_KERNEL)
+                   < 0)
                        BUG();
-               vb->stats_vq->vq_ops->kick(vb->stats_vq);
+               virtqueue_kick(vb->stats_vq);
+       }
+       return 0;
+}
+
+static int virtballoon_probe(struct virtio_device *vdev)
+{
+       struct virtio_balloon *vb;
+       int err;
+
+       vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL);
+       if (!vb) {
+               err = -ENOMEM;
+               goto out;
        }
 
+       INIT_LIST_HEAD(&vb->pages);
+       vb->num_pages = 0;
+       init_waitqueue_head(&vb->config_change);
+       vb->vdev = vdev;
+       vb->need_stats_update = 0;
+
+       err = init_vqs(vb);
+       if (err)
+               goto out_free_vb;
+
        vb->thread = kthread_run(balloon, vb, "vballoon");
        if (IS_ERR(vb->thread)) {
                err = PTR_ERR(vb->thread);
                goto out_del_vqs;
        }
 
-       vb->tell_host_first
-               = virtio_has_feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
-
        return 0;
 
 out_del_vqs:
@@ -356,6 +364,46 @@ static void __devexit virtballoon_remove(struct virtio_device *vdev)
        kfree(vb);
 }
 
+#ifdef CONFIG_PM
+static int virtballoon_freeze(struct virtio_device *vdev)
+{
+       struct virtio_balloon *vb = vdev->priv;
+
+       /*
+        * The kthread is already frozen by the PM core before this
+        * function is called.
+        */
+
+       while (vb->num_pages)
+               leak_balloon(vb, vb->num_pages);
+       update_balloon_size(vb);
+
+       /* Ensure we don't get any more requests from the host */
+       vdev->config->reset(vdev);
+       vdev->config->del_vqs(vdev);
+       return 0;
+}
+
+static int restore_common(struct virtio_device *vdev)
+{
+       struct virtio_balloon *vb = vdev->priv;
+       int ret;
+
+       ret = init_vqs(vdev->priv);
+       if (ret)
+               return ret;
+
+       fill_balloon(vb, towards_target(vb));
+       update_balloon_size(vb);
+       return 0;
+}
+
+static int virtballoon_restore(struct virtio_device *vdev)
+{
+       return restore_common(vdev);
+}
+#endif
+
 static unsigned int features[] = {
        VIRTIO_BALLOON_F_MUST_TELL_HOST,
        VIRTIO_BALLOON_F_STATS_VQ,
@@ -370,6 +418,10 @@ static struct virtio_driver virtio_balloon_driver = {
        .probe =        virtballoon_probe,
        .remove =       __devexit_p(virtballoon_remove),
        .config_changed = virtballoon_changed,
+#ifdef CONFIG_PM
+       .freeze =       virtballoon_freeze,
+       .restore =      virtballoon_restore,
+#endif
 };
 
 static int __init init(void)