From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 0340D2210FB; Thu, 12 Dec 2024 15:50:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734018608; cv=none; b=MqSLgReEuNujxGDujsrRdvL58bZ/TCT331a44zbDxYbSA0JKXXewJP/HcvpTGtzkBKzEi1gT3I1+HDVk0xwKkzG4BWEa7WBr5yXt4a+fvYFwSc16qzQmAiYh9jtHPv+H7WkQKjEhOmf+a2okEBYwfJOHuOYoWL15DDUBAzOU5ro= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734018608; c=relaxed/simple; bh=Ur6ftnyB/QQ78ChHaGW1prAuGYrt/N622iIhqsgAINU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Xtl3Vp75G6XZBUwoMLxi7F140HjxG0hm+1VoazW3pLZu+7S93efMSzPf5PxnKe6GC6IJ6mQrUlWqZGeSNHHaZS2EaYoKBW/ESfEvr/1xnhbrzfnZw3XBOuaIx6ca235+ZhiLNd7jH2dQ1ca8Pzy8nfkroMIMki/gKiBG8V5fn8o= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b=gm8YFzgb; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b="gm8YFzgb" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4C343C4CECE; Thu, 12 Dec 2024 15:50:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1734018607; bh=Ur6ftnyB/QQ78ChHaGW1prAuGYrt/N622iIhqsgAINU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gm8YFzgbxMHxC6D2x8nFfYUmnfc5c73MvAhd0Atd7ZX0Pbh+fiiNXLKr8p2kgj80F A/UvCRqlQQEsmzik3bcQiy1b9JjyNWY/KdOQgc3suhy0ipTP9rlqoG/KESQAT2Ltcm o2PTBcUaEGjGFbxS7oCGalEAR38U6Hy/Jbs/wZVo= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Sean Christopherson , Nikolay Kuratov Subject: [PATCH 6.6 339/356] KVM: x86/mmu: Ensure that kvm_release_pfn_clean() takes exact pfn from kvm_faultin_pfn() Date: Thu, 12 Dec 2024 16:00:58 +0100 Message-ID: <20241212144257.961358183@linuxfoundation.org> X-Mailer: git-send-email 2.47.1 In-Reply-To: <20241212144244.601729511@linuxfoundation.org> References: <20241212144244.601729511@linuxfoundation.org> User-Agent: quilt/0.67 X-stable: review X-Patchwork-Hint: ignore Precedence: bulk X-Mailing-List: stable@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 6.6-stable review patch. If anyone has any objections, please let me know. ------------------ From: Nikolay Kuratov Since 5.16 and prior to 6.13 KVM can't be used with FSDAX guest memory (PMD pages). To reproduce the issue you need to reserve guest memory with `memmap=` cmdline, create and mount FS in DAX mode (tested both XFS and ext4), see doc link below. ndctl command for test: ndctl create-namespace -v -e namespace1.0 --map=dev --mode=fsdax -a 2M Then pass memory object to qemu like: -m 8G -object memory-backend-file,id=ram0,size=8G,\ mem-path=/mnt/pmem/guestmem,share=on,prealloc=on,dump=off,align=2097152 \ -numa node,memdev=ram0,cpus=0-1 QEMU fails to run guest with error: kvm run failed Bad address and there are two warnings in dmesg: WARN_ON_ONCE(!page_count(page)) in kvm_is_zone_device_page() and WARN_ON_ONCE(folio_ref_count(folio) <= 0) in try_grab_folio() (v6.6.63) It looks like in the past assumption was made that pfn won't change from faultin_pfn() to release_pfn_clean(), e.g. see commit 4cd071d13c5c ("KVM: x86/mmu: Move calls to thp_adjust() down a level") But kvm_page_fault structure made pfn part of mutable state, so now release_pfn_clean() can take hugepage-adjusted pfn. And it works for all cases (/dev/shm, hugetlb, devdax) except fsdax. Apparently in fsdax mode faultin-pfn and adjusted-pfn may refer to different folios, so we're getting get_page/put_page imbalance. To solve this preserve faultin pfn in separate local variable and pass it in kvm_release_pfn_clean(). Patch tested for all mentioned guest memory backends with tdp_mmu={0,1}. No bug in upstream as it was solved fundamentally by commit 8dd861cc07e2 ("KVM: x86/mmu: Put refcounted pages instead of blindly releasing pfns") and related patch series. Link: https://nvdimm.docs.kernel.org/2mib_fs_dax.html Fixes: 2f6305dd5676 ("KVM: MMU: change kvm_tdp_mmu_map() arguments to kvm_page_fault") Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson Reviewed-by: Sean Christopherson Signed-off-by: Nikolay Kuratov Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/mmu/mmu.c | 10 ++++++++-- arch/x86/kvm/mmu/paging_tmpl.h | 5 ++++- 2 files changed, 12 insertions(+), 3 deletions(-) --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -4363,6 +4363,7 @@ static bool is_page_fault_stale(struct k static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) { + kvm_pfn_t orig_pfn; int r; /* Dummy roots are used only for shadowing bad guest roots. */ @@ -4384,6 +4385,8 @@ static int direct_page_fault(struct kvm_ if (r != RET_PF_CONTINUE) return r; + orig_pfn = fault->pfn; + r = RET_PF_RETRY; write_lock(&vcpu->kvm->mmu_lock); @@ -4398,7 +4401,7 @@ static int direct_page_fault(struct kvm_ out_unlock: write_unlock(&vcpu->kvm->mmu_lock); - kvm_release_pfn_clean(fault->pfn); + kvm_release_pfn_clean(orig_pfn); return r; } @@ -4447,6 +4450,7 @@ EXPORT_SYMBOL_GPL(kvm_handle_page_fault) static int kvm_tdp_mmu_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) { + kvm_pfn_t orig_pfn; int r; if (page_fault_handle_page_track(vcpu, fault)) @@ -4464,6 +4468,8 @@ static int kvm_tdp_mmu_page_fault(struct if (r != RET_PF_CONTINUE) return r; + orig_pfn = fault->pfn; + r = RET_PF_RETRY; read_lock(&vcpu->kvm->mmu_lock); @@ -4474,7 +4480,7 @@ static int kvm_tdp_mmu_page_fault(struct out_unlock: read_unlock(&vcpu->kvm->mmu_lock); - kvm_release_pfn_clean(fault->pfn); + kvm_release_pfn_clean(orig_pfn); return r; } #endif --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -777,6 +777,7 @@ out_gpte_changed: static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) { struct guest_walker walker; + kvm_pfn_t orig_pfn; int r; WARN_ON_ONCE(fault->is_tdp); @@ -835,6 +836,8 @@ static int FNAME(page_fault)(struct kvm_ walker.pte_access &= ~ACC_EXEC_MASK; } + orig_pfn = fault->pfn; + r = RET_PF_RETRY; write_lock(&vcpu->kvm->mmu_lock); @@ -848,7 +851,7 @@ static int FNAME(page_fault)(struct kvm_ out_unlock: write_unlock(&vcpu->kvm->mmu_lock); - kvm_release_pfn_clean(fault->pfn); + kvm_release_pfn_clean(orig_pfn); return r; }