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 #include "qemu/osdep.h" 13 #include "qapi/error.h" 14 #include "qemu-common.h" 15 #include "qemu/error-report.h" 16 #include "sysemu/hostmem.h" 17 #include "sysemu/sysemu.h" 18 #include "qom/object_interfaces.h" 19 20 /* hostmem-file.c */ 21 /** 22 * @TYPE_MEMORY_BACKEND_FILE: 23 * name of backend that uses mmap on a file descriptor 24 */ 25 #define TYPE_MEMORY_BACKEND_FILE "memory-backend-file" 26 27 #define MEMORY_BACKEND_FILE(obj) \ 28 OBJECT_CHECK(HostMemoryBackendFile, (obj), TYPE_MEMORY_BACKEND_FILE) 29 30 typedef struct HostMemoryBackendFile HostMemoryBackendFile; 31 32 struct HostMemoryBackendFile { 33 HostMemoryBackend parent_obj; 34 35 char *mem_path; 36 uint64_t align; 37 bool discard_data; 38 bool is_pmem; 39 }; 40 41 static void 42 file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp) 43 { 44 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(backend); 45 #ifdef CONFIG_POSIX 46 gchar *name; 47 #endif 48 49 if (!backend->size) { 50 error_setg(errp, "can't create backend with size 0"); 51 return; 52 } 53 if (!fb->mem_path) { 54 error_setg(errp, "mem-path property not set"); 55 return; 56 } 57 #ifndef CONFIG_POSIX 58 error_setg(errp, "-mem-path not supported on this host"); 59 #else 60 backend->force_prealloc = mem_prealloc; 61 name = host_memory_backend_get_name(backend); 62 memory_region_init_ram_from_file(&backend->mr, OBJECT(backend), 63 name, 64 backend->size, fb->align, 65 (backend->share ? RAM_SHARED : 0) | 66 (fb->is_pmem ? RAM_PMEM : 0), 67 fb->mem_path, errp); 68 g_free(name); 69 #endif 70 } 71 72 static char *get_mem_path(Object *o, Error **errp) 73 { 74 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o); 75 76 return g_strdup(fb->mem_path); 77 } 78 79 static void set_mem_path(Object *o, const char *str, Error **errp) 80 { 81 HostMemoryBackend *backend = MEMORY_BACKEND(o); 82 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o); 83 84 if (host_memory_backend_mr_inited(backend)) { 85 error_setg(errp, "cannot change property 'mem-path' of %s", 86 object_get_typename(o)); 87 return; 88 } 89 g_free(fb->mem_path); 90 fb->mem_path = g_strdup(str); 91 } 92 93 static bool file_memory_backend_get_discard_data(Object *o, Error **errp) 94 { 95 return MEMORY_BACKEND_FILE(o)->discard_data; 96 } 97 98 static void file_memory_backend_set_discard_data(Object *o, bool value, 99 Error **errp) 100 { 101 MEMORY_BACKEND_FILE(o)->discard_data = value; 102 } 103 104 static void file_memory_backend_get_align(Object *o, Visitor *v, 105 const char *name, void *opaque, 106 Error **errp) 107 { 108 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o); 109 uint64_t val = fb->align; 110 111 visit_type_size(v, name, &val, errp); 112 } 113 114 static void file_memory_backend_set_align(Object *o, Visitor *v, 115 const char *name, void *opaque, 116 Error **errp) 117 { 118 HostMemoryBackend *backend = MEMORY_BACKEND(o); 119 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o); 120 Error *local_err = NULL; 121 uint64_t val; 122 123 if (host_memory_backend_mr_inited(backend)) { 124 error_setg(&local_err, "cannot change property '%s' of %s", 125 name, object_get_typename(o)); 126 goto out; 127 } 128 129 visit_type_size(v, name, &val, &local_err); 130 if (local_err) { 131 goto out; 132 } 133 fb->align = val; 134 135 out: 136 error_propagate(errp, local_err); 137 } 138 139 static bool file_memory_backend_get_pmem(Object *o, Error **errp) 140 { 141 return MEMORY_BACKEND_FILE(o)->is_pmem; 142 } 143 144 static void file_memory_backend_set_pmem(Object *o, bool value, Error **errp) 145 { 146 HostMemoryBackend *backend = MEMORY_BACKEND(o); 147 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o); 148 149 if (host_memory_backend_mr_inited(backend)) { 150 151 error_setg(errp, "cannot change property 'pmem' of %s.", 152 object_get_typename(o)); 153 return; 154 } 155 156 #ifndef CONFIG_LIBPMEM 157 if (value) { 158 Error *local_err = NULL; 159 160 error_setg(&local_err, 161 "Lack of libpmem support while setting the 'pmem=on'" 162 " of %s. We can't ensure data persistence.", 163 object_get_typename(o)); 164 error_propagate(errp, local_err); 165 return; 166 } 167 #endif 168 169 fb->is_pmem = value; 170 } 171 172 static void file_backend_unparent(Object *obj) 173 { 174 HostMemoryBackend *backend = MEMORY_BACKEND(obj); 175 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(obj); 176 177 if (host_memory_backend_mr_inited(backend) && fb->discard_data) { 178 void *ptr = memory_region_get_ram_ptr(&backend->mr); 179 uint64_t sz = memory_region_size(&backend->mr); 180 181 qemu_madvise(ptr, sz, QEMU_MADV_REMOVE); 182 } 183 } 184 185 static void 186 file_backend_class_init(ObjectClass *oc, void *data) 187 { 188 HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc); 189 190 bc->alloc = file_backend_memory_alloc; 191 oc->unparent = file_backend_unparent; 192 193 object_class_property_add_bool(oc, "discard-data", 194 file_memory_backend_get_discard_data, file_memory_backend_set_discard_data, 195 &error_abort); 196 object_class_property_add_str(oc, "mem-path", 197 get_mem_path, set_mem_path, 198 &error_abort); 199 object_class_property_add(oc, "align", "int", 200 file_memory_backend_get_align, 201 file_memory_backend_set_align, 202 NULL, NULL, &error_abort); 203 object_class_property_add_bool(oc, "pmem", 204 file_memory_backend_get_pmem, file_memory_backend_set_pmem, 205 &error_abort); 206 } 207 208 static void file_backend_instance_finalize(Object *o) 209 { 210 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o); 211 212 g_free(fb->mem_path); 213 } 214 215 static const TypeInfo file_backend_info = { 216 .name = TYPE_MEMORY_BACKEND_FILE, 217 .parent = TYPE_MEMORY_BACKEND, 218 .class_init = file_backend_class_init, 219 .instance_finalize = file_backend_instance_finalize, 220 .instance_size = sizeof(HostMemoryBackendFile), 221 }; 222 223 static void register_types(void) 224 { 225 type_register_static(&file_backend_info); 226 } 227 228 type_init(register_types); 229