diff mbox series

[v2,3/6] gnttab: allow per-domain control over transitive grants

Message ID 20210922082123.54374-4-roger.pau@citrix.com (mailing list archive)
State New, archived
Headers show
Series gnttab: add per-domain controls | expand

Commit Message

Roger Pau Monne Sept. 22, 2021, 8:21 a.m. UTC
Introduce a new grant options flags field in domain create and use it
to signal whether transitive grants are allowed on the domain. This is
settable from xl using the transitive_grants option.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
 docs/man/xl.cfg.5.pod.in            | 6 ++++++
 docs/man/xl.conf.5.pod.in           | 7 +++++++
 tools/include/libxl.h               | 7 +++++++
 tools/libs/light/libxl_create.c     | 3 +++
 tools/libs/light/libxl_dm.c         | 1 +
 tools/libs/light/libxl_types.idl    | 1 +
 tools/ocaml/libs/xc/xenctrl.ml      | 1 +
 tools/ocaml/libs/xc/xenctrl.mli     | 1 +
 tools/ocaml/libs/xc/xenctrl_stubs.c | 7 ++++++-
 tools/xl/xl.c                       | 7 +++++++
 tools/xl/xl.h                       | 1 +
 tools/xl/xl_parse.c                 | 4 ++++
 xen/arch/arm/domain_build.c         | 6 ++++--
 xen/arch/x86/setup.c                | 3 ++-
 xen/common/grant_table.c            | 8 +++++++-
 xen/include/public/domctl.h         | 5 ++++-
 16 files changed, 62 insertions(+), 6 deletions(-)

Comments

Christian Lindig Sept. 22, 2021, 9:28 a.m. UTC | #1
> On 22 Sep 2021, at 09:21, Roger Pau Monne <roger.pau@citrix.com> wrote:
> 
> Introduce a new grant options flags field in domain create and use it
> to signal whether transitive grants are allowed on the domain. This is
> settable from xl using the transitive_grants option.
> 
> Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
> ---
> docs/man/xl.cfg.5.pod.in            | 6 ++++++
> docs/man/xl.conf.5.pod.in           | 7 +++++++
> tools/include/libxl.h               | 7 +++++++
> tools/libs/light/libxl_create.c     | 3 +++
> tools/libs/light/libxl_dm.c         | 1 +
> tools/libs/light/libxl_types.idl    | 1 +
> tools/ocaml/libs/xc/xenctrl.ml      | 1 +
> tools/ocaml/libs/xc/xenctrl.mli     | 1 +
> tools/ocaml/libs/xc/xenctrl_stubs.c | 7 ++++++-
> tools/xl/xl.c                       | 7 +++++++
> tools/xl/xl.h                       | 1 +
> tools/xl/xl_parse.c                 | 4 ++++
> xen/arch/arm/domain_build.c         | 6 ++++--
> xen/arch/x86/setup.c                | 3 ++-
> xen/common/grant_table.c            | 8 +++++++-
> xen/include/public/domctl.h         | 5 ++++-
> 16 files changed, 62 insertions(+), 6 deletions(-)

Acked-by: Christian Lindig <christian.lindig@citrix.com>
Jan Beulich Oct. 15, 2021, 10:05 a.m. UTC | #2
On 22.09.2021 10:21, Roger Pau Monne wrote:
> --- a/xen/arch/arm/domain_build.c
> +++ b/xen/arch/arm/domain_build.c
> @@ -2649,7 +2649,8 @@ void __init create_domUs(void)
>              .max_evtchn_port = -1,
>              .max_grant_frames = -1,
>              .max_maptrack_frames = -1,
> -            .grant_opts = XEN_DOMCTL_GRANT_version_default,
> +            .grant_opts = XEN_DOMCTL_GRANT_version_default |
> +                          XEN_DOMCTL_GRANT_transitive,
>          };
>  
>          if ( !dt_device_is_compatible(node, "xen,domain") )
> @@ -2757,7 +2758,8 @@ void __init create_dom0(void)
>          .max_evtchn_port = -1,
>          .max_grant_frames = gnttab_dom0_frames(),
>          .max_maptrack_frames = -1,
> -        .grant_opts = XEN_DOMCTL_GRANT_version_default,
> +        .grant_opts = XEN_DOMCTL_GRANT_version_default |
> +                      XEN_DOMCTL_GRANT_transitive,
>      };
>  
>      /* The vGIC for DOM0 is exactly emulating the hardware GIC */
> --- a/xen/arch/x86/setup.c
> +++ b/xen/arch/x86/setup.c
> @@ -750,7 +750,8 @@ static struct domain *__init create_dom0(const module_t *image,
>          .max_evtchn_port = -1,
>          .max_grant_frames = -1,
>          .max_maptrack_frames = -1,
> -        .grant_opts = XEN_DOMCTL_GRANT_version_default,
> +        .grant_opts = XEN_DOMCTL_GRANT_version_default |
> +                      XEN_DOMCTL_GRANT_transitive,
>          .max_vcpus = dom0_max_vcpus(),
>          .arch = {
>              .misc_flags = opt_dom0_msr_relaxed ? XEN_X86_MSR_RELAXED : 0,

While I can see that you make these adjustments for retaining backwards
compatibility, I wonder if we need to, at least for Dom0. Dom0 doesn't
normally grant anything anyway and hence would even less so use
transitive grants. Of course then there's need to be a command line
control to re-enable that, just in case.

> @@ -1965,6 +1969,8 @@ int grant_table_init(struct domain *d, int max_grant_frames,
>      gt->max_grant_frames = max_grant_frames;
>      gt->max_maptrack_frames = max_maptrack_frames;
>      gt->max_grant_version = max_grant_version;
> +    gt->allow_transitive = !!(options & XEN_DOMCTL_GRANT_transitive) &&
> +                           opt_transitive_grants;

No need for !! here afaics. Not even if there weren't the &&.

As to combining with the global option: I think if an admin requested
them for a domain, this should overrule the command line option. Which
in turn suggests that the command line option could go away at this
point. Otherwise, if you AND both together and the guest is known to
not work without this functionality, domain creation would instead
better fail (or at the very least it should be logged by the tool
stack that the request wasn't satisfied, which would require a means
to retrieve the effective setting). IOW I would see the command line
turning this off to trump the per-guest enabling request.

> --- a/xen/include/public/domctl.h
> +++ b/xen/include/public/domctl.h
> @@ -98,8 +98,11 @@ struct xen_domctl_createdomain {
>  /* Grant version, use low 4 bits. */
>  #define XEN_DOMCTL_GRANT_version_mask    0xf
>  #define XEN_DOMCTL_GRANT_version_default 0xf
> +/* Allow transitive grants. */
> +#define _XEN_DOMCTL_GRANT_transitive     4
> +#define XEN_DOMCTL_GRANT_transitive      (1U << _XEN_DOMCTL_GRANT_transitive)

Omit the former and have the latter be 0x10 or (1U << 4)?

> -#define XEN_DOMCTLGRANT_MAX XEN_DOMCTL_GRANT_version_mask
> +#define XEN_DOMCTLGRANT_MAX XEN_DOMCTL_GRANT_transitive

I didn't even spot this in patch 2 - what is this intended to be used
for? Neither there nor here I can spot any use.

Jan
Jan Beulich Oct. 15, 2021, 11:46 a.m. UTC | #3
On 22.09.2021 10:21, Roger Pau Monne wrote:
> @@ -1965,6 +1969,8 @@ int grant_table_init(struct domain *d, int max_grant_frames,
>      gt->max_grant_frames = max_grant_frames;
>      gt->max_maptrack_frames = max_maptrack_frames;
>      gt->max_grant_version = max_grant_version;
> +    gt->allow_transitive = !!(options & XEN_DOMCTL_GRANT_transitive) &&
> +                           opt_transitive_grants;

Btw, should you perhaps reject the flag being set when max version isn't 2?

Jan
Roger Pau Monne Oct. 20, 2021, 10:14 a.m. UTC | #4
On Fri, Oct 15, 2021 at 12:05:06PM +0200, Jan Beulich wrote:
> On 22.09.2021 10:21, Roger Pau Monne wrote:
> > --- a/xen/arch/arm/domain_build.c
> > +++ b/xen/arch/arm/domain_build.c
> > @@ -2649,7 +2649,8 @@ void __init create_domUs(void)
> >              .max_evtchn_port = -1,
> >              .max_grant_frames = -1,
> >              .max_maptrack_frames = -1,
> > -            .grant_opts = XEN_DOMCTL_GRANT_version_default,
> > +            .grant_opts = XEN_DOMCTL_GRANT_version_default |
> > +                          XEN_DOMCTL_GRANT_transitive,
> >          };
> >  
> >          if ( !dt_device_is_compatible(node, "xen,domain") )
> > @@ -2757,7 +2758,8 @@ void __init create_dom0(void)
> >          .max_evtchn_port = -1,
> >          .max_grant_frames = gnttab_dom0_frames(),
> >          .max_maptrack_frames = -1,
> > -        .grant_opts = XEN_DOMCTL_GRANT_version_default,
> > +        .grant_opts = XEN_DOMCTL_GRANT_version_default |
> > +                      XEN_DOMCTL_GRANT_transitive,
> >      };
> >  
> >      /* The vGIC for DOM0 is exactly emulating the hardware GIC */
> > --- a/xen/arch/x86/setup.c
> > +++ b/xen/arch/x86/setup.c
> > @@ -750,7 +750,8 @@ static struct domain *__init create_dom0(const module_t *image,
> >          .max_evtchn_port = -1,
> >          .max_grant_frames = -1,
> >          .max_maptrack_frames = -1,
> > -        .grant_opts = XEN_DOMCTL_GRANT_version_default,
> > +        .grant_opts = XEN_DOMCTL_GRANT_version_default |
> > +                      XEN_DOMCTL_GRANT_transitive,
> >          .max_vcpus = dom0_max_vcpus(),
> >          .arch = {
> >              .misc_flags = opt_dom0_msr_relaxed ? XEN_X86_MSR_RELAXED : 0,
> 
> While I can see that you make these adjustments for retaining backwards
> compatibility, I wonder if we need to, at least for Dom0. Dom0 doesn't
> normally grant anything anyway and hence would even less so use
> transitive grants. Of course then there's need to be a command line
> control to re-enable that, just in case.

dom0=gnttab-transitive, or should it be placed somewhere else?

> > @@ -1965,6 +1969,8 @@ int grant_table_init(struct domain *d, int max_grant_frames,
> >      gt->max_grant_frames = max_grant_frames;
> >      gt->max_maptrack_frames = max_maptrack_frames;
> >      gt->max_grant_version = max_grant_version;
> > +    gt->allow_transitive = !!(options & XEN_DOMCTL_GRANT_transitive) &&
> > +                           opt_transitive_grants;
> 
> No need for !! here afaics. Not even if there weren't the &&.
> 
> As to combining with the global option: I think if an admin requested
> them for a domain, this should overrule the command line option. Which
> in turn suggests that the command line option could go away at this
> point. Otherwise, if you AND both together and the guest is known to
> not work without this functionality, domain creation would instead
> better fail (or at the very least it should be logged by the tool
> stack that the request wasn't satisfied, which would require a means
> to retrieve the effective setting). IOW I would see the command line
> turning this off to trump the per-guest enabling request.

How should we go about deprecating it? It would be a bit antisocial
IMO to just drop the option, since people using it would then be
exposed to guests using transient grants if they didn't realize it
should be set in xl.conf or xl.cfg now.

> > --- a/xen/include/public/domctl.h
> > +++ b/xen/include/public/domctl.h
> > @@ -98,8 +98,11 @@ struct xen_domctl_createdomain {
> >  /* Grant version, use low 4 bits. */
> >  #define XEN_DOMCTL_GRANT_version_mask    0xf
> >  #define XEN_DOMCTL_GRANT_version_default 0xf
> > +/* Allow transitive grants. */
> > +#define _XEN_DOMCTL_GRANT_transitive     4
> > +#define XEN_DOMCTL_GRANT_transitive      (1U << _XEN_DOMCTL_GRANT_transitive)
> 
> Omit the former and have the latter be 0x10 or (1U << 4)?
> 
> > -#define XEN_DOMCTLGRANT_MAX XEN_DOMCTL_GRANT_version_mask
> > +#define XEN_DOMCTLGRANT_MAX XEN_DOMCTL_GRANT_transitive
> 
> I didn't even spot this in patch 2 - what is this intended to be used
> for? Neither there nor here I can spot any use.

Yeah, AFAICT those _MAX definitions are used by the ocaml stubs to
assert the max option available. Given how these new options are handled
in ocaml the _MAX check is not implemented, so I could like drop those
(unless there's some other tool that also depends on them).

Thanks, Roger.
Jan Beulich Oct. 20, 2021, 11:51 a.m. UTC | #5
On 20.10.2021 12:14, Roger Pau Monné wrote:
> On Fri, Oct 15, 2021 at 12:05:06PM +0200, Jan Beulich wrote:
>> On 22.09.2021 10:21, Roger Pau Monne wrote:
>>> --- a/xen/arch/x86/setup.c
>>> +++ b/xen/arch/x86/setup.c
>>> @@ -750,7 +750,8 @@ static struct domain *__init create_dom0(const module_t *image,
>>>          .max_evtchn_port = -1,
>>>          .max_grant_frames = -1,
>>>          .max_maptrack_frames = -1,
>>> -        .grant_opts = XEN_DOMCTL_GRANT_version_default,
>>> +        .grant_opts = XEN_DOMCTL_GRANT_version_default |
>>> +                      XEN_DOMCTL_GRANT_transitive,
>>>          .max_vcpus = dom0_max_vcpus(),
>>>          .arch = {
>>>              .misc_flags = opt_dom0_msr_relaxed ? XEN_X86_MSR_RELAXED : 0,
>>
>> While I can see that you make these adjustments for retaining backwards
>> compatibility, I wonder if we need to, at least for Dom0. Dom0 doesn't
>> normally grant anything anyway and hence would even less so use
>> transitive grants. Of course then there's need to be a command line
>> control to re-enable that, just in case.
> 
> dom0=gnttab-transitive, or should it be placed somewhere else?

That sounds like the place to have it at; at least that's where I would
have suggested to put it. One question of course is how it ought to
interact with v2 being unavailable.

>>> @@ -1965,6 +1969,8 @@ int grant_table_init(struct domain *d, int max_grant_frames,
>>>      gt->max_grant_frames = max_grant_frames;
>>>      gt->max_maptrack_frames = max_maptrack_frames;
>>>      gt->max_grant_version = max_grant_version;
>>> +    gt->allow_transitive = !!(options & XEN_DOMCTL_GRANT_transitive) &&
>>> +                           opt_transitive_grants;
>>
>> No need for !! here afaics. Not even if there weren't the &&.
>>
>> As to combining with the global option: I think if an admin requested
>> them for a domain, this should overrule the command line option. Which
>> in turn suggests that the command line option could go away at this
>> point. Otherwise, if you AND both together and the guest is known to
>> not work without this functionality, domain creation would instead
>> better fail (or at the very least it should be logged by the tool
>> stack that the request wasn't satisfied, which would require a means
>> to retrieve the effective setting). IOW I would see the command line
>> turning this off to trump the per-guest enabling request.
> 
> How should we go about deprecating it? It would be a bit antisocial
> IMO to just drop the option, since people using it would then be
> exposed to guests using transient grants if they didn't realize it
> should be set in xl.conf or xl.cfg now.

So perhaps for a transitional phase fail if the command line option
says no and the request for the guest says yes? Accompanied by a
log message warning that the command line control is going to go
away, so that people will know to adjust their guest configs?

Jan
diff mbox series

Patch

diff --git a/docs/man/xl.cfg.5.pod.in b/docs/man/xl.cfg.5.pod.in
index a4bf2caafa..c5a447dfcd 100644
--- a/docs/man/xl.cfg.5.pod.in
+++ b/docs/man/xl.cfg.5.pod.in
@@ -586,6 +586,12 @@  Specify the maximum grant table version the domain is allowed to use. Current
 supported versions are 1 and 2. The default value is settable via
 L<xl.conf(5)>.
 
+=item B<transitive_grants=BOOLEAN>
+
+Specify whether transitive grants should be available to the domain. Note such
+functionality only applies to grant table version 2. The default value is
+settable via L<xl.conf(5)>.
+
 =item B<nomigrate=BOOLEAN>
 
 Disable migration of this domain.  This enables certain other features
diff --git a/docs/man/xl.conf.5.pod.in b/docs/man/xl.conf.5.pod.in
index 0a70698a7c..88efbee5fe 100644
--- a/docs/man/xl.conf.5.pod.in
+++ b/docs/man/xl.conf.5.pod.in
@@ -108,6 +108,13 @@  Sets the default value for the C<max_grant_version> domain config value.
 Default: value of Xen command line B<gnttab> parameter (or its default value if
 unspecified).
 
+=item B<transitive_grants=BOOLEAN>
+
+Sets the default value for the C<transitive_grants> domain config value.
+
+Default: value of Xen command line B<gnttab> parameter (or its default value if
+unspecified).
+
 =item B<vif.default.script="PATH">
 
 Configures the default hotplug script used by virtual network devices.
diff --git a/tools/include/libxl.h b/tools/include/libxl.h
index 7a35833312..d23586f2cc 100644
--- a/tools/include/libxl.h
+++ b/tools/include/libxl.h
@@ -509,6 +509,13 @@ 
  */
 #define LIBXL_HAVE_MAX_GRANT_VERSION 1
 
+/*
+ * LIBXL_HAVE_TRANSITIVE_GRANTS indicates libxl_domain_build_info has a
+ * transitive_grants field for setting whether such functionality should be
+ * available to the domain.
+ */
+#define LIBXL_HAVE_TRANSITIVE_GRANTS 1
+
 /*
  * libxl ABI compatibility
  *
diff --git a/tools/libs/light/libxl_create.c b/tools/libs/light/libxl_create.c
index 1ee86602ae..fa527923e4 100644
--- a/tools/libs/light/libxl_create.c
+++ b/tools/libs/light/libxl_create.c
@@ -635,6 +635,9 @@  int libxl__domain_make(libxl__gc *gc, libxl_domain_config *d_config,
         if (info->passthrough == LIBXL_PASSTHROUGH_SYNC_PT)
             create.iommu_opts |= XEN_DOMCTL_IOMMU_no_sharept;
 
+        if (libxl_defbool_val(b_info->transitive_grants))
+            create.grant_opts |= XEN_DOMCTL_GRANT_transitive;
+
         /* Ultimately, handle is an array of 16 uint8_t, same as uuid */
         libxl_uuid_copy(ctx, (libxl_uuid *)&create.handle, &info->uuid);
 
diff --git a/tools/libs/light/libxl_dm.c b/tools/libs/light/libxl_dm.c
index 9a8ddbe188..4ade437257 100644
--- a/tools/libs/light/libxl_dm.c
+++ b/tools/libs/light/libxl_dm.c
@@ -2321,6 +2321,7 @@  void libxl__spawn_stub_dm(libxl__egc *egc, libxl__stub_dm_spawn_state *sdss)
     dm_config->b_info.max_grant_frames = guest_config->b_info.max_grant_frames;
     dm_config->b_info.max_maptrack_frames = guest_config->b_info.max_maptrack_frames;
     dm_config->b_info.max_grant_version = guest_config->b_info.max_grant_version;
+    dm_config->b_info.transitive_grants = guest_config->b_info.transitive_grants;
 
     dm_config->b_info.u.pv.features = "";
 
diff --git a/tools/libs/light/libxl_types.idl b/tools/libs/light/libxl_types.idl
index 37789a568c..d05b5d2abc 100644
--- a/tools/libs/light/libxl_types.idl
+++ b/tools/libs/light/libxl_types.idl
@@ -519,6 +519,7 @@  libxl_domain_build_info = Struct("domain_build_info",[
     ("max_grant_frames",    uint32, {'init_val': 'LIBXL_MAX_GRANT_DEFAULT'}),
     ("max_maptrack_frames", uint32, {'init_val': 'LIBXL_MAX_GRANT_DEFAULT'}),
     ("max_grant_version",   integer, {'init_val': '-1'}),
+    ("transitive_grants",   libxl_defbool),
     
     ("device_model_version", libxl_device_model_version),
     ("device_model_stubdomain", libxl_defbool),
diff --git a/tools/ocaml/libs/xc/xenctrl.ml b/tools/ocaml/libs/xc/xenctrl.ml
index 6a8658bfec..da12b67baf 100644
--- a/tools/ocaml/libs/xc/xenctrl.ml
+++ b/tools/ocaml/libs/xc/xenctrl.ml
@@ -84,6 +84,7 @@  type domctl_create_config =
 	max_grant_frames: int;
 	max_maptrack_frames: int;
 	max_grant_version: int;
+	transitive_grants: bool;
 	arch: arch_domainconfig;
 }
 
diff --git a/tools/ocaml/libs/xc/xenctrl.mli b/tools/ocaml/libs/xc/xenctrl.mli
index 5933d32c70..83ca554eb7 100644
--- a/tools/ocaml/libs/xc/xenctrl.mli
+++ b/tools/ocaml/libs/xc/xenctrl.mli
@@ -76,6 +76,7 @@  type domctl_create_config = {
   max_grant_frames: int;
   max_maptrack_frames: int;
   max_grant_version: int;
+  transitive_grants: bool;
   arch: arch_domainconfig;
 }
 
diff --git a/tools/ocaml/libs/xc/xenctrl_stubs.c b/tools/ocaml/libs/xc/xenctrl_stubs.c
index 1e60925069..5697a8bd8b 100644
--- a/tools/ocaml/libs/xc/xenctrl_stubs.c
+++ b/tools/ocaml/libs/xc/xenctrl_stubs.c
@@ -189,7 +189,8 @@  CAMLprim value stub_xc_domain_create(value xch, value wanted_domid, value config
 #define VAL_MAX_GRANT_FRAMES    Field(config, 6)
 #define VAL_MAX_MAPTRACK_FRAMES Field(config, 7)
 #define VAL_MAX_GRANT_VERSION   Field(config, 8)
-#define VAL_ARCH                Field(config, 9)
+#define VAL_TRANSITIVE_GRANTS   Field(config, 9)
+#define VAL_ARCH                Field(config, 10)
 
 	uint32_t domid = Int_val(wanted_domid);
 	int result;
@@ -216,6 +217,9 @@  CAMLprim value stub_xc_domain_create(value xch, value wanted_domid, value config
 		/* ! XEN_DOMCTL_IOMMU_ XEN_DOMCTL_IOMMU_MAX max */
 		(VAL_IOMMU_OPTS);
 
+	cfg.grant_opts |= Bool_val(VAL_TRANSITIVE_GRANTS)
+			  ? XEN_DOMCTL_GRANT_transitive : 0;
+
 	arch_domconfig = Field(VAL_ARCH, 0);
 	switch ( Tag_val(VAL_ARCH) )
 	{
@@ -255,6 +259,7 @@  CAMLprim value stub_xc_domain_create(value xch, value wanted_domid, value config
 	}
 
 #undef VAL_ARCH
+#undef VAL_TRANSITIVE_GRANTS
 #undef VAL_MAX_GRANT_VERSION
 #undef VAL_MAX_MAPTRACK_FRAMES
 #undef VAL_MAX_GRANT_FRAMES
diff --git a/tools/xl/xl.c b/tools/xl/xl.c
index 0fde879cf4..9bd398f8c9 100644
--- a/tools/xl/xl.c
+++ b/tools/xl/xl.c
@@ -56,6 +56,7 @@  bool timestamps = 0;
 int max_grant_frames = -1;
 int max_maptrack_frames = -1;
 int max_grant_version = -1;
+bool transitive_grants = true;
 libxl_domid domid_policy = INVALID_DOMID;
 
 xentoollog_level minmsglevel = minmsglevel_default;
@@ -221,6 +222,12 @@  static void parse_global_config(const char *configfile,
     else if (e != ESRCH)
         exit(1);
 
+    e = xlu_cfg_get_long (config, "transitive_grants", &l, 0);
+    if (!e)
+        transitive_grants = l;
+    else if (e != ESRCH)
+        exit(1);
+
     libxl_cpu_bitmap_alloc(ctx, &global_vm_affinity_mask, 0);
     libxl_cpu_bitmap_alloc(ctx, &global_hvm_affinity_mask, 0);
     libxl_cpu_bitmap_alloc(ctx, &global_pv_affinity_mask, 0);
diff --git a/tools/xl/xl.h b/tools/xl/xl.h
index cf12c79a9b..d7f83c9abd 100644
--- a/tools/xl/xl.h
+++ b/tools/xl/xl.h
@@ -283,6 +283,7 @@  extern char *blkdev_start;
 extern int max_grant_frames;
 extern int max_maptrack_frames;
 extern int max_grant_version;
+extern bool transitive_grants;
 extern libxl_bitmap global_vm_affinity_mask;
 extern libxl_bitmap global_hvm_affinity_mask;
 extern libxl_bitmap global_pv_affinity_mask;
diff --git a/tools/xl/xl_parse.c b/tools/xl/xl_parse.c
index 1206d7ea51..8e4e561df8 100644
--- a/tools/xl/xl_parse.c
+++ b/tools/xl/xl_parse.c
@@ -1440,6 +1440,10 @@  void parse_config_data(const char *config_source,
     else
         exit(1);
 
+    xlu_cfg_get_defbool(config, "transitive_grants", &b_info->transitive_grants,
+                        0);
+    libxl_defbool_setdefault(&b_info->transitive_grants, transitive_grants);
+
     libxl_defbool_set(&b_info->claim_mode, claim_mode);
 
     if (xlu_cfg_get_string (config, "on_poweroff", &buf, 0))
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 3beb1cbb41..b9048aa9cc 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -2649,7 +2649,8 @@  void __init create_domUs(void)
             .max_evtchn_port = -1,
             .max_grant_frames = -1,
             .max_maptrack_frames = -1,
-            .grant_opts = XEN_DOMCTL_GRANT_version_default,
+            .grant_opts = XEN_DOMCTL_GRANT_version_default |
+                          XEN_DOMCTL_GRANT_transitive,
         };
 
         if ( !dt_device_is_compatible(node, "xen,domain") )
@@ -2757,7 +2758,8 @@  void __init create_dom0(void)
         .max_evtchn_port = -1,
         .max_grant_frames = gnttab_dom0_frames(),
         .max_maptrack_frames = -1,
-        .grant_opts = XEN_DOMCTL_GRANT_version_default,
+        .grant_opts = XEN_DOMCTL_GRANT_version_default |
+                      XEN_DOMCTL_GRANT_transitive,
     };
 
     /* The vGIC for DOM0 is exactly emulating the hardware GIC */
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index b5b6c75447..7ce54a5a57 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -750,7 +750,8 @@  static struct domain *__init create_dom0(const module_t *image,
         .max_evtchn_port = -1,
         .max_grant_frames = -1,
         .max_maptrack_frames = -1,
-        .grant_opts = XEN_DOMCTL_GRANT_version_default,
+        .grant_opts = XEN_DOMCTL_GRANT_version_default |
+                      XEN_DOMCTL_GRANT_transitive,
         .max_vcpus = dom0_max_vcpus(),
         .arch = {
             .misc_flags = opt_dom0_msr_relaxed ? XEN_X86_MSR_RELAXED : 0,
diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index c43e9d5ee4..f50e9f6a06 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -74,6 +74,10 @@  struct grant_table {
      * progress.
      */
     unsigned int          maptrack_limit;
+
+    /* Allow transitive grants. Only applies to grant v2. */
+    bool                  allow_transitive:1;
+
     /* Shared grant table (see include/public/grant_table.h). */
     union {
         void **shared_raw;
@@ -1965,6 +1969,8 @@  int grant_table_init(struct domain *d, int max_grant_frames,
     gt->max_grant_frames = max_grant_frames;
     gt->max_maptrack_frames = max_maptrack_frames;
     gt->max_grant_version = max_grant_version;
+    gt->allow_transitive = !!(options & XEN_DOMCTL_GRANT_transitive) &&
+                           opt_transitive_grants;
 
     /* Install the structure early to simplify the error path. */
     gt->domain = d;
@@ -2887,7 +2893,7 @@  static int gnttab_copy_claim_buf(const struct gnttab_copy *op,
                                     buf->read_only,
                                     &buf->mfn, &buf->page,
                                     &buf->ptr.offset, &buf->len,
-                                    opt_transitive_grants);
+                                    buf->domain->grant_table->allow_transitive);
         if ( rc != GNTST_okay )
             goto out;
         buf->ptr.u.ref = ptr->u.ref;
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index e2b47184a0..2f90e4c3f8 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -98,8 +98,11 @@  struct xen_domctl_createdomain {
 /* Grant version, use low 4 bits. */
 #define XEN_DOMCTL_GRANT_version_mask    0xf
 #define XEN_DOMCTL_GRANT_version_default 0xf
+/* Allow transitive grants. */
+#define _XEN_DOMCTL_GRANT_transitive     4
+#define XEN_DOMCTL_GRANT_transitive      (1U << _XEN_DOMCTL_GRANT_transitive)
 
-#define XEN_DOMCTLGRANT_MAX XEN_DOMCTL_GRANT_version_mask
+#define XEN_DOMCTLGRANT_MAX XEN_DOMCTL_GRANT_transitive
 
     uint32_t grant_opts;