[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v3 1/3] introduce GFN notification for translated domains



> -----Original Message-----
> From: Xen-devel <xen-devel-bounces@xxxxxxxxxxxxxxxxxxxx> On Behalf Of Jan
> Beulich
> Sent: 25 November 2019 09:58
> To: xen-devel@xxxxxxxxxxxxxxxxxxxx
> Cc: Juergen Gross <jgross@xxxxxxxx>; Stefano Stabellini
> <sstabellini@xxxxxxxxxx>; Julien Grall <julien@xxxxxxx>; Wei Liu
> <wl@xxxxxxx>; Konrad Wilk <konrad.wilk@xxxxxxxxxx>; George Dunlap
> <George.Dunlap@xxxxxxxxxxxxx>; Andrew Cooper <andrew.cooper3@xxxxxxxxxx>;
> Sander Eikelenboom <linux@xxxxxxxxxxxxxx>; Ian Jackson
> <ian.jackson@xxxxxxxxxx>; Roger Pau Monné <roger.pau@xxxxxxxxxx>
> Subject: [Xen-devel] [PATCH v3 1/3] introduce GFN notification for
> translated domains
> 
> In order for individual IOMMU drivers (and from an abstract pov also
> architectures) to be able to adjust, ahead of actual mapping requests,
> their data structures when they might cover only a sub-range of all
> possible GFNs, introduce a notification call used by various code paths
> potentially installing a fresh mapping of a never used GFN (for a
> particular domain).
> 
> Note that before this patch, in gnttab_transfer(), once past
> assign_pages(), further errors modifying the physmap are ignored
> (presumably because it would be too complicated to try to roll back at
> that point). This patch follows suit by ignoring failed notify_gfn()s or
> races due to the need to intermediately drop locks, simply printing out
> a warning that the gfn may not be accessible due to the failure.
> 
> Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
> ---
> v3: Conditionalize upon CONFIG_IOMMU_FORCE_PT_SHARE, also covering the
>     share_p2m_table() functionality as appropriate. Un-comment the
>     GNTMAP_host_map check.
> v2: Introduce arch_notify_gfn(), to invoke gfn_valid() on x86 (this
>     unfortunately means it and notify_gfn() now need to be macros, or
>     else include file dependencies get in the way, as gfn_valid() lives
>     in paging.h, which we shouldn't include from xen/sched.h). Improve
>     description.
> 
> TBD: Does Arm actually have anything to check against in its
>      arch_notify_gfn()?
> 
> --- a/xen/arch/x86/hvm/dom0_build.c
> +++ b/xen/arch/x86/hvm/dom0_build.c
> @@ -173,7 +173,8 @@ static int __init pvh_populate_memory_ra
>              continue;
>          }
> 
> -        rc = guest_physmap_add_page(d, _gfn(start), page_to_mfn(page),
> +        rc = notify_gfn(d, _gfn(start + (1UL << order) - 1)) ?:
> +             guest_physmap_add_page(d, _gfn(start), page_to_mfn(page),
>                                      order);
>          if ( rc != 0 )
>          {
> --- a/xen/arch/x86/hvm/hvm.c
> +++ b/xen/arch/x86/hvm/hvm.c
> @@ -4304,9 +4304,17 @@ static int hvmop_set_param(
>          if ( a.value > SHUTDOWN_MAX )
>              rc = -EINVAL;
>          break;
> +
>      case HVM_PARAM_IOREQ_SERVER_PFN:
> -        d->arch.hvm.ioreq_gfn.base = a.value;
> +        if ( d->arch.hvm.params[HVM_PARAM_NR_IOREQ_SERVER_PAGES] )
> +            rc = notify_gfn(
> +                     d,
> +                     _gfn(a.value + d->arch.hvm.params
> +                                    [HVM_PARAM_NR_IOREQ_SERVER_PAGES] -
> 1));

IIRC the PFN is typically set by the toolstack before the number of pages, so 
the notify will be for a.value - 1, i.e. the previous gfn. Is that a problem?

  Paul

> +        if ( !rc )
> +             d->arch.hvm.ioreq_gfn.base = a.value;
>          break;
> +
>      case HVM_PARAM_NR_IOREQ_SERVER_PAGES:
>      {
>          unsigned int i;
> @@ -4317,6 +4325,9 @@ static int hvmop_set_param(
>              rc = -EINVAL;
>              break;
>          }
> +        rc = notify_gfn(d, _gfn(d->arch.hvm.ioreq_gfn.base + a.value -
> 1));
> +        if ( rc )
> +            break;
>          for ( i = 0; i < a.value; i++ )
>              set_bit(i, &d->arch.hvm.ioreq_gfn.mask);
> 
> @@ -4330,7 +4341,11 @@ static int hvmop_set_param(
>          BUILD_BUG_ON(HVM_PARAM_BUFIOREQ_PFN >
>                       sizeof(d->arch.hvm.ioreq_gfn.legacy_mask) * 8);
>          if ( a.value )
> -            set_bit(a.index, &d->arch.hvm.ioreq_gfn.legacy_mask);
> +        {
> +            rc = notify_gfn(d, _gfn(a.value));
> +            if ( !rc )
> +                set_bit(a.index, &d->arch.hvm.ioreq_gfn.legacy_mask);
> +        }
>          break;
> 
>      case HVM_PARAM_X87_FIP_WIDTH:
> --- a/xen/common/grant_table.c
> +++ b/xen/common/grant_table.c
> @@ -946,6 +946,16 @@ map_grant_ref(
>          return;
>      }
> 
> +    if ( paging_mode_translate(ld) && (op->flags & GNTMAP_host_map) &&
> +         (rc = notify_gfn(ld, gaddr_to_gfn(op->host_addr))) )
> +    {
> +        gdprintk(XENLOG_INFO, "notify(%"PRI_gfn") -> %d\n",
> +                 gfn_x(gaddr_to_gfn(op->host_addr)), rc);
> +        op->status = GNTST_general_error;
> +        return;
> +        BUILD_BUG_ON(GNTST_okay);
> +    }
> +
>      if ( unlikely((rd = rcu_lock_domain_by_id(op->dom)) == NULL) )
>      {
>          gdprintk(XENLOG_INFO, "Could not find domain %d\n", op->dom);
> @@ -2123,6 +2133,7 @@ gnttab_transfer(
>      {
>          bool_t okay;
>          int rc;
> +        gfn_t gfn;
> 
>          if ( i && hypercall_preempt_check() )
>              return i;
> @@ -2300,21 +2311,52 @@ gnttab_transfer(
>          act = active_entry_acquire(e->grant_table, gop.ref);
> 
>          if ( evaluate_nospec(e->grant_table->gt_version == 1) )
> +            gfn = _gfn(shared_entry_v1(e->grant_table, gop.ref).frame);
> +        else
> +            gfn = _gfn(shared_entry_v2(e->grant_table,
> gop.ref).full_page.frame);
> +
> +        if ( paging_mode_translate(e) )
>          {
> -            grant_entry_v1_t *sha = &shared_entry_v1(e->grant_table,
> gop.ref);
> +            gfn_t gfn2;
> +
> +            active_entry_release(act);
> +            grant_read_unlock(e->grant_table);
> +
> +            rc = notify_gfn(e, gfn);
> +            if ( rc )
> +                printk(XENLOG_G_WARNING
> +                       "%pd: gref %u: xfer GFN %"PRI_gfn" may be
> inaccessible (%d)\n",
> +                       e, gop.ref, gfn_x(gfn), rc);
> +
> +            grant_read_lock(e->grant_table);
> +            act = active_entry_acquire(e->grant_table, gop.ref);
> 
> -            guest_physmap_add_page(e, _gfn(sha->frame), mfn, 0);
> -            if ( !paging_mode_translate(e) )
> -                sha->frame = mfn_x(mfn);
> +            if ( evaluate_nospec(e->grant_table->gt_version == 1) )
> +                gfn2 = _gfn(shared_entry_v1(e->grant_table,
> gop.ref).frame);
> +            else
> +                gfn2 = _gfn(shared_entry_v2(e->grant_table, gop.ref).
> +                    full_page.frame);
> +
> +            if ( !gfn_eq(gfn, gfn2) )
> +            {
> +                printk(XENLOG_G_WARNING
> +                       "%pd: gref %u: xfer GFN went %"PRI_gfn" ->
> %"PRI_gfn"\n",
> +                       e, gop.ref, gfn_x(gfn), gfn_x(gfn2));
> +                gfn = gfn2;
> +            }
>          }
> -        else
> -        {
> -            grant_entry_v2_t *sha = &shared_entry_v2(e->grant_table,
> gop.ref);
> 
> -            guest_physmap_add_page(e, _gfn(sha->full_page.frame), mfn,
> 0);
> -            if ( !paging_mode_translate(e) )
> -                sha->full_page.frame = mfn_x(mfn);
> +        guest_physmap_add_page(e, gfn, mfn, 0);
> +
> +        if ( !paging_mode_translate(e) )
> +        {
> +            if ( evaluate_nospec(e->grant_table->gt_version == 1) )
> +                shared_entry_v1(e->grant_table, gop.ref).frame =
> mfn_x(mfn);
> +            else
> +                shared_entry_v2(e->grant_table, gop.ref).full_page.frame
> =
> +                    mfn_x(mfn);
>          }
> +
>          smp_wmb();
>          shared_entry_header(e->grant_table, gop.ref)->flags |=
>              GTF_transfer_completed;
> --- a/xen/common/memory.c
> +++ b/xen/common/memory.c
> @@ -203,6 +203,10 @@ static void populate_physmap(struct memo
>          if ( unlikely(__copy_from_guest_offset(&gpfn, a->extent_list, i,
> 1)) )
>              goto out;
> 
> +        if ( paging_mode_translate(d) &&
> +             notify_gfn(d, _gfn(gpfn + (1U << a->extent_order) - 1)) )
> +            goto out;
> +
>          if ( a->memflags & MEMF_populate_on_demand )
>          {
>              /* Disallow populating PoD pages on oneself. */
> @@ -745,6 +749,10 @@ static long memory_exchange(XEN_GUEST_HA
>                  continue;
>              }
> 
> +            if ( paging_mode_translate(d) )
> +                rc = notify_gfn(d,
> +                                _gfn(gpfn + (1U << exch.out.extent_order)
> - 1));
> +
>              mfn = page_to_mfn(page);
>              guest_physmap_add_page(d, _gfn(gpfn), mfn,
>                                     exch.out.extent_order);
> @@ -813,12 +821,20 @@ int xenmem_add_to_physmap(struct domain
>          extra.foreign_domid = DOMID_INVALID;
> 
>      if ( xatp->space != XENMAPSPACE_gmfn_range )
> -        return xenmem_add_to_physmap_one(d, xatp->space, extra,
> +        return notify_gfn(d, _gfn(xatp->gpfn)) ?:
> +               xenmem_add_to_physmap_one(d, xatp->space, extra,
>                                           xatp->idx, _gfn(xatp->gpfn));
> 
>      if ( xatp->size < start )
>          return -EILSEQ;
> 
> +    if ( !start && xatp->size )
> +    {
> +        rc = notify_gfn(d, _gfn(xatp->gpfn + xatp->size - 1));
> +        if ( rc )
> +            return rc;
> +    }
> +
>      xatp->idx += start;
>      xatp->gpfn += start;
>      xatp->size -= start;
> @@ -891,7 +907,8 @@ static int xenmem_add_to_physmap_batch(s
>                                                 extent, 1)) )
>              return -EFAULT;
> 
> -        rc = xenmem_add_to_physmap_one(d, xatpb->space,
> +        rc = notify_gfn(d, _gfn(gpfn)) ?:
> +             xenmem_add_to_physmap_one(d, xatpb->space,
>                                         xatpb->u,
>                                         idx, _gfn(gpfn));
> 
> --- a/xen/drivers/passthrough/iommu.c
> +++ b/xen/drivers/passthrough/iommu.c
> @@ -522,6 +522,7 @@ int iommu_do_domctl(
>      return ret;
>  }
> 
> +#ifndef CONFIG_IOMMU_FORCE_PT_SHARE
>  void iommu_share_p2m_table(struct domain* d)
>  {
>      ASSERT(hap_enabled(d));
> @@ -530,6 +531,15 @@ void iommu_share_p2m_table(struct domain
>          iommu_get_ops()->share_p2m(d);
>  }
> 
> +int iommu_notify_gfn(struct domain *d, gfn_t gfn)
> +{
> +    const struct iommu_ops *ops = dom_iommu(d)->platform_ops;
> +
> +    return need_iommu_pt_sync(d) && ops->notify_dfn
> +           ? iommu_call(ops, notify_dfn, d, _dfn(gfn_x(gfn))) : 0;
> +}
> +#endif
> +
>  void iommu_crash_shutdown(void)
>  {
>      if ( !iommu_crash_disable )
> --- a/xen/include/asm-arm/domain.h
> +++ b/xen/include/asm-arm/domain.h
> @@ -272,6 +272,8 @@ static inline void free_vcpu_guest_conte
> 
>  static inline void arch_vcpu_block(struct vcpu *v) {}
> 
> +#define arch_notify_gfn(d, gfn) ((void)(d), (void)(gfn), 0)
> +
>  #endif /* __ASM_DOMAIN_H__ */
> 
>  /*
> --- a/xen/include/asm-x86/domain.h
> +++ b/xen/include/asm-x86/domain.h
> @@ -647,6 +647,8 @@ static inline void free_vcpu_guest_conte
> 
>  void arch_vcpu_regs_init(struct vcpu *v);
> 
> +#define arch_notify_gfn(d, gfn) (gfn_valid(d, gfn) ? 0 : -EADDRNOTAVAIL)
> +
>  struct vcpu_hvm_context;
>  int arch_set_info_hvm_guest(struct vcpu *v, const struct vcpu_hvm_context
> *ctx);
> 
> --- a/xen/include/xen/iommu.h
> +++ b/xen/include/xen/iommu.h
> @@ -237,6 +237,11 @@ struct iommu_ops {
>      int __must_check (*lookup_page)(struct domain *d, dfn_t dfn, mfn_t
> *mfn,
>                                      unsigned int *flags);
> 
> +#ifndef CONFIG_IOMMU_FORCE_PT_SHARE
> +    void (*share_p2m)(struct domain *d);
> +    int __must_check (*notify_dfn)(struct domain *d, dfn_t dfn);
> +#endif
> +
>      void (*free_page_table)(struct page_info *);
> 
>  #ifdef CONFIG_X86
> @@ -253,7 +258,6 @@ struct iommu_ops {
> 
>      int __must_check (*suspend)(void);
>      void (*resume)(void);
> -    void (*share_p2m)(struct domain *d);
>      void (*crash_shutdown)(void);
>      int __must_check (*iotlb_flush)(struct domain *d, dfn_t dfn,
>                                      unsigned int page_count,
> @@ -330,7 +334,15 @@ void iommu_resume(void);
>  void iommu_crash_shutdown(void);
>  int iommu_get_reserved_device_memory(iommu_grdm_t *, void *);
> 
> +#ifndef CONFIG_IOMMU_FORCE_PT_SHARE
>  void iommu_share_p2m_table(struct domain *d);
> +int __must_check iommu_notify_gfn(struct domain *d, gfn_t gfn);
> +#else
> +static inline int __must_check iommu_notify_gfn(struct domain *d, gfn_t
> gfn)
> +{
> +    return 0;
> +}
> +#endif
> 
>  #ifdef CONFIG_HAS_PCI
>  int iommu_do_pci_domctl(struct xen_domctl *, struct domain *d,
> --- a/xen/include/xen/sched.h
> +++ b/xen/include/xen/sched.h
> @@ -1039,6 +1039,8 @@ static always_inline bool is_iommu_enabl
>      return evaluate_nospec(d->options & XEN_DOMCTL_CDF_iommu);
>  }
> 
> +#define notify_gfn(d, gfn) (arch_notify_gfn(d, gfn) ?:
> iommu_notify_gfn(d, gfn))
> +
>  extern bool sched_smt_power_savings;
>  extern bool sched_disable_smt_switching;
> 
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@xxxxxxxxxxxxxxxxxxxx
> https://lists.xenproject.org/mailman/listinfo/xen-devel
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.