[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