All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 0/5] qapi: Add detection for the 'savevm' fix for blockdev
@ 2019-10-18  8:14 Markus Armbruster
  2019-10-18  8:14 ` [PATCH v5 1/5] tests/qapi-schema: Tidy up test output indentation Markus Armbruster
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Markus Armbruster @ 2019-10-18  8:14 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, mdroth


Add 'features' field in the schema for commands and add a feature flag
to advertise that the fix for savevm [1] is present.

[1] https://lists.gnu.org/archive/html/qemu-devel/2019-09/msg03487.html

Based-on: <20191018074345.24034-1-armbru@redhat.com>

v5:
* PATCH 2:
  - qapi-code-gen.txt grammar updated
  - Doc generation for boxed commands fixed
  - Commit message tweaked
* PATCH 3:
  - Command names in qapi-schema-test.json tweaked
  - Trivial pycodestyle-3 fix
* PATCH 4: New
* PATCH 5: Whitespace tweaked

v4:
* PATCH 1: New
* PATCH 2: Factor out check_features()
* PATCH 3: Factor out _print_features(), drop duplicated test
* PATCH 4
  - Shorten savevm-blockdev-monitor-nodes to just savevm-monitor-nodes
  - Tweak commit message and documentation

Markus Armbruster (2):
  tests/qapi-schema: Tidy up test output indentation
  tests/qapi-schema: Cover feature documentation comments

Peter Krempa (3):
  qapi: Add feature flags to commands
  tests: qapi: Test 'features' of commands
  qapi: Allow introspecting fix for savevm's cooperation with blockdev

 docs/devel/qapi-code-gen.txt            | 10 ++--
 tests/qapi-schema/doc-good.texi         | 22 ++++++++
 qapi/introspect.json                    |  6 +-
 qapi/misc.json                          |  9 ++-
 tests/test-qmp-cmds.c                   | 24 ++++++++
 scripts/qapi/commands.py                |  3 +-
 scripts/qapi/doc.py                     |  4 +-
 scripts/qapi/expr.py                    | 35 +++++++-----
 scripts/qapi/introspect.py              |  7 ++-
 scripts/qapi/schema.py                  | 22 ++++++--
 tests/qapi-schema/doc-good.json         | 17 +++++-
 tests/qapi-schema/doc-good.out          |  9 ++-
 tests/qapi-schema/event-case.out        |  2 +-
 tests/qapi-schema/indented-expr.out     |  4 +-
 tests/qapi-schema/qapi-schema-test.json | 18 ++++++
 tests/qapi-schema/qapi-schema-test.out  | 75 ++++++++++++++++---------
 tests/qapi-schema/test-qapi.py          | 20 ++++---
 17 files changed, 219 insertions(+), 68 deletions(-)

-- 
2.21.0



^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v5 1/5] tests/qapi-schema: Tidy up test output indentation
  2019-10-18  8:14 [PATCH v5 0/5] qapi: Add detection for the 'savevm' fix for blockdev Markus Armbruster
@ 2019-10-18  8:14 ` Markus Armbruster
  2019-10-18  8:14 ` [PATCH v5 2/5] qapi: Add feature flags to commands Markus Armbruster
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Markus Armbruster @ 2019-10-18  8:14 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, Peter Krempa, mdroth

Command and event details are indented three spaces, everything else
four.  Messed up in commit 156402e5042.  Use four spaces consistently.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
---
 tests/qapi-schema/doc-good.out         |  4 +-
 tests/qapi-schema/event-case.out       |  2 +-
 tests/qapi-schema/indented-expr.out    |  4 +-
 tests/qapi-schema/qapi-schema-test.out | 52 +++++++++++++-------------
 tests/qapi-schema/test-qapi.py         |  4 +-
 5 files changed, 33 insertions(+), 33 deletions(-)

diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index d3bca343eb..6562e1f412 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -46,9 +46,9 @@ object q_obj_cmd-arg
     member arg2: str optional=True
     member arg3: bool optional=False
 command cmd q_obj_cmd-arg -> Object
-   gen=True success_response=True boxed=False oob=False preconfig=False
+    gen=True success_response=True boxed=False oob=False preconfig=False
 command cmd-boxed Object -> None
-   gen=True success_response=True boxed=True oob=False preconfig=False
+    gen=True success_response=True boxed=True oob=False preconfig=False
 doc freeform
     body=
 = Section
diff --git a/tests/qapi-schema/event-case.out b/tests/qapi-schema/event-case.out
index ec8a1406e4..42ae519656 100644
--- a/tests/qapi-schema/event-case.out
+++ b/tests/qapi-schema/event-case.out
@@ -11,4 +11,4 @@ enum QType
     member qbool
 module event-case.json
 event oops None
-   boxed=False
+    boxed=False
diff --git a/tests/qapi-schema/indented-expr.out b/tests/qapi-schema/indented-expr.out
index bffdf6756d..04356775cd 100644
--- a/tests/qapi-schema/indented-expr.out
+++ b/tests/qapi-schema/indented-expr.out
@@ -11,6 +11,6 @@ enum QType
     member qbool
 module indented-expr.json
 command eins None -> None
-   gen=True success_response=True boxed=False oob=False preconfig=False
+    gen=True success_response=True boxed=False oob=False preconfig=False
 command zwei None -> None
-   gen=True success_response=True boxed=False oob=False preconfig=False
+    gen=True success_response=True boxed=False oob=False preconfig=False
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 98031da96f..aca43186a9 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -33,7 +33,7 @@ object Union
     case value3: q_empty
     case value4: q_empty
 command user_def_cmd0 Empty2 -> Empty2
-   gen=True success_response=True boxed=False oob=False preconfig=False
+    gen=True success_response=True boxed=False oob=False preconfig=False
 enum QEnumTwo
     prefix QENUM_TWO
     member value1
@@ -205,35 +205,35 @@ object SecondArrayRef
     member s: StatusList optional=False
 module qapi-schema-test.json
 command user_def_cmd None -> None
-   gen=True success_response=True boxed=False oob=False preconfig=False
+    gen=True success_response=True boxed=False oob=False preconfig=False
 object q_obj_user_def_cmd1-arg
     member ud1a: UserDefOne optional=False
 command user_def_cmd1 q_obj_user_def_cmd1-arg -> None
-   gen=True success_response=True boxed=False oob=False preconfig=False
+    gen=True success_response=True boxed=False oob=False preconfig=False
 object q_obj_user_def_cmd2-arg
     member ud1a: UserDefOne optional=False
     member ud1b: UserDefOne optional=True
 command user_def_cmd2 q_obj_user_def_cmd2-arg -> UserDefTwo
-   gen=True success_response=True boxed=False oob=False preconfig=False
+    gen=True success_response=True boxed=False oob=False preconfig=False
 command cmd-success-response None -> None
-   gen=True success_response=False boxed=False oob=False preconfig=False
+    gen=True success_response=False boxed=False oob=False preconfig=False
 object q_obj_guest-get-time-arg
     member a: int optional=False
     member b: int optional=True
 command guest-get-time q_obj_guest-get-time-arg -> int
-   gen=True success_response=True boxed=False oob=False preconfig=False
+    gen=True success_response=True boxed=False oob=False preconfig=False
 object q_obj_guest-sync-arg
     member arg: any optional=False
 command guest-sync q_obj_guest-sync-arg -> any
-   gen=True success_response=True boxed=False oob=False preconfig=False
+    gen=True success_response=True boxed=False oob=False preconfig=False
 command boxed-struct UserDefZero -> None
-   gen=True success_response=True boxed=True oob=False preconfig=False
+    gen=True success_response=True boxed=True oob=False preconfig=False
 command boxed-union UserDefListUnion -> None
-   gen=True success_response=True boxed=True oob=False preconfig=False
+    gen=True success_response=True boxed=True oob=False preconfig=False
 command boxed-empty Empty1 -> None
-   gen=True success_response=True boxed=True oob=False preconfig=False
+    gen=True success_response=True boxed=True oob=False preconfig=False
 command test-flags-command None -> None
-   gen=True success_response=True boxed=False oob=True preconfig=True
+    gen=True success_response=True boxed=False oob=True preconfig=True
 object UserDefOptions
     member i64: intList optional=True
     member u64: uint64List optional=True
@@ -245,28 +245,28 @@ object EventStructOne
     member string: str optional=False
     member enum2: EnumOne optional=True
 event EVENT_A None
-   boxed=False
+    boxed=False
 event EVENT_B None
-   boxed=False
+    boxed=False
 object q_obj_EVENT_C-arg
     member a: int optional=True
     member b: UserDefOne optional=True
     member c: str optional=False
 event EVENT_C q_obj_EVENT_C-arg
-   boxed=False
+    boxed=False
 object q_obj_EVENT_D-arg
     member a: EventStructOne optional=False
     member b: str optional=False
     member c: str optional=True
     member enum3: EnumOne optional=True
 event EVENT_D q_obj_EVENT_D-arg
-   boxed=False
+    boxed=False
 event EVENT_E UserDefZero
-   boxed=True
+    boxed=True
 event EVENT_F UserDefFlatUnion
-   boxed=True
+    boxed=True
 event EVENT_G Empty1
-   boxed=True
+    boxed=True
 enum __org.qemu_x-Enum
     member __org.qemu_x-value
 object __org.qemu_x-Base
@@ -297,7 +297,7 @@ alternate __org.qemu_x-Alt
     tag type
     case __org.qemu_x-branch: __org.qemu_x-Base
 event __ORG.QEMU_X-EVENT __org.qemu_x-Struct
-   boxed=False
+    boxed=False
 array __org.qemu_x-EnumList __org.qemu_x-Enum
 array __org.qemu_x-StructList __org.qemu_x-Struct
 object q_obj___org.qemu_x-command-arg
@@ -306,7 +306,7 @@ object q_obj___org.qemu_x-command-arg
     member c: __org.qemu_x-Union2 optional=False
     member d: __org.qemu_x-Alt optional=False
 command __org.qemu_x-command q_obj___org.qemu_x-command-arg -> __org.qemu_x-Union1
-   gen=True success_response=True boxed=False oob=False preconfig=False
+    gen=True success_response=True boxed=False oob=False preconfig=False
 object TestIfStruct
     member foo: int optional=False
     member bar: int optional=False
@@ -335,7 +335,7 @@ object q_obj_TestIfUnionCmd-arg
     member union_cmd_arg: TestIfUnion optional=False
     if ['defined(TEST_IF_UNION)']
 command TestIfUnionCmd q_obj_TestIfUnionCmd-arg -> None
-   gen=True success_response=True boxed=False oob=False preconfig=False
+    gen=True success_response=True boxed=False oob=False preconfig=False
     if ['defined(TEST_IF_UNION)']
 alternate TestIfAlternate
     tag type
@@ -347,7 +347,7 @@ object q_obj_TestIfAlternateCmd-arg
     member alt_cmd_arg: TestIfAlternate optional=False
     if ['defined(TEST_IF_ALT)']
 command TestIfAlternateCmd q_obj_TestIfAlternateCmd-arg -> None
-   gen=True success_response=True boxed=False oob=False preconfig=False
+    gen=True success_response=True boxed=False oob=False preconfig=False
     if ['defined(TEST_IF_ALT)']
 object q_obj_TestIfCmd-arg
     member foo: TestIfStruct optional=False
@@ -355,10 +355,10 @@ object q_obj_TestIfCmd-arg
         if ['defined(TEST_IF_CMD_BAR)']
     if ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)']
 command TestIfCmd q_obj_TestIfCmd-arg -> UserDefThree
-   gen=True success_response=True boxed=False oob=False preconfig=False
+    gen=True success_response=True boxed=False oob=False preconfig=False
     if ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)']
 command TestCmdReturnDefThree None -> UserDefThree
-   gen=True success_response=True boxed=False oob=False preconfig=False
+    gen=True success_response=True boxed=False oob=False preconfig=False
 array TestIfEnumList TestIfEnum
     if ['defined(TEST_IF_ENUM)']
 object q_obj_TestIfEvent-arg
@@ -367,7 +367,7 @@ object q_obj_TestIfEvent-arg
         if ['defined(TEST_IF_EVT_BAR)']
     if ['defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)']
 event TestIfEvent q_obj_TestIfEvent-arg
-   boxed=False
+    boxed=False
     if ['defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)']
 object FeatureStruct0
     member foo: int optional=False
@@ -411,4 +411,4 @@ object q_obj_test-features-arg
     member cfs2: CondFeatureStruct2 optional=False
     member cfs3: CondFeatureStruct3 optional=False
 command test-features q_obj_test-features-arg -> None
-   gen=True success_response=True boxed=False oob=False preconfig=False
+    gen=True success_response=True boxed=False oob=False preconfig=False
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index 664254618a..29d9435bf7 100755
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -76,13 +76,13 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
         print('command %s %s -> %s'
               % (name, arg_type and arg_type.name,
                  ret_type and ret_type.name))
-        print('   gen=%s success_response=%s boxed=%s oob=%s preconfig=%s'
+        print('    gen=%s success_response=%s boxed=%s oob=%s preconfig=%s'
               % (gen, success_response, boxed, allow_oob, allow_preconfig))
         self._print_if(ifcond)
 
     def visit_event(self, name, info, ifcond, arg_type, boxed):
         print('event %s %s' % (name, arg_type and arg_type.name))
-        print('   boxed=%s' % boxed)
+        print('    boxed=%s' % boxed)
         self._print_if(ifcond)
 
     @staticmethod
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v5 2/5] qapi: Add feature flags to commands
  2019-10-18  8:14 [PATCH v5 0/5] qapi: Add detection for the 'savevm' fix for blockdev Markus Armbruster
  2019-10-18  8:14 ` [PATCH v5 1/5] tests/qapi-schema: Tidy up test output indentation Markus Armbruster
@ 2019-10-18  8:14 ` Markus Armbruster
  2019-10-18  8:14 ` [PATCH v5 3/5] tests: qapi: Test 'features' of commands Markus Armbruster
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Markus Armbruster @ 2019-10-18  8:14 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, Peter Krempa, mdroth

From: Peter Krempa <pkrempa@redhat.com>

Similarly to features for struct types introduce the feature flags also
for commands. This will allow notifying management layers of fixes and
compatible changes in the behaviour of a command which may not be
detectable any other way.

The changes were heavily inspired by commit 6a8c0b51025.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 docs/devel/qapi-code-gen.txt   | 10 ++++++----
 qapi/introspect.json           |  6 +++++-
 scripts/qapi/commands.py       |  3 ++-
 scripts/qapi/doc.py            |  4 +++-
 scripts/qapi/expr.py           | 35 +++++++++++++++++++---------------
 scripts/qapi/introspect.py     |  7 ++++++-
 scripts/qapi/schema.py         | 22 +++++++++++++++++----
 tests/qapi-schema/test-qapi.py |  3 ++-
 8 files changed, 62 insertions(+), 28 deletions(-)

diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index 64d9e4c6a9..45c93a43cc 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -457,7 +457,8 @@ Syntax:
                 '*gen': false,
                 '*allow-oob': true,
                 '*allow-preconfig': true,
-                '*if': COND }
+                '*if': COND,
+                '*features': FEATURES }
 
 Member 'command' names the command.
 
@@ -640,9 +641,10 @@ change in the QMP syntax (usually by allowing values or operations
 that previously resulted in an error).  QMP clients may still need to
 know whether the extension is available.
 
-For this purpose, a list of features can be specified for a struct type.
-This is exposed to the client as a list of string, where each string
-signals that this build of QEMU shows a certain behaviour.
+For this purpose, a list of features can be specified for a command or
+struct type.  This is exposed to the client as a list of strings,
+where each string signals that this build of QEMU shows a certain
+behaviour.
 
 Each member of the 'features' array defines a feature.  It can either
 be { 'name': STRING, '*if': COND }, or STRING, which is shorthand for
diff --git a/qapi/introspect.json b/qapi/introspect.json
index 1843c1cb17..031a954fa9 100644
--- a/qapi/introspect.json
+++ b/qapi/introspect.json
@@ -266,13 +266,17 @@
 # @allow-oob: whether the command allows out-of-band execution,
 #             defaults to false (Since: 2.12)
 #
+# @features: names of features associated with the command, in no particular
+#            order. (since 4.2)
+#
 # TODO: @success-response (currently irrelevant, because it's QGA, not QMP)
 #
 # Since: 2.5
 ##
 { 'struct': 'SchemaInfoCommand',
   'data': { 'arg-type': 'str', 'ret-type': 'str',
-            '*allow-oob': 'bool' } }
+            '*allow-oob': 'bool',
+            '*features': [ 'str' ] } }
 
 ##
 # @SchemaInfoEvent:
diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
index 898516b086..ab98e504f3 100644
--- a/scripts/qapi/commands.py
+++ b/scripts/qapi/commands.py
@@ -277,7 +277,8 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
         genc.add(gen_registry(self._regy.get_content(), self._prefix))
 
     def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
-                      success_response, boxed, allow_oob, allow_preconfig):
+                      success_response, boxed, allow_oob, allow_preconfig,
+                      features):
         if not gen:
             return
         # FIXME: If T is a user-defined type, the user is responsible
diff --git a/scripts/qapi/doc.py b/scripts/qapi/doc.py
index dc8919bab7..6d5726cf6e 100644
--- a/scripts/qapi/doc.py
+++ b/scripts/qapi/doc.py
@@ -249,12 +249,14 @@ class QAPISchemaGenDocVisitor(QAPISchemaVisitor):
                                body=texi_entity(doc, 'Members', ifcond)))
 
     def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
-                      success_response, boxed, allow_oob, allow_preconfig):
+                      success_response, boxed, allow_oob, allow_preconfig,
+                      features):
         doc = self.cur_doc
         if boxed:
             body = texi_body(doc)
             body += ('\n@b{Arguments:} the members of @code{%s}\n'
                      % arg_type.name)
+            body += texi_features(doc)
             body += texi_sections(doc, ifcond)
         else:
             body = texi_entity(doc, 'Arguments', ifcond)
diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py
index da23063f57..5a7e548899 100644
--- a/scripts/qapi/expr.py
+++ b/scripts/qapi/expr.py
@@ -184,6 +184,22 @@ def normalize_features(features):
                        for f in features]
 
 
+def check_features(features, info):
+    if features is None:
+        return
+    if not isinstance(features, list):
+        raise QAPISemError(info, "'features' must be an array")
+    for f in features:
+        source = "'features' member"
+        assert isinstance(f, dict)
+        check_keys(f, info, source, ['name'], ['if'])
+        check_name_is_str(f['name'], info, source)
+        source = "%s '%s'" % (source, f['name'])
+        check_name_str(f['name'], info, source)
+        check_if(f, info, source)
+        normalize_if(f)
+
+
 def normalize_enum(expr):
     if isinstance(expr['data'], list):
         expr['data'] = [m if isinstance(m, dict) else {'name': m}
@@ -216,23 +232,10 @@ def check_enum(expr, info):
 def check_struct(expr, info):
     name = expr['struct']
     members = expr['data']
-    features = expr.get('features')
 
     check_type(members, info, "'data'", allow_dict=name)
     check_type(expr.get('base'), info, "'base'")
-
-    if features:
-        if not isinstance(features, list):
-            raise QAPISemError(info, "'features' must be an array")
-        for f in features:
-            source = "'features' member"
-            assert isinstance(f, dict)
-            check_keys(f, info, source, ['name'], ['if'])
-            check_name_is_str(f['name'], info, source)
-            source = "%s '%s'" % (source, f['name'])
-            check_name_str(f['name'], info, source)
-            check_if(f, info, source)
-            normalize_if(f)
+    check_features(expr.get('features'), info)
 
 
 def check_union(expr, info):
@@ -282,6 +285,7 @@ def check_command(expr, info):
         raise QAPISemError(info, "'boxed': true requires 'data'")
     check_type(args, info, "'data'", allow_dict=not boxed)
     check_type(rets, info, "'returns'", allow_array=True)
+    check_features(expr.get('features'), info)
 
 
 def check_event(expr, info):
@@ -357,10 +361,11 @@ def check_exprs(exprs):
         elif meta == 'command':
             check_keys(expr, info, meta,
                        ['command'],
-                       ['data', 'returns', 'boxed', 'if',
+                       ['data', 'returns', 'boxed', 'if', 'features',
                         'gen', 'success-response', 'allow-oob',
                         'allow-preconfig'])
             normalize_members(expr.get('data'))
+            normalize_features(expr.get('features'))
             check_command(expr, info)
         elif meta == 'event':
             check_keys(expr, info, meta,
diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py
index 4f257591de..b3a463dd8b 100644
--- a/scripts/qapi/introspect.py
+++ b/scripts/qapi/introspect.py
@@ -211,13 +211,18 @@ const QLitObject %(c_name)s = %(c_string)s;
                            for m in variants.variants]}, ifcond)
 
     def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
-                      success_response, boxed, allow_oob, allow_preconfig):
+                      success_response, boxed, allow_oob, allow_preconfig,
+                      features):
         arg_type = arg_type or self._schema.the_empty_object_type
         ret_type = ret_type or self._schema.the_empty_object_type
         obj = {'arg-type': self._use_type(arg_type),
                'ret-type': self._use_type(ret_type)}
         if allow_oob:
             obj['allow-oob'] = allow_oob
+
+        if features:
+            obj['features'] = [(f.name, {'if': f.ifcond}) for f in features]
+
         self._gen_qlit(name, 'command', obj, ifcond)
 
     def visit_event(self, name, info, ifcond, arg_type, boxed):
diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
index 38041098bd..8a48231766 100644
--- a/scripts/qapi/schema.py
+++ b/scripts/qapi/schema.py
@@ -109,7 +109,8 @@ class QAPISchemaVisitor(object):
         pass
 
     def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
-                      success_response, boxed, allow_oob, allow_preconfig):
+                      success_response, boxed, allow_oob, allow_preconfig,
+                      features):
         pass
 
     def visit_event(self, name, info, ifcond, arg_type, boxed):
@@ -658,10 +659,14 @@ class QAPISchemaCommand(QAPISchemaEntity):
     meta = 'command'
 
     def __init__(self, name, info, doc, ifcond, arg_type, ret_type,
-                 gen, success_response, boxed, allow_oob, allow_preconfig):
+                 gen, success_response, boxed, allow_oob, allow_preconfig,
+                 features):
         QAPISchemaEntity.__init__(self, name, info, doc, ifcond)
         assert not arg_type or isinstance(arg_type, str)
         assert not ret_type or isinstance(ret_type, str)
+        for f in features:
+            assert isinstance(f, QAPISchemaFeature)
+            f.set_defined_in(name)
         self._arg_type_name = arg_type
         self.arg_type = None
         self._ret_type_name = ret_type
@@ -671,6 +676,7 @@ class QAPISchemaCommand(QAPISchemaEntity):
         self.boxed = boxed
         self.allow_oob = allow_oob
         self.allow_preconfig = allow_preconfig
+        self.features = features
 
     def check(self, schema):
         QAPISchemaEntity.check(self, schema)
@@ -700,13 +706,19 @@ class QAPISchemaCommand(QAPISchemaEntity):
                         "command's 'returns' cannot take %s"
                         % self.ret_type.describe())
 
+        # Features are in a name space separate from members
+        seen = {}
+        for f in self.features:
+            f.check_clash(self.info, seen)
+
     def visit(self, visitor):
         QAPISchemaEntity.visit(self, visitor)
         visitor.visit_command(self.name, self.info, self.ifcond,
                               self.arg_type, self.ret_type,
                               self.gen, self.success_response,
                               self.boxed, self.allow_oob,
-                              self.allow_preconfig)
+                              self.allow_preconfig,
+                              self.features)
 
 
 class QAPISchemaEvent(QAPISchemaEntity):
@@ -983,6 +995,7 @@ class QAPISchema(object):
         allow_oob = expr.get('allow-oob', False)
         allow_preconfig = expr.get('allow-preconfig', False)
         ifcond = expr.get('if')
+        features = expr.get('features', [])
         if isinstance(data, OrderedDict):
             data = self._make_implicit_object_type(
                 name, info, doc, ifcond, 'arg', self._make_members(data, info))
@@ -991,7 +1004,8 @@ class QAPISchema(object):
             rets = self._make_array_type(rets[0], info)
         self._def_entity(QAPISchemaCommand(name, info, doc, ifcond, data, rets,
                                            gen, success_response,
-                                           boxed, allow_oob, allow_preconfig))
+                                           boxed, allow_oob, allow_preconfig,
+                                           self._make_features(features, info)))
 
     def _def_event(self, expr, info, doc):
         name = expr['event']
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index 29d9435bf7..d31ac4bbb7 100755
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -72,7 +72,8 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
         self._print_if(ifcond)
 
     def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
-                      success_response, boxed, allow_oob, allow_preconfig):
+                      success_response, boxed, allow_oob, allow_preconfig,
+                      features):
         print('command %s %s -> %s'
               % (name, arg_type and arg_type.name,
                  ret_type and ret_type.name))
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v5 3/5] tests: qapi: Test 'features' of commands
  2019-10-18  8:14 [PATCH v5 0/5] qapi: Add detection for the 'savevm' fix for blockdev Markus Armbruster
  2019-10-18  8:14 ` [PATCH v5 1/5] tests/qapi-schema: Tidy up test output indentation Markus Armbruster
  2019-10-18  8:14 ` [PATCH v5 2/5] qapi: Add feature flags to commands Markus Armbruster
@ 2019-10-18  8:14 ` Markus Armbruster
  2019-10-18  8:14 ` [PATCH v5 4/5] tests/qapi-schema: Cover feature documentation comments Markus Armbruster
  2019-10-18  8:14 ` [PATCH v5 5/5] qapi: Allow introspecting fix for savevm's cooperation with blockdev Markus Armbruster
  4 siblings, 0 replies; 7+ messages in thread
From: Markus Armbruster @ 2019-10-18  8:14 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, Peter Krempa, mdroth

From: Peter Krempa <pkrempa@redhat.com>

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 tests/test-qmp-cmds.c                   | 24 ++++++++++++++++++++++++
 tests/qapi-schema/qapi-schema-test.json | 18 ++++++++++++++++++
 tests/qapi-schema/qapi-schema-test.out  | 23 +++++++++++++++++++++++
 tests/qapi-schema/test-qapi.py          | 13 +++++++++----
 4 files changed, 74 insertions(+), 4 deletions(-)

diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c
index 36fdf5b115..27b0afe55a 100644
--- a/tests/test-qmp-cmds.c
+++ b/tests/test-qmp-cmds.c
@@ -51,6 +51,30 @@ void qmp_test_features(FeatureStruct0 *fs0, FeatureStruct1 *fs1,
 {
 }
 
+void qmp_test_command_features0(Error **errp)
+{
+}
+
+void qmp_test_command_features1(Error **errp)
+{
+}
+
+void qmp_test_command_features3(Error **errp)
+{
+}
+
+void qmp_test_command_cond_features1(Error **errp)
+{
+}
+
+void qmp_test_command_cond_features2(Error **errp)
+{
+}
+
+void qmp_test_command_cond_features3(Error **errp)
+{
+}
+
 UserDefTwo *qmp_user_def_cmd2(UserDefOne *ud1a,
                               bool has_udb1, UserDefOne *ud1b,
                               Error **errp)
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 75c42eb0e3..9abf175fe0 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -290,3 +290,21 @@
             'cfs1': 'CondFeatureStruct1',
             'cfs2': 'CondFeatureStruct2',
             'cfs3': 'CondFeatureStruct3' } }
+
+# test 'features' for command
+
+{ 'command': 'test-command-features0',
+  'features': [] }
+{ 'command': 'test-command-features1',
+  'features': [ 'feature1' ] }
+{ 'command': 'test-command-features3',
+  'features': [ 'feature1', 'feature2' ] }
+
+{ 'command': 'test-command-cond-features1',
+  'features': [ { 'name': 'feature1', 'if': 'defined(TEST_IF_FEATURE_1)'} ] }
+{ 'command': 'test-command-cond-features2',
+  'features': [ { 'name': 'feature1', 'if': 'defined(TEST_IF_FEATURE_1)'},
+                { 'name': 'feature2', 'if': 'defined(TEST_IF_FEATURE_2)'} ] }
+{ 'command': 'test-command-cond-features3',
+  'features': [ { 'name': 'feature1', 'if': [ 'defined(TEST_IF_COND_1)',
+                                              'defined(TEST_IF_COND_2)'] } ] }
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index aca43186a9..3660e75a48 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -412,3 +412,26 @@ object q_obj_test-features-arg
     member cfs3: CondFeatureStruct3 optional=False
 command test-features q_obj_test-features-arg -> None
     gen=True success_response=True boxed=False oob=False preconfig=False
+command test-command-features0 None -> None
+    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
+    feature feature1
+command test-command-features3 None -> None
+    gen=True success_response=True boxed=False oob=False preconfig=False
+    feature feature1
+    feature feature2
+command test-command-cond-features1 None -> None
+    gen=True success_response=True boxed=False oob=False preconfig=False
+    feature feature1
+        if ['defined(TEST_IF_FEATURE_1)']
+command test-command-cond-features2 None -> None
+    gen=True success_response=True boxed=False oob=False preconfig=False
+    feature feature1
+        if ['defined(TEST_IF_FEATURE_1)']
+    feature feature2
+        if ['defined(TEST_IF_FEATURE_2)']
+command test-command-cond-features3 None -> None
+    gen=True success_response=True boxed=False oob=False preconfig=False
+    feature feature1
+        if ['defined(TEST_IF_COND_1)', 'defined(TEST_IF_COND_2)']
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index d31ac4bbb7..2bd9fd8742 100755
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -61,10 +61,7 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
             self._print_if(m.ifcond, 8)
         self._print_variants(variants)
         self._print_if(ifcond)
-        if features:
-            for f in features:
-                print('    feature %s' % f.name)
-                self._print_if(f.ifcond, 8)
+        self._print_features(features)
 
     def visit_alternate_type(self, name, info, ifcond, variants):
         print('alternate %s' % name)
@@ -80,6 +77,7 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
         print('    gen=%s success_response=%s boxed=%s oob=%s preconfig=%s'
               % (gen, success_response, boxed, allow_oob, allow_preconfig))
         self._print_if(ifcond)
+        self._print_features(features)
 
     def visit_event(self, name, info, ifcond, arg_type, boxed):
         print('event %s %s' % (name, arg_type and arg_type.name))
@@ -99,6 +97,13 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
         if ifcond:
             print('%sif %s' % (' ' * indent, ifcond))
 
+    @classmethod
+    def _print_features(cls, features):
+        if features:
+            for f in features:
+                print('    feature %s' % f.name)
+                cls._print_if(f.ifcond, 8)
+
 
 def test_frontend(fname):
     schema = QAPISchema(fname)
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v5 4/5] tests/qapi-schema: Cover feature documentation comments
  2019-10-18  8:14 [PATCH v5 0/5] qapi: Add detection for the 'savevm' fix for blockdev Markus Armbruster
                   ` (2 preceding siblings ...)
  2019-10-18  8:14 ` [PATCH v5 3/5] tests: qapi: Test 'features' of commands Markus Armbruster
@ 2019-10-18  8:14 ` Markus Armbruster
  2019-10-18 13:26   ` Eric Blake
  2019-10-18  8:14 ` [PATCH v5 5/5] qapi: Allow introspecting fix for savevm's cooperation with blockdev Markus Armbruster
  4 siblings, 1 reply; 7+ messages in thread
From: Markus Armbruster @ 2019-10-18  8:14 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, mdroth

Commit 8aa3a33e44 "tests/qapi-schema: Test for good feature lists in
structs" neglected to cover documentation comments, and the previous
commit followed its example.  Make up for them.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 tests/qapi-schema/doc-good.texi | 22 ++++++++++++++++++++++
 tests/qapi-schema/doc-good.json | 17 +++++++++++++++--
 tests/qapi-schema/doc-good.out  |  5 +++++
 3 files changed, 42 insertions(+), 2 deletions(-)

diff --git a/tests/qapi-schema/doc-good.texi b/tests/qapi-schema/doc-good.texi
index 2526abc6d9..2ce8b883c9 100644
--- a/tests/qapi-schema/doc-good.texi
+++ b/tests/qapi-schema/doc-good.texi
@@ -122,6 +122,12 @@ Not documented
 @*@b{If:} @code{defined(IFSTR)}
 @end table
 
+@b{Features:}
+@table @asis
+@item @code{variant1-feat}
+a feature
+@end table
+
 @end deftp
 
 
@@ -182,6 +188,14 @@ argument
 Not documented
 @end table
 
+@b{Features:}
+@table @asis
+@item @code{cmd-feat1}
+a feature
+@item @code{cmd-feat2}
+another feature
+@end table
+
 @b{Note:}
 @code{arg3} is undocumented
 
@@ -227,6 +241,14 @@ If you're bored enough to read this, go see a video of boxed cats
 
 @b{Arguments:} the members of @code{Object}
 
+@b{Features:}
+@table @asis
+@item @code{cmd-feat1}
+a feature
+@item @code{cmd-feat2}
+another feature
+@end table
+
 @b{Example:}
 @example
 -> in
diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json
index f7fb48af38..7dc21e58a3 100644
--- a/tests/qapi-schema/doc-good.json
+++ b/tests/qapi-schema/doc-good.json
@@ -71,8 +71,12 @@
 # A paragraph
 #
 # Another paragraph (but no @var: line)
+#
+# Features:
+# @variant1-feat: a feature
 ##
 { 'struct': 'Variant1',
+  'features': [ 'variant1-feat' ],
   'data': { 'var1': { 'type': 'str', 'if': 'defined(IFSTR)' } } }
 
 ##
@@ -104,6 +108,10 @@
 #
 # @arg2: the second
 # argument
+#
+# Features:
+# @cmd-feat1: a feature
+# @cmd-feat2: another feature
 # Note: @arg3 is undocumented
 # Returns: @Object
 # TODO: frobnicate
@@ -123,11 +131,15 @@
 ##
 { 'command': 'cmd',
   'data': { 'arg1': 'int', '*arg2': 'str', 'arg3': 'bool' },
-  'returns': 'Object' }
+  'returns': 'Object',
+  'features': [ 'cmd-feat1', 'cmd-feat2' ] }
 
 ##
 # @cmd-boxed:
 # If you're bored enough to read this, go see a video of boxed cats
+# Features:
+# @cmd-feat1: a feature
+# @cmd-feat2: another feature
 # Example:
 #
 # -> in
@@ -135,4 +147,5 @@
 # <- out
 ##
 { 'command': 'cmd-boxed', 'boxed': true,
-  'data': 'Object' }
+  'data': 'Object',
+  'features': [ 'cmd-feat1', 'cmd-feat2' ] }
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index 6562e1f412..f78fdef6a9 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -20,6 +20,7 @@ object Base
 object Variant1
     member var1: str optional=False
         if ['defined(IFSTR)']
+    feature variant1-feat
 object Variant2
 object Object
     base Base
@@ -47,8 +48,12 @@ object q_obj_cmd-arg
     member arg3: bool optional=False
 command cmd q_obj_cmd-arg -> Object
     gen=True success_response=True boxed=False oob=False preconfig=False
+    feature cmd-feat1
+    feature cmd-feat2
 command cmd-boxed Object -> None
     gen=True success_response=True boxed=True oob=False preconfig=False
+    feature cmd-feat1
+    feature cmd-feat2
 doc freeform
     body=
 = Section
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v5 5/5] qapi: Allow introspecting fix for savevm's cooperation with blockdev
  2019-10-18  8:14 [PATCH v5 0/5] qapi: Add detection for the 'savevm' fix for blockdev Markus Armbruster
                   ` (3 preceding siblings ...)
  2019-10-18  8:14 ` [PATCH v5 4/5] tests/qapi-schema: Cover feature documentation comments Markus Armbruster
@ 2019-10-18  8:14 ` Markus Armbruster
  4 siblings, 0 replies; 7+ messages in thread
From: Markus Armbruster @ 2019-10-18  8:14 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, Peter Krempa, mdroth

From: Peter Krempa <pkrempa@redhat.com>

'savevm' was buggy as it considered all monitor-owned block device
nodes for snapshot. With the introduction of -blockdev, the common
usage made all nodes including protocol and backing file nodes be
monitor-owned and thus considered for snapshot.

This is a problem since the 'file' protocol nodes can't have internal
snapshots and it does not make sense to take snapshot of nodes
representing backing files.

This was fixed by commit 05f4aced658a02b02. Clients need to be able to
detect whether this fix is present.

Since savevm does not have an QMP alternative, add the feature for the
'human-monitor-command' backdoor which is used to call this command in
modern use.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 qapi/misc.json | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/qapi/misc.json b/qapi/misc.json
index 6bd11f50e6..33b94e3589 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -1020,6 +1020,12 @@
 #
 # @cpu-index: The CPU to use for commands that require an implicit CPU
 #
+# Features:
+# @savevm-monitor-nodes: If present, HMP command savevm only snapshots
+#                        monitor-owned nodes if they have no parents.
+#                        This allows the use of 'savevm' with
+#                        -blockdev. (since 4.2)
+#
 # Returns: the output of the command as a string
 #
 # Since: 0.14.0
@@ -1047,7 +1053,8 @@
 ##
 { 'command': 'human-monitor-command',
   'data': {'command-line': 'str', '*cpu-index': 'int'},
-  'returns': 'str' }
+  'returns': 'str',
+  'features': [ 'savevm-monitor-nodes' ] }
 
 ##
 # @change:
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v5 4/5] tests/qapi-schema: Cover feature documentation comments
  2019-10-18  8:14 ` [PATCH v5 4/5] tests/qapi-schema: Cover feature documentation comments Markus Armbruster
@ 2019-10-18 13:26   ` Eric Blake
  0 siblings, 0 replies; 7+ messages in thread
From: Eric Blake @ 2019-10-18 13:26 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: kwolf, mdroth

On 10/18/19 3:14 AM, Markus Armbruster wrote:
> Commit 8aa3a33e44 "tests/qapi-schema: Test for good feature lists in
> structs" neglected to cover documentation comments, and the previous
> commit followed its example.  Make up for them.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---

> @@ -227,6 +241,14 @@ If you're bored enough to read this, go see a video of boxed cats

Meow.

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2019-10-18 13:27 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-18  8:14 [PATCH v5 0/5] qapi: Add detection for the 'savevm' fix for blockdev Markus Armbruster
2019-10-18  8:14 ` [PATCH v5 1/5] tests/qapi-schema: Tidy up test output indentation Markus Armbruster
2019-10-18  8:14 ` [PATCH v5 2/5] qapi: Add feature flags to commands Markus Armbruster
2019-10-18  8:14 ` [PATCH v5 3/5] tests: qapi: Test 'features' of commands Markus Armbruster
2019-10-18  8:14 ` [PATCH v5 4/5] tests/qapi-schema: Cover feature documentation comments Markus Armbruster
2019-10-18 13:26   ` Eric Blake
2019-10-18  8:14 ` [PATCH v5 5/5] qapi: Allow introspecting fix for savevm's cooperation with blockdev Markus Armbruster

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.