From: Rusty Russell <rusty-8n+1lVoiYb80n/F98K4Iww@public.gmane.org>
To: Anthony Liguori <anthony-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
Cc: Marcelo Tosatti <marcelo-Bw31MaZKKs3YtjvyW6yDsg@public.gmane.org>,
kvm-devel
<kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>,
Avi Kivity <avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org>,
virtualization-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
Subject: Re: [PATCH] KVM simplified virtio balloon driver
Date: Thu, 24 Jan 2008 12:58:59 +1100 [thread overview]
Message-ID: <200801241258.59441.rusty@rustcorp.com.au> (raw)
In-Reply-To: <47929884.2010908-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
Here's the latest. Hope this works for everyone (putting in a oom handler or
shrinker requires a lock, but can be done quite easily).
Untested.
===
After discussions with Anthony Liguori, it seems that the virtio
balloon can be made even simpler. Here's my attempt.
Signed-off-by: Rusty Russell <rusty-8n+1lVoiYb80n/F98K4Iww@public.gmane.org>
---
drivers/virtio/Kconfig | 10 +
drivers/virtio/Makefile | 1
drivers/virtio/virtio_balloon.c | 284 ++++++++++++++++++++++++++++++++++++++++
include/linux/virtio_balloon.h | 18 ++
4 files changed, 313 insertions(+)
diff -r e977a88ffefd drivers/virtio/Kconfig
--- a/drivers/virtio/Kconfig Thu Jan 24 12:34:05 2008 +1100
+++ b/drivers/virtio/Kconfig Thu Jan 24 12:40:07 2008 +1100
@@ -23,3 +23,13 @@ config VIRTIO_PCI
If unsure, say M.
+config VIRTIO_BALLOON
+ tristate "Virtio balloon driver (EXPERIMENTAL)"
+ select VIRTIO
+ select VIRTIO_RING
+ ---help---
+ This driver supports increasing and decreasing the amount
+ of memory within a KVM guest.
+
+ If unsure, say M.
+
diff -r e977a88ffefd drivers/virtio/Makefile
--- a/drivers/virtio/Makefile Thu Jan 24 12:34:05 2008 +1100
+++ b/drivers/virtio/Makefile Thu Jan 24 12:40:07 2008 +1100
@@ -1,3 +1,4 @@ obj-$(CONFIG_VIRTIO) += virtio.o
obj-$(CONFIG_VIRTIO) += virtio.o
obj-$(CONFIG_VIRTIO_RING) += virtio_ring.o
obj-$(CONFIG_VIRTIO_PCI) += virtio_pci.o
+obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o
diff -r e977a88ffefd drivers/virtio/virtio_balloon.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/virtio/virtio_balloon.c Thu Jan 24 12:40:07 2008 +1100
@@ -0,0 +1,284 @@
+/* Virtio balloon implementation, inspired by Dor Loar and Marcelo
+ * Tosatti's implementations.
+ *
+ * Copyright 2008 Rusty Russell IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * 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>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+
+struct virtio_balloon
+{
+ struct virtio_device *vdev;
+ struct virtqueue *inflate_vq, *deflate_vq;
+
+ /* Where the ballooning thread waits for config to change. */
+ wait_queue_head_t config_change;
+
+ /* The thread servicing the balloon. */
+ struct task_struct *thread;
+
+ /* 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;
+
+ /* The array of pfns we tell the Host about. */
+ unsigned int num_pfns;
+ u32 pfns[256];
+};
+
+static struct virtio_device_id id_table[] = {
+ { VIRTIO_ID_BALLOON, VIRTIO_DEV_ANY_ID },
+ { 0 },
+};
+
+static void balloon_ack(struct virtqueue *vq)
+{
+ struct virtio_balloon *vb;
+ unsigned int len;
+
+ vb = vq->vq_ops->get_buf(vq, &len);
+ if (vb)
+ complete(&vb->acked);
+}
+
+static void tell_host(struct virtio_balloon *vb, struct virtqueue *vq)
+{
+ struct scatterlist sg;
+
+ sg_init_one(&sg, vb->pfns, sizeof(vb->pfns[0]) * vb->num_pfns);
+
+ 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)
+ BUG();
+ vq->vq_ops->kick(vq);
+
+ /* When host has read buffer, this completes via balloon_ack */
+ wait_for_completion(&vb->acked);
+}
+
+static void fill_balloon(struct virtio_balloon *vb, unsigned int num)
+{
+ /* We can only do one array worth at a time. */
+ num = min(num, ARRAY_SIZE(vb->pfns));
+
+ for (vb->num_pfns = 0; vb->num_pfns < num; vb->num_pfns++) {
+ struct page *page = alloc_page(GFP_HIGHUSER | __GFP_NORETRY);
+ if (!page) {
+ if (printk_ratelimit())
+ dev_printk(KERN_INFO, &vb->vdev->dev,
+ "Out of puff! Can't get %u pages\n",
+ num);
+ /* Sleep for at least 1/5 of a second before retry. */
+ msleep(200);
+ break;
+ }
+ vb->pfns[vb->num_pfns] = page_to_pfn(page);
+ totalram_pages--;
+ vb->num_pages++;
+ list_add(&page->lru, &vb->pages);
+ }
+
+ /* Didn't get any? Oh well. */
+ if (vb->num_pfns == 0)
+ return;
+
+ tell_host(vb, vb->inflate_vq);
+}
+
+static void release_pages_by_pfn(const u32 pfns[], unsigned int num)
+{
+ unsigned int i;
+
+ for (i = 0; i < num; i++) {
+ __free_page(pfn_to_page(pfns[i]));
+ totalram_pages++;
+ }
+}
+
+static void leak_balloon(struct virtio_balloon *vb, unsigned int num)
+{
+ struct page *page;
+
+ /* We can only do one array worth at a time. */
+ num = min(num, ARRAY_SIZE(vb->pfns));
+
+ for (vb->num_pfns = 0; vb->num_pfns < num; vb->num_pfns++) {
+ page = list_first_entry(&vb->pages, struct page, lru);
+ list_del(&page->lru);
+ vb->pfns[vb->num_pfns] = page_to_pfn(page);
+ 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);
+ }
+}
+
+static void virtballoon_changed(struct virtio_device *vdev)
+{
+ struct virtio_balloon *vb = vdev->priv;
+
+ wake_up(&vb->config_change);
+}
+
+static inline int towards_target(struct virtio_balloon *vb)
+{
+ u32 v;
+ __virtio_config_val(vb->vdev,
+ offsetof(struct virtio_balloon_config, num_pages),
+ &v);
+ return v - vb->num_pages;
+}
+
+static void update_balloon_size(struct virtio_balloon *vb)
+{
+ __le32 actual = cpu_to_le32(vb->num_pages);
+
+ vb->vdev->config->set(vb->vdev,
+ offsetof(struct virtio_balloon_config, actual),
+ &actual, sizeof(actual));
+}
+
+static int balloon(void *_vballoon)
+{
+ struct virtio_balloon *vb = _vballoon;
+
+ set_freezable();
+ while (!kthread_should_stop()) {
+ int diff;
+
+ try_to_freeze();
+ wait_event_interruptible(vb->config_change,
+ (diff = towards_target(vb)) != 0
+ || kthread_should_stop());
+ if (diff > 0)
+ fill_balloon(vb, diff);
+ else if (diff < 0)
+ leak_balloon(vb, -diff);
+ update_balloon_size(vb);
+ }
+ 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;
+
+ /* We expect two virtqueues. */
+ vb->inflate_vq = vdev->config->find_vq(vdev, 0, balloon_ack);
+ if (IS_ERR(vb->inflate_vq)) {
+ err = PTR_ERR(vb->inflate_vq);
+ goto out_free_vb;
+ }
+
+ vb->deflate_vq = vdev->config->find_vq(vdev, 1, balloon_ack);
+ if (IS_ERR(vb->deflate_vq)) {
+ err = PTR_ERR(vb->deflate_vq);
+ goto out_del_inflate_vq;
+ }
+
+ vb->thread = kthread_run(balloon, vb, "vballoon");
+ if (IS_ERR(vb->thread)) {
+ err = PTR_ERR(vb->thread);
+ goto out_del_deflate_vq;
+ }
+
+ vb->tell_host_first
+ = vdev->config->feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
+
+ return 0;
+
+out_del_deflate_vq:
+ vdev->config->del_vq(vb->deflate_vq);
+out_del_inflate_vq:
+ vdev->config->del_vq(vb->inflate_vq);
+out_free_vb:
+ kfree(vb);
+out:
+ return err;
+}
+
+static void virtballoon_remove(struct virtio_device *vdev)
+{
+ struct virtio_balloon *vb = vdev->priv;
+
+ kthread_stop(vb->thread);
+
+ /* There might be pages left in the balloon: free them. */
+ while (vb->num_pages)
+ leak_balloon(vb, vb->num_pages);
+
+ /* Now we reset the device so we can clean up the queues. */
+ vdev->config->reset(vdev);
+
+ vdev->config->del_vq(vb->deflate_vq);
+ vdev->config->del_vq(vb->inflate_vq);
+ kfree(vb);
+}
+
+static struct virtio_driver virtio_balloon = {
+ .driver.name = KBUILD_MODNAME,
+ .driver.owner = THIS_MODULE,
+ .id_table = id_table,
+ .probe = virtballoon_probe,
+ .remove = __devexit_p(virtballoon_remove),
+ .config_changed = virtballoon_changed,
+};
+
+static int __init init(void)
+{
+ return register_virtio_driver(&virtio_balloon);
+}
+
+static void __exit fini(void)
+{
+ unregister_virtio_driver(&virtio_balloon);
+}
+module_init(init);
+module_exit(fini);
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("Virtio balloon driver");
+MODULE_LICENSE("GPL");
diff -r e977a88ffefd include/linux/virtio_balloon.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/include/linux/virtio_balloon.h Thu Jan 24 12:40:07 2008 +1100
@@ -0,0 +1,18 @@
+#ifndef _LINUX_VIRTIO_BALLOON_H
+#define _LINUX_VIRTIO_BALLOON_H
+#include <linux/virtio_config.h>
+
+/* The ID for virtio_balloon */
+#define VIRTIO_ID_BALLOON 5
+
+/* The feature bitmap for virtio balloon */
+#define VIRTIO_BALLOON_F_MUST_TELL_HOST 0 /* Tell before reclaiming pages */
+
+struct virtio_balloon_config
+{
+ /* Number of pages host wants Guest to give up. */
+ __le32 num_pages;
+ /* Number of pages we've actually got in balloon. */
+ __le32 actual;
+};
+#endif /* _LINUX_VIRTIO_BALLOON_H */
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
next prev parent reply other threads:[~2008-01-24 1:58 UTC|newest]
Thread overview: 41+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-01-14 20:03 [PATCH] KVM virtio balloon driver Marcelo Tosatti
2008-01-14 21:29 ` Anthony Liguori
2008-01-15 14:22 ` Marcelo Tosatti
2008-01-14 23:32 ` Rusty Russell
2008-01-15 19:01 ` Marcelo Tosatti
2008-01-16 23:12 ` Dor Laor
2008-01-16 23:12 ` Dor Laor
[not found] ` <1200525166.26281.103.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2008-01-17 1:45 ` [PATCH] KVM simplified " Rusty Russell
2008-01-17 2:14 ` [kvm-devel] " Anthony Liguori
2008-01-17 9:32 ` Christian Borntraeger
[not found] ` <200801171245.59510.rusty-8n+1lVoiYb80n/F98K4Iww@public.gmane.org>
2008-01-17 2:14 ` Anthony Liguori
[not found] ` <478EBA22.30301-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
2008-01-17 3:29 ` Rusty Russell
2008-01-17 4:01 ` [kvm-devel] " Anthony Liguori
[not found] ` <200801171429.32888.rusty-8n+1lVoiYb80n/F98K4Iww@public.gmane.org>
2008-01-17 4:01 ` Anthony Liguori
[not found] ` <478ED32A.1060803-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
2008-01-17 5:59 ` Rusty Russell
2008-01-19 7:05 ` Avi Kivity
2008-01-17 5:59 ` [kvm-devel] " Rusty Russell
2008-01-19 7:05 ` Avi Kivity
2008-01-17 3:29 ` Rusty Russell
2008-01-17 9:32 ` Christian Borntraeger
[not found] ` <200801171032.26198.borntraeger-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
2008-01-17 10:25 ` Martin Schwidefsky
2008-01-17 11:40 ` Dor Laor
2008-01-17 13:56 ` Anthony Liguori
[not found] ` <478F5E85.9020009-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2008-01-17 23:01 ` Dor Laor
2008-01-17 23:35 ` Anthony Liguori
[not found] ` <1200610891.26281.171.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2008-01-17 23:35 ` Anthony Liguori
2008-01-17 23:01 ` Dor Laor
2008-01-17 11:40 ` Dor Laor
2008-01-17 10:25 ` Martin Schwidefsky
2008-01-19 7:02 ` Avi Kivity
2008-01-19 7:02 ` [kvm-devel] " Avi Kivity
2008-01-19 22:37 ` Anthony Liguori
2008-01-19 22:37 ` Anthony Liguori
[not found] ` <4791A085.8060502__30665.5007684187$1200726687$gmane$org-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2008-01-19 22:37 ` Anthony Liguori
[not found] ` <47927BB7.7060805-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
2008-01-20 0:24 ` Marcelo Tosatti
2008-01-20 0:40 ` Anthony Liguori
[not found] ` <47929884.2010908-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
2008-01-24 1:58 ` Rusty Russell [this message]
2008-01-24 1:58 ` [kvm-devel] " Rusty Russell
2008-01-20 0:40 ` Anthony Liguori
2008-01-20 0:24 ` Marcelo Tosatti
2008-01-17 1:45 ` Rusty Russell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=200801241258.59441.rusty@rustcorp.com.au \
--to=rusty-8n+1lvoiyb80n/f98k4iww@public.gmane.org \
--cc=anthony-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org \
--cc=avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org \
--cc=kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org \
--cc=marcelo-Bw31MaZKKs3YtjvyW6yDsg@public.gmane.org \
--cc=virtualization-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.