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 if (qemu_memfd_check(MFD_HUGETLB)) { 144 object_class_property_add_bool(oc, "hugetlb", 145 memfd_backend_get_hugetlb, 146 memfd_backend_set_hugetlb, 147 &error_abort); 148 object_class_property_set_description(oc, "hugetlb", 149 "Use huge pages", 150 &error_abort); 151 object_class_property_add(oc, "hugetlbsize", "int", 152 memfd_backend_get_hugetlbsize, 153 memfd_backend_set_hugetlbsize, 154 NULL, NULL, &error_abort); 155 object_class_property_set_description(oc, "hugetlbsize", 156 "Huge pages size (ex: 2M, 1G)", 157 &error_abort); 158 } 159 if (qemu_memfd_check(MFD_ALLOW_SEALING)) { 160 object_class_property_add_bool(oc, "seal", 161 memfd_backend_get_seal, 162 memfd_backend_set_seal, 163 &error_abort); 164 object_class_property_set_description(oc, "seal", 165 "Seal growing & shrinking", 166 &error_abort); 167 } 168 } 169 170 static const TypeInfo memfd_backend_info = { 171 .name = TYPE_MEMORY_BACKEND_MEMFD, 172 .parent = TYPE_MEMORY_BACKEND, 173 .instance_init = memfd_backend_instance_init, 174 .class_init = memfd_backend_class_init, 175 .instance_size = sizeof(HostMemoryBackendMemfd), 176 }; 177 178 static void register_types(void) 179 { 180 if (qemu_memfd_check(0)) { 181 type_register_static(&memfd_backend_info); 182 } 183 } 184 185 type_init(register_types); 186