From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.3 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,NICE_REPLY_A,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_SANE_1 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7BD09C07E96 for ; Tue, 6 Jul 2021 22:41:50 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 349FA61CA7 for ; Tue, 6 Jul 2021 22:41:48 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 349FA61CA7 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 9100C89E98; Tue, 6 Jul 2021 22:41:45 +0000 (UTC) Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by gabe.freedesktop.org (Postfix) with ESMTPS id AAE7D89444; Tue, 6 Jul 2021 22:41:43 +0000 (UTC) X-IronPort-AV: E=McAfee;i="6200,9189,10037"; a="209162670" X-IronPort-AV: E=Sophos;i="5.83,329,1616482800"; d="scan'208";a="209162670" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Jul 2021 15:41:42 -0700 X-IronPort-AV: E=Sophos;i="5.83,329,1616482800"; d="scan'208";a="457233989" Received: from johnharr-mobl1.amr.corp.intel.com (HELO [10.212.151.177]) ([10.212.151.177]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Jul 2021 15:41:42 -0700 Subject: Re: [PATCH 6/7] drm/i915/guc: Optimize CTB writes and reads To: Michal Wajdeczko , Matthew Brost , intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org References: <20210701171550.49353-1-matthew.brost@intel.com> <20210701171550.49353-7-matthew.brost@intel.com> <3147114d-4b4b-1a42-c40b-8d8be870e633@intel.com> From: John Harrison Message-ID: Date: Tue, 6 Jul 2021 15:41:41 -0700 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Thunderbird/78.11.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit Content-Language: en-GB X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" On 7/6/2021 12:33, Michal Wajdeczko wrote: > On 06.07.2021 21:19, John Harrison wrote: >> On 7/6/2021 12:12, Michal Wajdeczko wrote: >>> On 06.07.2021 21:00, John Harrison wrote: >>>> On 7/1/2021 10:15, Matthew Brost wrote: >>>>> CTB writes are now in the path of command submission and should be >>>>> optimized for performance. Rather than reading CTB descriptor values >>>>> (e.g. head, tail) which could result in accesses across the PCIe bus, >>>>> store shadow local copies and only read/write the descriptor values >>>>> when >>>>> absolutely necessary. Also store the current space in the each channel >>>>> locally. >>>>> >>>>> v2: >>>>>    (Michel) >>>>>     - Add additional sanity checks for head / tail pointers >>>>>     - Use GUC_CTB_HDR_LEN rather than magic 1 >>>>> >>>>> Signed-off-by: John Harrison >>>>> Signed-off-by: Matthew Brost >>>>> --- >>>>>    drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c | 88 >>>>> +++++++++++++++-------- >>>>>    drivers/gpu/drm/i915/gt/uc/intel_guc_ct.h |  6 ++ >>>>>    2 files changed, 65 insertions(+), 29 deletions(-) >>>>> >>>>> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c >>>>> b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c >>>>> index a9cb7b608520..5b8b4ff609e2 100644 >>>>> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c >>>>> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c >>>>> @@ -130,6 +130,10 @@ static void guc_ct_buffer_desc_init(struct >>>>> guc_ct_buffer_desc *desc) >>>>>    static void guc_ct_buffer_reset(struct intel_guc_ct_buffer *ctb) >>>>>    { >>>>>        ctb->broken = false; >>>>> +    ctb->tail = 0; >>>>> +    ctb->head = 0; >>>>> +    ctb->space = CIRC_SPACE(ctb->tail, ctb->head, ctb->size); >>>>> + >>>>>        guc_ct_buffer_desc_init(ctb->desc); >>>>>    } >>>>>    @@ -383,10 +387,8 @@ static int ct_write(struct intel_guc_ct *ct, >>>>>    { >>>>>        struct intel_guc_ct_buffer *ctb = &ct->ctbs.send; >>>>>        struct guc_ct_buffer_desc *desc = ctb->desc; >>>>> -    u32 head = desc->head; >>>>> -    u32 tail = desc->tail; >>>>> +    u32 tail = ctb->tail; >>>>>        u32 size = ctb->size; >>>>> -    u32 used; >>>>>        u32 header; >>>>>        u32 hxg; >>>>>        u32 *cmds = ctb->cmds; >>>>> @@ -395,25 +397,22 @@ static int ct_write(struct intel_guc_ct *ct, >>>>>        if (unlikely(desc->status)) >>>>>            goto corrupted; >>>>>    -    if (unlikely((tail | head) >= size)) { >>>>> +    GEM_BUG_ON(tail > size); >>>>> + >>>>> +#ifdef CONFIG_DRM_I915_DEBUG_GUC >>>>> +    if (unlikely(tail != READ_ONCE(desc->tail))) { >>>>> +        CT_ERROR(ct, "Tail was modified %u != %u\n", >>>>> +             desc->tail, ctb->tail); >>>>> +        desc->status |= GUC_CTB_STATUS_MISMATCH; >>>>> +        goto corrupted; >>>>> +    } >>>>> +    if (unlikely((desc->tail | desc->head) >= size)) { >>>>>            CT_ERROR(ct, "Invalid offsets head=%u tail=%u (size=%u)\n", >>>>> -             head, tail, size); >>>>> +             desc->head, desc->tail, size); >>>>>            desc->status |= GUC_CTB_STATUS_OVERFLOW; >>>>>            goto corrupted; >>>>>        } >>>>> - >>>>> -    /* >>>>> -     * tail == head condition indicates empty. GuC FW does not support >>>>> -     * using up the entire buffer to get tail == head meaning full. >>>>> -     */ >>>>> -    if (tail < head) >>>>> -        used = (size - head) + tail; >>>>> -    else >>>>> -        used = tail - head; >>>>> - >>>>> -    /* make sure there is a space including extra dw for the fence */ >>>>> -    if (unlikely(used + len + GUC_CTB_HDR_LEN >= size)) >>>>> -        return -ENOSPC; >>>>> +#endif >>>>>          /* >>>>>         * dw0: CT header (including fence) >>>>> @@ -454,7 +453,9 @@ static int ct_write(struct intel_guc_ct *ct, >>>>>        write_barrier(ct); >>>>>          /* now update descriptor */ >>>>> +    ctb->tail = tail; >>>>>        WRITE_ONCE(desc->tail, tail); >>>>> +    ctb->space -= len + GUC_CTB_HDR_LEN; >>>>>          return 0; >>>>>    @@ -470,7 +471,7 @@ static int ct_write(struct intel_guc_ct *ct, >>>>>     * @req:    pointer to pending request >>>>>     * @status:    placeholder for status >>>>>     * >>>>> - * For each sent request, Guc shall send bac CT response message. >>>>> + * For each sent request, GuC shall send back CT response message. >>>>>     * Our message handler will update status of tracked request once >>>>>     * response message with given fence is received. Wait here and >>>>>     * check for valid response status value. >>>>> @@ -526,24 +527,35 @@ static inline bool ct_deadlocked(struct >>>>> intel_guc_ct *ct) >>>>>        return ret; >>>>>    } >>>>>    -static inline bool h2g_has_room(struct intel_guc_ct_buffer *ctb, >>>>> u32 len_dw) >>>>> +static inline bool h2g_has_room(struct intel_guc_ct *ct, u32 len_dw) >>>>>    { >>>>> -    struct guc_ct_buffer_desc *desc = ctb->desc; >>>>> -    u32 head = READ_ONCE(desc->head); >>>>> +    struct intel_guc_ct_buffer *ctb = &ct->ctbs.send; >>>>> +    u32 head; >>>>>        u32 space; >>>>>    -    space = CIRC_SPACE(desc->tail, head, ctb->size); >>>>> +    if (ctb->space >= len_dw) >>>>> +        return true; >>>>> + >>>>> +    head = READ_ONCE(ctb->desc->head); >>>>> +    if (unlikely(head > ctb->size)) { >>>>> +        CT_ERROR(ct, "Corrupted descriptor head=%u tail=%u size=%u\n", >>>>> +             ctb->desc->head, ctb->desc->tail, ctb->size); >>>>> +        ctb->desc->status |= GUC_CTB_STATUS_OVERFLOW; >>>>> +        ctb->broken = true; >>>>> +        return false; >>>>> +    } >>>>> + >>>>> +    space = CIRC_SPACE(ctb->tail, head, ctb->size); >>>>> +    ctb->space = space; >>>>>          return space >= len_dw; >>>>>    } >>>>>      static int has_room_nb(struct intel_guc_ct *ct, u32 len_dw) >>>>>    { >>>>> -    struct intel_guc_ct_buffer *ctb = &ct->ctbs.send; >>>>> - >>>>>        lockdep_assert_held(&ct->ctbs.send.lock); >>>>>    -    if (unlikely(!h2g_has_room(ctb, len_dw))) { >>>>> +    if (unlikely(!h2g_has_room(ct, len_dw))) { >>>>>            if (ct->stall_time == KTIME_MAX) >>>>>                ct->stall_time = ktime_get(); >>>>>    @@ -613,7 +625,7 @@ static int ct_send(struct intel_guc_ct *ct, >>>>>         */ >>>>>    retry: >>>>>        spin_lock_irqsave(&ctb->lock, flags); >>>>> -    if (unlikely(!h2g_has_room(ctb, len + GUC_CTB_HDR_LEN))) { >>>>> +    if (unlikely(!h2g_has_room(ct, len + GUC_CTB_HDR_LEN))) { >>>>>            if (ct->stall_time == KTIME_MAX) >>>>>                ct->stall_time = ktime_get(); >>>>>            spin_unlock_irqrestore(&ctb->lock, flags); >>>>> @@ -733,7 +745,7 @@ static int ct_read(struct intel_guc_ct *ct, struct >>>>> ct_incoming_msg **msg) >>>>>    { >>>>>        struct intel_guc_ct_buffer *ctb = &ct->ctbs.recv; >>>>>        struct guc_ct_buffer_desc *desc = ctb->desc; >>>>> -    u32 head = desc->head; >>>>> +    u32 head = ctb->head; >>>>>        u32 tail = desc->tail; >>>>>        u32 size = ctb->size; >>>>>        u32 *cmds = ctb->cmds; >>>>> @@ -748,12 +760,29 @@ static int ct_read(struct intel_guc_ct *ct, >>>>> struct ct_incoming_msg **msg) >>>>>        if (unlikely(desc->status)) >>>>>            goto corrupted; >>>>>    -    if (unlikely((tail | head) >= size)) { >>>>> +    GEM_BUG_ON(head > size); >>>> Is the BUG_ON necessary given that both options below do the same check >>>> but as a corrupted buffer test (with subsequent recovery by GT reset?) >>>> rather than killing the driver. >>> "head" and "size" are now fully owned by the driver. >>> BUGON here is to make sure driver is coded correctly. >> The point is that both sides of the #if below also validate head. So > but not the same "head" It is from the point of view of is the BUG_ON redundant duplication: +    if (unlikely(head != READ_ONCE(desc->head))) { > > under DEBUG we are validating the one from descriptor (together with > tail) - and that should be recoverable as if this fails it was clearly > not our fault. > > but under non-DEBUG we were attempting to validate again the local one, > pretending that this is recoverable, but it is not, as this is our fault > (elsewhere in i915 we don't attempt to recover from obvious coding errors). If it happens during driver development when someone is editing code then it might be an obvious coding error. If it happens once in a blue moon on some customer's system then it is a very hard to track down race condition that is totally not obvious at all. The former won't make it past CI whether it is a BUG_ON or a CT_ERROR. The latter has just killed the end user's kernel rather than attempted to recover (and would have been likely to succeed the recovery). John. > >> first there is a BUG_ON, then there is the same test but without blowing >> the driver apart. One or the other is not required. My vote would be to >> keep the recoverable test rather than the BUG_ON. > IMHO we should keep GEMBUGON and drop redundant check in non-DEBUG. > > But let Matt decide. > > Michal > >> John. >> >>>>> + >>>>> +#ifdef CONFIG_DRM_I915_DEBUG_GUC >>>>> +    if (unlikely(head != READ_ONCE(desc->head))) { >>>>> +        CT_ERROR(ct, "Head was modified %u != %u\n", >>>>> +             desc->head, ctb->head); >>>>> +        desc->status |= GUC_CTB_STATUS_MISMATCH; >>>>> +        goto corrupted; >>>>> +    } >>>>> +    if (unlikely((desc->tail | desc->head) >= size)) { >>>>> +        CT_ERROR(ct, "Invalid offsets head=%u tail=%u (size=%u)\n", >>>>> +             head, tail, size); >>>>> +        desc->status |= GUC_CTB_STATUS_OVERFLOW; >>>>> +        goto corrupted; >>>>> +    } >>>>> +#else >>>>> +    if (unlikely((tail | ctb->head) >= size)) { >>>> Could just be 'head' rather than 'ctb->head'. >>> or drop "ctb->head" completely since this is driver owned field and >>> above you already have BUGON to test it >>> >>> Michal >>> >>>> John. >>>> >>>>>            CT_ERROR(ct, "Invalid offsets head=%u tail=%u (size=%u)\n", >>>>>                 head, tail, size); >>>>>            desc->status |= GUC_CTB_STATUS_OVERFLOW; >>>>>            goto corrupted; >>>>>        } >>>>> +#endif >>>>>          /* tail == head condition indicates empty */ >>>>>        available = tail - head; >>>>> @@ -803,6 +832,7 @@ static int ct_read(struct intel_guc_ct *ct, struct >>>>> ct_incoming_msg **msg) >>>>>        } >>>>>        CT_DEBUG(ct, "received %*ph\n", 4 * len, (*msg)->msg); >>>>>    +    ctb->head = head; >>>>>        /* now update descriptor */ >>>>>        WRITE_ONCE(desc->head, head); >>>>>    diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.h >>>>> b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.h >>>>> index bee03794c1eb..edd1bba0445d 100644 >>>>> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.h >>>>> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.h >>>>> @@ -33,6 +33,9 @@ struct intel_guc; >>>>>     * @desc: pointer to the buffer descriptor >>>>>     * @cmds: pointer to the commands buffer >>>>>     * @size: size of the commands buffer in dwords >>>>> + * @head: local shadow copy of head in dwords >>>>> + * @tail: local shadow copy of tail in dwords >>>>> + * @space: local shadow copy of space in dwords >>>>>     * @broken: flag to indicate if descriptor data is broken >>>>>     */ >>>>>    struct intel_guc_ct_buffer { >>>>> @@ -40,6 +43,9 @@ struct intel_guc_ct_buffer { >>>>>        struct guc_ct_buffer_desc *desc; >>>>>        u32 *cmds; >>>>>        u32 size; >>>>> +    u32 tail; >>>>> +    u32 head; >>>>> +    u32 space; >>>>>        bool broken; >>>>>    }; >>>>> From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.3 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,NICE_REPLY_A,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_SANE_1 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 124D4C07E96 for ; Tue, 6 Jul 2021 22:41:46 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7162B61CA8 for ; Tue, 6 Jul 2021 22:41:45 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 7162B61CA8 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 1901789444; Tue, 6 Jul 2021 22:41:45 +0000 (UTC) Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by gabe.freedesktop.org (Postfix) with ESMTPS id AAE7D89444; Tue, 6 Jul 2021 22:41:43 +0000 (UTC) X-IronPort-AV: E=McAfee;i="6200,9189,10037"; a="209162670" X-IronPort-AV: E=Sophos;i="5.83,329,1616482800"; d="scan'208";a="209162670" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Jul 2021 15:41:42 -0700 X-IronPort-AV: E=Sophos;i="5.83,329,1616482800"; d="scan'208";a="457233989" Received: from johnharr-mobl1.amr.corp.intel.com (HELO [10.212.151.177]) ([10.212.151.177]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Jul 2021 15:41:42 -0700 To: Michal Wajdeczko , Matthew Brost , intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org References: <20210701171550.49353-1-matthew.brost@intel.com> <20210701171550.49353-7-matthew.brost@intel.com> <3147114d-4b4b-1a42-c40b-8d8be870e633@intel.com> From: John Harrison Message-ID: Date: Tue, 6 Jul 2021 15:41:41 -0700 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Thunderbird/78.11.0 MIME-Version: 1.0 In-Reply-To: Content-Language: en-GB Subject: Re: [Intel-gfx] [PATCH 6/7] drm/i915/guc: Optimize CTB writes and reads X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Transfer-Encoding: base64 Content-Type: text/plain; charset="utf-8"; Format="flowed" Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" T24gNy82LzIwMjEgMTI6MzMsIE1pY2hhbCBXYWpkZWN6a28gd3JvdGU6Cj4gT24gMDYuMDcuMjAy MSAyMToxOSwgSm9obiBIYXJyaXNvbiB3cm90ZToKPj4gT24gNy82LzIwMjEgMTI6MTIsIE1pY2hh bCBXYWpkZWN6a28gd3JvdGU6Cj4+PiBPbiAwNi4wNy4yMDIxIDIxOjAwLCBKb2huIEhhcnJpc29u IHdyb3RlOgo+Pj4+IE9uIDcvMS8yMDIxIDEwOjE1LCBNYXR0aGV3IEJyb3N0IHdyb3RlOgo+Pj4+ PiBDVEIgd3JpdGVzIGFyZSBub3cgaW4gdGhlIHBhdGggb2YgY29tbWFuZCBzdWJtaXNzaW9uIGFu ZCBzaG91bGQgYmUKPj4+Pj4gb3B0aW1pemVkIGZvciBwZXJmb3JtYW5jZS4gUmF0aGVyIHRoYW4g cmVhZGluZyBDVEIgZGVzY3JpcHRvciB2YWx1ZXMKPj4+Pj4gKGUuZy4gaGVhZCwgdGFpbCkgd2hp Y2ggY291bGQgcmVzdWx0IGluIGFjY2Vzc2VzIGFjcm9zcyB0aGUgUENJZSBidXMsCj4+Pj4+IHN0 b3JlIHNoYWRvdyBsb2NhbCBjb3BpZXMgYW5kIG9ubHkgcmVhZC93cml0ZSB0aGUgZGVzY3JpcHRv ciB2YWx1ZXMKPj4+Pj4gd2hlbgo+Pj4+PiBhYnNvbHV0ZWx5IG5lY2Vzc2FyeS4gQWxzbyBzdG9y ZSB0aGUgY3VycmVudCBzcGFjZSBpbiB0aGUgZWFjaCBjaGFubmVsCj4+Pj4+IGxvY2FsbHkuCj4+ Pj4+Cj4+Pj4+IHYyOgo+Pj4+PiAgwqDCoCAoTWljaGVsKQo+Pj4+PiAgwqDCoMKgIC0gQWRkIGFk ZGl0aW9uYWwgc2FuaXR5IGNoZWNrcyBmb3IgaGVhZCAvIHRhaWwgcG9pbnRlcnMKPj4+Pj4gIMKg wqDCoCAtIFVzZSBHVUNfQ1RCX0hEUl9MRU4gcmF0aGVyIHRoYW4gbWFnaWMgMQo+Pj4+Pgo+Pj4+ PiBTaWduZWQtb2ZmLWJ5OiBKb2huIEhhcnJpc29uIDxKb2huLkMuSGFycmlzb25ASW50ZWwuY29t Pgo+Pj4+PiBTaWduZWQtb2ZmLWJ5OiBNYXR0aGV3IEJyb3N0IDxtYXR0aGV3LmJyb3N0QGludGVs LmNvbT4KPj4+Pj4gLS0tCj4+Pj4+ICDCoMKgIGRyaXZlcnMvZ3B1L2RybS9pOTE1L2d0L3VjL2lu dGVsX2d1Y19jdC5jIHwgODgKPj4+Pj4gKysrKysrKysrKysrKysrLS0tLS0tLS0KPj4+Pj4gIMKg wqAgZHJpdmVycy9ncHUvZHJtL2k5MTUvZ3QvdWMvaW50ZWxfZ3VjX2N0LmggfMKgIDYgKysKPj4+ Pj4gIMKgwqAgMiBmaWxlcyBjaGFuZ2VkLCA2NSBpbnNlcnRpb25zKCspLCAyOSBkZWxldGlvbnMo LSkKPj4+Pj4KPj4+Pj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvZ3B1L2RybS9pOTE1L2d0L3VjL2lu dGVsX2d1Y19jdC5jCj4+Pj4+IGIvZHJpdmVycy9ncHUvZHJtL2k5MTUvZ3QvdWMvaW50ZWxfZ3Vj X2N0LmMKPj4+Pj4gaW5kZXggYTljYjdiNjA4NTIwLi41YjhiNGZmNjA5ZTIgMTAwNjQ0Cj4+Pj4+ IC0tLSBhL2RyaXZlcnMvZ3B1L2RybS9pOTE1L2d0L3VjL2ludGVsX2d1Y19jdC5jCj4+Pj4+ICsr KyBiL2RyaXZlcnMvZ3B1L2RybS9pOTE1L2d0L3VjL2ludGVsX2d1Y19jdC5jCj4+Pj4+IEBAIC0x MzAsNiArMTMwLDEwIEBAIHN0YXRpYyB2b2lkIGd1Y19jdF9idWZmZXJfZGVzY19pbml0KHN0cnVj dAo+Pj4+PiBndWNfY3RfYnVmZmVyX2Rlc2MgKmRlc2MpCj4+Pj4+ICDCoMKgIHN0YXRpYyB2b2lk IGd1Y19jdF9idWZmZXJfcmVzZXQoc3RydWN0IGludGVsX2d1Y19jdF9idWZmZXIgKmN0YikKPj4+ Pj4gIMKgwqAgewo+Pj4+PiAgwqDCoMKgwqDCoMKgIGN0Yi0+YnJva2VuID0gZmFsc2U7Cj4+Pj4+ ICvCoMKgwqAgY3RiLT50YWlsID0gMDsKPj4+Pj4gK8KgwqDCoCBjdGItPmhlYWQgPSAwOwo+Pj4+ PiArwqDCoMKgIGN0Yi0+c3BhY2UgPSBDSVJDX1NQQUNFKGN0Yi0+dGFpbCwgY3RiLT5oZWFkLCBj dGItPnNpemUpOwo+Pj4+PiArCj4+Pj4+ICDCoMKgwqDCoMKgwqAgZ3VjX2N0X2J1ZmZlcl9kZXNj X2luaXQoY3RiLT5kZXNjKTsKPj4+Pj4gIMKgwqAgfQo+Pj4+PiAgwqDCoCBAQCAtMzgzLDEwICsz ODcsOCBAQCBzdGF0aWMgaW50IGN0X3dyaXRlKHN0cnVjdCBpbnRlbF9ndWNfY3QgKmN0LAo+Pj4+ PiAgwqDCoCB7Cj4+Pj4+ICDCoMKgwqDCoMKgwqAgc3RydWN0IGludGVsX2d1Y19jdF9idWZmZXIg KmN0YiA9ICZjdC0+Y3Ricy5zZW5kOwo+Pj4+PiAgwqDCoMKgwqDCoMKgIHN0cnVjdCBndWNfY3Rf YnVmZmVyX2Rlc2MgKmRlc2MgPSBjdGItPmRlc2M7Cj4+Pj4+IC3CoMKgwqAgdTMyIGhlYWQgPSBk ZXNjLT5oZWFkOwo+Pj4+PiAtwqDCoMKgIHUzMiB0YWlsID0gZGVzYy0+dGFpbDsKPj4+Pj4gK8Kg wqDCoCB1MzIgdGFpbCA9IGN0Yi0+dGFpbDsKPj4+Pj4gIMKgwqDCoMKgwqDCoCB1MzIgc2l6ZSA9 IGN0Yi0+c2l6ZTsKPj4+Pj4gLcKgwqDCoCB1MzIgdXNlZDsKPj4+Pj4gIMKgwqDCoMKgwqDCoCB1 MzIgaGVhZGVyOwo+Pj4+PiAgwqDCoMKgwqDCoMKgIHUzMiBoeGc7Cj4+Pj4+ICDCoMKgwqDCoMKg wqAgdTMyICpjbWRzID0gY3RiLT5jbWRzOwo+Pj4+PiBAQCAtMzk1LDI1ICszOTcsMjIgQEAgc3Rh dGljIGludCBjdF93cml0ZShzdHJ1Y3QgaW50ZWxfZ3VjX2N0ICpjdCwKPj4+Pj4gIMKgwqDCoMKg wqDCoCBpZiAodW5saWtlbHkoZGVzYy0+c3RhdHVzKSkKPj4+Pj4gIMKgwqDCoMKgwqDCoMKgwqDC oMKgIGdvdG8gY29ycnVwdGVkOwo+Pj4+PiAgwqDCoCAtwqDCoMKgIGlmICh1bmxpa2VseSgodGFp bCB8IGhlYWQpID49IHNpemUpKSB7Cj4+Pj4+ICvCoMKgwqAgR0VNX0JVR19PTih0YWlsID4gc2l6 ZSk7Cj4+Pj4+ICsKPj4+Pj4gKyNpZmRlZiBDT05GSUdfRFJNX0k5MTVfREVCVUdfR1VDCj4+Pj4+ ICvCoMKgwqAgaWYgKHVubGlrZWx5KHRhaWwgIT0gUkVBRF9PTkNFKGRlc2MtPnRhaWwpKSkgewo+ Pj4+PiArwqDCoMKgwqDCoMKgwqAgQ1RfRVJST1IoY3QsICJUYWlsIHdhcyBtb2RpZmllZCAldSAh PSAldVxuIiwKPj4+Pj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBkZXNjLT50YWlsLCBjdGIt PnRhaWwpOwo+Pj4+PiArwqDCoMKgwqDCoMKgwqAgZGVzYy0+c3RhdHVzIHw9IEdVQ19DVEJfU1RB VFVTX01JU01BVENIOwo+Pj4+PiArwqDCoMKgwqDCoMKgwqAgZ290byBjb3JydXB0ZWQ7Cj4+Pj4+ ICvCoMKgwqAgfQo+Pj4+PiArwqDCoMKgIGlmICh1bmxpa2VseSgoZGVzYy0+dGFpbCB8IGRlc2Mt PmhlYWQpID49IHNpemUpKSB7Cj4+Pj4+ICDCoMKgwqDCoMKgwqDCoMKgwqDCoCBDVF9FUlJPUihj dCwgIkludmFsaWQgb2Zmc2V0cyBoZWFkPSV1IHRhaWw9JXUgKHNpemU9JXUpXG4iLAo+Pj4+PiAt wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGhlYWQsIHRhaWwsIHNpemUpOwo+Pj4+PiArwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgIGRlc2MtPmhlYWQsIGRlc2MtPnRhaWwsIHNpemUpOwo+Pj4+PiAg wqDCoMKgwqDCoMKgwqDCoMKgwqAgZGVzYy0+c3RhdHVzIHw9IEdVQ19DVEJfU1RBVFVTX09WRVJG TE9XOwo+Pj4+PiAgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZ290byBjb3JydXB0ZWQ7Cj4+Pj4+ICDC oMKgwqDCoMKgwqAgfQo+Pj4+PiAtCj4+Pj4+IC3CoMKgwqAgLyoKPj4+Pj4gLcKgwqDCoMKgICog dGFpbCA9PSBoZWFkIGNvbmRpdGlvbiBpbmRpY2F0ZXMgZW1wdHkuIEd1QyBGVyBkb2VzIG5vdCBz dXBwb3J0Cj4+Pj4+IC3CoMKgwqDCoCAqIHVzaW5nIHVwIHRoZSBlbnRpcmUgYnVmZmVyIHRvIGdl dCB0YWlsID09IGhlYWQgbWVhbmluZyBmdWxsLgo+Pj4+PiAtwqDCoMKgwqAgKi8KPj4+Pj4gLcKg wqDCoCBpZiAodGFpbCA8IGhlYWQpCj4+Pj4+IC3CoMKgwqDCoMKgwqDCoCB1c2VkID0gKHNpemUg LSBoZWFkKSArIHRhaWw7Cj4+Pj4+IC3CoMKgwqAgZWxzZQo+Pj4+PiAtwqDCoMKgwqDCoMKgwqAg dXNlZCA9IHRhaWwgLSBoZWFkOwo+Pj4+PiAtCj4+Pj4+IC3CoMKgwqAgLyogbWFrZSBzdXJlIHRo ZXJlIGlzIGEgc3BhY2UgaW5jbHVkaW5nIGV4dHJhIGR3IGZvciB0aGUgZmVuY2UgKi8KPj4+Pj4g LcKgwqDCoCBpZiAodW5saWtlbHkodXNlZCArIGxlbiArIEdVQ19DVEJfSERSX0xFTiA+PSBzaXpl KSkKPj4+Pj4gLcKgwqDCoMKgwqDCoMKgIHJldHVybiAtRU5PU1BDOwo+Pj4+PiArI2VuZGlmCj4+ Pj4+ICDCoMKgIMKgwqDCoMKgwqAgLyoKPj4+Pj4gIMKgwqDCoMKgwqDCoMKgICogZHcwOiBDVCBo ZWFkZXIgKGluY2x1ZGluZyBmZW5jZSkKPj4+Pj4gQEAgLTQ1NCw3ICs0NTMsOSBAQCBzdGF0aWMg aW50IGN0X3dyaXRlKHN0cnVjdCBpbnRlbF9ndWNfY3QgKmN0LAo+Pj4+PiAgwqDCoMKgwqDCoMKg IHdyaXRlX2JhcnJpZXIoY3QpOwo+Pj4+PiAgwqDCoCDCoMKgwqDCoMKgIC8qIG5vdyB1cGRhdGUg ZGVzY3JpcHRvciAqLwo+Pj4+PiArwqDCoMKgIGN0Yi0+dGFpbCA9IHRhaWw7Cj4+Pj4+ICDCoMKg wqDCoMKgwqAgV1JJVEVfT05DRShkZXNjLT50YWlsLCB0YWlsKTsKPj4+Pj4gK8KgwqDCoCBjdGIt PnNwYWNlIC09IGxlbiArIEdVQ19DVEJfSERSX0xFTjsKPj4+Pj4gIMKgwqAgwqDCoMKgwqDCoCBy ZXR1cm4gMDsKPj4+Pj4gIMKgwqAgQEAgLTQ3MCw3ICs0NzEsNyBAQCBzdGF0aWMgaW50IGN0X3dy aXRlKHN0cnVjdCBpbnRlbF9ndWNfY3QgKmN0LAo+Pj4+PiAgwqDCoMKgICogQHJlcTrCoMKgwqAg cG9pbnRlciB0byBwZW5kaW5nIHJlcXVlc3QKPj4+Pj4gIMKgwqDCoCAqIEBzdGF0dXM6wqDCoMKg IHBsYWNlaG9sZGVyIGZvciBzdGF0dXMKPj4+Pj4gIMKgwqDCoCAqCj4+Pj4+IC0gKiBGb3IgZWFj aCBzZW50IHJlcXVlc3QsIEd1YyBzaGFsbCBzZW5kIGJhYyBDVCByZXNwb25zZSBtZXNzYWdlLgo+ Pj4+PiArICogRm9yIGVhY2ggc2VudCByZXF1ZXN0LCBHdUMgc2hhbGwgc2VuZCBiYWNrIENUIHJl c3BvbnNlIG1lc3NhZ2UuCj4+Pj4+ICDCoMKgwqAgKiBPdXIgbWVzc2FnZSBoYW5kbGVyIHdpbGwg dXBkYXRlIHN0YXR1cyBvZiB0cmFja2VkIHJlcXVlc3Qgb25jZQo+Pj4+PiAgwqDCoMKgICogcmVz cG9uc2UgbWVzc2FnZSB3aXRoIGdpdmVuIGZlbmNlIGlzIHJlY2VpdmVkLiBXYWl0IGhlcmUgYW5k Cj4+Pj4+ICDCoMKgwqAgKiBjaGVjayBmb3IgdmFsaWQgcmVzcG9uc2Ugc3RhdHVzIHZhbHVlLgo+ Pj4+PiBAQCAtNTI2LDI0ICs1MjcsMzUgQEAgc3RhdGljIGlubGluZSBib29sIGN0X2RlYWRsb2Nr ZWQoc3RydWN0Cj4+Pj4+IGludGVsX2d1Y19jdCAqY3QpCj4+Pj4+ICDCoMKgwqDCoMKgwqAgcmV0 dXJuIHJldDsKPj4+Pj4gIMKgwqAgfQo+Pj4+PiAgwqDCoCAtc3RhdGljIGlubGluZSBib29sIGgy Z19oYXNfcm9vbShzdHJ1Y3QgaW50ZWxfZ3VjX2N0X2J1ZmZlciAqY3RiLAo+Pj4+PiB1MzIgbGVu X2R3KQo+Pj4+PiArc3RhdGljIGlubGluZSBib29sIGgyZ19oYXNfcm9vbShzdHJ1Y3QgaW50ZWxf Z3VjX2N0ICpjdCwgdTMyIGxlbl9kdykKPj4+Pj4gIMKgwqAgewo+Pj4+PiAtwqDCoMKgIHN0cnVj dCBndWNfY3RfYnVmZmVyX2Rlc2MgKmRlc2MgPSBjdGItPmRlc2M7Cj4+Pj4+IC3CoMKgwqAgdTMy IGhlYWQgPSBSRUFEX09OQ0UoZGVzYy0+aGVhZCk7Cj4+Pj4+ICvCoMKgwqAgc3RydWN0IGludGVs X2d1Y19jdF9idWZmZXIgKmN0YiA9ICZjdC0+Y3Ricy5zZW5kOwo+Pj4+PiArwqDCoMKgIHUzMiBo ZWFkOwo+Pj4+PiAgwqDCoMKgwqDCoMKgIHUzMiBzcGFjZTsKPj4+Pj4gIMKgwqAgLcKgwqDCoCBz cGFjZSA9IENJUkNfU1BBQ0UoZGVzYy0+dGFpbCwgaGVhZCwgY3RiLT5zaXplKTsKPj4+Pj4gK8Kg wqDCoCBpZiAoY3RiLT5zcGFjZSA+PSBsZW5fZHcpCj4+Pj4+ICvCoMKgwqDCoMKgwqDCoCByZXR1 cm4gdHJ1ZTsKPj4+Pj4gKwo+Pj4+PiArwqDCoMKgIGhlYWQgPSBSRUFEX09OQ0UoY3RiLT5kZXNj LT5oZWFkKTsKPj4+Pj4gK8KgwqDCoCBpZiAodW5saWtlbHkoaGVhZCA+IGN0Yi0+c2l6ZSkpIHsK Pj4+Pj4gK8KgwqDCoMKgwqDCoMKgIENUX0VSUk9SKGN0LCAiQ29ycnVwdGVkIGRlc2NyaXB0b3Ig aGVhZD0ldSB0YWlsPSV1IHNpemU9JXVcbiIsCj4+Pj4+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqAgY3RiLT5kZXNjLT5oZWFkLCBjdGItPmRlc2MtPnRhaWwsIGN0Yi0+c2l6ZSk7Cj4+Pj4+ICvC oMKgwqDCoMKgwqDCoCBjdGItPmRlc2MtPnN0YXR1cyB8PSBHVUNfQ1RCX1NUQVRVU19PVkVSRkxP VzsKPj4+Pj4gK8KgwqDCoMKgwqDCoMKgIGN0Yi0+YnJva2VuID0gdHJ1ZTsKPj4+Pj4gK8KgwqDC oMKgwqDCoMKgIHJldHVybiBmYWxzZTsKPj4+Pj4gK8KgwqDCoCB9Cj4+Pj4+ICsKPj4+Pj4gK8Kg wqDCoCBzcGFjZSA9IENJUkNfU1BBQ0UoY3RiLT50YWlsLCBoZWFkLCBjdGItPnNpemUpOwo+Pj4+ PiArwqDCoMKgIGN0Yi0+c3BhY2UgPSBzcGFjZTsKPj4+Pj4gIMKgwqAgwqDCoMKgwqDCoCByZXR1 cm4gc3BhY2UgPj0gbGVuX2R3Owo+Pj4+PiAgwqDCoCB9Cj4+Pj4+ICDCoMKgIMKgIHN0YXRpYyBp bnQgaGFzX3Jvb21fbmIoc3RydWN0IGludGVsX2d1Y19jdCAqY3QsIHUzMiBsZW5fZHcpCj4+Pj4+ ICDCoMKgIHsKPj4+Pj4gLcKgwqDCoCBzdHJ1Y3QgaW50ZWxfZ3VjX2N0X2J1ZmZlciAqY3RiID0g JmN0LT5jdGJzLnNlbmQ7Cj4+Pj4+IC0KPj4+Pj4gIMKgwqDCoMKgwqDCoCBsb2NrZGVwX2Fzc2Vy dF9oZWxkKCZjdC0+Y3Ricy5zZW5kLmxvY2spOwo+Pj4+PiAgwqDCoCAtwqDCoMKgIGlmICh1bmxp a2VseSghaDJnX2hhc19yb29tKGN0YiwgbGVuX2R3KSkpIHsKPj4+Pj4gK8KgwqDCoCBpZiAodW5s aWtlbHkoIWgyZ19oYXNfcm9vbShjdCwgbGVuX2R3KSkpIHsKPj4+Pj4gIMKgwqDCoMKgwqDCoMKg wqDCoMKgIGlmIChjdC0+c3RhbGxfdGltZSA9PSBLVElNRV9NQVgpCj4+Pj4+ICDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgIGN0LT5zdGFsbF90aW1lID0ga3RpbWVfZ2V0KCk7Cj4+Pj4+ICDC oMKgIEBAIC02MTMsNyArNjI1LDcgQEAgc3RhdGljIGludCBjdF9zZW5kKHN0cnVjdCBpbnRlbF9n dWNfY3QgKmN0LAo+Pj4+PiAgwqDCoMKgwqDCoMKgwqAgKi8KPj4+Pj4gIMKgwqAgcmV0cnk6Cj4+ Pj4+ICDCoMKgwqDCoMKgwqAgc3Bpbl9sb2NrX2lycXNhdmUoJmN0Yi0+bG9jaywgZmxhZ3MpOwo+ Pj4+PiAtwqDCoMKgIGlmICh1bmxpa2VseSghaDJnX2hhc19yb29tKGN0YiwgbGVuICsgR1VDX0NU Ql9IRFJfTEVOKSkpIHsKPj4+Pj4gK8KgwqDCoCBpZiAodW5saWtlbHkoIWgyZ19oYXNfcm9vbShj dCwgbGVuICsgR1VDX0NUQl9IRFJfTEVOKSkpIHsKPj4+Pj4gIMKgwqDCoMKgwqDCoMKgwqDCoMKg IGlmIChjdC0+c3RhbGxfdGltZSA9PSBLVElNRV9NQVgpCj4+Pj4+ICDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgIGN0LT5zdGFsbF90aW1lID0ga3RpbWVfZ2V0KCk7Cj4+Pj4+ICDCoMKgwqDC oMKgwqDCoMKgwqDCoCBzcGluX3VubG9ja19pcnFyZXN0b3JlKCZjdGItPmxvY2ssIGZsYWdzKTsK Pj4+Pj4gQEAgLTczMyw3ICs3NDUsNyBAQCBzdGF0aWMgaW50IGN0X3JlYWQoc3RydWN0IGludGVs X2d1Y19jdCAqY3QsIHN0cnVjdAo+Pj4+PiBjdF9pbmNvbWluZ19tc2cgKiptc2cpCj4+Pj4+ICDC oMKgIHsKPj4+Pj4gIMKgwqDCoMKgwqDCoCBzdHJ1Y3QgaW50ZWxfZ3VjX2N0X2J1ZmZlciAqY3Ri ID0gJmN0LT5jdGJzLnJlY3Y7Cj4+Pj4+ICDCoMKgwqDCoMKgwqAgc3RydWN0IGd1Y19jdF9idWZm ZXJfZGVzYyAqZGVzYyA9IGN0Yi0+ZGVzYzsKPj4+Pj4gLcKgwqDCoCB1MzIgaGVhZCA9IGRlc2Mt PmhlYWQ7Cj4+Pj4+ICvCoMKgwqAgdTMyIGhlYWQgPSBjdGItPmhlYWQ7Cj4+Pj4+ICDCoMKgwqDC oMKgwqAgdTMyIHRhaWwgPSBkZXNjLT50YWlsOwo+Pj4+PiAgwqDCoMKgwqDCoMKgIHUzMiBzaXpl ID0gY3RiLT5zaXplOwo+Pj4+PiAgwqDCoMKgwqDCoMKgIHUzMiAqY21kcyA9IGN0Yi0+Y21kczsK Pj4+Pj4gQEAgLTc0OCwxMiArNzYwLDI5IEBAIHN0YXRpYyBpbnQgY3RfcmVhZChzdHJ1Y3QgaW50 ZWxfZ3VjX2N0ICpjdCwKPj4+Pj4gc3RydWN0IGN0X2luY29taW5nX21zZyAqKm1zZykKPj4+Pj4g IMKgwqDCoMKgwqDCoCBpZiAodW5saWtlbHkoZGVzYy0+c3RhdHVzKSkKPj4+Pj4gIMKgwqDCoMKg wqDCoMKgwqDCoMKgIGdvdG8gY29ycnVwdGVkOwo+Pj4+PiAgwqDCoCAtwqDCoMKgIGlmICh1bmxp a2VseSgodGFpbCB8IGhlYWQpID49IHNpemUpKSB7Cj4+Pj4+ICvCoMKgwqAgR0VNX0JVR19PTiho ZWFkID4gc2l6ZSk7Cj4+Pj4gSXMgdGhlIEJVR19PTiBuZWNlc3NhcnkgZ2l2ZW4gdGhhdCBib3Ro IG9wdGlvbnMgYmVsb3cgZG8gdGhlIHNhbWUgY2hlY2sKPj4+PiBidXQgYXMgYSBjb3JydXB0ZWQg YnVmZmVyIHRlc3QgKHdpdGggc3Vic2VxdWVudCByZWNvdmVyeSBieSBHVCByZXNldD8pCj4+Pj4g cmF0aGVyIHRoYW4ga2lsbGluZyB0aGUgZHJpdmVyLgo+Pj4gImhlYWQiIGFuZCAic2l6ZSIgYXJl IG5vdyBmdWxseSBvd25lZCBieSB0aGUgZHJpdmVyLgo+Pj4gQlVHT04gaGVyZSBpcyB0byBtYWtl IHN1cmUgZHJpdmVyIGlzIGNvZGVkIGNvcnJlY3RseS4KPj4gVGhlIHBvaW50IGlzIHRoYXQgYm90 aCBzaWRlcyBvZiB0aGUgI2lmIGJlbG93IGFsc28gdmFsaWRhdGUgaGVhZC4gU28KPiBidXQgbm90 IHRoZSBzYW1lICJoZWFkIgpJdCBpcyBmcm9tIHRoZSBwb2ludCBvZiB2aWV3IG9mIGlzIHRoZSBC VUdfT04gcmVkdW5kYW50IGR1cGxpY2F0aW9uOgoKK8KgwqDCoCBpZiAodW5saWtlbHkoaGVhZCAh PSBSRUFEX09OQ0UoZGVzYy0+aGVhZCkpKSB7CgoKCj4KPiB1bmRlciBERUJVRyB3ZSBhcmUgdmFs aWRhdGluZyB0aGUgb25lIGZyb20gZGVzY3JpcHRvciAodG9nZXRoZXIgd2l0aAo+IHRhaWwpIC0g YW5kIHRoYXQgc2hvdWxkIGJlIHJlY292ZXJhYmxlIGFzIGlmIHRoaXMgZmFpbHMgaXQgd2FzIGNs ZWFybHkKPiBub3Qgb3VyIGZhdWx0Lgo+Cj4gYnV0IHVuZGVyIG5vbi1ERUJVRyB3ZSB3ZXJlIGF0 dGVtcHRpbmcgdG8gdmFsaWRhdGUgYWdhaW4gdGhlIGxvY2FsIG9uZSwKPiBwcmV0ZW5kaW5nIHRo YXQgdGhpcyBpcyByZWNvdmVyYWJsZSwgYnV0IGl0IGlzIG5vdCwgYXMgdGhpcyBpcyBvdXIgZmF1 bHQKPiAoZWxzZXdoZXJlIGluIGk5MTUgd2UgZG9uJ3QgYXR0ZW1wdCB0byByZWNvdmVyIGZyb20g b2J2aW91cyBjb2RpbmcgZXJyb3JzKS4KSWYgaXQgaGFwcGVucyBkdXJpbmcgZHJpdmVyIGRldmVs b3BtZW50IHdoZW4gc29tZW9uZSBpcyBlZGl0aW5nIGNvZGUgCnRoZW4gaXQgbWlnaHQgYmUgYW4g b2J2aW91cyBjb2RpbmcgZXJyb3IuIElmIGl0IGhhcHBlbnMgb25jZSBpbiBhIGJsdWUgCm1vb24g b24gc29tZSBjdXN0b21lcidzIHN5c3RlbSB0aGVuIGl0IGlzIGEgdmVyeSBoYXJkIHRvIHRyYWNr IGRvd24gcmFjZSAKY29uZGl0aW9uIHRoYXQgaXMgdG90YWxseSBub3Qgb2J2aW91cyBhdCBhbGwu IFRoZSBmb3JtZXIgd29uJ3QgbWFrZSBpdCAKcGFzdCBDSSB3aGV0aGVyIGl0IGlzIGEgQlVHX09O IG9yIGEgQ1RfRVJST1IuIFRoZSBsYXR0ZXIgaGFzIGp1c3Qga2lsbGVkIAp0aGUgZW5kIHVzZXIn cyBrZXJuZWwgcmF0aGVyIHRoYW4gYXR0ZW1wdGVkIHRvIHJlY292ZXIgKGFuZCB3b3VsZCBoYXZl IApiZWVuIGxpa2VseSB0byBzdWNjZWVkIHRoZSByZWNvdmVyeSkuCgpKb2huLgoKPgo+PiBmaXJz dCB0aGVyZSBpcyBhIEJVR19PTiwgdGhlbiB0aGVyZSBpcyB0aGUgc2FtZSB0ZXN0IGJ1dCB3aXRo b3V0IGJsb3dpbmcKPj4gdGhlIGRyaXZlciBhcGFydC4gT25lIG9yIHRoZSBvdGhlciBpcyBub3Qg cmVxdWlyZWQuIE15IHZvdGUgd291bGQgYmUgdG8KPj4ga2VlcCB0aGUgcmVjb3ZlcmFibGUgdGVz dCByYXRoZXIgdGhhbiB0aGUgQlVHX09OLgo+IElNSE8gd2Ugc2hvdWxkIGtlZXAgR0VNQlVHT04g YW5kIGRyb3AgcmVkdW5kYW50IGNoZWNrIGluIG5vbi1ERUJVRy4KPgo+IEJ1dCBsZXQgTWF0dCBk ZWNpZGUuCj4KPiBNaWNoYWwKPgo+PiBKb2huLgo+Pgo+Pj4+PiArCj4+Pj4+ICsjaWZkZWYgQ09O RklHX0RSTV9JOTE1X0RFQlVHX0dVQwo+Pj4+PiArwqDCoMKgIGlmICh1bmxpa2VseShoZWFkICE9 IFJFQURfT05DRShkZXNjLT5oZWFkKSkpIHsKPj4+Pj4gK8KgwqDCoMKgwqDCoMKgIENUX0VSUk9S KGN0LCAiSGVhZCB3YXMgbW9kaWZpZWQgJXUgIT0gJXVcbiIsCj4+Pj4+ICvCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqAgZGVzYy0+aGVhZCwgY3RiLT5oZWFkKTsKPj4+Pj4gK8KgwqDCoMKgwqDCoMKg IGRlc2MtPnN0YXR1cyB8PSBHVUNfQ1RCX1NUQVRVU19NSVNNQVRDSDsKPj4+Pj4gK8KgwqDCoMKg wqDCoMKgIGdvdG8gY29ycnVwdGVkOwo+Pj4+PiArwqDCoMKgIH0KPj4+Pj4gK8KgwqDCoCBpZiAo dW5saWtlbHkoKGRlc2MtPnRhaWwgfCBkZXNjLT5oZWFkKSA+PSBzaXplKSkgewo+Pj4+PiArwqDC oMKgwqDCoMKgwqAgQ1RfRVJST1IoY3QsICJJbnZhbGlkIG9mZnNldHMgaGVhZD0ldSB0YWlsPSV1 IChzaXplPSV1KVxuIiwKPj4+Pj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBoZWFkLCB0YWls LCBzaXplKTsKPj4+Pj4gK8KgwqDCoMKgwqDCoMKgIGRlc2MtPnN0YXR1cyB8PSBHVUNfQ1RCX1NU QVRVU19PVkVSRkxPVzsKPj4+Pj4gK8KgwqDCoMKgwqDCoMKgIGdvdG8gY29ycnVwdGVkOwo+Pj4+ PiArwqDCoMKgIH0KPj4+Pj4gKyNlbHNlCj4+Pj4+ICvCoMKgwqAgaWYgKHVubGlrZWx5KCh0YWls IHwgY3RiLT5oZWFkKSA+PSBzaXplKSkgewo+Pj4+IENvdWxkIGp1c3QgYmUgJ2hlYWQnIHJhdGhl ciB0aGFuICdjdGItPmhlYWQnLgo+Pj4gb3IgZHJvcCAiY3RiLT5oZWFkIiBjb21wbGV0ZWx5IHNp bmNlIHRoaXMgaXMgZHJpdmVyIG93bmVkIGZpZWxkIGFuZAo+Pj4gYWJvdmUgeW91IGFscmVhZHkg aGF2ZSBCVUdPTiB0byB0ZXN0IGl0Cj4+Pgo+Pj4gTWljaGFsCj4+Pgo+Pj4+IEpvaG4uCj4+Pj4K Pj4+Pj4gIMKgwqDCoMKgwqDCoMKgwqDCoMKgIENUX0VSUk9SKGN0LCAiSW52YWxpZCBvZmZzZXRz IGhlYWQ9JXUgdGFpbD0ldSAoc2l6ZT0ldSlcbiIsCj4+Pj4+ICDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqAgaGVhZCwgdGFpbCwgc2l6ZSk7Cj4+Pj4+ICDCoMKgwqDCoMKgwqDCoMKgwqDC oCBkZXNjLT5zdGF0dXMgfD0gR1VDX0NUQl9TVEFUVVNfT1ZFUkZMT1c7Cj4+Pj4+ICDCoMKgwqDC oMKgwqDCoMKgwqDCoCBnb3RvIGNvcnJ1cHRlZDsKPj4+Pj4gIMKgwqDCoMKgwqDCoCB9Cj4+Pj4+ ICsjZW5kaWYKPj4+Pj4gIMKgwqAgwqDCoMKgwqDCoCAvKiB0YWlsID09IGhlYWQgY29uZGl0aW9u IGluZGljYXRlcyBlbXB0eSAqLwo+Pj4+PiAgwqDCoMKgwqDCoMKgIGF2YWlsYWJsZSA9IHRhaWwg LSBoZWFkOwo+Pj4+PiBAQCAtODAzLDYgKzgzMiw3IEBAIHN0YXRpYyBpbnQgY3RfcmVhZChzdHJ1 Y3QgaW50ZWxfZ3VjX2N0ICpjdCwgc3RydWN0Cj4+Pj4+IGN0X2luY29taW5nX21zZyAqKm1zZykK Pj4+Pj4gIMKgwqDCoMKgwqDCoCB9Cj4+Pj4+ICDCoMKgwqDCoMKgwqAgQ1RfREVCVUcoY3QsICJy ZWNlaXZlZCAlKnBoXG4iLCA0ICogbGVuLCAoKm1zZyktPm1zZyk7Cj4+Pj4+ICDCoMKgICvCoMKg wqAgY3RiLT5oZWFkID0gaGVhZDsKPj4+Pj4gIMKgwqDCoMKgwqDCoCAvKiBub3cgdXBkYXRlIGRl c2NyaXB0b3IgKi8KPj4+Pj4gIMKgwqDCoMKgwqDCoCBXUklURV9PTkNFKGRlc2MtPmhlYWQsIGhl YWQpOwo+Pj4+PiAgwqDCoCBkaWZmIC0tZ2l0IGEvZHJpdmVycy9ncHUvZHJtL2k5MTUvZ3QvdWMv aW50ZWxfZ3VjX2N0LmgKPj4+Pj4gYi9kcml2ZXJzL2dwdS9kcm0vaTkxNS9ndC91Yy9pbnRlbF9n dWNfY3QuaAo+Pj4+PiBpbmRleCBiZWUwMzc5NGMxZWIuLmVkZDFiYmEwNDQ1ZCAxMDA2NDQKPj4+ Pj4gLS0tIGEvZHJpdmVycy9ncHUvZHJtL2k5MTUvZ3QvdWMvaW50ZWxfZ3VjX2N0LmgKPj4+Pj4g KysrIGIvZHJpdmVycy9ncHUvZHJtL2k5MTUvZ3QvdWMvaW50ZWxfZ3VjX2N0LmgKPj4+Pj4gQEAg LTMzLDYgKzMzLDkgQEAgc3RydWN0IGludGVsX2d1YzsKPj4+Pj4gIMKgwqDCoCAqIEBkZXNjOiBw b2ludGVyIHRvIHRoZSBidWZmZXIgZGVzY3JpcHRvcgo+Pj4+PiAgwqDCoMKgICogQGNtZHM6IHBv aW50ZXIgdG8gdGhlIGNvbW1hbmRzIGJ1ZmZlcgo+Pj4+PiAgwqDCoMKgICogQHNpemU6IHNpemUg b2YgdGhlIGNvbW1hbmRzIGJ1ZmZlciBpbiBkd29yZHMKPj4+Pj4gKyAqIEBoZWFkOiBsb2NhbCBz aGFkb3cgY29weSBvZiBoZWFkIGluIGR3b3Jkcwo+Pj4+PiArICogQHRhaWw6IGxvY2FsIHNoYWRv dyBjb3B5IG9mIHRhaWwgaW4gZHdvcmRzCj4+Pj4+ICsgKiBAc3BhY2U6IGxvY2FsIHNoYWRvdyBj b3B5IG9mIHNwYWNlIGluIGR3b3Jkcwo+Pj4+PiAgwqDCoMKgICogQGJyb2tlbjogZmxhZyB0byBp bmRpY2F0ZSBpZiBkZXNjcmlwdG9yIGRhdGEgaXMgYnJva2VuCj4+Pj4+ICDCoMKgwqAgKi8KPj4+ Pj4gIMKgwqAgc3RydWN0IGludGVsX2d1Y19jdF9idWZmZXIgewo+Pj4+PiBAQCAtNDAsNiArNDMs OSBAQCBzdHJ1Y3QgaW50ZWxfZ3VjX2N0X2J1ZmZlciB7Cj4+Pj4+ICDCoMKgwqDCoMKgwqAgc3Ry dWN0IGd1Y19jdF9idWZmZXJfZGVzYyAqZGVzYzsKPj4+Pj4gIMKgwqDCoMKgwqDCoCB1MzIgKmNt ZHM7Cj4+Pj4+ICDCoMKgwqDCoMKgwqAgdTMyIHNpemU7Cj4+Pj4+ICvCoMKgwqAgdTMyIHRhaWw7 Cj4+Pj4+ICvCoMKgwqAgdTMyIGhlYWQ7Cj4+Pj4+ICvCoMKgwqAgdTMyIHNwYWNlOwo+Pj4+PiAg wqDCoMKgwqDCoMKgIGJvb2wgYnJva2VuOwo+Pj4+PiAgwqDCoCB9Owo+Pj4+PiAgICAgCgpfX19f X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXwpJbnRlbC1nZnggbWFp bGluZyBsaXN0CkludGVsLWdmeEBsaXN0cy5mcmVlZGVza3RvcC5vcmcKaHR0cHM6Ly9saXN0cy5m cmVlZGVza3RvcC5vcmcvbWFpbG1hbi9saXN0aW5mby9pbnRlbC1nZngK