diff options
author | Marc-André Lureau <marcandre.lureau@redhat.com> | 2018-02-01 14:27:54 +0100 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2018-02-07 14:09:25 +0100 |
commit | dbb9e0f40d7d561dcffcf7e41ac9f6a5ec90e5b5 (patch) | |
tree | 950d003f8c14f5408f9152fcdbf79dd137c71986 /backends/hostmem-memfd.c | |
parent | 2ef8c0c99be7ee5b9dbceaae41b8890e7c81240f (diff) | |
download | qemu-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.c | 170 |
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); |