Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2021-03-1…
Browse files Browse the repository at this point in the history
…6-v4' into staging

QAPI patches patches for 2021-03-16

# gpg: Signature made Fri 19 Mar 2021 15:06:52 GMT
# gpg:                using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653
# gpg:                issuer "armbru@redhat.com"
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [full]
# gpg:                 aka "Markus Armbruster <armbru@pond.sub.org>" [full]
# Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867  4E5F 3870 B400 EB91 8653

* remotes/armbru/tags/pull-qapi-2021-03-16-v4:
  qapi: New -compat deprecated-input=crash
  qapi: Implement deprecated-input=reject for QMP command arguments
  qapi: Implement deprecated-input=reject for QMP commands
  test-util-sockets: Add stub for monitor_set_cur()
  qapi: Implement deprecated-output=hide for QMP introspection
  monitor: Drop query-qmp-schema 'gen': false hack
  qapi: Implement deprecated-output=hide for QMP event data
  qapi: Implement deprecated-output=hide for QMP events
  qapi: Implement deprecated-output=hide for QMP command results
  qemu-options: New -compat to set policy for deprecated interfaces
  qemuutil: remove qemu_set_fd_handler duplicate symbol

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed Mar 19, 2021
2 parents 8631a43 + dbb675c commit 2e1293c
Show file tree
Hide file tree
Showing 31 changed files with 549 additions and 64 deletions.
38 changes: 38 additions & 0 deletions include/qapi/compat-policy.h
@@ -0,0 +1,38 @@
/*
* Policy for handling "funny" management interfaces
*
* Copyright (C) 2020 Red Hat, Inc.
*
* Authors:
* Markus Armbruster <armbru@redhat.com>
*
* 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 QAPI_COMPAT_POLICY_H
#define QAPI_COMPAT_POLICY_H

#include "qapi/qapi-types-compat.h"

extern CompatPolicy compat_policy;

/*
* Create a QObject input visitor for @obj for use with QMP
*
* This is like qobject_input_visitor_new(), except it obeys the
* policy for handling deprecated management interfaces set with
* -compat.
*/
Visitor *qobject_input_visitor_new_qmp(QObject *obj);

/*
* Create a QObject output visitor for @obj for use with QMP
*
* This is like qobject_output_visitor_new(), except it obeys the
* policy for handling deprecated management interfaces set with
* -compat.
*/
Visitor *qobject_output_visitor_new_qmp(QObject **result);

#endif
1 change: 1 addition & 0 deletions include/qapi/qmp/dispatch.h
Expand Up @@ -26,6 +26,7 @@ typedef enum QmpCommandOptions
QCO_ALLOW_OOB = (1U << 1),
QCO_ALLOW_PRECONFIG = (1U << 2),
QCO_COROUTINE = (1U << 3),
QCO_DEPRECATED = (1U << 4),
} QmpCommandOptions;

typedef struct QmpCommand
Expand Down
4 changes: 4 additions & 0 deletions include/qapi/qobject-input-visitor.h
Expand Up @@ -15,6 +15,7 @@
#ifndef QOBJECT_INPUT_VISITOR_H
#define QOBJECT_INPUT_VISITOR_H

#include "qapi/qapi-types-compat.h"
#include "qapi/visitor.h"

typedef struct QObjectInputVisitor QObjectInputVisitor;
Expand Down Expand Up @@ -58,6 +59,9 @@ typedef struct QObjectInputVisitor QObjectInputVisitor;
*/
Visitor *qobject_input_visitor_new(QObject *obj);

void qobject_input_visitor_set_policy(Visitor *v,
CompatPolicyInput deprecated);

/*
* Create a QObject input visitor for @obj for use with keyval_parse()
*
Expand Down
4 changes: 4 additions & 0 deletions include/qapi/qobject-output-visitor.h
Expand Up @@ -15,6 +15,7 @@
#define QOBJECT_OUTPUT_VISITOR_H

#include "qapi/visitor.h"
#include "qapi/qapi-types-compat.h"

typedef struct QObjectOutputVisitor QObjectOutputVisitor;

Expand Down Expand Up @@ -53,4 +54,7 @@ typedef struct QObjectOutputVisitor QObjectOutputVisitor;
*/
Visitor *qobject_output_visitor_new(QObject **result);

void qobject_output_visitor_set_policy(Visitor *v,
CompatPolicyOutput deprecated);

#endif
6 changes: 6 additions & 0 deletions include/qapi/visitor-impl.h
Expand Up @@ -113,6 +113,12 @@ struct Visitor
The core takes care of the return type in the public interface. */
void (*optional)(Visitor *v, const char *name, bool *present);

/* Optional */
bool (*deprecated_accept)(Visitor *v, const char *name, Error **errp);

/* Optional */
bool (*deprecated)(Visitor *v, const char *name);

/* Must be set */
VisitorType type;

Expand Down
18 changes: 18 additions & 0 deletions include/qapi/visitor.h
Expand Up @@ -459,6 +459,24 @@ void visit_end_alternate(Visitor *v, void **obj);
*/
bool visit_optional(Visitor *v, const char *name, bool *present);

/*
* Should we reject deprecated member @name?
*
* @name must not be NULL. This function is only useful between
* visit_start_struct() and visit_end_struct(), since only objects
* have deprecated members.
*/
bool visit_deprecated_accept(Visitor *v, const char *name, Error **errp);

/*
* Should we visit deprecated member @name?
*
* @name must not be NULL. This function is only useful between
* visit_start_struct() and visit_end_struct(), since only objects
* have deprecated members.
*/
bool visit_deprecated(Visitor *v, const char *name);

/*
* Visit an enum value.
*
Expand Down
2 changes: 0 additions & 2 deletions monitor/misc.c
Expand Up @@ -231,8 +231,6 @@ static void monitor_init_qmp_commands(void)

qmp_init_marshal(&qmp_commands);

qmp_register_command(&qmp_commands, "query-qmp-schema",
qmp_query_qmp_schema, QCO_ALLOW_PRECONFIG);
qmp_register_command(&qmp_commands, "device_add", qmp_device_add,
QCO_NO_OPTIONS);

Expand Down
3 changes: 0 additions & 3 deletions monitor/monitor-internal.h
Expand Up @@ -183,7 +183,4 @@ void help_cmd(Monitor *mon, const char *name);
void handle_hmp_command(MonitorHMP *mon, const char *cmdline);
int hmp_compare_cmd(const char *name, const char *list);

void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
Error **errp);

#endif
100 changes: 88 additions & 12 deletions monitor/qmp-cmds-control.c
Expand Up @@ -26,10 +26,14 @@

#include "monitor-internal.h"
#include "qemu-version.h"
#include "qapi/compat-policy.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-control.h"
#include "qapi/qapi-commands-introspect.h"
#include "qapi/qapi-emit-events.h"
#include "qapi/qapi-introspect.h"
#include "qapi/qapi-visit-introspect.h"
#include "qapi/qobject-input-visitor.h"

/*
* Accept QMP capabilities in @list for @mon.
Expand Down Expand Up @@ -130,17 +134,89 @@ CommandInfoList *qmp_query_commands(Error **errp)
return list;
}

/*
* Minor hack: generated marshalling suppressed for this command
* ('gen': false in the schema) so we can parse the JSON string
* directly into QObject instead of first parsing it with
* visit_type_SchemaInfoList() into a SchemaInfoList, then marshal it
* to QObject with generated output marshallers, every time. Instead,
* we do it in test-qobject-input-visitor.c, just to make sure
* qapi-gen.py's output actually conforms to the schema.
*/
void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
Error **errp)
static void *split_off_generic_list(void *list,
bool (*splitp)(void *elt),
void **part)
{
GenericList *keep = NULL, **keep_tailp = &keep;
GenericList *split = NULL, **split_tailp = &split;
GenericList *tail;

for (tail = list; tail; tail = tail->next) {
if (splitp(tail)) {
*split_tailp = tail;
split_tailp = &tail->next;
} else {
*keep_tailp = tail;
keep_tailp = &tail->next;
}
}

*keep_tailp = *split_tailp = NULL;
*part = split;
return keep;
}

static bool is_in(const char *s, strList *list)
{
strList *tail;

for (tail = list; tail; tail = tail->next) {
if (!strcmp(tail->value, s)) {
return true;
}
}
return false;
}

static bool is_entity_deprecated(void *link)
{
return is_in("deprecated", ((SchemaInfoList *)link)->value->features);
}

static bool is_member_deprecated(void *link)
{
return is_in("deprecated",
((SchemaInfoObjectMemberList *)link)->value->features);
}

static SchemaInfoList *zap_deprecated(SchemaInfoList *schema)
{
*ret_data = qobject_from_qlit(&qmp_schema_qlit);
void *to_zap;
SchemaInfoList *tail;
SchemaInfo *ent;

schema = split_off_generic_list(schema, is_entity_deprecated, &to_zap);
qapi_free_SchemaInfoList(to_zap);

for (tail = schema; tail; tail = tail->next) {
ent = tail->value;
if (ent->meta_type == SCHEMA_META_TYPE_OBJECT) {
ent->u.object.members
= split_off_generic_list(ent->u.object.members,
is_member_deprecated, &to_zap);
qapi_free_SchemaInfoObjectMemberList(to_zap);
}
}

return schema;
}

SchemaInfoList *qmp_query_qmp_schema(Error **errp)
{
QObject *obj = qobject_from_qlit(&qmp_schema_qlit);
Visitor *v = qobject_input_visitor_new(obj);
SchemaInfoList *schema = NULL;

/* test_visitor_in_qmp_introspect() ensures this can't fail */
visit_type_SchemaInfoList(v, NULL, &schema, &error_abort);
g_assert(schema);

qobject_unref(obj);
visit_free(v);

if (compat_policy.deprecated_output == COMPAT_POLICY_OUTPUT_HIDE) {
return zap_deprecated(schema);
}
return schema;
}
52 changes: 52 additions & 0 deletions qapi/compat.json
@@ -0,0 +1,52 @@
# -*- Mode: Python -*-

##
# = Compatibility policy
##

##
# @CompatPolicyInput:
#
# Policy for handling "funny" input.
#
# @accept: Accept silently
# @reject: Reject with an error
# @crash: abort() the process
#
# Since: 6.0
##
{ 'enum': 'CompatPolicyInput',
'data': [ 'accept', 'reject', 'crash' ] }

##
# @CompatPolicyOutput:
#
# Policy for handling "funny" output.
#
# @accept: Pass on unchanged
# @hide: Filter out
#
# Since: 6.0
##
{ 'enum': 'CompatPolicyOutput',
'data': [ 'accept', 'hide' ] }

##
# @CompatPolicy:
#
# Policy for handling deprecated management interfaces.
#
# This is intended for testing users of the management interfaces.
#
# Limitation: covers only syntactic aspects of QMP, i.e. stuff tagged
# with feature 'deprecated'. We may want to extend it to cover
# semantic aspects, CLI, and experimental features.
#
# @deprecated-input: how to handle deprecated input (default 'accept')
# @deprecated-output: how to handle deprecated output (default 'accept')
#
# Since: 6.0
##
{ 'struct': 'CompatPolicy',
'data': { '*deprecated-input': 'CompatPolicyInput',
'*deprecated-output': 'CompatPolicyOutput' } }
2 changes: 1 addition & 1 deletion qapi/introspect.json
Expand Up @@ -49,7 +49,7 @@
##
{ 'command': 'query-qmp-schema',
'returns': [ 'SchemaInfo' ],
'gen': false } # just to simplify qmp_query_json()
'allow-preconfig': true }

##
# @SchemaMetaType:
Expand Down
1 change: 1 addition & 0 deletions qapi/meson.build
Expand Up @@ -25,6 +25,7 @@ qapi_all_modules = [
'block-export',
'char',
'common',
'compat',
'control',
'crypto',
'dump',
Expand Down
1 change: 1 addition & 0 deletions qapi/qapi-schema.json
Expand Up @@ -79,6 +79,7 @@
{ 'include': 'migration.json' }
{ 'include': 'transaction.json' }
{ 'include': 'trace.json' }
{ 'include': 'compat.json' }
{ 'include': 'control.json' }
{ 'include': 'introspect.json' }
{ 'include': 'qom.json' }
Expand Down
18 changes: 18 additions & 0 deletions qapi/qapi-visit-core.c
Expand Up @@ -135,6 +135,24 @@ bool visit_optional(Visitor *v, const char *name, bool *present)
return *present;
}

bool visit_deprecated_accept(Visitor *v, const char *name, Error **errp)
{
trace_visit_deprecated_accept(v, name);
if (v->deprecated_accept) {
return v->deprecated_accept(v, name, errp);
}
return true;
}

bool visit_deprecated(Visitor *v, const char *name)
{
trace_visit_deprecated(v, name);
if (v->deprecated) {
return v->deprecated(v, name);
}
return true;
}

bool visit_is_input(Visitor *v)
{
return v->type == VISITOR_INPUT;
Expand Down

0 comments on commit 2e1293c

Please sign in to comment.