Commit b54f18ba authored by Anthony Liguori's avatar Anthony Liguori
Browse files

Merge remote-tracking branch 'quintela/tags/migration/20140113' into staging



migration.next for 20140113

# gpg: Signature made Mon 13 Jan 2014 09:38:27 AM PST using RSA key ID 5872D723
# gpg: Can't check signature: public key not found

* quintela/tags/migration/20140113: (49 commits)
  migration: synchronize memory bitmap 64bits at a time
  ram: split function that synchronizes a range
  memory: syncronize kvm bitmap using bitmaps operations
  memory: move bitmap synchronization to its own function
  kvm: refactor start address calculation
  kvm: use directly cpu_physical_memory_* api for tracking dirty pages
  memory: unfold memory_region_test_and_clear()
  memory: split cpu_physical_memory_* functions to its own include
  memory: cpu_physical_memory_set_dirty_tracking() should return void
  memory: make cpu_physical_memory_reset_dirty() take a length parameter
  memory: s/dirty/clean/ in cpu_physical_memory_is_dirty()
  memory: cpu_physical_memory_clear_dirty_range() now uses bitmap operations
  memory: cpu_physical_memory_set_dirty_range() now uses bitmap operations
  memory: use find_next_bit() to find dirty bits
  memory: s/mask/clear/ cpu_physical_memory_mask_dirty_range
  memory: cpu_physical_memory_get_dirty() is used as returning a bool
  memory: make cpu_physical_memory_get_dirty() the main function
  memory: unfold cpu_physical_memory_set_dirty_flag()
  memory: unfold cpu_physical_memory_set_dirty() in its only user
  memory: unfold cpu_physical_memory_clear_dirty_flag() in its only user
  ...

Message-id: 1389634834-24181-1-git-send-email-quintela@redhat.com
Signed-off-by: default avatarAnthony Liguori <aliguori@amazon.com>
parents dd089c0a aa8dc044
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -51,6 +51,8 @@ common-obj-$(CONFIG_POSIX) += os-posix.o
common-obj-$(CONFIG_LINUX) += fsdev/

common-obj-y += migration.o migration-tcp.o
common-obj-y += vmstate.o
common-obj-y += qemu-file.o
common-obj-$(CONFIG_RDMA) += migration-rdma.o
common-obj-y += qemu-char.o #aio.o
common-obj-y += block-migration.o
+41 −11
Original line number Diff line number Diff line
@@ -48,7 +48,9 @@
#include "qmp-commands.h"
#include "trace.h"
#include "exec/cpu-all.h"
#include "exec/ram_addr.h"
#include "hw/acpi/acpi.h"
#include "qemu/host-utils.h"

#ifdef DEBUG_ARCH_INIT
#define DPRINTF(fmt, ...) \
@@ -359,11 +361,10 @@ ram_addr_t migration_bitmap_find_and_reset_dirty(MemoryRegion *mr,
    return (next - base) << TARGET_PAGE_BITS;
}

static inline bool migration_bitmap_set_dirty(MemoryRegion *mr,
                                              ram_addr_t offset)
static inline bool migration_bitmap_set_dirty(ram_addr_t addr)
{
    bool ret;
    int nr = (mr->ram_addr + offset) >> TARGET_PAGE_BITS;
    int nr = addr >> TARGET_PAGE_BITS;

    ret = test_and_set_bit(nr, migration_bitmap);

@@ -373,12 +374,47 @@ static inline bool migration_bitmap_set_dirty(MemoryRegion *mr,
    return ret;
}

static void migration_bitmap_sync_range(ram_addr_t start, ram_addr_t length)
{
    ram_addr_t addr;
    unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS);

    /* start address is aligned at the start of a word? */
    if (((page * BITS_PER_LONG) << TARGET_PAGE_BITS) == start) {
        int k;
        int nr = BITS_TO_LONGS(length >> TARGET_PAGE_BITS);
        unsigned long *src = ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION];

        for (k = page; k < page + nr; k++) {
            if (src[k]) {
                unsigned long new_dirty;
                new_dirty = ~migration_bitmap[k];
                migration_bitmap[k] |= src[k];
                new_dirty &= src[k];
                migration_dirty_pages += ctpopl(new_dirty);
                src[k] = 0;
            }
        }
    } else {
        for (addr = 0; addr < length; addr += TARGET_PAGE_SIZE) {
            if (cpu_physical_memory_get_dirty(start + addr,
                                              TARGET_PAGE_SIZE,
                                              DIRTY_MEMORY_MIGRATION)) {
                cpu_physical_memory_reset_dirty(start + addr,
                                                TARGET_PAGE_SIZE,
                                                DIRTY_MEMORY_MIGRATION);
                migration_bitmap_set_dirty(start + addr);
            }
        }
    }
}


/* Needs iothread lock! */

static void migration_bitmap_sync(void)
{
    RAMBlock *block;
    ram_addr_t addr;
    uint64_t num_dirty_pages_init = migration_dirty_pages;
    MigrationState *s = migrate_get_current();
    static int64_t start_time;
@@ -399,13 +435,7 @@ static void migration_bitmap_sync(void)
    address_space_sync_dirty_bitmap(&address_space_memory);

    QTAILQ_FOREACH(block, &ram_list.blocks, next) {
        for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
            if (memory_region_test_and_clear_dirty(block->mr,
                                                   addr, TARGET_PAGE_SIZE,
                                                   DIRTY_MEMORY_MIGRATION)) {
                migration_bitmap_set_dirty(block->mr, addr);
            }
        }
        migration_bitmap_sync_range(block->mr->ram_addr, block->length);
    }
    trace_migration_bitmap_sync_end(migration_dirty_pages
                                    - num_dirty_pages_init);
+6 −5
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include "exec/cputlb.h"

#include "exec/memory-internal.h"
#include "exec/ram_addr.h"

//#define DEBUG_TLB
//#define DEBUG_TLB_CHECK
@@ -112,9 +113,8 @@ void tlb_flush_page(CPUArchState *env, target_ulong addr)
   can be detected */
void tlb_protect_code(ram_addr_t ram_addr)
{
    cpu_physical_memory_reset_dirty(ram_addr,
                                    ram_addr + TARGET_PAGE_SIZE,
                                    CODE_DIRTY_FLAG);
    cpu_physical_memory_reset_dirty(ram_addr, TARGET_PAGE_SIZE,
                                    DIRTY_MEMORY_CODE);
}

/* update the TLB so that writes in physical page 'phys_addr' are no longer
@@ -122,7 +122,7 @@ void tlb_protect_code(ram_addr_t ram_addr)
void tlb_unprotect_code_phys(CPUArchState *env, ram_addr_t ram_addr,
                             target_ulong vaddr)
{
    cpu_physical_memory_set_dirty_flags(ram_addr, CODE_DIRTY_FLAG);
    cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_CODE);
}

static bool tlb_is_dirty_ram(CPUTLBEntry *tlbe)
@@ -284,7 +284,8 @@ void tlb_set_page(CPUArchState *env, target_ulong vaddr,
            /* Write access calls the I/O callback.  */
            te->addr_write = address | TLB_MMIO;
        } else if (memory_region_is_ram(section->mr)
                   && !cpu_physical_memory_is_dirty(section->mr->ram_addr + xlat)) {
                   && cpu_physical_memory_is_clean(section->mr->ram_addr
                                                   + xlat)) {
            te->addr_write = address | TLB_NOTDIRTY;
        } else {
            te->addr_write = address;
+40 −36
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@
#include "translate-all.h"

#include "exec/memory-internal.h"
#include "exec/ram_addr.h"
#include "qemu/cache-utils.h"

#include "qemu/range.h"
@@ -57,7 +58,7 @@
//#define DEBUG_SUBPAGE

#if !defined(CONFIG_USER_ONLY)
static int in_migration;
static bool in_migration;

RAMList ram_list = { .blocks = QTAILQ_HEAD_INITIALIZER(ram_list.blocks) };

@@ -724,11 +725,14 @@ found:
    return block;
}

static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t end,
                                      uintptr_t length)
static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t length)
{
    RAMBlock *block;
    ram_addr_t start1;
    RAMBlock *block;
    ram_addr_t end;

    end = TARGET_PAGE_ALIGN(start + length);
    start &= TARGET_PAGE_MASK;

    block = qemu_get_ram_block(start);
    assert(block == qemu_get_ram_block(end - 1));
@@ -737,29 +741,21 @@ static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t end,
}

/* Note: start and end must be within the same ram block.  */
void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
                                     int dirty_flags)
void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t length,
                                     unsigned client)
{
    uintptr_t length;

    start &= TARGET_PAGE_MASK;
    end = TARGET_PAGE_ALIGN(end);

    length = end - start;
    if (length == 0)
        return;
    cpu_physical_memory_mask_dirty_range(start, length, dirty_flags);
    cpu_physical_memory_clear_dirty_range(start, length, client);

    if (tcg_enabled()) {
        tlb_reset_dirty_range_all(start, end, length);
        tlb_reset_dirty_range_all(start, length);
    }
}

static int cpu_physical_memory_set_dirty_tracking(int enable)
static void cpu_physical_memory_set_dirty_tracking(bool enable)
{
    int ret = 0;
    in_migration = enable;
    return ret;
}

hwaddr memory_region_section_get_iotlb(CPUArchState *env,
@@ -1211,6 +1207,9 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
                                   MemoryRegion *mr)
{
    RAMBlock *block, *new_block;
    ram_addr_t old_ram_size, new_ram_size;

    old_ram_size = last_ram_offset() >> TARGET_PAGE_BITS;

    size = TARGET_PAGE_ALIGN(size);
    new_block = g_malloc0(sizeof(*new_block));
@@ -1271,11 +1270,17 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
    ram_list.version++;
    qemu_mutex_unlock_ramlist();

    ram_list.phys_dirty = g_realloc(ram_list.phys_dirty,
                                       last_ram_offset() >> TARGET_PAGE_BITS);
    memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
           0, size >> TARGET_PAGE_BITS);
    cpu_physical_memory_set_dirty_range(new_block->offset, size, 0xff);
    new_ram_size = last_ram_offset() >> TARGET_PAGE_BITS;

    if (new_ram_size > old_ram_size) {
        int i;
        for (i = 0; i < DIRTY_MEMORY_NUM; i++) {
            ram_list.dirty_memory[i] =
                bitmap_zero_extend(ram_list.dirty_memory[i],
                                   old_ram_size, new_ram_size);
       }
    }
    cpu_physical_memory_set_dirty_range(new_block->offset, size);

    qemu_ram_setup_dump(new_block->host, size);
    qemu_madvise(new_block->host, size, QEMU_MADV_HUGEPAGE);
@@ -1485,11 +1490,8 @@ found:
static void notdirty_mem_write(void *opaque, hwaddr ram_addr,
                               uint64_t val, unsigned size)
{
    int dirty_flags;
    dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
    if (!(dirty_flags & CODE_DIRTY_FLAG)) {
    if (!cpu_physical_memory_get_dirty_flag(ram_addr, DIRTY_MEMORY_CODE)) {
        tb_invalidate_phys_page_fast(ram_addr, size);
        dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
    }
    switch (size) {
    case 1:
@@ -1504,11 +1506,11 @@ static void notdirty_mem_write(void *opaque, hwaddr ram_addr,
    default:
        abort();
    }
    dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
    cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
    cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_MIGRATION);
    cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_VGA);
    /* we remove the notdirty callback only if the code has been
       flushed */
    if (dirty_flags == 0xff) {
    if (!cpu_physical_memory_is_clean(ram_addr)) {
        CPUArchState *env = current_cpu->env_ptr;
        tlb_set_dirty(env, env->mem_io_vaddr);
    }
@@ -1795,12 +1797,12 @@ static void tcg_commit(MemoryListener *listener)

static void core_log_global_start(MemoryListener *listener)
{
    cpu_physical_memory_set_dirty_tracking(1);
    cpu_physical_memory_set_dirty_tracking(true);
}

static void core_log_global_stop(MemoryListener *listener)
{
    cpu_physical_memory_set_dirty_tracking(0);
    cpu_physical_memory_set_dirty_tracking(false);
}

static MemoryListener core_memory_listener = {
@@ -1911,11 +1913,12 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
static void invalidate_and_set_dirty(hwaddr addr,
                                     hwaddr length)
{
    if (!cpu_physical_memory_is_dirty(addr)) {
    if (cpu_physical_memory_is_clean(addr)) {
        /* invalidate code */
        tb_invalidate_phys_page_range(addr, addr + length, 0);
        /* set dirty bit */
        cpu_physical_memory_set_dirty_flags(addr, (0xff & ~CODE_DIRTY_FLAG));
        cpu_physical_memory_set_dirty_flag(addr, DIRTY_MEMORY_VGA);
        cpu_physical_memory_set_dirty_flag(addr, DIRTY_MEMORY_MIGRATION);
    }
    xen_modified_memory(addr, length);
}
@@ -2526,12 +2529,13 @@ void stl_phys_notdirty(hwaddr addr, uint32_t val)
        stl_p(ptr, val);

        if (unlikely(in_migration)) {
            if (!cpu_physical_memory_is_dirty(addr1)) {
            if (cpu_physical_memory_is_clean(addr1)) {
                /* invalidate code */
                tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
                /* set dirty bit */
                cpu_physical_memory_set_dirty_flags(
                    addr1, (0xff & ~CODE_DIRTY_FLAG));
                cpu_physical_memory_set_dirty_flag(addr1,
                                                   DIRTY_MEMORY_MIGRATION);
                cpu_physical_memory_set_dirty_flag(addr1, DIRTY_MEMORY_VGA);
            }
        }
    }
+2 −1
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@

#include "qemu-common.h"
#include "exec/cpu-common.h"
#include "exec/memory.h"
#include "qemu/thread.h"
#include "qom/cpu.h"

@@ -459,7 +460,7 @@ typedef struct RAMBlock {
typedef struct RAMList {
    QemuMutex mutex;
    /* Protected by the iothread lock.  */
    uint8_t *phys_dirty;
    unsigned long *dirty_memory[DIRTY_MEMORY_NUM];
    RAMBlock *mru_block;
    /* Protected by the ramlist lock.  */
    QTAILQ_HEAD(, RAMBlock) blocks;
Loading