From nobody Sat May 4 13:19:26 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1554734433121666.747787685318; Mon, 8 Apr 2019 07:40:33 -0700 (PDT) Received: from localhost ([127.0.0.1]:54086 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hDVRi-0001RV-2W for importer@patchew.org; Mon, 08 Apr 2019 10:40:26 -0400 Received: from eggs.gnu.org ([209.51.188.92]:55417) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hDVO1-0007Kn-1C for qemu-devel@nongnu.org; Mon, 08 Apr 2019 10:36:39 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hDVNx-0000Sn-FP for qemu-devel@nongnu.org; Mon, 08 Apr 2019 10:36:35 -0400 Received: from mx1.redhat.com ([209.132.183.28]:60501) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hDVNq-0000Lk-CC; Mon, 08 Apr 2019 10:36:26 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id F0EACC074128; Mon, 8 Apr 2019 14:36:23 +0000 (UTC) Received: from linux.fritz.box.com (ovpn-117-165.ams2.redhat.com [10.36.117.165]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7209317ADF; Mon, 8 Apr 2019 14:36:20 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Mon, 8 Apr 2019 16:35:40 +0200 Message-Id: <20190408143543.3982-2-kwolf@redhat.com> In-Reply-To: <20190408143543.3982-1-kwolf@redhat.com> References: <20190408143543.3982-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Mon, 08 Apr 2019 14:36:24 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH 1/4] qapi: Support features for structs X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, pkrempa@redhat.com, armbru@redhat.com, qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Sometimes, the behaviour of QEMU changes compatibly, but without a 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. This allows to add a list of features to struct definitions that will be made visible to QMP clients through schema introspection. Signed-off-by: Kevin Wolf --- qapi/introspect.json | 8 ++++- docs/devel/qapi-code-gen.txt | 38 ++++++++++++++++++++ scripts/qapi/common.py | 49 ++++++++++++++++++++------ scripts/qapi/doc.py | 3 +- scripts/qapi/introspect.py | 6 +++- scripts/qapi/types.py | 3 +- scripts/qapi/visit.py | 3 +- tests/qapi-schema/double-type.err | 2 +- tests/qapi-schema/test-qapi.py | 3 +- tests/qapi-schema/unknown-expr-key.err | 2 +- 10 files changed, 99 insertions(+), 18 deletions(-) diff --git a/qapi/introspect.json b/qapi/introspect.json index 3d22166b2b..3cb6c1aca4 100644 --- a/qapi/introspect.json +++ b/qapi/introspect.json @@ -174,6 +174,11 @@ # and may even differ from the order of the values of the # enum type of the @tag. # +# @features: names of features that are supported by this version and buil= d and +# aren't othervise visible through schema introspection (e.g. c= hange +# of behaviour related to an object type that didn't come with a +# syntactic change in the schema of the object type) (since: 4.= 1) +# # Values of this type are JSON object on the wire. # # Since: 2.5 @@ -181,7 +186,8 @@ { 'struct': 'SchemaInfoObject', 'data': { 'members': [ 'SchemaInfoObjectMember' ], '*tag': 'str', - '*variants': [ 'SchemaInfoObjectVariant' ] } } + '*variants': [ 'SchemaInfoObjectVariant' ], + '*features': [ 'str' ] } } =20 ## # @SchemaInfoObjectMember: diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt index b517b0cfbf..e8ec8ac1de 100644 --- a/docs/devel/qapi-code-gen.txt +++ b/docs/devel/qapi-code-gen.txt @@ -719,6 +719,34 @@ any non-empty complex type (struct, union, or alternat= e), and a pointer to that QAPI type is passed as a single argument. =20 =20 +=3D=3D=3D Features =3D=3D=3D + +Sometimes, the behaviour of QEMU changes compatibly, but without a +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. + +In the schema, features can be specified as simple strings, for example: + +{ 'struct': 'TestType', + 'data': { 'number': 'int' }, + 'features': [ 'allow-negative-numbers' ] } + +Another option is to specify features as dictionaries, where the key +'name' specifies the feature string to be exposed to clients: + +{ 'struct': 'TestType', + 'data': { 'number': 'int' }, + 'features': [ { 'name': 'allow-negative-numbers' } ] } + +This expanded form is necessary if you want to make the feature +conditional (see below in "Configuring the schema"). + + =3D=3D=3D Downstream extensions =3D=3D=3D =20 QAPI schema names that are externally visible, say in the Client JSON @@ -771,6 +799,16 @@ Example: a conditional 'bar' enum member. [ 'foo', { 'name' : 'bar', 'if': 'defined(IFCOND)' } ] } =20 +Similarly, features can be specified as a dictionary with a 'name' and +an 'if' key. + +Example: a conditional 'allow-negative-numbers' feature + +{ 'struct': 'TestType', + 'data': { 'number': 'int' }, + 'features': [ { 'name': 'allow-negative-numbers', + 'if' 'defined(IFCOND)' } ] } + Please note that you are responsible to ensure that the C code will compile with an arbitrary combination of conditions, since the generators are unable to check it at this point. diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index f07869ec73..692d787f04 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -886,12 +886,29 @@ def check_enum(expr, info): def check_struct(expr, info): name =3D expr['struct'] members =3D expr['data'] + features =3D expr.get('features') =20 check_type(info, "'data' for struct '%s'" % name, members, allow_dict=3DTrue, allow_optional=3DTrue) check_type(info, "'base' for struct '%s'" % name, expr.get('base'), allow_metas=3D['struct']) =20 + if features: + if not isinstance(features, list): + raise QAPISemError(info, + "Struct '%s' requires an array for 'feature= s'" % + name) + for f in features: + assert isinstance(f, dict) + check_known_keys(info, "feature of struct %s" % (name), f, + ['name'], ['if']) + + check_if(f, info) + f['if'] =3D listify_cond(f.get('if')) + + if not isinstance(f['name'], str): + raise QAPISemError(info, "Feature names for struct '%s' mu= st " + "be strings" % name) =20 def check_known_keys(info, source, keys, required, optional): =20 @@ -947,6 +964,10 @@ def normalize_members(members): continue members[key] =3D {'type': arg} =20 +def normalize_features(features): + if isinstance(features, list): + features[:] =3D [f if isinstance(f, dict) else {'name': f} + for f in features] =20 def check_exprs(exprs): global all_names @@ -986,8 +1007,10 @@ def check_exprs(exprs): normalize_members(expr['data']) elif 'struct' in expr: meta =3D 'struct' - check_keys(expr_elem, 'struct', ['data'], ['base', 'if']) + check_keys(expr_elem, 'struct', ['data'], + ['base', 'if', 'features']) normalize_members(expr['data']) + normalize_features(expr.get('features')) struct_types[expr[meta]] =3D expr elif 'command' in expr: meta =3D 'command' @@ -1126,10 +1149,12 @@ class QAPISchemaVisitor(object): def visit_array_type(self, name, info, ifcond, element_type): pass =20 - def visit_object_type(self, name, info, ifcond, base, members, variant= s): + def visit_object_type(self, name, info, ifcond, base, members, variant= s, + features): pass =20 - def visit_object_type_flat(self, name, info, ifcond, members, variants= ): + def visit_object_type_flat(self, name, info, ifcond, members, variants, + features): pass =20 def visit_alternate_type(self, name, info, ifcond, variants): @@ -1290,7 +1315,7 @@ class QAPISchemaArrayType(QAPISchemaType): =20 class QAPISchemaObjectType(QAPISchemaType): def __init__(self, name, info, doc, ifcond, - base, local_members, variants): + base, local_members, variants, features): # struct has local_members, optional base, and no variants # flat union has base, variants, and no local_members # simple union has local_members, variants, and no base @@ -1307,6 +1332,7 @@ class QAPISchemaObjectType(QAPISchemaType): self.local_members =3D local_members self.variants =3D variants self.members =3D None + self.features =3D features =20 def check(self, schema): QAPISchemaType.check(self, schema) @@ -1368,9 +1394,11 @@ class QAPISchemaObjectType(QAPISchemaType): =20 def visit(self, visitor): visitor.visit_object_type(self.name, self.info, self.ifcond, - self.base, self.local_members, self.vari= ants) + self.base, self.local_members, self.vari= ants, + self.features) visitor.visit_object_type_flat(self.name, self.info, self.ifcond, - self.members, self.variants) + self.members, self.variants, + self.features) =20 =20 class QAPISchemaMember(object): @@ -1675,7 +1703,7 @@ class QAPISchema(object): ('null', 'null', 'QNull' + pointer_suffix)]: self._def_builtin_type(*t) self.the_empty_object_type =3D QAPISchemaObjectType( - 'q_empty', None, None, None, None, [], None) + 'q_empty', None, None, None, None, [], None, []) self._def_entity(self.the_empty_object_type) =20 qtypes =3D ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', @@ -1721,7 +1749,7 @@ class QAPISchema(object): assert ifcond =3D=3D typ._ifcond # pylint: disable=3Dprotected= -access else: self._def_entity(QAPISchemaObjectType(name, info, doc, ifcond, - None, members, None)) + None, members, None, [])) return name =20 def _def_enum_type(self, expr, info, doc): @@ -1752,9 +1780,10 @@ class QAPISchema(object): base =3D expr.get('base') data =3D expr['data'] ifcond =3D expr.get('if') + features =3D expr.get('features') self._def_entity(QAPISchemaObjectType(name, info, doc, ifcond, bas= e, self._make_members(data, inf= o), - None)) + None, features)) =20 def _make_variant(self, case, typ, ifcond): return QAPISchemaObjectTypeVariant(case, typ, ifcond) @@ -1795,7 +1824,7 @@ class QAPISchema(object): QAPISchemaObjectType(name, info, doc, ifcond, base, members, QAPISchemaObjectTypeVariants(tag_name, tag_member, - variants))) + variants), [= ])) =20 def _def_alternate_type(self, expr, info, doc): name =3D expr['alternate'] diff --git a/scripts/qapi/doc.py b/scripts/qapi/doc.py index 5c8c136899..433e9fcbfb 100755 --- a/scripts/qapi/doc.py +++ b/scripts/qapi/doc.py @@ -220,7 +220,8 @@ class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVis= itor): body=3Dtexi_entity(doc, 'Values', ifcond, member_func=3Dtexi_enum_va= lue))) =20 - def visit_object_type(self, name, info, ifcond, base, members, variant= s): + def visit_object_type(self, name, info, ifcond, base, members, variant= s, + features): doc =3D self.cur_doc if base and base.is_implicit(): base =3D None diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py index f7f2ca07e4..8909cecde4 100644 --- a/scripts/qapi/introspect.py +++ b/scripts/qapi/introspect.py @@ -188,11 +188,15 @@ const QLitObject %(c_name)s =3D %(c_string)s; self._gen_qlit('[' + element + ']', 'array', {'element-type': elem= ent}, ifcond) =20 - def visit_object_type_flat(self, name, info, ifcond, members, variants= ): + def visit_object_type_flat(self, name, info, ifcond, members, variants, + features): obj =3D {'members': [self._gen_member(m) for m in members]} if variants: obj.update(self._gen_variants(variants.tag_member.name, variants.variants)) + if features: + obj['features'] =3D [ (f['name'], f) for f in features ] + self._gen_qlit(name, 'object', obj, ifcond) =20 def visit_alternate_type(self, name, info, ifcond, variants): diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py index 2bd6fcd44f..3edd9374aa 100644 --- a/scripts/qapi/types.py +++ b/scripts/qapi/types.py @@ -227,7 +227,8 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisito= r): self._genh.add(gen_array(name, element_type)) self._gen_type_cleanup(name) =20 - def visit_object_type(self, name, info, ifcond, base, members, variant= s): + def visit_object_type(self, name, info, ifcond, base, members, variant= s, + features): # Nothing to do for the special empty builtin if name =3D=3D 'q_empty': return diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py index 826b8066e1..c1cd675c95 100644 --- a/scripts/qapi/visit.py +++ b/scripts/qapi/visit.py @@ -326,7 +326,8 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisit= or): self._genh.add(gen_visit_decl(name)) self._genc.add(gen_visit_list(name, element_type)) =20 - def visit_object_type(self, name, info, ifcond, base, members, variant= s): + def visit_object_type(self, name, info, ifcond, base, members, variant= s, + features): # Nothing to do for the special empty builtin if name =3D=3D 'q_empty': return diff --git a/tests/qapi-schema/double-type.err b/tests/qapi-schema/double-t= ype.err index 799193dba1..69457173a7 100644 --- a/tests/qapi-schema/double-type.err +++ b/tests/qapi-schema/double-type.err @@ -1,2 +1,2 @@ tests/qapi-schema/double-type.json:2: Unknown key 'command' in struct 'bar' -Valid keys are 'base', 'data', 'if', 'struct'. +Valid keys are 'base', 'data', 'features', 'if', 'struct'. diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py index d21fca01fc..f2d6815c86 100644 --- a/tests/qapi-schema/test-qapi.py +++ b/tests/qapi-schema/test-qapi.py @@ -38,7 +38,8 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor): print('array %s %s' % (name, element_type.name)) self._print_if(ifcond) =20 - def visit_object_type(self, name, info, ifcond, base, members, variant= s): + def visit_object_type(self, name, info, ifcond, base, members, variant= s, + features): print('object %s' % name) if base: print(' base %s' % base.name) diff --git a/tests/qapi-schema/unknown-expr-key.err b/tests/qapi-schema/unk= nown-expr-key.err index 6ff8bb99c5..4340eaf894 100644 --- a/tests/qapi-schema/unknown-expr-key.err +++ b/tests/qapi-schema/unknown-expr-key.err @@ -1,2 +1,2 @@ tests/qapi-schema/unknown-expr-key.json:2: Unknown keys 'bogus', 'phony' i= n struct 'bar' -Valid keys are 'base', 'data', 'if', 'struct'. +Valid keys are 'base', 'data', 'features', 'if', 'struct'. --=20 2.20.1 From nobody Sat May 4 13:19:26 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1554734304328703.1813410357573; Mon, 8 Apr 2019 07:38:24 -0700 (PDT) Received: from localhost ([127.0.0.1]:54026 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hDVPh-0008Hg-A4 for importer@patchew.org; Mon, 08 Apr 2019 10:38:21 -0400 Received: from eggs.gnu.org ([209.51.188.92]:55421) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hDVO1-0007Kp-1B for qemu-devel@nongnu.org; Mon, 08 Apr 2019 10:36:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hDVNy-0000To-N7 for qemu-devel@nongnu.org; Mon, 08 Apr 2019 10:36:35 -0400 Received: from mx1.redhat.com ([209.132.183.28]:52776) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hDVNq-0000N0-IB; Mon, 08 Apr 2019 10:36:28 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id AA48EC057F4F; Mon, 8 Apr 2019 14:36:25 +0000 (UTC) Received: from linux.fritz.box.com (ovpn-117-165.ams2.redhat.com [10.36.117.165]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4670417ADF; Mon, 8 Apr 2019 14:36:24 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Mon, 8 Apr 2019 16:35:41 +0200 Message-Id: <20190408143543.3982-3-kwolf@redhat.com> In-Reply-To: <20190408143543.3982-1-kwolf@redhat.com> References: <20190408143543.3982-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Mon, 08 Apr 2019 14:36:25 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH 2/4] tests/qapi-schema: Test for good feature lists in structs X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, pkrempa@redhat.com, armbru@redhat.com, qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Signed-off-by: Kevin Wolf --- tests/qapi-schema/qapi-schema-test.json | 27 +++++++++++++++++++++++++ tests/qapi-schema/qapi-schema-test.out | 26 ++++++++++++++++++++++++ tests/qapi-schema/test-qapi.py | 4 ++++ 3 files changed, 57 insertions(+) diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qa= pi-schema-test.json index 0952c68734..263514b448 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -242,3 +242,30 @@ { 'foo': 'TestIfStruct', 'bar': { 'type': ['TestIfEnum'], 'if': 'defined(TEST_IF_EVT_BAR)' } }, 'if': 'defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)' } + +# test 'features' for structs + +{ 'struct': 'FeatureStruct0', + 'data': { 'foo': 'int' }, + 'features': [] } +{ 'struct': 'FeatureStruct1', + 'data': { 'foo': 'int' }, + 'features': [ 'feature1' ] } +{ 'struct': 'FeatureStruct2', + 'data': { 'foo': 'int' }, + 'features': [ { 'name': 'feature1' } ] } +{ 'struct': 'FeatureStruct3', + 'data': { 'foo': 'int' }, + 'features': [ 'feature1', 'feature2' ] } + +{ 'struct': 'CondFeatureStruct1', + 'data': { 'foo': 'int' }, + 'features': [ { 'name': 'feature1', 'if': 'defined(TEST_IF_FEATURE_1)'} = ] } +{ 'struct': 'CondFeatureStruct2', + 'data': { 'foo': 'int' }, + 'features': [ { 'name': 'feature1', 'if': 'defined(TEST_IF_FEATURE_1)'}, + { 'name': 'feature2', 'if': 'defined(TEST_IF_FEATURE_2)'} = ] } +{ 'struct': 'CondFeatureStruct3', + 'data': { 'foo': 'int' }, + '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/qap= i-schema-test.out index 77fb1e1aa9..490e202f65 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -354,3 +354,29 @@ object q_obj_TestIfEvent-arg event TestIfEvent q_obj_TestIfEvent-arg boxed=3DFalse if ['defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)'] +object FeatureStruct0 + member foo: int optional=3DFalse +object FeatureStruct1 + member foo: int optional=3DFalse + feature feature1 +object FeatureStruct2 + member foo: int optional=3DFalse + feature feature1 +object FeatureStruct3 + member foo: int optional=3DFalse + feature feature1 + feature feature2 +object CondFeatureStruct1 + member foo: int optional=3DFalse + feature feature1 + if ['defined(TEST_IF_FEATURE_1)'] +object CondFeatureStruct2 + member foo: int optional=3DFalse + feature feature1 + if ['defined(TEST_IF_FEATURE_1)'] + feature feature2 + if ['defined(TEST_IF_FEATURE_2)'] +object CondFeatureStruct3 + member foo: int optional=3DFalse + 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 f2d6815c86..08e29c23a6 100644 --- a/tests/qapi-schema/test-qapi.py +++ b/tests/qapi-schema/test-qapi.py @@ -49,6 +49,10 @@ 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.get('if'), 8) =20 def visit_alternate_type(self, name, info, ifcond, variants): print('alternate %s' % name) --=20 2.20.1 From nobody Sat May 4 13:19:26 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1554734312817189.3045379482445; Mon, 8 Apr 2019 07:38:32 -0700 (PDT) Received: from localhost ([127.0.0.1]:54028 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hDVPo-0008NQ-OE for importer@patchew.org; Mon, 08 Apr 2019 10:38:28 -0400 Received: from eggs.gnu.org ([209.51.188.92]:55459) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hDVO2-0007ND-Te for qemu-devel@nongnu.org; Mon, 08 Apr 2019 10:36:42 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hDVO1-0000VR-9V for qemu-devel@nongnu.org; Mon, 08 Apr 2019 10:36:38 -0400 Received: from mx1.redhat.com ([209.132.183.28]:57090) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hDVNs-0000OI-9S; Mon, 08 Apr 2019 10:36:29 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 62B9D3001A73; Mon, 8 Apr 2019 14:36:27 +0000 (UTC) Received: from linux.fritz.box.com (ovpn-117-165.ams2.redhat.com [10.36.117.165]) by smtp.corp.redhat.com (Postfix) with ESMTP id F39FA6402B; Mon, 8 Apr 2019 14:36:25 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Mon, 8 Apr 2019 16:35:42 +0200 Message-Id: <20190408143543.3982-4-kwolf@redhat.com> In-Reply-To: <20190408143543.3982-1-kwolf@redhat.com> References: <20190408143543.3982-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.45]); Mon, 08 Apr 2019 14:36:27 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH 3/4] tests/qapi-schema: Error case tests for features in structs X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, pkrempa@redhat.com, armbru@redhat.com, qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Signed-off-by: Kevin Wolf --- tests/qapi-schema/features-bad-type.json | 3 +++ tests/qapi-schema/features-missing-name.json | 3 +++ tests/qapi-schema/features-name-bad-type.json | 3 +++ tests/qapi-schema/features-no-list.json | 3 +++ tests/qapi-schema/features-unknown-key.json | 3 +++ tests/Makefile.include | 5 +++++ tests/qapi-schema/features-bad-type.err | 1 + tests/qapi-schema/features-bad-type.exit | 1 + tests/qapi-schema/features-bad-type.out | 0 tests/qapi-schema/features-missing-name.err | 1 + tests/qapi-schema/features-missing-name.exit | 1 + tests/qapi-schema/features-missing-name.out | 0 tests/qapi-schema/features-name-bad-type.err | 1 + tests/qapi-schema/features-name-bad-type.exit | 1 + tests/qapi-schema/features-name-bad-type.out | 0 tests/qapi-schema/features-no-list.err | 1 + tests/qapi-schema/features-no-list.exit | 1 + tests/qapi-schema/features-no-list.out | 0 tests/qapi-schema/features-unknown-key.err | 2 ++ tests/qapi-schema/features-unknown-key.exit | 1 + tests/qapi-schema/features-unknown-key.out | 0 21 files changed, 31 insertions(+) create mode 100644 tests/qapi-schema/features-bad-type.json create mode 100644 tests/qapi-schema/features-missing-name.json create mode 100644 tests/qapi-schema/features-name-bad-type.json create mode 100644 tests/qapi-schema/features-no-list.json create mode 100644 tests/qapi-schema/features-unknown-key.json create mode 100644 tests/qapi-schema/features-bad-type.err create mode 100644 tests/qapi-schema/features-bad-type.exit create mode 100644 tests/qapi-schema/features-bad-type.out create mode 100644 tests/qapi-schema/features-missing-name.err create mode 100644 tests/qapi-schema/features-missing-name.exit create mode 100644 tests/qapi-schema/features-missing-name.out create mode 100644 tests/qapi-schema/features-name-bad-type.err create mode 100644 tests/qapi-schema/features-name-bad-type.exit create mode 100644 tests/qapi-schema/features-name-bad-type.out create mode 100644 tests/qapi-schema/features-no-list.err create mode 100644 tests/qapi-schema/features-no-list.exit create mode 100644 tests/qapi-schema/features-no-list.out create mode 100644 tests/qapi-schema/features-unknown-key.err create mode 100644 tests/qapi-schema/features-unknown-key.exit create mode 100644 tests/qapi-schema/features-unknown-key.out diff --git a/tests/qapi-schema/features-bad-type.json b/tests/qapi-schema/f= eatures-bad-type.json new file mode 100644 index 0000000000..57db5540e7 --- /dev/null +++ b/tests/qapi-schema/features-bad-type.json @@ -0,0 +1,3 @@ +{ 'struct': 'FeatureStruct0', + 'data': { 'foo': 'int' }, + 'features': [ [ 'a feature cannot be an array' ] ] } diff --git a/tests/qapi-schema/features-missing-name.json b/tests/qapi-sche= ma/features-missing-name.json new file mode 100644 index 0000000000..2314f97c00 --- /dev/null +++ b/tests/qapi-schema/features-missing-name.json @@ -0,0 +1,3 @@ +{ 'struct': 'FeatureStruct0', + 'data': { 'foo': 'int' }, + 'features': [ { 'if': 'defined(NAMELESS_FEATURES)' } ] } diff --git a/tests/qapi-schema/features-name-bad-type.json b/tests/qapi-sch= ema/features-name-bad-type.json new file mode 100644 index 0000000000..b07139978a --- /dev/null +++ b/tests/qapi-schema/features-name-bad-type.json @@ -0,0 +1,3 @@ +{ 'struct': 'FeatureStruct0', + 'data': { 'foo': 'int' }, + 'features': [ { 'name': { 'feature-type': 'object' } } ] } diff --git a/tests/qapi-schema/features-no-list.json b/tests/qapi-schema/fe= atures-no-list.json new file mode 100644 index 0000000000..9484fd94fc --- /dev/null +++ b/tests/qapi-schema/features-no-list.json @@ -0,0 +1,3 @@ +{ 'struct': 'FeatureStruct0', + 'data': { 'foo': 'int' }, + 'features': 'bar' } diff --git a/tests/qapi-schema/features-unknown-key.json b/tests/qapi-schem= a/features-unknown-key.json new file mode 100644 index 0000000000..134df3b503 --- /dev/null +++ b/tests/qapi-schema/features-unknown-key.json @@ -0,0 +1,3 @@ +{ 'struct': 'FeatureStruct0', + 'data': { 'foo': 'int' }, + 'features': [ { 'name': 'bar', 'colour': 'red' } ] } diff --git a/tests/Makefile.include b/tests/Makefile.include index 6b904d7430..d116ad770c 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -377,6 +377,11 @@ qapi-schema +=3D event-boxed-empty.json qapi-schema +=3D event-case.json qapi-schema +=3D event-member-invalid-dict.json qapi-schema +=3D event-nest-struct.json +qapi-schema +=3D features-bad-type.json +qapi-schema +=3D features-missing-name.json +qapi-schema +=3D features-name-bad-type.json +qapi-schema +=3D features-no-list.json +qapi-schema +=3D features-unknown-key.json qapi-schema +=3D flat-union-array-branch.json qapi-schema +=3D flat-union-bad-base.json qapi-schema +=3D flat-union-bad-discriminator.json diff --git a/tests/qapi-schema/features-bad-type.err b/tests/qapi-schema/fe= atures-bad-type.err new file mode 100644 index 0000000000..7ca7a08ab0 --- /dev/null +++ b/tests/qapi-schema/features-bad-type.err @@ -0,0 +1 @@ +tests/qapi-schema/features-bad-type.json:1: Feature names for struct 'Feat= ureStruct0' must be strings diff --git a/tests/qapi-schema/features-bad-type.exit b/tests/qapi-schema/f= eatures-bad-type.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/features-bad-type.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/features-bad-type.out b/tests/qapi-schema/fe= atures-bad-type.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/qapi-schema/features-missing-name.err b/tests/qapi-schem= a/features-missing-name.err new file mode 100644 index 0000000000..4f1d2715aa --- /dev/null +++ b/tests/qapi-schema/features-missing-name.err @@ -0,0 +1 @@ +tests/qapi-schema/features-missing-name.json:1: Key 'name' is missing from= feature of struct FeatureStruct0 diff --git a/tests/qapi-schema/features-missing-name.exit b/tests/qapi-sche= ma/features-missing-name.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/features-missing-name.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/features-missing-name.out b/tests/qapi-schem= a/features-missing-name.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/qapi-schema/features-name-bad-type.err b/tests/qapi-sche= ma/features-name-bad-type.err new file mode 100644 index 0000000000..8a68d7cb73 --- /dev/null +++ b/tests/qapi-schema/features-name-bad-type.err @@ -0,0 +1 @@ +tests/qapi-schema/features-name-bad-type.json:1: Feature names for struct = 'FeatureStruct0' must be strings diff --git a/tests/qapi-schema/features-name-bad-type.exit b/tests/qapi-sch= ema/features-name-bad-type.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/features-name-bad-type.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/features-name-bad-type.out b/tests/qapi-sche= ma/features-name-bad-type.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/qapi-schema/features-no-list.err b/tests/qapi-schema/fea= tures-no-list.err new file mode 100644 index 0000000000..61ed68612b --- /dev/null +++ b/tests/qapi-schema/features-no-list.err @@ -0,0 +1 @@ +tests/qapi-schema/features-no-list.json:1: Struct 'FeatureStruct0' require= s an array for 'features' diff --git a/tests/qapi-schema/features-no-list.exit b/tests/qapi-schema/fe= atures-no-list.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/features-no-list.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/features-no-list.out b/tests/qapi-schema/fea= tures-no-list.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/qapi-schema/features-unknown-key.err b/tests/qapi-schema= /features-unknown-key.err new file mode 100644 index 0000000000..a1d693030d --- /dev/null +++ b/tests/qapi-schema/features-unknown-key.err @@ -0,0 +1,2 @@ +tests/qapi-schema/features-unknown-key.json:1: Unknown key 'colour' in fea= ture of struct FeatureStruct0 +Valid keys are 'if', 'name'. diff --git a/tests/qapi-schema/features-unknown-key.exit b/tests/qapi-schem= a/features-unknown-key.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/features-unknown-key.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/features-unknown-key.out b/tests/qapi-schema= /features-unknown-key.out new file mode 100644 index 0000000000..e69de29bb2 --=20 2.20.1 From nobody Sat May 4 13:19:26 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1554734506821206.2084168940321; Mon, 8 Apr 2019 07:41:46 -0700 (PDT) Received: from localhost ([127.0.0.1]:54092 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hDVSt-000262-TP for importer@patchew.org; Mon, 08 Apr 2019 10:41:39 -0400 Received: from eggs.gnu.org ([209.51.188.92]:55447) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hDVO2-0007MD-AD for qemu-devel@nongnu.org; Mon, 08 Apr 2019 10:36:42 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hDVO1-0000VV-9W for qemu-devel@nongnu.org; Mon, 08 Apr 2019 10:36:38 -0400 Received: from mx1.redhat.com ([209.132.183.28]:49078) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hDVNu-0000Q9-Du; Mon, 08 Apr 2019 10:36:32 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 1F859859FB; Mon, 8 Apr 2019 14:36:29 +0000 (UTC) Received: from linux.fritz.box.com (ovpn-117-165.ams2.redhat.com [10.36.117.165]) by smtp.corp.redhat.com (Postfix) with ESMTP id AE2F717DD4; Mon, 8 Apr 2019 14:36:27 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Mon, 8 Apr 2019 16:35:43 +0200 Message-Id: <20190408143543.3982-5-kwolf@redhat.com> In-Reply-To: <20190408143543.3982-1-kwolf@redhat.com> References: <20190408143543.3982-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Mon, 08 Apr 2019 14:36:29 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH 4/4] file-posix: Add dynamic-auto-read-only QAPI feature X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, pkrempa@redhat.com, armbru@redhat.com, qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" In commit 23dece19da4 ('file-posix: Make auto-read-only dynamic') , auto-read-only=3Don changed its behaviour in file-posix for the 4.0 release. This change cannot be detected through the usual mechanisms like schema introspection. Add a new feature flag to the schema to allow libvirt to detect the presence of the new behaviour. Signed-off-by: Kevin Wolf --- qapi/block-core.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index 7ccbfff9d0..4f96d5846b 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2843,6 +2843,13 @@ # file is large, do not use in production. # (default: off) (since: 3.0) # +# If the feature 'dynamic-auto-read-only' is present, enabled auto-read-on= ly +# means that the driver will open the image read-only at first, dynamically +# reopen the image file read-write when the first writer is attached to the +# node and reopen read-only when the last writer is detached. This allows = to +# give QEMU write permissions only on demand when an operation actually ne= eds +# write access. +# # Since: 2.9 ## { 'struct': 'BlockdevOptionsFile', @@ -2852,7 +2859,9 @@ '*aio': 'BlockdevAioOptions', '*drop-cache': {'type': 'bool', 'if': 'defined(CONFIG_LINUX)'}, - '*x-check-cache-dropped': 'bool' } } + '*x-check-cache-dropped': 'bool' }, + 'features': [ { 'name': 'dynamic-auto-read-only', + 'if': 'defined(CONFIG_POSIX)' } ] } =20 ## # @BlockdevOptionsNull: --=20 2.20.1