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 #include "qemu/osdep.h" 13 #include "qemu-common.h" 14 #include "sysemu/hostmem.h" 15 #include "sysemu/sysemu.h" 16 #include "qom/object_interfaces.h" 17 #include "qemu/memfd.h" 18 #include "qapi/error.h" 19 20 #define TYPE_MEMORY_BACKEND_MEMFD "memory-backend-memfd" 21 22 #define MEMORY_BACKEND_MEMFD(obj) \ 23 OBJECT_CHECK(HostMemoryBackendMemfd, (obj), TYPE_MEMORY_BACKEND_MEMFD) 24 25 typedef struct HostMemoryBackendMemfd HostMemoryBackendMemfd; 26 27 struct HostMemoryBackendMemfd { 28 HostMemoryBackend parent_obj; 29 30 bool hugetlb; 31 uint64_t hugetlbsize; 32 bool seal; 33 }; 34 35 static void 36 memfd_backend_memory_alloc(HostMemoryBackend *backend, Error **errp) 37 { 38 HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(backend); 39 char *name; 40 int fd; 41 42 if (!backend->size) { 43 error_setg(errp, "can't create backend with size 0"); 44 return; 45 } 46 47 if (host_memory_backend_mr_inited(backend)) { 48 return; 49 } 50 51 backend->force_prealloc = mem_prealloc; 52 fd = qemu_memfd_create(TYPE_MEMORY_BACKEND_MEMFD, backend->size, 53 m->hugetlb, m->hugetlbsize, m->seal ? 54 F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL : 0, 55 errp); 56 if (fd == -1) { 57 return; 58 } 59 60 name = object_get_canonical_path(OBJECT(backend)); 61 memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend), 62 name, backend->size, true, fd, errp); 63 g_free(name); 64 } 65 66 static bool 67 memfd_backend_get_hugetlb(Object *o, Error **errp) 68 { 69 return MEMORY_BACKEND_MEMFD(o)->hugetlb; 70 } 71 72 static void 73 memfd_backend_set_hugetlb(Object *o, bool value, Error **errp) 74 { 75 MEMORY_BACKEND_MEMFD(o)->hugetlb = value; 76 } 77 78 static void 79 memfd_backend_set_hugetlbsize(Object *obj, Visitor *v, const char *name, 80 void *opaque, Error **errp) 81 { 82 HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj); 83 Error *local_err = NULL; 84 uint64_t value; 85 86 if (host_memory_backend_mr_inited(MEMORY_BACKEND(obj))) { 87 error_setg(&local_err, "cannot change property value"); 88 goto out; 89 } 90 91 visit_type_size(v, name, &value, &local_err); 92 if (local_err) { 93 goto out; 94 } 95 if (!value) { 96 error_setg(&local_err, "Property '%s.%s' doesn't take value '%" 97 PRIu64 "'", object_get_typename(obj), name, value); 98 goto out; 99 } 100 m->hugetlbsize = value; 101 out: 102 error_propagate(errp, local_err); 103 } 104 105 static void 106 memfd_backend_get_hugetlbsize(Object *obj, Visitor *v, const char *name, 107 void *opaque, Error **errp) 108 { 109 HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj); 110 uint64_t value = m->hugetlbsize; 111 112 visit_type_size(v, name, &value, errp); 113 } 114 115 static bool 116 memfd_backend_get_seal(Object *o, Error **errp) 117 { 118 return MEMORY_BACKEND_MEMFD(o)->seal; 119 } 120 121 static void 122 memfd_backend_set_seal(Object *o, bool value, Error **errp) 123 { 124 MEMORY_BACKEND_MEMFD(o)->seal = value; 125 } 126 127 static void 128 memfd_backend_instance_init(Object *obj) 129 { 130 HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj); 131 132 /* default to sealed file */ 133 m->seal = true; 134 } 135 136 static void 137 memfd_backend_class_init(ObjectClass *oc, void *data) 138 { 139 HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc); 140 141 bc->alloc = memfd_backend_memory_alloc; 142 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_add(oc, "hugetlbsize", "int", 148 memfd_backend_get_hugetlbsize, 149 memfd_backend_set_hugetlbsize, 150 NULL, NULL, &error_abort); 151 object_class_property_add_bool(oc, "seal", 152 memfd_backend_get_seal, 153 memfd_backend_set_seal, 154 &error_abort); 155 } 156 157 static const TypeInfo memfd_backend_info = { 158 .name = TYPE_MEMORY_BACKEND_MEMFD, 159 .parent = TYPE_MEMORY_BACKEND, 160 .instance_init = memfd_backend_instance_init, 161 .class_init = memfd_backend_class_init, 162 .instance_size = sizeof(HostMemoryBackendMemfd), 163 }; 164 165 static void register_types(void) 166 { 167 type_register_static(&memfd_backend_info); 168 } 169 170 type_init(register_types); 171