From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755434AbeEaOcs (ORCPT ); Thu, 31 May 2018 10:32:48 -0400 Received: from mail-lf0-f66.google.com ([209.85.215.66]:43652 "EHLO mail-lf0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755297AbeEaOcp (ORCPT ); Thu, 31 May 2018 10:32:45 -0400 X-Google-Smtp-Source: ADUXVKKzi1AnGayC7ihu88G9pNu/sydwjXoHSS8RInZoDiBSWmOr4lY+BfKtnoJctd7nsEzUFmdi5w== Subject: Re: [PATCH 6/8] xen/gntdev: Implement dma-buf export functionality From: Oleksandr Andrushchenko To: Dongwon Kim Cc: xen-devel@lists.xenproject.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-media@vger.kernel.org, jgross@suse.com, boris.ostrovsky@oracle.com, konrad.wilk@oracle.com, daniel.vetter@intel.com, matthew.d.roper@intel.com, Oleksandr Andrushchenko References: <20180525153331.31188-1-andr2000@gmail.com> <20180525153331.31188-7-andr2000@gmail.com> <20180530231006.GA2929@downor-Z87X-UD5H> <072fb651-52db-05bd-d110-ada904bcac3d@gmail.com> Message-ID: Date: Thu, 31 May 2018 17:32:41 +0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.8.0 MIME-Version: 1.0 In-Reply-To: <072fb651-52db-05bd-d110-ada904bcac3d@gmail.com> Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit Content-Language: en-US Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 05/31/2018 08:55 AM, Oleksandr Andrushchenko wrote: > On 05/31/2018 02:10 AM, Dongwon Kim wrote: >> On Fri, May 25, 2018 at 06:33:29PM +0300, Oleksandr Andrushchenko wrote: >>> From: Oleksandr Andrushchenko >>> >>> 1. Create a dma-buf from grant references provided by the foreign >>>     domain. By default dma-buf is backed by system memory pages, but >>>     by providing GNTDEV_DMA_FLAG_XXX flags it can also be created >>>     as a DMA write-combine/coherent buffer, e.g. allocated with >>>     corresponding dma_alloc_xxx API. >>>     Export the resulting buffer as a new dma-buf. >>> >>> 2. Implement waiting for the dma-buf to be released: block until the >>>     dma-buf with the file descriptor provided is released. >>>     If within the time-out provided the buffer is not released then >>>     -ETIMEDOUT error is returned. If the buffer with the file >>> descriptor >>>     does not exist or has already been released, then -ENOENT is >>> returned. >>>     For valid file descriptors this must not be treated as error. >>> >>> Signed-off-by: Oleksandr Andrushchenko >>> >>> --- >>>   drivers/xen/gntdev.c | 478 >>> ++++++++++++++++++++++++++++++++++++++++++- >>>   1 file changed, 476 insertions(+), 2 deletions(-) >>> >>> diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c >>> index 9e450622af1a..52abc6cd5846 100644 >>> --- a/drivers/xen/gntdev.c >>> +++ b/drivers/xen/gntdev.c >>> @@ -4,6 +4,8 @@ >>>    * Device for accessing (in user-space) pages that have been >>> granted by other >>>    * domains. >>>    * >>> + * DMA buffer implementation is based on drivers/gpu/drm/drm_prime.c. >>> + * >>>    * Copyright (c) 2006-2007, D G Murray. >>>    *           (c) 2009 Gerd Hoffmann >>>    *           (c) 2018 Oleksandr Andrushchenko, EPAM Systems Inc. >>> @@ -41,6 +43,9 @@ >>>   #ifdef CONFIG_XEN_GRANT_DMA_ALLOC >>>   #include >>>   #endif >>> +#ifdef CONFIG_XEN_GNTDEV_DMABUF >>> +#include >>> +#endif >>>     #include >>>   #include >>> @@ -81,6 +86,17 @@ struct gntdev_priv { >>>       /* Device for which DMA memory is allocated. */ >>>       struct device *dma_dev; >>>   #endif >>> + >>> +#ifdef CONFIG_XEN_GNTDEV_DMABUF >>> +    /* Private data of the hyper DMA buffers. */ >>> + >>> +    /* List of exported DMA buffers. */ >>> +    struct list_head dmabuf_exp_list; >>> +    /* List of wait objects. */ >>> +    struct list_head dmabuf_exp_wait_list; >>> +    /* This is the lock which protects dma_buf_xxx lists. */ >>> +    struct mutex dmabuf_lock; >>> +#endif >>>   }; >>>     struct unmap_notify { >>> @@ -125,12 +141,38 @@ struct grant_map { >>>     #ifdef CONFIG_XEN_GNTDEV_DMABUF >>>   struct xen_dmabuf { >>> +    struct gntdev_priv *priv; >>> +    struct dma_buf *dmabuf; >>> +    struct list_head next; >>> +    int fd; >>> + >>>       union { >>> +        struct { >>> +            /* Exported buffers are reference counted. */ >>> +            struct kref refcount; >>> +            struct grant_map *map; >>> +        } exp; >>>           struct { >>>               /* Granted references of the imported buffer. */ >>>               grant_ref_t *refs; >>>           } imp; >>>       } u; >>> + >>> +    /* Number of pages this buffer has. */ >>> +    int nr_pages; >>> +    /* Pages of this buffer. */ >>> +    struct page **pages; >>> +}; >>> + >>> +struct xen_dmabuf_wait_obj { >>> +    struct list_head next; >>> +    struct xen_dmabuf *xen_dmabuf; >>> +    struct completion completion; >>> +}; >>> + >>> +struct xen_dmabuf_attachment { >>> +    struct sg_table *sgt; >>> +    enum dma_data_direction dir; >>>   }; >>>   #endif >>>   @@ -320,6 +362,16 @@ static void gntdev_put_map(struct gntdev_priv >>> *priv, struct grant_map *map) >>>       gntdev_free_map(map); >>>   } >>>   +#ifdef CONFIG_XEN_GNTDEV_DMABUF >>> +static void gntdev_remove_map(struct gntdev_priv *priv, struct >>> grant_map *map) >>> +{ >>> +    mutex_lock(&priv->lock); >>> +    list_del(&map->next); >>> +    gntdev_put_map(NULL /* already removed */, map); >>> +    mutex_unlock(&priv->lock); >>> +} >>> +#endif >>> + >>>   /* >>> ------------------------------------------------------------------ */ >>>     static int find_grant_ptes(pte_t *pte, pgtable_t token, >>> @@ -628,6 +680,12 @@ static int gntdev_open(struct inode *inode, >>> struct file *flip) >>>       INIT_LIST_HEAD(&priv->freeable_maps); >>>       mutex_init(&priv->lock); >>>   +#ifdef CONFIG_XEN_GNTDEV_DMABUF >>> +    mutex_init(&priv->dmabuf_lock); >>> +    INIT_LIST_HEAD(&priv->dmabuf_exp_list); >>> +    INIT_LIST_HEAD(&priv->dmabuf_exp_wait_list); >>> +#endif >>> + >>>       if (use_ptemod) { >>>           priv->mm = get_task_mm(current); >>>           if (!priv->mm) { >>> @@ -1053,17 +1111,433 @@ static long gntdev_ioctl_grant_copy(struct >>> gntdev_priv *priv, void __user *u) >>>   /* DMA buffer export >>> support.                                         */ >>>   /* >>> ------------------------------------------------------------------ */ >>>   +/* >>> ------------------------------------------------------------------ */ >>> +/* Implementation of wait for exported DMA buffer to be >>> released.     */ >>> +/* >>> ------------------------------------------------------------------ */ >>> + >>> +static void dmabuf_exp_release(struct kref *kref); >>> + >>> +static struct xen_dmabuf_wait_obj * >>> +dmabuf_exp_wait_obj_new(struct gntdev_priv *priv, >>> +            struct xen_dmabuf *xen_dmabuf) >>> +{ >>> +    struct xen_dmabuf_wait_obj *obj; >>> + >>> +    obj = kzalloc(sizeof(*obj), GFP_KERNEL); >>> +    if (!obj) >>> +        return ERR_PTR(-ENOMEM); >>> + >>> +    init_completion(&obj->completion); >>> +    obj->xen_dmabuf = xen_dmabuf; >>> + >>> +    mutex_lock(&priv->dmabuf_lock); >>> +    list_add(&obj->next, &priv->dmabuf_exp_wait_list); >>> +    /* Put our reference and wait for xen_dmabuf's release to fire. */ >>> +    kref_put(&xen_dmabuf->u.exp.refcount, dmabuf_exp_release); >>> +    mutex_unlock(&priv->dmabuf_lock); >>> +    return obj; >>> +} >>> + >>> +static void dmabuf_exp_wait_obj_free(struct gntdev_priv *priv, >>> +                     struct xen_dmabuf_wait_obj *obj) >>> +{ >>> +    struct xen_dmabuf_wait_obj *cur_obj, *q; >>> + >>> +    mutex_lock(&priv->dmabuf_lock); >>> +    list_for_each_entry_safe(cur_obj, q, >>> &priv->dmabuf_exp_wait_list, next) >>> +        if (cur_obj == obj) { >>> +            list_del(&obj->next); >>> +            kfree(obj); >>> +            break; >>> +        } >>> +    mutex_unlock(&priv->dmabuf_lock); >>> +} >>> + >>> +static int dmabuf_exp_wait_obj_wait(struct xen_dmabuf_wait_obj *obj, >>> +                    u32 wait_to_ms) >>> +{ >>> +    if (wait_for_completion_timeout(&obj->completion, >>> +            msecs_to_jiffies(wait_to_ms)) <= 0) >>> +        return -ETIMEDOUT; >>> + >>> +    return 0; >>> +} >>> + >>> +static void dmabuf_exp_wait_obj_signal(struct gntdev_priv *priv, >>> +                       struct xen_dmabuf *xen_dmabuf) >>> +{ >>> +    struct xen_dmabuf_wait_obj *obj, *q; >>> + >>> +    list_for_each_entry_safe(obj, q, &priv->dmabuf_exp_wait_list, >>> next) >>> +        if (obj->xen_dmabuf == xen_dmabuf) { >>> +            pr_debug("Found xen_dmabuf in the wait list, wake\n"); >>> +            complete_all(&obj->completion); >>> +        } >>> +} >>> + >>> +static struct xen_dmabuf * >>> +dmabuf_exp_wait_obj_get_by_fd(struct gntdev_priv *priv, int fd) >>> +{ >>> +    struct xen_dmabuf *q, *xen_dmabuf, *ret = ERR_PTR(-ENOENT); >>> + >>> +    mutex_lock(&priv->dmabuf_lock); >>> +    list_for_each_entry_safe(xen_dmabuf, q, &priv->dmabuf_exp_list, >>> next) >>> +        if (xen_dmabuf->fd == fd) { >>> +            pr_debug("Found xen_dmabuf in the wait list\n"); >>> +            kref_get(&xen_dmabuf->u.exp.refcount); >>> +            ret = xen_dmabuf; >>> +            break; >>> +        } >>> +    mutex_unlock(&priv->dmabuf_lock); >>> +    return ret; >>> +} >>> + >>>   static int dmabuf_exp_wait_released(struct gntdev_priv *priv, int fd, >>>                       int wait_to_ms) >>>   { >>> -    return -ETIMEDOUT; >>> +    struct xen_dmabuf *xen_dmabuf; >>> +    struct xen_dmabuf_wait_obj *obj; >>> +    int ret; >>> + >>> +    pr_debug("Will wait for dma-buf with fd %d\n", fd); >>> +    /* >>> +     * Try to find the DMA buffer: if not found means that >>> +     * either the buffer has already been released or file descriptor >>> +     * provided is wrong. >>> +     */ >>> +    xen_dmabuf = dmabuf_exp_wait_obj_get_by_fd(priv, fd); >>> +    if (IS_ERR(xen_dmabuf)) >>> +        return PTR_ERR(xen_dmabuf); >>> + >>> +    /* >>> +     * xen_dmabuf still exists and is reference count locked by us >>> now, >>> +     * so prepare to wait: allocate wait object and add it to the >>> wait list, >>> +     * so we can find it on release. >>> +     */ >>> +    obj = dmabuf_exp_wait_obj_new(priv, xen_dmabuf); >>> +    if (IS_ERR(obj)) { >>> +        pr_err("Failed to setup wait object, ret %ld\n", >>> PTR_ERR(obj)); >>> +        return PTR_ERR(obj); >>> +    } >>> + >>> +    ret = dmabuf_exp_wait_obj_wait(obj, wait_to_ms); >>> +    dmabuf_exp_wait_obj_free(priv, obj); >>> +    return ret; >>> +} >>> + >>> +/* >>> ------------------------------------------------------------------ */ >>> +/* DMA buffer export >>> support.                                         */ >>> +/* >>> ------------------------------------------------------------------ */ >>> + >>> +static struct sg_table * >>> +dmabuf_pages_to_sgt(struct page **pages, unsigned int nr_pages) >>> +{ >>> +    struct sg_table *sgt; >>> +    int ret; >>> + >>> +    sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); >>> +    if (!sgt) { >>> +        ret = -ENOMEM; >>> +        goto out; >>> +    } >>> + >>> +    ret = sg_alloc_table_from_pages(sgt, pages, nr_pages, 0, >>> +                    nr_pages << PAGE_SHIFT, >>> +                    GFP_KERNEL); >>> +    if (ret) >>> +        goto out; >>> + >>> +    return sgt; >>> + >>> +out: >>> +    kfree(sgt); >>> +    return ERR_PTR(ret); >>> +} >>> + >>> +static int dmabuf_exp_ops_attach(struct dma_buf *dma_buf, >>> +                 struct device *target_dev, >>> +                 struct dma_buf_attachment *attach) >>> +{ >>> +    struct xen_dmabuf_attachment *xen_dmabuf_attach; >>> + >>> +    xen_dmabuf_attach = kzalloc(sizeof(*xen_dmabuf_attach), >>> GFP_KERNEL); >>> +    if (!xen_dmabuf_attach) >>> +        return -ENOMEM; >>> + >>> +    xen_dmabuf_attach->dir = DMA_NONE; >>> +    attach->priv = xen_dmabuf_attach; >>> +    /* Might need to pin the pages of the buffer now. */ >>> +    return 0; >>> +} >>> + >>> +static void dmabuf_exp_ops_detach(struct dma_buf *dma_buf, >>> +                  struct dma_buf_attachment *attach) >>> +{ >>> +    struct xen_dmabuf_attachment *xen_dmabuf_attach = attach->priv; >>> + >>> +    if (xen_dmabuf_attach) { >>> +        struct sg_table *sgt = xen_dmabuf_attach->sgt; >>> + >>> +        if (sgt) { >>> +            if (xen_dmabuf_attach->dir != DMA_NONE) >>> +                dma_unmap_sg_attrs(attach->dev, sgt->sgl, >>> +                           sgt->nents, >>> +                           xen_dmabuf_attach->dir, >>> +                           DMA_ATTR_SKIP_CPU_SYNC); >>> +            sg_free_table(sgt); >>> +        } >>> + >>> +        kfree(sgt); >>> +        kfree(xen_dmabuf_attach); >>> +        attach->priv = NULL; >>> +    } >>> +    /* Might need to unpin the pages of the buffer now. */ >>> +} >>> + >>> +static struct sg_table * >>> +dmabuf_exp_ops_map_dma_buf(struct dma_buf_attachment *attach, >>> +               enum dma_data_direction dir) >>> +{ >>> +    struct xen_dmabuf_attachment *xen_dmabuf_attach = attach->priv; >>> +    struct xen_dmabuf *xen_dmabuf = attach->dmabuf->priv; >>> +    struct sg_table *sgt; >>> + >>> +    pr_debug("Mapping %d pages for dev %p\n", xen_dmabuf->nr_pages, >>> +         attach->dev); >>> + >>> +    if (WARN_ON(dir == DMA_NONE || !xen_dmabuf_attach)) >>> +        return ERR_PTR(-EINVAL); >>> + >>> +    /* Return the cached mapping when possible. */ >>> +    if (xen_dmabuf_attach->dir == dir) >>> +        return xen_dmabuf_attach->sgt; >> may need to check xen_dmabuf_attach->sgt == NULL (i.e. first time >> mapping)? >> Also, I am not sure if this mechanism of reusing previously generated >> sgt >> for other mappings is universally ok for any use-cases... I don't >> know if >> it is acceptable as per the specification. > Well, I was not sure about this piece of code as well, > so I'll probably allocate a new sgt each time and do not reuse it > as now The sgt returned for the same attachment, so it is ok to return this cached one as we also check that the direction has not changed So, I'll leave it as is >>> + >>> +    /* >>> +     * Two mappings with different directions for the same >>> attachment are >>> +     * not allowed. >>> +     */ >>> +    if (WARN_ON(xen_dmabuf_attach->dir != DMA_NONE)) >>> +        return ERR_PTR(-EBUSY); >>> + >>> +    sgt = dmabuf_pages_to_sgt(xen_dmabuf->pages, >>> xen_dmabuf->nr_pages); >>> +    if (!IS_ERR(sgt)) { >>> +        if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir, >>> +                      DMA_ATTR_SKIP_CPU_SYNC)) { >>> +            sg_free_table(sgt); >>> +            kfree(sgt); >>> +            sgt = ERR_PTR(-ENOMEM); >>> +        } else { >>> +            xen_dmabuf_attach->sgt = sgt; >>> +            xen_dmabuf_attach->dir = dir; >>> +        } >>> +    } >>> +    if (IS_ERR(sgt)) >>> +        pr_err("Failed to map sg table for dev %p\n", attach->dev); >>> +    return sgt; >>> +} >>> + >>> +static void dmabuf_exp_ops_unmap_dma_buf(struct dma_buf_attachment >>> *attach, >>> +                     struct sg_table *sgt, >>> +                     enum dma_data_direction dir) >>> +{ >>> +    /* Not implemented. The unmap is done at >>> dmabuf_exp_ops_detach(). */ >> Not sure if it's ok to do nothing here because the spec says this >> function is >> mandatory and it should unmap and "release" &sg_table associated with >> it. >> >>     /** >>      * @unmap_dma_buf: >>      * >>      * This is called by dma_buf_unmap_attachment() and should unmap and >>      * release the &sg_table allocated in @map_dma_buf, and it is >> mandatory. >>      * It should also unpin the backing storage if this is the last >> mapping >>      * of the DMA buffer, it the exporter supports backing storage >>      * migration. >>      */ > Yes, as I say at the top of the file dma-buf handling is DRM PRIME > based, so I have the workflow just like in there. > Do you think we have to be more strict and rework this? > > Daniel, what do you think? I see other drivers in the kernel do the same. I think that *should* in the dma-buf documentation does allow that. So, I'll leave it as is for now >>> +} >>> + >>> +static void dmabuf_exp_release(struct kref *kref) >>> +{ >>> +    struct xen_dmabuf *xen_dmabuf = >>> +        container_of(kref, struct xen_dmabuf, u.exp.refcount); >>> + >>> +    dmabuf_exp_wait_obj_signal(xen_dmabuf->priv, xen_dmabuf); >>> +    list_del(&xen_dmabuf->next); >>> +    kfree(xen_dmabuf); >>> +} >>> + >>> +static void dmabuf_exp_ops_release(struct dma_buf *dma_buf) >>> +{ >>> +    struct xen_dmabuf *xen_dmabuf = dma_buf->priv; >>> +    struct gntdev_priv *priv = xen_dmabuf->priv; >>> + >>> +    gntdev_remove_map(priv, xen_dmabuf->u.exp.map); >>> +    mutex_lock(&priv->dmabuf_lock); >>> +    kref_put(&xen_dmabuf->u.exp.refcount, dmabuf_exp_release); >>> +    mutex_unlock(&priv->dmabuf_lock); >>> +} >>> + >>> +static void *dmabuf_exp_ops_kmap_atomic(struct dma_buf *dma_buf, >>> +                    unsigned long page_num) >>> +{ >>> +    /* Not implemented. */ >>> +    return NULL; >>> +} >>> + >>> +static void dmabuf_exp_ops_kunmap_atomic(struct dma_buf *dma_buf, >>> +                     unsigned long page_num, void *addr) >>> +{ >>> +    /* Not implemented. */ >>> +} >>> + >>> +static void *dmabuf_exp_ops_kmap(struct dma_buf *dma_buf, >>> +                 unsigned long page_num) >>> +{ >>> +    /* Not implemented. */ >>> +    return NULL; >>> +} >>> + >>> +static void dmabuf_exp_ops_kunmap(struct dma_buf *dma_buf, >>> +                  unsigned long page_num, void *addr) >>> +{ >>> +    /* Not implemented. */ >>> +} >>> + >>> +static int dmabuf_exp_ops_mmap(struct dma_buf *dma_buf, >>> +                   struct vm_area_struct *vma) >>> +{ >>> +    /* Not implemented. */ >>> +    return 0; >>> +} >>> + >>> +static const struct dma_buf_ops dmabuf_exp_ops =  { >>> +    .attach = dmabuf_exp_ops_attach, >>> +    .detach = dmabuf_exp_ops_detach, >>> +    .map_dma_buf = dmabuf_exp_ops_map_dma_buf, >>> +    .unmap_dma_buf = dmabuf_exp_ops_unmap_dma_buf, >>> +    .release = dmabuf_exp_ops_release, >>> +    .map = dmabuf_exp_ops_kmap, >>> +    .map_atomic = dmabuf_exp_ops_kmap_atomic, >>> +    .unmap = dmabuf_exp_ops_kunmap, >>> +    .unmap_atomic = dmabuf_exp_ops_kunmap_atomic, >>> +    .mmap = dmabuf_exp_ops_mmap, >>> +}; >>> + >>> +static int dmabuf_export(struct gntdev_priv *priv, struct grant_map >>> *map, >>> +             int *fd) >>> +{ >>> +    DEFINE_DMA_BUF_EXPORT_INFO(exp_info); >>> +    struct xen_dmabuf *xen_dmabuf; >>> +    int ret = 0; >>> + >>> +    xen_dmabuf = kzalloc(sizeof(*xen_dmabuf), GFP_KERNEL); >>> +    if (!xen_dmabuf) >>> +        return -ENOMEM; >>> + >>> +    kref_init(&xen_dmabuf->u.exp.refcount); >>> + >>> +    xen_dmabuf->priv = priv; >>> +    xen_dmabuf->nr_pages = map->count; >>> +    xen_dmabuf->pages = map->pages; >>> +    xen_dmabuf->u.exp.map = map; >>> + >>> +    exp_info.exp_name = KBUILD_MODNAME; >>> +    if (map->dma_dev->driver && map->dma_dev->driver->owner) >>> +        exp_info.owner = map->dma_dev->driver->owner; >>> +    else >>> +        exp_info.owner = THIS_MODULE; >>> +    exp_info.ops = &dmabuf_exp_ops; >>> +    exp_info.size = map->count << PAGE_SHIFT; >>> +    exp_info.flags = O_RDWR; >>> +    exp_info.priv = xen_dmabuf; >>> + >>> +    xen_dmabuf->dmabuf = dma_buf_export(&exp_info); >>> +    if (IS_ERR(xen_dmabuf->dmabuf)) { >>> +        ret = PTR_ERR(xen_dmabuf->dmabuf); >>> +        xen_dmabuf->dmabuf = NULL; >>> +        goto fail; >>> +    } >>> + >>> +    ret = dma_buf_fd(xen_dmabuf->dmabuf, O_CLOEXEC); >>> +    if (ret < 0) >>> +        goto fail; >>> + >>> +    xen_dmabuf->fd = ret; >>> +    *fd = ret; >>> + >>> +    pr_debug("Exporting DMA buffer with fd %d\n", ret); >>> + >>> +    mutex_lock(&priv->dmabuf_lock); >>> +    list_add(&xen_dmabuf->next, &priv->dmabuf_exp_list); >>> +    mutex_unlock(&priv->dmabuf_lock); >>> +    return 0; >>> + >>> +fail: >>> +    if (xen_dmabuf->dmabuf) >>> +        dma_buf_put(xen_dmabuf->dmabuf); >>> +    kfree(xen_dmabuf); >>> +    return ret; >>> +} >>> + >>> +static struct grant_map * >>> +dmabuf_exp_alloc_backing_storage(struct gntdev_priv *priv, int >>> dmabuf_flags, >>> +                 int count) >>> +{ >>> +    struct grant_map *map; >>> + >>> +    if (unlikely(count <= 0)) >>> +        return ERR_PTR(-EINVAL); >>> + >>> +    if ((dmabuf_flags & GNTDEV_DMA_FLAG_WC) && >>> +        (dmabuf_flags & GNTDEV_DMA_FLAG_COHERENT)) { >>> +        pr_err("Wrong dma-buf flags: either WC or coherent, not >>> both\n"); >>> +        return ERR_PTR(-EINVAL); >>> +    } >>> + >>> +    map = gntdev_alloc_map(priv, count, dmabuf_flags); >>> +    if (!map) >>> +        return ERR_PTR(-ENOMEM); >>> + >>> +    if (unlikely(atomic_add_return(count, &pages_mapped) > limit)) { >>> +        pr_err("can't map: over limit\n"); >>> +        gntdev_put_map(NULL, map); >>> +        return ERR_PTR(-ENOMEM); >>> +    } >>> +    return map; >>>   } >> When and how would this allocation be freed? I don't see any ioctl >> for freeing up >> shared pages. > on xen_dmabuf.release callback which is refcounted >>>     static int dmabuf_exp_from_refs(struct gntdev_priv *priv, int >>> flags, >>>                   int count, u32 domid, u32 *refs, u32 *fd) >>>   { >>> +    struct grant_map *map; >>> +    int i, ret; >>> + >>>       *fd = -1; >>> -    return -EINVAL; >>> + >>> +    if (use_ptemod) { >>> +        pr_err("Cannot provide dma-buf: use_ptemode %d\n", >>> +               use_ptemod); >>> +        return -EINVAL; >>> +    } >>> + >>> +    map = dmabuf_exp_alloc_backing_storage(priv, flags, count); >>> +    if (IS_ERR(map)) >>> +        return PTR_ERR(map); >>> + >>> +    for (i = 0; i < count; i++) { >>> +        map->grants[i].domid = domid; >>> +        map->grants[i].ref = refs[i]; >>> +    } >>> + >>> +    mutex_lock(&priv->lock); >>> +    gntdev_add_map(priv, map); >>> +    mutex_unlock(&priv->lock); >>> + >>> +    map->flags |= GNTMAP_host_map; >>> +#if defined(CONFIG_X86) >>> +    map->flags |= GNTMAP_device_map; >>> +#endif >>> + >>> +    ret = map_grant_pages(map); >>> +    if (ret < 0) >>> +        goto out; >>> + >>> +    ret = dmabuf_export(priv, map, fd); >>> +    if (ret < 0) >>> +        goto out; >>> + >>> +    return 0; >>> + >>> +out: >>> +    gntdev_remove_map(priv, map); >>> +    return ret; >>>   } >>>     /* >>> ------------------------------------------------------------------ */ >>> -- >>> 2.17.0 >>> > From mboxrd@z Thu Jan 1 00:00:00 1970 From: Oleksandr Andrushchenko Subject: Re: [PATCH 6/8] xen/gntdev: Implement dma-buf export functionality Date: Thu, 31 May 2018 17:32:41 +0300 Message-ID: References: <20180525153331.31188-1-andr2000@gmail.com> <20180525153331.31188-7-andr2000@gmail.com> <20180530231006.GA2929@downor-Z87X-UD5H> <072fb651-52db-05bd-d110-ada904bcac3d@gmail.com> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8"; Format="flowed" Content-Transfer-Encoding: base64 Return-path: Received: from mail-lf0-x242.google.com (mail-lf0-x242.google.com [IPv6:2a00:1450:4010:c07::242]) by gabe.freedesktop.org (Postfix) with ESMTPS id 776EC6E450 for ; Thu, 31 May 2018 14:32:45 +0000 (UTC) Received: by mail-lf0-x242.google.com with SMTP id t134-v6so10084414lff.6 for ; Thu, 31 May 2018 07:32:45 -0700 (PDT) In-Reply-To: <072fb651-52db-05bd-d110-ada904bcac3d@gmail.com> Content-Language: en-US List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: Dongwon Kim Cc: jgross@suse.com, konrad.wilk@oracle.com, Oleksandr Andrushchenko , linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, daniel.vetter@intel.com, xen-devel@lists.xenproject.org, boris.ostrovsky@oracle.com, linux-media@vger.kernel.org List-Id: dri-devel@lists.freedesktop.org T24gMDUvMzEvMjAxOCAwODo1NSBBTSwgT2xla3NhbmRyIEFuZHJ1c2hjaGVua28gd3JvdGU6Cj4g T24gMDUvMzEvMjAxOCAwMjoxMCBBTSwgRG9uZ3dvbiBLaW0gd3JvdGU6Cj4+IE9uIEZyaSwgTWF5 IDI1LCAyMDE4IGF0IDA2OjMzOjI5UE0gKzAzMDAsIE9sZWtzYW5kciBBbmRydXNoY2hlbmtvIHdy b3RlOgo+Pj4gRnJvbTogT2xla3NhbmRyIEFuZHJ1c2hjaGVua28gPG9sZWtzYW5kcl9hbmRydXNo Y2hlbmtvQGVwYW0uY29tPgo+Pj4KPj4+IDEuIENyZWF0ZSBhIGRtYS1idWYgZnJvbSBncmFudCBy ZWZlcmVuY2VzIHByb3ZpZGVkIGJ5IHRoZSBmb3JlaWduCj4+PiDCoMKgwqAgZG9tYWluLiBCeSBk ZWZhdWx0IGRtYS1idWYgaXMgYmFja2VkIGJ5IHN5c3RlbSBtZW1vcnkgcGFnZXMsIGJ1dAo+Pj4g wqDCoMKgIGJ5IHByb3ZpZGluZyBHTlRERVZfRE1BX0ZMQUdfWFhYIGZsYWdzIGl0IGNhbiBhbHNv IGJlIGNyZWF0ZWQKPj4+IMKgwqDCoCBhcyBhIERNQSB3cml0ZS1jb21iaW5lL2NvaGVyZW50IGJ1 ZmZlciwgZS5nLiBhbGxvY2F0ZWQgd2l0aAo+Pj4gwqDCoMKgIGNvcnJlc3BvbmRpbmcgZG1hX2Fs bG9jX3h4eCBBUEkuCj4+PiDCoMKgwqAgRXhwb3J0IHRoZSByZXN1bHRpbmcgYnVmZmVyIGFzIGEg bmV3IGRtYS1idWYuCj4+Pgo+Pj4gMi4gSW1wbGVtZW50IHdhaXRpbmcgZm9yIHRoZSBkbWEtYnVm IHRvIGJlIHJlbGVhc2VkOiBibG9jayB1bnRpbCB0aGUKPj4+IMKgwqDCoCBkbWEtYnVmIHdpdGgg dGhlIGZpbGUgZGVzY3JpcHRvciBwcm92aWRlZCBpcyByZWxlYXNlZC4KPj4+IMKgwqDCoCBJZiB3 aXRoaW4gdGhlIHRpbWUtb3V0IHByb3ZpZGVkIHRoZSBidWZmZXIgaXMgbm90IHJlbGVhc2VkIHRo ZW4KPj4+IMKgwqDCoCAtRVRJTUVET1VUIGVycm9yIGlzIHJldHVybmVkLiBJZiB0aGUgYnVmZmVy IHdpdGggdGhlIGZpbGUgCj4+PiBkZXNjcmlwdG9yCj4+PiDCoMKgwqAgZG9lcyBub3QgZXhpc3Qg b3IgaGFzIGFscmVhZHkgYmVlbiByZWxlYXNlZCwgdGhlbiAtRU5PRU5UIGlzIAo+Pj4gcmV0dXJu ZWQuCj4+PiDCoMKgwqAgRm9yIHZhbGlkIGZpbGUgZGVzY3JpcHRvcnMgdGhpcyBtdXN0IG5vdCBi ZSB0cmVhdGVkIGFzIGVycm9yLgo+Pj4KPj4+IFNpZ25lZC1vZmYtYnk6IE9sZWtzYW5kciBBbmRy dXNoY2hlbmtvIAo+Pj4gPG9sZWtzYW5kcl9hbmRydXNoY2hlbmtvQGVwYW0uY29tPgo+Pj4gLS0t Cj4+PiDCoCBkcml2ZXJzL3hlbi9nbnRkZXYuYyB8IDQ3OCAKPj4+ICsrKysrKysrKysrKysrKysr KysrKysrKysrKysrKysrKysrKysrKysrKy0KPj4+IMKgIDEgZmlsZSBjaGFuZ2VkLCA0NzYgaW5z ZXJ0aW9ucygrKSwgMiBkZWxldGlvbnMoLSkKPj4+Cj4+PiBkaWZmIC0tZ2l0IGEvZHJpdmVycy94 ZW4vZ250ZGV2LmMgYi9kcml2ZXJzL3hlbi9nbnRkZXYuYwo+Pj4gaW5kZXggOWU0NTA2MjJhZjFh Li41MmFiYzZjZDU4NDYgMTAwNjQ0Cj4+PiAtLS0gYS9kcml2ZXJzL3hlbi9nbnRkZXYuYwo+Pj4g KysrIGIvZHJpdmVycy94ZW4vZ250ZGV2LmMKPj4+IEBAIC00LDYgKzQsOCBAQAo+Pj4gwqDCoCAq IERldmljZSBmb3IgYWNjZXNzaW5nIChpbiB1c2VyLXNwYWNlKSBwYWdlcyB0aGF0IGhhdmUgYmVl biAKPj4+IGdyYW50ZWQgYnkgb3RoZXIKPj4+IMKgwqAgKiBkb21haW5zLgo+Pj4gwqDCoCAqCj4+ PiArICogRE1BIGJ1ZmZlciBpbXBsZW1lbnRhdGlvbiBpcyBiYXNlZCBvbiBkcml2ZXJzL2dwdS9k cm0vZHJtX3ByaW1lLmMuCj4+PiArICoKPj4+IMKgwqAgKiBDb3B5cmlnaHQgKGMpIDIwMDYtMjAw NywgRCBHIE11cnJheS4KPj4+IMKgwqAgKsKgwqDCoMKgwqDCoMKgwqDCoMKgIChjKSAyMDA5IEdl cmQgSG9mZm1hbm4gPGtyYXhlbEByZWRoYXQuY29tPgo+Pj4gwqDCoCAqwqDCoMKgwqDCoMKgwqDC oMKgwqAgKGMpIDIwMTggT2xla3NhbmRyIEFuZHJ1c2hjaGVua28sIEVQQU0gU3lzdGVtcyBJbmMu Cj4+PiBAQCAtNDEsNiArNDMsOSBAQAo+Pj4gwqAgI2lmZGVmIENPTkZJR19YRU5fR1JBTlRfRE1B X0FMTE9DCj4+PiDCoCAjaW5jbHVkZSA8bGludXgvb2ZfZGV2aWNlLmg+Cj4+PiDCoCAjZW5kaWYK Pj4+ICsjaWZkZWYgQ09ORklHX1hFTl9HTlRERVZfRE1BQlVGCj4+PiArI2luY2x1ZGUgPGxpbnV4 L2RtYS1idWYuaD4KPj4+ICsjZW5kaWYKPj4+IMKgIMKgICNpbmNsdWRlIDx4ZW4veGVuLmg+Cj4+ PiDCoCAjaW5jbHVkZSA8eGVuL2dyYW50X3RhYmxlLmg+Cj4+PiBAQCAtODEsNiArODYsMTcgQEAg c3RydWN0IGdudGRldl9wcml2IHsKPj4+IMKgwqDCoMKgwqAgLyogRGV2aWNlIGZvciB3aGljaCBE TUEgbWVtb3J5IGlzIGFsbG9jYXRlZC4gKi8KPj4+IMKgwqDCoMKgwqAgc3RydWN0IGRldmljZSAq ZG1hX2RldjsKPj4+IMKgICNlbmRpZgo+Pj4gKwo+Pj4gKyNpZmRlZiBDT05GSUdfWEVOX0dOVERF Vl9ETUFCVUYKPj4+ICvCoMKgwqAgLyogUHJpdmF0ZSBkYXRhIG9mIHRoZSBoeXBlciBETUEgYnVm ZmVycy4gKi8KPj4+ICsKPj4+ICvCoMKgwqAgLyogTGlzdCBvZiBleHBvcnRlZCBETUEgYnVmZmVy cy4gKi8KPj4+ICvCoMKgwqAgc3RydWN0IGxpc3RfaGVhZCBkbWFidWZfZXhwX2xpc3Q7Cj4+PiAr wqDCoMKgIC8qIExpc3Qgb2Ygd2FpdCBvYmplY3RzLiAqLwo+Pj4gK8KgwqDCoCBzdHJ1Y3QgbGlz dF9oZWFkIGRtYWJ1Zl9leHBfd2FpdF9saXN0Owo+Pj4gK8KgwqDCoCAvKiBUaGlzIGlzIHRoZSBs b2NrIHdoaWNoIHByb3RlY3RzIGRtYV9idWZfeHh4IGxpc3RzLiAqLwo+Pj4gK8KgwqDCoCBzdHJ1 Y3QgbXV0ZXggZG1hYnVmX2xvY2s7Cj4+PiArI2VuZGlmCj4+PiDCoCB9Owo+Pj4gwqAgwqAgc3Ry dWN0IHVubWFwX25vdGlmeSB7Cj4+PiBAQCAtMTI1LDEyICsxNDEsMzggQEAgc3RydWN0IGdyYW50 X21hcCB7Cj4+PiDCoCDCoCAjaWZkZWYgQ09ORklHX1hFTl9HTlRERVZfRE1BQlVGCj4+PiDCoCBz dHJ1Y3QgeGVuX2RtYWJ1ZiB7Cj4+PiArwqDCoMKgIHN0cnVjdCBnbnRkZXZfcHJpdiAqcHJpdjsK Pj4+ICvCoMKgwqAgc3RydWN0IGRtYV9idWYgKmRtYWJ1ZjsKPj4+ICvCoMKgwqAgc3RydWN0IGxp c3RfaGVhZCBuZXh0Owo+Pj4gK8KgwqDCoCBpbnQgZmQ7Cj4+PiArCj4+PiDCoMKgwqDCoMKgIHVu aW9uIHsKPj4+ICvCoMKgwqDCoMKgwqDCoCBzdHJ1Y3Qgewo+Pj4gK8KgwqDCoMKgwqDCoMKgwqDC oMKgwqAgLyogRXhwb3J0ZWQgYnVmZmVycyBhcmUgcmVmZXJlbmNlIGNvdW50ZWQuICovCj4+PiAr wqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzdHJ1Y3Qga3JlZiByZWZjb3VudDsKPj4+ICvCoMKgwqDC oMKgwqDCoMKgwqDCoMKgIHN0cnVjdCBncmFudF9tYXAgKm1hcDsKPj4+ICvCoMKgwqDCoMKgwqDC oCB9IGV4cDsKPj4+IMKgwqDCoMKgwqDCoMKgwqDCoCBzdHJ1Y3Qgewo+Pj4gwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqAgLyogR3JhbnRlZCByZWZlcmVuY2VzIG9mIHRoZSBpbXBvcnRlZCBidWZm ZXIuICovCj4+PiDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBncmFudF9yZWZfdCAqcmVmczsK Pj4+IMKgwqDCoMKgwqDCoMKgwqDCoCB9IGltcDsKPj4+IMKgwqDCoMKgwqAgfSB1Owo+Pj4gKwo+ Pj4gK8KgwqDCoCAvKiBOdW1iZXIgb2YgcGFnZXMgdGhpcyBidWZmZXIgaGFzLiAqLwo+Pj4gK8Kg wqDCoCBpbnQgbnJfcGFnZXM7Cj4+PiArwqDCoMKgIC8qIFBhZ2VzIG9mIHRoaXMgYnVmZmVyLiAq Lwo+Pj4gK8KgwqDCoCBzdHJ1Y3QgcGFnZSAqKnBhZ2VzOwo+Pj4gK307Cj4+PiArCj4+PiArc3Ry dWN0IHhlbl9kbWFidWZfd2FpdF9vYmogewo+Pj4gK8KgwqDCoCBzdHJ1Y3QgbGlzdF9oZWFkIG5l eHQ7Cj4+PiArwqDCoMKgIHN0cnVjdCB4ZW5fZG1hYnVmICp4ZW5fZG1hYnVmOwo+Pj4gK8KgwqDC oCBzdHJ1Y3QgY29tcGxldGlvbiBjb21wbGV0aW9uOwo+Pj4gK307Cj4+PiArCj4+PiArc3RydWN0 IHhlbl9kbWFidWZfYXR0YWNobWVudCB7Cj4+PiArwqDCoMKgIHN0cnVjdCBzZ190YWJsZSAqc2d0 Owo+Pj4gK8KgwqDCoCBlbnVtIGRtYV9kYXRhX2RpcmVjdGlvbiBkaXI7Cj4+PiDCoCB9Owo+Pj4g wqAgI2VuZGlmCj4+PiDCoCBAQCAtMzIwLDYgKzM2MiwxNiBAQCBzdGF0aWMgdm9pZCBnbnRkZXZf cHV0X21hcChzdHJ1Y3QgZ250ZGV2X3ByaXYgCj4+PiAqcHJpdiwgc3RydWN0IGdyYW50X21hcCAq bWFwKQo+Pj4gwqDCoMKgwqDCoCBnbnRkZXZfZnJlZV9tYXAobWFwKTsKPj4+IMKgIH0KPj4+IMKg ICsjaWZkZWYgQ09ORklHX1hFTl9HTlRERVZfRE1BQlVGCj4+PiArc3RhdGljIHZvaWQgZ250ZGV2 X3JlbW92ZV9tYXAoc3RydWN0IGdudGRldl9wcml2ICpwcml2LCBzdHJ1Y3QgCj4+PiBncmFudF9t YXAgKm1hcCkKPj4+ICt7Cj4+PiArwqDCoMKgIG11dGV4X2xvY2soJnByaXYtPmxvY2spOwo+Pj4g K8KgwqDCoCBsaXN0X2RlbCgmbWFwLT5uZXh0KTsKPj4+ICvCoMKgwqAgZ250ZGV2X3B1dF9tYXAo TlVMTCAvKiBhbHJlYWR5IHJlbW92ZWQgKi8sIG1hcCk7Cj4+PiArwqDCoMKgIG11dGV4X3VubG9j aygmcHJpdi0+bG9jayk7Cj4+PiArfQo+Pj4gKyNlbmRpZgo+Pj4gKwo+Pj4gwqAgLyogCj4+PiAt LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0gKi8KPj4+IMKgIMKgIHN0YXRpYyBpbnQgZmluZF9ncmFudF9wdGVzKHB0ZV90ICpw dGUsIHBndGFibGVfdCB0b2tlbiwKPj4+IEBAIC02MjgsNiArNjgwLDEyIEBAIHN0YXRpYyBpbnQg Z250ZGV2X29wZW4oc3RydWN0IGlub2RlICppbm9kZSwgCj4+PiBzdHJ1Y3QgZmlsZSAqZmxpcCkK Pj4+IMKgwqDCoMKgwqAgSU5JVF9MSVNUX0hFQUQoJnByaXYtPmZyZWVhYmxlX21hcHMpOwo+Pj4g wqDCoMKgwqDCoCBtdXRleF9pbml0KCZwcml2LT5sb2NrKTsKPj4+IMKgICsjaWZkZWYgQ09ORklH X1hFTl9HTlRERVZfRE1BQlVGCj4+PiArwqDCoMKgIG11dGV4X2luaXQoJnByaXYtPmRtYWJ1Zl9s b2NrKTsKPj4+ICvCoMKgwqAgSU5JVF9MSVNUX0hFQUQoJnByaXYtPmRtYWJ1Zl9leHBfbGlzdCk7 Cj4+PiArwqDCoMKgIElOSVRfTElTVF9IRUFEKCZwcml2LT5kbWFidWZfZXhwX3dhaXRfbGlzdCk7 Cj4+PiArI2VuZGlmCj4+PiArCj4+PiDCoMKgwqDCoMKgIGlmICh1c2VfcHRlbW9kKSB7Cj4+PiDC oMKgwqDCoMKgwqDCoMKgwqAgcHJpdi0+bW0gPSBnZXRfdGFza19tbShjdXJyZW50KTsKPj4+IMKg wqDCoMKgwqDCoMKgwqDCoCBpZiAoIXByaXYtPm1tKSB7Cj4+PiBAQCAtMTA1MywxNyArMTExMSw0 MzMgQEAgc3RhdGljIGxvbmcgZ250ZGV2X2lvY3RsX2dyYW50X2NvcHkoc3RydWN0IAo+Pj4gZ250 ZGV2X3ByaXYgKnByaXYsIHZvaWQgX191c2VyICp1KQo+Pj4gwqAgLyogRE1BIGJ1ZmZlciBleHBv cnQgCj4+PiBzdXBwb3J0LsKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgICovCj4+PiDCoCAvKiAKPj4+ IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLSAqLwo+Pj4gwqAgKy8qIAo+Pj4gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovCj4+PiArLyogSW1wbGVt ZW50YXRpb24gb2Ygd2FpdCBmb3IgZXhwb3J0ZWQgRE1BIGJ1ZmZlciB0byBiZSAKPj4+IHJlbGVh c2VkLsKgwqDCoMKgICovCj4+PiArLyogCj4+PiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi8KPj4+ICsKPj4+ICtzdGF0 aWMgdm9pZCBkbWFidWZfZXhwX3JlbGVhc2Uoc3RydWN0IGtyZWYgKmtyZWYpOwo+Pj4gKwo+Pj4g K3N0YXRpYyBzdHJ1Y3QgeGVuX2RtYWJ1Zl93YWl0X29iaiAqCj4+PiArZG1hYnVmX2V4cF93YWl0 X29ial9uZXcoc3RydWN0IGdudGRldl9wcml2ICpwcml2LAo+Pj4gK8KgwqDCoMKgwqDCoMKgwqDC oMKgwqAgc3RydWN0IHhlbl9kbWFidWYgKnhlbl9kbWFidWYpCj4+PiArewo+Pj4gK8KgwqDCoCBz dHJ1Y3QgeGVuX2RtYWJ1Zl93YWl0X29iaiAqb2JqOwo+Pj4gKwo+Pj4gK8KgwqDCoCBvYmogPSBr emFsbG9jKHNpemVvZigqb2JqKSwgR0ZQX0tFUk5FTCk7Cj4+PiArwqDCoMKgIGlmICghb2JqKQo+ Pj4gK8KgwqDCoMKgwqDCoMKgIHJldHVybiBFUlJfUFRSKC1FTk9NRU0pOwo+Pj4gKwo+Pj4gK8Kg wqDCoCBpbml0X2NvbXBsZXRpb24oJm9iai0+Y29tcGxldGlvbik7Cj4+PiArwqDCoMKgIG9iai0+ eGVuX2RtYWJ1ZiA9IHhlbl9kbWFidWY7Cj4+PiArCj4+PiArwqDCoMKgIG11dGV4X2xvY2soJnBy aXYtPmRtYWJ1Zl9sb2NrKTsKPj4+ICvCoMKgwqAgbGlzdF9hZGQoJm9iai0+bmV4dCwgJnByaXYt PmRtYWJ1Zl9leHBfd2FpdF9saXN0KTsKPj4+ICvCoMKgwqAgLyogUHV0IG91ciByZWZlcmVuY2Ug YW5kIHdhaXQgZm9yIHhlbl9kbWFidWYncyByZWxlYXNlIHRvIGZpcmUuICovCj4+PiArwqDCoMKg IGtyZWZfcHV0KCZ4ZW5fZG1hYnVmLT51LmV4cC5yZWZjb3VudCwgZG1hYnVmX2V4cF9yZWxlYXNl KTsKPj4+ICvCoMKgwqAgbXV0ZXhfdW5sb2NrKCZwcml2LT5kbWFidWZfbG9jayk7Cj4+PiArwqDC oMKgIHJldHVybiBvYmo7Cj4+PiArfQo+Pj4gKwo+Pj4gK3N0YXRpYyB2b2lkIGRtYWJ1Zl9leHBf d2FpdF9vYmpfZnJlZShzdHJ1Y3QgZ250ZGV2X3ByaXYgKnByaXYsCj4+PiArwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzdHJ1Y3QgeGVuX2RtYWJ1Zl93YWl0X29iaiAq b2JqKQo+Pj4gK3sKPj4+ICvCoMKgwqAgc3RydWN0IHhlbl9kbWFidWZfd2FpdF9vYmogKmN1cl9v YmosICpxOwo+Pj4gKwo+Pj4gK8KgwqDCoCBtdXRleF9sb2NrKCZwcml2LT5kbWFidWZfbG9jayk7 Cj4+PiArwqDCoMKgIGxpc3RfZm9yX2VhY2hfZW50cnlfc2FmZShjdXJfb2JqLCBxLCAKPj4+ICZw cml2LT5kbWFidWZfZXhwX3dhaXRfbGlzdCwgbmV4dCkKPj4+ICvCoMKgwqDCoMKgwqDCoCBpZiAo Y3VyX29iaiA9PSBvYmopIHsKPj4+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGxpc3RfZGVsKCZv YmotPm5leHQpOwo+Pj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAga2ZyZWUob2JqKTsKPj4+ICvC oMKgwqDCoMKgwqDCoMKgwqDCoMKgIGJyZWFrOwo+Pj4gK8KgwqDCoMKgwqDCoMKgIH0KPj4+ICvC oMKgwqAgbXV0ZXhfdW5sb2NrKCZwcml2LT5kbWFidWZfbG9jayk7Cj4+PiArfQo+Pj4gKwo+Pj4g K3N0YXRpYyBpbnQgZG1hYnVmX2V4cF93YWl0X29ial93YWl0KHN0cnVjdCB4ZW5fZG1hYnVmX3dh aXRfb2JqICpvYmosCj4+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAg dTMyIHdhaXRfdG9fbXMpCj4+PiArewo+Pj4gK8KgwqDCoCBpZiAod2FpdF9mb3JfY29tcGxldGlv bl90aW1lb3V0KCZvYmotPmNvbXBsZXRpb24sCj4+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBt c2Vjc190b19qaWZmaWVzKHdhaXRfdG9fbXMpKSA8PSAwKQo+Pj4gK8KgwqDCoMKgwqDCoMKgIHJl dHVybiAtRVRJTUVET1VUOwo+Pj4gKwo+Pj4gK8KgwqDCoCByZXR1cm4gMDsKPj4+ICt9Cj4+PiAr Cj4+PiArc3RhdGljIHZvaWQgZG1hYnVmX2V4cF93YWl0X29ial9zaWduYWwoc3RydWN0IGdudGRl dl9wcml2ICpwcml2LAo+Pj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgIHN0cnVjdCB4ZW5fZG1hYnVmICp4ZW5fZG1hYnVmKQo+Pj4gK3sKPj4+ICvCoMKgwqAg c3RydWN0IHhlbl9kbWFidWZfd2FpdF9vYmogKm9iaiwgKnE7Cj4+PiArCj4+PiArwqDCoMKgIGxp c3RfZm9yX2VhY2hfZW50cnlfc2FmZShvYmosIHEsICZwcml2LT5kbWFidWZfZXhwX3dhaXRfbGlz dCwgCj4+PiBuZXh0KQo+Pj4gK8KgwqDCoMKgwqDCoMKgIGlmIChvYmotPnhlbl9kbWFidWYgPT0g eGVuX2RtYWJ1Zikgewo+Pj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgcHJfZGVidWcoIkZvdW5k IHhlbl9kbWFidWYgaW4gdGhlIHdhaXQgbGlzdCwgd2FrZVxuIik7Cj4+PiArwqDCoMKgwqDCoMKg wqDCoMKgwqDCoCBjb21wbGV0ZV9hbGwoJm9iai0+Y29tcGxldGlvbik7Cj4+PiArwqDCoMKgwqDC oMKgwqAgfQo+Pj4gK30KPj4+ICsKPj4+ICtzdGF0aWMgc3RydWN0IHhlbl9kbWFidWYgKgo+Pj4g K2RtYWJ1Zl9leHBfd2FpdF9vYmpfZ2V0X2J5X2ZkKHN0cnVjdCBnbnRkZXZfcHJpdiAqcHJpdiwg aW50IGZkKQo+Pj4gK3sKPj4+ICvCoMKgwqAgc3RydWN0IHhlbl9kbWFidWYgKnEsICp4ZW5fZG1h YnVmLCAqcmV0ID0gRVJSX1BUUigtRU5PRU5UKTsKPj4+ICsKPj4+ICvCoMKgwqAgbXV0ZXhfbG9j aygmcHJpdi0+ZG1hYnVmX2xvY2spOwo+Pj4gK8KgwqDCoCBsaXN0X2Zvcl9lYWNoX2VudHJ5X3Nh ZmUoeGVuX2RtYWJ1ZiwgcSwgJnByaXYtPmRtYWJ1Zl9leHBfbGlzdCwgCj4+PiBuZXh0KQo+Pj4g K8KgwqDCoMKgwqDCoMKgIGlmICh4ZW5fZG1hYnVmLT5mZCA9PSBmZCkgewo+Pj4gK8KgwqDCoMKg wqDCoMKgwqDCoMKgwqAgcHJfZGVidWcoIkZvdW5kIHhlbl9kbWFidWYgaW4gdGhlIHdhaXQgbGlz dFxuIik7Cj4+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBrcmVmX2dldCgmeGVuX2RtYWJ1Zi0+ dS5leHAucmVmY291bnQpOwo+Pj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqAgcmV0ID0geGVuX2Rt YWJ1ZjsKPj4+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGJyZWFrOwo+Pj4gK8KgwqDCoMKgwqDC oMKgIH0KPj4+ICvCoMKgwqAgbXV0ZXhfdW5sb2NrKCZwcml2LT5kbWFidWZfbG9jayk7Cj4+PiAr wqDCoMKgIHJldHVybiByZXQ7Cj4+PiArfQo+Pj4gKwo+Pj4gwqAgc3RhdGljIGludCBkbWFidWZf ZXhwX3dhaXRfcmVsZWFzZWQoc3RydWN0IGdudGRldl9wcml2ICpwcml2LCBpbnQgZmQsCj4+PiDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgaW50IHdhaXRfdG9fbXMp Cj4+PiDCoCB7Cj4+PiAtwqDCoMKgIHJldHVybiAtRVRJTUVET1VUOwo+Pj4gK8KgwqDCoCBzdHJ1 Y3QgeGVuX2RtYWJ1ZiAqeGVuX2RtYWJ1ZjsKPj4+ICvCoMKgwqAgc3RydWN0IHhlbl9kbWFidWZf d2FpdF9vYmogKm9iajsKPj4+ICvCoMKgwqAgaW50IHJldDsKPj4+ICsKPj4+ICvCoMKgwqAgcHJf ZGVidWcoIldpbGwgd2FpdCBmb3IgZG1hLWJ1ZiB3aXRoIGZkICVkXG4iLCBmZCk7Cj4+PiArwqDC oMKgIC8qCj4+PiArwqDCoMKgwqAgKiBUcnkgdG8gZmluZCB0aGUgRE1BIGJ1ZmZlcjogaWYgbm90 IGZvdW5kIG1lYW5zIHRoYXQKPj4+ICvCoMKgwqDCoCAqIGVpdGhlciB0aGUgYnVmZmVyIGhhcyBh bHJlYWR5IGJlZW4gcmVsZWFzZWQgb3IgZmlsZSBkZXNjcmlwdG9yCj4+PiArwqDCoMKgwqAgKiBw cm92aWRlZCBpcyB3cm9uZy4KPj4+ICvCoMKgwqDCoCAqLwo+Pj4gK8KgwqDCoCB4ZW5fZG1hYnVm ID0gZG1hYnVmX2V4cF93YWl0X29ial9nZXRfYnlfZmQocHJpdiwgZmQpOwo+Pj4gK8KgwqDCoCBp ZiAoSVNfRVJSKHhlbl9kbWFidWYpKQo+Pj4gK8KgwqDCoMKgwqDCoMKgIHJldHVybiBQVFJfRVJS KHhlbl9kbWFidWYpOwo+Pj4gKwo+Pj4gK8KgwqDCoCAvKgo+Pj4gK8KgwqDCoMKgICogeGVuX2Rt YWJ1ZiBzdGlsbCBleGlzdHMgYW5kIGlzIHJlZmVyZW5jZSBjb3VudCBsb2NrZWQgYnkgdXMgCj4+ PiBub3csCj4+PiArwqDCoMKgwqAgKiBzbyBwcmVwYXJlIHRvIHdhaXQ6IGFsbG9jYXRlIHdhaXQg b2JqZWN0IGFuZCBhZGQgaXQgdG8gdGhlIAo+Pj4gd2FpdCBsaXN0LAo+Pj4gK8KgwqDCoMKgICog c28gd2UgY2FuIGZpbmQgaXQgb24gcmVsZWFzZS4KPj4+ICvCoMKgwqDCoCAqLwo+Pj4gK8KgwqDC oCBvYmogPSBkbWFidWZfZXhwX3dhaXRfb2JqX25ldyhwcml2LCB4ZW5fZG1hYnVmKTsKPj4+ICvC oMKgwqAgaWYgKElTX0VSUihvYmopKSB7Cj4+PiArwqDCoMKgwqDCoMKgwqAgcHJfZXJyKCJGYWls ZWQgdG8gc2V0dXAgd2FpdCBvYmplY3QsIHJldCAlbGRcbiIsIAo+Pj4gUFRSX0VSUihvYmopKTsK Pj4+ICvCoMKgwqDCoMKgwqDCoCByZXR1cm4gUFRSX0VSUihvYmopOwo+Pj4gK8KgwqDCoCB9Cj4+ PiArCj4+PiArwqDCoMKgIHJldCA9IGRtYWJ1Zl9leHBfd2FpdF9vYmpfd2FpdChvYmosIHdhaXRf dG9fbXMpOwo+Pj4gK8KgwqDCoCBkbWFidWZfZXhwX3dhaXRfb2JqX2ZyZWUocHJpdiwgb2JqKTsK Pj4+ICvCoMKgwqAgcmV0dXJuIHJldDsKPj4+ICt9Cj4+PiArCj4+PiArLyogCj4+PiAtLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0gKi8KPj4+ICsvKiBETUEgYnVmZmVyIGV4cG9ydCAKPj4+IHN1cHBvcnQuwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqAgKi8KPj4+ICsvKiAKPj4+IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqLwo+Pj4gKwo+Pj4gK3N0YXRp YyBzdHJ1Y3Qgc2dfdGFibGUgKgo+Pj4gK2RtYWJ1Zl9wYWdlc190b19zZ3Qoc3RydWN0IHBhZ2Ug KipwYWdlcywgdW5zaWduZWQgaW50IG5yX3BhZ2VzKQo+Pj4gK3sKPj4+ICvCoMKgwqAgc3RydWN0 IHNnX3RhYmxlICpzZ3Q7Cj4+PiArwqDCoMKgIGludCByZXQ7Cj4+PiArCj4+PiArwqDCoMKgIHNn dCA9IGttYWxsb2Moc2l6ZW9mKCpzZ3QpLCBHRlBfS0VSTkVMKTsKPj4+ICvCoMKgwqAgaWYgKCFz Z3QpIHsKPj4+ICvCoMKgwqDCoMKgwqDCoCByZXQgPSAtRU5PTUVNOwo+Pj4gK8KgwqDCoMKgwqDC oMKgIGdvdG8gb3V0Owo+Pj4gK8KgwqDCoCB9Cj4+PiArCj4+PiArwqDCoMKgIHJldCA9IHNnX2Fs bG9jX3RhYmxlX2Zyb21fcGFnZXMoc2d0LCBwYWdlcywgbnJfcGFnZXMsIDAsCj4+PiArwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgbnJfcGFnZXMgPDwgUEFHRV9TSElGVCwK Pj4+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBHRlBfS0VSTkVMKTsK Pj4+ICvCoMKgwqAgaWYgKHJldCkKPj4+ICvCoMKgwqDCoMKgwqDCoCBnb3RvIG91dDsKPj4+ICsK Pj4+ICvCoMKgwqAgcmV0dXJuIHNndDsKPj4+ICsKPj4+ICtvdXQ6Cj4+PiArwqDCoMKgIGtmcmVl KHNndCk7Cj4+PiArwqDCoMKgIHJldHVybiBFUlJfUFRSKHJldCk7Cj4+PiArfQo+Pj4gKwo+Pj4g K3N0YXRpYyBpbnQgZG1hYnVmX2V4cF9vcHNfYXR0YWNoKHN0cnVjdCBkbWFfYnVmICpkbWFfYnVm LAo+Pj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHN0cnVjdCBkZXZpY2UgKnRh cmdldF9kZXYsCj4+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgc3RydWN0IGRt YV9idWZfYXR0YWNobWVudCAqYXR0YWNoKQo+Pj4gK3sKPj4+ICvCoMKgwqAgc3RydWN0IHhlbl9k bWFidWZfYXR0YWNobWVudCAqeGVuX2RtYWJ1Zl9hdHRhY2g7Cj4+PiArCj4+PiArwqDCoMKgIHhl bl9kbWFidWZfYXR0YWNoID0ga3phbGxvYyhzaXplb2YoKnhlbl9kbWFidWZfYXR0YWNoKSwgCj4+ PiBHRlBfS0VSTkVMKTsKPj4+ICvCoMKgwqAgaWYgKCF4ZW5fZG1hYnVmX2F0dGFjaCkKPj4+ICvC oMKgwqDCoMKgwqDCoCByZXR1cm4gLUVOT01FTTsKPj4+ICsKPj4+ICvCoMKgwqAgeGVuX2RtYWJ1 Zl9hdHRhY2gtPmRpciA9IERNQV9OT05FOwo+Pj4gK8KgwqDCoCBhdHRhY2gtPnByaXYgPSB4ZW5f ZG1hYnVmX2F0dGFjaDsKPj4+ICvCoMKgwqAgLyogTWlnaHQgbmVlZCB0byBwaW4gdGhlIHBhZ2Vz IG9mIHRoZSBidWZmZXIgbm93LiAqLwo+Pj4gK8KgwqDCoCByZXR1cm4gMDsKPj4+ICt9Cj4+PiAr Cj4+PiArc3RhdGljIHZvaWQgZG1hYnVmX2V4cF9vcHNfZGV0YWNoKHN0cnVjdCBkbWFfYnVmICpk bWFfYnVmLAo+Pj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgc3RydWN0IGRt YV9idWZfYXR0YWNobWVudCAqYXR0YWNoKQo+Pj4gK3sKPj4+ICvCoMKgwqAgc3RydWN0IHhlbl9k bWFidWZfYXR0YWNobWVudCAqeGVuX2RtYWJ1Zl9hdHRhY2ggPSBhdHRhY2gtPnByaXY7Cj4+PiAr Cj4+PiArwqDCoMKgIGlmICh4ZW5fZG1hYnVmX2F0dGFjaCkgewo+Pj4gK8KgwqDCoMKgwqDCoMKg IHN0cnVjdCBzZ190YWJsZSAqc2d0ID0geGVuX2RtYWJ1Zl9hdHRhY2gtPnNndDsKPj4+ICsKPj4+ ICvCoMKgwqDCoMKgwqDCoCBpZiAoc2d0KSB7Cj4+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBp ZiAoeGVuX2RtYWJ1Zl9hdHRhY2gtPmRpciAhPSBETUFfTk9ORSkKPj4+ICvCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqAgZG1hX3VubWFwX3NnX2F0dHJzKGF0dGFjaC0+ZGV2LCBzZ3QtPnNn bCwKPj4+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgIHNndC0+bmVudHMsCj4+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoCB4ZW5fZG1hYnVmX2F0dGFjaC0+ZGlyLAo+Pj4gK8KgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgRE1BX0FUVFJfU0tJUF9D UFVfU1lOQyk7Cj4+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzZ19mcmVlX3RhYmxlKHNndCk7 Cj4+PiArwqDCoMKgwqDCoMKgwqAgfQo+Pj4gKwo+Pj4gK8KgwqDCoMKgwqDCoMKgIGtmcmVlKHNn dCk7Cj4+PiArwqDCoMKgwqDCoMKgwqAga2ZyZWUoeGVuX2RtYWJ1Zl9hdHRhY2gpOwo+Pj4gK8Kg wqDCoMKgwqDCoMKgIGF0dGFjaC0+cHJpdiA9IE5VTEw7Cj4+PiArwqDCoMKgIH0KPj4+ICvCoMKg wqAgLyogTWlnaHQgbmVlZCB0byB1bnBpbiB0aGUgcGFnZXMgb2YgdGhlIGJ1ZmZlciBub3cuICov Cj4+PiArfQo+Pj4gKwo+Pj4gK3N0YXRpYyBzdHJ1Y3Qgc2dfdGFibGUgKgo+Pj4gK2RtYWJ1Zl9l eHBfb3BzX21hcF9kbWFfYnVmKHN0cnVjdCBkbWFfYnVmX2F0dGFjaG1lbnQgKmF0dGFjaCwKPj4+ ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGVudW0gZG1hX2RhdGFfZGlyZWN0aW9uIGRp cikKPj4+ICt7Cj4+PiArwqDCoMKgIHN0cnVjdCB4ZW5fZG1hYnVmX2F0dGFjaG1lbnQgKnhlbl9k bWFidWZfYXR0YWNoID0gYXR0YWNoLT5wcml2Owo+Pj4gK8KgwqDCoCBzdHJ1Y3QgeGVuX2RtYWJ1 ZiAqeGVuX2RtYWJ1ZiA9IGF0dGFjaC0+ZG1hYnVmLT5wcml2Owo+Pj4gK8KgwqDCoCBzdHJ1Y3Qg c2dfdGFibGUgKnNndDsKPj4+ICsKPj4+ICvCoMKgwqAgcHJfZGVidWcoIk1hcHBpbmcgJWQgcGFn ZXMgZm9yIGRldiAlcFxuIiwgeGVuX2RtYWJ1Zi0+bnJfcGFnZXMsCj4+PiArwqDCoMKgwqDCoMKg wqDCoCBhdHRhY2gtPmRldik7Cj4+PiArCj4+PiArwqDCoMKgIGlmIChXQVJOX09OKGRpciA9PSBE TUFfTk9ORSB8fCAheGVuX2RtYWJ1Zl9hdHRhY2gpKQo+Pj4gK8KgwqDCoMKgwqDCoMKgIHJldHVy biBFUlJfUFRSKC1FSU5WQUwpOwo+Pj4gKwo+Pj4gK8KgwqDCoCAvKiBSZXR1cm4gdGhlIGNhY2hl ZCBtYXBwaW5nIHdoZW4gcG9zc2libGUuICovCj4+PiArwqDCoMKgIGlmICh4ZW5fZG1hYnVmX2F0 dGFjaC0+ZGlyID09IGRpcikKPj4+ICvCoMKgwqDCoMKgwqDCoCByZXR1cm4geGVuX2RtYWJ1Zl9h dHRhY2gtPnNndDsKPj4gbWF5IG5lZWQgdG8gY2hlY2sgeGVuX2RtYWJ1Zl9hdHRhY2gtPnNndCA9 PSBOVUxMIChpLmUuIGZpcnN0IHRpbWUgCj4+IG1hcHBpbmcpPwo+PiBBbHNvLCBJIGFtIG5vdCBz dXJlIGlmIHRoaXMgbWVjaGFuaXNtIG9mIHJldXNpbmcgcHJldmlvdXNseSBnZW5lcmF0ZWQgCj4+ IHNndAo+PiBmb3Igb3RoZXIgbWFwcGluZ3MgaXMgdW5pdmVyc2FsbHkgb2sgZm9yIGFueSB1c2Ut Y2FzZXMuLi4gSSBkb24ndCAKPj4ga25vdyBpZgo+PiBpdCBpcyBhY2NlcHRhYmxlIGFzIHBlciB0 aGUgc3BlY2lmaWNhdGlvbi4KPiBXZWxsLCBJIHdhcyBub3Qgc3VyZSBhYm91dCB0aGlzIHBpZWNl IG9mIGNvZGUgYXMgd2VsbCwKPiBzbyBJJ2xsIHByb2JhYmx5IGFsbG9jYXRlIGEgbmV3IHNndCBl YWNoIHRpbWUgYW5kIGRvIG5vdCByZXVzZSBpdAo+IGFzIG5vdwpUaGUgc2d0IHJldHVybmVkIGZv ciB0aGUgc2FtZSBhdHRhY2htZW50LCBzbyBpdCBpcyBvayB0byByZXR1cm4gdGhpcyAKY2FjaGVk IG9uZQphcyB3ZSBhbHNvIGNoZWNrIHRoYXQgdGhlIGRpcmVjdGlvbiBoYXMgbm90IGNoYW5nZWQK U28sIEknbGwgbGVhdmUgaXQgYXMgaXMKPj4+ICsKPj4+ICvCoMKgwqAgLyoKPj4+ICvCoMKgwqDC oCAqIFR3byBtYXBwaW5ncyB3aXRoIGRpZmZlcmVudCBkaXJlY3Rpb25zIGZvciB0aGUgc2FtZSAK Pj4+IGF0dGFjaG1lbnQgYXJlCj4+PiArwqDCoMKgwqAgKiBub3QgYWxsb3dlZC4KPj4+ICvCoMKg wqDCoCAqLwo+Pj4gK8KgwqDCoCBpZiAoV0FSTl9PTih4ZW5fZG1hYnVmX2F0dGFjaC0+ZGlyICE9 IERNQV9OT05FKSkKPj4+ICvCoMKgwqDCoMKgwqDCoCByZXR1cm4gRVJSX1BUUigtRUJVU1kpOwo+ Pj4gKwo+Pj4gK8KgwqDCoCBzZ3QgPSBkbWFidWZfcGFnZXNfdG9fc2d0KHhlbl9kbWFidWYtPnBh Z2VzLCAKPj4+IHhlbl9kbWFidWYtPm5yX3BhZ2VzKTsKPj4+ICvCoMKgwqAgaWYgKCFJU19FUlIo c2d0KSkgewo+Pj4gK8KgwqDCoMKgwqDCoMKgIGlmICghZG1hX21hcF9zZ19hdHRycyhhdHRhY2gt PmRldiwgc2d0LT5zZ2wsIHNndC0+bmVudHMsIGRpciwKPj4+ICvCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgRE1BX0FUVFJfU0tJUF9DUFVfU1lOQykpIHsKPj4+ICvC oMKgwqDCoMKgwqDCoMKgwqDCoMKgIHNnX2ZyZWVfdGFibGUoc2d0KTsKPj4+ICvCoMKgwqDCoMKg wqDCoMKgwqDCoMKgIGtmcmVlKHNndCk7Cj4+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzZ3Qg PSBFUlJfUFRSKC1FTk9NRU0pOwo+Pj4gK8KgwqDCoMKgwqDCoMKgIH0gZWxzZSB7Cj4+PiArwqDC oMKgwqDCoMKgwqDCoMKgwqDCoCB4ZW5fZG1hYnVmX2F0dGFjaC0+c2d0ID0gc2d0Owo+Pj4gK8Kg wqDCoMKgwqDCoMKgwqDCoMKgwqAgeGVuX2RtYWJ1Zl9hdHRhY2gtPmRpciA9IGRpcjsKPj4+ICvC oMKgwqDCoMKgwqDCoCB9Cj4+PiArwqDCoMKgIH0KPj4+ICvCoMKgwqAgaWYgKElTX0VSUihzZ3Qp KQo+Pj4gK8KgwqDCoMKgwqDCoMKgIHByX2VycigiRmFpbGVkIHRvIG1hcCBzZyB0YWJsZSBmb3Ig ZGV2ICVwXG4iLCBhdHRhY2gtPmRldik7Cj4+PiArwqDCoMKgIHJldHVybiBzZ3Q7Cj4+PiArfQo+ Pj4gKwo+Pj4gK3N0YXRpYyB2b2lkIGRtYWJ1Zl9leHBfb3BzX3VubWFwX2RtYV9idWYoc3RydWN0 IGRtYV9idWZfYXR0YWNobWVudCAKPj4+ICphdHRhY2gsCj4+PiArwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzdHJ1Y3Qgc2dfdGFibGUgKnNndCwKPj4+ICvCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGVudW0gZG1hX2RhdGFfZGlyZWN0aW9u IGRpcikKPj4+ICt7Cj4+PiArwqDCoMKgIC8qIE5vdCBpbXBsZW1lbnRlZC4gVGhlIHVubWFwIGlz IGRvbmUgYXQgCj4+PiBkbWFidWZfZXhwX29wc19kZXRhY2goKS4gKi8KPj4gTm90IHN1cmUgaWYg aXQncyBvayB0byBkbyBub3RoaW5nIGhlcmUgYmVjYXVzZSB0aGUgc3BlYyBzYXlzIHRoaXMgCj4+ IGZ1bmN0aW9uIGlzCj4+IG1hbmRhdG9yeSBhbmQgaXQgc2hvdWxkIHVubWFwIGFuZCAicmVsZWFz ZSIgJnNnX3RhYmxlIGFzc29jaWF0ZWQgd2l0aCAKPj4gaXQuCj4+Cj4+IMKgwqDCoMKgLyoqCj4+ IMKgwqDCoMKgICogQHVubWFwX2RtYV9idWY6Cj4+IMKgwqDCoMKgICoKPj4gwqDCoMKgwqAgKiBU aGlzIGlzIGNhbGxlZCBieSBkbWFfYnVmX3VubWFwX2F0dGFjaG1lbnQoKSBhbmQgc2hvdWxkIHVu bWFwIGFuZAo+PiDCoMKgwqDCoCAqIHJlbGVhc2UgdGhlICZzZ190YWJsZSBhbGxvY2F0ZWQgaW4g QG1hcF9kbWFfYnVmLCBhbmQgaXQgaXMgCj4+IG1hbmRhdG9yeS4KPj4gwqDCoMKgwqAgKiBJdCBz aG91bGQgYWxzbyB1bnBpbiB0aGUgYmFja2luZyBzdG9yYWdlIGlmIHRoaXMgaXMgdGhlIGxhc3Qg Cj4+IG1hcHBpbmcKPj4gwqDCoMKgwqAgKiBvZiB0aGUgRE1BIGJ1ZmZlciwgaXQgdGhlIGV4cG9y dGVyIHN1cHBvcnRzIGJhY2tpbmcgc3RvcmFnZQo+PiDCoMKgwqDCoCAqIG1pZ3JhdGlvbi4KPj4g wqDCoMKgwqAgKi8KPiBZZXMsIGFzIEkgc2F5IGF0IHRoZSB0b3Agb2YgdGhlIGZpbGUgZG1hLWJ1 ZiBoYW5kbGluZyBpcyBEUk0gUFJJTUUKPiBiYXNlZCwgc28gSSBoYXZlIHRoZSB3b3JrZmxvdyBq dXN0IGxpa2UgaW4gdGhlcmUuCj4gRG8geW91IHRoaW5rIHdlIGhhdmUgdG8gYmUgbW9yZSBzdHJp Y3QgYW5kIHJld29yayB0aGlzPwo+Cj4gRGFuaWVsLCB3aGF0IGRvIHlvdSB0aGluaz8KSSBzZWUg b3RoZXIgZHJpdmVycyBpbiB0aGUga2VybmVsIGRvIHRoZSBzYW1lLiBJIHRoaW5rIHRoYXQgKnNo b3VsZCoKaW4gdGhlIGRtYS1idWYgZG9jdW1lbnRhdGlvbiBkb2VzIGFsbG93IHRoYXQuClNvLCBJ J2xsIGxlYXZlIGl0IGFzIGlzIGZvciBub3cKPj4+ICt9Cj4+PiArCj4+PiArc3RhdGljIHZvaWQg ZG1hYnVmX2V4cF9yZWxlYXNlKHN0cnVjdCBrcmVmICprcmVmKQo+Pj4gK3sKPj4+ICvCoMKgwqAg c3RydWN0IHhlbl9kbWFidWYgKnhlbl9kbWFidWYgPQo+Pj4gK8KgwqDCoMKgwqDCoMKgIGNvbnRh aW5lcl9vZihrcmVmLCBzdHJ1Y3QgeGVuX2RtYWJ1ZiwgdS5leHAucmVmY291bnQpOwo+Pj4gKwo+ Pj4gK8KgwqDCoCBkbWFidWZfZXhwX3dhaXRfb2JqX3NpZ25hbCh4ZW5fZG1hYnVmLT5wcml2LCB4 ZW5fZG1hYnVmKTsKPj4+ICvCoMKgwqAgbGlzdF9kZWwoJnhlbl9kbWFidWYtPm5leHQpOwo+Pj4g K8KgwqDCoCBrZnJlZSh4ZW5fZG1hYnVmKTsKPj4+ICt9Cj4+PiArCj4+PiArc3RhdGljIHZvaWQg ZG1hYnVmX2V4cF9vcHNfcmVsZWFzZShzdHJ1Y3QgZG1hX2J1ZiAqZG1hX2J1ZikKPj4+ICt7Cj4+ PiArwqDCoMKgIHN0cnVjdCB4ZW5fZG1hYnVmICp4ZW5fZG1hYnVmID0gZG1hX2J1Zi0+cHJpdjsK Pj4+ICvCoMKgwqAgc3RydWN0IGdudGRldl9wcml2ICpwcml2ID0geGVuX2RtYWJ1Zi0+cHJpdjsK Pj4+ICsKPj4+ICvCoMKgwqAgZ250ZGV2X3JlbW92ZV9tYXAocHJpdiwgeGVuX2RtYWJ1Zi0+dS5l eHAubWFwKTsKPj4+ICvCoMKgwqAgbXV0ZXhfbG9jaygmcHJpdi0+ZG1hYnVmX2xvY2spOwo+Pj4g K8KgwqDCoCBrcmVmX3B1dCgmeGVuX2RtYWJ1Zi0+dS5leHAucmVmY291bnQsIGRtYWJ1Zl9leHBf cmVsZWFzZSk7Cj4+PiArwqDCoMKgIG11dGV4X3VubG9jaygmcHJpdi0+ZG1hYnVmX2xvY2spOwo+ Pj4gK30KPj4+ICsKPj4+ICtzdGF0aWMgdm9pZCAqZG1hYnVmX2V4cF9vcHNfa21hcF9hdG9taWMo c3RydWN0IGRtYV9idWYgKmRtYV9idWYsCj4+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqAgdW5zaWduZWQgbG9uZyBwYWdlX251bSkKPj4+ICt7Cj4+PiArwqDCoMKgIC8q IE5vdCBpbXBsZW1lbnRlZC4gKi8KPj4+ICvCoMKgwqAgcmV0dXJuIE5VTEw7Cj4+PiArfQo+Pj4g Kwo+Pj4gK3N0YXRpYyB2b2lkIGRtYWJ1Zl9leHBfb3BzX2t1bm1hcF9hdG9taWMoc3RydWN0IGRt YV9idWYgKmRtYV9idWYsCj4+PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoCB1bnNpZ25lZCBsb25nIHBhZ2VfbnVtLCB2b2lkICphZGRyKQo+Pj4gK3sKPj4+ICvCoMKg wqAgLyogTm90IGltcGxlbWVudGVkLiAqLwo+Pj4gK30KPj4+ICsKPj4+ICtzdGF0aWMgdm9pZCAq ZG1hYnVmX2V4cF9vcHNfa21hcChzdHJ1Y3QgZG1hX2J1ZiAqZG1hX2J1ZiwKPj4+ICvCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCB1bnNpZ25lZCBsb25nIHBhZ2VfbnVtKQo+Pj4gK3sK Pj4+ICvCoMKgwqAgLyogTm90IGltcGxlbWVudGVkLiAqLwo+Pj4gK8KgwqDCoCByZXR1cm4gTlVM TDsKPj4+ICt9Cj4+PiArCj4+PiArc3RhdGljIHZvaWQgZG1hYnVmX2V4cF9vcHNfa3VubWFwKHN0 cnVjdCBkbWFfYnVmICpkbWFfYnVmLAo+Pj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqAgdW5zaWduZWQgbG9uZyBwYWdlX251bSwgdm9pZCAqYWRkcikKPj4+ICt7Cj4+PiArwqDC oMKgIC8qIE5vdCBpbXBsZW1lbnRlZC4gKi8KPj4+ICt9Cj4+PiArCj4+PiArc3RhdGljIGludCBk bWFidWZfZXhwX29wc19tbWFwKHN0cnVjdCBkbWFfYnVmICpkbWFfYnVmLAo+Pj4gK8KgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzdHJ1Y3Qgdm1fYXJlYV9zdHJ1Y3QgKnZtYSkK Pj4+ICt7Cj4+PiArwqDCoMKgIC8qIE5vdCBpbXBsZW1lbnRlZC4gKi8KPj4+ICvCoMKgwqAgcmV0 dXJuIDA7Cj4+PiArfQo+Pj4gKwo+Pj4gK3N0YXRpYyBjb25zdCBzdHJ1Y3QgZG1hX2J1Zl9vcHMg ZG1hYnVmX2V4cF9vcHMgPcKgIHsKPj4+ICvCoMKgwqAgLmF0dGFjaCA9IGRtYWJ1Zl9leHBfb3Bz X2F0dGFjaCwKPj4+ICvCoMKgwqAgLmRldGFjaCA9IGRtYWJ1Zl9leHBfb3BzX2RldGFjaCwKPj4+ ICvCoMKgwqAgLm1hcF9kbWFfYnVmID0gZG1hYnVmX2V4cF9vcHNfbWFwX2RtYV9idWYsCj4+PiAr wqDCoMKgIC51bm1hcF9kbWFfYnVmID0gZG1hYnVmX2V4cF9vcHNfdW5tYXBfZG1hX2J1ZiwKPj4+ ICvCoMKgwqAgLnJlbGVhc2UgPSBkbWFidWZfZXhwX29wc19yZWxlYXNlLAo+Pj4gK8KgwqDCoCAu bWFwID0gZG1hYnVmX2V4cF9vcHNfa21hcCwKPj4+ICvCoMKgwqAgLm1hcF9hdG9taWMgPSBkbWFi dWZfZXhwX29wc19rbWFwX2F0b21pYywKPj4+ICvCoMKgwqAgLnVubWFwID0gZG1hYnVmX2V4cF9v cHNfa3VubWFwLAo+Pj4gK8KgwqDCoCAudW5tYXBfYXRvbWljID0gZG1hYnVmX2V4cF9vcHNfa3Vu bWFwX2F0b21pYywKPj4+ICvCoMKgwqAgLm1tYXAgPSBkbWFidWZfZXhwX29wc19tbWFwLAo+Pj4g K307Cj4+PiArCj4+PiArc3RhdGljIGludCBkbWFidWZfZXhwb3J0KHN0cnVjdCBnbnRkZXZfcHJp diAqcHJpdiwgc3RydWN0IGdyYW50X21hcCAKPj4+ICptYXAsCj4+PiArwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgIGludCAqZmQpCj4+PiArewo+Pj4gK8KgwqDCoCBERUZJTkVfRE1BX0JVRl9FWFBP UlRfSU5GTyhleHBfaW5mbyk7Cj4+PiArwqDCoMKgIHN0cnVjdCB4ZW5fZG1hYnVmICp4ZW5fZG1h YnVmOwo+Pj4gK8KgwqDCoCBpbnQgcmV0ID0gMDsKPj4+ICsKPj4+ICvCoMKgwqAgeGVuX2RtYWJ1 ZiA9IGt6YWxsb2Moc2l6ZW9mKCp4ZW5fZG1hYnVmKSwgR0ZQX0tFUk5FTCk7Cj4+PiArwqDCoMKg IGlmICgheGVuX2RtYWJ1ZikKPj4+ICvCoMKgwqDCoMKgwqDCoCByZXR1cm4gLUVOT01FTTsKPj4+ ICsKPj4+ICvCoMKgwqAga3JlZl9pbml0KCZ4ZW5fZG1hYnVmLT51LmV4cC5yZWZjb3VudCk7Cj4+ PiArCj4+PiArwqDCoMKgIHhlbl9kbWFidWYtPnByaXYgPSBwcml2Owo+Pj4gK8KgwqDCoCB4ZW5f ZG1hYnVmLT5ucl9wYWdlcyA9IG1hcC0+Y291bnQ7Cj4+PiArwqDCoMKgIHhlbl9kbWFidWYtPnBh Z2VzID0gbWFwLT5wYWdlczsKPj4+ICvCoMKgwqAgeGVuX2RtYWJ1Zi0+dS5leHAubWFwID0gbWFw Owo+Pj4gKwo+Pj4gK8KgwqDCoCBleHBfaW5mby5leHBfbmFtZSA9IEtCVUlMRF9NT0ROQU1FOwo+ Pj4gK8KgwqDCoCBpZiAobWFwLT5kbWFfZGV2LT5kcml2ZXIgJiYgbWFwLT5kbWFfZGV2LT5kcml2 ZXItPm93bmVyKQo+Pj4gK8KgwqDCoMKgwqDCoMKgIGV4cF9pbmZvLm93bmVyID0gbWFwLT5kbWFf ZGV2LT5kcml2ZXItPm93bmVyOwo+Pj4gK8KgwqDCoCBlbHNlCj4+PiArwqDCoMKgwqDCoMKgwqAg ZXhwX2luZm8ub3duZXIgPSBUSElTX01PRFVMRTsKPj4+ICvCoMKgwqAgZXhwX2luZm8ub3BzID0g JmRtYWJ1Zl9leHBfb3BzOwo+Pj4gK8KgwqDCoCBleHBfaW5mby5zaXplID0gbWFwLT5jb3VudCA8 PCBQQUdFX1NISUZUOwo+Pj4gK8KgwqDCoCBleHBfaW5mby5mbGFncyA9IE9fUkRXUjsKPj4+ICvC oMKgwqAgZXhwX2luZm8ucHJpdiA9IHhlbl9kbWFidWY7Cj4+PiArCj4+PiArwqDCoMKgIHhlbl9k bWFidWYtPmRtYWJ1ZiA9IGRtYV9idWZfZXhwb3J0KCZleHBfaW5mbyk7Cj4+PiArwqDCoMKgIGlm IChJU19FUlIoeGVuX2RtYWJ1Zi0+ZG1hYnVmKSkgewo+Pj4gK8KgwqDCoMKgwqDCoMKgIHJldCA9 IFBUUl9FUlIoeGVuX2RtYWJ1Zi0+ZG1hYnVmKTsKPj4+ICvCoMKgwqDCoMKgwqDCoCB4ZW5fZG1h YnVmLT5kbWFidWYgPSBOVUxMOwo+Pj4gK8KgwqDCoMKgwqDCoMKgIGdvdG8gZmFpbDsKPj4+ICvC oMKgwqAgfQo+Pj4gKwo+Pj4gK8KgwqDCoCByZXQgPSBkbWFfYnVmX2ZkKHhlbl9kbWFidWYtPmRt YWJ1ZiwgT19DTE9FWEVDKTsKPj4+ICvCoMKgwqAgaWYgKHJldCA8IDApCj4+PiArwqDCoMKgwqDC oMKgwqAgZ290byBmYWlsOwo+Pj4gKwo+Pj4gK8KgwqDCoCB4ZW5fZG1hYnVmLT5mZCA9IHJldDsK Pj4+ICvCoMKgwqAgKmZkID0gcmV0Owo+Pj4gKwo+Pj4gK8KgwqDCoCBwcl9kZWJ1ZygiRXhwb3J0 aW5nIERNQSBidWZmZXIgd2l0aCBmZCAlZFxuIiwgcmV0KTsKPj4+ICsKPj4+ICvCoMKgwqAgbXV0 ZXhfbG9jaygmcHJpdi0+ZG1hYnVmX2xvY2spOwo+Pj4gK8KgwqDCoCBsaXN0X2FkZCgmeGVuX2Rt YWJ1Zi0+bmV4dCwgJnByaXYtPmRtYWJ1Zl9leHBfbGlzdCk7Cj4+PiArwqDCoMKgIG11dGV4X3Vu bG9jaygmcHJpdi0+ZG1hYnVmX2xvY2spOwo+Pj4gK8KgwqDCoCByZXR1cm4gMDsKPj4+ICsKPj4+ ICtmYWlsOgo+Pj4gK8KgwqDCoCBpZiAoeGVuX2RtYWJ1Zi0+ZG1hYnVmKQo+Pj4gK8KgwqDCoMKg wqDCoMKgIGRtYV9idWZfcHV0KHhlbl9kbWFidWYtPmRtYWJ1Zik7Cj4+PiArwqDCoMKgIGtmcmVl KHhlbl9kbWFidWYpOwo+Pj4gK8KgwqDCoCByZXR1cm4gcmV0Owo+Pj4gK30KPj4+ICsKPj4+ICtz dGF0aWMgc3RydWN0IGdyYW50X21hcCAqCj4+PiArZG1hYnVmX2V4cF9hbGxvY19iYWNraW5nX3N0 b3JhZ2Uoc3RydWN0IGdudGRldl9wcml2ICpwcml2LCBpbnQgCj4+PiBkbWFidWZfZmxhZ3MsCj4+ PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgaW50IGNvdW50KQo+Pj4gK3sKPj4+ ICvCoMKgwqAgc3RydWN0IGdyYW50X21hcCAqbWFwOwo+Pj4gKwo+Pj4gK8KgwqDCoCBpZiAodW5s aWtlbHkoY291bnQgPD0gMCkpCj4+PiArwqDCoMKgwqDCoMKgwqAgcmV0dXJuIEVSUl9QVFIoLUVJ TlZBTCk7Cj4+PiArCj4+PiArwqDCoMKgIGlmICgoZG1hYnVmX2ZsYWdzICYgR05UREVWX0RNQV9G TEFHX1dDKSAmJgo+Pj4gK8KgwqDCoMKgwqDCoMKgIChkbWFidWZfZmxhZ3MgJiBHTlRERVZfRE1B X0ZMQUdfQ09IRVJFTlQpKSB7Cj4+PiArwqDCoMKgwqDCoMKgwqAgcHJfZXJyKCJXcm9uZyBkbWEt YnVmIGZsYWdzOiBlaXRoZXIgV0Mgb3IgY29oZXJlbnQsIG5vdCAKPj4+IGJvdGhcbiIpOwo+Pj4g K8KgwqDCoMKgwqDCoMKgIHJldHVybiBFUlJfUFRSKC1FSU5WQUwpOwo+Pj4gK8KgwqDCoCB9Cj4+ PiArCj4+PiArwqDCoMKgIG1hcCA9IGdudGRldl9hbGxvY19tYXAocHJpdiwgY291bnQsIGRtYWJ1 Zl9mbGFncyk7Cj4+PiArwqDCoMKgIGlmICghbWFwKQo+Pj4gK8KgwqDCoMKgwqDCoMKgIHJldHVy biBFUlJfUFRSKC1FTk9NRU0pOwo+Pj4gKwo+Pj4gK8KgwqDCoCBpZiAodW5saWtlbHkoYXRvbWlj X2FkZF9yZXR1cm4oY291bnQsICZwYWdlc19tYXBwZWQpID4gbGltaXQpKSB7Cj4+PiArwqDCoMKg wqDCoMKgwqAgcHJfZXJyKCJjYW4ndCBtYXA6IG92ZXIgbGltaXRcbiIpOwo+Pj4gK8KgwqDCoMKg wqDCoMKgIGdudGRldl9wdXRfbWFwKE5VTEwsIG1hcCk7Cj4+PiArwqDCoMKgwqDCoMKgwqAgcmV0 dXJuIEVSUl9QVFIoLUVOT01FTSk7Cj4+PiArwqDCoMKgIH0KPj4+ICvCoMKgwqAgcmV0dXJuIG1h cDsKPj4+IMKgIH0KPj4gV2hlbiBhbmQgaG93IHdvdWxkIHRoaXMgYWxsb2NhdGlvbiBiZSBmcmVl ZD8gSSBkb24ndCBzZWUgYW55IGlvY3RsIAo+PiBmb3IgZnJlZWluZyB1cAo+PiBzaGFyZWQgcGFn ZXMuCj4gb24geGVuX2RtYWJ1Zi5yZWxlYXNlIGNhbGxiYWNrIHdoaWNoIGlzIHJlZmNvdW50ZWQK Pj4+IMKgIMKgIHN0YXRpYyBpbnQgZG1hYnVmX2V4cF9mcm9tX3JlZnMoc3RydWN0IGdudGRldl9w cml2ICpwcml2LCBpbnQgCj4+PiBmbGFncywKPj4+IMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqAgaW50IGNvdW50LCB1MzIgZG9taWQsIHUzMiAqcmVmcywgdTMyICpmZCkKPj4+IMKg IHsKPj4+ICvCoMKgwqAgc3RydWN0IGdyYW50X21hcCAqbWFwOwo+Pj4gK8KgwqDCoCBpbnQgaSwg cmV0Owo+Pj4gKwo+Pj4gwqDCoMKgwqDCoCAqZmQgPSAtMTsKPj4+IC3CoMKgwqAgcmV0dXJuIC1F SU5WQUw7Cj4+PiArCj4+PiArwqDCoMKgIGlmICh1c2VfcHRlbW9kKSB7Cj4+PiArwqDCoMKgwqDC oMKgwqAgcHJfZXJyKCJDYW5ub3QgcHJvdmlkZSBkbWEtYnVmOiB1c2VfcHRlbW9kZSAlZFxuIiwK Pj4+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHVzZV9wdGVtb2QpOwo+Pj4gK8KgwqDC oMKgwqDCoMKgIHJldHVybiAtRUlOVkFMOwo+Pj4gK8KgwqDCoCB9Cj4+PiArCj4+PiArwqDCoMKg IG1hcCA9IGRtYWJ1Zl9leHBfYWxsb2NfYmFja2luZ19zdG9yYWdlKHByaXYsIGZsYWdzLCBjb3Vu dCk7Cj4+PiArwqDCoMKgIGlmIChJU19FUlIobWFwKSkKPj4+ICvCoMKgwqDCoMKgwqDCoCByZXR1 cm4gUFRSX0VSUihtYXApOwo+Pj4gKwo+Pj4gK8KgwqDCoCBmb3IgKGkgPSAwOyBpIDwgY291bnQ7 IGkrKykgewo+Pj4gK8KgwqDCoMKgwqDCoMKgIG1hcC0+Z3JhbnRzW2ldLmRvbWlkID0gZG9taWQ7 Cj4+PiArwqDCoMKgwqDCoMKgwqAgbWFwLT5ncmFudHNbaV0ucmVmID0gcmVmc1tpXTsKPj4+ICvC oMKgwqAgfQo+Pj4gKwo+Pj4gK8KgwqDCoCBtdXRleF9sb2NrKCZwcml2LT5sb2NrKTsKPj4+ICvC oMKgwqAgZ250ZGV2X2FkZF9tYXAocHJpdiwgbWFwKTsKPj4+ICvCoMKgwqAgbXV0ZXhfdW5sb2Nr KCZwcml2LT5sb2NrKTsKPj4+ICsKPj4+ICvCoMKgwqAgbWFwLT5mbGFncyB8PSBHTlRNQVBfaG9z dF9tYXA7Cj4+PiArI2lmIGRlZmluZWQoQ09ORklHX1g4NikKPj4+ICvCoMKgwqAgbWFwLT5mbGFn cyB8PSBHTlRNQVBfZGV2aWNlX21hcDsKPj4+ICsjZW5kaWYKPj4+ICsKPj4+ICvCoMKgwqAgcmV0 ID0gbWFwX2dyYW50X3BhZ2VzKG1hcCk7Cj4+PiArwqDCoMKgIGlmIChyZXQgPCAwKQo+Pj4gK8Kg wqDCoMKgwqDCoMKgIGdvdG8gb3V0Owo+Pj4gKwo+Pj4gK8KgwqDCoCByZXQgPSBkbWFidWZfZXhw b3J0KHByaXYsIG1hcCwgZmQpOwo+Pj4gK8KgwqDCoCBpZiAocmV0IDwgMCkKPj4+ICvCoMKgwqDC oMKgwqDCoCBnb3RvIG91dDsKPj4+ICsKPj4+ICvCoMKgwqAgcmV0dXJuIDA7Cj4+PiArCj4+PiAr b3V0Ogo+Pj4gK8KgwqDCoCBnbnRkZXZfcmVtb3ZlX21hcChwcml2LCBtYXApOwo+Pj4gK8KgwqDC oCByZXR1cm4gcmV0Owo+Pj4gwqAgfQo+Pj4gwqAgwqAgLyogCj4+PiAtLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi8KPj4+ IC0tIAo+Pj4gMi4xNy4wCj4+Pgo+CgpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f X19fX19fX19fX19fXwpkcmktZGV2ZWwgbWFpbGluZyBsaXN0CmRyaS1kZXZlbEBsaXN0cy5mcmVl ZGVza3RvcC5vcmcKaHR0cHM6Ly9saXN0cy5mcmVlZGVza3RvcC5vcmcvbWFpbG1hbi9saXN0aW5m by9kcmktZGV2ZWwK