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
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel

Reply via email to