aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backends/hostmem-memfd.c9
-rw-r--r--backends/hostmem.c14
-rw-r--r--include/monitor/monitor.h3
-rw-r--r--include/qemu/cutils.h12
-rw-r--r--monitor.c16
-rw-r--r--qdev-monitor.c32
-rw-r--r--qom/object.c9
-rw-r--r--qom/object_interfaces.c6
-rw-r--r--tests/check-qom-proplist.c58
-rw-r--r--util/cutils.c5
-rw-r--r--util/qemu-option.c71
-rw-r--r--vl.c53
12 files changed, 228 insertions, 60 deletions
diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c
index 3800bd0..b6836b2 100644
--- a/backends/hostmem-memfd.c
+++ b/backends/hostmem-memfd.c
@@ -145,16 +145,25 @@ memfd_backend_class_init(ObjectClass *oc, void *data)
memfd_backend_get_hugetlb,
memfd_backend_set_hugetlb,
&error_abort);
+ object_class_property_set_description(oc, "hugetlb",
+ "Use huge pages",
+ &error_abort);
object_class_property_add(oc, "hugetlbsize", "int",
memfd_backend_get_hugetlbsize,
memfd_backend_set_hugetlbsize,
NULL, NULL, &error_abort);
+ object_class_property_set_description(oc, "hugetlbsize",
+ "Huge pages size (ex: 2M, 1G)",
+ &error_abort);
}
if (qemu_memfd_check(MFD_ALLOW_SEALING)) {
object_class_property_add_bool(oc, "seal",
memfd_backend_get_seal,
memfd_backend_set_seal,
&error_abort);
+ object_class_property_set_description(oc, "seal",
+ "Seal growing & shrinking",
+ &error_abort);
}
}
diff --git a/backends/hostmem.c b/backends/hostmem.c
index 4908946..1a89342 100644
--- a/backends/hostmem.c
+++ b/backends/hostmem.c
@@ -397,27 +397,41 @@ host_memory_backend_class_init(ObjectClass *oc, void *data)
object_class_property_add_bool(oc, "merge",
host_memory_backend_get_merge,
host_memory_backend_set_merge, &error_abort);
+ object_class_property_set_description(oc, "merge",
+ "Mark memory as mergeable", &error_abort);
object_class_property_add_bool(oc, "dump",
host_memory_backend_get_dump,
host_memory_backend_set_dump, &error_abort);
+ object_class_property_set_description(oc, "dump",
+ "Set to 'off' to exclude from core dump", &error_abort);
object_class_property_add_bool(oc, "prealloc",
host_memory_backend_get_prealloc,
host_memory_backend_set_prealloc, &error_abort);
+ object_class_property_set_description(oc, "prealloc",
+ "Preallocate memory", &error_abort);
object_class_property_add(oc, "size", "int",
host_memory_backend_get_size,
host_memory_backend_set_size,
NULL, NULL, &error_abort);
+ object_class_property_set_description(oc, "size",
+ "Size of the memory region (ex: 500M)", &error_abort);
object_class_property_add(oc, "host-nodes", "int",
host_memory_backend_get_host_nodes,
host_memory_backend_set_host_nodes,
NULL, NULL, &error_abort);
+ object_class_property_set_description(oc, "host-nodes",
+ "Binds memory to the list of NUMA host nodes", &error_abort);
object_class_property_add_enum(oc, "policy", "HostMemPolicy",
&HostMemPolicy_lookup,
host_memory_backend_get_policy,
host_memory_backend_set_policy, &error_abort);
+ object_class_property_set_description(oc, "policy",
+ "Set the NUMA policy", &error_abort);
object_class_property_add_bool(oc, "share",
host_memory_backend_get_share, host_memory_backend_set_share,
&error_abort);
+ object_class_property_set_description(oc, "share",
+ "Mark the memory as private to QEMU or shared", &error_abort);
}
static const TypeInfo host_memory_backend_info = {
diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 2ef5e04..6fd2c53 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -47,4 +47,7 @@ int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd);
void monitor_fdset_dup_fd_remove(int dup_fd);
int monitor_fdset_dup_fd_find(int dup_fd);
+void monitor_vfprintf(FILE *stream,
+ const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0);
+
#endif /* MONITOR_H */
diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h
index 47aaa3b..7071bfe 100644
--- a/include/qemu/cutils.h
+++ b/include/qemu/cutils.h
@@ -169,4 +169,16 @@ bool test_buffer_is_zero_next_accel(void);
int uleb128_encode_small(uint8_t *out, uint32_t n);
int uleb128_decode_small(const uint8_t *in, uint32_t *n);
+/**
+ * qemu_pstrcmp0:
+ * @str1: a non-NULL pointer to a C string (*str1 can be NULL)
+ * @str2: a non-NULL pointer to a C string (*str2 can be NULL)
+ *
+ * Compares *str1 and *str2 with g_strcmp0().
+ *
+ * Returns: an integer less than, equal to, or greater than zero, if
+ * *str1 is <, == or > than *str2.
+ */
+int qemu_pstrcmp0(const char **str1, const char **str2);
+
#endif
diff --git a/monitor.c b/monitor.c
index c4677b5..b9258a7 100644
--- a/monitor.c
+++ b/monitor.c
@@ -4493,19 +4493,29 @@ static void monitor_readline_flush(void *opaque)
}
/*
- * Print to current monitor if we have one, else to stderr.
+ * Print to current monitor if we have one, else to stream.
* TODO should return int, so callers can calculate width, but that
* requires surgery to monitor_vprintf(). Left for another day.
*/
-void error_vprintf(const char *fmt, va_list ap)
+void monitor_vfprintf(FILE *stream, const char *fmt, va_list ap)
{
if (cur_mon && !monitor_cur_is_qmp()) {
monitor_vprintf(cur_mon, fmt, ap);
} else {
- vfprintf(stderr, fmt, ap);
+ vfprintf(stream, fmt, ap);
}
}
+/*
+ * Print to current monitor if we have one, else to stderr.
+ * TODO should return int, so callers can calculate width, but that
+ * requires surgery to monitor_vprintf(). Left for another day.
+ */
+void error_vprintf(const char *fmt, va_list ap)
+{
+ monitor_vfprintf(stderr, fmt, ap);
+}
+
void error_vprintf_unless_qmp(const char *fmt, va_list ap)
{
if (cur_mon && !monitor_cur_is_qmp()) {
diff --git a/qdev-monitor.c b/qdev-monitor.c
index 61e0300..802c18a 100644
--- a/qdev-monitor.c
+++ b/qdev-monitor.c
@@ -104,22 +104,31 @@ static bool qdev_class_has_alias(DeviceClass *dc)
return (qdev_class_get_alias(dc) != NULL);
}
+static void out_printf(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ monitor_vfprintf(stdout, fmt, ap);
+ va_end(ap);
+}
+
static void qdev_print_devinfo(DeviceClass *dc)
{
- error_printf("name \"%s\"", object_class_get_name(OBJECT_CLASS(dc)));
+ out_printf("name \"%s\"", object_class_get_name(OBJECT_CLASS(dc)));
if (dc->bus_type) {
- error_printf(", bus %s", dc->bus_type);
+ out_printf(", bus %s", dc->bus_type);
}
if (qdev_class_has_alias(dc)) {
- error_printf(", alias \"%s\"", qdev_class_get_alias(dc));
+ out_printf(", alias \"%s\"", qdev_class_get_alias(dc));
}
if (dc->desc) {
- error_printf(", desc \"%s\"", dc->desc);
+ out_printf(", desc \"%s\"", dc->desc);
}
if (!dc->user_creatable) {
- error_printf(", no-user");
+ out_printf(", no-user");
}
- error_printf("\n");
+ out_printf("\n");
}
static void qdev_print_devinfos(bool show_no_user)
@@ -155,8 +164,7 @@ static void qdev_print_devinfos(bool show_no_user)
continue;
}
if (!cat_printed) {
- error_printf("%s%s devices:\n", i ? "\n" : "",
- cat_name[i]);
+ out_printf("%s%s devices:\n", i ? "\n" : "", cat_name[i]);
cat_printed = true;
}
qdev_print_devinfo(dc);
@@ -278,13 +286,11 @@ int qdev_device_help(QemuOpts *opts)
}
for (prop = prop_list; prop; prop = prop->next) {
- error_printf("%s.%s=%s", driver,
- prop->value->name,
- prop->value->type);
+ out_printf("%s.%s=%s", driver, prop->value->name, prop->value->type);
if (prop->value->has_description) {
- error_printf(" (%s)\n", prop->value->description);
+ out_printf(" (%s)\n", prop->value->description);
} else {
- error_printf("\n");
+ out_printf("\n");
}
}
diff --git a/qom/object.c b/qom/object.c
index 9222b23..547dcf9 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -1115,7 +1115,7 @@ void object_class_property_iter_init(ObjectPropertyIterator *iter,
ObjectClass *klass)
{
g_hash_table_iter_init(&iter->iter, klass->properties);
- iter->nextclass = klass;
+ iter->nextclass = object_class_get_parent(klass);
}
ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name,
@@ -2430,9 +2430,10 @@ void object_class_property_set_description(ObjectClass *klass,
op->description = g_strdup(description);
}
-static void object_instance_init(Object *obj)
+static void object_class_init(ObjectClass *klass, void *data)
{
- object_property_add_str(obj, "type", qdev_get_type, NULL, NULL);
+ object_class_property_add_str(klass, "type", qdev_get_type,
+ NULL, &error_abort);
}
static void register_types(void)
@@ -2446,7 +2447,7 @@ static void register_types(void)
static TypeInfo object_info = {
.name = TYPE_OBJECT,
.instance_size = sizeof(Object),
- .instance_init = object_instance_init,
+ .class_init = object_class_init,
.abstract = true,
};
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
index 72b97a8..941fd63 100644
--- a/qom/object_interfaces.c
+++ b/qom/object_interfaces.c
@@ -141,14 +141,14 @@ Object *user_creatable_add_opts(QemuOpts *opts, Error **errp)
int user_creatable_add_opts_foreach(void *opaque, QemuOpts *opts, Error **errp)
{
- bool (*type_predicate)(const char *) = opaque;
+ bool (*type_opt_predicate)(const char *, QemuOpts *) = opaque;
Object *obj = NULL;
Error *err = NULL;
const char *type;
type = qemu_opt_get(opts, "qom-type");
- if (type && type_predicate &&
- !type_predicate(type)) {
+ if (type && type_opt_predicate &&
+ !type_opt_predicate(type, opts)) {
return 0;
}
diff --git a/tests/check-qom-proplist.c b/tests/check-qom-proplist.c
index 92898e1..a8b2958 100644
--- a/tests/check-qom-proplist.c
+++ b/tests/check-qom-proplist.c
@@ -125,10 +125,13 @@ static char *dummy_get_sv(Object *obj,
static void dummy_init(Object *obj)
{
+ Error *err = NULL;
+
object_property_add_bool(obj, "bv",
dummy_get_bv,
dummy_set_bv,
- NULL);
+ &err);
+ error_free_or_abort(&err);
}
@@ -517,32 +520,19 @@ static void test_dummy_getenum(void)
}
-static void test_dummy_iterator(void)
+static void test_dummy_prop_iterator(ObjectPropertyIterator *iter)
{
- Object *parent = object_get_objects_root();
- DummyObject *dobj = DUMMY_OBJECT(
- object_new_with_props(TYPE_DUMMY,
- parent,
- "dummy0",
- &error_abort,
- "bv", "yes",
- "sv", "Hiss hiss hiss",
- "av", "platypus",
- NULL));
-
+ bool seenbv = false, seensv = false, seenav = false, seentype = false;
ObjectProperty *prop;
- ObjectPropertyIterator iter;
- bool seenbv = false, seensv = false, seenav = false, seentype;
- object_property_iter_init(&iter, OBJECT(dobj));
- while ((prop = object_property_iter_next(&iter))) {
- if (g_str_equal(prop->name, "bv")) {
+ while ((prop = object_property_iter_next(iter))) {
+ if (!seenbv && g_str_equal(prop->name, "bv")) {
seenbv = true;
- } else if (g_str_equal(prop->name, "sv")) {
+ } else if (!seensv && g_str_equal(prop->name, "sv")) {
seensv = true;
- } else if (g_str_equal(prop->name, "av")) {
+ } else if (!seenav && g_str_equal(prop->name, "av")) {
seenav = true;
- } else if (g_str_equal(prop->name, "type")) {
+ } else if (!seentype && g_str_equal(prop->name, "type")) {
/* This prop comes from the base Object class */
seentype = true;
} else {
@@ -554,10 +544,35 @@ static void test_dummy_iterator(void)
g_assert(seenav);
g_assert(seensv);
g_assert(seentype);
+}
+
+static void test_dummy_iterator(void)
+{
+ Object *parent = object_get_objects_root();
+ DummyObject *dobj = DUMMY_OBJECT(
+ object_new_with_props(TYPE_DUMMY,
+ parent,
+ "dummy0",
+ &error_abort,
+ "bv", "yes",
+ "sv", "Hiss hiss hiss",
+ "av", "platypus",
+ NULL));
+ ObjectPropertyIterator iter;
+ object_property_iter_init(&iter, OBJECT(dobj));
+ test_dummy_prop_iterator(&iter);
object_unparent(OBJECT(dobj));
}
+static void test_dummy_class_iterator(void)
+{
+ ObjectPropertyIterator iter;
+ ObjectClass *klass = object_class_by_name(TYPE_DUMMY);
+
+ object_class_property_iter_init(&iter, klass);
+ test_dummy_prop_iterator(&iter);
+}
static void test_dummy_delchild(void)
{
@@ -629,6 +644,7 @@ int main(int argc, char **argv)
g_test_add_func("/qom/proplist/badenum", test_dummy_badenum);
g_test_add_func("/qom/proplist/getenum", test_dummy_getenum);
g_test_add_func("/qom/proplist/iterator", test_dummy_iterator);
+ g_test_add_func("/qom/proplist/class_iterator", test_dummy_class_iterator);
g_test_add_func("/qom/proplist/delchild", test_dummy_delchild);
g_test_add_func("/qom/resolve/partial", test_qom_partial_path);
diff --git a/util/cutils.c b/util/cutils.c
index 9205e09..698bd31 100644
--- a/util/cutils.c
+++ b/util/cutils.c
@@ -769,3 +769,8 @@ char *size_to_str(uint64_t val)
return g_strdup_printf("%0.3g %sB", (double)val / div, suffixes[i]);
}
+
+int qemu_pstrcmp0(const char **str1, const char **str2)
+{
+ return g_strcmp0(*str1, *str2);
+}
diff --git a/util/qemu-option.c b/util/qemu-option.c
index 01886ef..9a5f263 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -208,17 +208,51 @@ out:
return result;
}
+static const char *opt_type_to_string(enum QemuOptType type)
+{
+ switch (type) {
+ case QEMU_OPT_STRING:
+ return "str";
+ case QEMU_OPT_BOOL:
+ return "bool (on/off)";
+ case QEMU_OPT_NUMBER:
+ return "num";
+ case QEMU_OPT_SIZE:
+ return "size";
+ }
+
+ g_assert_not_reached();
+}
+
void qemu_opts_print_help(QemuOptsList *list)
{
QemuOptDesc *desc;
+ int i;
+ GPtrArray *array = g_ptr_array_new();
assert(list);
desc = list->desc;
while (desc && desc->name) {
- printf("%-16s %s\n", desc->name,
- desc->help ? desc->help : "No description available");
+ GString *str = g_string_new(NULL);
+ if (list->name) {
+ g_string_append_printf(str, "%s.", list->name);
+ }
+ g_string_append_printf(str, "%s=%s", desc->name,
+ opt_type_to_string(desc->type));
+ if (desc->help) {
+ g_string_append_printf(str, " - %s", desc->help);
+ }
+ g_ptr_array_add(array, g_string_free(str, false));
desc++;
}
+
+ g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
+ for (i = 0; i < array->len; i++) {
+ printf("%s\n", (char *)array->pdata[i]);
+ }
+ g_ptr_array_set_free_func(array, g_free);
+ g_ptr_array_free(array, true);
+
}
/* ------------------------------------------------------------------ */
@@ -486,7 +520,7 @@ int qemu_opt_unset(QemuOpts *opts, const char *name)
}
static void opt_set(QemuOpts *opts, const char *name, char *value,
- bool prepend, Error **errp)
+ bool prepend, bool *invalidp, Error **errp)
{
QemuOpt *opt;
const QemuOptDesc *desc;
@@ -496,6 +530,9 @@ static void opt_set(QemuOpts *opts, const char *name, char *value,
if (!desc && !opts_accepts_any(opts)) {
g_free(value);
error_setg(errp, QERR_INVALID_PARAMETER, name);
+ if (invalidp) {
+ *invalidp = true;
+ }
return;
}
@@ -519,7 +556,7 @@ static void opt_set(QemuOpts *opts, const char *name, char *value,
void qemu_opt_set(QemuOpts *opts, const char *name, const char *value,
Error **errp)
{
- opt_set(opts, name, g_strdup(value), false, errp);
+ opt_set(opts, name, g_strdup(value), false, NULL, errp);
}
void qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val,
@@ -750,7 +787,8 @@ void qemu_opts_print(QemuOpts *opts, const char *separator)
}
static void opts_do_parse(QemuOpts *opts, const char *params,
- const char *firstname, bool prepend, Error **errp)
+ const char *firstname, bool prepend,
+ bool *invalidp, Error **errp)
{
char *option = NULL;
char *value = NULL;
@@ -785,7 +823,7 @@ static void opts_do_parse(QemuOpts *opts, const char *params,
}
if (strcmp(option, "id") != 0) {
/* store and parse */
- opt_set(opts, option, value, prepend, &local_err);
+ opt_set(opts, option, value, prepend, invalidp, &local_err);
value = NULL;
if (local_err) {
error_propagate(errp, local_err);
@@ -814,11 +852,12 @@ static void opts_do_parse(QemuOpts *opts, const char *params,
void qemu_opts_do_parse(QemuOpts *opts, const char *params,
const char *firstname, Error **errp)
{
- opts_do_parse(opts, params, firstname, false, errp);
+ opts_do_parse(opts, params, firstname, false, NULL, errp);
}
static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
- bool permit_abbrev, bool defaults, Error **errp)
+ bool permit_abbrev, bool defaults,
+ bool *invalidp, Error **errp)
{
const char *firstname;
char *id = NULL;
@@ -850,7 +889,7 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
return NULL;
}
- opts_do_parse(opts, params, firstname, defaults, &local_err);
+ opts_do_parse(opts, params, firstname, defaults, invalidp, &local_err);
if (local_err) {
error_propagate(errp, local_err);
qemu_opts_del(opts);
@@ -870,7 +909,7 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
bool permit_abbrev, Error **errp)
{
- return opts_parse(list, params, permit_abbrev, false, errp);
+ return opts_parse(list, params, permit_abbrev, false, NULL, errp);
}
/**
@@ -886,10 +925,16 @@ QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params,
{
Error *err = NULL;
QemuOpts *opts;
+ bool invalidp = false;
- opts = opts_parse(list, params, permit_abbrev, false, &err);
+ opts = opts_parse(list, params, permit_abbrev, false, &invalidp, &err);
if (err) {
- error_report_err(err);
+ if (invalidp && has_help_option(params)) {
+ qemu_opts_print_help(list);
+ error_free(err);
+ } else {
+ error_report_err(err);
+ }
}
return opts;
}
@@ -899,7 +944,7 @@ void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
{
QemuOpts *opts;
- opts = opts_parse(list, params, permit_abbrev, true, NULL);
+ opts = opts_parse(list, params, permit_abbrev, true, NULL, NULL);
assert(opts);
}
diff --git a/vl.c b/vl.c
index a867c9c..4e25c78 100644
--- a/vl.c
+++ b/vl.c
@@ -2696,8 +2696,55 @@ static int machine_set_property(void *opaque,
* cannot be created here, as it depends on the chardev
* already existing.
*/
-static bool object_create_initial(const char *type)
+static bool object_create_initial(const char *type, QemuOpts *opts)
{
+ ObjectClass *klass;
+
+ if (is_help_option(type)) {
+ GSList *l, *list;
+
+ printf("List of user creatable objects:\n");
+ list = object_class_get_list_sorted(TYPE_USER_CREATABLE, false);
+ for (l = list; l != NULL; l = l->next) {
+ ObjectClass *oc = OBJECT_CLASS(l->data);
+ printf("%s\n", object_class_get_name(oc));
+ }
+ g_slist_free(list);
+ exit(0);
+ }
+
+ klass = object_class_by_name(type);
+ if (klass && qemu_opt_has_help_opt(opts)) {
+ ObjectPropertyIterator iter;
+ ObjectProperty *prop;
+ GPtrArray *array = g_ptr_array_new();
+ int i;
+
+ object_class_property_iter_init(&iter, klass);
+ while ((prop = object_property_iter_next(&iter))) {
+ GString *str;
+
+ if (!prop->set) {
+ continue;
+ }
+
+ str = g_string_new(NULL);
+ g_string_append_printf(str, "%s.%s=%s", type,
+ prop->name, prop->type);
+ if (prop->description) {
+ g_string_append_printf(str, " - %s", prop->description);
+ }
+ g_ptr_array_add(array, g_string_free(str, false));
+ }
+ g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
+ for (i = 0; i < array->len; i++) {
+ printf("%s\n", (char *)array->pdata[i]);
+ }
+ g_ptr_array_set_free_func(array, g_free);
+ g_ptr_array_free(array, true);
+ exit(0);
+ }
+
if (g_str_equal(type, "rng-egd") ||
g_str_has_prefix(type, "pr-manager-")) {
return false;
@@ -2744,9 +2791,9 @@ static bool object_create_initial(const char *type)
* The remainder of object creation happens after the
* creation of chardev, fsdev, net clients and device data types.
*/
-static bool object_create_delayed(const char *type)
+static bool object_create_delayed(const char *type, QemuOpts *opts)
{
- return !object_create_initial(type);
+ return !object_create_initial(type, opts);
}