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 #include "qom/object.h" 21 22 #define TYPE_MEMORY_BACKEND_MEMFD "memory-backend-memfd" 23 24 OBJECT_DECLARE_SIMPLE_TYPE(HostMemoryBackendMemfd, MEMORY_BACKEND_MEMFD) 25 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 fd = qemu_memfd_create(TYPE_MEMORY_BACKEND_MEMFD, backend->size, 48 m->hugetlb, m->hugetlbsize, m->seal ? 49 F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL : 0, 50 errp); 51 if (fd == -1) { 52 return; 53 } 54 55 name = host_memory_backend_get_name(backend); 56 memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend), 57 name, backend->size, 58 backend->share, fd, 0, errp); 59 g_free(name); 60 } 61 62 static bool 63 memfd_backend_get_hugetlb(Object *o, Error **errp) 64 { 65 return MEMORY_BACKEND_MEMFD(o)->hugetlb; 66 } 67 68 static void 69 memfd_backend_set_hugetlb(Object *o, bool value, Error **errp) 70 { 71 MEMORY_BACKEND_MEMFD(o)->hugetlb = value; 72 } 73 74 static void 75 memfd_backend_set_hugetlbsize(Object *obj, Visitor *v, const char *name, 76 void *opaque, Error **errp) 77 { 78 HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj); 79 uint64_t value; 80 81 if (host_memory_backend_mr_inited(MEMORY_BACKEND(obj))) { 82 error_setg(errp, "cannot change property value"); 83 return; 84 } 85 86 if (!visit_type_size(v, name, &value, errp)) { 87 return; 88 } 89 if (!value) { 90 error_setg(errp, "Property '%s.%s' doesn't take value '%" PRIu64 "'", 91 object_get_typename(obj), name, value); 92 return; 93 } 94 m->hugetlbsize = value; 95 } 96 97 static void 98 memfd_backend_get_hugetlbsize(Object *obj, Visitor *v, const char *name, 99 void *opaque, Error **errp) 100 { 101 HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj); 102 uint64_t value = m->hugetlbsize; 103 104 visit_type_size(v, name, &value, errp); 105 } 106 107 static bool 108 memfd_backend_get_seal(Object *o, Error **errp) 109 { 110 return MEMORY_BACKEND_MEMFD(o)->seal; 111 } 112 113 static void 114 memfd_backend_set_seal(Object *o, bool value, Error **errp) 115 { 116 MEMORY_BACKEND_MEMFD(o)->seal = value; 117 } 118 119 static void 120 memfd_backend_instance_init(Object *obj) 121 { 122 HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj); 123 124 /* default to sealed file */ 125 m->seal = true; 126 MEMORY_BACKEND(m)->share = true; 127 } 128 129 static void 130 memfd_backend_class_init(ObjectClass *oc, void *data) 131 { 132 HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc); 133 134 bc->alloc = memfd_backend_memory_alloc; 135 136 if (qemu_memfd_check(MFD_HUGETLB)) { 137 object_class_property_add_bool(oc, "hugetlb", 138 memfd_backend_get_hugetlb, 139 memfd_backend_set_hugetlb); 140 object_class_property_set_description(oc, "hugetlb", 141 "Use huge pages"); 142 object_class_property_add(oc, "hugetlbsize", "int", 143 memfd_backend_get_hugetlbsize, 144 memfd_backend_set_hugetlbsize, 145 NULL, NULL); 146 object_class_property_set_description(oc, "hugetlbsize", 147 "Huge pages size (ex: 2M, 1G)"); 148 } 149 object_class_property_add_bool(oc, "seal", 150 memfd_backend_get_seal, 151 memfd_backend_set_seal); 152 object_class_property_set_description(oc, "seal", 153 "Seal growing & shrinking"); 154 } 155 156 static const TypeInfo memfd_backend_info = { 157 .name = TYPE_MEMORY_BACKEND_MEMFD, 158 .parent = TYPE_MEMORY_BACKEND, 159 .instance_init = memfd_backend_instance_init, 160 .class_init = memfd_backend_class_init, 161 .instance_size = sizeof(HostMemoryBackendMemfd), 162 }; 163 164 static void register_types(void) 165 { 166 if (qemu_memfd_check(MFD_ALLOW_SEALING)) { 167 type_register_static(&memfd_backend_info); 168 } 169 } 170 171 type_init(register_types); 172