1 /* 2 * QEMU Host Memory Backend for hugetlbfs 3 * 4 * Copyright (C) 2013-2014 Red Hat Inc 5 * 6 * Authors: 7 * Paolo Bonzini <pbonzini@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 "qapi/error.h" 15 #include "qemu/error-report.h" 16 #include "qemu/module.h" 17 #include "qemu/madvise.h" 18 #include "sysemu/hostmem.h" 19 #include "qom/object_interfaces.h" 20 #include "qom/object.h" 21 22 OBJECT_DECLARE_SIMPLE_TYPE(HostMemoryBackendFile, MEMORY_BACKEND_FILE) 23 24 25 struct HostMemoryBackendFile { 26 HostMemoryBackend parent_obj; 27 28 char *mem_path; 29 uint64_t align; 30 uint64_t offset; 31 bool discard_data; 32 bool is_pmem; 33 bool readonly; 34 }; 35 36 static void 37 file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp) 38 { 39 #ifndef CONFIG_POSIX 40 error_setg(errp, "backend '%s' not supported on this host", 41 object_get_typename(OBJECT(backend))); 42 #else 43 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(backend); 44 uint32_t ram_flags; 45 gchar *name; 46 47 if (!backend->size) { 48 error_setg(errp, "can't create backend with size 0"); 49 return; 50 } 51 if (!fb->mem_path) { 52 error_setg(errp, "mem-path property not set"); 53 return; 54 } 55 56 name = host_memory_backend_get_name(backend); 57 ram_flags = backend->share ? RAM_SHARED : 0; 58 ram_flags |= backend->reserve ? 0 : RAM_NORESERVE; 59 ram_flags |= fb->is_pmem ? RAM_PMEM : 0; 60 ram_flags |= RAM_NAMED_FILE; 61 memory_region_init_ram_from_file(&backend->mr, OBJECT(backend), name, 62 backend->size, fb->align, ram_flags, 63 fb->mem_path, fb->offset, fb->readonly, 64 errp); 65 g_free(name); 66 #endif 67 } 68 69 static char *get_mem_path(Object *o, Error **errp) 70 { 71 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o); 72 73 return g_strdup(fb->mem_path); 74 } 75 76 static void set_mem_path(Object *o, const char *str, Error **errp) 77 { 78 HostMemoryBackend *backend = MEMORY_BACKEND(o); 79 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o); 80 81 if (host_memory_backend_mr_inited(backend)) { 82 error_setg(errp, "cannot change property 'mem-path' of %s", 83 object_get_typename(o)); 84 return; 85 } 86 g_free(fb->mem_path); 87 fb->mem_path = g_strdup(str); 88 } 89 90 static bool file_memory_backend_get_discard_data(Object *o, Error **errp) 91 { 92 return MEMORY_BACKEND_FILE(o)->discard_data; 93 } 94 95 static void file_memory_backend_set_discard_data(Object *o, bool value, 96 Error **errp) 97 { 98 MEMORY_BACKEND_FILE(o)->discard_data = value; 99 } 100 101 static void file_memory_backend_get_align(Object *o, Visitor *v, 102 const char *name, void *opaque, 103 Error **errp) 104 { 105 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o); 106 uint64_t val = fb->align; 107 108 visit_type_size(v, name, &val, errp); 109 } 110 111 static void file_memory_backend_set_align(Object *o, Visitor *v, 112 const char *name, void *opaque, 113 Error **errp) 114 { 115 HostMemoryBackend *backend = MEMORY_BACKEND(o); 116 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o); 117 uint64_t val; 118 119 if (host_memory_backend_mr_inited(backend)) { 120 error_setg(errp, "cannot change property '%s' of %s", name, 121 object_get_typename(o)); 122 return; 123 } 124 125 if (!visit_type_size(v, name, &val, errp)) { 126 return; 127 } 128 fb->align = val; 129 } 130 131 static void file_memory_backend_get_offset(Object *o, Visitor *v, 132 const char *name, void *opaque, 133 Error **errp) 134 { 135 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o); 136 uint64_t val = fb->offset; 137 138 visit_type_size(v, name, &val, errp); 139 } 140 141 static void file_memory_backend_set_offset(Object *o, Visitor *v, 142 const char *name, void *opaque, 143 Error **errp) 144 { 145 HostMemoryBackend *backend = MEMORY_BACKEND(o); 146 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o); 147 uint64_t val; 148 149 if (host_memory_backend_mr_inited(backend)) { 150 error_setg(errp, "cannot change property '%s' of %s", name, 151 object_get_typename(o)); 152 return; 153 } 154 155 if (!visit_type_size(v, name, &val, errp)) { 156 return; 157 } 158 fb->offset = val; 159 } 160 161 #ifdef CONFIG_LIBPMEM 162 static bool file_memory_backend_get_pmem(Object *o, Error **errp) 163 { 164 return MEMORY_BACKEND_FILE(o)->is_pmem; 165 } 166 167 static void file_memory_backend_set_pmem(Object *o, bool value, Error **errp) 168 { 169 HostMemoryBackend *backend = MEMORY_BACKEND(o); 170 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o); 171 172 if (host_memory_backend_mr_inited(backend)) { 173 error_setg(errp, "cannot change property 'pmem' of %s.", 174 object_get_typename(o)); 175 return; 176 } 177 178 fb->is_pmem = value; 179 } 180 #endif /* CONFIG_LIBPMEM */ 181 182 static bool file_memory_backend_get_readonly(Object *obj, Error **errp) 183 { 184 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(obj); 185 186 return fb->readonly; 187 } 188 189 static void file_memory_backend_set_readonly(Object *obj, bool value, 190 Error **errp) 191 { 192 HostMemoryBackend *backend = MEMORY_BACKEND(obj); 193 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(obj); 194 195 if (host_memory_backend_mr_inited(backend)) { 196 error_setg(errp, "cannot change property 'readonly' of %s.", 197 object_get_typename(obj)); 198 return; 199 } 200 201 fb->readonly = value; 202 } 203 204 static void file_backend_unparent(Object *obj) 205 { 206 HostMemoryBackend *backend = MEMORY_BACKEND(obj); 207 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(obj); 208 209 if (host_memory_backend_mr_inited(backend) && fb->discard_data) { 210 void *ptr = memory_region_get_ram_ptr(&backend->mr); 211 uint64_t sz = memory_region_size(&backend->mr); 212 213 qemu_madvise(ptr, sz, QEMU_MADV_REMOVE); 214 } 215 } 216 217 static void 218 file_backend_class_init(ObjectClass *oc, void *data) 219 { 220 HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc); 221 222 bc->alloc = file_backend_memory_alloc; 223 oc->unparent = file_backend_unparent; 224 225 object_class_property_add_bool(oc, "discard-data", 226 file_memory_backend_get_discard_data, file_memory_backend_set_discard_data); 227 object_class_property_add_str(oc, "mem-path", 228 get_mem_path, set_mem_path); 229 object_class_property_add(oc, "align", "int", 230 file_memory_backend_get_align, 231 file_memory_backend_set_align, 232 NULL, NULL); 233 object_class_property_add(oc, "offset", "int", 234 file_memory_backend_get_offset, 235 file_memory_backend_set_offset, 236 NULL, NULL); 237 object_class_property_set_description(oc, "offset", 238 "Offset into the target file (ex: 1G)"); 239 #ifdef CONFIG_LIBPMEM 240 object_class_property_add_bool(oc, "pmem", 241 file_memory_backend_get_pmem, file_memory_backend_set_pmem); 242 #endif 243 object_class_property_add_bool(oc, "readonly", 244 file_memory_backend_get_readonly, 245 file_memory_backend_set_readonly); 246 } 247 248 static void file_backend_instance_finalize(Object *o) 249 { 250 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o); 251 252 g_free(fb->mem_path); 253 } 254 255 static const TypeInfo file_backend_info = { 256 .name = TYPE_MEMORY_BACKEND_FILE, 257 .parent = TYPE_MEMORY_BACKEND, 258 .class_init = file_backend_class_init, 259 .instance_finalize = file_backend_instance_finalize, 260 .instance_size = sizeof(HostMemoryBackendFile), 261 }; 262 263 static void register_types(void) 264 { 265 type_register_static(&file_backend_info); 266 } 267 268 type_init(register_types); 269