qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

kvm: 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 board 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 <imammedo@redhat.com>
Message-Id: <20190924144751.24149-4-imammedo@redhat.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Acked-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>

authored by

Igor Mammedov and committed by
Christian Borntraeger
023ae9a8 84516e5b

+80 -43
+79 -43
accel/kvm/kvm-all.c
··· 140 140 bool kvm_ioeventfd_any_length_allowed; 141 141 bool kvm_msi_use_devid; 142 142 static bool kvm_immediate_exit; 143 + static hwaddr kvm_max_slot_size = ~0; 143 144 144 145 static const KVMCapabilityInfo kvm_required_capabilites[] = { 145 146 KVM_CAP_INFO(USER_MEMORY), ··· 437 438 static int kvm_section_update_flags(KVMMemoryListener *kml, 438 439 MemoryRegionSection *section) 439 440 { 440 - hwaddr start_addr, size; 441 + hwaddr start_addr, size, slot_size; 441 442 KVMSlot *mem; 442 443 int ret = 0; 443 444 ··· 448 449 449 450 kvm_slots_lock(kml); 450 451 451 - mem = kvm_lookup_matching_slot(kml, start_addr, size); 452 - if (!mem) { 453 - /* We don't have a slot if we want to trap every access. */ 454 - goto out; 452 + while (size && !ret) { 453 + slot_size = MIN(kvm_max_slot_size, size); 454 + mem = kvm_lookup_matching_slot(kml, start_addr, slot_size); 455 + if (!mem) { 456 + /* We don't have a slot if we want to trap every access. */ 457 + goto out; 458 + } 459 + 460 + ret = kvm_slot_update_flags(kml, mem, section->mr); 461 + start_addr += slot_size; 462 + size -= slot_size; 455 463 } 456 - 457 - ret = kvm_slot_update_flags(kml, mem, section->mr); 458 464 459 465 out: 460 466 kvm_slots_unlock(kml); ··· 527 533 struct kvm_dirty_log d = {}; 528 534 KVMSlot *mem; 529 535 hwaddr start_addr, size; 536 + hwaddr slot_size, slot_offset = 0; 530 537 int ret = 0; 531 538 532 539 size = kvm_align_section(section, &start_addr); 533 - if (size) { 534 - mem = kvm_lookup_matching_slot(kml, start_addr, size); 540 + while (size) { 541 + MemoryRegionSection subsection = *section; 542 + 543 + slot_size = MIN(kvm_max_slot_size, size); 544 + mem = kvm_lookup_matching_slot(kml, start_addr, slot_size); 535 545 if (!mem) { 536 546 /* We don't have a slot if we want to trap every access. */ 537 547 goto out; ··· 549 559 * So for now, let's align to 64 instead of HOST_LONG_BITS here, in 550 560 * a hope that sizeof(long) won't become >8 any time soon. 551 561 */ 552 - size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS), 553 - /*HOST_LONG_BITS*/ 64) / 8; 554 562 if (!mem->dirty_bmap) { 563 + hwaddr bitmap_size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS), 564 + /*HOST_LONG_BITS*/ 64) / 8; 555 565 /* Allocate on the first log_sync, once and for all */ 556 - mem->dirty_bmap = g_malloc0(size); 566 + mem->dirty_bmap = g_malloc0(bitmap_size); 557 567 } 558 568 559 569 d.dirty_bitmap = mem->dirty_bmap; ··· 564 574 goto out; 565 575 } 566 576 567 - kvm_get_dirty_pages_log_range(section, d.dirty_bitmap); 577 + subsection.offset_within_region += slot_offset; 578 + subsection.size = int128_make64(slot_size); 579 + kvm_get_dirty_pages_log_range(&subsection, d.dirty_bitmap); 580 + 581 + slot_offset += slot_size; 582 + start_addr += slot_size; 583 + size -= slot_size; 568 584 } 569 585 out: 570 586 return ret; ··· 972 988 return NULL; 973 989 } 974 990 991 + void kvm_set_max_memslot_size(hwaddr max_slot_size) 992 + { 993 + g_assert( 994 + ROUND_UP(max_slot_size, qemu_real_host_page_size) == max_slot_size 995 + ); 996 + kvm_max_slot_size = max_slot_size; 997 + } 998 + 975 999 static void kvm_set_phys_mem(KVMMemoryListener *kml, 976 1000 MemoryRegionSection *section, bool add) 977 1001 { ··· 979 1003 int err; 980 1004 MemoryRegion *mr = section->mr; 981 1005 bool writeable = !mr->readonly && !mr->rom_device; 982 - hwaddr start_addr, size; 1006 + hwaddr start_addr, size, slot_size; 983 1007 void *ram; 984 1008 985 1009 if (!memory_region_is_ram(mr)) { ··· 1004 1028 kvm_slots_lock(kml); 1005 1029 1006 1030 if (!add) { 1007 - mem = kvm_lookup_matching_slot(kml, start_addr, size); 1008 - if (!mem) { 1009 - goto out; 1010 - } 1011 - if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) { 1012 - kvm_physical_sync_dirty_bitmap(kml, section); 1013 - } 1031 + do { 1032 + slot_size = MIN(kvm_max_slot_size, size); 1033 + mem = kvm_lookup_matching_slot(kml, start_addr, slot_size); 1034 + if (!mem) { 1035 + goto out; 1036 + } 1037 + if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) { 1038 + kvm_physical_sync_dirty_bitmap(kml, section); 1039 + } 1014 1040 1015 - /* unregister the slot */ 1016 - g_free(mem->dirty_bmap); 1017 - mem->dirty_bmap = NULL; 1018 - mem->memory_size = 0; 1019 - mem->flags = 0; 1020 - err = kvm_set_user_memory_region(kml, mem, false); 1021 - if (err) { 1022 - fprintf(stderr, "%s: error unregistering slot: %s\n", 1023 - __func__, strerror(-err)); 1024 - abort(); 1025 - } 1041 + /* unregister the slot */ 1042 + g_free(mem->dirty_bmap); 1043 + mem->dirty_bmap = NULL; 1044 + mem->memory_size = 0; 1045 + mem->flags = 0; 1046 + err = kvm_set_user_memory_region(kml, mem, false); 1047 + if (err) { 1048 + fprintf(stderr, "%s: error unregistering slot: %s\n", 1049 + __func__, strerror(-err)); 1050 + abort(); 1051 + } 1052 + start_addr += slot_size; 1053 + size -= slot_size; 1054 + } while (size); 1026 1055 goto out; 1027 1056 } 1028 1057 1029 1058 /* register the new slot */ 1030 - mem = kvm_alloc_slot(kml); 1031 - mem->memory_size = size; 1032 - mem->start_addr = start_addr; 1033 - mem->ram = ram; 1034 - mem->flags = kvm_mem_flags(mr); 1059 + do { 1060 + slot_size = MIN(kvm_max_slot_size, size); 1061 + mem = kvm_alloc_slot(kml); 1062 + mem->memory_size = slot_size; 1063 + mem->start_addr = start_addr; 1064 + mem->ram = ram; 1065 + mem->flags = kvm_mem_flags(mr); 1035 1066 1036 - err = kvm_set_user_memory_region(kml, mem, true); 1037 - if (err) { 1038 - fprintf(stderr, "%s: error registering slot: %s\n", __func__, 1039 - strerror(-err)); 1040 - abort(); 1041 - } 1067 + err = kvm_set_user_memory_region(kml, mem, true); 1068 + if (err) { 1069 + fprintf(stderr, "%s: error registering slot: %s\n", __func__, 1070 + strerror(-err)); 1071 + abort(); 1072 + } 1073 + start_addr += slot_size; 1074 + ram += slot_size; 1075 + size -= slot_size; 1076 + } while (size); 1042 1077 1043 1078 out: 1044 1079 kvm_slots_unlock(kml); ··· 2878 2913 2879 2914 for (i = 0; i < kvm->nr_as; ++i) { 2880 2915 if (kvm->as[i].as == as && kvm->as[i].ml) { 2916 + size = MIN(kvm_max_slot_size, size); 2881 2917 return NULL != kvm_lookup_matching_slot(kvm->as[i].ml, 2882 2918 start_addr, size); 2883 2919 }
+1
include/sysemu/kvm_int.h
··· 41 41 void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml, 42 42 AddressSpace *as, int as_id); 43 43 44 + void kvm_set_max_memslot_size(hwaddr max_slot_size); 44 45 #endif