From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:60387) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aj59T-0001Yi-W6 for qemu-devel@nongnu.org; Thu, 24 Mar 2016 09:18:17 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aj59S-00055v-56 for qemu-devel@nongnu.org; Thu, 24 Mar 2016 09:18:15 -0400 Received: from mail-wm0-x241.google.com ([2a00:1450:400c:c09::241]:35049) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aj59R-00055o-PW for qemu-devel@nongnu.org; Thu, 24 Mar 2016 09:18:14 -0400 Received: by mail-wm0-x241.google.com with SMTP id s187so2613368wme.2 for ; Thu, 24 Mar 2016 06:18:13 -0700 (PDT) From: Baptiste Reynal Date: Thu, 24 Mar 2016 14:16:40 +0100 Message-Id: <1458825402-9592-3-git-send-email-b.reynal@virtualopensystems.com> In-Reply-To: <1458825402-9592-1-git-send-email-b.reynal@virtualopensystems.com> References: <1458825402-9592-1-git-send-email-b.reynal@virtualopensystems.com> Subject: [Qemu-devel] [RFC 2/4] backend: shared memory over network backend List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: pbonzini@redhat.com, Jani.Kokkonen@huawei.com, tech@virtualopensystems.com, Claudio.Fontana@huawei.com, b.reynal@virtualopensystems.com 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=,size=, socket=,shared_size=,master Instantiation on the slave: -object memory-backend-network,id=,size=, 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 --- 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 + * + * 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 + * + * 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