aboutsummaryrefslogtreecommitdiff
path: root/backends/hostmem-memfd.c
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@redhat.com>2018-02-01 14:27:54 +0100
committerPaolo Bonzini <pbonzini@redhat.com>2018-02-07 14:09:25 +0100
commitdbb9e0f40d7d561dcffcf7e41ac9f6a5ec90e5b5 (patch)
tree950d003f8c14f5408f9152fcdbf79dd137c71986 /backends/hostmem-memfd.c
parent2ef8c0c99be7ee5b9dbceaae41b8890e7c81240f (diff)
downloadqemu-dbb9e0f40d7d561dcffcf7e41ac9f6a5ec90e5b5.zip
qemu-dbb9e0f40d7d561dcffcf7e41ac9f6a5ec90e5b5.tar.gz
qemu-dbb9e0f40d7d561dcffcf7e41ac9f6a5ec90e5b5.tar.bz2
Add memfd based hostmem
Add a new memory backend, similar to hostmem-file, except that it doesn't need to create files. It also enforces memory sealing. This backend is mainly useful for sharing the memory with other processes. Note that Linux supports transparent huge-pages of shmem/memfd memory since 4.8. It is relatively easier to set up THP than a dedicate hugepage mount point by using "madvise" in /sys/kernel/mm/transparent_hugepage/shmem_enabled. Since 4.14, memfd allows to set hugetlb requirement explicitly. Pending for merge in 4.16 is memfd sealing support for hugetlb backed memory. Usage: -object memory-backend-memfd,id=mem1,size=1G Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20180201132757.23063-5-marcandre.lureau@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'backends/hostmem-memfd.c')
-rw-r--r--backends/hostmem-memfd.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c
new file mode 100644
index 0000000..1e20fe0
--- /dev/null
+++ b/backends/hostmem-memfd.c
@@ -0,0 +1,170 @@
+/*
+ * QEMU host memfd memory backend
+ *
+ * Copyright (C) 2018 Red Hat Inc
+ *
+ * Authors:
+ * Marc-André Lureau <marcandre.lureau@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "sysemu/hostmem.h"
+#include "sysemu/sysemu.h"
+#include "qom/object_interfaces.h"
+#include "qemu/memfd.h"
+#include "qapi/error.h"
+
+#define TYPE_MEMORY_BACKEND_MEMFD "memory-backend-memfd"
+
+#define MEMORY_BACKEND_MEMFD(obj) \
+ OBJECT_CHECK(HostMemoryBackendMemfd, (obj), TYPE_MEMORY_BACKEND_MEMFD)
+
+typedef struct HostMemoryBackendMemfd HostMemoryBackendMemfd;
+
+struct HostMemoryBackendMemfd {
+ HostMemoryBackend parent_obj;
+
+ bool hugetlb;
+ uint64_t hugetlbsize;
+ bool seal;
+};
+
+static void
+memfd_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
+{
+ HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(backend);
+ char *name;
+ int fd;
+
+ if (!backend->size) {
+ error_setg(errp, "can't create backend with size 0");
+ return;
+ }
+
+ if (host_memory_backend_mr_inited(backend)) {
+ return;
+ }
+
+ backend->force_prealloc = mem_prealloc;
+ fd = qemu_memfd_create(TYPE_MEMORY_BACKEND_MEMFD, backend->size,
+ m->hugetlb, m->hugetlbsize, m->seal ?
+ F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL : 0,
+ errp);
+ if (fd == -1) {
+ return;
+ }
+
+ name = object_get_canonical_path(OBJECT(backend));
+ memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend),
+ name, backend->size, true, fd, errp);
+ g_free(name);
+}
+
+static bool
+memfd_backend_get_hugetlb(Object *o, Error **errp)
+{
+ return MEMORY_BACKEND_MEMFD(o)->hugetlb;
+}
+
+static void
+memfd_backend_set_hugetlb(Object *o, bool value, Error **errp)
+{
+ MEMORY_BACKEND_MEMFD(o)->hugetlb = value;
+}
+
+static void
+memfd_backend_set_hugetlbsize(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj);
+ Error *local_err = NULL;
+ uint64_t value;
+
+ if (host_memory_backend_mr_inited(MEMORY_BACKEND(obj))) {
+ error_setg(&local_err, "cannot change property value");
+ goto out;
+ }
+
+ visit_type_size(v, name, &value, &local_err);
+ if (local_err) {
+ goto out;
+ }
+ if (!value) {
+ error_setg(&local_err, "Property '%s.%s' doesn't take value '%"
+ PRIu64 "'", object_get_typename(obj), name, value);
+ goto out;
+ }
+ m->hugetlbsize = value;
+out:
+ error_propagate(errp, local_err);
+}
+
+static void
+memfd_backend_get_hugetlbsize(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj);
+ uint64_t value = m->hugetlbsize;
+
+ visit_type_size(v, name, &value, errp);
+}
+
+static bool
+memfd_backend_get_seal(Object *o, Error **errp)
+{
+ return MEMORY_BACKEND_MEMFD(o)->seal;
+}
+
+static void
+memfd_backend_set_seal(Object *o, bool value, Error **errp)
+{
+ MEMORY_BACKEND_MEMFD(o)->seal = value;
+}
+
+static void
+memfd_backend_instance_init(Object *obj)
+{
+ HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj);
+
+ /* default to sealed file */
+ m->seal = true;
+}
+
+static void
+memfd_backend_class_init(ObjectClass *oc, void *data)
+{
+ HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc);
+
+ bc->alloc = memfd_backend_memory_alloc;
+
+ object_class_property_add_bool(oc, "hugetlb",
+ memfd_backend_get_hugetlb,
+ memfd_backend_set_hugetlb,
+ &error_abort);
+ object_class_property_add(oc, "hugetlbsize", "int",
+ memfd_backend_get_hugetlbsize,
+ memfd_backend_set_hugetlbsize,
+ NULL, NULL, &error_abort);
+ object_class_property_add_bool(oc, "seal",
+ memfd_backend_get_seal,
+ memfd_backend_set_seal,
+ &error_abort);
+}
+
+static const TypeInfo memfd_backend_info = {
+ .name = TYPE_MEMORY_BACKEND_MEMFD,
+ .parent = TYPE_MEMORY_BACKEND,
+ .instance_init = memfd_backend_instance_init,
+ .class_init = memfd_backend_class_init,
+ .instance_size = sizeof(HostMemoryBackendMemfd),
+};
+
+static void register_types(void)
+{
+ type_register_static(&memfd_backend_info);
+}
+
+type_init(register_types);