All of lore.kernel.org
 help / color / mirror / Atom feed
From: Marcelo Tosatti <marcelo-Bw31MaZKKs3YtjvyW6yDsg@public.gmane.org>
To: virtualization-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org,
	kvm-devel
	<kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
Cc: Avi Kivity <avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
Subject: [PATCH] QEMU KVM balloon support
Date: Tue, 8 Jan 2008 13:43:40 -0200	[thread overview]
Message-ID: <20080108154340.GC21726@dmt> (raw)


Add QEMU support for the KVM balloon driver.

Memory hinting is performed via madvise().

Signed-off-by: Marcelo Tosatti <mtosatti-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

Index: kvm-userspace/libkvm/libkvm.c
===================================================================
--- kvm-userspace.orig/libkvm/libkvm.c
+++ kvm-userspace/libkvm/libkvm.c
@@ -886,6 +886,17 @@ int kvm_is_ready_for_interrupt_injection
 	return run->ready_for_interrupt_injection;
 }
 
+int kvm_sync_shadow_with_user(kvm_context_t kvm)
+{
+        int r = 0;
+#ifdef KVM_CAP_SYNC_SHADOW_WITH_USER
+        r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_SYNC_SHADOW_WITH_USER);
+        if (r > 0)
+		r = ioctl(kvm->vm_fd, KVM_SYNC_SHADOW_WITH_USER);
+#endif
+	return r;
+}
+
 int kvm_run(kvm_context_t kvm, int vcpu)
 {
 	int r;
Index: kvm-userspace/libkvm/libkvm.h
===================================================================
--- kvm-userspace.orig/libkvm/libkvm.h
+++ kvm-userspace/libkvm/libkvm.h
@@ -423,6 +423,8 @@ int kvm_get_dirty_pages_range(kvm_contex
 			      int (*cb)(unsigned long start, unsigned long len,
 					void*bitmap, void *opaque));
 
+int kvm_sync_shadow_with_user(kvm_context_t kvm);
+
 /*!
  * \brief Create a memory alias
  *
Index: kvm-userspace/qemu/Makefile.target
===================================================================
--- kvm-userspace.orig/qemu/Makefile.target
+++ kvm-userspace/qemu/Makefile.target
@@ -464,7 +464,7 @@ VL_OBJS += rtl8139.o
 VL_OBJS+= hypercall.o
 
 # virtio devices
-VL_OBJS += virtio.o virtio-net.o virtio-blk.o
+VL_OBJS += virtio.o virtio-net.o virtio-blk.o virtio-balloon.o
 
 ifeq ($(TARGET_BASE_ARCH), i386)
 # Hardware support
Index: kvm-userspace/qemu/hw/pc.c
===================================================================
--- kvm-userspace.orig/qemu/hw/pc.c
+++ kvm-userspace/qemu/hw/pc.c
@@ -1029,6 +1029,8 @@ static void pc_init1(ram_addr_t ram_size
         }
     }
 
+    virtio_balloon_init(pci_bus);
+
 #define USE_HYPERCALL
 #ifdef USE_HYPERCALL
     pci_hypercall_init(pci_bus);
Index: kvm-userspace/qemu/hw/pc.h
===================================================================
--- kvm-userspace.orig/qemu/hw/pc.h
+++ kvm-userspace/qemu/hw/pc.h
@@ -155,4 +155,7 @@ void *virtio_blk_init(PCIBus *bus, uint1
 
 void extboot_init(BlockDriverState *bs, int cmd);
 
+/* virtio-balloon.c */
+void *virtio_balloon_init(PCIBus *bus);
+
 #endif
Index: kvm-userspace/qemu/hw/virtio-balloon.c
===================================================================
--- /dev/null
+++ kvm-userspace/qemu/hw/virtio-balloon.c
@@ -0,0 +1,103 @@
+#include "virtio.h"
+#include "pc.h"
+
+typedef struct VirtIOBalloon
+{
+    VirtIODevice vdev;
+} VirtIOBalloon;
+
+struct virtio_balloon_hdr 
+{
+	uint8_t cmd;
+	uint8_t status;
+};
+
+struct virtio_balloon_config
+{
+	uint32_t target_nrpages;
+};
+
+VirtIOBalloon *virtio_balloon;
+
+extern int64_t ram_size;
+int64_t target_ramsize;
+
+#define VIRTIO_ID_BALLOON 3
+
+#define CMD_BALLOON_INFLATE 0x1
+#define CMD_BALLOON_DEFLATE 0x2
+
+static VirtIOBalloon *to_virtio_balloon(VirtIODevice *vdev)
+{
+	return (VirtIOBalloon *)vdev;
+}
+
+static void virtio_balloon_queue(VirtIODevice *vdev, VirtQueue *vq)
+{
+	VirtIOBalloon *n = to_virtio_balloon(vdev);
+	VirtQueueElement elem;
+
+	while (virtqueue_pop(vq, &elem)) { 
+		int i, r;
+		size_t len = 0;
+		struct virtio_balloon_hdr *hdr;
+		void *data;
+
+		hdr = (void *)elem.in_sg[0].iov_base;
+		switch(hdr->cmd) {
+			case CMD_BALLOON_INFLATE:
+			case CMD_BALLOON_DEFLATE:
+				data = elem.in_sg[1].iov_base;
+				len = elem.in_sg[1].iov_len;
+
+				r = kvm_handle_ballooning_call(data, len);
+				hdr->status = (uint8_t) r; 
+				break;
+			default:
+				fprintf(stderr, "unknown command %x\n",
+						hdr->cmd);
+				hdr->status = 1;
+		}
+		len += sizeof(struct virtio_balloon_hdr);
+		virtqueue_push(vq, &elem, len);
+		virtio_notify(vdev, vq);
+	}
+}
+
+static void virtio_balloon_update_config(VirtIODevice *vdev, uint8_t *config)
+{
+	struct virtio_balloon_config cfg;
+
+	cfg.target_nrpages = target_ramsize / TARGET_PAGE_SIZE;
+
+	memcpy(config, &cfg, sizeof(cfg));
+}
+
+void *virtio_balloon_init(PCIBus *bus)
+{
+	VirtIOBalloon *n;
+
+	/* XXX: pif=0x80? */
+	n = (VirtIOBalloon *)virtio_init_pci(bus, "virtio-kvm-balloon", 0x1AF4,
+					     0x1003, 0, VIRTIO_ID_BALLOON,
+					     0xff, 0x80, 0x00, 4, 
+					     sizeof(VirtIOBalloon));
+	
+	virtio_add_queue(&n->vdev, 128, virtio_balloon_queue);
+	n->vdev.update_config = virtio_balloon_update_config;
+	target_ramsize = ram_size;
+	virtio_balloon = n;
+
+	return &n->vdev;
+}
+
+int balloon_update_target(int64_t target)
+{
+	VirtIODevice *vdev = &virtio_balloon->vdev;
+	target_ramsize = target;
+
+	vdev->update_config(vdev, vdev->config);
+	qemu_set_irq(vdev->pci_dev.irq[0], 1);
+
+	return 1;
+}
Index: kvm-userspace/qemu/migration.c
===================================================================
--- kvm-userspace.orig/qemu/migration.c
+++ kvm-userspace/qemu/migration.c
@@ -34,6 +34,7 @@
 #endif
 
 #include <sys/wait.h>
+#include <sys/mman.h>
 
 #define MIN_FINALIZE_SIZE	(200 << 10)
 #define MAX_ITERATIONS           30
@@ -765,6 +766,9 @@ static void migrate_incoming_homogeneous
 
     for (i=0; i<n; i++)
         p[i] = v;
+
+    if (v == 0)
+        madvise(phys_ram_base + addr, TARGET_PAGE_SIZE, MADV_DONTNEED);
 }
 
 static int migrate_incoming_page(QEMUFile *f, uint32_t addr)
Index: kvm-userspace/qemu/monitor.c
===================================================================
--- kvm-userspace.orig/qemu/monitor.c
+++ kvm-userspace/qemu/monitor.c
@@ -1339,6 +1339,8 @@ static term_cmd_t term_cmds[] = {
       "", "cancel the current VM migration" },
     { "migrate_set_speed", "s", do_migrate_set_speed,
       "value", "set maximum speed (in bytes) for migrations" },
+    { "setmem", "s", do_setmemory, "value", 
+      "set memory for the guest (in bytes)" },
     { NULL, NULL, },
 };
 
Index: kvm-userspace/qemu/qemu-kvm.c
===================================================================
--- kvm-userspace.orig/qemu/qemu-kvm.c
+++ kvm-userspace/qemu/qemu-kvm.c
@@ -21,6 +21,7 @@ int kvm_irqchip = 1;
 #include <libkvm.h>
 #include <pthread.h>
 #include <sys/utsname.h>
+#include <sys/mman.h>
 
 extern void perror(const char *s);
 
@@ -513,7 +514,74 @@ static int kvm_shutdown(void *opaque, in
     qemu_system_reset_request();
     return 1;
 }
- 
+
+static int do_balloon_on_page(unsigned int gfn, int is_inflate)
+{
+    unsigned long addr = gfn * TARGET_PAGE_SIZE;
+    unsigned char *curr_addr = phys_ram_base + addr;
+    int r;
+    int advice = is_inflate ? MADV_DONTNEED : MADV_NORMAL;
+    
+    r = madvise(curr_addr, TARGET_PAGE_SIZE, advice);
+
+    if (r < 0) {
+        perror("madvise");
+        fprintf(stderr, "%s: gfn=0x%x is_inflate=%d mlock/madvise: failed\n",
+                __FUNCTION__, gfn, is_inflate);
+    }
+    return r;
+}
+
+int kvm_handle_ballooning_call(void *data, size_t len)
+{
+    unsigned int gfn;
+    unsigned int *curr_pfn;
+    int is_inflate;
+    int req_npages, npages;
+    int i, r = 0, saved_r = 0;
+
+    curr_pfn = data;
+
+    req_npages = (int)*curr_pfn++;
+
+    npages = abs(req_npages);
+    is_inflate = (req_npages > 0);
+    
+    if (is_inflate)
+         kvm_sync_shadow_with_user(kvm_context);
+
+    for (i = 0; i < npages; i++, curr_pfn++) {
+        gfn = *curr_pfn;
+
+        r = do_balloon_on_page(gfn, is_inflate);
+        if (r) {
+            printf("do_balloon_on_page FAILED, gfn=0x%x, is_inflate=%d\n",
+                   gfn, is_inflate);
+            goto out_failed;
+        }
+    }
+
+    return r;
+
+out_failed:
+    npages = i;
+    curr_pfn = data;
+    curr_pfn++;
+    saved_r = r;
+
+    for (i = 0; i<npages; i++, curr_pfn++) {
+        gfn = *curr_pfn;
+
+        r = do_balloon_on_page(gfn, !is_inflate);
+        if (r) {
+             printf("do_balloon_on_page EH FAILED, gfn=0x%x, is_inflate=%d\n",
+                    gfn, !is_inflate);
+             return r;
+        }
+    }
+    return saved_r;
+}
+
 static struct kvm_callbacks qemu_kvm_ops = {
     .debug = kvm_debug,
     .inb   = kvm_inb,
@@ -546,6 +614,31 @@ int kvm_qemu_init()
     return 0;
 }
 
+void do_setmemory(const char *value)
+{
+	int target_ramsize;
+	char *ptr;
+
+	target_ramsize = strtol(value, &ptr, 10);
+	switch (*ptr) {
+	case 'G': case 'g':
+		target_ramsize *= 1024;
+	case 'M': case 'm':
+		target_ramsize *= 1024;
+	case 'K': case 'k':
+		target_ramsize *= 1024;
+	default:
+		break;
+	}
+
+	if (target_ramsize > ram_size) {
+		term_printf("Invalid RAM size, maximum: %d\n", ram_size);
+		return;
+	}
+	
+	balloon_update_target(target_ramsize);
+}
+
 int kvm_qemu_create_context(void)
 {
     int r;
Index: kvm-userspace/qemu/qemu-kvm.h
===================================================================
--- kvm-userspace.orig/qemu/qemu-kvm.h
+++ kvm-userspace/qemu/qemu-kvm.h
@@ -39,6 +39,9 @@ void kvm_arch_post_kvm_run(void *opaque,
 int kvm_arch_has_work(CPUState *env);
 int kvm_arch_try_push_interrupts(void *opaque);
 void kvm_arch_update_regs_for_sipi(CPUState *env);
+int kvm_handle_ballooning_call(void *data, size_t len);
+
+void do_setmemory(const char *value);
 
 extern int kvm_allowed;
 extern int kvm_irqchip;
Index: kvm-userspace/qemu/vl.c
===================================================================
--- kvm-userspace.orig/qemu/vl.c
+++ kvm-userspace/qemu/vl.c
@@ -7216,6 +7216,30 @@ static void ram_decompress_close(RamDeco
     inflateEnd(&s->zstream);
 }
 
+#ifdef USE_KVM
+extern int64_t target_ramsize; /* qemu/hw/virtio-balloon.c */
+static void balloon_save(QEMUFile *f, void *opaque)
+{
+    qemu_put_be64(f, target_ramsize);
+}
+
+static int balloon_load(QEMUFile *f, void *opaque, int version_id)
+{
+    int64_t target;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    target = qemu_get_be64(f);
+    if (!target)
+        return -EINVAL;
+
+    balloon_update_target(target);
+
+    return 0;
+}
+#endif
+
 static void ram_save_live(QEMUFile *f, void *opaque)
 {
     target_ulong addr;
@@ -9378,6 +9402,9 @@ int main(int argc, char **argv)
 
     register_savevm("timer", 0, 2, timer_save, timer_load, NULL);
     register_savevm("ram", 0, 3, ram_save, ram_load, NULL);
+    if (kvm_allowed)
+        register_savevm("balloon", 0, 1, balloon_save, balloon_load, NULL);
+
 
     init_ioports();
 

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace

             reply	other threads:[~2008-01-08 15:43 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-01-08 15:43 Marcelo Tosatti [this message]
2008-01-08 16:43 ` [kvm-devel] [PATCH] QEMU KVM balloon support Daniel P. Berrange
2008-01-08 16:43 ` Daniel P. Berrange
2008-01-08 17:08   ` [kvm-devel] " Marcelo Tosatti
     [not found]   ` <20080108164342.GF21294-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2008-01-08 17:08     ` Marcelo Tosatti
  -- strict thread matches above, loose matches on Subject: below --
2008-01-08 15:43 Marcelo Tosatti

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=20080108154340.GC21726@dmt \
    --to=marcelo-bw31mazkks3ytjvyw6ydsg@public.gmane.org \
    --cc=avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org \
    --cc=kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@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.