152330e1aSPaolo Bonzini /*
252330e1aSPaolo Bonzini * QEMU Host Memory Backend for hugetlbfs
352330e1aSPaolo Bonzini *
452330e1aSPaolo Bonzini * Copyright (C) 2013-2014 Red Hat Inc
552330e1aSPaolo Bonzini *
652330e1aSPaolo Bonzini * Authors:
752330e1aSPaolo Bonzini * Paolo Bonzini <pbonzini@redhat.com>
852330e1aSPaolo Bonzini *
952330e1aSPaolo Bonzini * This work is licensed under the terms of the GNU GPL, version 2 or later.
1052330e1aSPaolo Bonzini * See the COPYING file in the top-level directory.
1152330e1aSPaolo Bonzini */
120b8fa32fSMarkus Armbruster
139c058332SPeter Maydell #include "qemu/osdep.h"
14da34e65cSMarkus Armbruster #include "qapi/error.h"
15a4de8552SJunyan He #include "qemu/error-report.h"
160b8fa32fSMarkus Armbruster #include "qemu/module.h"
17b85ea5faSPeter Maydell #include "qemu/madvise.h"
1852330e1aSPaolo Bonzini #include "sysemu/hostmem.h"
1952330e1aSPaolo Bonzini #include "qom/object_interfaces.h"
20db1015e9SEduardo Habkost #include "qom/object.h"
21e92666b0SDavid Hildenbrand #include "qapi/visitor.h"
22e92666b0SDavid Hildenbrand #include "qapi/qapi-visit-common.h"
2352330e1aSPaolo Bonzini
248063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(HostMemoryBackendFile, MEMORY_BACKEND_FILE)
2552330e1aSPaolo Bonzini
2652330e1aSPaolo Bonzini
2752330e1aSPaolo Bonzini struct HostMemoryBackendFile {
2852330e1aSPaolo Bonzini HostMemoryBackend parent_obj;
29dbcb8981SPaolo Bonzini
3052330e1aSPaolo Bonzini char *mem_path;
3198376843SHaozhong Zhang uint64_t align;
324b870dc4SAlexander Graf uint64_t offset;
33a4de8552SJunyan He bool discard_data;
34a4de8552SJunyan He bool is_pmem;
3586635aa4SStefan Hajnoczi bool readonly;
36e92666b0SDavid Hildenbrand OnOffAuto rom;
3752330e1aSPaolo Bonzini };
3852330e1aSPaolo Bonzini
39fdb63cf3SPhilippe Mathieu-Daudé static bool
file_backend_memory_alloc(HostMemoryBackend * backend,Error ** errp)4052330e1aSPaolo Bonzini file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
4152330e1aSPaolo Bonzini {
425c7ba877SIgor Mammedov #ifndef CONFIG_POSIX
435c7ba877SIgor Mammedov error_setg(errp, "backend '%s' not supported on this host",
445c7ba877SIgor Mammedov object_get_typename(OBJECT(backend)));
45fdb63cf3SPhilippe Mathieu-Daudé return false;
465c7ba877SIgor Mammedov #else
4752330e1aSPaolo Bonzini HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(backend);
482d7a1eb6SPhilippe Mathieu-Daudé g_autofree gchar *name = NULL;
499181fb70SDavid Hildenbrand uint32_t ram_flags;
5052330e1aSPaolo Bonzini
5152330e1aSPaolo Bonzini if (!backend->size) {
5252330e1aSPaolo Bonzini error_setg(errp, "can't create backend with size 0");
53fdb63cf3SPhilippe Mathieu-Daudé return false;
5452330e1aSPaolo Bonzini }
5552330e1aSPaolo Bonzini if (!fb->mem_path) {
56c2cb2b04SJan Kiszka error_setg(errp, "mem-path property not set");
57fdb63cf3SPhilippe Mathieu-Daudé return false;
5852330e1aSPaolo Bonzini }
59314aec4aSStefan Hajnoczi
60e92666b0SDavid Hildenbrand switch (fb->rom) {
61e92666b0SDavid Hildenbrand case ON_OFF_AUTO_AUTO:
62e92666b0SDavid Hildenbrand /* Traditionally, opening the file readonly always resulted in ROM. */
63e92666b0SDavid Hildenbrand fb->rom = fb->readonly ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
64e92666b0SDavid Hildenbrand break;
65e92666b0SDavid Hildenbrand case ON_OFF_AUTO_ON:
66e92666b0SDavid Hildenbrand if (!fb->readonly) {
67e92666b0SDavid Hildenbrand error_setg(errp, "property 'rom' = 'on' is not supported with"
68e92666b0SDavid Hildenbrand " 'readonly' = 'off'");
69fdb63cf3SPhilippe Mathieu-Daudé return false;
70e92666b0SDavid Hildenbrand }
71e92666b0SDavid Hildenbrand break;
72e92666b0SDavid Hildenbrand case ON_OFF_AUTO_OFF:
73e92666b0SDavid Hildenbrand if (fb->readonly && backend->share) {
74e92666b0SDavid Hildenbrand error_setg(errp, "property 'rom' = 'off' is incompatible with"
75e92666b0SDavid Hildenbrand " 'readonly' = 'on' and 'share' = 'on'");
76fdb63cf3SPhilippe Mathieu-Daudé return false;
77e92666b0SDavid Hildenbrand }
78e92666b0SDavid Hildenbrand break;
79e92666b0SDavid Hildenbrand default:
80fdb63cf3SPhilippe Mathieu-Daudé g_assert_not_reached();
81e92666b0SDavid Hildenbrand }
82e92666b0SDavid Hildenbrand
83*5d9a9a61SMichal Privoznik backend->aligned = true;
84fa0cb34dSMarc-André Lureau name = host_memory_backend_get_name(backend);
859181fb70SDavid Hildenbrand ram_flags = backend->share ? RAM_SHARED : 0;
86e92666b0SDavid Hildenbrand ram_flags |= fb->readonly ? RAM_READONLY_FD : 0;
87e92666b0SDavid Hildenbrand ram_flags |= fb->rom == ON_OFF_AUTO_ON ? RAM_READONLY : 0;
889181fb70SDavid Hildenbrand ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
8937662d85SXiaoyao Li ram_flags |= backend->guest_memfd ? RAM_GUEST_MEMFD : 0;
909181fb70SDavid Hildenbrand ram_flags |= fb->is_pmem ? RAM_PMEM : 0;
91b0182e53SSteve Sistare ram_flags |= RAM_NAMED_FILE;
92fdb63cf3SPhilippe Mathieu-Daudé return memory_region_init_ram_from_file(&backend->mr, OBJECT(backend), name,
939181fb70SDavid Hildenbrand backend->size, fb->align, ram_flags,
945c52a219SDavid Hildenbrand fb->mem_path, fb->offset, errp);
9552330e1aSPaolo Bonzini #endif
9652330e1aSPaolo Bonzini }
9752330e1aSPaolo Bonzini
get_mem_path(Object * o,Error ** errp)9852330e1aSPaolo Bonzini static char *get_mem_path(Object *o, Error **errp)
9952330e1aSPaolo Bonzini {
10052330e1aSPaolo Bonzini HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
10152330e1aSPaolo Bonzini
10252330e1aSPaolo Bonzini return g_strdup(fb->mem_path);
10352330e1aSPaolo Bonzini }
10452330e1aSPaolo Bonzini
set_mem_path(Object * o,const char * str,Error ** errp)10552330e1aSPaolo Bonzini static void set_mem_path(Object *o, const char *str, Error **errp)
10652330e1aSPaolo Bonzini {
10752330e1aSPaolo Bonzini HostMemoryBackend *backend = MEMORY_BACKEND(o);
10852330e1aSPaolo Bonzini HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
10952330e1aSPaolo Bonzini
1106f4c60e4SPeter Xu if (host_memory_backend_mr_inited(backend)) {
11121d16836SZhang Yi error_setg(errp, "cannot change property 'mem-path' of %s",
11221d16836SZhang Yi object_get_typename(o));
11352330e1aSPaolo Bonzini return;
11452330e1aSPaolo Bonzini }
11552330e1aSPaolo Bonzini g_free(fb->mem_path);
11652330e1aSPaolo Bonzini fb->mem_path = g_strdup(str);
11752330e1aSPaolo Bonzini }
11852330e1aSPaolo Bonzini
file_memory_backend_get_discard_data(Object * o,Error ** errp)11911ae6ed8SEduardo Habkost static bool file_memory_backend_get_discard_data(Object *o, Error **errp)
12011ae6ed8SEduardo Habkost {
12111ae6ed8SEduardo Habkost return MEMORY_BACKEND_FILE(o)->discard_data;
12211ae6ed8SEduardo Habkost }
12311ae6ed8SEduardo Habkost
file_memory_backend_set_discard_data(Object * o,bool value,Error ** errp)12411ae6ed8SEduardo Habkost static void file_memory_backend_set_discard_data(Object *o, bool value,
12511ae6ed8SEduardo Habkost Error **errp)
12611ae6ed8SEduardo Habkost {
12711ae6ed8SEduardo Habkost MEMORY_BACKEND_FILE(o)->discard_data = value;
12811ae6ed8SEduardo Habkost }
12911ae6ed8SEduardo Habkost
file_memory_backend_get_align(Object * o,Visitor * v,const char * name,void * opaque,Error ** errp)13098376843SHaozhong Zhang static void file_memory_backend_get_align(Object *o, Visitor *v,
13198376843SHaozhong Zhang const char *name, void *opaque,
13298376843SHaozhong Zhang Error **errp)
13398376843SHaozhong Zhang {
13498376843SHaozhong Zhang HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
13598376843SHaozhong Zhang uint64_t val = fb->align;
13698376843SHaozhong Zhang
13798376843SHaozhong Zhang visit_type_size(v, name, &val, errp);
13898376843SHaozhong Zhang }
13998376843SHaozhong Zhang
file_memory_backend_set_align(Object * o,Visitor * v,const char * name,void * opaque,Error ** errp)14098376843SHaozhong Zhang static void file_memory_backend_set_align(Object *o, Visitor *v,
14198376843SHaozhong Zhang const char *name, void *opaque,
14298376843SHaozhong Zhang Error **errp)
14398376843SHaozhong Zhang {
14498376843SHaozhong Zhang HostMemoryBackend *backend = MEMORY_BACKEND(o);
14598376843SHaozhong Zhang HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
14698376843SHaozhong Zhang uint64_t val;
14798376843SHaozhong Zhang
14898376843SHaozhong Zhang if (host_memory_backend_mr_inited(backend)) {
149dcfe4805SMarkus Armbruster error_setg(errp, "cannot change property '%s' of %s", name,
150dcfe4805SMarkus Armbruster object_get_typename(o));
151dcfe4805SMarkus Armbruster return;
15298376843SHaozhong Zhang }
15398376843SHaozhong Zhang
154668f62ecSMarkus Armbruster if (!visit_type_size(v, name, &val, errp)) {
155dcfe4805SMarkus Armbruster return;
15698376843SHaozhong Zhang }
15798376843SHaozhong Zhang fb->align = val;
15898376843SHaozhong Zhang }
15998376843SHaozhong Zhang
file_memory_backend_get_offset(Object * o,Visitor * v,const char * name,void * opaque,Error ** errp)1604b870dc4SAlexander Graf static void file_memory_backend_get_offset(Object *o, Visitor *v,
1614b870dc4SAlexander Graf const char *name, void *opaque,
1624b870dc4SAlexander Graf Error **errp)
1634b870dc4SAlexander Graf {
1644b870dc4SAlexander Graf HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
1654b870dc4SAlexander Graf uint64_t val = fb->offset;
1664b870dc4SAlexander Graf
1674b870dc4SAlexander Graf visit_type_size(v, name, &val, errp);
1684b870dc4SAlexander Graf }
1694b870dc4SAlexander Graf
file_memory_backend_set_offset(Object * o,Visitor * v,const char * name,void * opaque,Error ** errp)1704b870dc4SAlexander Graf static void file_memory_backend_set_offset(Object *o, Visitor *v,
1714b870dc4SAlexander Graf const char *name, void *opaque,
1724b870dc4SAlexander Graf Error **errp)
1734b870dc4SAlexander Graf {
1744b870dc4SAlexander Graf HostMemoryBackend *backend = MEMORY_BACKEND(o);
1754b870dc4SAlexander Graf HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
1764b870dc4SAlexander Graf uint64_t val;
1774b870dc4SAlexander Graf
1784b870dc4SAlexander Graf if (host_memory_backend_mr_inited(backend)) {
1794b870dc4SAlexander Graf error_setg(errp, "cannot change property '%s' of %s", name,
1804b870dc4SAlexander Graf object_get_typename(o));
1814b870dc4SAlexander Graf return;
1824b870dc4SAlexander Graf }
1834b870dc4SAlexander Graf
1844b870dc4SAlexander Graf if (!visit_type_size(v, name, &val, errp)) {
1854b870dc4SAlexander Graf return;
1864b870dc4SAlexander Graf }
1874b870dc4SAlexander Graf fb->offset = val;
1884b870dc4SAlexander Graf }
1894b870dc4SAlexander Graf
190def835f0SMichal Privoznik #ifdef CONFIG_LIBPMEM
file_memory_backend_get_pmem(Object * o,Error ** errp)191a4de8552SJunyan He static bool file_memory_backend_get_pmem(Object *o, Error **errp)
192a4de8552SJunyan He {
193a4de8552SJunyan He return MEMORY_BACKEND_FILE(o)->is_pmem;
194a4de8552SJunyan He }
195a4de8552SJunyan He
file_memory_backend_set_pmem(Object * o,bool value,Error ** errp)196a4de8552SJunyan He static void file_memory_backend_set_pmem(Object *o, bool value, Error **errp)
197a4de8552SJunyan He {
198a4de8552SJunyan He HostMemoryBackend *backend = MEMORY_BACKEND(o);
199a4de8552SJunyan He HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
200a4de8552SJunyan He
201a4de8552SJunyan He if (host_memory_backend_mr_inited(backend)) {
20287dc3ce6SZhang Yi error_setg(errp, "cannot change property 'pmem' of %s.",
20387dc3ce6SZhang Yi object_get_typename(o));
204a4de8552SJunyan He return;
205a4de8552SJunyan He }
206a4de8552SJunyan He
207a4de8552SJunyan He fb->is_pmem = value;
208a4de8552SJunyan He }
209def835f0SMichal Privoznik #endif /* CONFIG_LIBPMEM */
210a4de8552SJunyan He
file_memory_backend_get_readonly(Object * obj,Error ** errp)21186635aa4SStefan Hajnoczi static bool file_memory_backend_get_readonly(Object *obj, Error **errp)
21286635aa4SStefan Hajnoczi {
21386635aa4SStefan Hajnoczi HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(obj);
21486635aa4SStefan Hajnoczi
21586635aa4SStefan Hajnoczi return fb->readonly;
21686635aa4SStefan Hajnoczi }
21786635aa4SStefan Hajnoczi
file_memory_backend_set_readonly(Object * obj,bool value,Error ** errp)21886635aa4SStefan Hajnoczi static void file_memory_backend_set_readonly(Object *obj, bool value,
21986635aa4SStefan Hajnoczi Error **errp)
22086635aa4SStefan Hajnoczi {
22186635aa4SStefan Hajnoczi HostMemoryBackend *backend = MEMORY_BACKEND(obj);
22286635aa4SStefan Hajnoczi HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(obj);
22386635aa4SStefan Hajnoczi
22486635aa4SStefan Hajnoczi if (host_memory_backend_mr_inited(backend)) {
22586635aa4SStefan Hajnoczi error_setg(errp, "cannot change property 'readonly' of %s.",
22686635aa4SStefan Hajnoczi object_get_typename(obj));
22786635aa4SStefan Hajnoczi return;
22886635aa4SStefan Hajnoczi }
22986635aa4SStefan Hajnoczi
23086635aa4SStefan Hajnoczi fb->readonly = value;
23186635aa4SStefan Hajnoczi }
23286635aa4SStefan Hajnoczi
file_memory_backend_get_rom(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)233e92666b0SDavid Hildenbrand static void file_memory_backend_get_rom(Object *obj, Visitor *v,
234e92666b0SDavid Hildenbrand const char *name, void *opaque,
235e92666b0SDavid Hildenbrand Error **errp)
236e92666b0SDavid Hildenbrand {
237e92666b0SDavid Hildenbrand HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(obj);
238e92666b0SDavid Hildenbrand OnOffAuto rom = fb->rom;
239e92666b0SDavid Hildenbrand
240e92666b0SDavid Hildenbrand visit_type_OnOffAuto(v, name, &rom, errp);
241e92666b0SDavid Hildenbrand }
242e92666b0SDavid Hildenbrand
file_memory_backend_set_rom(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)243e92666b0SDavid Hildenbrand static void file_memory_backend_set_rom(Object *obj, Visitor *v,
244e92666b0SDavid Hildenbrand const char *name, void *opaque,
245e92666b0SDavid Hildenbrand Error **errp)
246e92666b0SDavid Hildenbrand {
247e92666b0SDavid Hildenbrand HostMemoryBackend *backend = MEMORY_BACKEND(obj);
248e92666b0SDavid Hildenbrand HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(obj);
249e92666b0SDavid Hildenbrand
250e92666b0SDavid Hildenbrand if (host_memory_backend_mr_inited(backend)) {
251e92666b0SDavid Hildenbrand error_setg(errp, "cannot change property '%s' of %s.", name,
252e92666b0SDavid Hildenbrand object_get_typename(obj));
253e92666b0SDavid Hildenbrand return;
254e92666b0SDavid Hildenbrand }
255e92666b0SDavid Hildenbrand
256e92666b0SDavid Hildenbrand visit_type_OnOffAuto(v, name, &fb->rom, errp);
257e92666b0SDavid Hildenbrand }
258e92666b0SDavid Hildenbrand
file_backend_unparent(Object * obj)25911ae6ed8SEduardo Habkost static void file_backend_unparent(Object *obj)
26011ae6ed8SEduardo Habkost {
26111ae6ed8SEduardo Habkost HostMemoryBackend *backend = MEMORY_BACKEND(obj);
26211ae6ed8SEduardo Habkost HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(obj);
26311ae6ed8SEduardo Habkost
26411ae6ed8SEduardo Habkost if (host_memory_backend_mr_inited(backend) && fb->discard_data) {
26511ae6ed8SEduardo Habkost void *ptr = memory_region_get_ram_ptr(&backend->mr);
26611ae6ed8SEduardo Habkost uint64_t sz = memory_region_size(&backend->mr);
26711ae6ed8SEduardo Habkost
26811ae6ed8SEduardo Habkost qemu_madvise(ptr, sz, QEMU_MADV_REMOVE);
26911ae6ed8SEduardo Habkost }
27011ae6ed8SEduardo Habkost }
27111ae6ed8SEduardo Habkost
27252330e1aSPaolo Bonzini static void
file_backend_class_init(ObjectClass * oc,void * data)273026ac483SEduardo Habkost file_backend_class_init(ObjectClass *oc, void *data)
27452330e1aSPaolo Bonzini {
275026ac483SEduardo Habkost HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc);
276026ac483SEduardo Habkost
277026ac483SEduardo Habkost bc->alloc = file_backend_memory_alloc;
27811ae6ed8SEduardo Habkost oc->unparent = file_backend_unparent;
279026ac483SEduardo Habkost
28011ae6ed8SEduardo Habkost object_class_property_add_bool(oc, "discard-data",
281d2623129SMarkus Armbruster file_memory_backend_get_discard_data, file_memory_backend_set_discard_data);
282026ac483SEduardo Habkost object_class_property_add_str(oc, "mem-path",
283d2623129SMarkus Armbruster get_mem_path, set_mem_path);
28498376843SHaozhong Zhang object_class_property_add(oc, "align", "int",
28598376843SHaozhong Zhang file_memory_backend_get_align,
28698376843SHaozhong Zhang file_memory_backend_set_align,
287d2623129SMarkus Armbruster NULL, NULL);
2884b870dc4SAlexander Graf object_class_property_add(oc, "offset", "int",
2894b870dc4SAlexander Graf file_memory_backend_get_offset,
2904b870dc4SAlexander Graf file_memory_backend_set_offset,
2914b870dc4SAlexander Graf NULL, NULL);
2924b870dc4SAlexander Graf object_class_property_set_description(oc, "offset",
2934b870dc4SAlexander Graf "Offset into the target file (ex: 1G)");
294def835f0SMichal Privoznik #ifdef CONFIG_LIBPMEM
295a4de8552SJunyan He object_class_property_add_bool(oc, "pmem",
296d2623129SMarkus Armbruster file_memory_backend_get_pmem, file_memory_backend_set_pmem);
297def835f0SMichal Privoznik #endif
29886635aa4SStefan Hajnoczi object_class_property_add_bool(oc, "readonly",
29986635aa4SStefan Hajnoczi file_memory_backend_get_readonly,
30086635aa4SStefan Hajnoczi file_memory_backend_set_readonly);
301e92666b0SDavid Hildenbrand object_class_property_add(oc, "rom", "OnOffAuto",
302e92666b0SDavid Hildenbrand file_memory_backend_get_rom, file_memory_backend_set_rom, NULL, NULL);
303e92666b0SDavid Hildenbrand object_class_property_set_description(oc, "rom",
304e92666b0SDavid Hildenbrand "Whether to create Read Only Memory (ROM)");
30552330e1aSPaolo Bonzini }
30652330e1aSPaolo Bonzini
file_backend_instance_finalize(Object * o)307bc78a013SMarc-André Lureau static void file_backend_instance_finalize(Object *o)
308bc78a013SMarc-André Lureau {
309bc78a013SMarc-André Lureau HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
310bc78a013SMarc-André Lureau
311bc78a013SMarc-André Lureau g_free(fb->mem_path);
312bc78a013SMarc-André Lureau }
313bc78a013SMarc-André Lureau
31452330e1aSPaolo Bonzini static const TypeInfo file_backend_info = {
31552330e1aSPaolo Bonzini .name = TYPE_MEMORY_BACKEND_FILE,
31652330e1aSPaolo Bonzini .parent = TYPE_MEMORY_BACKEND,
31752330e1aSPaolo Bonzini .class_init = file_backend_class_init,
318bc78a013SMarc-André Lureau .instance_finalize = file_backend_instance_finalize,
31952330e1aSPaolo Bonzini .instance_size = sizeof(HostMemoryBackendFile),
32052330e1aSPaolo Bonzini };
32152330e1aSPaolo Bonzini
register_types(void)32252330e1aSPaolo Bonzini static void register_types(void)
32352330e1aSPaolo Bonzini {
32452330e1aSPaolo Bonzini type_register_static(&file_backend_info);
32552330e1aSPaolo Bonzini }
32652330e1aSPaolo Bonzini
32752330e1aSPaolo Bonzini type_init(register_types);
328