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

Re: [Xen-devel] [PATCH v2 11/11] ioreq: provide support for long-running operations...



> -----Original Message-----
> From: Roger Pau Monne <roger.pau@xxxxxxxxxx>
> Sent: 03 September 2019 17:14
> To: xen-devel@xxxxxxxxxxxxxxxxxxxx
> Cc: Roger Pau Monne <roger.pau@xxxxxxxxxx>; Paul Durrant 
> <Paul.Durrant@xxxxxxxxxx>; Jan Beulich
> <jbeulich@xxxxxxxx>; Andrew Cooper <Andrew.Cooper3@xxxxxxxxxx>; Wei Liu 
> <wl@xxxxxxx>; George Dunlap
> <George.Dunlap@xxxxxxxxxx>; Ian Jackson <Ian.Jackson@xxxxxxxxxx>; Julien 
> Grall <julien.grall@xxxxxxx>;
> Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>; Stefano Stabellini 
> <sstabellini@xxxxxxxxxx>; Tim
> (Xen.org) <tim@xxxxxxx>
> Subject: [PATCH v2 11/11] ioreq: provide support for long-running 
> operations...
> 
> ...and switch vPCI to use this infrastructure for long running
> physmap modification operations.
> 
> This allows to get rid of the vPCI specific modifications done to
> handle_hvm_io_completion and allows generalizing the support for
> long-running operations to other internal ioreq servers. Such support
> is implemented as a specific handler that can be registers by internal
> ioreq servers and that will be called to check for pending work.
> Returning true from this handler will prevent the vcpu from running
> until the handler returns false.
> 
> Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
> ---
>  xen/arch/x86/hvm/ioreq.c       | 55 +++++++++++++++++++++++++-----
>  xen/drivers/vpci/header.c      | 61 ++++++++++++++++++----------------
>  xen/drivers/vpci/vpci.c        |  8 ++++-
>  xen/include/asm-x86/hvm/vcpu.h |  3 +-
>  xen/include/xen/vpci.h         |  6 ----
>  5 files changed, 89 insertions(+), 44 deletions(-)
> 
> diff --git a/xen/arch/x86/hvm/ioreq.c b/xen/arch/x86/hvm/ioreq.c
> index 33c56b880c..caa53dfa84 100644
> --- a/xen/arch/x86/hvm/ioreq.c
> +++ b/xen/arch/x86/hvm/ioreq.c
> @@ -239,16 +239,48 @@ bool handle_hvm_io_completion(struct vcpu *v)
>      enum hvm_io_completion io_completion;
>      unsigned int id;
> 
> -    if ( has_vpci(d) && vpci_process_pending(v) )
> -    {
> -        raise_softirq(SCHEDULE_SOFTIRQ);
> -        return false;
> -    }
> -
> -    FOR_EACH_EXTERNAL_IOREQ_SERVER(d, id, s)
> +    FOR_EACH_IOREQ_SERVER(d, id, s)
>      {
>          struct hvm_ioreq_vcpu *sv;
> 
> +        if ( hvm_ioreq_is_internal(id) )
> +        {

I wonder whether it would be neater by saying:

           if ( !hvm_ioreq_is_internal(id) )
               continue;

here to avoid the indentation below.

> +            if ( vio->io_req.state == STATE_IOREQ_INPROCESS )
> +            {
> +                ioreq_t req = vio->io_req;
> +
> +                /*
> +                 * Check and convert the PIO/MMIO ioreq to a PCI config space
> +                 * access.
> +                 */
> +                convert_pci_ioreq(d, &req);
> +
> +                if ( s->handler(v, &req, s->data) == X86EMUL_RETRY )
> +                {
> +                    /*
> +                     * Need to raise a scheduler irq in order to prevent the
> +                     * guest vcpu from resuming execution.
> +                     *
> +                     * Note this is not required for external ioreq 
> operations
> +                     * because in that case the vcpu is marked as blocked, 
> but
> +                     * this cannot be done for long-running internal
> +                     * operations, since it would prevent the vcpu from being
> +                     * scheduled and thus the long running operation from
> +                     * finishing.
> +                     */
> +                    raise_softirq(SCHEDULE_SOFTIRQ);
> +                    return false;
> +                }
> +
> +                /* Finished processing the ioreq. */
> +                if ( hvm_ioreq_needs_completion(&vio->io_req) )
> +                    vio->io_req.state = STATE_IORESP_READY;
> +                else
> +                    vio->io_req.state = STATE_IOREQ_NONE;

IMO the above is also neater as:

    vio->io_req.state = hvm_ioreq_needs_completion(&vio->io_req) ?
                        STATE_IORESP_READY : STATE_IOREQ_NONE;

> +            }
> +            continue;
> +        }
> +
>          list_for_each_entry ( sv,
>                                &s->ioreq_vcpu_list,
>                                list_entry )
> @@ -1582,7 +1614,14 @@ int hvm_send_ioreq(ioservid_t id, ioreq_t *proto_p, 
> bool buffered)
>          return hvm_send_buffered_ioreq(s, proto_p);
> 
>      if ( hvm_ioreq_is_internal(id) )
> -        return s->handler(curr, proto_p, s->data);
> +    {
> +        int rc = s->handler(curr, proto_p, s->data);
> +
> +        if ( rc == X86EMUL_RETRY )
> +            curr->arch.hvm.hvm_io.io_req.state = STATE_IOREQ_INPROCESS;
> +
> +        return rc;
> +    }
> 
>      if ( unlikely(!vcpu_start_shutdown_deferral(curr)) )
>          return X86EMUL_RETRY;
> diff --git a/xen/drivers/vpci/header.c b/xen/drivers/vpci/header.c
> index 3c794f486d..f1c1a69492 100644
> --- a/xen/drivers/vpci/header.c
> +++ b/xen/drivers/vpci/header.c
> @@ -129,37 +129,42 @@ static void modify_decoding(const struct pci_dev *pdev, 
> uint16_t cmd,
> 
>  bool vpci_process_pending(struct vcpu *v)
>  {
> -    if ( v->vpci.mem )
> +    struct map_data data = {
> +        .d = v->domain,
> +        .map = v->vpci.cmd & PCI_COMMAND_MEMORY,
> +    };
> +    int rc;
> +
> +    if ( !v->vpci.mem )
>      {
> -        struct map_data data = {
> -            .d = v->domain,
> -            .map = v->vpci.cmd & PCI_COMMAND_MEMORY,
> -        };
> -        int rc = rangeset_consume_ranges(v->vpci.mem, map_range, &data);
> -
> -        if ( rc == -ERESTART )
> -            return true;
> -
> -        spin_lock(&v->vpci.pdev->vpci->lock);
> -        /* Disable memory decoding unconditionally on failure. */
> -        modify_decoding(v->vpci.pdev,
> -                        rc ? v->vpci.cmd & ~PCI_COMMAND_MEMORY : v->vpci.cmd,
> -                        !rc && v->vpci.rom_only);
> -        spin_unlock(&v->vpci.pdev->vpci->lock);
> -
> -        rangeset_destroy(v->vpci.mem);
> -        v->vpci.mem = NULL;
> -        if ( rc )
> -            /*
> -             * FIXME: in case of failure remove the device from the domain.
> -             * Note that there might still be leftover mappings. While this 
> is
> -             * safe for Dom0, for DomUs the domain will likely need to be
> -             * killed in order to avoid leaking stale p2m mappings on
> -             * failure.
> -             */
> -            vpci_remove_device(v->vpci.pdev);
> +        ASSERT_UNREACHABLE();
> +        return false;
>      }
> 
> +    rc = rangeset_consume_ranges(v->vpci.mem, map_range, &data);
> +

Extraneous blank line?

  Paul

> +    if ( rc == -ERESTART )
> +        return true;
> +
> +    spin_lock(&v->vpci.pdev->vpci->lock);
> +    /* Disable memory decoding unconditionally on failure. */
> +    modify_decoding(v->vpci.pdev,
> +                    rc ? v->vpci.cmd & ~PCI_COMMAND_MEMORY : v->vpci.cmd,
> +                    !rc && v->vpci.rom_only);
> +    spin_unlock(&v->vpci.pdev->vpci->lock);
> +
> +    rangeset_destroy(v->vpci.mem);
> +    v->vpci.mem = NULL;
> +    if ( rc )
> +        /*
> +         * FIXME: in case of failure remove the device from the domain.
> +         * Note that there might still be leftover mappings. While this is
> +         * safe for Dom0, for DomUs the domain will likely need to be
> +         * killed in order to avoid leaking stale p2m mappings on
> +         * failure.
> +         */
> +        vpci_remove_device(v->vpci.pdev);
> +
>      return false;
>  }
> 
> diff --git a/xen/drivers/vpci/vpci.c b/xen/drivers/vpci/vpci.c
> index 5664020c2d..6069dff612 100644
> --- a/xen/drivers/vpci/vpci.c
> +++ b/xen/drivers/vpci/vpci.c
> @@ -498,6 +498,12 @@ static int ioreq_handler(struct vcpu *v, ioreq_t *req, 
> void *data)
>          return X86EMUL_UNHANDLEABLE;
>      }
> 
> +    if ( v->vpci.mem )
> +    {
> +        ASSERT(req->state == STATE_IOREQ_INPROCESS);
> +        return vpci_process_pending(v) ? X86EMUL_RETRY : X86EMUL_OKAY;
> +    }
> +
>      sbdf.sbdf = req->addr >> 32;
> 
>      if ( req->dir )
> @@ -505,7 +511,7 @@ static int ioreq_handler(struct vcpu *v, ioreq_t *req, 
> void *data)
>      else
>          write(sbdf, req->addr, req->size, req->data);
> 
> -    return X86EMUL_OKAY;
> +    return v->vpci.mem ? X86EMUL_RETRY : X86EMUL_OKAY;
>  }
> 
>  int vpci_register_ioreq(struct domain *d)
> diff --git a/xen/include/asm-x86/hvm/vcpu.h b/xen/include/asm-x86/hvm/vcpu.h
> index 38f5c2bb9b..4563746466 100644
> --- a/xen/include/asm-x86/hvm/vcpu.h
> +++ b/xen/include/asm-x86/hvm/vcpu.h
> @@ -92,7 +92,8 @@ struct hvm_vcpu_io {
> 
>  static inline bool hvm_ioreq_needs_completion(const ioreq_t *ioreq)
>  {
> -    return ioreq->state == STATE_IOREQ_READY &&
> +    return (ioreq->state == STATE_IOREQ_READY ||
> +            ioreq->state == STATE_IOREQ_INPROCESS) &&
>             !ioreq->data_is_ptr &&
>             (ioreq->type != IOREQ_TYPE_PIO || ioreq->dir != IOREQ_WRITE);
>  }
> diff --git a/xen/include/xen/vpci.h b/xen/include/xen/vpci.h
> index 36f435ed5b..a65491e0c9 100644
> --- a/xen/include/xen/vpci.h
> +++ b/xen/include/xen/vpci.h
> @@ -225,12 +225,6 @@ static inline int vpci_register_ioreq(struct domain *d)
>  }
> 
>  static inline void vpci_dump_msi(void) { }
> -
> -static inline bool vpci_process_pending(struct vcpu *v)
> -{
> -    ASSERT_UNREACHABLE();
> -    return false;
> -}
>  #endif
> 
>  #endif
> --
> 2.22.0

_______________________________________________
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®.