diff mbox

[RFC,v2,1/6] backend: shared memory backend

Message ID 1458292438-13909-2-git-send-email-b.reynal@virtualopensystems.com
State New, archived
Headers show

Commit Message

Baptiste Reynal March 18, 2016, 9:13 a.m. UTC
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
diff mbox

Patch

diff --git a/backends/Makefile.objs b/backends/Makefile.objs
index 689eac3..de76906 100644
--- a/backends/Makefile.objs
+++ b/backends/Makefile.objs
@@ -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
diff --git a/backends/hostmem-shared.c b/backends/hostmem-shared.c
new file mode 100644
index 0000000..b45a87b
--- /dev/null
+++ b/backends/hostmem-shared.c
@@ -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);
diff --git a/include/sysemu/hostmem-shared.h b/include/sysemu/hostmem-shared.h
new file mode 100644
index 0000000..7db3b37
--- /dev/null
+++ b/include/sysemu/hostmem-shared.h
@@ -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