Re: [Qemu-devel] [PATCH for-4.2 v3 1/2] kvm: s390: split too big memory section on several memslots
On 02.08.19 15:32, Igor Mammedov wrote: > Max memslot size supported by kvm on s390 is 8Tb, > move logic of splitting RAM in chunks upto 8T to KVM code. > > This way it will hide KVM specific restrictions in KVM code > and won't affect baord level design decisions. Which would allow > us to avoid misusing memory_region_allocate_system_memory() API > and eventually use a single hostmem backend for guest RAM. > > Signed-off-by: Igor Mammedov > --- > patch prepares only KVM side for switching to single RAM memory region > another patch will take care of dropping manual RAM partitioning in > s390 code. > --- /home/cborntra/REPOS/qemu/target/s390x/kvm.c: In function ‘kvm_arch_init’: /home/cborntra/REPOS/qemu/target/s390x/kvm.c:350:5: error: implicit declaration of function ‘kvm_set_max_memslot_size’; did you mean ‘kvm_get_max_memslots’? [-Werror=implicit-function-declaration] 350 | kvm_set_max_memslot_size(KVM_SLOT_MAX_BYTES); | ^~~~ | kvm_get_max_memslots /home/cborntra/REPOS/qemu/target/s390x/kvm.c:350:5: error: nested extern declaration of ‘kvm_set_max_memslot_size’ [-Werror=nested-externs] cc1: all warnings being treated as errors make[1]: *** [/home/cborntra/REPOS/qemu/rules.mak:69: target/s390x/kvm.o] Error 1 make: *** [Makefile:472: s390x-softmmu/all] Error 2 We probably need an include of sysemu/kvm_int.h in target/s390x/kvm.c I will test with that fixup > include/hw/s390x/s390-virtio-ccw.h | 10 > include/sysemu/kvm_int.h | 1 + > accel/kvm/kvm-all.c| 79 ++ > hw/s390x/s390-virtio-ccw.c | 9 > target/s390x/kvm.c | 1 + > 5 files changed, 60 insertions(+), 40 deletions(-) > > diff --git a/include/hw/s390x/s390-virtio-ccw.h > b/include/hw/s390x/s390-virtio-ccw.h > index 8aa27199c9..00632f94b4 100644 > --- a/include/hw/s390x/s390-virtio-ccw.h > +++ b/include/hw/s390x/s390-virtio-ccw.h > @@ -21,6 +21,16 @@ > #define S390_MACHINE_CLASS(klass) \ > OBJECT_CLASS_CHECK(S390CcwMachineClass, (klass), TYPE_S390_CCW_MACHINE) > > +/* > + * KVM does only support memory slots up to KVM_MEM_MAX_NR_PAGES pages > + * as the dirty bitmap must be managed by bitops that take an int as > + * position indicator. If we have a guest beyond that we will split off > + * new subregions. The split must happen on a segment boundary (1MB). > + */ > +#define KVM_MEM_MAX_NR_PAGES ((1ULL << 31) - 1) > +#define SEG_MSK (~0xfULL) > +#define KVM_SLOT_MAX_BYTES ((KVM_MEM_MAX_NR_PAGES * TARGET_PAGE_SIZE) & > SEG_MSK) > + > typedef struct S390CcwMachineState { > /*< private >*/ > MachineState parent_obj; > diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h > index 31df465fdc..7f7520bce2 100644 > --- a/include/sysemu/kvm_int.h > +++ b/include/sysemu/kvm_int.h > @@ -41,4 +41,5 @@ typedef struct KVMMemoryListener { > void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml, >AddressSpace *as, int as_id); > > +void kvm_set_max_memslot_size(hwaddr max_slot_size); > #endif > diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c > index f450f25295..7a6efb9612 100644 > --- a/accel/kvm/kvm-all.c > +++ b/accel/kvm/kvm-all.c > @@ -138,6 +138,7 @@ bool kvm_direct_msi_allowed; > bool kvm_ioeventfd_any_length_allowed; > bool kvm_msi_use_devid; > static bool kvm_immediate_exit; > +static hwaddr kvm_max_slot_size = ~0; > > static const KVMCapabilityInfo kvm_required_capabilites[] = { > KVM_CAP_INFO(USER_MEMORY), > @@ -951,6 +952,14 @@ kvm_check_extension_list(KVMState *s, const > KVMCapabilityInfo *list) > return NULL; > } > > +void kvm_set_max_memslot_size(hwaddr max_slot_size) > +{ > +g_assert( > +ROUND_UP(max_slot_size, qemu_real_host_page_size) == max_slot_size > +); > +kvm_max_slot_size = max_slot_size; > +} > + > static void kvm_set_phys_mem(KVMMemoryListener *kml, > MemoryRegionSection *section, bool add) > { > @@ -958,7 +967,7 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml, > int err; > MemoryRegion *mr = section->mr; > bool writeable = !mr->readonly && !mr->rom_device; > -hwaddr start_addr, size; > +hwaddr start_addr, size, slot_size; > void *ram; > > if (!memory_region_is_ram(mr)) { > @@ -983,41 +992,49 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml, > kvm_slots_lock(kml); > > if (!add) { > -mem = kvm_lookup_matching_slot(kml, start_addr, size); > -if (!mem) { > -goto out; > -} > -if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) { > -kvm_physical_sync_dirty_bitmap(kml, section); > -} > +do { > +slot_size = kvm_max_slot_size < size ? kvm_max_slot_size : size; > +mem = kvm_lookup_matching_slot(kml, start_addr, slot_size); > +if (!mem) { > +goto out; > +
[Qemu-devel] [PATCH for-4.2 v3 1/2] kvm: s390: split too big memory section on several memslots
Max memslot size supported by kvm on s390 is 8Tb, move logic of splitting RAM in chunks upto 8T to KVM code. This way it will hide KVM specific restrictions in KVM code and won't affect baord level design decisions. Which would allow us to avoid misusing memory_region_allocate_system_memory() API and eventually use a single hostmem backend for guest RAM. Signed-off-by: Igor Mammedov --- patch prepares only KVM side for switching to single RAM memory region another patch will take care of dropping manual RAM partitioning in s390 code. --- include/hw/s390x/s390-virtio-ccw.h | 10 include/sysemu/kvm_int.h | 1 + accel/kvm/kvm-all.c| 79 ++ hw/s390x/s390-virtio-ccw.c | 9 target/s390x/kvm.c | 1 + 5 files changed, 60 insertions(+), 40 deletions(-) diff --git a/include/hw/s390x/s390-virtio-ccw.h b/include/hw/s390x/s390-virtio-ccw.h index 8aa27199c9..00632f94b4 100644 --- a/include/hw/s390x/s390-virtio-ccw.h +++ b/include/hw/s390x/s390-virtio-ccw.h @@ -21,6 +21,16 @@ #define S390_MACHINE_CLASS(klass) \ OBJECT_CLASS_CHECK(S390CcwMachineClass, (klass), TYPE_S390_CCW_MACHINE) +/* + * KVM does only support memory slots up to KVM_MEM_MAX_NR_PAGES pages + * as the dirty bitmap must be managed by bitops that take an int as + * position indicator. If we have a guest beyond that we will split off + * new subregions. The split must happen on a segment boundary (1MB). + */ +#define KVM_MEM_MAX_NR_PAGES ((1ULL << 31) - 1) +#define SEG_MSK (~0xfULL) +#define KVM_SLOT_MAX_BYTES ((KVM_MEM_MAX_NR_PAGES * TARGET_PAGE_SIZE) & SEG_MSK) + typedef struct S390CcwMachineState { /*< private >*/ MachineState parent_obj; diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h index 31df465fdc..7f7520bce2 100644 --- a/include/sysemu/kvm_int.h +++ b/include/sysemu/kvm_int.h @@ -41,4 +41,5 @@ typedef struct KVMMemoryListener { void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml, AddressSpace *as, int as_id); +void kvm_set_max_memslot_size(hwaddr max_slot_size); #endif diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index f450f25295..7a6efb9612 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -138,6 +138,7 @@ bool kvm_direct_msi_allowed; bool kvm_ioeventfd_any_length_allowed; bool kvm_msi_use_devid; static bool kvm_immediate_exit; +static hwaddr kvm_max_slot_size = ~0; static const KVMCapabilityInfo kvm_required_capabilites[] = { KVM_CAP_INFO(USER_MEMORY), @@ -951,6 +952,14 @@ kvm_check_extension_list(KVMState *s, const KVMCapabilityInfo *list) return NULL; } +void kvm_set_max_memslot_size(hwaddr max_slot_size) +{ +g_assert( +ROUND_UP(max_slot_size, qemu_real_host_page_size) == max_slot_size +); +kvm_max_slot_size = max_slot_size; +} + static void kvm_set_phys_mem(KVMMemoryListener *kml, MemoryRegionSection *section, bool add) { @@ -958,7 +967,7 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml, int err; MemoryRegion *mr = section->mr; bool writeable = !mr->readonly && !mr->rom_device; -hwaddr start_addr, size; +hwaddr start_addr, size, slot_size; void *ram; if (!memory_region_is_ram(mr)) { @@ -983,41 +992,49 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml, kvm_slots_lock(kml); if (!add) { -mem = kvm_lookup_matching_slot(kml, start_addr, size); -if (!mem) { -goto out; -} -if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) { -kvm_physical_sync_dirty_bitmap(kml, section); -} +do { +slot_size = kvm_max_slot_size < size ? kvm_max_slot_size : size; +mem = kvm_lookup_matching_slot(kml, start_addr, slot_size); +if (!mem) { +goto out; +} +if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) { +kvm_physical_sync_dirty_bitmap(kml, section); +} -/* unregister the slot */ -g_free(mem->dirty_bmap); -mem->dirty_bmap = NULL; -mem->memory_size = 0; -mem->flags = 0; -err = kvm_set_user_memory_region(kml, mem, false); -if (err) { -fprintf(stderr, "%s: error unregistering slot: %s\n", -__func__, strerror(-err)); -abort(); -} +/* unregister the slot */ +g_free(mem->dirty_bmap); +mem->dirty_bmap = NULL; +mem->memory_size = 0; +mem->flags = 0; +err = kvm_set_user_memory_region(kml, mem, false); +if (err) { +fprintf(stderr, "%s: error unregistering slot: %s\n", +__func__, strerror(-err)); +abort(); +} +start_addr += slot_size; +} while ((size -= slot_size)); goto out; } /* register