From 5d9a9a617053a97a76ef332896c386d8fc895631 Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Wed, 5 Jun 2024 12:44:58 +0200 Subject: [PATCH] backends/hostmem: Report error when memory size is unaligned MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If memory-backend-{file,ram} has a size that's not aligned to underlying page size it is not only wasteful, but also may lead to hard to debug behaviour. For instance, in case memory-backend-file and hugepages, madvise() and mbind() fail. Rightfully so, page is the smallest unit they can work with. And even though an error is reported, the root cause it not very clear: qemu-system-x86_64: Couldn't set property 'dump' on 'memory-backend-file': Invalid argument After this commit: qemu-system-x86_64: backend 'memory-backend-file' memory size must be multiple of 2 MiB Signed-off-by: Michal Privoznik Reviewed-by: Philippe Mathieu-Daudé Tested-by: Mario Casquero Message-ID: Signed-off-by: Paolo Bonzini --- backends/hostmem-epc.c | 1 + backends/hostmem-file.c | 1 + backends/hostmem-memfd.c | 1 + backends/hostmem.c | 10 ++++++++++ include/sysemu/hostmem.h | 2 +- 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/backends/hostmem-epc.c b/backends/hostmem-epc.c index 735e2e1cf8..f58fcf00a1 100644 --- a/backends/hostmem-epc.c +++ b/backends/hostmem-epc.c @@ -36,6 +36,7 @@ sgx_epc_backend_memory_alloc(HostMemoryBackend *backend, Error **errp) return false; } + backend->aligned = true; name = object_get_canonical_path(OBJECT(backend)); ram_flags = (backend->share ? RAM_SHARED : 0) | RAM_PROTECTED; return memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend), name, diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c index 3c69db7946..7e5072e33e 100644 --- a/backends/hostmem-file.c +++ b/backends/hostmem-file.c @@ -80,6 +80,7 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp) g_assert_not_reached(); } + backend->aligned = true; name = host_memory_backend_get_name(backend); ram_flags = backend->share ? RAM_SHARED : 0; ram_flags |= fb->readonly ? RAM_READONLY_FD : 0; diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c index 745ead0034..6a3c89a12b 100644 --- a/backends/hostmem-memfd.c +++ b/backends/hostmem-memfd.c @@ -52,6 +52,7 @@ memfd_backend_memory_alloc(HostMemoryBackend *backend, Error **errp) return false; } + backend->aligned = true; name = host_memory_backend_get_name(backend); ram_flags = backend->share ? RAM_SHARED : 0; ram_flags |= backend->reserve ? 0 : RAM_NORESERVE; diff --git a/backends/hostmem.c b/backends/hostmem.c index eb9682b4a8..1edc0ede2a 100644 --- a/backends/hostmem.c +++ b/backends/hostmem.c @@ -20,6 +20,7 @@ #include "qom/object_interfaces.h" #include "qemu/mmap-alloc.h" #include "qemu/madvise.h" +#include "qemu/cutils.h" #include "hw/qdev-core.h" #ifdef CONFIG_NUMA @@ -325,6 +326,7 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp) HostMemoryBackendClass *bc = MEMORY_BACKEND_GET_CLASS(uc); void *ptr; uint64_t sz; + size_t pagesize; bool async = !phase_check(PHASE_LATE_BACKENDS_CREATED); if (!bc->alloc) { @@ -336,6 +338,14 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp) ptr = memory_region_get_ram_ptr(&backend->mr); sz = memory_region_size(&backend->mr); + pagesize = qemu_ram_pagesize(backend->mr.ram_block); + + if (backend->aligned && !QEMU_IS_ALIGNED(sz, pagesize)) { + g_autofree char *pagesize_str = size_to_str(pagesize); + error_setg(errp, "backend '%s' memory size must be multiple of %s", + object_get_typename(OBJECT(uc)), pagesize_str); + return; + } if (backend->merge) { qemu_madvise(ptr, sz, QEMU_MADV_MERGEABLE); diff --git a/include/sysemu/hostmem.h b/include/sysemu/hostmem.h index 04b884bf42..de47ae59e4 100644 --- a/include/sysemu/hostmem.h +++ b/include/sysemu/hostmem.h @@ -74,7 +74,7 @@ struct HostMemoryBackend { uint64_t size; bool merge, dump, use_canonical_path; bool prealloc, is_mapped, share, reserve; - bool guest_memfd; + bool guest_memfd, aligned; uint32_t prealloc_threads; ThreadContext *prealloc_context; DECLARE_BITMAP(host_nodes, MAX_NODES + 1);