public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
From: Marcelo Tosatti <mtosatti@redhat.com>
To: Avi Kivity <avi@qumranet.com>
Cc: kvm-devel@lists.sourceforge.net
Subject: [patch 1/3] QEMU support for virtio balloon driver
Date: Wed, 12 Mar 2008 16:17:21 -0300	[thread overview]
Message-ID: <20080312191945.273458996@localhost.localdomain> (raw)
In-Reply-To: 20080312191720.490529767@localhost.localdomain

[-- Attachment #1: qemu-balloon --]
[-- Type: text/plain, Size: 12508 bytes --]

From: Anthony Liguori <aliguori@us.ibm.com>

This patch adds support to QEMU for Rusty's recently introduce virtio balloon
driver.  The user-facing portions of this are the introduction of a "balloon"
and "info balloon" command in the monitor.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>


Index: kvm-userspace.balloon/qemu/Makefile.target
===================================================================
--- kvm-userspace.balloon.orig/qemu/Makefile.target
+++ kvm-userspace.balloon/qemu/Makefile.target
@@ -577,7 +577,7 @@ OBJS += e1000.o
 OBJS+= hypercall.o
 
 # virtio devices
-OBJS += virtio.o virtio-net.o virtio-blk.o
+OBJS += virtio.o virtio-net.o virtio-blk.o virtio-balloon.o
 
 ifeq ($(TARGET_BASE_ARCH), i386)
 # Hardware support
Index: kvm-userspace.balloon/qemu/balloon.h
===================================================================
--- /dev/null
+++ kvm-userspace.balloon/qemu/balloon.h
@@ -0,0 +1,14 @@
+#ifndef _QEMU_BALLOON_H
+#define _QEMU_BALLOON_H
+
+#include "cpu-defs.h"
+
+typedef ram_addr_t (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
+
+void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque);
+
+void qemu_balloon(ram_addr_t target);
+
+ram_addr_t qemu_balloon_status(void);
+
+#endif
Index: kvm-userspace.balloon/qemu/hw/pc.c
===================================================================
--- kvm-userspace.balloon.orig/qemu/hw/pc.c
+++ kvm-userspace.balloon/qemu/hw/pc.c
@@ -1120,6 +1120,9 @@ static void pc_init1(ram_addr_t ram_size
 	}
     }
 
+    if (pci_enabled)
+	virtio_balloon_init(pci_bus, 0x1AF4, 0x1002);
+
     if (extboot_drive != -1) {
 	DriveInfo *info = &drives_table[extboot_drive];
 	int cyls, heads, secs;
Index: kvm-userspace.balloon/qemu/hw/pc.h
===================================================================
--- kvm-userspace.balloon.orig/qemu/hw/pc.h
+++ kvm-userspace.balloon/qemu/hw/pc.h
@@ -153,6 +153,9 @@ void virtio_net_poll(void);
 void *virtio_blk_init(PCIBus *bus, uint16_t vendor, uint16_t device,
 		      BlockDriverState *bs);
 
+/* virtio-balloon.h */
+void *virtio_balloon_init(PCIBus *bus, uint16_t vendor, uint16_t device);
+
 /* extboot.c */
 
 void extboot_init(BlockDriverState *bs, int cmd);
Index: kvm-userspace.balloon/qemu/hw/virtio-balloon.c
===================================================================
--- /dev/null
+++ kvm-userspace.balloon/qemu/hw/virtio-balloon.c
@@ -0,0 +1,145 @@
+/*
+ * Virtio Block Device
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "virtio.h"
+#include "block.h"
+#include "pc.h"
+#include "balloon.h"
+#include "sysemu.h"
+
+#include <sys/mman.h>
+
+/* from Linux's linux/virtio_blk.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. */
+    uint32_t num_pages;
+    /* Number of pages we've actually got in balloon. */
+    uint32_t actual;
+};
+
+typedef struct VirtIOBalloon
+{
+    VirtIODevice vdev;
+    VirtQueue *ivq, *dvq;
+    uint32_t num_pages;
+    uint32_t actual;
+} VirtIOBalloon;
+
+static VirtIOBalloon *to_virtio_balloon(VirtIODevice *vdev)
+{
+    return (VirtIOBalloon *)vdev;
+}
+
+static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIOBalloon *s = to_virtio_balloon(vdev);
+    VirtQueueElement elem;
+    unsigned int count;
+
+    while ((count = virtqueue_pop(vq, &elem)) != 0) {
+	int i;
+	unsigned int wlen = 0;
+
+	for (i = 0; i < elem.out_num; i++) {
+	    int flags;
+	    uint32_t *pfns = elem.out_sg[i].iov_base;
+	    unsigned int n_pfns = elem.out_sg[i].iov_len / 4;
+	    int j;
+
+	    for (j = 0; j < n_pfns; j++) {
+		if (vq == s->dvq) /* deflate */
+		    flags = MADV_WILLNEED;
+		else /* inflate */
+		    flags = MADV_DONTNEED;
+
+#if 0
+		/* can't use this until we have mmu notifier support */
+		madvise(phys_ram_base + (pfns[j] << TARGET_PAGE_BITS),
+			TARGET_PAGE_SIZE, flags);
+#endif
+	    }
+
+	    wlen += elem.out_sg[i].iov_len;
+	}
+
+	virtqueue_push(vq, &elem, wlen);
+	virtio_notify(vdev, vq);
+    }
+}
+
+static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
+{
+    VirtIOBalloon *dev = to_virtio_balloon(vdev);
+    struct virtio_balloon_config config;
+
+    config.num_pages = dev->num_pages;
+    config.actual = dev->actual;
+
+    memcpy(config_data, &config, 8);
+}
+
+static void virtio_balloon_set_config(VirtIODevice *vdev,
+				      const uint8_t *config_data)
+{
+    VirtIOBalloon *dev = to_virtio_balloon(vdev);
+    struct virtio_balloon_config config;
+    memcpy(&config, config_data, 8);
+    dev->actual = config.actual;
+}
+
+static uint32_t virtio_balloon_get_features(VirtIODevice *vdev)
+{
+    return 0;
+}
+
+static ram_addr_t virtio_balloon_to_target(void *opaque, ram_addr_t target)
+{
+    VirtIOBalloon *dev = opaque;
+
+    if (target) {
+	dev->num_pages = (ram_size - target) >> TARGET_PAGE_BITS;
+	virtio_notify_config(&dev->vdev);
+    }
+
+    return ram_size - (dev->actual << TARGET_PAGE_BITS);
+}
+
+void *virtio_balloon_init(PCIBus *bus, uint16_t vendor, uint16_t device)
+{
+    VirtIOBalloon *s;
+
+    s = (VirtIOBalloon *)virtio_init_pci(bus, "virtio-balloon",
+					 vendor, device,
+					 0, VIRTIO_ID_BALLOON,
+					 0x05, 0x00, 0x00,
+					 8, sizeof(VirtIOBalloon));
+
+    s->vdev.get_config = virtio_balloon_get_config;
+    s->vdev.set_config = virtio_balloon_set_config;
+    s->vdev.get_features = virtio_balloon_get_features;
+
+    s->ivq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
+    s->dvq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
+
+    qemu_add_balloon_handler(virtio_balloon_to_target, s);
+
+    return &s->vdev;
+}
Index: kvm-userspace.balloon/qemu/hw/virtio-blk.c
===================================================================
--- kvm-userspace.balloon.orig/qemu/hw/virtio-blk.c
+++ kvm-userspace.balloon/qemu/hw/virtio-blk.c
@@ -153,7 +153,7 @@ void *virtio_blk_init(PCIBus *bus, uint1
 				       0x01, 0x80, 0x00,
 				       16, sizeof(VirtIOBlock));
 
-    s->vdev.update_config = virtio_blk_update_config;
+    s->vdev.get_config = virtio_blk_update_config;
     s->vdev.get_features = virtio_blk_get_features;
     s->bs = bs;
 
Index: kvm-userspace.balloon/qemu/hw/virtio-net.c
===================================================================
--- kvm-userspace.balloon.orig/qemu/hw/virtio-net.c
+++ kvm-userspace.balloon/qemu/hw/virtio-net.c
@@ -288,7 +288,7 @@ void *virtio_net_init(PCIBus *bus, NICIn
 				     0x02, 0x00, 0x00,
 				     6, sizeof(VirtIONet));
 
-    n->vdev.update_config = virtio_net_update_config;
+    n->vdev.get_config = virtio_net_update_config;
     n->vdev.get_features = virtio_net_get_features;
     n->rx_vq = virtio_add_queue(&n->vdev, 512, virtio_net_handle_rx);
     n->tx_vq = virtio_add_queue(&n->vdev, 128, virtio_net_handle_tx);
Index: kvm-userspace.balloon/qemu/hw/virtio.c
===================================================================
--- kvm-userspace.balloon.orig/qemu/hw/virtio.c
+++ kvm-userspace.balloon/qemu/hw/virtio.c
@@ -307,6 +307,9 @@ static void virtio_config_writeb(void *o
 	return;
 
     memcpy(vdev->config + addr, &val, sizeof(val));
+
+    if (vdev->set_config)
+	vdev->set_config(vdev, vdev->config);
 }
 
 static void virtio_config_writew(void *opaque, uint32_t addr, uint32_t data)
@@ -319,6 +322,9 @@ static void virtio_config_writew(void *o
 	return;
 
     memcpy(vdev->config + addr, &val, sizeof(val));
+
+    if (vdev->set_config)
+	vdev->set_config(vdev, vdev->config);
 }
 
 static void virtio_config_writel(void *opaque, uint32_t addr, uint32_t data)
@@ -331,6 +337,9 @@ static void virtio_config_writel(void *o
 	return;
 
     memcpy(vdev->config + addr, &val, sizeof(val));
+
+    if (vdev->set_config)
+	vdev->set_config(vdev, vdev->config);
 }
 
 static void virtio_map(PCIDevice *pci_dev, int region_num,
@@ -359,7 +368,7 @@ static void virtio_map(PCIDevice *pci_de
 	register_ioport_read(addr + 20, vdev->config_len, 4,
 			     virtio_config_readl, vdev);
 
-	vdev->update_config(vdev, vdev->config);
+	vdev->get_config(vdev, vdev->config);
     }
 }
 
@@ -383,6 +392,14 @@ VirtQueue *virtio_add_queue(VirtIODevice
     return &vdev->vq[i];
 }
 
+void virtio_notify_config(VirtIODevice *vdev)
+{
+    /* make sure we have the latest config */
+    vdev->get_config(vdev, vdev->config);
+    vdev->isr = 3;
+    virtio_update_irq(vdev);
+}
+
 void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
 {
     /* Always notify when queue is empty */
Index: kvm-userspace.balloon/qemu/hw/virtio.h
===================================================================
--- kvm-userspace.balloon.orig/qemu/hw/virtio.h
+++ kvm-userspace.balloon/qemu/hw/virtio.h
@@ -118,7 +118,8 @@ struct VirtIODevice
     void *config;
     uint32_t (*get_features)(VirtIODevice *vdev);
     void (*set_features)(VirtIODevice *vdev, uint32_t val);
-    void (*update_config)(VirtIODevice *vdev, uint8_t *config);
+    void (*get_config)(VirtIODevice *vdev, uint8_t *config);
+    void (*set_config)(VirtIODevice *vdev, const uint8_t *config);
     VirtQueue vq[VIRTIO_PCI_QUEUE_MAX];
 };
 
@@ -140,4 +141,6 @@ int virtqueue_pop(VirtQueue *vq, VirtQue
 
 void virtio_notify(VirtIODevice *vdev, VirtQueue *vq);
 
+void virtio_notify_config(VirtIODevice *vdev);
+
 #endif
Index: kvm-userspace.balloon/qemu/monitor.c
===================================================================
--- kvm-userspace.balloon.orig/qemu/monitor.c
+++ kvm-userspace.balloon/qemu/monitor.c
@@ -35,6 +35,7 @@
 #include "audio/audio.h"
 #include "disas.h"
 #include "migration.h"
+#include "balloon.h"
 #include <dirent.h>
 
 #include "qemu-kvm.h"
@@ -1281,6 +1282,23 @@ static void do_wav_capture (const char *
 }
 #endif
 
+static void do_balloon(int value)
+{
+    ram_addr_t target = value;
+    qemu_balloon(target << 20);
+}
+
+static void do_info_balloon(void)
+{
+    ram_addr_t actual;
+
+    actual = qemu_balloon_status();
+    if (actual == 0)
+	term_printf("Ballooning not activated in VM\n");
+    else
+	term_printf("balloon: actual=%d\n", (int)(actual >> 20));
+}
+
 static term_cmd_t term_cmds[] = {
     { "help|?", "s?", do_help,
       "[cmd]", "show the help" },
@@ -1359,6 +1377,8 @@ static term_cmd_t term_cmds[] = {
     { "migrate_set_speed", "s", do_migrate_set_speed,
       "value", "set maximum speed (in bytes) for migrations" },
     { "cpu_set", "is", do_cpu_set_nr, "cpu [online|offline]", "change cpu state" },
+    { "balloon", "i", do_balloon,
+       "target", "request VM to change it's memory allocation (in MB)" },
     { NULL, NULL, },
 };
 
@@ -1421,6 +1441,8 @@ static term_cmd_t info_cmds[] = {
 #endif
     { "migration", "", do_info_migration,
       "", "show migration information" },
+    { "balloon", "", do_info_balloon,
+      "", "show balloon information" },
     { NULL, NULL, },
 };
 
Index: kvm-userspace.balloon/qemu/vl.c
===================================================================
--- kvm-userspace.balloon.orig/qemu/vl.c
+++ kvm-userspace.balloon/qemu/vl.c
@@ -38,6 +38,7 @@
 #include "block.h"
 #include "audio/audio.h"
 #include "migration.h"
+#include "balloon.h"
 #include "qemu-kvm.h"
 
 #include <unistd.h>
@@ -513,6 +514,31 @@ void hw_error(const char *fmt, ...)
     abort();
 }
 
+/***************/
+/* ballooning */
+
+static QEMUBalloonEvent *qemu_balloon_event;
+void *qemu_balloon_event_opaque;
+
+void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque)
+{
+    qemu_balloon_event = func;
+    qemu_balloon_event_opaque = opaque;
+}
+
+void qemu_balloon(ram_addr_t target)
+{
+    if (qemu_balloon_event)
+	qemu_balloon_event(qemu_balloon_event_opaque, target);
+}
+
+ram_addr_t qemu_balloon_status(void)
+{
+    if (qemu_balloon_event)
+	return qemu_balloon_event(qemu_balloon_event_opaque, 0);
+    return 0;
+}
+
 /***********************************************************/
 /* keyboard/mouse */
 

-- 


-------------------------------------------------------------------------
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/

  reply	other threads:[~2008-03-12 19:17 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-03-12 19:17 [patch 0/3] QEMU balloon support Marcelo Tosatti
2008-03-12 19:17 ` Marcelo Tosatti [this message]
2008-03-12 19:17 ` [patch 2/3] QEMU: balloon: dont allow target larger than ram size Marcelo Tosatti
2008-03-12 19:17 ` [patch 3/3] QEMU: balloon: zap any shadow mappings to a page before madvise(MADV_DONTNEED) Marcelo Tosatti
2008-03-16 14:00 ` [patch 0/3] QEMU balloon support Avi Kivity
2008-03-16 18:59   ` Marcelo Tosatti
2008-03-17 11:11     ` Avi Kivity
2008-03-17 13:08       ` Marcelo Tosatti
2008-03-17 14:56         ` Avi Kivity

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=20080312191945.273458996@localhost.localdomain \
    --to=mtosatti@redhat.com \
    --cc=avi@qumranet.com \
    --cc=kvm-devel@lists.sourceforge.net \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox