qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC 2/4] backend: shared memory over network backend


From: Baptiste Reynal
Subject: [Qemu-devel] [RFC 2/4] backend: shared memory over network backend
Date: Thu, 24 Mar 2016 14:16:40 +0100

This patch extends the shared memory backend with the capability to
share a memory region over the network.

On the master side, when a slave connects an mmio region is created and
each access is trapped and sent over the network through the multi-client
socket.

Instantiation on the master:
-object memory-backend-network,id=<id>,size=<memory_sizeK,M,G>,
    socket=<socket>,shared_size=<shared_sizeK,M,G>,master

Instantiation on the slave:
-object memory-backend-network,id=<id>,size=<memory_sizeK,M,H>,
    socket=<socket>

To allocate the memory, the master will start from (size - shared_size),
and search for an area of the slave size (round up to the power of 2).
It is meant to be coherent with the dma_alloc_coherent allocator.

Signed-off-by: Baptiste Reynal <address@hidden>
---
 backends/Makefile.objs           |   2 +-
 backends/hostmem-network.c       | 301 +++++++++++++++++++++++++++++++++++++++
 include/sysemu/hostmem-network.h |  79 ++++++++++
 3 files changed, 381 insertions(+), 1 deletion(-)
 create mode 100644 backends/hostmem-network.c
 create mode 100644 include/sysemu/hostmem-network.h

diff --git a/backends/Makefile.objs b/backends/Makefile.objs
index de76906..b66c097 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 hostmem-shared.o
+common-obj-$(CONFIG_LINUX) += hostmem-file.o hostmem-shared.o hostmem-network.o
 
 common-obj-y += multi-socket.o
diff --git a/backends/hostmem-network.c b/backends/hostmem-network.c
new file mode 100644
index 0000000..4317d63
--- /dev/null
+++ b/backends/hostmem-network.c
@@ -0,0 +1,301 @@
+/*
+ * QEMU Host Memory Backend over network
+ *
+ * Copyright (C) 2016 - Virtual Open Systems
+ *
+ * Author: Baptiste Reynal <address@hidden>
+ *
+ * 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-network.h"
+#include "migration/vmstate.h"
+#include "qapi-visit.h"
+
+static uint64_t socket_mmio_read(void *opaque, hwaddr addr, unsigned size)
+{
+    NMArea *area = opaque;
+    MSMessage message;
+    NMData nm_data;
+
+    nm_data.addr = addr;
+    nm_data.size = size;
+
+    strcpy(message.cmd, MBN_READ_CMD);
+    memcpy(message.payload, &nm_data, sizeof(NMData));
+
+    multi_socket_write_and_block_to(area->client, &message);
+
+    return area->nhm->last_read.data;
+}
+
+static void
+socket_mmio_write(void *opaque, hwaddr addr, uint64_t data, unsigned size)
+{
+    NMArea *area = opaque;
+    MSMessage message;
+    NMData nm_data;
+
+    nm_data.addr = addr;
+    nm_data.data = data;
+    nm_data.size = size;
+
+    strcpy(message.cmd, MBN_WRITE_CMD);
+    memcpy(message.payload, &nm_data, sizeof(NMData));
+
+    multi_socket_write_message_to(area->client, &message);
+}
+
+static const MemoryRegionOps socket_mmio_ops = {
+    .read = socket_mmio_read,
+    .write = socket_mmio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void
+network_memory_register(MSClient *c, const char *message, void *opaque)
+{
+    HostMemoryBackend *backend = MEMORY_BACKEND(opaque);
+    HostMemoryBackendNetwork *nhm = MEMORY_BACKEND_NETWORK(opaque);
+    NMArea *area, *new_area;
+    int hw_size = 1, size = *(int *) message;
+
+    /* Search for available space */
+    while (hw_size < size) {
+        hw_size <<= 1;
+    }
+
+    QLIST_FOREACH(area, &nhm->areas, next) {
+        if (!area->client && area->size >= hw_size) {
+            if (area->size > hw_size) {
+                new_area = g_new(NMArea, 1);
+                new_area->size = area->size - hw_size;
+                new_area->addr = area->addr + hw_size;
+                new_area->client = NULL;
+                new_area->nhm = nhm;
+
+                QLIST_INSERT_AFTER(area, new_area, next);
+            }
+
+            area->size = hw_size;
+            area->client = c;
+
+            break;
+        }
+    }
+
+    memory_region_init_io(&area->region,
+            OBJECT(opaque),
+            &socket_mmio_ops,
+            area,
+            "socket_region",
+            size
+    );
+
+    memory_region_add_subregion(&backend->mr, area->addr, &area->region);
+}
+
+static void
+network_memory_read_cb(MSClient *c, const char *message, void *opaque)
+{
+    HostMemoryBackendNetwork *nhm = opaque;
+    NMData *data = (NMData *) message;
+
+    memcpy(&nhm->last_read, message, sizeof(NMData));
+}
+
+static void
+network_memory_read(MSClient *c, const char *message, void *opaque)
+{
+    MSMessage nm_message;
+    NMData *data = (NMData *) message;
+    HostMemoryBackend *backend = MEMORY_BACKEND(opaque);
+
+    memcpy(&data->data, memory_region_get_ram_ptr(&backend->mr) + data->addr,
+            data->size);
+
+    strcpy(nm_message.cmd, MBN_READ_CMD);
+    memcpy(nm_message.payload, data, sizeof(NMData));
+
+    multi_socket_write_message_to(c, &nm_message);
+}
+
+static void
+network_memory_write(MSClient *c, const char *message, void *opaque)
+{
+    NMData *data = (NMData *) message;
+    HostMemoryBackend *backend = MEMORY_BACKEND(opaque);
+
+    memcpy(memory_region_get_ram_ptr(&backend->mr) + data->addr, &data->data,
+            data->size);
+}
+
+static void
+network_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
+{
+    HostMemoryBackendNetwork *shm = MEMORY_BACKEND_NETWORK(backend);
+    MSMessage message;
+
+    if (!backend->size) {
+        error_setg(errp, "can't create backend with size 0");
+        return;
+    }
+
+    if (!memory_region_size(&backend->mr)) {
+        backend->force_prealloc = mem_prealloc;
+        memory_region_init_ram(&backend->mr,
+                OBJECT(backend),
+                object_get_canonical_path(OBJECT(backend)),
+                backend->size,
+                errp);
+
+        if (shm->master) {
+            multi_socket_add_handler(shm->ms, MBN_REGISTER_CMD,
+                    network_memory_register, shm);
+            multi_socket_add_handler(shm->ms, MBN_READ_CMD,
+                    network_memory_read_cb, shm);
+        } else {
+            multi_socket_add_handler(shm->ms, MBN_READ_CMD,
+                    network_memory_read, shm);
+            multi_socket_add_handler(shm->ms, MBN_WRITE_CMD,
+                    network_memory_write, shm);
+
+            strcpy(message.cmd, MBN_REGISTER_CMD);
+            memcpy(message.payload, &backend->size, sizeof(int));
+
+            multi_socket_write_message_to(&shm->ms->listener, &message);
+        }
+    }
+
+    shm->levent = g_new(EventNotifier, 1);
+    event_notifier_init(shm->levent, 0);
+
+    shm->event = event_notifier_get_fd(shm->levent);
+}
+
+
+static void
+network_memory_backend_complete(UserCreatable *uc, Error **errp)
+{
+    HostMemoryBackend *hm = MEMORY_BACKEND(uc);
+    HostMemoryBackendNetwork *shm = MEMORY_BACKEND_NETWORK(uc);
+    HostMemoryBackendClass *bc = MEMORY_BACKEND_GET_CLASS(uc);
+    HostMemoryBackendNetworkClass *bnc = MEMORY_BACKEND_NETWORK_GET_CLASS(uc);
+
+    QLIST_INIT(&shm->areas);
+
+    NMArea *area = g_new(NMArea, 1);
+    area->size = shm->shared_size;
+    area->addr = hm->size - shm->shared_size;
+    area->client = NULL;
+    area->nhm = shm;
+
+    QLIST_INSERT_HEAD(&shm->areas, area, next);
+
+    if (shm->master) {
+        bnc->parent_complete(uc, errp);
+    } else {
+        bc->alloc(hm, errp);
+    }
+}
+
+static void ms_boot(HostMemoryBackendNetwork *nhm)
+{
+    event_notifier_set(nhm->levent);
+}
+
+static void network_backend_class_init(ObjectClass *oc, void *data)
+{
+    UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
+    HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc);
+    HostMemoryBackendNetworkClass *bnc = MEMORY_BACKEND_NETWORK_CLASS(oc);
+
+    bc->alloc = network_backend_memory_alloc;
+    bnc->parent_complete = ucc->complete;
+    bnc->boot = ms_boot;
+    ucc->complete = network_memory_backend_complete;
+}
+
+static bool get_master(Object *o, Error **errp)
+{
+    HostMemoryBackendNetwork *shm = MEMORY_BACKEND_NETWORK(o);
+
+    return shm->master;
+}
+
+static void set_master(Object *o, bool value, Error **errp)
+{
+    HostMemoryBackendNetwork *shm = MEMORY_BACKEND_NETWORK(o);
+
+    shm->master = value;
+}
+
+static void
+host_memory_backend_get_size(Object *obj, Visitor *v, void *opaque,
+                             const char *name, Error **errp)
+{
+    HostMemoryBackendNetwork *backend = MEMORY_BACKEND_NETWORK(obj);
+    uint64_t value = backend->shared_size;
+
+    visit_type_size(v, &value, name, errp);
+}
+
+static void
+host_memory_backend_set_size(Object *obj, Visitor *v, void *opaque,
+                             const char *name, Error **errp)
+{
+    HostMemoryBackend *backend = MEMORY_BACKEND(obj);
+    HostMemoryBackendNetwork *nhm = MEMORY_BACKEND_NETWORK(obj);
+    Error *local_err = NULL;
+    uint64_t value;
+
+    if (memory_region_size(&backend->mr)) {
+        error_setg(&local_err, "cannot change property value");
+        goto out;
+    }
+
+    visit_type_size(v, &value, name, &local_err);
+    if (local_err) {
+        goto out;
+    }
+    if (!value) {
+        error_setg(&local_err, "Property '%s.%s' doesn't take value '%"
+                   PRIu64 "'", object_get_typename(obj), name, value);
+        goto out;
+    }
+    nhm->shared_size = value;
+out:
+    error_propagate(errp, local_err);
+}
+
+static void network_backend_instance_init(Object *o)
+{
+    HostMemoryBackendNetwork *shm = MEMORY_BACKEND_NETWORK(o);
+
+    object_property_add_bool(o, "master", get_master, set_master, 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);
+    object_property_add(o, "shared-size", "int",
+            host_memory_backend_get_size,
+            host_memory_backend_set_size, NULL, NULL, NULL);
+}
+
+static const TypeInfo network_backend_info = {
+    .name = TYPE_MEMORY_BACKEND_NETWORK,
+    .parent = TYPE_MEMORY_BACKEND,
+    .class_init = network_backend_class_init,
+    .class_size = sizeof(HostMemoryBackendNetworkClass),
+    .instance_init = network_backend_instance_init,
+    .instance_size = sizeof(HostMemoryBackendNetwork),
+};
+
+static void register_types(void)
+{
+    type_register_static(&network_backend_info);
+}
+
+type_init(register_types);
diff --git a/include/sysemu/hostmem-network.h b/include/sysemu/hostmem-network.h
new file mode 100644
index 0000000..ffadad9
--- /dev/null
+++ b/include/sysemu/hostmem-network.h
@@ -0,0 +1,79 @@
+/*
+ * QEMU Host Memory Backend over network
+ *
+ * Copyright (C) 2016 - Virtual Open Systems
+ *
+ * Author: Baptiste Reynal <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_HMN_H
+#define QEMU_HMN_H
+
+#include "qemu-common.h"
+#include "sysemu/hostmem.h"
+#include "qom/object_interfaces.h"
+#include "qemu/multi-socket.h"
+#include "qemu/queue.h"
+
+#define MBN_REGISTER_CMD "nm-register"
+#define MBN_READ_CMD "nm-read"
+#define MBN_WRITE_CMD "nm-write"
+
+#define TYPE_MEMORY_BACKEND_NETWORK "memory-backend-network"
+
+#define MEMORY_BACKEND_NETWORK(obj) \
+    OBJECT_CHECK(HostMemoryBackendNetwork, (obj), TYPE_MEMORY_BACKEND_NETWORK)
+#define MEMORY_BACKEND_NETWORK_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(HostMemoryBackendNetworkClass, (obj), \
+            TYPE_MEMORY_BACKEND_NETWORK)
+#define MEMORY_BACKEND_NETWORK_CLASS(klass) \
+    OBJECT_CLASS_CHECK(HostMemoryBackendNetworkClass, (klass), \
+            TYPE_MEMORY_BACKEND_NETWORK)
+
+typedef struct HostMemoryBackendNetwork HostMemoryBackendNetwork;
+typedef struct HostMemoryBackendNetworkClass HostMemoryBackendNetworkClass;
+typedef struct NMData NMData;
+typedef struct NMArea NMArea;
+
+struct NMData {
+    hwaddr addr;
+    uint64_t data;
+    unsigned size;
+};
+
+struct NMArea {
+    unsigned size;
+    hwaddr addr;
+
+    MemoryRegion region;
+    MSClient *client;
+    HostMemoryBackendNetwork *nhm;
+
+    QLIST_ENTRY(NMArea) next;
+};
+
+struct HostMemoryBackendNetwork {
+    HostMemoryBackend parent_obj;
+
+    bool master;
+    int shared_size;
+    MSBackend *ms;
+
+    int event;
+    EventNotifier *levent;
+
+    NMData last_read;
+
+    QLIST_HEAD(areas_head, NMArea) areas;
+};
+
+struct HostMemoryBackendNetworkClass {
+    HostMemoryBackendClass parent_class;
+
+    void (*parent_complete)(UserCreatable *uc, Error **errp);
+    void (*boot)(HostMemoryBackendNetwork *nhm);
+};
+#endif
-- 
2.7.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]