qemu/backends/hostmem-memfd.c
<<
>>
Prefs
   1/*
   2 * QEMU host memfd memory backend
   3 *
   4 * Copyright (C) 2018 Red Hat Inc
   5 *
   6 * Authors:
   7 *   Marc-André Lureau <marcandre.lureau@redhat.com>
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10 * See the COPYING file in the top-level directory.
  11 */
  12
  13#include "qemu/osdep.h"
  14#include "sysemu/hostmem.h"
  15#include "sysemu/sysemu.h"
  16#include "qom/object_interfaces.h"
  17#include "qemu/memfd.h"
  18#include "qemu/module.h"
  19#include "qapi/error.h"
  20
  21#define TYPE_MEMORY_BACKEND_MEMFD "memory-backend-memfd"
  22
  23#define MEMORY_BACKEND_MEMFD(obj)                                        \
  24    OBJECT_CHECK(HostMemoryBackendMemfd, (obj), TYPE_MEMORY_BACKEND_MEMFD)
  25
  26typedef struct HostMemoryBackendMemfd HostMemoryBackendMemfd;
  27
  28struct HostMemoryBackendMemfd {
  29    HostMemoryBackend parent_obj;
  30
  31    bool hugetlb;
  32    uint64_t hugetlbsize;
  33    bool seal;
  34};
  35
  36static void
  37memfd_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
  38{
  39    HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(backend);
  40    char *name;
  41    int fd;
  42
  43    if (!backend->size) {
  44        error_setg(errp, "can't create backend with size 0");
  45        return;
  46    }
  47
  48    backend->force_prealloc = mem_prealloc;
  49    fd = qemu_memfd_create(TYPE_MEMORY_BACKEND_MEMFD, backend->size,
  50                           m->hugetlb, m->hugetlbsize, m->seal ?
  51                           F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL : 0,
  52                           errp);
  53    if (fd == -1) {
  54        return;
  55    }
  56
  57    name = host_memory_backend_get_name(backend);
  58    memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend),
  59                                   name, backend->size,
  60                                   backend->share, fd, errp);
  61    g_free(name);
  62}
  63
  64static bool
  65memfd_backend_get_hugetlb(Object *o, Error **errp)
  66{
  67    return MEMORY_BACKEND_MEMFD(o)->hugetlb;
  68}
  69
  70static void
  71memfd_backend_set_hugetlb(Object *o, bool value, Error **errp)
  72{
  73    MEMORY_BACKEND_MEMFD(o)->hugetlb = value;
  74}
  75
  76static void
  77memfd_backend_set_hugetlbsize(Object *obj, Visitor *v, const char *name,
  78                              void *opaque, Error **errp)
  79{
  80    HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj);
  81    Error *local_err = NULL;
  82    uint64_t value;
  83
  84    if (host_memory_backend_mr_inited(MEMORY_BACKEND(obj))) {
  85        error_setg(&local_err, "cannot change property value");
  86        goto out;
  87    }
  88
  89    visit_type_size(v, name, &value, &local_err);
  90    if (local_err) {
  91        goto out;
  92    }
  93    if (!value) {
  94        error_setg(&local_err, "Property '%s.%s' doesn't take value '%"
  95                   PRIu64 "'", object_get_typename(obj), name, value);
  96        goto out;
  97    }
  98    m->hugetlbsize = value;
  99out:
 100    error_propagate(errp, local_err);
 101}
 102
 103static void
 104memfd_backend_get_hugetlbsize(Object *obj, Visitor *v, const char *name,
 105                              void *opaque, Error **errp)
 106{
 107    HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj);
 108    uint64_t value = m->hugetlbsize;
 109
 110    visit_type_size(v, name, &value, errp);
 111}
 112
 113static bool
 114memfd_backend_get_seal(Object *o, Error **errp)
 115{
 116    return MEMORY_BACKEND_MEMFD(o)->seal;
 117}
 118
 119static void
 120memfd_backend_set_seal(Object *o, bool value, Error **errp)
 121{
 122    MEMORY_BACKEND_MEMFD(o)->seal = value;
 123}
 124
 125static void
 126memfd_backend_instance_init(Object *obj)
 127{
 128    HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj);
 129
 130    /* default to sealed file */
 131    m->seal = true;
 132    MEMORY_BACKEND(m)->share = true;
 133}
 134
 135static void
 136memfd_backend_class_init(ObjectClass *oc, void *data)
 137{
 138    HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc);
 139
 140    bc->alloc = memfd_backend_memory_alloc;
 141
 142    if (qemu_memfd_check(MFD_HUGETLB)) {
 143        object_class_property_add_bool(oc, "hugetlb",
 144                                       memfd_backend_get_hugetlb,
 145                                       memfd_backend_set_hugetlb,
 146                                       &error_abort);
 147        object_class_property_set_description(oc, "hugetlb",
 148                                              "Use huge pages",
 149                                              &error_abort);
 150        object_class_property_add(oc, "hugetlbsize", "int",
 151                                  memfd_backend_get_hugetlbsize,
 152                                  memfd_backend_set_hugetlbsize,
 153                                  NULL, NULL, &error_abort);
 154        object_class_property_set_description(oc, "hugetlbsize",
 155                                              "Huge pages size (ex: 2M, 1G)",
 156                                              &error_abort);
 157    }
 158    object_class_property_add_bool(oc, "seal",
 159                                   memfd_backend_get_seal,
 160                                   memfd_backend_set_seal,
 161                                   &error_abort);
 162    object_class_property_set_description(oc, "seal",
 163                                          "Seal growing & shrinking",
 164                                          &error_abort);
 165}
 166
 167static const TypeInfo memfd_backend_info = {
 168    .name = TYPE_MEMORY_BACKEND_MEMFD,
 169    .parent = TYPE_MEMORY_BACKEND,
 170    .instance_init = memfd_backend_instance_init,
 171    .class_init = memfd_backend_class_init,
 172    .instance_size = sizeof(HostMemoryBackendMemfd),
 173};
 174
 175static void register_types(void)
 176{
 177    if (qemu_memfd_check(MFD_ALLOW_SEALING)) {
 178        type_register_static(&memfd_backend_info);
 179    }
 180}
 181
 182type_init(register_types);
 183