From patchwork Fri Sep 9 10:44:58 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Emanuele Giuseppe Esposito X-Patchwork-Id: 12971490 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 267CEECAAD3 for ; Fri, 9 Sep 2022 10:45:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231238AbiIIKp0 (ORCPT ); Fri, 9 Sep 2022 06:45:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40078 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231148AbiIIKpS (ORCPT ); Fri, 9 Sep 2022 06:45:18 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 603DF41983 for ; Fri, 9 Sep 2022 03:45:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1662720314; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=5USZdofT3b7rr0YzPxgVn0M8YXPxXCyJIOd7HvwaYnU=; b=Iaodoauu/qntVzYUZmQkXu5bAGEtV1pSZQ39SJy6H7fkh7lYcnlJHXe1gx3NjUaVtJQ+5d 2ju/eQZwryDlGxcbylM1Q4PR72mq2t82RBDOJG/pN1hsA5nx/Zrwy9Fs4n3ofbTjJ2m49c U+p47aqI0fqnDZbE9RGLGfE340z1cmk= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-537-3yjYgqGqN4ePcQJ31JTu2w-1; Fri, 09 Sep 2022 06:45:10 -0400 X-MC-Unique: 3yjYgqGqN4ePcQJ31JTu2w-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id A3A09811E81; Fri, 9 Sep 2022 10:45:09 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4111F40D282E; Fri, 9 Sep 2022 10:45:09 +0000 (UTC) From: Emanuele Giuseppe Esposito To: kvm@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Vitaly Kuznetsov , Wanpeng Li , Jim Mattson , Joerg Roedel , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , David Hildenbrand , Maxim Levitsky , x86@kernel.org, "H. Peter Anvin" , linux-kernel@vger.kernel.org, Emanuele Giuseppe Esposito Subject: [RFC PATCH 1/9] kvm_main.c: move slot check in kvm_set_memory_region Date: Fri, 9 Sep 2022 06:44:58 -0400 Message-Id: <20220909104506.738478-2-eesposit@redhat.com> In-Reply-To: <20220909104506.738478-1-eesposit@redhat.com> References: <20220909104506.738478-1-eesposit@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.11.54.2 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org And make kvm_set_memory_region static, since it is not used outside kvm_main.c Signed-off-by: Emanuele Giuseppe Esposito --- include/linux/kvm_host.h | 2 -- virt/kvm/kvm_main.c | 11 +++++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 3b40f8d68fbb..1c5b7b2e35dd 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1108,8 +1108,6 @@ enum kvm_mr_change { KVM_MR_FLAGS_ONLY, }; -int kvm_set_memory_region(struct kvm *kvm, - const struct kvm_userspace_memory_region *mem); int __kvm_set_memory_region(struct kvm *kvm, const struct kvm_userspace_memory_region *mem); void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index da263c370d00..339de0ed4557 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2007,24 +2007,23 @@ int __kvm_set_memory_region(struct kvm *kvm, } EXPORT_SYMBOL_GPL(__kvm_set_memory_region); -int kvm_set_memory_region(struct kvm *kvm, - const struct kvm_userspace_memory_region *mem) +static int kvm_set_memory_region(struct kvm *kvm, + const struct kvm_userspace_memory_region *mem) { int r; + if ((u16)mem->slot >= KVM_USER_MEM_SLOTS) + return -EINVAL; + mutex_lock(&kvm->slots_lock); r = __kvm_set_memory_region(kvm, mem); mutex_unlock(&kvm->slots_lock); return r; } -EXPORT_SYMBOL_GPL(kvm_set_memory_region); static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem) { - if ((u16)mem->slot >= KVM_USER_MEM_SLOTS) - return -EINVAL; - return kvm_set_memory_region(kvm, mem); } From patchwork Fri Sep 9 10:44:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Emanuele Giuseppe Esposito X-Patchwork-Id: 12971492 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 881E0ECAAD3 for ; Fri, 9 Sep 2022 10:45:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231137AbiIIKpb (ORCPT ); Fri, 9 Sep 2022 06:45:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40164 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231168AbiIIKpT (ORCPT ); Fri, 9 Sep 2022 06:45:19 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A812E4F67B for ; Fri, 9 Sep 2022 03:45:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1662720316; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=sP4vjAy5dPb317LaSVOvXhYqCo8CTxm9lVTHh2Rs0Uk=; b=HQD1xFk6ubBsMaPjOUGbs9OWMM7atEg7TWm+rX6X4hLnUntOYBmQofXpwiPnjtn5oq7lTO 9+pxThslmdNlfSYBt0QqFck36ZGpASuOibPm3+SzJLUuzHMFyg/nPwpB4w/TBnIcmJHKWg pW76E9xerJdDI7GESgh5AewgmpWtSug= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-592-LRY8QVp1N3GagGCz9l-VOQ-1; Fri, 09 Sep 2022 06:45:10 -0400 X-MC-Unique: LRY8QVp1N3GagGCz9l-VOQ-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 1BA451C05AE6; Fri, 9 Sep 2022 10:45:10 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id AC63140D282E; Fri, 9 Sep 2022 10:45:09 +0000 (UTC) From: Emanuele Giuseppe Esposito To: kvm@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Vitaly Kuznetsov , Wanpeng Li , Jim Mattson , Joerg Roedel , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , David Hildenbrand , Maxim Levitsky , x86@kernel.org, "H. Peter Anvin" , linux-kernel@vger.kernel.org, Emanuele Giuseppe Esposito Subject: [RFC PATCH 2/9] kvm.h: introduce KVM_SET_USER_MEMORY_REGION_LIST ioctl Date: Fri, 9 Sep 2022 06:44:59 -0400 Message-Id: <20220909104506.738478-3-eesposit@redhat.com> In-Reply-To: <20220909104506.738478-1-eesposit@redhat.com> References: <20220909104506.738478-1-eesposit@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.11.54.2 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org This IOCTL enables atomic update of multiple memslots. The userspace application provides a kvm_userspace_memory_region_list containing a list of entries, each representing a modification to be performed to a memslot. Requests with invalidate_slot == 1 are pre-processed, because they are ther DELETE or MOVE, and therefore the memslot must be first replaced with a copy marked as KVM_MEMSLOT_INVALID, and then replaced. Signed-off-by: Emanuele Giuseppe Esposito --- include/uapi/linux/kvm.h | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index a36e78710382..673496b91a25 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -103,6 +103,24 @@ struct kvm_userspace_memory_region { __u64 userspace_addr; /* start of the userspace allocated memory */ }; +/* for KVM_SET_USER_MEMORY_REGION_LIST */ +struct kvm_userspace_memory_region_entry { + __u32 slot; + __u32 flags; + __u64 guest_phys_addr; + __u64 memory_size; /* bytes */ + __u64 userspace_addr; /* start of the userspace allocated memory */ + __u8 invalidate_slot; + __u8 padding[31]; +}; + +/* for KVM_SET_USER_MEMORY_REGION_LIST */ +struct kvm_userspace_memory_region_list { + __u32 nent; + __u32 flags; + struct kvm_userspace_memory_region_entry entries[0]; +}; + /* * The bit 0 ~ bit 15 of kvm_memory_region::flags are visible for userspace, * other bits are reserved for kvm internal use which are defined in @@ -1444,7 +1462,8 @@ struct kvm_vfio_spapr_tce { struct kvm_userspace_memory_region) #define KVM_SET_TSS_ADDR _IO(KVMIO, 0x47) #define KVM_SET_IDENTITY_MAP_ADDR _IOW(KVMIO, 0x48, __u64) - +#define KVM_SET_USER_MEMORY_REGION_LIST _IOW(KVMIO, 0x49, \ + struct kvm_userspace_memory_region_list) /* enable ucontrol for s390 */ struct kvm_s390_ucas_mapping { __u64 user_addr; From patchwork Fri Sep 9 10:45:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Emanuele Giuseppe Esposito X-Patchwork-Id: 12971489 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3CD1FC6FA82 for ; Fri, 9 Sep 2022 10:45:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229765AbiIIKpY (ORCPT ); Fri, 9 Sep 2022 06:45:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39930 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231137AbiIIKpR (ORCPT ); Fri, 9 Sep 2022 06:45:17 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E72764C620 for ; Fri, 9 Sep 2022 03:45:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1662720314; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=E7/IU2R6um6C8tfOW4fXuw4iFHpygm2D4d5AJXUUCVc=; b=DoGW1O/qcc6RH4Exo1sJqHN3p00WLkegSbcy6Kg5LnKpHX0RIoa1soQp5t/cc2Avg+EOQB k11OR616BSDps9t9wYKgDwRpJ5t5GE5tPh3kND/l02EoCNmglHBOlj2pDLTva8CQja+C0R 9Wu8Oj72kh8zNMhdfoBzpsimRoCYbTA= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-62-tBzAaOcGPbmx8yJxhzsLMg-1; Fri, 09 Sep 2022 06:45:11 -0400 X-MC-Unique: tBzAaOcGPbmx8yJxhzsLMg-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 8D91A80029D; Fri, 9 Sep 2022 10:45:10 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2548D40D282E; Fri, 9 Sep 2022 10:45:10 +0000 (UTC) From: Emanuele Giuseppe Esposito To: kvm@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Vitaly Kuznetsov , Wanpeng Li , Jim Mattson , Joerg Roedel , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , David Hildenbrand , Maxim Levitsky , x86@kernel.org, "H. Peter Anvin" , linux-kernel@vger.kernel.org, Emanuele Giuseppe Esposito Subject: [RFC PATCH 3/9] kvm_main.c: introduce kvm_internal_memory_region_list Date: Fri, 9 Sep 2022 06:45:00 -0400 Message-Id: <20220909104506.738478-4-eesposit@redhat.com> In-Reply-To: <20220909104506.738478-1-eesposit@redhat.com> References: <20220909104506.738478-1-eesposit@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.11.54.2 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org For now this struct is only used to pass new,old and change variable in a single parameter instead of three. In future, it will be used to also carry additional information and handle atomic memslot updates. Signed-off-by: Emanuele Giuseppe Esposito --- arch/x86/kvm/x86.c | 3 ++- include/linux/kvm_host.h | 15 +++++++++++- virt/kvm/kvm_main.c | 52 +++++++++++++++++++++++++++------------- 3 files changed, 51 insertions(+), 19 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 567d13405445..da5a5dd3d4bf 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -12155,13 +12155,14 @@ void __user * __x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa, for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) { struct kvm_userspace_memory_region m; + struct kvm_internal_memory_region_list b = { 0 }; m.slot = id | (i << 16); m.flags = 0; m.guest_phys_addr = gpa; m.userspace_addr = hva; m.memory_size = size; - r = __kvm_set_memory_region(kvm, &m); + r = __kvm_set_memory_region(kvm, &m, &b); if (r < 0) return ERR_PTR_USR(r); } diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 1c5b7b2e35dd..69af94472b39 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1108,8 +1108,21 @@ enum kvm_mr_change { KVM_MR_FLAGS_ONLY, }; +/* + * Internally used to atomically update multiple memslots. + * Must be always zeroed by the caller. + */ +struct kvm_internal_memory_region_list { + /* Fields initialized in __kvm_set_memory_region() */ + struct kvm_memory_slot *old; + struct kvm_memory_slot *new; + struct kvm_memory_slot *invalid; + enum kvm_mr_change change; +}; + int __kvm_set_memory_region(struct kvm *kvm, - const struct kvm_userspace_memory_region *mem); + const struct kvm_userspace_memory_region *mem, + struct kvm_internal_memory_region_list *batch); void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot); void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen); int kvm_arch_prepare_memory_region(struct kvm *kvm, diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 339de0ed4557..e4fab15d0d4b 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1583,10 +1583,11 @@ static void kvm_swap_active_memslots(struct kvm *kvm, int as_id) } static int kvm_prepare_memory_region(struct kvm *kvm, - const struct kvm_memory_slot *old, - struct kvm_memory_slot *new, - enum kvm_mr_change change) + struct kvm_internal_memory_region_list *batch) { + struct kvm_memory_slot *old = batch->old; + struct kvm_memory_slot *new = batch->new; + enum kvm_mr_change change = batch->change; int r; /* @@ -1621,10 +1622,12 @@ static int kvm_prepare_memory_region(struct kvm *kvm, } static void kvm_commit_memory_region(struct kvm *kvm, - struct kvm_memory_slot *old, - const struct kvm_memory_slot *new, - enum kvm_mr_change change) + struct kvm_internal_memory_region_list *batch) { + struct kvm_memory_slot *old = batch->old; + struct kvm_memory_slot *new = batch->new; + enum kvm_mr_change change = batch->change; + /* * Update the total number of memslot pages before calling the arch * hook so that architectures can consume the result directly. @@ -1788,11 +1791,12 @@ static void kvm_update_flags_memslot(struct kvm *kvm, } static int kvm_set_memslot(struct kvm *kvm, - struct kvm_memory_slot *old, - struct kvm_memory_slot *new, - enum kvm_mr_change change) + struct kvm_internal_memory_region_list *batch) { struct kvm_memory_slot *invalid_slot; + struct kvm_memory_slot *old = batch->old; + struct kvm_memory_slot *new = batch->new; + enum kvm_mr_change change = batch->change; int r; /* @@ -1830,10 +1834,11 @@ static int kvm_set_memslot(struct kvm *kvm, mutex_unlock(&kvm->slots_arch_lock); return -ENOMEM; } + batch->invalid = invalid_slot; kvm_invalidate_memslot(kvm, old, invalid_slot); } - r = kvm_prepare_memory_region(kvm, old, new, change); + r = kvm_prepare_memory_region(kvm, batch); if (r) { /* * For DELETE/MOVE, revert the above INVALID change. No @@ -1877,7 +1882,7 @@ static int kvm_set_memslot(struct kvm *kvm, * will directly hit the final, active memslot. Architectures are * responsible for knowing that new->arch may be stale. */ - kvm_commit_memory_region(kvm, old, new, change); + kvm_commit_memory_region(kvm, batch); return 0; } @@ -1900,11 +1905,14 @@ static bool kvm_check_memslot_overlap(struct kvm_memslots *slots, int id, * space. * * Discontiguous memory is allowed, mostly for framebuffers. + * This function takes also care of initializing batch->new/old/invalid/change + * fields. * * Must be called holding kvm->slots_lock for write. */ int __kvm_set_memory_region(struct kvm *kvm, - const struct kvm_userspace_memory_region *mem) + const struct kvm_userspace_memory_region *mem, + struct kvm_internal_memory_region_list *batch) { struct kvm_memory_slot *old, *new; struct kvm_memslots *slots; @@ -1947,6 +1955,7 @@ int __kvm_set_memory_region(struct kvm *kvm, * and/or destroyed by kvm_set_memslot(). */ old = id_to_memslot(slots, id); + batch->old = old; if (!mem->memory_size) { if (!old || !old->npages) @@ -1955,7 +1964,9 @@ int __kvm_set_memory_region(struct kvm *kvm, if (WARN_ON_ONCE(kvm->nr_memslot_pages < old->npages)) return -EIO; - return kvm_set_memslot(kvm, old, NULL, KVM_MR_DELETE); + batch->change = KVM_MR_DELETE; + batch->new = NULL; + return kvm_set_memslot(kvm, batch); } base_gfn = (mem->guest_phys_addr >> PAGE_SHIFT); @@ -1963,6 +1974,7 @@ int __kvm_set_memory_region(struct kvm *kvm, if (!old || !old->npages) { change = KVM_MR_CREATE; + batch->old = NULL; /* * To simplify KVM internals, the total number of pages across @@ -2000,7 +2012,10 @@ int __kvm_set_memory_region(struct kvm *kvm, new->flags = mem->flags; new->userspace_addr = mem->userspace_addr; - r = kvm_set_memslot(kvm, old, new, change); + batch->new = new; + batch->change = change; + + r = kvm_set_memslot(kvm, batch); if (r) kfree(new); return r; @@ -2008,7 +2023,8 @@ int __kvm_set_memory_region(struct kvm *kvm, EXPORT_SYMBOL_GPL(__kvm_set_memory_region); static int kvm_set_memory_region(struct kvm *kvm, - const struct kvm_userspace_memory_region *mem) + const struct kvm_userspace_memory_region *mem, + struct kvm_internal_memory_region_list *batch) { int r; @@ -2016,7 +2032,7 @@ static int kvm_set_memory_region(struct kvm *kvm, return -EINVAL; mutex_lock(&kvm->slots_lock); - r = __kvm_set_memory_region(kvm, mem); + r = __kvm_set_memory_region(kvm, mem, batch); mutex_unlock(&kvm->slots_lock); return r; } @@ -2024,7 +2040,9 @@ static int kvm_set_memory_region(struct kvm *kvm, static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem) { - return kvm_set_memory_region(kvm, mem); + struct kvm_internal_memory_region_list batch = { 0 }; + + return kvm_set_memory_region(kvm, mem, &batch); } #ifndef CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT From patchwork Fri Sep 9 10:45:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Emanuele Giuseppe Esposito X-Patchwork-Id: 12971491 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B6903ECAAD3 for ; Fri, 9 Sep 2022 10:45:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231225AbiIIKp2 (ORCPT ); Fri, 9 Sep 2022 06:45:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40072 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231150AbiIIKpS (ORCPT ); Fri, 9 Sep 2022 06:45:18 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AAFBC4DB7E for ; Fri, 9 Sep 2022 03:45:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1662720315; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=m8Uwqb2u54NGuVgopEXAeF7Kt4xDeaUDYurd/mYS65U=; b=eEvAAQmNGHsQ+sBQvGtjlEvmMPO/r3B1jJzSnvEnZHOGa+evU/10MkpIkC7fHO2I1puUi3 j1+tFGR/4fmDdoZ1sRW4QUcWkEogtWYkfupqPQLSPiFRfOlXFtYhEIs2Hi43OS2C9QmRSH NNNGAgmRxCvlE2YSylhB7gkU9y4hXJA= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-451-YI5_BTabN4-gBYxsFpbhVA-1; Fri, 09 Sep 2022 06:45:11 -0400 X-MC-Unique: YI5_BTabN4-gBYxsFpbhVA-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 049063C0E210; Fri, 9 Sep 2022 10:45:11 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9645340D282E; Fri, 9 Sep 2022 10:45:10 +0000 (UTC) From: Emanuele Giuseppe Esposito To: kvm@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Vitaly Kuznetsov , Wanpeng Li , Jim Mattson , Joerg Roedel , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , David Hildenbrand , Maxim Levitsky , x86@kernel.org, "H. Peter Anvin" , linux-kernel@vger.kernel.org, Emanuele Giuseppe Esposito Subject: [RFC PATCH 4/9] kvm_main.c: split logic in kvm_set_memslots Date: Fri, 9 Sep 2022 06:45:01 -0400 Message-Id: <20220909104506.738478-5-eesposit@redhat.com> In-Reply-To: <20220909104506.738478-1-eesposit@redhat.com> References: <20220909104506.738478-1-eesposit@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.11.54.2 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org At this point it is also just a split, but later will handle atomic memslot updates (thus avoiding swapping the memslot list every time). No functional change intended. Signed-off-by: Emanuele Giuseppe Esposito --- virt/kvm/kvm_main.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index e4fab15d0d4b..17f07546d591 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1790,12 +1790,15 @@ static void kvm_update_flags_memslot(struct kvm *kvm, kvm_activate_memslot(kvm, old, new); } -static int kvm_set_memslot(struct kvm *kvm, - struct kvm_internal_memory_region_list *batch) +/* + * Takes kvm->slots_arch_lock, and releases it only if + * invalid_slot allocation or kvm_prepare_memory_region failed. + */ +static int kvm_prepare_memslot(struct kvm *kvm, + struct kvm_internal_memory_region_list *batch) { struct kvm_memory_slot *invalid_slot; struct kvm_memory_slot *old = batch->old; - struct kvm_memory_slot *new = batch->new; enum kvm_mr_change change = batch->change; int r; @@ -1829,7 +1832,8 @@ static int kvm_set_memslot(struct kvm *kvm, * invalidation needs to be reverted. */ if (change == KVM_MR_DELETE || change == KVM_MR_MOVE) { - invalid_slot = kzalloc(sizeof(*invalid_slot), GFP_KERNEL_ACCOUNT); + invalid_slot = kzalloc(sizeof(*invalid_slot), + GFP_KERNEL_ACCOUNT); if (!invalid_slot) { mutex_unlock(&kvm->slots_arch_lock); return -ENOMEM; @@ -1847,13 +1851,24 @@ static int kvm_set_memslot(struct kvm *kvm, * release slots_arch_lock. */ if (change == KVM_MR_DELETE || change == KVM_MR_MOVE) { + /* kvm_activate_memslot releases kvm->slots_arch_lock */ kvm_activate_memslot(kvm, invalid_slot, old); kfree(invalid_slot); } else { mutex_unlock(&kvm->slots_arch_lock); } - return r; } + return r; +} + +/* Must be called with kvm->slots_arch_lock held, but releases it. */ +static void kvm_finish_memslot(struct kvm *kvm, + struct kvm_internal_memory_region_list *batch) +{ + struct kvm_memory_slot *invalid_slot = batch->invalid; + struct kvm_memory_slot *old = batch->old; + struct kvm_memory_slot *new = batch->new; + enum kvm_mr_change change = batch->change; /* * For DELETE and MOVE, the working slot is now active as the INVALID @@ -1883,6 +1898,18 @@ static int kvm_set_memslot(struct kvm *kvm, * responsible for knowing that new->arch may be stale. */ kvm_commit_memory_region(kvm, batch); +} + +static int kvm_set_memslot(struct kvm *kvm, + struct kvm_internal_memory_region_list *batch) +{ + int r; + + r = kvm_prepare_memslot(kvm, batch); + if (r) + return r; + + kvm_finish_memslot(kvm, batch); return 0; } From patchwork Fri Sep 9 10:45:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Emanuele Giuseppe Esposito X-Patchwork-Id: 12971495 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C9A5BECAAD3 for ; Fri, 9 Sep 2022 10:45:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231254AbiIIKpj (ORCPT ); Fri, 9 Sep 2022 06:45:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40230 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231196AbiIIKpT (ORCPT ); Fri, 9 Sep 2022 06:45:19 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 05214501A3 for ; Fri, 9 Sep 2022 03:45:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1662720317; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ga0KXbfsZxBvniEYK+V0PLuE8LBCeWPj6GbvQKqhHp4=; b=KpbecsM0gQsNbDjufhUUFX2OudHHpQcAdlEW6ZnsRUfcUZ8e7AW5N6PvZJ++3zxhYz35h7 DmlNEqsXUL8Jk0aQXojQyQunvIZaMAPtbplmsN9F9yzr/DYC6EnZRkVuVn4RbR/AU8j4+l +TUtY/fnw9LLFM42KiuswR6kl4ZkZw0= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-587-up2WwOObMYGsMZmYRXOhfQ-1; Fri, 09 Sep 2022 06:45:12 -0400 X-MC-Unique: up2WwOObMYGsMZmYRXOhfQ-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 7144A802E5D; Fri, 9 Sep 2022 10:45:11 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0DFA940D282E; Fri, 9 Sep 2022 10:45:11 +0000 (UTC) From: Emanuele Giuseppe Esposito To: kvm@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Vitaly Kuznetsov , Wanpeng Li , Jim Mattson , Joerg Roedel , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , David Hildenbrand , Maxim Levitsky , x86@kernel.org, "H. Peter Anvin" , linux-kernel@vger.kernel.org, Emanuele Giuseppe Esposito Subject: [RFC PATCH 5/9] kvm_main.c: split __kvm_set_memory_region logic in kvm_check_mem and kvm_prepare_batch Date: Fri, 9 Sep 2022 06:45:02 -0400 Message-Id: <20220909104506.738478-6-eesposit@redhat.com> In-Reply-To: <20220909104506.738478-1-eesposit@redhat.com> References: <20220909104506.738478-1-eesposit@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.11.54.2 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Just a function split. No functional change intended, except for the fact that kvm_prepare_batch() does not immediately call kvm_set_memslot() if batch->change is KVM_MR_DELETE, but delegates the caller (__kvm_set_memory_region). Signed-off-by: Emanuele Giuseppe Esposito --- virt/kvm/kvm_main.c | 120 +++++++++++++++++++++++++++++--------------- 1 file changed, 79 insertions(+), 41 deletions(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 17f07546d591..9d917af30593 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1927,19 +1927,9 @@ static bool kvm_check_memslot_overlap(struct kvm_memslots *slots, int id, return false; } -/* - * Allocate some memory and give it an address in the guest physical address - * space. - * - * Discontiguous memory is allowed, mostly for framebuffers. - * This function takes also care of initializing batch->new/old/invalid/change - * fields. - * - * Must be called holding kvm->slots_lock for write. - */ -int __kvm_set_memory_region(struct kvm *kvm, - const struct kvm_userspace_memory_region *mem, - struct kvm_internal_memory_region_list *batch) +static int kvm_prepare_batch(struct kvm *kvm, + const struct kvm_userspace_memory_region *mem, + struct kvm_internal_memory_region_list *batch) { struct kvm_memory_slot *old, *new; struct kvm_memslots *slots; @@ -1947,34 +1937,10 @@ int __kvm_set_memory_region(struct kvm *kvm, unsigned long npages; gfn_t base_gfn; int as_id, id; - int r; - - r = check_memory_region_flags(mem); - if (r) - return r; as_id = mem->slot >> 16; id = (u16)mem->slot; - /* General sanity checks */ - if ((mem->memory_size & (PAGE_SIZE - 1)) || - (mem->memory_size != (unsigned long)mem->memory_size)) - return -EINVAL; - if (mem->guest_phys_addr & (PAGE_SIZE - 1)) - return -EINVAL; - /* We can read the guest memory with __xxx_user() later on. */ - if ((mem->userspace_addr & (PAGE_SIZE - 1)) || - (mem->userspace_addr != untagged_addr(mem->userspace_addr)) || - !access_ok((void __user *)(unsigned long)mem->userspace_addr, - mem->memory_size)) - return -EINVAL; - if (as_id >= KVM_ADDRESS_SPACE_NUM || id >= KVM_MEM_SLOTS_NUM) - return -EINVAL; - if (mem->guest_phys_addr + mem->memory_size < mem->guest_phys_addr) - return -EINVAL; - if ((mem->memory_size >> PAGE_SHIFT) > KVM_MEM_MAX_NR_PAGES) - return -EINVAL; - slots = __kvm_memslots(kvm, as_id); /* @@ -1993,7 +1959,7 @@ int __kvm_set_memory_region(struct kvm *kvm, batch->change = KVM_MR_DELETE; batch->new = NULL; - return kvm_set_memslot(kvm, batch); + return 0; } base_gfn = (mem->guest_phys_addr >> PAGE_SHIFT); @@ -2020,7 +1986,7 @@ int __kvm_set_memory_region(struct kvm *kvm, else if (mem->flags != old->flags) change = KVM_MR_FLAGS_ONLY; else /* Nothing to change. */ - return 0; + return 1; } if ((change == KVM_MR_CREATE || change == KVM_MR_MOVE) && @@ -2041,12 +2007,81 @@ int __kvm_set_memory_region(struct kvm *kvm, batch->new = new; batch->change = change; + return 0; +} + +static int kvm_check_mem(const struct kvm_userspace_memory_region *mem) +{ + int as_id, id; + + as_id = mem->slot >> 16; + id = (u16)mem->slot; + + /* General sanity checks */ + if ((mem->memory_size & (PAGE_SIZE - 1)) || + (mem->memory_size != (unsigned long)mem->memory_size)) + return -EINVAL; + if (mem->guest_phys_addr & (PAGE_SIZE - 1)) + return -EINVAL; + /* We can read the guest memory with __xxx_user() later on. */ + if ((mem->userspace_addr & (PAGE_SIZE - 1)) || + (mem->userspace_addr != untagged_addr(mem->userspace_addr)) || + !access_ok((void __user *)(unsigned long)mem->userspace_addr, + mem->memory_size)) + return -EINVAL; + if (as_id >= KVM_ADDRESS_SPACE_NUM || id >= KVM_MEM_SLOTS_NUM) + return -EINVAL; + if (mem->guest_phys_addr + mem->memory_size < mem->guest_phys_addr) + return -EINVAL; + if ((mem->memory_size >> PAGE_SHIFT) > KVM_MEM_MAX_NR_PAGES) + return -EINVAL; + + return 0; +} + +static int kvm_check_memory_region(struct kvm *kvm, + const struct kvm_userspace_memory_region *mem, + struct kvm_internal_memory_region_list *batch) +{ + int r; + + r = check_memory_region_flags(mem); + if (r) + return r; - r = kvm_set_memslot(kvm, batch); + r = kvm_check_mem(mem); if (r) - kfree(new); + return r; + + r = kvm_prepare_batch(kvm, mem, batch); + if (r && batch->new) + kfree(batch->new); + return r; } + +/* + * Allocate some memory and give it an address in the guest physical address + * space. + * + * Discontiguous memory is allowed, mostly for framebuffers. + * This function takes also care of initializing batch->new/old/invalid/change + * fields. + * + * Must be called holding kvm->slots_lock for write. + */ +int __kvm_set_memory_region(struct kvm *kvm, + const struct kvm_userspace_memory_region *mem, + struct kvm_internal_memory_region_list *batch) +{ + int r; + + r = kvm_check_memory_region(kvm, mem, batch); + if (r) + return r; + + return kvm_set_memslot(kvm, batch); +} EXPORT_SYMBOL_GPL(__kvm_set_memory_region); static int kvm_set_memory_region(struct kvm *kvm, @@ -2061,6 +2096,9 @@ static int kvm_set_memory_region(struct kvm *kvm, mutex_lock(&kvm->slots_lock); r = __kvm_set_memory_region(kvm, mem, batch); mutex_unlock(&kvm->slots_lock); + /* r == 1 means empty request, nothing to do but no error */ + if (r == 1) + r = 0; return r; } From patchwork Fri Sep 9 10:45:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Emanuele Giuseppe Esposito X-Patchwork-Id: 12971497 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 99E4BECAAD3 for ; Fri, 9 Sep 2022 10:45:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231301AbiIIKpp (ORCPT ); Fri, 9 Sep 2022 06:45:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40162 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231174AbiIIKpT (ORCPT ); Fri, 9 Sep 2022 06:45:19 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A80174F66E for ; Fri, 9 Sep 2022 03:45:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1662720316; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=4DkIOa4ss6n0l+Uwq2rxErjUkkNwBYbVflsNmqJrnW0=; b=YY6k29Nz9jbW9VAXx0bcEVoIe2pXj94S+cDqUEISUbtL6H08UiPbcm2FRn5rF9B39llhSq Jsf2QcFcIiOtGg337UHKOZ2GtDUT9EYDpTlRBXe38xbpo0WiIaZk0okks+RpZvfRFBmVuC 2eEyupiziv9vC13UXGFd3Ev4h8IPx4w= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-65-mP8g3QoaPCyRCIhg2g8B6A-1; Fri, 09 Sep 2022 06:45:12 -0400 X-MC-Unique: mP8g3QoaPCyRCIhg2g8B6A-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id DC66B80029D; Fri, 9 Sep 2022 10:45:11 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7A63D40D282E; Fri, 9 Sep 2022 10:45:11 +0000 (UTC) From: Emanuele Giuseppe Esposito To: kvm@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Vitaly Kuznetsov , Wanpeng Li , Jim Mattson , Joerg Roedel , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , David Hildenbrand , Maxim Levitsky , x86@kernel.org, "H. Peter Anvin" , linux-kernel@vger.kernel.org, Emanuele Giuseppe Esposito Subject: [RFC PATCH 6/9] kvm_main.c: simplify change-specific callbacks Date: Fri, 9 Sep 2022 06:45:03 -0400 Message-Id: <20220909104506.738478-7-eesposit@redhat.com> In-Reply-To: <20220909104506.738478-1-eesposit@redhat.com> References: <20220909104506.738478-1-eesposit@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.11.54.2 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Instead of replacing the memslot in the inactive slots and activate for each "change" specific function (NEW, MOVE, DELETE, ...), make kvm_set_memslot() replace the memslot in current inactive list and swap the lists, and then kvm_finish_memslot just takes care of updating the new inactive list (was active). We can generalize here the pre-swap replacement with replace(old, new) because even if in a DELETE or MOVE operation, old will always stay in the inactive list (used by kvm_replace_memslot). Signed-off-by: Emanuele Giuseppe Esposito --- virt/kvm/kvm_main.c | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 9d917af30593..6b73615891f0 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1747,34 +1747,26 @@ static void kvm_invalidate_memslot(struct kvm *kvm, static void kvm_create_memslot(struct kvm *kvm, struct kvm_memory_slot *new) { - /* Add the new memslot to the inactive set and activate. */ + /* Update inactive slot (was active) by adding the new slot */ kvm_replace_memslot(kvm, NULL, new); - kvm_activate_memslot(kvm, NULL, new); } static void kvm_delete_memslot(struct kvm *kvm, - struct kvm_memory_slot *old, struct kvm_memory_slot *invalid_slot) { - /* - * Remove the old memslot (in the inactive memslots) by passing NULL as - * the "new" slot, and for the invalid version in the active slots. - */ - kvm_replace_memslot(kvm, old, NULL); - kvm_activate_memslot(kvm, invalid_slot, NULL); + /* Update inactive slot (was active) by removing the invalid slot */ + kvm_replace_memslot(kvm, invalid_slot, NULL); } static void kvm_move_memslot(struct kvm *kvm, - struct kvm_memory_slot *old, struct kvm_memory_slot *new, struct kvm_memory_slot *invalid_slot) { /* - * Replace the old memslot in the inactive slots, and then swap slots - * and replace the current INVALID with the new as well. + * Update inactive slot (was active) by removing the invalid slot + * and adding the new one. */ - kvm_replace_memslot(kvm, old, new); - kvm_activate_memslot(kvm, invalid_slot, new); + kvm_replace_memslot(kvm, invalid_slot, new); } static void kvm_update_flags_memslot(struct kvm *kvm, @@ -1782,12 +1774,10 @@ static void kvm_update_flags_memslot(struct kvm *kvm, struct kvm_memory_slot *new) { /* - * Similar to the MOVE case, but the slot doesn't need to be zapped as - * an intermediate step. Instead, the old memslot is simply replaced - * with a new, updated copy in both memslot sets. + * Update inactive slot (was active) by removing the old slot + * and adding the new one. */ kvm_replace_memslot(kvm, old, new); - kvm_activate_memslot(kvm, old, new); } /* @@ -1880,9 +1870,9 @@ static void kvm_finish_memslot(struct kvm *kvm, if (change == KVM_MR_CREATE) kvm_create_memslot(kvm, new); else if (change == KVM_MR_DELETE) - kvm_delete_memslot(kvm, old, invalid_slot); + kvm_delete_memslot(kvm, invalid_slot); else if (change == KVM_MR_MOVE) - kvm_move_memslot(kvm, old, new, invalid_slot); + kvm_move_memslot(kvm, new, invalid_slot); else if (change == KVM_MR_FLAGS_ONLY) kvm_update_flags_memslot(kvm, old, new); else @@ -1903,12 +1893,24 @@ static void kvm_finish_memslot(struct kvm *kvm, static int kvm_set_memslot(struct kvm *kvm, struct kvm_internal_memory_region_list *batch) { - int r; + int r, as_id; r = kvm_prepare_memslot(kvm, batch); if (r) return r; + /* + * if change is DELETE or MOVE, invalid is in active memslots + * and old in inactive, so replace old with new. + */ + kvm_replace_memslot(kvm, batch->old, batch->new); + + /* either old or invalid is the same, since invalid is old's copy */ + as_id = kvm_memslots_get_as_id(batch->old, batch->new); + + /* releases kvm->slots_arch_lock */ + kvm_swap_active_memslots(kvm, as_id); + kvm_finish_memslot(kvm, batch); return 0; From patchwork Fri Sep 9 10:45:04 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Emanuele Giuseppe Esposito X-Patchwork-Id: 12971496 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6215EECAAD3 for ; Fri, 9 Sep 2022 10:45:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230306AbiIIKpm (ORCPT ); Fri, 9 Sep 2022 06:45:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40076 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231192AbiIIKpT (ORCPT ); Fri, 9 Sep 2022 06:45:19 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EAA8C5005E for ; Fri, 9 Sep 2022 03:45:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1662720317; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=c0NgkoxjaxWZzPMna+r8g36cHTkfcmxMVnLk3I8tBk0=; b=PfJGHivym1xzIz2AjYjnhBL9e8CORwAur1pK6zV4nEvI21x1lpfukiv58gFvK8f1MO7f5T uZt3GO1q3G4Ww7DsyZ2RAH2mh73nifwHOYgVTyVgNcxJCsXdbZtJFLcsS+hTwK/S2NJwCJ jepm8tGeldt7Z2WyX/odgRBT3/0JgFw= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-614-MkxgwddvMM-9vnd2TjolAQ-1; Fri, 09 Sep 2022 06:45:13 -0400 X-MC-Unique: MkxgwddvMM-9vnd2TjolAQ-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 52A2C101A56C; Fri, 9 Sep 2022 10:45:12 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id E512E40D282E; Fri, 9 Sep 2022 10:45:11 +0000 (UTC) From: Emanuele Giuseppe Esposito To: kvm@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Vitaly Kuznetsov , Wanpeng Li , Jim Mattson , Joerg Roedel , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , David Hildenbrand , Maxim Levitsky , x86@kernel.org, "H. Peter Anvin" , linux-kernel@vger.kernel.org, Emanuele Giuseppe Esposito Subject: [RFC PATCH 7/9] kvm_main.c: duplicate invalid memslot also in inactive list Date: Fri, 9 Sep 2022 06:45:04 -0400 Message-Id: <20220909104506.738478-8-eesposit@redhat.com> In-Reply-To: <20220909104506.738478-1-eesposit@redhat.com> References: <20220909104506.738478-1-eesposit@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.11.54.2 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org In preparation for atomic memslot updates, make sure the invalid memslot is also replacing the old one in the inactive list. This implies that once we want to insert the new slot for a MOVE, or simply delete the existing one for a DELETE, we need to remove the "invalid" slot, not the "old" one. Signed-off-by: Emanuele Giuseppe Esposito --- virt/kvm/kvm_main.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 6b73615891f0..31e46f9a06fa 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1830,6 +1830,7 @@ static int kvm_prepare_memslot(struct kvm *kvm, } batch->invalid = invalid_slot; kvm_invalidate_memslot(kvm, old, invalid_slot); + kvm_replace_memslot(kvm, old, invalid_slot); } r = kvm_prepare_memory_region(kvm, batch); @@ -1900,10 +1901,14 @@ static int kvm_set_memslot(struct kvm *kvm, return r; /* - * if change is DELETE or MOVE, invalid is in active memslots - * and old in inactive, so replace old with new. + * if change is DELETE or MOVE, invalid is in both active and inactive + * memslot list. This means that we don't need old anymore, and + * we should replace invalid with new. */ - kvm_replace_memslot(kvm, batch->old, batch->new); + if (batch->change == KVM_MR_DELETE || batch->change == KVM_MR_MOVE) + kvm_replace_memslot(kvm, batch->invalid, batch->new); + else + kvm_replace_memslot(kvm, batch->old, batch->new); /* either old or invalid is the same, since invalid is old's copy */ as_id = kvm_memslots_get_as_id(batch->old, batch->new); From patchwork Fri Sep 9 10:45:05 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Emanuele Giuseppe Esposito X-Patchwork-Id: 12971493 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3192BECAAD3 for ; Fri, 9 Sep 2022 10:45:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230238AbiIIKpg (ORCPT ); Fri, 9 Sep 2022 06:45:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40168 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231172AbiIIKpT (ORCPT ); Fri, 9 Sep 2022 06:45:19 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A83724F69E for ; Fri, 9 Sep 2022 03:45:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1662720316; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=eUVXlYDwK0/TqR7ADYfBnKPJM99YoNpijZnP7G2Z+Ds=; b=AZm8lDSX0eggR0U9ANhNfOwcLFcE4LNFQabalsoZ+7HzgKDAi2v1z4N1u+Y2z+ik4vDgBq hMGFnEPGOXyDM6Y5pGCU98LeltInCM70qPSXMB7WGTaw0a0vyaXRJmlcbYK8IbYLolg8mz 3MdXIxrjsTt3SydTQd79sz59MGGtR6I= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-649-Jxe2dHiBOQ-FzA5qflBSeg-1; Fri, 09 Sep 2022 06:45:13 -0400 X-MC-Unique: Jxe2dHiBOQ-FzA5qflBSeg-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id EEA911C05AE6; Fri, 9 Sep 2022 10:45:12 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5B5F740D282E; Fri, 9 Sep 2022 10:45:12 +0000 (UTC) From: Emanuele Giuseppe Esposito To: kvm@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Vitaly Kuznetsov , Wanpeng Li , Jim Mattson , Joerg Roedel , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , David Hildenbrand , Maxim Levitsky , x86@kernel.org, "H. Peter Anvin" , linux-kernel@vger.kernel.org, Emanuele Giuseppe Esposito Subject: [RFC PATCH 8/9] kvm_main.c: find memslots from the inactive memslot list Date: Fri, 9 Sep 2022 06:45:05 -0400 Message-Id: <20220909104506.738478-9-eesposit@redhat.com> In-Reply-To: <20220909104506.738478-1-eesposit@redhat.com> References: <20220909104506.738478-1-eesposit@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.11.54.2 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Instead of looking at the active list, look at the inactive. This causes no harm to the current code, as active and inactive lists are identical at this point. In addition, provide flexibility for atomic memslot updates, because in that case we want to perform multiple updates in the inactive list first, and then perform a single swap only. If we were to use the active list, previous updates that were not yet swapped won't be seen, and the following logic in kvm_prepare_batch() could for example find an old memslot that was deleted in the inactive but not in the active, thus wrongly assuming that the coming request is a MOVE and not a CREATE. Note that this also causes no harm to the invalidate memslot, since we are already inserting it as replacement in both active and inactive list. Signed-off-by: Emanuele Giuseppe Esposito --- virt/kvm/kvm_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 31e46f9a06fa..ecd43560281c 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1948,7 +1948,7 @@ static int kvm_prepare_batch(struct kvm *kvm, as_id = mem->slot >> 16; id = (u16)mem->slot; - slots = __kvm_memslots(kvm, as_id); + slots = kvm_get_inactive_memslots(kvm, as_id); /* * Note, the old memslot (and the pointer itself!) may be invalidated From patchwork Fri Sep 9 10:45:06 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Emanuele Giuseppe Esposito X-Patchwork-Id: 12971494 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E2B87C6FA82 for ; Fri, 9 Sep 2022 10:45:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231270AbiIIKph (ORCPT ); Fri, 9 Sep 2022 06:45:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40072 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231204AbiIIKpU (ORCPT ); Fri, 9 Sep 2022 06:45:20 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2DBB14A830 for ; Fri, 9 Sep 2022 03:45:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1662720318; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=n4cgIksUzFB9SvsBadLEVot1eDVS36LvXAqIPpUHUGo=; b=JH+y4iIAzJ1CLiHaXSlYmWbisNj9m08oyK3h+we3TlXd/YEYZ1Rf89VRansSPD9Bv94Fpk GyJtMLW36Df4J3n+DVO75TsoPiNiDn9unLlT/YoGw0Ld2y+5pWB1UiY1clIzMQSviOULxo 3lzveYxjrNA0RYoGUEqpcCrxZzm6ZbE= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-400-UN6rHOoxM_C2zLMtMkJXMA-1; Fri, 09 Sep 2022 06:45:14 -0400 X-MC-Unique: UN6rHOoxM_C2zLMtMkJXMA-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 6A77980418F; Fri, 9 Sep 2022 10:45:13 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0422A40D282E; Fri, 9 Sep 2022 10:45:12 +0000 (UTC) From: Emanuele Giuseppe Esposito To: kvm@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Vitaly Kuznetsov , Wanpeng Li , Jim Mattson , Joerg Roedel , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , David Hildenbrand , Maxim Levitsky , x86@kernel.org, "H. Peter Anvin" , linux-kernel@vger.kernel.org, Emanuele Giuseppe Esposito Subject: [RFC PATCH 9/9] kvm_main.c: handle atomic memslot update Date: Fri, 9 Sep 2022 06:45:06 -0400 Message-Id: <20220909104506.738478-10-eesposit@redhat.com> In-Reply-To: <20220909104506.738478-1-eesposit@redhat.com> References: <20220909104506.738478-1-eesposit@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.11.54.2 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org When kvm_vm_ioctl_set_memory_region_list() is invoked, we need to make sure that all memslots are updated in the inactive list and then swap (preferreably only once) the lists, so that all changes are visible immediately. The only issue is that DELETE and MOVE need to perform 2 swaps: firstly replace old memslot with invalid, and then remove invalid. Therefore we need to perform two passes in the memslot list provided by the ioctl: first handle only the DELETE and MOVE memslots, by replacing the old node with an invalid one. This implies a swap for each memslot (they could also be grouped in a single one, but for simplicity we are not going to do it). Userspace already marks the DELETE and MOVE requests with the flag invalid_slot == 1. Then, scan again the list and update the inactive memslot list. Once the inactive memslot list is ready, swap it only once per address space, and conclude the memslot handling. Regarding kvm->slots_arch_lock, it is always taken in kvm_prepare_memslot but depending on the batch->change and loop (first, second, conclusion) in kvm_vm_ioctl_set_memory_region_list, we release in different places: - change = DELETE or MOVE. In the first pass, we release after creating the invalid memslot and swapping. - Second loop in kvm_vm_ioctl_set_memory_region_list. We release it in kvm_set_memslot since batch->batch is true. - Third loop in kvm_vm_ioctl_set_memory_region_list. We take and release it for each swap. - Call from kvm_vm_ioctl_set_memory_region: as before this patch, acquire in kvm_prepare_memslot and release in kvm_swap_active_memslots. Signed-off-by: Emanuele Giuseppe Esposito --- include/linux/kvm_host.h | 4 + virt/kvm/kvm_main.c | 185 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 179 insertions(+), 10 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 69af94472b39..753650145836 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1118,6 +1118,10 @@ struct kvm_internal_memory_region_list { struct kvm_memory_slot *new; struct kvm_memory_slot *invalid; enum kvm_mr_change change; + + /* Fields that need to be set by the caller */ + bool batch; + bool is_move_delete; }; int __kvm_set_memory_region(struct kvm *kvm, diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index ecd43560281c..85ba05924f0c 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1782,7 +1782,8 @@ static void kvm_update_flags_memslot(struct kvm *kvm, /* * Takes kvm->slots_arch_lock, and releases it only if - * invalid_slot allocation or kvm_prepare_memory_region failed. + * invalid_slot allocation, kvm_prepare_memory_region failed + * or batch->is_move_delete is true. */ static int kvm_prepare_memslot(struct kvm *kvm, struct kvm_internal_memory_region_list *batch) @@ -1822,15 +1823,26 @@ static int kvm_prepare_memslot(struct kvm *kvm, * invalidation needs to be reverted. */ if (change == KVM_MR_DELETE || change == KVM_MR_MOVE) { - invalid_slot = kzalloc(sizeof(*invalid_slot), + if (!batch->invalid) { + invalid_slot = kzalloc(sizeof(*invalid_slot), GFP_KERNEL_ACCOUNT); - if (!invalid_slot) { + if (!invalid_slot) { + mutex_unlock(&kvm->slots_arch_lock); + return -ENOMEM; + } + batch->invalid = invalid_slot; + kvm_invalidate_memslot(kvm, old, invalid_slot); + kvm_replace_memslot(kvm, old, invalid_slot); + } + + /* + * We are in first pass of kvm_vm_ioctl_set_memory_region_list() + * just take care of making the old slot invalid and visible. + */ + if (batch->is_move_delete) { mutex_unlock(&kvm->slots_arch_lock); - return -ENOMEM; + return 0; } - batch->invalid = invalid_slot; - kvm_invalidate_memslot(kvm, old, invalid_slot); - kvm_replace_memslot(kvm, old, invalid_slot); } r = kvm_prepare_memory_region(kvm, batch); @@ -1896,6 +1908,13 @@ static int kvm_set_memslot(struct kvm *kvm, { int r, as_id; + /* + * First, prepare memslot. If DELETE and MOVE, take care of creating + * the invalid slot and use it to replace the old one. + * In order to keep things simple, allow each single update + * to be immediately visibile by swapping the active and inactive + * memory slot arrays. + */ r = kvm_prepare_memslot(kvm, batch); if (r) return r; @@ -1910,6 +1929,12 @@ static int kvm_set_memslot(struct kvm *kvm, else kvm_replace_memslot(kvm, batch->old, batch->new); + /* Caller has to manually commit changes afterwards */ + if (batch->batch) { + mutex_unlock(&kvm->slots_arch_lock); + return r; + } + /* either old or invalid is the same, since invalid is old's copy */ as_id = kvm_memslots_get_as_id(batch->old, batch->new); @@ -2083,9 +2108,11 @@ int __kvm_set_memory_region(struct kvm *kvm, { int r; - r = kvm_check_memory_region(kvm, mem, batch); - if (r) - return r; + if (!batch->old && !batch->new && !batch->invalid) { + r = kvm_check_memory_region(kvm, mem, batch); + if (r) + return r; + } return kvm_set_memslot(kvm, batch); } @@ -2117,6 +2144,133 @@ static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, return kvm_set_memory_region(kvm, mem, &batch); } +static int kvm_vm_ioctl_set_memory_region_list(struct kvm *kvm, + struct kvm_userspace_memory_region_list *list, + struct kvm_userspace_memory_region_entry __user *mem_arg) +{ + struct kvm_userspace_memory_region_entry *mem, *m_iter; + struct kvm_userspace_memory_region *mem_region; + struct kvm_internal_memory_region_list *batch, *b_iter; + int i, r = 0; + bool *as_to_swap; + + /* TODO: limit the number of mem to a max? */ + + if (!list->nent) + return r; + + mem = vmemdup_user(mem_arg, array_size(sizeof(*mem), list->nent)); + if (IS_ERR(mem)) { + r = PTR_ERR(mem); + goto out; + } + + batch = kcalloc(list->nent, sizeof(*batch), GFP_KERNEL_ACCOUNT); + if (IS_ERR(batch)) { + r = PTR_ERR(batch); + goto out2; + } + + as_to_swap = kcalloc(KVM_ADDRESS_SPACE_NUM, sizeof(bool), + GFP_KERNEL_ACCOUNT); + if (IS_ERR(as_to_swap)) { + r = PTR_ERR(as_to_swap); + goto out3; + } + + m_iter = mem; + b_iter = batch; + /* + * First pass: handle all DELETE and MOVE requests + * (since they swap active and inactive memslots) + * by switching old memslot in invalid. + */ + mutex_lock(&kvm->slots_lock); + for (i = 0; i < list->nent; i++) { + + if ((u16)m_iter->slot >= KVM_USER_MEM_SLOTS) { + r = -EINVAL; + goto out4; + } + + if (!m_iter->invalidate_slot) { + m_iter++; + b_iter++; + continue; + } + + mem_region = (struct kvm_userspace_memory_region *) m_iter; + r = kvm_check_memory_region(kvm, mem_region, b_iter); + if (r) { + mutex_unlock(&kvm->slots_lock); + goto out4; + } + + WARN_ON(b_iter->change != KVM_MR_DELETE && + b_iter->change != KVM_MR_MOVE); + + b_iter->is_move_delete = true; + r = kvm_prepare_memslot(kvm, b_iter); + b_iter->is_move_delete = false; + if (r < 0) { + mutex_unlock(&kvm->slots_lock); + goto out4; + } + m_iter++; + b_iter++; + } + mutex_unlock(&kvm->slots_lock); + + + m_iter = mem; + b_iter = batch; + /* + * Second pass: handle all other request types + * but do not swap the memslots array yet. + */ + for (i = 0; i < list->nent; i++) { + b_iter->batch = true; + as_to_swap[m_iter->slot >> 16] = true; + mem_region = (struct kvm_userspace_memory_region *) m_iter; + r = kvm_set_memory_region(kvm, mem_region, b_iter); + if (r < 0) + goto out4; + m_iter++; + b_iter++; + } + + /* + * Conclude by swapping the memslot lists and updating the inactive set too. + */ + b_iter = batch; + mutex_lock(&kvm->slots_lock); + mutex_lock(&kvm->slots_arch_lock); + for (i = 0; i < list->nent; i++) { + int as_id; + + as_id = kvm_memslots_get_as_id(b_iter->old, b_iter->new); + if (as_to_swap[as_id]) { + kvm_swap_active_memslots(kvm, as_id); + mutex_lock(&kvm->slots_arch_lock); + as_to_swap[as_id] = false; + } + + kvm_finish_memslot(kvm, b_iter); + b_iter++; + } + mutex_unlock(&kvm->slots_arch_lock); + mutex_unlock(&kvm->slots_lock); + +out4: + kfree(as_to_swap); +out3: + kfree(batch); +out2: + kvfree(mem); +out: + return r; +} + #ifndef CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT /** * kvm_get_dirty_log - get a snapshot of dirty pages @@ -4732,6 +4886,17 @@ static long kvm_vm_ioctl(struct file *filp, r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem); break; } + case KVM_SET_USER_MEMORY_REGION_LIST: { + struct kvm_userspace_memory_region_list __user *mem_arg = argp; + struct kvm_userspace_memory_region_list mem; + + r = -EFAULT; + if (copy_from_user(&mem, mem_arg, sizeof(mem))) + goto out; + + r = kvm_vm_ioctl_set_memory_region_list(kvm, &mem, mem_arg->entries); + break; + } case KVM_GET_DIRTY_LOG: { struct kvm_dirty_log log;