@@ -53,4 +53,13 @@ typedef struct QObjectOutputVisitor QObjectOutputVisitor;
*/
Visitor *qobject_output_visitor_new(QObject **result);
+/*
+ * 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
@@ -113,6 +113,9 @@ 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)(Visitor *v, const char *name);
+
/* Must be set */
VisitorType type;
@@ -459,6 +459,15 @@ void visit_end_alternate(Visitor *v, void **obj);
*/
bool visit_optional(Visitor *v, const char *name, bool *present);
+/*
+ * 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.
*
@@ -135,6 +135,15 @@ bool visit_optional(Visitor *v, const char *name, bool *present)
return *present;
}
+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;
@@ -13,6 +13,7 @@
*/
#include "qemu/osdep.h"
+#include "qapi/compat-policy.h"
#include "qapi/qobject-output-visitor.h"
#include "qapi/visitor-impl.h"
#include "qemu/queue.h"
@@ -31,6 +32,8 @@ typedef struct QStackEntry {
struct QObjectOutputVisitor {
Visitor visitor;
+ CompatPolicyOutput deprecated_policy;
+
QSLIST_HEAD(, QStackEntry) stack; /* Stack of unfinished containers */
QObject *root; /* Root of the output visit */
QObject **result; /* User's storage location for result */
@@ -207,6 +210,13 @@ static bool qobject_output_type_null(Visitor *v, const char *name,
return true;
}
+static bool qobject_output_deprecated(Visitor *v, const char *name)
+{
+ QObjectOutputVisitor *qov = to_qov(v);
+
+ return qov->deprecated_policy != COMPAT_POLICY_OUTPUT_HIDE;
+}
+
/* Finish building, and return the root object.
* The root object is never null. The caller becomes the object's
* owner, and should use qobject_unref() when done with it. */
@@ -256,6 +266,7 @@ Visitor *qobject_output_visitor_new(QObject **result)
v->visitor.type_number = qobject_output_type_number;
v->visitor.type_any = qobject_output_type_any;
v->visitor.type_null = qobject_output_type_null;
+ v->visitor.deprecated = qobject_output_deprecated;
v->visitor.complete = qobject_output_complete;
v->visitor.free = qobject_output_free;
@@ -264,3 +275,11 @@ Visitor *qobject_output_visitor_new(QObject **result)
return &v->visitor;
}
+
+Visitor *qobject_output_visitor_new_qmp(QObject **result)
+{
+ QObjectOutputVisitor *v = to_qov(qobject_output_visitor_new(result));
+
+ v->deprecated_policy = compat_policy.deprecated_output;
+ return &v->visitor;
+}
@@ -1,4 +1,5 @@
#include "qemu/osdep.h"
+#include "qapi/compat-policy.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qjson.h"
#include "qapi/qmp/qnum.h"
@@ -45,12 +46,17 @@ void qmp_user_def_cmd1(UserDefOne * ud1, Error **errp)
{
}
-void qmp_test_features0(FeatureStruct0 *fs0, FeatureStruct1 *fs1,
- FeatureStruct2 *fs2, FeatureStruct3 *fs3,
- FeatureStruct4 *fs4, CondFeatureStruct1 *cfs1,
- CondFeatureStruct2 *cfs2, CondFeatureStruct3 *cfs3,
- Error **errp)
+FeatureStruct1 *qmp_test_features0(bool has_fs0, FeatureStruct0 *fs0,
+ bool has_fs1, FeatureStruct1 *fs1,
+ bool has_fs2, FeatureStruct2 *fs2,
+ bool has_fs3, FeatureStruct3 *fs3,
+ bool has_fs4, FeatureStruct4 *fs4,
+ bool has_cfs1, CondFeatureStruct1 *cfs1,
+ bool has_cfs2, CondFeatureStruct2 *cfs2,
+ bool has_cfs3, CondFeatureStruct3 *cfs3,
+ Error **errp)
{
+ return g_new0(FeatureStruct1, 1);
}
void qmp_test_command_features1(Error **errp)
@@ -271,6 +277,30 @@ static void test_dispatch_cmd_io(void)
qobject_unref(ret3);
}
+static void test_dispatch_cmd_ret_deprecated(void)
+{
+ const char *cmd = "{ 'execute': 'test-features0' }";
+ QDict *ret;
+
+ memset(&compat_policy, 0, sizeof(compat_policy));
+
+ /* default accept */
+ ret = qobject_to(QDict, do_qmp_dispatch(false, cmd));
+ assert(ret && qdict_size(ret) == 1);
+ qobject_unref(ret);
+
+ compat_policy.has_deprecated_output = true;
+ compat_policy.deprecated_output = COMPAT_POLICY_OUTPUT_ACCEPT;
+ ret = qobject_to(QDict, do_qmp_dispatch(false, cmd));
+ assert(ret && qdict_size(ret) == 1);
+ qobject_unref(ret);
+
+ compat_policy.deprecated_output = COMPAT_POLICY_OUTPUT_HIDE;
+ ret = qobject_to(QDict, do_qmp_dispatch(false, cmd));
+ assert(ret && qdict_size(ret) == 0);
+ qobject_unref(ret);
+}
+
/* test generated dealloc functions for generated types */
static void test_dealloc_types(void)
{
@@ -345,6 +375,8 @@ int main(int argc, char **argv)
g_test_add_func("/qmp/dispatch_cmd_io", test_dispatch_cmd_io);
g_test_add_func("/qmp/dispatch_cmd_success_response",
test_dispatch_cmd_success_response);
+ g_test_add_func("/qmp/dispatch_cmd_ret_deprecated",
+ test_dispatch_cmd_ret_deprecated);
g_test_add_func("/qmp/dealloc_types", test_dealloc_types);
g_test_add_func("/qmp/dealloc_partial", test_dealloc_partial);
@@ -17,6 +17,7 @@ visit_start_alternate(void *v, const char *name, void *obj, size_t size) "v=%p n
visit_end_alternate(void *v, void *obj) "v=%p obj=%p"
visit_optional(void *v, const char *name, bool *present) "v=%p name=%s present=%p"
+visit_deprecated(void *v, const char *name) "v=%p name=%s"
visit_type_enum(void *v, const char *name, int *obj) "v=%p name=%s obj=%p"
visit_type_int(void *v, const char *name, int64_t *obj) "v=%p name=%s obj=%p"
@@ -69,7 +69,7 @@ static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in, QObject **ret_out,
{
Visitor *v;
- v = qobject_output_visitor_new(ret_out);
+ v = qobject_output_visitor_new_qmp(ret_out);
if (visit_type_%(c_name)s(v, "unused", &ret_in, errp)) {
visit_complete(v, ret_out);
}
@@ -53,6 +53,7 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
c_type=base.c_name())
for memb in members:
+ deprecated = 'deprecated' in [f.name for f in memb.features]
ret += gen_if(memb.ifcond)
if memb.optional:
ret += mcgen('''
@@ -60,6 +61,12 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
''',
name=memb.name, c_name=c_name(memb.name))
push_indent()
+ if deprecated:
+ ret += mcgen('''
+ if (visit_deprecated(v, "%(name)s")) {
+''',
+ name=memb.name)
+ push_indent()
ret += mcgen('''
if (!visit_type_%(c_type)s(v, "%(name)s", &obj->%(c_name)s, errp)) {
return false;
@@ -67,6 +74,11 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
''',
c_type=memb.type.c_name(), name=memb.name,
c_name=c_name(memb.name))
+ if deprecated:
+ pop_indent()
+ ret += mcgen('''
+ }
+''')
if memb.optional:
pop_indent()
ret += mcgen('''
@@ -298,14 +298,15 @@
'features': [ 'feature1' ] }
{ 'command': 'test-features0',
- 'data': { 'fs0': 'FeatureStruct0',
- 'fs1': 'FeatureStruct1',
- 'fs2': 'FeatureStruct2',
- 'fs3': 'FeatureStruct3',
- 'fs4': 'FeatureStruct4',
- 'cfs1': 'CondFeatureStruct1',
- 'cfs2': 'CondFeatureStruct2',
- 'cfs3': 'CondFeatureStruct3' },
+ 'data': { '*fs0': 'FeatureStruct0',
+ '*fs1': 'FeatureStruct1',
+ '*fs2': 'FeatureStruct2',
+ '*fs3': 'FeatureStruct3',
+ '*fs4': 'FeatureStruct4',
+ '*cfs1': 'CondFeatureStruct1',
+ '*cfs2': 'CondFeatureStruct2',
+ '*cfs3': 'CondFeatureStruct3' },
+ 'returns': 'FeatureStruct1',
'features': [] }
{ 'command': 'test-command-features1',
@@ -407,15 +407,15 @@ alternate FeatureAlternate1
case eins: FeatureStruct1
feature feature1
object q_obj_test-features0-arg
- member fs0: FeatureStruct0 optional=False
- member fs1: FeatureStruct1 optional=False
- member fs2: FeatureStruct2 optional=False
- member fs3: FeatureStruct3 optional=False
- member fs4: FeatureStruct4 optional=False
- member cfs1: CondFeatureStruct1 optional=False
- member cfs2: CondFeatureStruct2 optional=False
- member cfs3: CondFeatureStruct3 optional=False
-command test-features0 q_obj_test-features0-arg -> None
+ member fs0: FeatureStruct0 optional=True
+ member fs1: FeatureStruct1 optional=True
+ member fs2: FeatureStruct2 optional=True
+ member fs3: FeatureStruct3 optional=True
+ member fs4: FeatureStruct4 optional=True
+ member cfs1: CondFeatureStruct1 optional=True
+ member cfs2: CondFeatureStruct2 optional=True
+ member cfs3: CondFeatureStruct3 optional=True
+command test-features0 q_obj_test-features0-arg -> FeatureStruct1
gen=True success_response=True boxed=False oob=False preconfig=False
command test-command-features1 None -> None
gen=True success_response=True boxed=False oob=False preconfig=False