From 927d66381948659b0acbb1b3f23de5a5008d48a4 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 18 Apr 2017 18:12:35 +0200 Subject: migration: Pass Error ** argument to {save,load}_vmstate This way we use the "normal" way of printing errors for hmp commands. Signed-off-by: Juan Quintela Suggested-by: Paolo Bonzini Reviewed-by: Peter Xu Reviewed-by: Laurent Vivier --- include/sysemu/sysemu.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index be9e22c955..282f6bc8d2 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -75,8 +75,8 @@ void qemu_remove_exit_notifier(Notifier *notify); void qemu_add_machine_init_done_notifier(Notifier *notify); void qemu_remove_machine_init_done_notifier(Notifier *notify); -int save_vmstate(const char *name); -int load_vmstate(const char *name); +int save_vmstate(const char *name, Error **errp); +int load_vmstate(const char *name, Error **errp); void qemu_announce_self(void); -- cgit v1.2.3-55-g7522 From 795c40b8bdbe3fd04bb976416e1bdcf5e3fe997e Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Thu, 6 Apr 2017 12:00:28 +0200 Subject: migration: Create migration/blocker.h This allows us to remove lots of includes of migration/migration.h Signed-off-by: Juan Quintela Reviewed-by: Peter Xu Reviewed-by: Dr. David Alan Gilbert --- block/qcow.c | 2 +- block/vdi.c | 2 +- block/vhdx.c | 2 +- block/vmdk.c | 2 +- block/vpc.c | 2 +- block/vvfat.c | 2 +- hw/9pfs/9p.c | 2 +- hw/display/qxl.c | 2 +- hw/display/virtio-gpu.c | 2 +- hw/intc/arm_gic_kvm.c | 2 +- hw/intc/arm_gicv3_its_kvm.c | 2 +- hw/intc/arm_gicv3_kvm.c | 2 +- hw/misc/ivshmem.c | 2 +- hw/scsi/vhost-scsi.c | 2 +- hw/virtio/vhost.c | 2 +- include/migration/blocker.h | 35 +++++++++++++++++++++++++++++++++++ include/migration/migration.h | 18 ------------------ migration/migration.c | 1 + stubs/migr-blocker.c | 2 +- target/i386/kvm.c | 2 +- 20 files changed, 53 insertions(+), 35 deletions(-) create mode 100644 include/migration/blocker.h (limited to 'include') diff --git a/block/qcow.c b/block/qcow.c index 5d147b962e..95ab123407 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -32,7 +32,7 @@ #include #include "qapi/qmp/qerror.h" #include "crypto/cipher.h" -#include "migration/migration.h" +#include "migration/blocker.h" /**************************************************************/ /* QEMU COW block driver with compression and encryption support */ diff --git a/block/vdi.c b/block/vdi.c index d12d9cdc79..79af47763b 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -55,7 +55,7 @@ #include "sysemu/block-backend.h" #include "qemu/module.h" #include "qemu/bswap.h" -#include "migration/migration.h" +#include "migration/blocker.h" #include "qemu/coroutine.h" #include "qemu/cutils.h" #include "qemu/uuid.h" diff --git a/block/vhdx.c b/block/vhdx.c index e8fe3fb5e9..8b270b57c9 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -24,7 +24,7 @@ #include "qemu/crc32c.h" #include "qemu/bswap.h" #include "block/vhdx.h" -#include "migration/migration.h" +#include "migration/blocker.h" #include "qemu/uuid.h" /* Options for VHDX creation */ diff --git a/block/vmdk.c b/block/vmdk.c index c61b9cc8e0..55581b03fe 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -31,7 +31,7 @@ #include "qemu/error-report.h" #include "qemu/module.h" #include "qemu/bswap.h" -#include "migration/migration.h" +#include "migration/blocker.h" #include "qemu/cutils.h" #include diff --git a/block/vpc.c b/block/vpc.c index ecfee77149..4240ba9d1c 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -28,7 +28,7 @@ #include "block/block_int.h" #include "sysemu/block-backend.h" #include "qemu/module.h" -#include "migration/migration.h" +#include "migration/blocker.h" #include "qemu/bswap.h" #include "qemu/uuid.h" diff --git a/block/vvfat.c b/block/vvfat.c index 9c82371360..426ca70e35 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -28,7 +28,7 @@ #include "block/block_int.h" #include "qemu/module.h" #include "qemu/bswap.h" -#include "migration/migration.h" +#include "migration/blocker.h" #include "qapi/qmp/qint.h" #include "qapi/qmp/qbool.h" #include "qapi/qmp/qstring.h" diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index c80ba67389..ab3e22f231 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -23,7 +23,7 @@ #include "9p-xattr.h" #include "coth.h" #include "trace.h" -#include "migration/migration.h" +#include "migration/blocker.h" int open_fd_hw; int total_open_fd; diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 4d94cecd72..ad09bb98f9 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -26,7 +26,7 @@ #include "qemu/queue.h" #include "qemu/atomic.h" #include "sysemu/sysemu.h" -#include "migration/migration.h" +#include "migration/blocker.h" #include "trace.h" #include "qxl.h" diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index cfb5dfa336..58dc0b2737 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -19,7 +19,7 @@ #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-gpu.h" #include "hw/virtio/virtio-bus.h" -#include "migration/migration.h" +#include "migration/blocker.h" #include "qemu/log.h" #include "qapi/error.h" diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index ec952ece93..af5cd367e9 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -24,7 +24,7 @@ #include "qemu-common.h" #include "cpu.h" #include "hw/sysbus.h" -#include "migration/migration.h" +#include "migration/blocker.h" #include "sysemu/kvm.h" #include "kvm_arm.h" #include "gic_internal.h" diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c index bd4f3aafc6..a0441d6bd1 100644 --- a/hw/intc/arm_gicv3_its_kvm.c +++ b/hw/intc/arm_gicv3_its_kvm.c @@ -24,7 +24,7 @@ #include "sysemu/sysemu.h" #include "sysemu/kvm.h" #include "kvm_arm.h" -#include "migration/migration.h" +#include "migration/blocker.h" #define TYPE_KVM_ARM_ITS "arm-its-kvm" #define KVM_ARM_ITS(obj) OBJECT_CHECK(GICv3ITSState, (obj), TYPE_KVM_ARM_ITS) diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 19aab56072..4ee2baa691 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -28,7 +28,7 @@ #include "kvm_arm.h" #include "gicv3_internal.h" #include "vgic_common.h" -#include "migration/migration.h" +#include "migration/blocker.h" #ifdef DEBUG_GICV3_KVM #define DPRINTF(fmt, ...) \ diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 82ce8378bf..475e36a4c7 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -25,7 +25,7 @@ #include "hw/pci/msi.h" #include "hw/pci/msix.h" #include "sysemu/kvm.h" -#include "migration/migration.h" +#include "migration/blocker.h" #include "qemu/error-report.h" #include "qemu/event_notifier.h" #include "qom/object_interfaces.h" diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 8f53ac3795..cd4ab05233 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -21,7 +21,7 @@ #include "qemu/error-report.h" #include "qemu/queue.h" #include "monitor/monitor.h" -#include "migration/migration.h" +#include "migration/blocker.h" #include "hw/virtio/vhost-scsi.h" #include "hw/virtio/vhost.h" #include "hw/virtio/virtio-scsi.h" diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 0001e60b77..03a46a7429 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -25,7 +25,7 @@ #include "exec/address-spaces.h" #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-access.h" -#include "migration/migration.h" +#include "migration/blocker.h" #include "sysemu/dma.h" /* enabled until disconnected backend stabilizes */ diff --git a/include/migration/blocker.h b/include/migration/blocker.h new file mode 100644 index 0000000000..acd27018e9 --- /dev/null +++ b/include/migration/blocker.h @@ -0,0 +1,35 @@ +/* + * QEMU migration blockers + * + * Copyright IBM, Corp. 2008 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef MIGRATION_BLOCKER_H +#define MIGRATION_BLOCKER_H + +/** + * @migrate_add_blocker - prevent migration from proceeding + * + * @reason - an error to be returned whenever migration is attempted + * + * @errp - [out] The reason (if any) we cannot block migration right now. + * + * @returns - 0 on success, -EBUSY/-EACCES on failure, with errp set. + */ +int migrate_add_blocker(Error *reason, Error **errp); + +/** + * @migrate_del_blocker - remove a blocking error from migration + * + * @reason - the error blocking migration + */ +void migrate_del_blocker(Error *reason); + +#endif diff --git a/include/migration/migration.h b/include/migration/migration.h index e29cb0144b..47262bdcdc 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -275,24 +275,6 @@ int ram_discard_range(const char *block_name, uint64_t start, size_t length); int ram_postcopy_incoming_init(MigrationIncomingState *mis); void ram_postcopy_migrated_memory_release(MigrationState *ms); -/** - * @migrate_add_blocker - prevent migration from proceeding - * - * @reason - an error to be returned whenever migration is attempted - * - * @errp - [out] The reason (if any) we cannot block migration right now. - * - * @returns - 0 on success, -EBUSY/-EACCES on failure, with errp set. - */ -int migrate_add_blocker(Error *reason, Error **errp); - -/** - * @migrate_del_blocker - remove a blocking error from migration - * - * @reason - the error blocking migration - */ -void migrate_del_blocker(Error *reason); - int check_migratable(Object *obj, Error **err); bool migrate_release_ram(void); diff --git a/migration/migration.c b/migration/migration.c index a5ade23e24..5c9285125a 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -17,6 +17,7 @@ #include "qemu/cutils.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" +#include "migration/blocker.h" #include "migration/migration.h" #include "migration/qemu-file.h" #include "sysemu/sysemu.h" diff --git a/stubs/migr-blocker.c b/stubs/migr-blocker.c index a5ba18f53d..2b64ac9560 100644 --- a/stubs/migr-blocker.c +++ b/stubs/migr-blocker.c @@ -1,6 +1,6 @@ #include "qemu/osdep.h" #include "qemu-common.h" -#include "migration/migration.h" +#include "migration/blocker.h" int migrate_add_blocker(Error *reason, Error **errp) { diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 55865dbee0..011d4a55b1 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -43,7 +43,7 @@ #include "standard-headers/asm-x86/hyperv.h" #include "hw/pci/pci.h" #include "hw/pci/msi.h" -#include "migration/migration.h" +#include "migration/blocker.h" #include "exec/memattrs.h" #include "trace.h" -- cgit v1.2.3-55-g7522 From aa3544c371748fdc2c012c2aaeeac8c66b4f0808 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Thu, 20 Apr 2017 12:37:23 +0200 Subject: migration: Move page_cache.c to migration/ It is only used by migration, so move it there. Signed-off-by: Juan Quintela Reviewed-by: Dr. David Alan Gilbert --- Makefile.objs | 1 - include/migration/page_cache.h | 86 --------------- migration/Makefile.objs | 2 +- migration/page_cache.c | 236 +++++++++++++++++++++++++++++++++++++++++ migration/page_cache.h | 86 +++++++++++++++ page_cache.c | 236 ----------------------------------------- tests/Makefile.include | 2 +- 7 files changed, 324 insertions(+), 325 deletions(-) delete mode 100644 include/migration/page_cache.h create mode 100644 migration/page_cache.c create mode 100644 migration/page_cache.h delete mode 100644 page_cache.c (limited to 'include') diff --git a/Makefile.objs b/Makefile.objs index 6167e7b17d..2100845ce2 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -49,7 +49,6 @@ common-obj-$(CONFIG_POSIX) += os-posix.o common-obj-$(CONFIG_LINUX) += fsdev/ common-obj-y += migration/ -common-obj-y += page_cache.o #aio.o common-obj-$(CONFIG_SPICE) += spice-qemu-char.o diff --git a/include/migration/page_cache.h b/include/migration/page_cache.h deleted file mode 100644 index 10ed53274c..0000000000 --- a/include/migration/page_cache.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Page cache for QEMU - * The cache is base on a hash of the page address - * - * Copyright 2012 Red Hat, Inc. and/or its affiliates - * - * Authors: - * Orit Wasserman - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * - */ - -#ifndef PAGE_CACHE_H -#define PAGE_CACHE_H - -/* Page cache for storing guest pages */ -typedef struct PageCache PageCache; - -/** - * cache_init: Initialize the page cache - * - * - * Returns new allocated cache or NULL on error - * - * @cache pointer to the PageCache struct - * @num_pages: cache maximal number of cached pages - * @page_size: cache page size - */ -PageCache *cache_init(int64_t num_pages, unsigned int page_size); - -/** - * cache_fini: free all cache resources - * @cache pointer to the PageCache struct - */ -void cache_fini(PageCache *cache); - -/** - * cache_is_cached: Checks to see if the page is cached - * - * Returns %true if page is cached - * - * @cache pointer to the PageCache struct - * @addr: page addr - * @current_age: current bitmap generation - */ -bool cache_is_cached(const PageCache *cache, uint64_t addr, - uint64_t current_age); - -/** - * get_cached_data: Get the data cached for an addr - * - * Returns pointer to the data cached or NULL if not cached - * - * @cache pointer to the PageCache struct - * @addr: page addr - */ -uint8_t *get_cached_data(const PageCache *cache, uint64_t addr); - -/** - * cache_insert: insert the page into the cache. the page cache - * will dup the data on insert. the previous value will be overwritten - * - * Returns -1 when the page isn't inserted into cache - * - * @cache pointer to the PageCache struct - * @addr: page address - * @pdata: pointer to the page - * @current_age: current bitmap generation - */ -int cache_insert(PageCache *cache, uint64_t addr, const uint8_t *pdata, - uint64_t current_age); - -/** - * cache_resize: resize the page cache. In case of size reduction the extra - * pages will be freed - * - * Returns -1 on error new cache size on success - * - * @cache pointer to the PageCache struct - * @num_pages: new page cache size (in pages) - */ -int64_t cache_resize(PageCache *cache, int64_t num_pages); - -#endif diff --git a/migration/Makefile.objs b/migration/Makefile.objs index 480dd493a9..c1920b6fc0 100644 --- a/migration/Makefile.objs +++ b/migration/Makefile.objs @@ -1,7 +1,7 @@ common-obj-y += migration.o socket.o fd.o exec.o common-obj-y += tls.o common-obj-y += colo-comm.o colo.o colo-failover.o -common-obj-y += vmstate.o +common-obj-y += vmstate.o page_cache.o common-obj-y += qemu-file.o common-obj-y += qemu-file-channel.o common-obj-y += xbzrle.o postcopy-ram.o diff --git a/migration/page_cache.c b/migration/page_cache.c new file mode 100644 index 0000000000..5f8578736e --- /dev/null +++ b/migration/page_cache.c @@ -0,0 +1,236 @@ +/* + * Page cache for QEMU + * The cache is base on a hash of the page address + * + * Copyright 2012 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Orit Wasserman + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" + +#include "qemu-common.h" +#include "qemu/host-utils.h" +#include "migration/page_cache.h" + +#ifdef DEBUG_CACHE +#define DPRINTF(fmt, ...) \ + do { fprintf(stdout, "cache: " fmt, ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) \ + do { } while (0) +#endif + +/* the page in cache will not be replaced in two cycles */ +#define CACHED_PAGE_LIFETIME 2 + +typedef struct CacheItem CacheItem; + +struct CacheItem { + uint64_t it_addr; + uint64_t it_age; + uint8_t *it_data; +}; + +struct PageCache { + CacheItem *page_cache; + unsigned int page_size; + int64_t max_num_items; + uint64_t max_item_age; + int64_t num_items; +}; + +PageCache *cache_init(int64_t num_pages, unsigned int page_size) +{ + int64_t i; + + PageCache *cache; + + if (num_pages <= 0) { + DPRINTF("invalid number of pages\n"); + return NULL; + } + + /* We prefer not to abort if there is no memory */ + cache = g_try_malloc(sizeof(*cache)); + if (!cache) { + DPRINTF("Failed to allocate cache\n"); + return NULL; + } + /* round down to the nearest power of 2 */ + if (!is_power_of_2(num_pages)) { + num_pages = pow2floor(num_pages); + DPRINTF("rounding down to %" PRId64 "\n", num_pages); + } + cache->page_size = page_size; + cache->num_items = 0; + cache->max_item_age = 0; + cache->max_num_items = num_pages; + + DPRINTF("Setting cache buckets to %" PRId64 "\n", cache->max_num_items); + + /* We prefer not to abort if there is no memory */ + cache->page_cache = g_try_malloc((cache->max_num_items) * + sizeof(*cache->page_cache)); + if (!cache->page_cache) { + DPRINTF("Failed to allocate cache->page_cache\n"); + g_free(cache); + return NULL; + } + + for (i = 0; i < cache->max_num_items; i++) { + cache->page_cache[i].it_data = NULL; + cache->page_cache[i].it_age = 0; + cache->page_cache[i].it_addr = -1; + } + + return cache; +} + +void cache_fini(PageCache *cache) +{ + int64_t i; + + g_assert(cache); + g_assert(cache->page_cache); + + for (i = 0; i < cache->max_num_items; i++) { + g_free(cache->page_cache[i].it_data); + } + + g_free(cache->page_cache); + cache->page_cache = NULL; + g_free(cache); +} + +static size_t cache_get_cache_pos(const PageCache *cache, + uint64_t address) +{ + g_assert(cache->max_num_items); + return (address / cache->page_size) & (cache->max_num_items - 1); +} + +static CacheItem *cache_get_by_addr(const PageCache *cache, uint64_t addr) +{ + size_t pos; + + g_assert(cache); + g_assert(cache->page_cache); + + pos = cache_get_cache_pos(cache, addr); + + return &cache->page_cache[pos]; +} + +uint8_t *get_cached_data(const PageCache *cache, uint64_t addr) +{ + return cache_get_by_addr(cache, addr)->it_data; +} + +bool cache_is_cached(const PageCache *cache, uint64_t addr, + uint64_t current_age) +{ + CacheItem *it; + + it = cache_get_by_addr(cache, addr); + + if (it->it_addr == addr) { + /* update the it_age when the cache hit */ + it->it_age = current_age; + return true; + } + return false; +} + +int cache_insert(PageCache *cache, uint64_t addr, const uint8_t *pdata, + uint64_t current_age) +{ + + CacheItem *it; + + /* actual update of entry */ + it = cache_get_by_addr(cache, addr); + + if (it->it_data && it->it_addr != addr && + it->it_age + CACHED_PAGE_LIFETIME > current_age) { + /* the cache page is fresh, don't replace it */ + return -1; + } + /* allocate page */ + if (!it->it_data) { + it->it_data = g_try_malloc(cache->page_size); + if (!it->it_data) { + DPRINTF("Error allocating page\n"); + return -1; + } + cache->num_items++; + } + + memcpy(it->it_data, pdata, cache->page_size); + + it->it_age = current_age; + it->it_addr = addr; + + return 0; +} + +int64_t cache_resize(PageCache *cache, int64_t new_num_pages) +{ + PageCache *new_cache; + int64_t i; + + CacheItem *old_it, *new_it; + + g_assert(cache); + + /* cache was not inited */ + if (cache->page_cache == NULL) { + return -1; + } + + /* same size */ + if (pow2floor(new_num_pages) == cache->max_num_items) { + return cache->max_num_items; + } + + new_cache = cache_init(new_num_pages, cache->page_size); + if (!(new_cache)) { + DPRINTF("Error creating new cache\n"); + return -1; + } + + /* move all data from old cache */ + for (i = 0; i < cache->max_num_items; i++) { + old_it = &cache->page_cache[i]; + if (old_it->it_addr != -1) { + /* check for collision, if there is, keep MRU page */ + new_it = cache_get_by_addr(new_cache, old_it->it_addr); + if (new_it->it_data && new_it->it_age >= old_it->it_age) { + /* keep the MRU page */ + g_free(old_it->it_data); + } else { + if (!new_it->it_data) { + new_cache->num_items++; + } + g_free(new_it->it_data); + new_it->it_data = old_it->it_data; + new_it->it_age = old_it->it_age; + new_it->it_addr = old_it->it_addr; + } + } + } + + g_free(cache->page_cache); + cache->page_cache = new_cache->page_cache; + cache->max_num_items = new_cache->max_num_items; + cache->num_items = new_cache->num_items; + + g_free(new_cache); + + return cache->max_num_items; +} diff --git a/migration/page_cache.h b/migration/page_cache.h new file mode 100644 index 0000000000..10ed53274c --- /dev/null +++ b/migration/page_cache.h @@ -0,0 +1,86 @@ +/* + * Page cache for QEMU + * The cache is base on a hash of the page address + * + * Copyright 2012 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Orit Wasserman + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef PAGE_CACHE_H +#define PAGE_CACHE_H + +/* Page cache for storing guest pages */ +typedef struct PageCache PageCache; + +/** + * cache_init: Initialize the page cache + * + * + * Returns new allocated cache or NULL on error + * + * @cache pointer to the PageCache struct + * @num_pages: cache maximal number of cached pages + * @page_size: cache page size + */ +PageCache *cache_init(int64_t num_pages, unsigned int page_size); + +/** + * cache_fini: free all cache resources + * @cache pointer to the PageCache struct + */ +void cache_fini(PageCache *cache); + +/** + * cache_is_cached: Checks to see if the page is cached + * + * Returns %true if page is cached + * + * @cache pointer to the PageCache struct + * @addr: page addr + * @current_age: current bitmap generation + */ +bool cache_is_cached(const PageCache *cache, uint64_t addr, + uint64_t current_age); + +/** + * get_cached_data: Get the data cached for an addr + * + * Returns pointer to the data cached or NULL if not cached + * + * @cache pointer to the PageCache struct + * @addr: page addr + */ +uint8_t *get_cached_data(const PageCache *cache, uint64_t addr); + +/** + * cache_insert: insert the page into the cache. the page cache + * will dup the data on insert. the previous value will be overwritten + * + * Returns -1 when the page isn't inserted into cache + * + * @cache pointer to the PageCache struct + * @addr: page address + * @pdata: pointer to the page + * @current_age: current bitmap generation + */ +int cache_insert(PageCache *cache, uint64_t addr, const uint8_t *pdata, + uint64_t current_age); + +/** + * cache_resize: resize the page cache. In case of size reduction the extra + * pages will be freed + * + * Returns -1 on error new cache size on success + * + * @cache pointer to the PageCache struct + * @num_pages: new page cache size (in pages) + */ +int64_t cache_resize(PageCache *cache, int64_t num_pages); + +#endif diff --git a/page_cache.c b/page_cache.c deleted file mode 100644 index 5f8578736e..0000000000 --- a/page_cache.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Page cache for QEMU - * The cache is base on a hash of the page address - * - * Copyright 2012 Red Hat, Inc. and/or its affiliates - * - * Authors: - * Orit Wasserman - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * - */ - -#include "qemu/osdep.h" - -#include "qemu-common.h" -#include "qemu/host-utils.h" -#include "migration/page_cache.h" - -#ifdef DEBUG_CACHE -#define DPRINTF(fmt, ...) \ - do { fprintf(stdout, "cache: " fmt, ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) \ - do { } while (0) -#endif - -/* the page in cache will not be replaced in two cycles */ -#define CACHED_PAGE_LIFETIME 2 - -typedef struct CacheItem CacheItem; - -struct CacheItem { - uint64_t it_addr; - uint64_t it_age; - uint8_t *it_data; -}; - -struct PageCache { - CacheItem *page_cache; - unsigned int page_size; - int64_t max_num_items; - uint64_t max_item_age; - int64_t num_items; -}; - -PageCache *cache_init(int64_t num_pages, unsigned int page_size) -{ - int64_t i; - - PageCache *cache; - - if (num_pages <= 0) { - DPRINTF("invalid number of pages\n"); - return NULL; - } - - /* We prefer not to abort if there is no memory */ - cache = g_try_malloc(sizeof(*cache)); - if (!cache) { - DPRINTF("Failed to allocate cache\n"); - return NULL; - } - /* round down to the nearest power of 2 */ - if (!is_power_of_2(num_pages)) { - num_pages = pow2floor(num_pages); - DPRINTF("rounding down to %" PRId64 "\n", num_pages); - } - cache->page_size = page_size; - cache->num_items = 0; - cache->max_item_age = 0; - cache->max_num_items = num_pages; - - DPRINTF("Setting cache buckets to %" PRId64 "\n", cache->max_num_items); - - /* We prefer not to abort if there is no memory */ - cache->page_cache = g_try_malloc((cache->max_num_items) * - sizeof(*cache->page_cache)); - if (!cache->page_cache) { - DPRINTF("Failed to allocate cache->page_cache\n"); - g_free(cache); - return NULL; - } - - for (i = 0; i < cache->max_num_items; i++) { - cache->page_cache[i].it_data = NULL; - cache->page_cache[i].it_age = 0; - cache->page_cache[i].it_addr = -1; - } - - return cache; -} - -void cache_fini(PageCache *cache) -{ - int64_t i; - - g_assert(cache); - g_assert(cache->page_cache); - - for (i = 0; i < cache->max_num_items; i++) { - g_free(cache->page_cache[i].it_data); - } - - g_free(cache->page_cache); - cache->page_cache = NULL; - g_free(cache); -} - -static size_t cache_get_cache_pos(const PageCache *cache, - uint64_t address) -{ - g_assert(cache->max_num_items); - return (address / cache->page_size) & (cache->max_num_items - 1); -} - -static CacheItem *cache_get_by_addr(const PageCache *cache, uint64_t addr) -{ - size_t pos; - - g_assert(cache); - g_assert(cache->page_cache); - - pos = cache_get_cache_pos(cache, addr); - - return &cache->page_cache[pos]; -} - -uint8_t *get_cached_data(const PageCache *cache, uint64_t addr) -{ - return cache_get_by_addr(cache, addr)->it_data; -} - -bool cache_is_cached(const PageCache *cache, uint64_t addr, - uint64_t current_age) -{ - CacheItem *it; - - it = cache_get_by_addr(cache, addr); - - if (it->it_addr == addr) { - /* update the it_age when the cache hit */ - it->it_age = current_age; - return true; - } - return false; -} - -int cache_insert(PageCache *cache, uint64_t addr, const uint8_t *pdata, - uint64_t current_age) -{ - - CacheItem *it; - - /* actual update of entry */ - it = cache_get_by_addr(cache, addr); - - if (it->it_data && it->it_addr != addr && - it->it_age + CACHED_PAGE_LIFETIME > current_age) { - /* the cache page is fresh, don't replace it */ - return -1; - } - /* allocate page */ - if (!it->it_data) { - it->it_data = g_try_malloc(cache->page_size); - if (!it->it_data) { - DPRINTF("Error allocating page\n"); - return -1; - } - cache->num_items++; - } - - memcpy(it->it_data, pdata, cache->page_size); - - it->it_age = current_age; - it->it_addr = addr; - - return 0; -} - -int64_t cache_resize(PageCache *cache, int64_t new_num_pages) -{ - PageCache *new_cache; - int64_t i; - - CacheItem *old_it, *new_it; - - g_assert(cache); - - /* cache was not inited */ - if (cache->page_cache == NULL) { - return -1; - } - - /* same size */ - if (pow2floor(new_num_pages) == cache->max_num_items) { - return cache->max_num_items; - } - - new_cache = cache_init(new_num_pages, cache->page_size); - if (!(new_cache)) { - DPRINTF("Error creating new cache\n"); - return -1; - } - - /* move all data from old cache */ - for (i = 0; i < cache->max_num_items; i++) { - old_it = &cache->page_cache[i]; - if (old_it->it_addr != -1) { - /* check for collision, if there is, keep MRU page */ - new_it = cache_get_by_addr(new_cache, old_it->it_addr); - if (new_it->it_data && new_it->it_age >= old_it->it_age) { - /* keep the MRU page */ - g_free(old_it->it_data); - } else { - if (!new_it->it_data) { - new_cache->num_items++; - } - g_free(new_it->it_data); - new_it->it_data = old_it->it_data; - new_it->it_age = old_it->it_age; - new_it->it_addr = old_it->it_addr; - } - } - } - - g_free(cache->page_cache); - cache->page_cache = new_cache->page_cache; - cache->max_num_items = new_cache->max_num_items; - cache->num_items = new_cache->num_items; - - g_free(new_cache); - - return cache->max_num_items; -} diff --git a/tests/Makefile.include b/tests/Makefile.include index 16ff8f399f..4277597e93 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -554,7 +554,7 @@ tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y) tests/test-iov$(EXESUF): tests/test-iov.o $(test-util-obj-y) tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y) tests/test-x86-cpuid$(EXESUF): tests/test-x86-cpuid.o -tests/test-xbzrle$(EXESUF): tests/test-xbzrle.o migration/xbzrle.o page_cache.o $(test-util-obj-y) +tests/test-xbzrle$(EXESUF): tests/test-xbzrle.o migration/xbzrle.o migration/page_cache.o $(test-util-obj-y) tests/test-cutils$(EXESUF): tests/test-cutils.o util/cutils.o tests/test-int128$(EXESUF): tests/test-int128.o tests/rcutorture$(EXESUF): tests/rcutorture.o $(test-util-obj-y) -- cgit v1.2.3-55-g7522 From bac3b21218925006e1f7d3cae564afb1e9aeb8ee Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Mon, 24 Apr 2017 16:50:35 +0200 Subject: migration: Move postcopy stuff to postcopy-ram.c Yes, we don't have a good place to put that stuff. Signed-off-by: Juan Quintela Reviewed-by: Dr. David Alan Gilbert --- include/migration/migration.h | 26 -------------------------- migration/migration.c | 18 ------------------ migration/postcopy-ram.c | 18 ++++++++++++++++++ migration/postcopy-ram.h | 26 ++++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 44 deletions(-) (limited to 'include') diff --git a/include/migration/migration.h b/include/migration/migration.h index 47262bdcdc..97e78ba908 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -61,28 +61,6 @@ enum mig_rp_message_type { typedef QLIST_HEAD(, LoadStateEntry) LoadStateEntry_Head; -/* The current postcopy state is read/set by postcopy_state_get/set - * which update it atomically. - * The state is updated as postcopy messages are received, and - * in general only one thread should be writing to the state at any one - * time, initially the main thread and then the listen thread; - * Corner cases are where either thread finishes early and/or errors. - * The state is checked as messages are received to ensure that - * the source is sending us messages in the correct order. - * The state is also used by the RAM reception code to know if it - * has to place pages atomically, and the cleanup code at the end of - * the main thread to know if it has to delay cleanup until the end - * of postcopy. - */ -typedef enum { - POSTCOPY_INCOMING_NONE = 0, /* Initial state - no postcopy */ - POSTCOPY_INCOMING_ADVISE, - POSTCOPY_INCOMING_DISCARD, - POSTCOPY_INCOMING_LISTENING, - POSTCOPY_INCOMING_RUNNING, - POSTCOPY_INCOMING_END -} PostcopyState; - /* State for the incoming migration */ struct MigrationIncomingState { QEMUFile *from_src_file; @@ -339,8 +317,4 @@ void global_state_store_running(void); void migration_page_queue_free(void); int ram_save_queue_pages(const char *rbname, ram_addr_t start, ram_addr_t len); uint64_t ram_pagesize_summary(void); - -PostcopyState postcopy_state_get(void); -/* Set the state and return the old state */ -PostcopyState postcopy_state_set(PostcopyState new_state); #endif diff --git a/migration/migration.c b/migration/migration.c index 5c9285125a..ed11c1fb53 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -78,13 +78,6 @@ static NotifierList migration_state_notifiers = static bool deferred_incoming; -/* - * Current state of incoming postcopy; note this is not part of - * MigrationIncomingState since it's state is used during cleanup - * at the end as MIS is being freed. - */ -static PostcopyState incoming_postcopy_state; - /* When we add fault tolerance, we could have several migrations at once. For now we don't need to add dynamic creation of migration */ @@ -2098,14 +2091,3 @@ void migrate_fd_connect(MigrationState *s) s->migration_thread_running = true; } -PostcopyState postcopy_state_get(void) -{ - return atomic_mb_read(&incoming_postcopy_state); -} - -/* Set the state and return the old state */ -PostcopyState postcopy_state_set(PostcopyState new_state) -{ - return atomic_xchg(&incoming_postcopy_state, new_state); -} - diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index cdadaf6578..a0489f6542 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -784,3 +784,21 @@ void postcopy_discard_send_finish(MigrationState *ms, PostcopyDiscardState *pds) g_free(pds); } + +/* + * Current state of incoming postcopy; note this is not part of + * MigrationIncomingState since it's state is used during cleanup + * at the end as MIS is being freed. + */ +static PostcopyState incoming_postcopy_state; + +PostcopyState postcopy_state_get(void) +{ + return atomic_mb_read(&incoming_postcopy_state); +} + +/* Set the state and return the old state */ +PostcopyState postcopy_state_set(PostcopyState new_state) +{ + return atomic_xchg(&incoming_postcopy_state, new_state); +} diff --git a/migration/postcopy-ram.h b/migration/postcopy-ram.h index 4c25f03be2..52d51e8007 100644 --- a/migration/postcopy-ram.h +++ b/migration/postcopy-ram.h @@ -81,6 +81,28 @@ int postcopy_place_page(MigrationIncomingState *mis, void *host, void *from, int postcopy_place_page_zero(MigrationIncomingState *mis, void *host, size_t pagesize); +/* The current postcopy state is read/set by postcopy_state_get/set + * which update it atomically. + * The state is updated as postcopy messages are received, and + * in general only one thread should be writing to the state at any one + * time, initially the main thread and then the listen thread; + * Corner cases are where either thread finishes early and/or errors. + * The state is checked as messages are received to ensure that + * the source is sending us messages in the correct order. + * The state is also used by the RAM reception code to know if it + * has to place pages atomically, and the cleanup code at the end of + * the main thread to know if it has to delay cleanup until the end + * of postcopy. + */ +typedef enum { + POSTCOPY_INCOMING_NONE = 0, /* Initial state - no postcopy */ + POSTCOPY_INCOMING_ADVISE, + POSTCOPY_INCOMING_DISCARD, + POSTCOPY_INCOMING_LISTENING, + POSTCOPY_INCOMING_RUNNING, + POSTCOPY_INCOMING_END +} PostcopyState; + /* * Allocate a page of memory that can be mapped at a later point in time * using postcopy_place_page @@ -88,4 +110,8 @@ int postcopy_place_page_zero(MigrationIncomingState *mis, void *host, */ void *postcopy_get_tmp_page(MigrationIncomingState *mis); +PostcopyState postcopy_state_get(void); +/* Set the state and return the old state */ +PostcopyState postcopy_state_set(PostcopyState new_state); + #endif -- cgit v1.2.3-55-g7522 From 1bfe5f0586083747f1602931713111673849cd9d Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Mon, 17 Apr 2017 14:57:54 +0200 Subject: migration: Move check_migratable() into qdev.c The function is only used once, and nothing else in migration knows about objects. Create the function vmstate_device_is_migratable() in savem.c that really do the bit that is related with migration. Signed-off-by: Juan Quintela Reviewed-by: Peter Xu --- hw/core/qdev.c | 20 ++++++++++++++++---- include/migration/migration.h | 6 ------ include/migration/vmstate.h | 2 ++ include/sysemu/sysemu.h | 2 +- migration/migration.c | 15 --------------- migration/savevm.c | 10 ++++++++++ stubs/vmstate.c | 5 ++--- 7 files changed, 31 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 02b632f6b3..6f1b070616 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -37,7 +37,7 @@ #include "hw/boards.h" #include "hw/sysbus.h" #include "qapi-event.h" -#include "migration/migration.h" +#include "migration/vmstate.h" bool qdev_hotplug = false; static bool qdev_hot_added = false; @@ -861,6 +861,20 @@ static bool device_get_realized(Object *obj, Error **errp) return dev->realized; } +static bool check_only_migratable(Object *obj, Error **err) +{ + DeviceClass *dc = DEVICE_GET_CLASS(obj); + + if (!vmstate_check_only_migratable(dc->vmsd)) { + error_setg(err, "Device %s is not migratable, but " + "--only-migratable was specified", + object_get_typename(obj)); + return false; + } + + return true; +} + static void device_set_realized(Object *obj, bool value, Error **errp) { DeviceState *dev = DEVICE(obj); @@ -870,7 +884,6 @@ static void device_set_realized(Object *obj, bool value, Error **errp) Error *local_err = NULL; bool unattached_parent = false; static int unattached_count; - int ret; if (dev->hotplugged && !dc->hotpluggable) { error_setg(errp, QERR_DEVICE_NO_HOTPLUG, object_get_typename(obj)); @@ -878,8 +891,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp) } if (value && !dev->realized) { - ret = check_migratable(obj, &local_err); - if (ret < 0) { + if (!check_only_migratable(obj, &local_err)) { goto fail; } diff --git a/include/migration/migration.h b/include/migration/migration.h index 97e78ba908..49ec5015e5 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -22,7 +22,6 @@ #include "qapi-types.h" #include "exec/cpu-common.h" #include "qemu/coroutine_int.h" -#include "qom/object.h" #define QEMU_VM_FILE_MAGIC 0x5145564d #define QEMU_VM_FILE_VERSION_COMPAT 0x00000002 @@ -39,9 +38,6 @@ #define QEMU_VM_COMMAND 0x08 #define QEMU_VM_SECTION_FOOTER 0x7e -/* for vl.c */ -extern int only_migratable; - struct MigrationParams { bool blk; bool shared; @@ -253,8 +249,6 @@ int ram_discard_range(const char *block_name, uint64_t start, size_t length); int ram_postcopy_incoming_init(MigrationIncomingState *mis); void ram_postcopy_migrated_memory_release(MigrationState *ms); -int check_migratable(Object *obj, Error **err); - bool migrate_release_ram(void); bool migrate_postcopy_ram(void); bool migrate_zero_blocks(void); diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index f4bf3f1b4e..848965963a 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -1067,4 +1067,6 @@ int64_t self_announce_delay(int round) void dump_vmstate_json_to_file(FILE *out_fp); +bool vmstate_check_only_migratable(const VMStateDescription *vmsd); + #endif diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 282f6bc8d2..83c1ceb33e 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -15,7 +15,7 @@ /* vl.c */ extern const char *bios_name; - +extern int only_migratable; extern const char *qemu_name; extern QemuUUID qemu_uuid; extern bool qemu_uuid_set; diff --git a/migration/migration.c b/migration/migration.c index ed11c1fb53..0304c013f3 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1143,21 +1143,6 @@ void migrate_del_blocker(Error *reason) migration_blockers = g_slist_remove(migration_blockers, reason); } -int check_migratable(Object *obj, Error **err) -{ - DeviceClass *dc = DEVICE_GET_CLASS(obj); - if (only_migratable && dc->vmsd) { - if (dc->vmsd->unmigratable) { - error_setg(err, "Device %s is not migratable, but " - "--only-migratable was specified", - object_get_typename(obj)); - return -1; - } - } - - return 0; -} - void qmp_migrate_incoming(const char *uri, Error **errp) { Error *local_err = NULL; diff --git a/migration/savevm.c b/migration/savevm.c index b4f736f5f7..f5e81948e6 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -2317,3 +2317,13 @@ void vmstate_register_ram_global(MemoryRegion *mr) { vmstate_register_ram(mr, NULL); } + +bool vmstate_check_only_migratable(const VMStateDescription *vmsd) +{ + /* check needed if --only-migratable is specified */ + if (!only_migratable) { + return true; + } + + return !(vmsd && vmsd->unmigratable); +} diff --git a/stubs/vmstate.c b/stubs/vmstate.c index 6d52f29bb2..6399474e49 100644 --- a/stubs/vmstate.c +++ b/stubs/vmstate.c @@ -1,7 +1,6 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "migration/vmstate.h" -#include "migration/migration.h" const VMStateDescription vmstate_dummy = {}; @@ -21,7 +20,7 @@ void vmstate_unregister(DeviceState *dev, { } -int check_migratable(Object *obj, Error **err) +bool vmstate_check_only_migratable(const VMStateDescription *vmsd) { - return 0; + return true; } -- cgit v1.2.3-55-g7522