]> git.proxmox.com Git - mirror_qemu.git/blob - backends/hostmem-file.c
backends: Use g_autofree in HostMemoryBackendClass::alloc() handlers
[mirror_qemu.git] / backends / hostmem-file.c
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 #include "qapi/visitor.h"
22 #include "qapi/qapi-visit-common.h"
23
24 OBJECT_DECLARE_SIMPLE_TYPE(HostMemoryBackendFile, MEMORY_BACKEND_FILE)
25
26
27 struct HostMemoryBackendFile {
28 HostMemoryBackend parent_obj;
29
30 char *mem_path;
31 uint64_t align;
32 uint64_t offset;
33 bool discard_data;
34 bool is_pmem;
35 bool readonly;
36 OnOffAuto rom;
37 };
38
39 static void
40 file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
41 {
42 #ifndef CONFIG_POSIX
43 error_setg(errp, "backend '%s' not supported on this host",
44 object_get_typename(OBJECT(backend)));
45 #else
46 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(backend);
47 g_autofree gchar *name = NULL;
48 uint32_t ram_flags;
49
50 if (!backend->size) {
51 error_setg(errp, "can't create backend with size 0");
52 return;
53 }
54 if (!fb->mem_path) {
55 error_setg(errp, "mem-path property not set");
56 return;
57 }
58
59 switch (fb->rom) {
60 case ON_OFF_AUTO_AUTO:
61 /* Traditionally, opening the file readonly always resulted in ROM. */
62 fb->rom = fb->readonly ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
63 break;
64 case ON_OFF_AUTO_ON:
65 if (!fb->readonly) {
66 error_setg(errp, "property 'rom' = 'on' is not supported with"
67 " 'readonly' = 'off'");
68 return;
69 }
70 break;
71 case ON_OFF_AUTO_OFF:
72 if (fb->readonly && backend->share) {
73 error_setg(errp, "property 'rom' = 'off' is incompatible with"
74 " 'readonly' = 'on' and 'share' = 'on'");
75 return;
76 }
77 break;
78 default:
79 assert(false);
80 }
81
82 name = host_memory_backend_get_name(backend);
83 ram_flags = backend->share ? RAM_SHARED : 0;
84 ram_flags |= fb->readonly ? RAM_READONLY_FD : 0;
85 ram_flags |= fb->rom == ON_OFF_AUTO_ON ? RAM_READONLY : 0;
86 ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
87 ram_flags |= fb->is_pmem ? RAM_PMEM : 0;
88 ram_flags |= RAM_NAMED_FILE;
89 memory_region_init_ram_from_file(&backend->mr, OBJECT(backend), name,
90 backend->size, fb->align, ram_flags,
91 fb->mem_path, fb->offset, errp);
92 #endif
93 }
94
95 static char *get_mem_path(Object *o, Error **errp)
96 {
97 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
98
99 return g_strdup(fb->mem_path);
100 }
101
102 static void set_mem_path(Object *o, const char *str, Error **errp)
103 {
104 HostMemoryBackend *backend = MEMORY_BACKEND(o);
105 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
106
107 if (host_memory_backend_mr_inited(backend)) {
108 error_setg(errp, "cannot change property 'mem-path' of %s",
109 object_get_typename(o));
110 return;
111 }
112 g_free(fb->mem_path);
113 fb->mem_path = g_strdup(str);
114 }
115
116 static bool file_memory_backend_get_discard_data(Object *o, Error **errp)
117 {
118 return MEMORY_BACKEND_FILE(o)->discard_data;
119 }
120
121 static void file_memory_backend_set_discard_data(Object *o, bool value,
122 Error **errp)
123 {
124 MEMORY_BACKEND_FILE(o)->discard_data = value;
125 }
126
127 static void file_memory_backend_get_align(Object *o, Visitor *v,
128 const char *name, void *opaque,
129 Error **errp)
130 {
131 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
132 uint64_t val = fb->align;
133
134 visit_type_size(v, name, &val, errp);
135 }
136
137 static void file_memory_backend_set_align(Object *o, Visitor *v,
138 const char *name, void *opaque,
139 Error **errp)
140 {
141 HostMemoryBackend *backend = MEMORY_BACKEND(o);
142 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
143 uint64_t val;
144
145 if (host_memory_backend_mr_inited(backend)) {
146 error_setg(errp, "cannot change property '%s' of %s", name,
147 object_get_typename(o));
148 return;
149 }
150
151 if (!visit_type_size(v, name, &val, errp)) {
152 return;
153 }
154 fb->align = val;
155 }
156
157 static void file_memory_backend_get_offset(Object *o, Visitor *v,
158 const char *name, void *opaque,
159 Error **errp)
160 {
161 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
162 uint64_t val = fb->offset;
163
164 visit_type_size(v, name, &val, errp);
165 }
166
167 static void file_memory_backend_set_offset(Object *o, Visitor *v,
168 const char *name, void *opaque,
169 Error **errp)
170 {
171 HostMemoryBackend *backend = MEMORY_BACKEND(o);
172 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
173 uint64_t val;
174
175 if (host_memory_backend_mr_inited(backend)) {
176 error_setg(errp, "cannot change property '%s' of %s", name,
177 object_get_typename(o));
178 return;
179 }
180
181 if (!visit_type_size(v, name, &val, errp)) {
182 return;
183 }
184 fb->offset = val;
185 }
186
187 #ifdef CONFIG_LIBPMEM
188 static bool file_memory_backend_get_pmem(Object *o, Error **errp)
189 {
190 return MEMORY_BACKEND_FILE(o)->is_pmem;
191 }
192
193 static void file_memory_backend_set_pmem(Object *o, bool value, Error **errp)
194 {
195 HostMemoryBackend *backend = MEMORY_BACKEND(o);
196 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
197
198 if (host_memory_backend_mr_inited(backend)) {
199 error_setg(errp, "cannot change property 'pmem' of %s.",
200 object_get_typename(o));
201 return;
202 }
203
204 fb->is_pmem = value;
205 }
206 #endif /* CONFIG_LIBPMEM */
207
208 static bool file_memory_backend_get_readonly(Object *obj, Error **errp)
209 {
210 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(obj);
211
212 return fb->readonly;
213 }
214
215 static void file_memory_backend_set_readonly(Object *obj, bool value,
216 Error **errp)
217 {
218 HostMemoryBackend *backend = MEMORY_BACKEND(obj);
219 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(obj);
220
221 if (host_memory_backend_mr_inited(backend)) {
222 error_setg(errp, "cannot change property 'readonly' of %s.",
223 object_get_typename(obj));
224 return;
225 }
226
227 fb->readonly = value;
228 }
229
230 static void file_memory_backend_get_rom(Object *obj, Visitor *v,
231 const char *name, void *opaque,
232 Error **errp)
233 {
234 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(obj);
235 OnOffAuto rom = fb->rom;
236
237 visit_type_OnOffAuto(v, name, &rom, errp);
238 }
239
240 static void file_memory_backend_set_rom(Object *obj, Visitor *v,
241 const char *name, void *opaque,
242 Error **errp)
243 {
244 HostMemoryBackend *backend = MEMORY_BACKEND(obj);
245 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(obj);
246
247 if (host_memory_backend_mr_inited(backend)) {
248 error_setg(errp, "cannot change property '%s' of %s.", name,
249 object_get_typename(obj));
250 return;
251 }
252
253 visit_type_OnOffAuto(v, name, &fb->rom, errp);
254 }
255
256 static void file_backend_unparent(Object *obj)
257 {
258 HostMemoryBackend *backend = MEMORY_BACKEND(obj);
259 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(obj);
260
261 if (host_memory_backend_mr_inited(backend) && fb->discard_data) {
262 void *ptr = memory_region_get_ram_ptr(&backend->mr);
263 uint64_t sz = memory_region_size(&backend->mr);
264
265 qemu_madvise(ptr, sz, QEMU_MADV_REMOVE);
266 }
267 }
268
269 static void
270 file_backend_class_init(ObjectClass *oc, void *data)
271 {
272 HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc);
273
274 bc->alloc = file_backend_memory_alloc;
275 oc->unparent = file_backend_unparent;
276
277 object_class_property_add_bool(oc, "discard-data",
278 file_memory_backend_get_discard_data, file_memory_backend_set_discard_data);
279 object_class_property_add_str(oc, "mem-path",
280 get_mem_path, set_mem_path);
281 object_class_property_add(oc, "align", "int",
282 file_memory_backend_get_align,
283 file_memory_backend_set_align,
284 NULL, NULL);
285 object_class_property_add(oc, "offset", "int",
286 file_memory_backend_get_offset,
287 file_memory_backend_set_offset,
288 NULL, NULL);
289 object_class_property_set_description(oc, "offset",
290 "Offset into the target file (ex: 1G)");
291 #ifdef CONFIG_LIBPMEM
292 object_class_property_add_bool(oc, "pmem",
293 file_memory_backend_get_pmem, file_memory_backend_set_pmem);
294 #endif
295 object_class_property_add_bool(oc, "readonly",
296 file_memory_backend_get_readonly,
297 file_memory_backend_set_readonly);
298 object_class_property_add(oc, "rom", "OnOffAuto",
299 file_memory_backend_get_rom, file_memory_backend_set_rom, NULL, NULL);
300 object_class_property_set_description(oc, "rom",
301 "Whether to create Read Only Memory (ROM)");
302 }
303
304 static void file_backend_instance_finalize(Object *o)
305 {
306 HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
307
308 g_free(fb->mem_path);
309 }
310
311 static const TypeInfo file_backend_info = {
312 .name = TYPE_MEMORY_BACKEND_FILE,
313 .parent = TYPE_MEMORY_BACKEND,
314 .class_init = file_backend_class_init,
315 .instance_finalize = file_backend_instance_finalize,
316 .instance_size = sizeof(HostMemoryBackendFile),
317 };
318
319 static void register_types(void)
320 {
321 type_register_static(&file_backend_info);
322 }
323
324 type_init(register_types);