aboutsummaryrefslogtreecommitdiff
path: root/backends
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
parent2ef8c0c99be7ee5b9dbceaae41b8890e7c81240f (diff)
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')
-rw-r--r--backends/Makefile.objs2
-rw-r--r--backends/hostmem-memfd.c170
2 files changed, 172 insertions, 0 deletions
diff --git a/backends/Makefile.objs b/backends/Makefile.objs
index 0400799efd..67eeeba5fc 100644
--- a/backends/Makefile.objs
+++ b/backends/Makefile.objs
@@ -8,3 +8,5 @@ common-obj-$(CONFIG_LINUX) += hostmem-file.o
common-obj-y += cryptodev.o
common-obj-y += cryptodev-builtin.o
+
+common-obj-$(CONFIG_LINUX) += hostmem-memfd.o
diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c
new file mode 100644
index 0000000000..1e20fe0ba8
--- /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);