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