vhost: Huge page align and merge

Align RAMBlocks to page size alignment, and adjust the merging code
to deal with partial overlap due to that alignment.

This is needed for postcopy so that we can place/fetch whole hugepages
when under userfault.

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Dr. David Alan Gilbert 2018-03-12 17:21:21 +00:00 committed by Michael S. Tsirkin
parent 46343570c0
commit c1ece84e7c
2 changed files with 58 additions and 11 deletions

View File

@ -3,7 +3,8 @@
# hw/virtio/vhost.c # hw/virtio/vhost.c
vhost_commit(bool started, bool changed) "Started: %d Changed: %d" 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_abut(const char *name, uint64_t new_size) "%s: 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_section(const char *name, int r) "%s:%d" vhost_section(const char *name, int r) "%s:%d"
# hw/virtio/vhost-user.c # hw/virtio/vhost-user.c

View File

@ -522,10 +522,28 @@ static void vhost_region_add_section(struct vhost_dev *dev,
uint64_t mrs_gpa = section->offset_within_address_space; uint64_t mrs_gpa = section->offset_within_address_space;
uintptr_t mrs_host = (uintptr_t)memory_region_get_ram_ptr(section->mr) + uintptr_t mrs_host = (uintptr_t)memory_region_get_ram_ptr(section->mr) +
section->offset_within_region; section->offset_within_region;
RAMBlock *mrs_rb = section->mr->ram_block;
size_t mrs_page = qemu_ram_pagesize(mrs_rb);
trace_vhost_region_add_section(section->mr->name, mrs_gpa, mrs_size, trace_vhost_region_add_section(section->mr->name, mrs_gpa, mrs_size,
mrs_host); mrs_host);
/* Round the section to it's page size */
/* First align the start down to a page boundary */
uint64_t alignage = mrs_host & (mrs_page - 1);
if (alignage) {
mrs_host -= alignage;
mrs_size += alignage;
mrs_gpa -= alignage;
}
/* Now align the size up to a page boundary */
alignage = mrs_size & (mrs_page - 1);
if (alignage) {
mrs_size += mrs_page - alignage;
}
trace_vhost_region_add_section_aligned(section->mr->name, mrs_gpa, mrs_size,
mrs_host);
if (dev->n_tmp_sections) { if (dev->n_tmp_sections) {
/* Since we already have at least one section, lets see if /* Since we already have at least one section, lets see if
* this extends it; since we're scanning in order, we only * this extends it; since we're scanning in order, we only
@ -542,18 +560,46 @@ static void vhost_region_add_section(struct vhost_dev *dev,
prev_sec->offset_within_region; prev_sec->offset_within_region;
uint64_t prev_host_end = range_get_last(prev_host_start, prev_size); uint64_t prev_host_end = range_get_last(prev_host_start, prev_size);
if (prev_gpa_end + 1 == mrs_gpa && if (mrs_gpa <= (prev_gpa_end + 1)) {
prev_host_end + 1 == mrs_host && /* OK, looks like overlapping/intersecting - it's possible that
* the rounding to page sizes has made them overlap, but they should
* match up in the same RAMBlock if they do.
*/
if (mrs_gpa < prev_gpa_start) {
error_report("%s:Section rounded to %"PRIx64
" prior to previous %"PRIx64,
__func__, mrs_gpa, prev_gpa_start);
/* A way to cleanly fail here would be better */
return;
}
/* Offset from the start of the previous GPA to this GPA */
size_t offset = mrs_gpa - prev_gpa_start;
if (prev_host_start + offset == mrs_host &&
section->mr == prev_sec->mr && section->mr == prev_sec->mr &&
(!dev->vhost_ops->vhost_backend_can_merge || (!dev->vhost_ops->vhost_backend_can_merge ||
dev->vhost_ops->vhost_backend_can_merge(dev, dev->vhost_ops->vhost_backend_can_merge(dev,
mrs_host, mrs_size, mrs_host, mrs_size,
prev_host_start, prev_size))) { prev_host_start, prev_size))) {
/* The two sections abut */ uint64_t max_end = MAX(prev_host_end, mrs_host + mrs_size);
need_add = false; need_add = false;
prev_sec->size = int128_add(prev_sec->size, section->size); prev_sec->offset_within_address_space =
trace_vhost_region_add_section_abut(section->mr->name, MIN(prev_gpa_start, mrs_gpa);
mrs_size + prev_size); prev_sec->offset_within_region =
MIN(prev_host_start, mrs_host) -
(uintptr_t)memory_region_get_ram_ptr(prev_sec->mr);
prev_sec->size = int128_make64(max_end - MIN(prev_host_start,
mrs_host));
trace_vhost_region_add_section_merge(section->mr->name,
int128_get64(prev_sec->size),
prev_sec->offset_within_address_space,
prev_sec->offset_within_region);
} else {
error_report("%s: Overlapping but not coherent sections "
"at %"PRIx64,
__func__, mrs_gpa);
return;
}
} }
} }