mirror of https://github.com/xqemu/xqemu.git
exec: ram_block_discard_range
Create ram_block_discard_range in exec.c to replace postcopy_ram_discard_range and most of ram_discard_range. Those two routines are a bit of a weird combination, and ram_discard_range is about to get more complex for hugepages. It's OS dependent code (so shouldn't be in migration/ram.c) but it needs quite a bit of the innards of RAMBlock so doesn't belong in the os*.c. Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> Reviewed-by: Juan Quintela <quintela@redhat.com> Reviewed-by: Laurent Vivier <lvivier@redhat.com> Message-Id: <20170224182844.32452-5-dgilbert@redhat.com> Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
This commit is contained in:
parent
29c5917201
commit
d3a5038c46
54
exec.c
54
exec.c
|
@ -45,6 +45,7 @@
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#include "sysemu/xen-mapcache.h"
|
#include "sysemu/xen-mapcache.h"
|
||||||
#include "trace-root.h"
|
#include "trace-root.h"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#include "exec/cpu-all.h"
|
#include "exec/cpu-all.h"
|
||||||
#include "qemu/rcu_queue.h"
|
#include "qemu/rcu_queue.h"
|
||||||
|
@ -3294,4 +3295,57 @@ int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque)
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unmap pages of memory from start to start+length such that
|
||||||
|
* they a) read as 0, b) Trigger whatever fault mechanism
|
||||||
|
* the OS provides for postcopy.
|
||||||
|
* The pages must be unmapped by the end of the function.
|
||||||
|
* Returns: 0 on success, none-0 on failure
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
uint8_t *host_startaddr = rb->host + start;
|
||||||
|
|
||||||
|
if ((uintptr_t)host_startaddr & (rb->page_size - 1)) {
|
||||||
|
error_report("ram_block_discard_range: Unaligned start address: %p",
|
||||||
|
host_startaddr);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((start + length) <= rb->used_length) {
|
||||||
|
uint8_t *host_endaddr = host_startaddr + length;
|
||||||
|
if ((uintptr_t)host_endaddr & (rb->page_size - 1)) {
|
||||||
|
error_report("ram_block_discard_range: Unaligned end address: %p",
|
||||||
|
host_endaddr);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = ENOTSUP; /* If we are missing MADVISE etc */
|
||||||
|
|
||||||
|
#if defined(CONFIG_MADVISE)
|
||||||
|
/* Note: We need the madvise MADV_DONTNEED behaviour of definitely
|
||||||
|
* freeing the page.
|
||||||
|
*/
|
||||||
|
ret = madvise(host_startaddr, length, MADV_DONTNEED);
|
||||||
|
#endif
|
||||||
|
if (ret) {
|
||||||
|
ret = -errno;
|
||||||
|
error_report("ram_block_discard_range: Failed to discard range "
|
||||||
|
"%s:%" PRIx64 " +%zx (%d)",
|
||||||
|
rb->idstr, start, length, ret);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error_report("ram_block_discard_range: Overrun block '%s' (%" PRIu64
|
||||||
|
"/%zx/" RAM_ADDR_FMT")",
|
||||||
|
rb->idstr, start, length, rb->used_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
err:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -105,6 +105,7 @@ typedef int (RAMBlockIterFunc)(const char *block_name, void *host_addr,
|
||||||
ram_addr_t offset, ram_addr_t length, void *opaque);
|
ram_addr_t offset, ram_addr_t length, void *opaque);
|
||||||
|
|
||||||
int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque);
|
int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque);
|
||||||
|
int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -34,13 +34,6 @@ int postcopy_ram_incoming_init(MigrationIncomingState *mis, size_t ram_pages);
|
||||||
*/
|
*/
|
||||||
int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis);
|
int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis);
|
||||||
|
|
||||||
/*
|
|
||||||
* Discard the contents of 'length' bytes from 'start'
|
|
||||||
* We can assume that if we've been called postcopy_ram_hosttest returned true
|
|
||||||
*/
|
|
||||||
int postcopy_ram_discard_range(MigrationIncomingState *mis, uint8_t *start,
|
|
||||||
size_t length);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Userfault requires us to mark RAM as NOHUGEPAGE prior to discard
|
* Userfault requires us to mark RAM as NOHUGEPAGE prior to discard
|
||||||
* however leaving it until after precopy means that most of the precopy
|
* however leaving it until after precopy means that most of the precopy
|
||||||
|
|
|
@ -200,27 +200,6 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* postcopy_ram_discard_range: Discard a range of memory.
|
|
||||||
* We can assume that if we've been called postcopy_ram_hosttest returned true.
|
|
||||||
*
|
|
||||||
* @mis: Current incoming migration state.
|
|
||||||
* @start, @length: range of memory to discard.
|
|
||||||
*
|
|
||||||
* returns: 0 on success.
|
|
||||||
*/
|
|
||||||
int postcopy_ram_discard_range(MigrationIncomingState *mis, uint8_t *start,
|
|
||||||
size_t length)
|
|
||||||
{
|
|
||||||
trace_postcopy_ram_discard_range(start, length);
|
|
||||||
if (madvise(start, length, MADV_DONTNEED)) {
|
|
||||||
error_report("%s MADV_DONTNEED: %s", __func__, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup an area of RAM so that it *can* be used for postcopy later; this
|
* Setup an area of RAM so that it *can* be used for postcopy later; this
|
||||||
* must be done right at the start prior to pre-copy.
|
* must be done right at the start prior to pre-copy.
|
||||||
|
@ -239,7 +218,7 @@ static int init_range(const char *block_name, void *host_addr,
|
||||||
* - we're going to get the copy from the source anyway.
|
* - we're going to get the copy from the source anyway.
|
||||||
* (Precopy will just overwrite this data, so doesn't need the discard)
|
* (Precopy will just overwrite this data, so doesn't need the discard)
|
||||||
*/
|
*/
|
||||||
if (postcopy_ram_discard_range(mis, host_addr, length)) {
|
if (ram_discard_range(mis, block_name, 0, length)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -658,13 +637,6 @@ int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int postcopy_ram_discard_range(MigrationIncomingState *mis, uint8_t *start,
|
|
||||||
size_t length)
|
|
||||||
{
|
|
||||||
assert(0);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int postcopy_ram_prepare_discard(MigrationIncomingState *mis)
|
int postcopy_ram_prepare_discard(MigrationIncomingState *mis)
|
||||||
{
|
{
|
||||||
assert(0);
|
assert(0);
|
||||||
|
|
|
@ -1890,6 +1890,8 @@ int ram_discard_range(MigrationIncomingState *mis,
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
|
trace_ram_discard_range(block_name, start, length);
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
RAMBlock *rb = qemu_ram_block_by_name(block_name);
|
RAMBlock *rb = qemu_ram_block_by_name(block_name);
|
||||||
|
|
||||||
|
@ -1899,27 +1901,7 @@ int ram_discard_range(MigrationIncomingState *mis,
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *host_startaddr = rb->host + start;
|
ret = ram_block_discard_range(rb, start, length);
|
||||||
|
|
||||||
if ((uintptr_t)host_startaddr & (qemu_host_page_size - 1)) {
|
|
||||||
error_report("ram_discard_range: Unaligned start address: %p",
|
|
||||||
host_startaddr);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((start + length) <= rb->used_length) {
|
|
||||||
uint8_t *host_endaddr = host_startaddr + length;
|
|
||||||
if ((uintptr_t)host_endaddr & (qemu_host_page_size - 1)) {
|
|
||||||
error_report("ram_discard_range: Unaligned end address: %p",
|
|
||||||
host_endaddr);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
ret = postcopy_ram_discard_range(mis, host_startaddr, length);
|
|
||||||
} else {
|
|
||||||
error_report("ram_discard_range: Overrun block '%s' (%" PRIu64
|
|
||||||
"/%zx/" RAM_ADDR_FMT")",
|
|
||||||
block_name, start, length, rb->used_length);
|
|
||||||
}
|
|
||||||
|
|
||||||
err:
|
err:
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
|
@ -68,6 +68,7 @@ get_queued_page_not_dirty(const char *block_name, uint64_t tmp_offset, uint64_t
|
||||||
migration_bitmap_sync_start(void) ""
|
migration_bitmap_sync_start(void) ""
|
||||||
migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64
|
migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64
|
||||||
migration_throttle(void) ""
|
migration_throttle(void) ""
|
||||||
|
ram_discard_range(const char *rbname, uint64_t start, size_t len) "%s: start: %" PRIx64 " %zx"
|
||||||
ram_load_postcopy_loop(uint64_t addr, int flags) "@%" PRIx64 " %x"
|
ram_load_postcopy_loop(uint64_t addr, int flags) "@%" PRIx64 " %x"
|
||||||
ram_postcopy_send_discard_bitmap(void) ""
|
ram_postcopy_send_discard_bitmap(void) ""
|
||||||
ram_save_queue_pages(const char *rbname, size_t start, size_t len) "%s: start: %zx len: %zx"
|
ram_save_queue_pages(const char *rbname, size_t start, size_t len) "%s: start: %zx len: %zx"
|
||||||
|
@ -176,7 +177,6 @@ rdma_start_outgoing_migration_after_rdma_source_init(void) ""
|
||||||
# migration/postcopy-ram.c
|
# migration/postcopy-ram.c
|
||||||
postcopy_discard_send_finish(const char *ramblock, int nwords, int ncmds) "%s mask words sent=%d in %d commands"
|
postcopy_discard_send_finish(const char *ramblock, int nwords, int ncmds) "%s mask words sent=%d in %d commands"
|
||||||
postcopy_discard_send_range(const char *ramblock, unsigned long start, unsigned long length) "%s:%lx/%lx"
|
postcopy_discard_send_range(const char *ramblock, unsigned long start, unsigned long length) "%s:%lx/%lx"
|
||||||
postcopy_ram_discard_range(void *start, size_t length) "%p,+%zx"
|
|
||||||
postcopy_cleanup_range(const char *ramblock, void *host_addr, size_t offset, size_t length) "%s: %p offset=%zx length=%zx"
|
postcopy_cleanup_range(const char *ramblock, void *host_addr, size_t offset, size_t length) "%s: %p offset=%zx length=%zx"
|
||||||
postcopy_init_range(const char *ramblock, void *host_addr, size_t offset, size_t length) "%s: %p offset=%zx length=%zx"
|
postcopy_init_range(const char *ramblock, void *host_addr, size_t offset, size_t length) "%s: %p offset=%zx length=%zx"
|
||||||
postcopy_nhp_range(const char *ramblock, void *host_addr, size_t offset, size_t length) "%s: %p offset=%zx length=%zx"
|
postcopy_nhp_range(const char *ramblock, void *host_addr, size_t offset, size_t length) "%s: %p offset=%zx length=%zx"
|
||||||
|
|
Loading…
Reference in New Issue