From patchwork Tue Feb 11 00:09:15 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxim Levitsky X-Patchwork-Id: 13969220 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3E9A879C8 for ; Tue, 11 Feb 2025 00:09:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739232583; cv=none; b=D/KAJWyVkWf+5TBYGKOb7GYCj5+x7S8X5oWEfWz1hqwrI3T6pcw9jSCxaTss/qbtGZ9vmNA72o8Tr0uYvx1Jpu8KZXhPxnH8eWhQjmJ7amY51QQXAF6Lp+Lnzok7VPkyisXSYW/cIkuULnde7sQlEwpl7TYw7qCt/4Ys/pzlgGE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739232583; c=relaxed/simple; bh=qcJEfO+ZiT4S3ADac4l4lz0xtxJSkA/jxhTgc/GyprA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=T8KTLViY5XhDsrVWof0vgR6tnYBjE8Uh6nZs9PN2sb1RboY2XZbRGbOBP5D0h2zb7JwbReEJEcudGXfvzQXwtK8d1Zx+UAEuj7iN/FulcN37QERwOEWhTW4oW1iu0qd+mxIwHfj1bISaBS188NfegjAKklaQz7kKN3N547QCXhU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=fk1yMzOc; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="fk1yMzOc" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1739232580; 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=SC2AHH3WB3DgFq91dBs/pGAOq1gu4zCMKsPmbplWkrQ=; b=fk1yMzOcaofpSpWVPQEYV7ispcRdAzCxS26JDiMDNA/KLLXKBdj+9dBL2DV/fdDCEnlSc8 EuZ2q33k834tKNJdkAr2Ue8/sjhY17rLG0AWtUjLIyAyvAHpxzXgNFkIl5T5NWM0YoPYHa eUK6M4RfePyT1aqWbZ+KJPGG0+WQWKk= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-681-l5dGL4BmNTSqW9uWH99yTQ-1; Mon, 10 Feb 2025 19:09:36 -0500 X-MC-Unique: l5dGL4BmNTSqW9uWH99yTQ-1 X-Mimecast-MFC-AGG-ID: l5dGL4BmNTSqW9uWH99yTQ Received: from mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.40]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 7E5001800268; Tue, 11 Feb 2025 00:09:32 +0000 (UTC) Received: from starship.lan (unknown [10.22.65.174]) by mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E1A6819560AF; Tue, 11 Feb 2025 00:09:25 +0000 (UTC) From: Maxim Levitsky To: kvm@vger.kernel.org Cc: Paolo Bonzini , Jing Zhang , Oliver Upton , linux-arm-kernel@lists.infradead.org, Marc Zyngier , linux-kernel@vger.kernel.org, Randy Dunlap , Suzuki K Poulose , Palmer Dabbelt , Zenghui Yu , kvm-riscv@lists.infradead.org, Ingo Molnar , linux-riscv@lists.infradead.org, Joey Gouly , Paul Walmsley , Maxim Levitsky , Thomas Gleixner , Bjorn Helgaas , Albert Ou , kvmarm@lists.linux.dev, Alexander Potapenko , x86@kernel.org, Sean Christopherson , Anup Patel , Kunkun Jiang , Atish Patra , Catalin Marinas , Will Deacon , Borislav Petkov , Dave Hansen , "H. Peter Anvin" Subject: [PATCH 1/3] KVM: x86: move sev_lock/unlock_vcpus_for_migration to kvm_main.c Date: Mon, 10 Feb 2025 19:09:15 -0500 Message-Id: <20250211000917.166856-2-mlevitsk@redhat.com> In-Reply-To: <20250211000917.166856-1-mlevitsk@redhat.com> References: <20250211000917.166856-1-mlevitsk@redhat.com> Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.40 Move sev_lock/unlock_vcpus_for_migration to kvm_main and call the new functions the kvm_lock_all_vcpus/kvm_unlock_all_vcpus and kvm_lock_all_vcpus_nested. This code allows to lock all vCPUs without triggering lockdep warning about reaching MAX_LOCK_DEPTH depth by coercing the lockdep into thinking that we release all the locks other than vcpu'0 lock immediately after we take them. No functional change intended. Suggested-by: Paolo Bonzini Signed-off-by: Maxim Levitsky --- arch/x86/kvm/svm/sev.c | 65 +++---------------------------------- include/linux/kvm_host.h | 6 ++++ virt/kvm/kvm_main.c | 69 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 61 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index a2a794c32050..5ba1dd61aff0 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -1909,63 +1909,6 @@ enum sev_migration_role { SEV_NR_MIGRATION_ROLES, }; -static int sev_lock_vcpus_for_migration(struct kvm *kvm, - enum sev_migration_role role) -{ - struct kvm_vcpu *vcpu; - unsigned long i, j; - - kvm_for_each_vcpu(i, vcpu, kvm) { - if (mutex_lock_killable_nested(&vcpu->mutex, role)) - goto out_unlock; - -#ifdef CONFIG_PROVE_LOCKING - if (!i) - /* - * Reset the role to one that avoids colliding with - * the role used for the first vcpu mutex. - */ - role = SEV_NR_MIGRATION_ROLES; - else - mutex_release(&vcpu->mutex.dep_map, _THIS_IP_); -#endif - } - - return 0; - -out_unlock: - - kvm_for_each_vcpu(j, vcpu, kvm) { - if (i == j) - break; - -#ifdef CONFIG_PROVE_LOCKING - if (j) - mutex_acquire(&vcpu->mutex.dep_map, role, 0, _THIS_IP_); -#endif - - mutex_unlock(&vcpu->mutex); - } - return -EINTR; -} - -static void sev_unlock_vcpus_for_migration(struct kvm *kvm) -{ - struct kvm_vcpu *vcpu; - unsigned long i; - bool first = true; - - kvm_for_each_vcpu(i, vcpu, kvm) { - if (first) - first = false; - else - mutex_acquire(&vcpu->mutex.dep_map, - SEV_NR_MIGRATION_ROLES, 0, _THIS_IP_); - - mutex_unlock(&vcpu->mutex); - } -} - static void sev_migrate_from(struct kvm *dst_kvm, struct kvm *src_kvm) { struct kvm_sev_info *dst = &to_kvm_svm(dst_kvm)->sev_info; @@ -2104,10 +2047,10 @@ int sev_vm_move_enc_context_from(struct kvm *kvm, unsigned int source_fd) charged = true; } - ret = sev_lock_vcpus_for_migration(kvm, SEV_MIGRATION_SOURCE); + ret = kvm_lock_all_vcpus_nested(kvm, SEV_MIGRATION_SOURCE); if (ret) goto out_dst_cgroup; - ret = sev_lock_vcpus_for_migration(source_kvm, SEV_MIGRATION_TARGET); + ret = kvm_lock_all_vcpus_nested(source_kvm, SEV_MIGRATION_TARGET); if (ret) goto out_dst_vcpu; @@ -2121,9 +2064,9 @@ int sev_vm_move_enc_context_from(struct kvm *kvm, unsigned int source_fd) ret = 0; out_source_vcpu: - sev_unlock_vcpus_for_migration(source_kvm); + kvm_unlock_all_vcpus(source_kvm); out_dst_vcpu: - sev_unlock_vcpus_for_migration(kvm); + kvm_unlock_all_vcpus(kvm); out_dst_cgroup: /* Operates on the source on success, on the destination on failure. */ if (charged) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index f34f4cfaa513..14b4a2a6f8e6 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1014,6 +1014,12 @@ static inline struct kvm_vcpu *kvm_get_vcpu_by_id(struct kvm *kvm, int id) void kvm_destroy_vcpus(struct kvm *kvm); +int kvm_lock_all_vcpus_nested(struct kvm *kvm, unsigned int role); +void kvm_unlock_all_vcpus(struct kvm *kvm); + +#define kvm_lock_all_vcpus(kvm) \ + kvm_lock_all_vcpus_nested(kvm, 0) + void vcpu_load(struct kvm_vcpu *vcpu); void vcpu_put(struct kvm_vcpu *vcpu); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index ba0327e2d0d3..f233a79af799 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1354,6 +1354,75 @@ static int kvm_vm_release(struct inode *inode, struct file *filp) return 0; } + +/* + * Lock all VM vCPUs. + * Can be used nested (to lock vCPUS of two VMs for example) + */ + +int kvm_lock_all_vcpus_nested(struct kvm *kvm, unsigned int role) +{ + struct kvm_vcpu *vcpu; + unsigned long i, j; + + lockdep_assert_held(&kvm->lock); + + kvm_for_each_vcpu(i, vcpu, kvm) { + if (mutex_lock_killable_nested(&vcpu->mutex, role)) + goto out_unlock; + +#ifdef CONFIG_PROVE_LOCKING + if (!i) + /* + * Reset the role to one that avoids colliding with + * the role used for the first vcpu mutex. + */ + role = MAX_LOCK_DEPTH - 1; + else + mutex_release(&vcpu->mutex.dep_map, _THIS_IP_); +#endif + } + + return 0; + +out_unlock: + + kvm_for_each_vcpu(j, vcpu, kvm) { + if (i == j) + break; + +#ifdef CONFIG_PROVE_LOCKING + if (j) + mutex_acquire(&vcpu->mutex.dep_map, role, 0, _THIS_IP_); +#endif + + mutex_unlock(&vcpu->mutex); + } + return -EINTR; +} +EXPORT_SYMBOL_GPL(kvm_lock_all_vcpus_nested); + +void kvm_unlock_all_vcpus(struct kvm *kvm) +{ + struct kvm_vcpu *vcpu; + unsigned long i; + bool first = true; + + lockdep_assert_held(&kvm->lock); + + kvm_for_each_vcpu(i, vcpu, kvm) { + if (first) + first = false; + else + mutex_acquire(&vcpu->mutex.dep_map, + MAX_LOCK_DEPTH - 1, 0, _THIS_IP_); + + mutex_unlock(&vcpu->mutex); + } +} +EXPORT_SYMBOL_GPL(kvm_unlock_all_vcpus); + + /* * Allocation size is twice as large as the actual dirty bitmap size. * See kvm_vm_ioctl_get_dirty_log() why this is needed.