qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Paulina Szubarczyk <paulinaszubarczyk@gmail.com>
To: roger.pau@citrix.com
Cc: Stefano Stabellini <sstabellini@kernel.org>,
	xen-devel@lists.xenproject.org, wei.liu2@citrix.com,
	ian.jackson@eu.citrix.com, david.vrabel@citrix.com,
	anthony.perard@citrix.com, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH v6 2/2] qdisk - hw/block/xen_disk: grant copy implementation
Date: Fri, 9 Sep 2016 14:32:41 +0200	[thread overview]
Message-ID: <57D2ABE9.9070800@gmail.com> (raw)
In-Reply-To: <57D08E12.4080607@gmail.com>



On 09/08/2016 12:00 AM, Paulina Szubarczyk wrote:
>
> On 09/07/2016 10:56 PM, Stefano Stabellini wrote:
>> On Wed, 7 Sep 2016, Paulina Szubarczyk wrote:
>>> Copy data operated on during request from/to local buffers to/from
>>> the grant references.
>>>
>>> Before grant copy operation local buffers must be allocated what is
>>> done by calling ioreq_init_copy_buffers. For the 'read' operation,
>>> first, the qemu device invokes the read operation on local buffers
>>> and on the completion grant copy is called and buffers are freed.
>>> For the 'write' operation grant copy is performed before invoking
>>> write by qemu device.
>>>
>>> A new value 'feature_grant_copy' is added to recognize when the
>>> grant copy operation is supported by a guest.
>>>
>>> Signed-off-by: Paulina Szubarczyk <paulinaszubarczyk@gmail.com>
>>> ---
>>> Changes since v5:
>>> -added checking of every interface in the configure file. Based on
>>>   the Roger's comment that xengnttab_map_grant_ref was added prior
>>>   xengnttab_grant_copy, thus do not need to be check again here
>>>   I dropped this check.
>>>
>>
>> Thank you Paulina, the patch is good. Thanks for your work! Sorry for
>> coming in late in the review; I have a couple of minor suggestions
>> below.
>>
> It had not been possible without all the help I have got. I am very
> grateful for it.
>
>> In addition to Anthony's ack, it would be also nice to have Roger's ack
>> on this patch.
>>
Roger, will you need more time to take a look at the patch or may I send 
a new version with applied Stefano comments?

>>
>>>   configure                   |  55 ++++++++++++++++
>>>   hw/block/xen_disk.c         | 157
>>> ++++++++++++++++++++++++++++++++++++++++++--
>>>   include/hw/xen/xen_common.h |  14 ++++
>>>   3 files changed, 221 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/configure b/configure
>>> index 4b808f9..3f44d38 100755
>>> --- a/configure
>>> +++ b/configure
>>> @@ -1956,6 +1956,61 @@ EOF
>>>   /*
>>>    * If we have stable libs the we don't want the libxc compat
>>>    * layers, regardless of what CFLAGS we may have been given.
>>> + *
>>> + * Also, check if xengnttab_grant_copy_segment_t is defined and
>>> + * grant copy operation is implemented.
>>> + */
>>> +#undef XC_WANT_COMPAT_EVTCHN_API
>>> +#undef XC_WANT_COMPAT_GNTTAB_API
>>> +#undef XC_WANT_COMPAT_MAP_FOREIGN_API
>>> +#include <xenctrl.h>
>>> +#include <xenstore.h>
>>> +#include <xenevtchn.h>
>>> +#include <xengnttab.h>
>>> +#include <xenforeignmemory.h>
>>> +#include <stdint.h>
>>> +#include <xen/hvm/hvm_info_table.h>
>>> +#if !defined(HVM_MAX_VCPUS)
>>> +# error HVM_MAX_VCPUS not defined
>>> +#endif
>>> +int main(void) {
>>> +  xc_interface *xc = NULL;
>>> +  xenforeignmemory_handle *xfmem;
>>> +  xenevtchn_handle *xe;
>>> +  xengnttab_handle *xg;
>>> +  xen_domain_handle_t handle;
>>> +  xengnttab_grant_copy_segment_t* seg = NULL;
>>> +
>>> +  xs_daemon_open();
>>> +
>>> +  xc = xc_interface_open(0, 0, 0);
>>> +  xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0);
>>> +  xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0);
>>> +  xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000);
>>> +  xc_hvm_create_ioreq_server(xc, 0, HVM_IOREQSRV_BUFIOREQ_ATOMIC,
>>> NULL);
>>> +  xc_domain_create(xc, 0, handle, 0, NULL, NULL);
>>> +
>>> +  xfmem = xenforeignmemory_open(0, 0);
>>> +  xenforeignmemory_map(xfmem, 0, 0, 0, 0, 0);
>>> +
>>> +  xe = xenevtchn_open(0, 0);
>>> +  xenevtchn_fd(xe);
>>> +
>>> +  xg = xengnttab_open(0, 0);
>>> +  xengnttab_grant_copy(xg, 0, seg);
>>> +
>>> +  return 0;
>>> +}
>>> +EOF
>>> +      compile_prog "" "$xen_libs $xen_stable_libs"
>>> +    then
>>> +    xen_ctrl_version=480
>>> +    xen=yes
>>> +  elif
>>> +      cat > $TMPC <<EOF &&
>>> +/*
>>> + * If we have stable libs the we don't want the libxc compat
>>> + * layers, regardless of what CFLAGS we may have been given.
>>>    */
>>>   #undef XC_WANT_COMPAT_EVTCHN_API
>>>   #undef XC_WANT_COMPAT_GNTTAB_API
>>> diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c
>>> index 3b8ad33..3739e13 100644
>>> --- a/hw/block/xen_disk.c
>>> +++ b/hw/block/xen_disk.c
>>> @@ -119,6 +119,9 @@ struct XenBlkDev {
>>>       unsigned int        persistent_gnt_count;
>>>       unsigned int        max_grants;
>>>
>>> +    /* Grant copy */
>>> +    gboolean            feature_grant_copy;
>>> +
>>>       /* qemu block driver */
>>>       DriveInfo           *dinfo;
>>>       BlockBackend        *blk;
>>> @@ -489,6 +492,108 @@ static int ioreq_map(struct ioreq *ioreq)
>>>       return 0;
>>>   }
>>>
>>> +#if CONFIG_XEN_CTRL_INTERFACE_VERSION >= 480
>>
>> In general I prefer to avoid this kind of #ifdef in xen_disk.c, but I
>> see that Anthony suggested it for a good reason. The only alternartive I
>> can think of would be to introduce two static inline functions in
>> xen_common.h to set a xengnttab_grant_copy_segment_t seg. But this is
>> also OK.
>>
> The functions take as parameters pointers to struct ioreq defined in
> xen_disk.c which members are used to fill the
> xengnttab_grant_copy_segment_t. There would be some overhead to move the
> functions to the header.
>>
>>> +static void free_buffers(struct ioreq *ioreq)
>>
>> Please name this function ioreq_free_copy_buffers to make it clearer
>> that has to do with the same buffers initialized below.
>>
>>
>>> +{
>>> +    int i;
>>> +
>>> +    for (i = 0; i < ioreq->v.niov; i++) {
>>> +        ioreq->page[i] = NULL;
>>> +    }
>>> +
>>> +    qemu_vfree(ioreq->pages);
>>> +}
>>> +
>>> +static int ioreq_init_copy_buffers(struct ioreq *ioreq)
>>> +{
>>> +    int i;
>>> +
>>> +    if (ioreq->v.niov == 0) {
>>> +        return 0;
>>> +    }
>>> +
>>> +    ioreq->pages = qemu_memalign(XC_PAGE_SIZE, ioreq->v.niov *
>>> XC_PAGE_SIZE);
>>> +
>>> +    for (i = 0; i < ioreq->v.niov; i++) {
>>> +        ioreq->page[i] = ioreq->pages + i * XC_PAGE_SIZE;
>>> +        ioreq->v.iov[i].iov_base = ioreq->page[i];
>>> +    }
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int ioreq_copy(struct ioreq *ioreq)
>>
>> Please name this function in a way that makes it clear that it has
>> something to do with grant copies. Like for example ioreq_grant_copy.
>>
> I will change the names of both functions and remove the blank line
> pointed below.
>>
>>> +{
>>> +    xengnttab_handle *gnt = ioreq->blkdev->xendev.gnttabdev;
>>> +    xengnttab_grant_copy_segment_t
>>> segs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
>>> +    int i, count, rc;
>>> +    int64_t file_blk = ioreq->blkdev->file_blk;
>>> +
>>> +    if (ioreq->v.niov == 0) {
>>> +        return 0;
>>> +    }
>>> +
>>> +    count = ioreq->v.niov;
>>> +
>>> +    for (i = 0; i < count; i++) {
>>> +
>>> +        if (ioreq->req.operation == BLKIF_OP_READ) {
>>> +            segs[i].flags = GNTCOPY_dest_gref;
>>> +            segs[i].dest.foreign.ref = ioreq->refs[i];
>>> +            segs[i].dest.foreign.domid = ioreq->domids[i];
>>> +            segs[i].dest.foreign.offset =
>>> ioreq->req.seg[i].first_sect * file_blk;
>>> +            segs[i].source.virt = ioreq->v.iov[i].iov_base;
>>> +        } else {
>>> +            segs[i].flags = GNTCOPY_source_gref;
>>> +            segs[i].source.foreign.ref = ioreq->refs[i];
>>> +            segs[i].source.foreign.domid = ioreq->domids[i];
>>> +            segs[i].source.foreign.offset =
>>> ioreq->req.seg[i].first_sect * file_blk;
>>> +            segs[i].dest.virt = ioreq->v.iov[i].iov_base;
>>> +        }
>>> +        segs[i].len = (ioreq->req.seg[i].last_sect
>>> +                       - ioreq->req.seg[i].first_sect + 1) * file_blk;
>>> +
>>> +    }
>>> +
>>> +    rc = xengnttab_grant_copy(gnt, count, segs);
>>> +
>>> +    if (rc) {
>>> +        xen_be_printf(&ioreq->blkdev->xendev, 0,
>>> +                      "failed to copy data %d\n", rc);
>>> +        ioreq->aio_errors++;
>>> +        return -1;
>>> +    }
>>> +
>>> +    for (i = 0; i < count; i++) {
>>> +        if (segs[i].status != GNTST_okay) {
>>> +            xen_be_printf(&ioreq->blkdev->xendev, 3,
>>> +                          "failed to copy data %d for gref %d, domid
>>> %d\n",
>>> +                          segs[i].status, ioreq->refs[i],
>>> ioreq->domids[i]);
>>> +            ioreq->aio_errors++;
>>> +            rc = -1;
>>> +        }
>>> +    }
>>> +
>>> +    return rc;
>>> +}
>>> +#else
>>> +static void free_buffers(struct ioreq *ioreq)
>>> +{
>>> +    abort();
>>> +}
>>> +
>>> +static int ioreq_init_copy_buffers(struct ioreq *ioreq)
>>> +{
>>> +    abort();
>>> +}
>>> +
>>> +static int ioreq_copy(struct ioreq *ioreq)
>>> +{
>>> +    abort();
>>> +}
>>> +#endif
>>> +
>>>   static int ioreq_runio_qemu_aio(struct ioreq *ioreq);
>>>
>>>   static void qemu_aio_complete(void *opaque, int ret)
>>> @@ -511,8 +616,31 @@ static void qemu_aio_complete(void *opaque, int
>>> ret)
>>>           return;
>>>       }
>>>
>>> +    if (ioreq->blkdev->feature_grant_copy) {
>>> +        switch (ioreq->req.operation) {
>>> +        case BLKIF_OP_READ:
>>> +            /* in case of failure ioreq->aio_errors is increased */
>>> +            if (ret == 0) {
>>> +                ioreq_copy(ioreq);
>>> +            }
>>> +            free_buffers(ioreq);
>>> +            break;
>>> +        case BLKIF_OP_WRITE:
>>> +        case BLKIF_OP_FLUSH_DISKCACHE:
>>> +            if (!ioreq->req.nr_segments) {
>>> +                break;
>>> +            }
>>> +            free_buffers(ioreq);
>>> +            break;
>>> +        default:
>>> +            break;
>>> +        }
>>> +    }
>>> +
>>>       ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR :
>>> BLKIF_RSP_OKAY;
>>> -    ioreq_unmap(ioreq);
>>> +    if (!ioreq->blkdev->feature_grant_copy) {
>>> +        ioreq_unmap(ioreq);
>>> +    }
>>>       ioreq_finish(ioreq);
>>>       switch (ioreq->req.operation) {
>>>       case BLKIF_OP_WRITE:
>>> @@ -538,8 +666,20 @@ static int ioreq_runio_qemu_aio(struct ioreq
>>> *ioreq)
>>>   {
>>>       struct XenBlkDev *blkdev = ioreq->blkdev;
>>>
>>> -    if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1) {
>>> -        goto err_no_map;
>>> +    if (ioreq->blkdev->feature_grant_copy) {
>>> +        ioreq_init_copy_buffers(ioreq);
>>> +        if (ioreq->req.nr_segments && (ioreq->req.operation ==
>>> BLKIF_OP_WRITE ||
>>> +            ioreq->req.operation == BLKIF_OP_FLUSH_DISKCACHE)) {
>>> +            if (ioreq_copy(ioreq)) {
>>> +                free_buffers(ioreq);
>>> +                goto err;
>>> +            }
>>> +        }
>>> +
>>
>> Please remove blank this line (it looks a bit odd)
>>
>>
>>> +    } else {
>>> +        if (ioreq->req.nr_segments && ioreq_map(ioreq)) {
>>> +            goto err;
>>> +        }
>>>       }
>>>
>>>       ioreq->aio_inflight++;
>>> @@ -582,6 +722,9 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
>>>       }
>>>       default:
>>>           /* unknown operation (shouldn't happen -- parse catches
>>> this) */
>>> +        if (!ioreq->blkdev->feature_grant_copy) {
>>> +            ioreq_unmap(ioreq);
>>> +        }
>>
>> Why are you adding this? Is it a bug fix? If so, please explain in the
>> commit message.
>>
> It is not a bug fix. In the ioreq_runio_qemu_aio there were two error
> labels 'err_no_map' and 'err' each of them used once. So before the
> patch the labels are looking this way:
> err:
>      ioreq_unmap(ioreq);
> err_no_map:
>      ioreq_finish(ioreq);
>      ioreq->status = BLKIF_RSP_ERROR;
>      return -1;
>
> I removed the 'err_no_map' label and from the 'err' section I removed
> the ioreq_unmap. The 'err' label was previously used in that default
> section of the switch because the grant_map is called regardless the
> ioreq->req.operation.
>
> In the patch, there is no need for any special behavior for grant_copy,
> because buffers were not allocated in this case, so there is only jump
> to 'err'.
>
> An advantage of this change is one unified error path for both grant
> operations.
>>
>>>           goto err;
>>>       }
>>>
>>> @@ -590,8 +733,6 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
>>>       return 0;
>>>
>>>   err:
>>> -    ioreq_unmap(ioreq);
>>> -err_no_map:
>>>       ioreq_finish(ioreq);
>>>       ioreq->status = BLKIF_RSP_ERROR;
>>>       return -1;
>>> @@ -1032,6 +1173,12 @@ static int blk_connect(struct XenDevice *xendev)
>>>
>>>       xen_be_bind_evtchn(&blkdev->xendev);
>>>
>>> +    blkdev->feature_grant_copy =
>>> +                (xengnttab_grant_copy(blkdev->xendev.gnttabdev, 0,
>>> NULL) == 0);
>>> +
>>> +    xen_be_printf(&blkdev->xendev, 3, "grant copy operation %s\n",
>>> +                  blkdev->feature_grant_copy ? "enabled" : "disabled");
>>> +
>>>       xen_be_printf(&blkdev->xendev, 1, "ok: proto %s, ring-ref %d, "
>>>                     "remote port %d, local port %d\n",
>>>                     blkdev->xendev.protocol, blkdev->ring_ref,
>>> diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h
>>> index bd39287..8e1580d 100644
>>> --- a/include/hw/xen/xen_common.h
>>> +++ b/include/hw/xen/xen_common.h
>>> @@ -424,4 +424,18 @@ static inline int xen_domain_create(xc_interface
>>> *xc, uint32_t ssidref,
>>>   #endif
>>>   #endif
>>>
>>> +/* Xen before 4.8 */
>>> +
>>> +#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 480
>>> +
>>> +
>>> +typedef void *xengnttab_grant_copy_segment_t;
>>> +
>>> +static inline int xengnttab_grant_copy(xengnttab_handle *xgt,
>>> uint32_t count,
>>> +
>>> xengnttab_grant_copy_segment_t *segs)
>>> +{
>>> +    return -ENOSYS;
>>> +}
>>> +#endif
>>> +
>>>   #endif /* QEMU_HW_XEN_COMMON_H */
>>> --
>>> 1.9.1
>>>
>
> Paulina
Paulina

  parent reply	other threads:[~2016-09-09 12:32 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-09-07 10:40 [Qemu-devel] [PATCH v6 0/2] qemu-qdisk: Implementation of grant copy operation Paulina Szubarczyk
2016-09-07 10:40 ` [Qemu-devel] [PATCH v6 1/2] libs/gnttab: introduce grant copy interface Paulina Szubarczyk
2016-09-07 10:41 ` [Qemu-devel] [PATCH v6 2/2] qdisk - hw/block/xen_disk: grant copy implementation Paulina Szubarczyk
2016-09-07 17:05   ` Anthony PERARD
2016-09-07 20:56   ` Stefano Stabellini
2016-09-07 22:00     ` Paulina Szubarczyk
2016-09-08 18:40       ` Stefano Stabellini
2016-09-09 12:32       ` Paulina Szubarczyk [this message]
2016-09-12 16:06   ` Roger Pau Monné

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=57D2ABE9.9070800@gmail.com \
    --to=paulinaszubarczyk@gmail.com \
    --cc=anthony.perard@citrix.com \
    --cc=david.vrabel@citrix.com \
    --cc=ian.jackson@eu.citrix.com \
    --cc=qemu-devel@nongnu.org \
    --cc=roger.pau@citrix.com \
    --cc=sstabellini@kernel.org \
    --cc=wei.liu2@citrix.com \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).