[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 07/27] add memdev backend infrastructure
From: |
Igor Mammedov |
Subject: |
[Qemu-devel] [PATCH 07/27] add memdev backend infrastructure |
Date: |
Thu, 21 Nov 2013 03:38:28 +0100 |
Provides framework for splitting host RAM allocation/
policies into a separate backend that could be used
by devices. It would allow to separate host specific
options from device model like it's done for netdev & co.
It adds new:
-memdev CLI option and corresponding memdev-add
QMP/HMP commands.
Upon successful command execution an new memdev object
is added to QOM tree into "/backend/memdev" container.
Initially only legacy RAM backend is provided, which
uses memory_region_init_ram() allocator and compatible
with every CLI option that affects memory_region_init_ram().
memdev object is intendend for usage with Dimm device,
example:
-memdev id=m1,size=1G -device dimm,id=dimm1,memdev=m1
Signed-off-by: Igor Mammedov <address@hidden>
---
backends/Makefile.objs | 2 +
backends/hostmem.c | 275 +++++++++++++++++++++++++++++++++++++++++
backends/hostmem_compat_ram.c | 42 ++++++
hmp-commands.hx | 13 ++
include/sysemu/hostmem.h | 102 +++++++++++++++
monitor.c | 1 +
qapi-schema.json | 18 +++
qemu-options.hx | 7 +
qmp-commands.hx | 27 ++++
vl.c | 14 ++
10 files changed, 501 insertions(+), 0 deletions(-)
create mode 100644 backends/hostmem.c
create mode 100644 backends/hostmem_compat_ram.c
create mode 100644 include/sysemu/hostmem.h
diff --git a/backends/Makefile.objs b/backends/Makefile.objs
index 42557d5..01c4476 100644
--- a/backends/Makefile.objs
+++ b/backends/Makefile.objs
@@ -6,3 +6,5 @@ common-obj-$(CONFIG_BRLAPI) += baum.o
$(obj)/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
common-obj-$(CONFIG_TPM) += tpm.o
+
+common-obj-y += hostmem.o hostmem_compat_ram.o
diff --git a/backends/hostmem.c b/backends/hostmem.c
new file mode 100644
index 0000000..9948b63
--- /dev/null
+++ b/backends/hostmem.c
@@ -0,0 +1,275 @@
+/*
+ * QEMU Host Memory Backend
+ *
+ * Copyright (C) 2013 Red Hat Inc
+ *
+ * Authors:
+ * Igor Mammedov <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "sysemu/hostmem.h"
+#include "sysemu/sysemu.h"
+#include "qapi/visitor.h"
+#include "qapi/qmp/qerror.h"
+#include "qemu/config-file.h"
+
+QemuOptsList qemu_memdev_opts = {
+ .name = "memdev",
+ .implied_opt_name = "type",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_memdev_opts.head),
+ .desc = {
+ { /* end of list */ }
+ },
+};
+
+static int set_object_prop(const char *name, const char *value, void *opaque)
+{
+ Error *local_err = NULL;
+ Object *obj = OBJECT(opaque);
+
+ object_property_parse(obj, value, name, &local_err);
+ if (error_is_set(&local_err)) {
+ qerror_report_err(local_err);
+ error_free(local_err);
+ return -1;
+ }
+ return 0;
+}
+
+void memdev_add(QemuOpts *opts, Error **errp)
+{
+ Error *local_err = NULL;
+ HostMemoryBackendClass *bc;
+ Object *obj = NULL;
+ ObjectClass *oc;
+ const char *type;
+
+ type = qemu_opt_get(opts, "type");
+ if (!type) {
+ type = TYPE_COMPAT_RAM_MEMORY_BACKEND;
+ }
+
+ oc = object_class_by_name(type);
+ if (!oc) {
+ error_setg(&local_err, "Unknown memdev type: %s", type);
+ goto out;
+ }
+ if (object_class_is_abstract(oc)) {
+ error_setg(&local_err, "Can't create abstract memdev type: %s", type);
+ goto out;
+ }
+
+ obj = object_new(type);
+ if (!object_dynamic_cast(obj, TYPE_MEMORY_BACKEND)) {
+ error_setg(&local_err, "Invalid memdev type: %s", type);
+ goto out;
+ }
+
+ if (qemu_opt_foreach(opts, set_object_prop, obj, true)) {
+ error_setg(&local_err, "failed to create memdev");
+ goto out;
+ }
+ object_property_parse(obj, qemu_opts_id(opts), "id", &local_err);
+ if (error_is_set(&local_err)) {
+ goto out;
+ }
+
+ /* verify properties correctnes and initialize backend */
+ bc = MEMORY_BACKEND_GET_CLASS(obj);
+ if (bc->get_memory) {
+ HostMemoryBackend *backend = MEMORY_BACKEND(obj);
+ if (!bc->get_memory(backend, &local_err)) {
+ goto out;
+ }
+ }
+
+ /* make backend available to the world via QOM tree */
+ object_property_add_child(container_get(qemu_get_backend(), "/memdev"),
+ qemu_opts_id(opts), obj, &local_err);
+
+out:
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ if (obj) {
+ object_unref(obj);
+ }
+ }
+}
+
+int qmp_memdev_add(Monitor *mon, const QDict *qdict, QObject **ret)
+{
+ Error *local_err = NULL;
+ QemuOptsList *opts_list;
+ QemuOpts *opts = NULL;
+
+ opts_list = qemu_find_opts_err("memdev", &local_err);
+ if (error_is_set(&local_err)) {
+ goto out;
+ }
+
+ opts = qemu_opts_from_qdict(opts_list, qdict, &local_err);
+ if (error_is_set(&local_err)) {
+ goto out;
+ }
+
+ memdev_add(opts, &local_err);
+
+out:
+ if (opts) {
+ qemu_opts_del(opts);
+ }
+ if (error_is_set(&local_err)) {
+ qerror_report_err(local_err);
+ error_free(local_err);
+ return -1;
+ }
+ return 0;
+}
+
+static void
+hostmemory_backend_get_size(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ HostMemoryBackend *backend = MEMORY_BACKEND(obj);
+ uint64_t value = backend->size;
+
+ visit_type_size(v, &value, name, errp);
+}
+
+static void
+hostmemory_backend_set_size(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ HostMemoryBackend *backend = MEMORY_BACKEND(obj);
+ uint64_t value;
+
+ visit_type_size(v, &value, name, errp);
+ if (error_is_set(errp)) {
+ return;
+ }
+ if (!value) {
+ error_setg(errp, "Property '%s.%s' doesn't take value '%" PRIu64 "'",
+ object_get_typename(obj), name , value);
+ return;
+ }
+ backend->size = value;
+}
+
+static void
+hostmemory_backend_get_id(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ HostMemoryBackend *backend = MEMORY_BACKEND(obj);
+
+ visit_type_str(v, &backend->id, name, errp);
+}
+
+static void
+hostmemory_backend_set_id(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ HostMemoryBackend *backend = MEMORY_BACKEND(obj);
+ Error *local_err = NULL;
+ Object *dup_obj;
+ char *str;
+
+ visit_type_str(v, &str, name, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ dup_obj = object_resolve_path(str, NULL);
+ if (dup_obj) {
+ error_setg(errp, "Duplicate property [%s.%s] value: '%s'",
+ object_get_typename(obj), name, str);
+ error_propagate(errp, local_err);
+ g_free(str);
+ return;
+ }
+
+ if (backend->id) {
+ g_free(backend->id);
+ }
+ backend->id = str;
+}
+
+static void hostmemory_backend_initfn(Object *obj)
+{
+ object_property_add(obj, "id", "string",
+ hostmemory_backend_get_id,
+ hostmemory_backend_set_id, NULL, NULL, NULL);
+ object_property_add(obj, "size", "int",
+ hostmemory_backend_get_size,
+ hostmemory_backend_set_size, NULL, NULL, NULL);
+}
+
+static void hostmemory_backend_finalize(Object *obj)
+{
+ HostMemoryBackend *backend = MEMORY_BACKEND(obj);
+
+ g_free(backend->id);
+ if (memory_region_size(&backend->mr)) {
+ memory_region_destroy(&backend->mr);
+ }
+}
+
+static void
+hostmemory_backend_memory_init(HostMemoryBackend *backend, Error **errp)
+{
+ error_setg(errp, "memory_init is not implemented for type [%s]",
+ object_get_typename(OBJECT(backend)));
+}
+
+static MemoryRegion *
+hostmemory_backend_get_memory(HostMemoryBackend *backend, Error **errp)
+{
+ HostMemoryBackendClass *bc = MEMORY_BACKEND_GET_CLASS(backend);
+ Object *obj = OBJECT(backend);
+ char *id = backend->id;
+
+ if (!id || (*id == '\0')) {
+ error_setg(errp, "Invalid property [%s.id] value: '%s'",
+ object_get_typename(obj), id ? id : "");
+ return NULL;
+ }
+
+ if (!backend->size) {
+ error_setg(errp, "Invalid property [%s.size] value: %" PRIu64,
+ object_get_typename(obj), backend->size);
+ return NULL;
+ }
+
+ bc->memory_init(backend, errp);
+
+ return memory_region_size(&backend->mr) ? &backend->mr : NULL;
+}
+
+static void
+hostmemory_backend_class_init(ObjectClass *oc, void *data)
+{
+ HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc);
+
+ bc->memory_init = hostmemory_backend_memory_init;
+ bc->get_memory = hostmemory_backend_get_memory;
+}
+
+static const TypeInfo hostmemory_backend_info = {
+ .name = TYPE_MEMORY_BACKEND,
+ .parent = TYPE_OBJECT,
+ .abstract = true,
+ .class_size = sizeof(HostMemoryBackendClass),
+ .class_init = hostmemory_backend_class_init,
+ .instance_size = sizeof(HostMemoryBackend),
+ .instance_init = hostmemory_backend_initfn,
+ .instance_finalize = hostmemory_backend_finalize,
+};
+
+static void register_types(void)
+{
+ type_register_static(&hostmemory_backend_info);
+}
+
+type_init(register_types);
diff --git a/backends/hostmem_compat_ram.c b/backends/hostmem_compat_ram.c
new file mode 100644
index 0000000..af1bbe0
--- /dev/null
+++ b/backends/hostmem_compat_ram.c
@@ -0,0 +1,42 @@
+/*
+ * QEMU Host Memory Backend
+ *
+ * Copyright (C) 2013 Red Hat Inc
+ *
+ * Authors:
+ * Igor Mammedov <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "sysemu/hostmem.h"
+
+static void
+compat_ram_backend_memory_init(HostMemoryBackend *backend, Error **errp)
+{
+ if (!memory_region_size(&backend->mr)) {
+ memory_region_init_ram(&backend->mr, OBJECT(backend),
+ backend->id, backend->size);
+ }
+}
+
+static void
+compat_ram_backend_class_init(ObjectClass *oc, void *data)
+{
+ HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc);
+
+ bc->memory_init = compat_ram_backend_memory_init;
+}
+
+static const TypeInfo compat_ram_backend_info = {
+ .name = TYPE_COMPAT_RAM_MEMORY_BACKEND,
+ .parent = TYPE_MEMORY_BACKEND,
+ .class_init = compat_ram_backend_class_init,
+};
+
+static void register_types(void)
+{
+ type_register_static(&compat_ram_backend_info);
+}
+
+type_init(register_types);
diff --git a/hmp-commands.hx b/hmp-commands.hx
index caae5ad..4f35ffa 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1719,3 +1719,16 @@ ETEXI
STEXI
@end table
ETEXI
+
+ {
+ .name = "memdev-add",
+ .args_type = "memdev:O",
+ .params = "id size",
+ .help = "add host memory",
+ .mhandler.cmd_new = qmp_memdev_add,
+ },
+
+STEXI
address@hidden memdev-add
address@hidden memdev-add
+Add host memory.
diff --git a/include/sysemu/hostmem.h b/include/sysemu/hostmem.h
new file mode 100644
index 0000000..7437712
--- /dev/null
+++ b/include/sysemu/hostmem.h
@@ -0,0 +1,102 @@
+/*
+ * QEMU Host Memory Backend
+ *
+ * Copyright (C) 2013 Red Hat Inc
+ *
+ * Authors:
+ * Igor Mammedov <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#ifndef QEMU_RAM_H
+#define QEMU_RAM_H
+
+#include "qom/object.h"
+#include "qapi/error.h"
+#include "exec/memory.h"
+#include "qemu/option.h"
+
+#define TYPE_MEMORY_BACKEND "host-memory"
+#define MEMORY_BACKEND(obj) \
+ OBJECT_CHECK(HostMemoryBackend, (obj), TYPE_MEMORY_BACKEND)
+#define MEMORY_BACKEND_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(HostMemoryBackendClass, (obj), TYPE_MEMORY_BACKEND)
+#define MEMORY_BACKEND_CLASS(klass) \
+ OBJECT_CLASS_CHECK(HostMemoryBackendClass, (klass), TYPE_MEMORY_BACKEND)
+
+typedef struct HostMemoryBackend HostMemoryBackend;
+typedef struct HostMemoryBackendClass HostMemoryBackendClass;
+
+/**
+ * HostMemoryBackendClass:
+ * @parent_class: opaque parent class container
+ * @memory_init: hook for derived classes to perform memory allocation
+ * @get_memory: get #MemoryRegion backed by @backend and link @backend
+ * with user @uobj to prevent backend disapearing while @uobj exists.
+ * @uobj must have "backend" link property or @get_memory will fail.
+ * retuns: pointer to intialized #MemoryRegion on success or
+ * NULL on failure with error set in errp
+ *
+ */
+struct HostMemoryBackendClass {
+ ObjectClass parent_class;
+
+ void (*memory_init)(HostMemoryBackend *backend, Error **errp);
+ MemoryRegion* (*get_memory)(HostMemoryBackend *backend, Error **errp);
+};
+
+/**
+ * @HostMemoryBackend
+ *
+ * @parent: opaque parent object container
+ * @size: amount of memory backend provides
+ * @id: unique identification string in memdev namespace
+ * @mr: MemoryRegion representing host memory belonging to backend
+ */
+struct HostMemoryBackend {
+ /* private */
+ Object parent;
+
+ /* protected */
+ char *id;
+ uint64_t size;
+
+ MemoryRegion mr;
+};
+
+extern QemuOptsList qemu_memdev_opts;
+
+/**
+ * @qmp_memdev_add:
+ * QMP/HMP memdev-add command handler
+ * returns 0 on success or -1 on failure
+ */
+int qmp_memdev_add(Monitor *mon, const QDict *qdict, QObject **ret);
+
+/**
+ * @memdev_add:
+ * CLI "-memdev" option parser
+ * @opts: options for accossiated with -memdev
+ * @errp: returns an error if this function fails
+ */
+void memdev_add(QemuOpts *opts, Error **errp);
+
+/**
+ * @memdev_name:
+ * @id: backend identification string
+ *
+ * returns backend name in format "memdev[id]",
+ * caller is responsible for freeing returned value.
+ */
+char *memdev_name(const char *id);
+
+/* hostmem_compat_ram.c */
+/**
+ * @TYPE_COMPAT_RAM_MEMORY_BACKEND:
+ * name of backend that uses legacy RAM allocation methods
+ * implemented by #memory_region_init_ram
+ */
+#define TYPE_COMPAT_RAM_MEMORY_BACKEND "compat-ram-host-memory"
+
+#endif
diff --git a/monitor.c b/monitor.c
index 845f608..39b4d8b 100644
--- a/monitor.c
+++ b/monitor.c
@@ -67,6 +67,7 @@
#include "qmp-commands.h"
#include "hmp.h"
#include "qemu/thread.h"
+#include "sysemu/hostmem.h"
/* for pic/irq_info */
#if defined(TARGET_SPARC)
diff --git a/qapi-schema.json b/qapi-schema.json
index 76c98a7..c1a20d2 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -4212,3 +4212,21 @@
# Since: 1.7
##
{ 'command': 'blockdev-add', 'data': { 'options': 'BlockdevOptions' } }
+
+##
+# @memdev_add:
+#
+# Add a host memory backend.
+#
+# @id: the name of the new memory backend
+# @size: amount of memory backend should allocate
+# @type: backend type. [default: compat-ram-host-memory]
+#
+# Since: 1.8
+#
+# Returns: Nothing on success
+##
+{ 'command': 'memdev-add',
+ 'data': {'id': 'str', 'size': 'size', '*type': 'str'},
+ 'gen': 'no'
+}
diff --git a/qemu-options.hx b/qemu-options.hx
index fe4559b..314b731 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3125,3 +3125,10 @@ HXCOMM This is the last statement. Insert new options
before this line!
STEXI
@end table
ETEXI
+
+DEF("memdev", HAS_ARG, QEMU_OPTION_memdev,
+ "-memdev [backend-type,]id=str,size=value\n"
+ " add host memory\n"
+ " default backend-type: compat-ram-host-memory\n",
+ QEMU_ARCH_ALL)
+STEXI
diff --git a/qmp-commands.hx b/qmp-commands.hx
index fba15cd..f2a8998 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3291,7 +3291,34 @@ Example (2):
}
}
}
+<- { "return": {} }
+
+EQMP
+
+ {
+ .name = "memdev-add",
+ .args_type = "memdev:O",
+ .mhandler.cmd_new = qmp_memdev_add,
+ },
+
+SQMP
+memdev-add
+----------
+
+Add host memory.
+
+Arguments:
+
+- "id": the device's ID, must be unique (json-string)
+- "size": amount of memory backend should allocate (json-int)
+- "type": backend type (json-string, optional), default: compat-ram-host-memory
+
+Example:
+-> { "execute": "memdev-add",
+ "arguments": { "id": "memdev1",
+ "size": "1G",
+ "type": "compat-ram-host-memory" } }
<- { "return": {} }
EQMP
diff --git a/vl.c b/vl.c
index 1de3d57..2e3a5a5 100644
--- a/vl.c
+++ b/vl.c
@@ -170,6 +170,7 @@ int main(int argc, char **argv)
#include "ui/qemu-spice.h"
#include "qapi/string-input-visitor.h"
+#include "sysemu/hostmem.h"
//#define DEBUG_NET
//#define DEBUG_SLIRP
@@ -2929,6 +2930,7 @@ int main(int argc, char **argv, char **envp)
qemu_add_opts(&qemu_realtime_opts);
qemu_add_opts(&qemu_msg_opts);
qemu_add_opts(&qemu_mem_opts);
+ qemu_add_opts(&qemu_memdev_opts);
runstate_init();
@@ -3859,6 +3861,18 @@ int main(int argc, char **argv, char **envp)
}
configure_msg(opts);
break;
+ case QEMU_OPTION_memdev:
+ {
+ Error *local_err = NULL;
+ opts = qemu_opts_parse(qemu_find_opts("memdev"), optarg,
1);
+ memdev_add(opts, &local_err);
+ if (error_is_set(&local_err)) {
+ qerror_report_err(local_err);
+ error_free(local_err);
+ exit(1);
+ }
+ break;
+ }
default:
os_parse_cmd_args(popt->index, optarg);
}
--
1.7.1
- [Qemu-devel] [PATCH 05/27] qapi: add SIZE type parser to string_input_visitor, (continued)
- [Qemu-devel] [PATCH 05/27] qapi: add SIZE type parser to string_input_visitor, Igor Mammedov, 2013/11/20
- Re: [Qemu-devel] [PATCH 05/27] qapi: add SIZE type parser to string_input_visitor, Markus Armbruster, 2013/11/21
- Re: [Qemu-devel] [PATCH 05/27] qapi: add SIZE type parser to string_input_visitor, Igor Mammedov, 2013/11/25
- Re: [Qemu-devel] [PATCH 05/27] qapi: add SIZE type parser to string_input_visitor, Michael S. Tsirkin, 2013/11/25
- Re: [Qemu-devel] [PATCH 05/27] qapi: add SIZE type parser to string_input_visitor, Paolo Bonzini, 2013/11/25
- Re: [Qemu-devel] [PATCH 05/27] qapi: add SIZE type parser to string_input_visitor, Eric Blake, 2013/11/25
- Re: [Qemu-devel] [PATCH 05/27] qapi: add SIZE type parser to string_input_visitor, Paolo Bonzini, 2013/11/25
- Re: [Qemu-devel] [PATCH 05/27] qapi: add SIZE type parser to string_input_visitor, Markus Armbruster, 2013/11/27
- Re: [Qemu-devel] [PATCH 05/27] qapi: add SIZE type parser to string_input_visitor, Paolo Bonzini, 2013/11/27
[Qemu-devel] [PATCH 06/27] get reference to /backend container via qemu_get_backend(), Igor Mammedov, 2013/11/20
[Qemu-devel] [PATCH 07/27] add memdev backend infrastructure,
Igor Mammedov <=
- Re: [Qemu-devel] [PATCH 07/27] add memdev backend infrastructure, Paolo Bonzini, 2013/11/25
- Re: [Qemu-devel] [PATCH 07/27] add memdev backend infrastructure, Igor Mammedov, 2013/11/25
- Re: [Qemu-devel] [PATCH 07/27] add memdev backend infrastructure, Paolo Bonzini, 2013/11/25
- Re: [Qemu-devel] [PATCH 07/27] add memdev backend infrastructure, Igor Mammedov, 2013/11/27
- Re: [Qemu-devel] [PATCH 07/27] add memdev backend infrastructure, Paolo Bonzini, 2013/11/27
- Re: [Qemu-devel] [PATCH 07/27] add memdev backend infrastructure, Igor Mammedov, 2013/11/27
Re: [Qemu-devel] [PATCH 07/27] add memdev backend infrastructure, Eric Blake, 2013/11/27
[Qemu-devel] [PATCH 08/27] dimm: implement dimm device abstraction, Igor Mammedov, 2013/11/20