Signed-off-by: Hu Tao <hu...@cn.fujitsu.com> --- backends/hostmem.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++-- include/sysemu/hostmem.h | 4 ++ qapi-schema.json | 20 ++++++++++ 3 files changed, 118 insertions(+), 3 deletions(-)
diff --git a/backends/hostmem.c b/backends/hostmem.c index 0bd3900..077e8cc 100644 --- a/backends/hostmem.c +++ b/backends/hostmem.c @@ -10,11 +10,14 @@ * See the COPYING file in the top-level directory. */ #include "sysemu/hostmem.h" -#include "sysemu/sysemu.h" #include "qapi/visitor.h" +#include "qapi-visit.h" #include "qapi/qmp/qerror.h" #include "qemu/config-file.h" #include "qom/object_interfaces.h" +#ifdef CONFIG_NUMA +#include <numaif.h> +#endif static void hostmemory_backend_get_size(Object *obj, Visitor *v, void *opaque, @@ -50,11 +53,85 @@ hostmemory_backend_set_size(Object *obj, Visitor *v, void *opaque, backend->size = value; } +static void +get_host_nodes(Object *obj, Visitor *v, void *opaque, const char *name, + Error **errp) +{ + HostMemoryBackend *backend = MEMORY_BACKEND(obj); + uint16List *host_nodes = NULL; + uint16List **node = &host_nodes; + unsigned long value; + + value = find_first_bit(backend->host_nodes, MAX_NODES); + if (value == MAX_NODES) { + return; + } + + *node = g_malloc0(sizeof(**node)); + (*node)->value = value; + node = &(*node)->next; + + do { + value = find_next_bit(backend->host_nodes, MAX_NODES, value + 1); + if (value == MAX_NODES) { + break; + } + + *node = g_malloc0(sizeof(**node)); + (*node)->value = value; + node = &(*node)->next; + } while (true); + + visit_type_uint16List(v, &host_nodes, name, errp); +} + +static void +set_host_nodes(Object *obj, Visitor *v, void *opaque, const char *name, + Error **errp) +{ + HostMemoryBackend *backend = MEMORY_BACKEND(obj); + uint16List *l = NULL; + + visit_type_uint16List(v, &l, name, errp); + + while (l) { + bitmap_set(backend->host_nodes, l->value, 1); + l = l->next; + } +} + +static void +get_policy(Object *obj, Visitor *v, void *opaque, const char *name, + Error **errp) +{ + HostMemoryBackend *backend = MEMORY_BACKEND(obj); + int policy = backend->policy; + + visit_type_enum(v, &policy, HostMemPolicy_lookup, NULL, name, errp); +} + +static void +set_policy(Object *obj, Visitor *v, void *opaque, const char *name, + Error **errp) +{ + HostMemoryBackend *backend = MEMORY_BACKEND(obj); + int policy; + + visit_type_enum(v, &policy, HostMemPolicy_lookup, NULL, name, errp); + backend->policy = policy; +} + static void hostmemory_backend_initfn(Object *obj) { object_property_add(obj, "size", "int", hostmemory_backend_get_size, hostmemory_backend_set_size, NULL, NULL, NULL); + object_property_add(obj, "host-nodes", "int", + get_host_nodes, + set_host_nodes, NULL, NULL, NULL); + object_property_add(obj, "policy", "str", + get_policy, + set_policy, NULL, NULL, NULL); } static void hostmemory_backend_finalize(Object *obj) @@ -69,8 +146,22 @@ static void hostmemory_backend_finalize(Object *obj) static void hostmemory_backend_memory_init(UserCreatable *uc, Error **errp) { - error_setg(errp, "memory_init is not implemented for type [%s]", - object_get_typename(OBJECT(uc))); +#ifdef CONFIG_NUMA + HostMemoryBackend *backend = MEMORY_BACKEND(uc); + void *p = memory_region_get_ram_ptr(&backend->mr); + unsigned long maxnode = find_last_bit(backend->host_nodes, MAX_NODES); + + /* This is a workaround for a long standing bug in Linux' + * mbind implementation, which cuts off the last specified + * node. + */ + if (mbind(p, backend->size, backend->policy, backend->host_nodes, + maxnode + 2, 0)) { + error_setg_errno(errp, errno, + "cannot bind memory to host NUMA nodes\n"); + return; + } +#endif } MemoryRegion * diff --git a/include/sysemu/hostmem.h b/include/sysemu/hostmem.h index bc3ffb3..a2b0702 100644 --- a/include/sysemu/hostmem.h +++ b/include/sysemu/hostmem.h @@ -12,10 +12,12 @@ #ifndef QEMU_RAM_H #define QEMU_RAM_H +#include "sysemu/sysemu.h" /* for MAX_NODES */ #include "qom/object.h" #include "qapi/error.h" #include "exec/memory.h" #include "qemu/option.h" +#include "qemu/bitmap.h" #define TYPE_MEMORY_BACKEND "memory" #define MEMORY_BACKEND(obj) \ @@ -50,6 +52,8 @@ struct HostMemoryBackend { /* protected */ uint64_t size; + DECLARE_BITMAP(host_nodes, MAX_NODES); + HostMemPolicy policy; MemoryRegion mr; }; diff --git a/qapi-schema.json b/qapi-schema.json index 62e0b83..86b78a5 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -4554,3 +4554,23 @@ '*cpus': ['uint16'], '*mem': 'size', '*memdev': 'str' }} + +## +# @HostMemPolicy +# +# Host memory policy types +# +# @default: restore default policy, remove any nondefault policy +# +# @preferred: set the preferred host nodes for allocation +# +# @membind: a strict policy that restricts memory allocation to the +# host nodes specified +# +# @interleave: memory allocations are interleaved across the set +# of host nodes specified +# +# Since 2.1 +## +{ 'enum': 'HostMemPolicy', + 'data': [ 'default', 'preferred', 'membind', 'interleave' ] } -- 1.8.5.2.229.g4448466