All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] QEMU KVM balloon support (v2)
@ 2008-01-09 18:26 Marcelo Tosatti
  0 siblings, 0 replies; only message in thread
From: Marcelo Tosatti @ 2008-01-09 18:26 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: kvm-devel


QEMU support for ballooning.

Changes: 
- Use int64_t for memory size input, otherwise it wraps around 
at 2GB (Daniel Berrange)
- Use virtio_update_config()
- Remove save/load hooks, they will be rewritten after Anthony introduces
proper virtio s/l support


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,84 @@
+#include "virtio.h"
+#include "pc.h"
+#include "console.h"
+#include "qemu-kvm.h"
+#include <linux/virtio_balloon.h>
+
+typedef struct VirtIOBalloon
+{
+	VirtIODevice vdev;
+} VirtIOBalloon;
+
+VirtIOBalloon *virtio_balloon;
+
+extern int64_t ram_size;
+int64_t target_ramsize;
+
+static void virtio_balloon_queue(VirtIODevice *vdev, VirtQueue *vq)
+{
+	VirtQueueElement elem;
+
+	while (virtqueue_pop(vq, &elem)) { 
+		int 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;
+
+	virtio_update_config(vdev);
+
+	return 0;
+}
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)
+{
+	int64_t target_ramsize;
+	char *ptr;
+
+	target_ramsize = strtoll(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;

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

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2008-01-09 18:26 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-09 18:26 [PATCH] QEMU KVM balloon support (v2) Marcelo Tosatti

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.