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/
next prev parent 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 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.