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

hostmem: fix strict bind policy

When option -mem-prealloc is used with one or more memory-backend
objects, created backends may not obey configured bind policy or
creation may fail after kernel attempts to move pages according
to bind policy.
Reason is in file_ram_alloc(), which will pre-allocate
any descriptor based RAM if global mem_prealloc != 0 and that
happens way before bind policy is applied to memory range.

One way to fix it would be to extend memory_region_foo() API
and add more invariants that could broken later due implicit
dependencies that's hard to track.

Another approach is to drop adhoc main RAM allocation and
consolidate it around memory-backend. That allows to have
single place that allocates guest RAM (main and memdev)
in the same way and then global mem_prealloc could be
replaced by backend's property[s] that will affect created
memory-backend objects but only in correct order this time.

With main RAM now converted to hostmem backends, there is no
point in keeping global mem_prealloc around, so alias
-mem-prealloc to "memory-backend.prealloc=on"
machine compat[*] property and make mem_prealloc a local
variable to only stir registration of compat property.

*) currently user accessible -global works only with DEVICE
based objects and extra work is needed to make it work
with hostmem backends. But that is convenience option
and out of scope of this already huge refactoring.
Hence machine compat properties were used.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Message-Id: <20200219160953.13771-78-imammedo@redhat.com>

authored by

Igor Mammedov and committed by
Patchew Importer
4ebc74db ffac16fa

+4 -27
-1
backends/hostmem-file.c
··· 51 51 return; 52 52 } 53 53 54 - backend->force_prealloc = mem_prealloc; 55 54 name = host_memory_backend_get_name(backend); 56 55 memory_region_init_ram_from_file(&backend->mr, OBJECT(backend), 57 56 name,
-1
backends/hostmem-memfd.c
··· 45 45 return; 46 46 } 47 47 48 - backend->force_prealloc = mem_prealloc; 49 48 fd = qemu_memfd_create(TYPE_MEMORY_BACKEND_MEMFD, backend->size, 50 49 m->hugetlb, m->hugetlbsize, m->seal ? 51 50 F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL : 0,
+1 -11
backends/hostmem.c
··· 215 215 { 216 216 HostMemoryBackend *backend = MEMORY_BACKEND(obj); 217 217 218 - return backend->prealloc || backend->force_prealloc; 218 + return backend->prealloc; 219 219 } 220 220 221 221 static void host_memory_backend_set_prealloc(Object *obj, bool value, ··· 223 223 { 224 224 Error *local_err = NULL; 225 225 HostMemoryBackend *backend = MEMORY_BACKEND(obj); 226 - 227 - if (backend->force_prealloc) { 228 - if (value) { 229 - error_setg(errp, 230 - "remove -mem-prealloc to use the prealloc property"); 231 - return; 232 - } 233 - } 234 226 235 227 if (!host_memory_backend_mr_inited(backend)) { 236 228 backend->prealloc = value; ··· 288 280 /* TODO: convert access to globals to compat properties */ 289 281 backend->merge = machine_mem_merge(machine); 290 282 backend->dump = machine_dump_guest_core(machine); 291 - backend->prealloc = mem_prealloc; 292 - backend->prealloc_threads = 1; 293 283 } 294 284 295 285 static void host_memory_backend_post_init(Object *obj)
-11
exec.c
··· 1801 1801 bool truncate, 1802 1802 Error **errp) 1803 1803 { 1804 - Error *err = NULL; 1805 - MachineState *ms = MACHINE(qdev_get_machine()); 1806 1804 void *area; 1807 1805 1808 1806 block->page_size = qemu_fd_getpagesize(fd); ··· 1856 1854 error_setg_errno(errp, errno, 1857 1855 "unable to map backing store for guest RAM"); 1858 1856 return NULL; 1859 - } 1860 - 1861 - if (mem_prealloc) { 1862 - os_mem_prealloc(fd, area, memory, ms->smp.cpus, &err); 1863 - if (err) { 1864 - error_propagate(errp, err); 1865 - qemu_ram_munmap(fd, area, memory); 1866 - return NULL; 1867 - } 1868 1857 } 1869 1858 1870 1859 block->fd = fd;
+1 -1
include/sysemu/hostmem.h
··· 70 70 /* protected */ 71 71 uint64_t size; 72 72 bool merge, dump, use_canonical_path; 73 - bool prealloc, force_prealloc, is_mapped, share; 73 + bool prealloc, is_mapped, share; 74 74 uint32_t prealloc_threads; 75 75 DECLARE_BITMAP(host_nodes, MAX_NODES + 1); 76 76 HostMemPolicy policy;
-1
include/sysemu/sysemu.h
··· 50 50 extern bool enable_mlock; 51 51 extern bool enable_cpu_pm; 52 52 extern QEMUClockType rtc_clock; 53 - extern int mem_prealloc; 54 53 55 54 #define MAX_OPTION_ROMS 16 56 55 typedef struct QEMUOptionRom {
+2 -1
vl.c
··· 140 140 int display_opengl; 141 141 const char* keyboard_layout = NULL; 142 142 ram_addr_t ram_size; 143 - int mem_prealloc = 0; /* force preallocation of physical target memory */ 144 143 bool enable_mlock = false; 145 144 bool enable_cpu_pm = false; 146 145 int nb_nics; ··· 2883 2882 const char *mem_path = NULL; 2884 2883 BlockdevOptionsQueue bdo_queue = QSIMPLEQ_HEAD_INITIALIZER(bdo_queue); 2885 2884 QemuPluginList plugin_list = QTAILQ_HEAD_INITIALIZER(plugin_list); 2885 + int mem_prealloc = 0; /* force preallocation of physical target memory */ 2886 2886 2887 2887 os_set_line_buffering(); 2888 2888 ··· 3984 3984 val = g_strdup_printf("%d", current_machine->smp.cpus); 3985 3985 object_register_sugar_prop("memory-backend", "prealloc-threads", val); 3986 3986 g_free(val); 3987 + object_register_sugar_prop("memory-backend", "prealloc", "on"); 3987 3988 } 3988 3989 3989 3990 /*