@@ -8,6 +8,6 @@ baum.o-cflags := $(SDL_CFLAGS)
common-obj-$(CONFIG_TPM) += tpm.o
common-obj-y += hostmem.o hostmem-ram.o
-common-obj-$(CONFIG_LINUX) += hostmem-file.o
+common-obj-$(CONFIG_LINUX) += hostmem-file.o hostmem-shared.o
common-obj-y += multi-socket.o
new file mode 100644
@@ -0,0 +1,192 @@
+/*
+ * QEMU Host Memory Backend for hugetlbfs
+ *
+ * Copyright (C) 2015 - Virtual Open Systems
+ *
+ * Author: Baptiste Reynal <b.reynal@virtualopensystems.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "sysemu/hostmem-shared.h"
+
+static void shm_map(HostMemoryBackendShared *shm, size_t size, off_t offset)
+{
+ void *shared_ram;
+ HostMemoryBackend *backend = MEMORY_BACKEND(shm);
+
+ shared_ram = mmap(0, size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, shm->fd, offset);
+ close(shm->fd);
+
+ if (shared_ram == MAP_FAILED) {
+ perror("Map failed");
+ }
+
+ memory_region_init_ram_ptr(&shm->shared_region, OBJECT(backend),
+ "shared_mem", size, shared_ram);
+
+ memory_region_add_subregion(&backend->mr,
+ 0, &shm->shared_region);
+
+ vmstate_register_ram_global(&shm->shared_region);
+
+ event_notifier_set(shm->levent);
+}
+
+/* Callback function if a fd is received over the socket */
+static void set_shared_memory(MSClient *c, const char *message, void *opaque)
+{
+ HostMemoryBackendShared *shm = MEMORY_BACKEND_SHARED(opaque);
+
+ int fd = 0;
+ multi_socket_get_fds_from(c, &fd);
+
+ if (fd <= 0) {
+ printf("Error receiving fd: %d", fd);
+ exit(-1);
+ }
+
+ shm->fd = fd;
+}
+
+static void shm_send_fd(MSClient *client, void *opaque)
+{
+ int fd;
+ const char *message = "send_fd";
+ HostMemoryBackend *hm = MEMORY_BACKEND(opaque);
+
+ fd = memory_region_get_fd(&hm->mr);
+
+ multi_socket_send_fds_to(client, &fd, 1, message, strlen(message) + 1);
+}
+
+static void
+shared_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
+{
+ HostMemoryBackendShared *shm = MEMORY_BACKEND_SHARED(backend);
+
+ if (!backend->size) {
+ error_setg(errp, "can't create backend with size 0");
+ return;
+ }
+
+ if (!memory_region_size(&backend->mr)) {
+ if (shm->master) {
+ backend->force_prealloc = mem_prealloc;
+ memory_region_init_ram_from_file(&backend->mr, OBJECT(backend),
+ object_get_canonical_path(OBJECT(backend)),
+ backend->size, true,
+ shm->mem_path, errp);
+ multi_socket_add_reg_handler(shm->ms, shm_send_fd, shm);
+ } else {
+ backend->force_prealloc = mem_prealloc;
+
+ /*
+ * Initialize only the main fields
+ * the rest is initialized when the fd is received
+ */
+ memory_region_init(&backend->mr, OBJECT(backend),
+ object_get_canonical_path(OBJECT(backend)),
+ backend->size);
+
+ multi_socket_add_handler(shm->ms, "send_fd",
+ set_shared_memory, shm);
+ }
+ }
+}
+
+static void
+shared_memory_backend_complete(UserCreatable *uc, Error **errp)
+{
+ HostMemoryBackend *hm = MEMORY_BACKEND(uc);
+ HostMemoryBackendShared *shm = MEMORY_BACKEND_SHARED(uc);
+ HostMemoryBackendClass *bc = MEMORY_BACKEND_GET_CLASS(uc);
+ HostMemoryBackendSharedClass *bsc = MEMORY_BACKEND_SHARED_GET_CLASS(uc);
+
+ if (shm->master) {
+ bsc->parent_complete(uc, errp);
+ } else {
+ bc->alloc(hm, errp);
+ }
+}
+
+static void shared_backend_class_init(ObjectClass *oc, void *data)
+{
+ UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
+ HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc);
+ HostMemoryBackendSharedClass *bsc = MEMORY_BACKEND_SHARED_CLASS(oc);
+
+ bc->alloc = shared_backend_memory_alloc;
+ bsc->parent_complete = ucc->complete;
+ bsc->map = shm_map;
+ ucc->complete = shared_memory_backend_complete;
+}
+
+static char *get_mem_path(Object *o, Error **errp)
+{
+ HostMemoryBackendShared *backend = MEMORY_BACKEND_SHARED(o);
+
+ return g_strdup(backend->mem_path);
+}
+
+static void set_mem_path(Object *o, const char *str, Error **errp)
+{
+ HostMemoryBackend *backend = MEMORY_BACKEND(o);
+ HostMemoryBackendShared *shm = MEMORY_BACKEND_SHARED(o);
+
+ if (memory_region_size(&backend->mr)) {
+ error_setg(errp, "cannot change property value");
+ return;
+ }
+ g_free(shm->mem_path);
+
+ shm->mem_path = g_strdup(str);
+}
+
+static bool get_master(Object *o, Error **errp)
+{
+ HostMemoryBackendShared *shm = MEMORY_BACKEND_SHARED(o);
+
+ return shm->master;
+}
+
+static void set_master(Object *o, bool value, Error **errp)
+{
+ HostMemoryBackendShared *shm = MEMORY_BACKEND_SHARED(o);
+
+ shm->master = value;
+}
+
+static void shared_backend_instance_init(Object *o)
+{
+ HostMemoryBackendShared *shm = MEMORY_BACKEND_SHARED(o);
+
+ object_property_add_bool(o, "master", get_master,
+ set_master, NULL);
+ object_property_add_str(o, "mem-path", get_mem_path,
+ set_mem_path, NULL);
+ object_property_add_link(o, "socket", TYPE_MULTI_SOCKET_BACKEND,
+ (Object **)&shm->ms,
+ object_property_allow_set_link,
+ OBJ_PROP_LINK_UNREF_ON_RELEASE,
+ &error_abort);
+}
+
+static const TypeInfo shared_backend_info = {
+ .name = TYPE_MEMORY_BACKEND_SHARED,
+ .parent = TYPE_MEMORY_BACKEND,
+ .class_init = shared_backend_class_init,
+ .class_size = sizeof(HostMemoryBackendSharedClass),
+ .instance_init = shared_backend_instance_init,
+ .instance_size = sizeof(HostMemoryBackendShared),
+};
+
+static void register_types(void)
+{
+ type_register_static(&shared_backend_info);
+}
+
+type_init(register_types);
new file mode 100644
@@ -0,0 +1,66 @@
+/*
+ * QEMU Host Memory Backend for hugetlbfs
+ *
+ * Copyright (C) 2015 - Virtual Open Systems
+ *
+ * Author: Baptiste Reynal <b.reynal@virtualopensystems.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_HM_H
+#define QEMU_HM_H
+
+#include "qemu-common.h"
+#include "sysemu/hostmem.h"
+#include "sysemu/sysemu.h"
+#include "qemu/multi-socket.h"
+#include "qom/object_interfaces.h"
+#include "qapi-visit.h"
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <fcntl.h>
+
+typedef struct HostMemoryBackendShared HostMemoryBackendShared;
+typedef struct HostMemoryBackendSharedClass HostMemoryBackendSharedClass;
+
+struct HostMemoryBackendShared {
+ HostMemoryBackend parent_obj;
+
+ bool master;
+
+ char *mem_path;
+
+ int event;
+ int fd;
+
+ EventNotifier *levent;
+
+ MSBackend *ms;
+ MemoryRegion shared_region;
+};
+
+struct HostMemoryBackendSharedClass {
+ HostMemoryBackendClass parent_class;
+
+ void (*parent_complete)(UserCreatable *uc, Error **errp);
+ void (*map)(HostMemoryBackendShared *shm, size_t size, off_t offset);
+};
+
+#define TYPE_MEMORY_BACKEND_SHARED "memory-backend-shared"
+
+#define MEMORY_BACKEND_SHARED(obj) \
+ OBJECT_CHECK(HostMemoryBackendShared, (obj), TYPE_MEMORY_BACKEND_SHARED)
+#define MEMORY_BACKEND_SHARED_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(HostMemoryBackendSharedClass, (obj), \
+ TYPE_MEMORY_BACKEND_SHARED)
+#define MEMORY_BACKEND_SHARED_CLASS(klass) \
+ OBJECT_CLASS_CHECK(HostMemoryBackendSharedClass, (klass), \
+ TYPE_MEMORY_BACKEND_SHARED)
+#define IS_MEMORY_BACKEND_SHARED(obj) \
+ object_dynamic_cast(OBJECT(obj), TYPE_MEMORY_BACKEND_SHARED)
+
+#endif
This patch introduces a shared memory backend, allowing to share memory between a master and many slaves. The memory is implemented using hugetlbfs, and relies on the multi-socket backend to share informations (size and offset for the slaves). Instantiation on the master: -object memory-backend-shared,id=<id>,size=<memory_sizeK,M,G>, chardev=<multi-socket_id>,master=on Instantiation on the slave: -object memory-backend-shared,id=<id>,size=<slave_memory_sizeK,M,G>, chardev=<multi-socket_id>,master=off Memory size on the slave can be smaller than on master. The master will send to the slave the size and the offset of the memory segment it can allocate in the total shared memory. Signed-off-by: Baptiste Reynal <b.reynal@virtualopensystems.com> --- backends/Makefile.objs | 2 +- backends/hostmem-shared.c | 192 ++++++++++++++++++++++++++++++++++++++++ include/sysemu/hostmem-shared.h | 66 ++++++++++++++ 3 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 backends/hostmem-shared.c create mode 100644 include/sysemu/hostmem-shared.h