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:
parent
881d588a98
commit
af60314291
|
@ -382,8 +382,6 @@ static void vhost_set_memory(MemoryListener *listener,
|
||||||
bool log_dirty = memory_region_is_logging(section->mr);
|
bool log_dirty = memory_region_is_logging(section->mr);
|
||||||
int s = offsetof(struct vhost_memory, regions) +
|
int s = offsetof(struct vhost_memory, regions) +
|
||||||
(dev->mem->nregions + 1) * sizeof dev->mem->regions[0];
|
(dev->mem->nregions + 1) * sizeof dev->mem->regions[0];
|
||||||
uint64_t log_size;
|
|
||||||
int r;
|
|
||||||
void *ram;
|
void *ram;
|
||||||
|
|
||||||
dev->mem = g_realloc(dev->mem, s);
|
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. */
|
/* Remove old mapping for this memory, if any. */
|
||||||
vhost_dev_unassign_memory(dev, start_addr, size);
|
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) {
|
if (!dev->started) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (dev->mem_changed_start_addr > dev->mem_changed_end_addr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (dev->started) {
|
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);
|
r = vhost_verify_ring_mappings(dev, start_addr, size);
|
||||||
assert(r >= 0);
|
assert(r >= 0);
|
||||||
}
|
}
|
||||||
|
@ -429,6 +462,7 @@ static void vhost_set_memory(MemoryListener *listener,
|
||||||
if (!dev->log_enabled) {
|
if (!dev->log_enabled) {
|
||||||
r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
|
r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
|
||||||
assert(r >= 0);
|
assert(r >= 0);
|
||||||
|
dev->memory_changed = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log_size = vhost_get_log_size(dev);
|
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) {
|
if (dev->log_size > log_size + VHOST_LOG_BUFFER) {
|
||||||
vhost_dev_log_resize(dev, log_size);
|
vhost_dev_log_resize(dev, log_size);
|
||||||
}
|
}
|
||||||
}
|
dev->memory_changed = false;
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vhost_region_add(MemoryListener *listener,
|
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_size = 0;
|
||||||
hdev->log_enabled = false;
|
hdev->log_enabled = false;
|
||||||
hdev->started = false;
|
hdev->started = false;
|
||||||
|
hdev->memory_changed = false;
|
||||||
memory_listener_register(&hdev->memory_listener, &address_space_memory);
|
memory_listener_register(&hdev->memory_listener, &address_space_memory);
|
||||||
hdev->force = force;
|
hdev->force = force;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -45,6 +45,9 @@ struct vhost_dev {
|
||||||
vhost_log_chunk_t *log;
|
vhost_log_chunk_t *log;
|
||||||
unsigned long long log_size;
|
unsigned long long log_size;
|
||||||
bool force;
|
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,
|
int vhost_dev_init(struct vhost_dev *hdev, int devfd, const char *devpath,
|
||||||
|
|
Loading…
Reference in a new issue