xen/hvm: correct reporting of modified memory under physmap during migration

When global_log_dirty is enabled VRAM modification tracking never
worked correctly. The address that is passed to xen_hvm_modified_memory()
is not the effective PFN but RAM block address which is not the same
for VRAM.

We need to make a translation for this address into PFN using
physmap. Since there is no way to access physmap properly inside
xen_hvm_modified_memory() let's make it a global structure.

Signed-off-by: Igor Druzhinin <igor.druzhinin@citrix.com>
Acked-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
master
Igor Druzhinin 2018-04-25 14:46:47 +01:00 committed by Stefano Stabellini
parent c181ddaa17
commit 04a8f72e87
3 changed files with 22 additions and 22 deletions

View File

@ -86,6 +86,8 @@ typedef struct XenPhysmap {
QLIST_ENTRY(XenPhysmap) list; QLIST_ENTRY(XenPhysmap) list;
} XenPhysmap; } XenPhysmap;
static QLIST_HEAD(, XenPhysmap) xen_physmap;
typedef struct XenIOState { typedef struct XenIOState {
ioservid_t ioservid; ioservid_t ioservid;
shared_iopage_t *shared_page; shared_iopage_t *shared_page;
@ -107,7 +109,6 @@ typedef struct XenIOState {
MemoryListener memory_listener; MemoryListener memory_listener;
MemoryListener io_listener; MemoryListener io_listener;
DeviceListener device_listener; DeviceListener device_listener;
QLIST_HEAD(, XenPhysmap) physmap;
hwaddr free_phys_offset; hwaddr free_phys_offset;
const XenPhysmap *log_for_dirtybit; const XenPhysmap *log_for_dirtybit;
@ -274,14 +275,13 @@ void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, MemoryRegion *mr,
g_free(pfn_list); g_free(pfn_list);
} }
static XenPhysmap *get_physmapping(XenIOState *state, static XenPhysmap *get_physmapping(hwaddr start_addr, ram_addr_t size)
hwaddr start_addr, ram_addr_t size)
{ {
XenPhysmap *physmap = NULL; XenPhysmap *physmap = NULL;
start_addr &= TARGET_PAGE_MASK; start_addr &= TARGET_PAGE_MASK;
QLIST_FOREACH(physmap, &state->physmap, list) { QLIST_FOREACH(physmap, &xen_physmap, list) {
if (range_covers_byte(physmap->start_addr, physmap->size, start_addr)) { if (range_covers_byte(physmap->start_addr, physmap->size, start_addr)) {
return physmap; return physmap;
} }
@ -289,23 +289,21 @@ static XenPhysmap *get_physmapping(XenIOState *state,
return NULL; return NULL;
} }
#ifdef XEN_COMPAT_PHYSMAP static hwaddr xen_phys_offset_to_gaddr(hwaddr phys_offset, ram_addr_t size)
static hwaddr xen_phys_offset_to_gaddr(hwaddr start_addr,
ram_addr_t size, void *opaque)
{ {
hwaddr addr = start_addr & TARGET_PAGE_MASK; hwaddr addr = phys_offset & TARGET_PAGE_MASK;
XenIOState *xen_io_state = opaque;
XenPhysmap *physmap = NULL; XenPhysmap *physmap = NULL;
QLIST_FOREACH(physmap, &xen_io_state->physmap, list) { QLIST_FOREACH(physmap, &xen_physmap, list) {
if (range_covers_byte(physmap->phys_offset, physmap->size, addr)) { if (range_covers_byte(physmap->phys_offset, physmap->size, addr)) {
return physmap->start_addr; return physmap->start_addr + (phys_offset - physmap->phys_offset);
} }
} }
return start_addr; return phys_offset;
} }
#ifdef XEN_COMPAT_PHYSMAP
static int xen_save_physmap(XenIOState *state, XenPhysmap *physmap) static int xen_save_physmap(XenIOState *state, XenPhysmap *physmap)
{ {
char path[80], value[17]; char path[80], value[17];
@ -355,7 +353,7 @@ static int xen_add_to_physmap(XenIOState *state,
hwaddr phys_offset = memory_region_get_ram_addr(mr); hwaddr phys_offset = memory_region_get_ram_addr(mr);
const char *mr_name; const char *mr_name;
if (get_physmapping(state, start_addr, size)) { if (get_physmapping(start_addr, size)) {
return 0; return 0;
} }
if (size <= 0) { if (size <= 0) {
@ -384,7 +382,7 @@ go_physmap:
physmap->name = mr_name; physmap->name = mr_name;
physmap->phys_offset = phys_offset; physmap->phys_offset = phys_offset;
QLIST_INSERT_HEAD(&state->physmap, physmap, list); QLIST_INSERT_HEAD(&xen_physmap, physmap, list);
if (runstate_check(RUN_STATE_INMIGRATE)) { if (runstate_check(RUN_STATE_INMIGRATE)) {
/* Now when we have a physmap entry we can replace a dummy mapping with /* Now when we have a physmap entry we can replace a dummy mapping with
@ -428,7 +426,7 @@ static int xen_remove_from_physmap(XenIOState *state,
XenPhysmap *physmap = NULL; XenPhysmap *physmap = NULL;
hwaddr phys_offset = 0; hwaddr phys_offset = 0;
physmap = get_physmapping(state, start_addr, size); physmap = get_physmapping(start_addr, size);
if (physmap == NULL) { if (physmap == NULL) {
return -1; return -1;
} }
@ -597,7 +595,7 @@ static void xen_sync_dirty_bitmap(XenIOState *state,
int rc, i, j; int rc, i, j;
const XenPhysmap *physmap = NULL; const XenPhysmap *physmap = NULL;
physmap = get_physmapping(state, start_addr, size); physmap = get_physmapping(start_addr, size);
if (physmap == NULL) { if (physmap == NULL) {
/* not handled */ /* not handled */
return; return;
@ -1222,7 +1220,7 @@ static void xen_read_physmap(XenIOState *state)
xen_domid, entries[i]); xen_domid, entries[i]);
physmap->name = xs_read(state->xenstore, 0, path, &len); physmap->name = xs_read(state->xenstore, 0, path, &len);
QLIST_INSERT_HEAD(&state->physmap, physmap, list); QLIST_INSERT_HEAD(&xen_physmap, physmap, list);
} }
free(entries); free(entries);
} }
@ -1374,7 +1372,6 @@ void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory)
qemu_add_vm_change_state_handler(xen_hvm_change_state_handler, state); qemu_add_vm_change_state_handler(xen_hvm_change_state_handler, state);
state->memory_listener = xen_memory_listener; state->memory_listener = xen_memory_listener;
QLIST_INIT(&state->physmap);
memory_listener_register(&state->memory_listener, &address_space_memory); memory_listener_register(&state->memory_listener, &address_space_memory);
state->log_for_dirtybit = NULL; state->log_for_dirtybit = NULL;
@ -1390,6 +1387,8 @@ void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory)
goto err; goto err;
} }
xen_be_register_common(); xen_be_register_common();
QLIST_INIT(&xen_physmap);
xen_read_physmap(state); xen_read_physmap(state);
/* Disable ACPI build because Xen handles it */ /* Disable ACPI build because Xen handles it */
@ -1461,6 +1460,8 @@ void xen_hvm_modified_memory(ram_addr_t start, ram_addr_t length)
int rc; int rc;
ram_addr_t start_pfn, nb_pages; ram_addr_t start_pfn, nb_pages;
start = xen_phys_offset_to_gaddr(start, length);
if (length == 0) { if (length == 0) {
length = TARGET_PAGE_SIZE; length = TARGET_PAGE_SIZE;
} }

View File

@ -319,7 +319,7 @@ tryagain:
mapcache->last_entry = NULL; mapcache->last_entry = NULL;
#ifdef XEN_COMPAT_PHYSMAP #ifdef XEN_COMPAT_PHYSMAP
if (!translated && mapcache->phys_offset_to_gaddr) { if (!translated && mapcache->phys_offset_to_gaddr) {
phys_addr = mapcache->phys_offset_to_gaddr(phys_addr, size, mapcache->opaque); phys_addr = mapcache->phys_offset_to_gaddr(phys_addr, size);
translated = true; translated = true;
goto tryagain; goto tryagain;
} }

View File

@ -9,9 +9,8 @@
#ifndef XEN_MAPCACHE_H #ifndef XEN_MAPCACHE_H
#define XEN_MAPCACHE_H #define XEN_MAPCACHE_H
typedef hwaddr (*phys_offset_to_gaddr_t)(hwaddr start_addr, typedef hwaddr (*phys_offset_to_gaddr_t)(hwaddr phys_offset,
ram_addr_t size, ram_addr_t size);
void *opaque);
#ifdef CONFIG_XEN #ifdef CONFIG_XEN
void xen_map_cache_init(phys_offset_to_gaddr_t f, void xen_map_cache_init(phys_offset_to_gaddr_t f,