@@ -29,8 +29,21 @@ ram_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
}
name = host_memory_backend_get_name(backend);
- memory_region_init_ram_shared_nomigrate(&backend->mr, OBJECT(backend), name,
- backend->size, backend->share, errp);
+ if (backend->managed_size) {
+ /*
+ * The size of a memory region must always be > 0 - start with 1. The
+ * managing object/device will resize accordingly.
+ */
+ g_assert(!backend->share);
+ memory_region_init_resizeable_ram(&backend->mr, OBJECT(backend), name,
+ 1, backend->size,
+ host_memory_backend_resized,
+ errp);
+ } else {
+ memory_region_init_ram_shared_nomigrate(&backend->mr, OBJECT(backend),
+ name, backend->size,
+ backend->share, errp);
+ }
g_free(name);
}
@@ -40,6 +53,7 @@ ram_backend_class_init(ObjectClass *oc, void *data)
HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc);
bc->alloc = ram_backend_memory_alloc;
+ bc->managed_size_supported = true;
}
static const TypeInfo ram_backend_info = {
@@ -238,7 +238,10 @@ static void host_memory_backend_set_prealloc(Object *obj, bool value,
return;
}
- if (value && !backend->prealloc) {
+ if (value && backend->managed_size) {
+ error_setg(errp, "'prealloc' is not compatible with 'managed-size'");
+ return;
+ } else if (value && !backend->prealloc) {
int fd = memory_region_get_fd(&backend->mr);
void *ptr = memory_region_get_ram_ptr(&backend->mr);
uint64_t sz = memory_region_size(&backend->mr);
@@ -292,7 +295,8 @@ bool host_memory_backend_is_mapped(HostMemoryBackend *backend)
}
void host_memory_backend_validate(HostMemoryBackend *backend,
- const char *property, Error **errp)
+ const char *property,
+ bool managed_size_support, Error **errp)
{
char *path = object_get_canonical_path_component(OBJECT(backend));
@@ -301,6 +305,10 @@ void host_memory_backend_validate(HostMemoryBackend *backend,
} else if (host_memory_backend_is_mapped(backend)) {
error_setg(errp, "'%s' property specifies a busy memdev: %s",
property, path);
+ } else if (backend->managed_size && !managed_size_support) {
+ error_setg(errp,
+ "'%s' property does not support a memdev with a managed size: %s",
+ property, path);
}
g_free(path);
}
@@ -395,6 +403,24 @@ static void host_memory_backend_apply_settings(HostMemoryBackend *backend,
}
}
+void host_memory_backend_resized(Object *owner, const char *idstr,
+ uint64_t size, void *host)
+{
+ HostMemoryBackend *backend = MEMORY_BACKEND(owner);
+ Error *local_err = NULL;
+
+ /*
+ * Just apply the settings for all (resized) memory again. Note that
+ * "shared" and "prealloc" is currently not compatible with resizable memory
+ * regions ("managed-size"). Warn only.
+ */
+ host_memory_backend_apply_settings(backend, &local_err);
+ if (local_err) {
+ warn_report_err(local_err);
+ local_err = NULL;
+ }
+}
+
static void
host_memory_backend_memory_complete(UserCreatable *uc, Error **errp)
{
@@ -441,6 +467,9 @@ static void host_memory_backend_set_share(Object *o, bool value, Error **errp)
if (host_memory_backend_mr_inited(backend)) {
error_setg(errp, "cannot change property value");
return;
+ } else if (value && backend->managed_size) {
+ error_setg(errp, "'prealloc' is not compatible with 'managed-size'");
+ return;
}
backend->share = value;
}
@@ -462,6 +491,39 @@ host_memory_backend_set_use_canonical_path(Object *obj, bool value,
backend->use_canonical_path = value;
}
+static bool
+ram_backend_get_managed_size(Object *obj, Error **errp)
+{
+ return MEMORY_BACKEND(obj)->managed_size;
+}
+
+static void
+ram_backend_set_managed_size(Object *obj, bool value, Error **errp)
+{
+ HostMemoryBackend *backend = MEMORY_BACKEND(obj);
+ HostMemoryBackendClass *bc = MEMORY_BACKEND_GET_CLASS(obj);
+
+ if (host_memory_backend_mr_inited(backend)) {
+ error_setg(errp, "cannot change property @managed_size'");
+ return;
+ } else if (value && !bc->managed_size_supported) {
+ error_setg(errp,
+ "'managed-size' is not supported yet for %s",
+ object_get_typename(obj));
+ return;
+ } else if (value && (backend->force_prealloc || backend->prealloc)) {
+ error_setg(errp,
+ "'managed-size' is not compatible with preallocated memory");
+ return;
+ } else if (value && backend->share) {
+ error_setg(errp,
+ "'managed-size' is not compatible with shared memory");
+ return;
+ }
+
+ backend->managed_size = value;
+}
+
static void
host_memory_backend_class_init(ObjectClass *oc, void *data)
{
@@ -511,6 +573,12 @@ host_memory_backend_class_init(ObjectClass *oc, void *data)
object_class_property_add_bool(oc, "x-use-canonical-path-for-ramblock-id",
host_memory_backend_get_use_canonical_path,
host_memory_backend_set_use_canonical_path, &error_abort);
+ object_class_property_add_bool(oc, "managed-size",
+ ram_backend_get_managed_size,
+ ram_backend_set_managed_size, &error_abort);
+ object_class_property_set_description(oc, "managed-size",
+ "The owner manages the actual size, 'size' is an upper limit",
+ &error_abort);
}
static const TypeInfo host_memory_backend_info = {
@@ -176,7 +176,8 @@ static void pc_dimm_realize(DeviceState *dev, Error **errp)
int nb_numa_nodes = ms->numa_state->num_nodes;
Error *err = NULL;
- host_memory_backend_validate(dimm->hostmem, PC_DIMM_MEMDEV_PROP, &err);
+ host_memory_backend_validate(dimm->hostmem, PC_DIMM_MEMDEV_PROP, false,
+ &err);
if (err) {
error_propagate(errp, err);
return;
@@ -1037,7 +1037,7 @@ static void ivshmem_plain_realize(PCIDevice *dev, Error **errp)
IVShmemState *s = IVSHMEM_COMMON(dev);
Error *err = NULL;
- host_memory_backend_validate(s->hostmem, "memdev", &err);
+ host_memory_backend_validate(s->hostmem, "memdev", false, &err);
if (err) {
error_propagate(errp, err);
return;
@@ -415,7 +415,7 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp)
/* verify the memdev */
host_memory_backend_validate(vm->memdev, VIRTIO_MEM_MEMDEV_PROP,
- &local_err);
+ false, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
@@ -107,7 +107,7 @@ static void virtio_pmem_realize(DeviceState *dev, Error **errp)
VirtIOPMEM *pmem = VIRTIO_PMEM(dev);
Error *err = NULL;
- host_memory_backend_validate(pmem->memdev, "memdev", &err);
+ host_memory_backend_validate(pmem->memdev, "memdev", false, &err);
if (err) {
error_propagate(errp, err);
return;
@@ -37,6 +37,7 @@ struct HostMemoryBackendClass {
ObjectClass parent_class;
void (*alloc)(HostMemoryBackend *backend, Error **errp);
+ bool managed_size_supported;
};
/**
@@ -53,7 +54,7 @@ struct HostMemoryBackend {
/* protected */
uint64_t size;
bool merge, dump, use_canonical_path;
- bool prealloc, force_prealloc, is_mapped, share;
+ bool prealloc, force_prealloc, is_mapped, share, managed_size;
DECLARE_BITMAP(host_nodes, MAX_NODES + 1);
HostMemPolicy policy;
@@ -61,12 +62,15 @@ struct HostMemoryBackend {
};
bool host_memory_backend_mr_inited(HostMemoryBackend *backend);
+void host_memory_backend_resized(Object *owner, const char *idstr,
+ uint64_t size, void *host);
MemoryRegion *host_memory_backend_get_memory(HostMemoryBackend *backend);
void host_memory_backend_set_mapped(HostMemoryBackend *backend, bool mapped);
bool host_memory_backend_is_mapped(HostMemoryBackend *backend);
void host_memory_backend_validate(HostMemoryBackend *backend,
- const char *property, Error **errp);
+ const char *property,
+ bool managed_size_support, Error **errp);
size_t host_memory_backend_pagesize(HostMemoryBackend *memdev);
char *host_memory_backend_get_name(HostMemoryBackend *backend);
virtio-mem wants to make use of resizable memory regions. Allow to create them by the user by specifying "managed-size". Disallow setting "managed-size" with "prealloc" and "shared". The latter might theoretically be possible, however has to be wired up internally first. Support for memory-backend-ram only for now. Support for other backends (especially, hugepages), can be added later (and once e.g., virtio-mem also supports hugepages). When the memory region gets resized, apply the same settings just as when allocating the memory. Fence off the all such memory backends in all existing users. We'll convert virtio-mem soon. Signed-off-by: David Hildenbrand <david@redhat.com> --- backends/hostmem-ram.c | 18 ++++++++-- backends/hostmem.c | 72 ++++++++++++++++++++++++++++++++++++++-- hw/mem/pc-dimm.c | 3 +- hw/misc/ivshmem.c | 2 +- hw/virtio/virtio-mem.c | 2 +- hw/virtio/virtio-pmem.c | 2 +- include/sysemu/hostmem.h | 8 +++-- 7 files changed, 97 insertions(+), 10 deletions(-)