vhost: Add vhost_commit callback for SeaBIOS ROM region re-mapping

This patch follows MST's recommendation to move checks for
vhost_verify_ring_mappings() -> cpu_physical_memory_map() operations
from MemoryListener->region_[add,del]() -> vhost_set_memory() into
final MemoryListener->commit() -> vhost_commit() callback.

It addresses the case where virtio-scsi vq ioport RAM re-mapping
to read-only SeaBIOS ROM triggers a cpu_physical_memory_map()
NIL MemoryRegionSection pointer failure.

Also save vhost_dev->mem_changed_[start,end]_addr values in
vhost_set_memory() for final ranges_overlap checks.  (Thanks Paolo!)

Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Asias He <asias@redhat.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Nicholas Bellinger 2013-04-03 09:15:11 +00:00 committed by Paolo Bonzini
parent 881d588a98
commit af60314291
2 changed files with 41 additions and 15 deletions

View file

@ -382,8 +382,6 @@ static void vhost_set_memory(MemoryListener *listener,
bool log_dirty = memory_region_is_logging(section->mr);
int s = offsetof(struct vhost_memory, regions) +
(dev->mem->nregions + 1) * sizeof dev->mem->regions[0];
uint64_t log_size;
int r;
void *ram;
dev->mem = g_realloc(dev->mem, s);
@ -416,12 +414,47 @@ static void vhost_set_memory(MemoryListener *listener,
/* Remove old mapping for this memory, if any. */
vhost_dev_unassign_memory(dev, start_addr, size);
}
dev->mem_changed_start_addr = MIN(dev->mem_changed_start_addr, start_addr);
dev->mem_changed_end_addr = MAX(dev->mem_changed_end_addr, start_addr + size - 1);
dev->memory_changed = true;
}
static bool vhost_section(MemoryRegionSection *section)
{
return memory_region_is_ram(section->mr);
}
static void vhost_begin(MemoryListener *listener)
{
struct vhost_dev *dev = container_of(listener, struct vhost_dev,
memory_listener);
dev->mem_changed_end_addr = 0;
dev->mem_changed_start_addr = -1;
}
static void vhost_commit(MemoryListener *listener)
{
struct vhost_dev *dev = container_of(listener, struct vhost_dev,
memory_listener);
hwaddr start_addr = 0;
ram_addr_t size = 0;
uint64_t log_size;
int r;
if (!dev->memory_changed) {
return;
}
if (!dev->started) {
return;
}
if (dev->mem_changed_start_addr > dev->mem_changed_end_addr) {
return;
}
if (dev->started) {
start_addr = dev->mem_changed_start_addr;
size = dev->mem_changed_end_addr - dev->mem_changed_start_addr + 1;
r = vhost_verify_ring_mappings(dev, start_addr, size);
assert(r >= 0);
}
@ -429,6 +462,7 @@ static void vhost_set_memory(MemoryListener *listener,
if (!dev->log_enabled) {
r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
assert(r >= 0);
dev->memory_changed = false;
return;
}
log_size = vhost_get_log_size(dev);
@ -445,19 +479,7 @@ static void vhost_set_memory(MemoryListener *listener,
if (dev->log_size > log_size + VHOST_LOG_BUFFER) {
vhost_dev_log_resize(dev, log_size);
}
}
static bool vhost_section(MemoryRegionSection *section)
{
return memory_region_is_ram(section->mr);
}
static void vhost_begin(MemoryListener *listener)
{
}
static void vhost_commit(MemoryListener *listener)
{
dev->memory_changed = false;
}
static void vhost_region_add(MemoryListener *listener,
@ -842,6 +864,7 @@ int vhost_dev_init(struct vhost_dev *hdev, int devfd, const char *devpath,
hdev->log_size = 0;
hdev->log_enabled = false;
hdev->started = false;
hdev->memory_changed = false;
memory_listener_register(&hdev->memory_listener, &address_space_memory);
hdev->force = force;
return 0;

View file

@ -45,6 +45,9 @@ struct vhost_dev {
vhost_log_chunk_t *log;
unsigned long long log_size;
bool force;
bool memory_changed;
hwaddr mem_changed_start_addr;
hwaddr mem_changed_end_addr;
};
int vhost_dev_init(struct vhost_dev *hdev, int devfd, const char *devpath,