Received: by 2002:a05:6a10:5bc5:0:0:0:0 with SMTP id os5csp669345pxb; Thu, 21 Oct 2021 07:17:47 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzVPnUeXb8tHvtmS/Ipu1luGbw+gGq8tt0tUIILq3c7GO7yVgI+lq0Uy4LoEN85V0+zxfxQ X-Received: by 2002:a63:6a49:: with SMTP id f70mr4636355pgc.199.1634825867244; Thu, 21 Oct 2021 07:17:47 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1634825867; cv=none; d=google.com; s=arc-20160816; b=c5EySgE800cnkO4ptoQ0bj4mqQCdHOrXjPuEB7ZTac3afvYti4DmRrjlQmxUdTAKBM 1mjScCdhcYaipKN9pyyNttIV2PvJ+A4uzG6FfqVx0uredsSulN0BqiCxOVKSWYekGyiW YccMDEmpvWcU+0+Z28c0l7hU8k/ntddyXAR/qxqnywwJ+PF4IEelNarGUZGRcN4qlkdo fubZL6sx1j4zinXOu4VoPWbVJFaHTHqFdqcM1Un9VhroP15MV2TbRKxUrjUFkvJa+zLI ZSpN/vIRSxMSB2gzJC4ybcV3MiXJjvBzUOOkTh4ImgSulUDIXC25g/Nm+pkfikWejljw CjaQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:content-language :in-reply-to:mime-version:user-agent:date:message-id:subject:from :references:cc:to; bh=spusgsHdW4MycqljHjzL3Ss/DyOPnkouAeyd4ew6fuU=; b=aDp9Akoi4HC+KghRTZypN6cTUIuxcDWzA5dBYJj6hRi0sRqcbLGrIr1Ez99P47lrZX YVAetgo1SBJwIVZYP5mWYJ7E2gYbSj3on6kU2Q+T2hU6lPxcUyIlCWOFR60NLlgrhgbN sFyIp9MPlV6mFLYqoSedrPh22u+Gz41mMzIuhkRIAb33CUNU/Q1+zhmufCGMCdFUBv45 H4aOH1eEK65l1AFRLPCvyLQ0z7VdcssFgXuTC7BHWA++Ro4A9mtDZZsksKZDvw+CojFI xINivI2eaWaCdlj6l0kNj+g5lo6QRjI9uLoi2DGua8QiDzdkqrhCipxzxbwJBkgh9xSr bwLg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id l18si9342038plh.50.2021.10.21.07.17.33; Thu, 21 Oct 2021 07:17:47 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230072AbhJUORm (ORCPT + 99 others); Thu, 21 Oct 2021 10:17:42 -0400 Received: from vps-vb.mhejs.net ([37.28.154.113]:34064 "EHLO vps-vb.mhejs.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231206AbhJUORl (ORCPT ); Thu, 21 Oct 2021 10:17:41 -0400 Received: from MUA by vps-vb.mhejs.net with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1mdYqj-0004tH-RZ; Thu, 21 Oct 2021 16:15:17 +0200 To: Sean Christopherson Cc: Paolo Bonzini , Vitaly Kuznetsov , Wanpeng Li , Jim Mattson , Igor Mammedov , Marc Zyngier , James Morse , Julien Thierry , Suzuki K Poulose , Huacai Chen , Aleksandar Markovic , Paul Mackerras , Christian Borntraeger , Janosch Frank , David Hildenbrand , Cornelia Huck , Claudio Imbrenda , Joerg Roedel , kvm@vger.kernel.org, linux-kernel@vger.kernel.org References: <555f58fdaec120aa7a6f6fbad06cca796a8c9168.1632171479.git.maciej.szmigiero@oracle.com> From: "Maciej S. Szmigiero" Subject: Re: [PATCH v5 08/13] KVM: Resolve memslot ID via a hash table instead of via a static array Message-ID: <139bdb6e-4f75-5f16-ae88-094709a6c42b@maciej.szmigiero.name> Date: Thu, 21 Oct 2021 16:15:12 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.13.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 21.10.2021 00:39, Sean Christopherson wrote: > On Mon, Sep 20, 2021, Maciej S. Szmigiero wrote: >> @@ -1251,12 +1251,13 @@ static inline void kvm_memslot_delete(struct kvm_memslots *slots, >> if (atomic_read(&slots->last_used_slot) >= slots->used_slots) >> atomic_set(&slots->last_used_slot, 0); >> >> - for (i = slots->id_to_index[memslot->id]; i < slots->used_slots; i++) { >> + for (i = oldslot - mslots; i < slots->used_slots; i++) { >> + hash_del(&mslots[i].id_node); >> mslots[i] = mslots[i + 1]; >> - slots->id_to_index[mslots[i].id] = i; >> + hash_add(slots->id_hash, &mslots[i].id_node, mslots[i].id); >> } >> + hash_del(&mslots[i].id_node); >> mslots[i] = *memslot; >> - slots->id_to_index[memslot->id] = -1; > > Aha! This code has been bugging and I finally figured out why. Fundamentally, > this is identical to kvm_memslot_move_backward(), the only difference being that > the _backward() variant has a second "stop" condition. > > But yet this is subtly different in the hash manipulations because performs the > final node deletion (which is a random node, that may not be the target node!) Technically, it's not truly "random" node that's deleted since it's simply the one belonging to the last slot in the old array (which slot will now be moved to the second to last position in the array). But I get your overall point here. > outside of the loop, whereas _backward() deletes the target node before the loop. > > I like the _backward() variant a lot more. And if this code is converted to that > approach, i.e. > > for (i = oldslot - mslots; i < slots->used_slots; i++) { > hash_del(&mslots[i + 1].id_node); > mslots[i] = mslots[i + 1]; > hash_add(slots->id_hash, &mslots[i].id_node, mslots[i].id); > } > > then all three loops fit a similar pattern and we can extract the node craziness > into a helper. I know this mostly goes away in the end, but I think/hope it will > make the future patches easier to follow this there's only ever one "replace" > helper. > > For convenience, with the s/mmemslot/oldslot and comment changes. The change in this patch was supposed to be minimally-invasive (since it's getting replaced by patch 11 anyway), but since you have already refactored it then I will update the patch with your proposed change. Thanks, Maciej > --- > virt/kvm/kvm_main.c | 63 ++++++++++++++++++++++++++------------------- > 1 file changed, 37 insertions(+), 26 deletions(-) > > diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c > index 50597608d085..6f5298bc7710 100644 > --- a/virt/kvm/kvm_main.c > +++ b/virt/kvm/kvm_main.c > @@ -1231,6 +1231,23 @@ static int kvm_alloc_dirty_bitmap(struct kvm_memory_slot *memslot) > return 0; > } > > +static void kvm_memslot_replace(struct kvm_memslots *slots, int dst, int src) > +{ > + struct kvm_memory_slot *mslots = slots->memslots; > + > + /* > + * Remove the source from the hash list, copying the hlist_node data > + * would corrupt the list. > + */ > + hash_del(&mslots[src].id_node); > + > + /* Copy the source *data*, not the pointer, to the destination. */ > + mslots[dst] = mslots[src]; > + > + /* Re-add the memslot to the list using the destination's node. */ > + hash_add(slots->id_hash, &mslots[dst].id_node, mslots[dst].id); > +} > + > /* > * Delete a memslot by decrementing the number of used slots and shifting all > * other entries in the array forward one spot. > @@ -1251,12 +1268,16 @@ static inline void kvm_memslot_delete(struct kvm_memslots *slots, > if (atomic_read(&slots->last_used_slot) >= slots->used_slots) > atomic_set(&slots->last_used_slot, 0); > > - for (i = oldslot - mslots; i < slots->used_slots; i++) { > - hash_del(&mslots[i].id_node); > - mslots[i] = mslots[i + 1]; > - hash_add(slots->id_hash, &mslots[i].id_node, mslots[i].id); > - } > - hash_del(&mslots[i].id_node); > + /* > + * Remove the to-be-deleted memslot from the list _before_ shifting > + * the trailing memslots forward, its data will be overwritten. > + * Defer the (somewhat pointless) copying of the memslot until after > + * the last slot has been shifted to avoid overwriting said last slot. > + */ > + hash_del(&oldslot->id_node); > + > + for (i = oldslot - mslots; i < slots->used_slots; i++) > + kvm_memslot_replace(slots, i, i + 1); > mslots[i] = *memslot; > } > > @@ -1282,39 +1303,32 @@ static inline int kvm_memslot_move_backward(struct kvm_memslots *slots, > struct kvm_memory_slot *memslot) > { > struct kvm_memory_slot *mslots = slots->memslots; > - struct kvm_memory_slot *mmemslot = id_to_memslot(slots, memslot->id); > + struct kvm_memory_slot *oldslot = id_to_memslot(slots, memslot->id); > int i; > > - if (!mmemslot || !slots->used_slots) > + if (!oldslot || !slots->used_slots) > return -1; > > /* > - * The loop below will (possibly) overwrite the target memslot with > - * data of the next memslot, or a similar loop in > - * kvm_memslot_move_forward() will overwrite it with data of the > - * previous memslot. > - * Then update_memslots() will unconditionally overwrite and re-add > - * it to the hash table. > - * That's why the memslot has to be first removed from the hash table > - * here. > + * Delete the slot from the hash table before sorting the remaining > + * slots, the slot's data may be overwritten when copying slots as part > + * of the sorting proccess. update_memslots() will unconditionally > + * rewrite the entire slot and re-add it to the hash table. > */ > - hash_del(&mmemslot->id_node); > + hash_del(&oldslot->id_node); > > /* > * Move the target memslot backward in the array by shifting existing > * memslots with a higher GFN (than the target memslot) towards the > * front of the array. > */ > - for (i = mmemslot - mslots; i < slots->used_slots - 1; i++) { > + for (i = oldslot - mslots; i < slots->used_slots - 1; i++) { > if (memslot->base_gfn > mslots[i + 1].base_gfn) > break; > > WARN_ON_ONCE(memslot->base_gfn == mslots[i + 1].base_gfn); > > - /* Shift the next memslot forward one and update its index. */ > - hash_del(&mslots[i + 1].id_node); > - mslots[i] = mslots[i + 1]; > - hash_add(slots->id_hash, &mslots[i].id_node, mslots[i].id); > + kvm_memslot_replace(slots, i, i + 1); > } > return i; > } > @@ -1343,10 +1357,7 @@ static inline int kvm_memslot_move_forward(struct kvm_memslots *slots, > > WARN_ON_ONCE(memslot->base_gfn == mslots[i - 1].base_gfn); > > - /* Shift the next memslot back one and update its index. */ > - hash_del(&mslots[i - 1].id_node); > - mslots[i] = mslots[i - 1]; > - hash_add(slots->id_hash, &mslots[i].id_node, mslots[i].id); > + kvm_memslot_replace(slots, i, i - 1); > } > return i; > } > -- >