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, 63 backend->share, fd, errp); 64 g_free(name); 65 } 66 67 static bool 68 memfd_backend_get_hugetlb(Object *o, Error **errp) 69 { 70 return MEMORY_BACKEND_MEMFD(o)->hugetlb; 71 } 72 73 static void 74 memfd_backend_set_hugetlb(Object *o, bool value, Error **errp) 75 { 76 MEMORY_BACKEND_MEMFD(o)->hugetlb = value; 77 } 78 79 static void 80 memfd_backend_set_hugetlbsize(Object *obj, Visitor *v, const char *name, 81 void *opaque, Error **errp) 82 { 83 HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj); 84 Error *local_err = NULL; 85 uint64_t value; 86 87 if (host_memory_backend_mr_inited(MEMORY_BACKEND(obj))) { 88 error_setg(&local_err, "cannot change property value"); 89 goto out; 90 } 91 92 visit_type_size(v, name, &value, &local_err); 93 if (local_err) { 94 goto out; 95 } 96 if (!value) { 97 error_setg(&local_err, "Property '%s.%s' doesn't take value '%" 98 PRIu64 "'", object_get_typename(obj), name, value); 99 goto out; 100 } 101 m->hugetlbsize = value; 102 out: 103 error_propagate(errp, local_err); 104 } 105 106 static void 107 memfd_backend_get_hugetlbsize(Object *obj, Visitor *v, const char *name, 108 void *opaque, Error **errp) 109 { 110 HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj); 111 uint64_t value = m->hugetlbsize; 112 113 visit_type_size(v, name, &value, errp); 114 } 115 116 static bool 117 memfd_backend_get_seal(Object *o, Error **errp) 118 { 119 return MEMORY_BACKEND_MEMFD(o)->seal; 120 } 121 122 static void 123 memfd_backend_set_seal(Object *o, bool value, Error **errp) 124 { 125 MEMORY_BACKEND_MEMFD(o)->seal = value; 126 } 127 128 static void 129 memfd_backend_instance_init(Object *obj) 130 { 131 HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj); 132 133 /* default to sealed file */ 134 m->seal = true; 135 MEMORY_BACKEND(m)->share = true; 136 } 137 138 static void 139 memfd_backend_class_init(ObjectClass *oc, void *data) 140 { 141 HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc); 142 143 bc->alloc = memfd_backend_memory_alloc; 144 145 if (qemu_memfd_check(MFD_HUGETLB)) { 146 object_class_property_add_bool(oc, "hugetlb", 147 memfd_backend_get_hugetlb, 148 memfd_backend_set_hugetlb, 149 &error_abort); 150 object_class_property_set_description(oc, "hugetlb", 151 "Use huge pages", 152 &error_abort); 153 object_class_property_add(oc, "hugetlbsize", "int", 154 memfd_backend_get_hugetlbsize, 155 memfd_backend_set_hugetlbsize, 156 NULL, NULL, &error_abort); 157 object_class_property_set_description(oc, "hugetlbsize", 158 "Huge pages size (ex: 2M, 1G)", 159 &error_abort); 160 } 161 if (qemu_memfd_check(MFD_ALLOW_SEALING)) { 162 object_class_property_add_bool(oc, "seal", 163 memfd_backend_get_seal, 164 memfd_backend_set_seal, 165 &error_abort); 166 object_class_property_set_description(oc, "seal", 167 "Seal growing & shrinking", 168 &error_abort); 169 } 170 } 171 172 static const TypeInfo memfd_backend_info = { 173 .name = TYPE_MEMORY_BACKEND_MEMFD, 174 .parent = TYPE_MEMORY_BACKEND, 175 .instance_init = memfd_backend_instance_init, 176 .class_init = memfd_backend_class_init, 177 .instance_size = sizeof(HostMemoryBackendMemfd), 178 }; 179 180 static void register_types(void) 181 { 182 if (qemu_memfd_check(0)) { 183 type_register_static(&memfd_backend_info); 184 } 185 } 186 187 type_init(register_types); 188