From mboxrd@z Thu Jan 1 00:00:00 1970 From: Marcelo Tosatti Subject: [PATCH] QEMU KVM balloon support (v2) Date: Wed, 9 Jan 2008 16:26:11 -0200 Message-ID: <20080109182611.GD303@dmt> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Cc: kvm-devel To: Anthony Liguori Return-path: Content-Disposition: inline List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: kvm-devel-bounces-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org Errors-To: kvm-devel-bounces-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org List-Id: kvm.vger.kernel.org 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 + +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 +#include #define MIN_FINALIZE_SIZE (200 << 10) #define MAX_ITERATIONS 30 @@ -765,6 +766,9 @@ static void migrate_incoming_homogeneous for (i=0; i #include #include +#include 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 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