hw/virtio/vhost: re-factor vhost-section and allow DIRTY_MEMORY_CODE
The purpose of vhost_section is to identify RAM regions that need to be made available to a vhost client. However when running under TCG all RAM sections have DIRTY_MEMORY_CODE set which leads to problems down the line. Re-factor the code so: - steps are clearer to follow - reason for rejection is recorded in the trace point - we allow DIRTY_MEMORY_CODE We expand the comment to explain that kernel based vhost has specific support for migration tracking. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Tested-by: Fabiano Rosas <farosas@linux.ibm.com> Cc: Michael S. Tsirkin <mst@redhat.com> Cc: Dr. David Alan Gilbert <dgilbert@redhat.com> Cc: Stefan Hajnoczi <stefanha@redhat.com> Message-Id: <20200605154929.26910-11-alex.bennee@linaro.org>
This commit is contained in:
parent
a97098844b
commit
083b9bd7a1
|
@ -5,7 +5,8 @@ vhost_commit(bool started, bool changed) "Started: %d Changed: %d"
|
||||||
vhost_region_add_section(const char *name, uint64_t gpa, uint64_t size, uint64_t host) "%s: 0x%"PRIx64"+0x%"PRIx64" @ 0x%"PRIx64
|
vhost_region_add_section(const char *name, uint64_t gpa, uint64_t size, uint64_t host) "%s: 0x%"PRIx64"+0x%"PRIx64" @ 0x%"PRIx64
|
||||||
vhost_region_add_section_merge(const char *name, uint64_t new_size, uint64_t gpa, uint64_t owr) "%s: size: 0x%"PRIx64 " gpa: 0x%"PRIx64 " owr: 0x%"PRIx64
|
vhost_region_add_section_merge(const char *name, uint64_t new_size, uint64_t gpa, uint64_t owr) "%s: size: 0x%"PRIx64 " gpa: 0x%"PRIx64 " owr: 0x%"PRIx64
|
||||||
vhost_region_add_section_aligned(const char *name, uint64_t gpa, uint64_t size, uint64_t host) "%s: 0x%"PRIx64"+0x%"PRIx64" @ 0x%"PRIx64
|
vhost_region_add_section_aligned(const char *name, uint64_t gpa, uint64_t size, uint64_t host) "%s: 0x%"PRIx64"+0x%"PRIx64" @ 0x%"PRIx64
|
||||||
vhost_section(const char *name, int r) "%s:%d"
|
vhost_section(const char *name) "%s"
|
||||||
|
vhost_reject_section(const char *name, int d) "%s:%d"
|
||||||
vhost_iotlb_miss(void *dev, int step) "%p step %d"
|
vhost_iotlb_miss(void *dev, int step) "%p step %d"
|
||||||
|
|
||||||
# vhost-user.c
|
# vhost-user.c
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "migration/blocker.h"
|
#include "migration/blocker.h"
|
||||||
#include "migration/qemu-file-types.h"
|
#include "migration/qemu-file-types.h"
|
||||||
#include "sysemu/dma.h"
|
#include "sysemu/dma.h"
|
||||||
|
#include "sysemu/tcg.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
/* enabled until disconnected backend stabilizes */
|
/* enabled until disconnected backend stabilizes */
|
||||||
|
@ -403,26 +404,50 @@ static int vhost_verify_ring_mappings(struct vhost_dev *dev,
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* vhost_section: identify sections needed for vhost access
|
||||||
|
*
|
||||||
|
* We only care about RAM sections here (where virtqueue and guest
|
||||||
|
* internals accessed by virtio might live). If we find one we still
|
||||||
|
* allow the backend to potentially filter it out of our list.
|
||||||
|
*/
|
||||||
static bool vhost_section(struct vhost_dev *dev, MemoryRegionSection *section)
|
static bool vhost_section(struct vhost_dev *dev, MemoryRegionSection *section)
|
||||||
{
|
{
|
||||||
bool result;
|
MemoryRegion *mr = section->mr;
|
||||||
bool log_dirty = memory_region_get_dirty_log_mask(section->mr) &
|
|
||||||
~(1 << DIRTY_MEMORY_MIGRATION);
|
|
||||||
result = memory_region_is_ram(section->mr) &&
|
|
||||||
!memory_region_is_rom(section->mr);
|
|
||||||
|
|
||||||
/* Vhost doesn't handle any block which is doing dirty-tracking other
|
if (memory_region_is_ram(mr) && !memory_region_is_rom(mr)) {
|
||||||
* than migration; this typically fires on VGA areas.
|
uint8_t dirty_mask = memory_region_get_dirty_log_mask(mr);
|
||||||
|
uint8_t handled_dirty;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Kernel based vhost doesn't handle any block which is doing
|
||||||
|
* dirty-tracking other than migration for which it has
|
||||||
|
* specific logging support. However for TCG the kernel never
|
||||||
|
* gets involved anyway so we can also ignore it's
|
||||||
|
* self-modiying code detection flags. However a vhost-user
|
||||||
|
* client could still confuse a TCG guest if it re-writes
|
||||||
|
* executable memory that has already been translated.
|
||||||
*/
|
*/
|
||||||
result &= !log_dirty;
|
handled_dirty = (1 << DIRTY_MEMORY_MIGRATION) |
|
||||||
|
(1 << DIRTY_MEMORY_CODE);
|
||||||
|
|
||||||
if (result && dev->vhost_ops->vhost_backend_mem_section_filter) {
|
if (dirty_mask & ~handled_dirty) {
|
||||||
result &=
|
trace_vhost_reject_section(mr->name, 1);
|
||||||
dev->vhost_ops->vhost_backend_mem_section_filter(dev, section);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
trace_vhost_section(section->mr->name, result);
|
if (dev->vhost_ops->vhost_backend_mem_section_filter &&
|
||||||
return result;
|
!dev->vhost_ops->vhost_backend_mem_section_filter(dev, section)) {
|
||||||
|
trace_vhost_reject_section(mr->name, 2);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
trace_vhost_section(mr->name);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
trace_vhost_reject_section(mr->name, 3);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vhost_begin(MemoryListener *listener)
|
static void vhost_begin(MemoryListener *listener)
|
||||||
|
|
Loading…
Reference in a new issue