From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.remote-ip=100.103.45.18 ARC-Seal: i=2; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=fail; t=1792711693; b=pQGOilMCkvZUer9RmNODfGpCOFVoUcHXq36R+bLfjNu45aAqXveRYSO6CBJD6Ldt8vfL i8LcKKfGBRlvjeNXIio9l7DUubgT37QVhI4osV5T1PVW4MyHLYMmTKF32Y2BpkZYJHfgx v6pU1vBPbcwSyer9dtEXMCRVqn33HjkavWgIEqPvCTS34GSmG0IsBbTPVGfaFA0kdj5SR Z82h9AAShQxAAll3/bVG8otbDiJSAOMnbgeT65u/w7oWrZHS+xOEtujQMq1/NKIxwfOIZ 1h4IOvXpKfVVIm9neNuZ8gcIqA5liklk4S2QxXYY958tVlW5I+fc33eaKh0dwocHkaQ== ARC-Message-Signature: i=2; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1792711693; h=Received:DKIM-Signature:Received:From:Date:Subject:MIME-Version: Content-Type:Message-Id:References:In-Reply-To:To:Cc:X-Mailer: X-Developer-Signature:X-Developer-Key:X-Endpoint-Received: X-Original-From:Reply-To:Content-Transfer-Encoding; bh=/ahL4TP/omD5Vlmg3sgYIZkznIxNyj2E4z7Lb7O0L7o=; b=et/2zWN5dco52nz+HLa4I7Ivoq1urj1eTev3hZMqh6CXyNpawDZfjS1lNysMhULCRNnG QJ/3aHBkTB6s8nyUlUeIUjXkOGmJb++daqkBnCsPXE8cZCE51+etox6L7FYuA7a1cIYyY FL7Kv/+nly8jUTY7h2YTgY5m51ynS4pXIuHiNlIjozU4kxRNAcCwJiIaweD4EESYWlV07 3Kfa16FT+OMrWosxjJUkk+cIzQoDwnkD6A/rqujSt5GfE5I0HonfatGGFr07qtwSDlEf+ ztkE+k3aaBG3bvDnlE+OGpimKzz4JOKvCjMZqBcD2qwTKn97fe8LeXESP1cbp+0HO+w== ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dkim=pass header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=akznfBkv; arc=fail smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6BD07606E792; Thu, 22 Oct 2026 23:28:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=akznfBkv Authentication-Results: smtp.kernel.org; arc=none smtp.remote-ip=100.80.115.77 ARC-Seal: i=1; d=kernel.org; s=arc20260519; a=rsa-sha256; cv=none; t=1792711693; b=aQ/2lHoCNowyTs4+qDuz50kZmQGsrjj85kFi0K39nfswxuDu3ocflxFzurouJJMeeScw uzAkxkggNPgKMCDs+OhsYHbxJv8IyQxb3tjNfujJRoujYF0DRuwJIkDcNriOCxdPGYtRt C7QFflyMVdxOKpTd4FSbiGWeMd2fBMx3Pjp/8zjrR8rzX+mAWI04BE7ROnf9ob3ZUzXDa EzHltIu4c+4XdOgHIvQFKeY5oQprcwqGiYmMUR+7e2UOkBerZNv1dx9kEMO/Uo+dU7o2B zN5vp72Jamq0Mpp0IgTvPg54n4qDtvd3zjhVoatAxb81f8uKuQ64y877zp1ZuufH81w== ARC-Message-Signature: i=1; d=kernel.org; s=arc20260519; a=rsa-sha256; c=relaxed/relaxed; t=1792711693; h=DKIM-Signature:Received:From:Date:Subject:MIME-Version:Content-Type: Message-Id:References:In-Reply-To:To:Cc:X-Mailer: X-Developer-Signature:X-Developer-Key:X-Endpoint-Received: X-Original-From:Reply-To:Content-Transfer-Encoding; bh=/ahL4TP/omD5Vlmg3sgYIZkznIxNyj2E4z7Lb7O0L7o=; b=WENU9fIDjSZu5lPd+8BlQsV4LXc3b7uaebcrUKHNVz1Pwb0wsReHa4wvlAclYeW/6H8A WK8hrJUVUOT0k1PVbgp41hSMqKLm0No9a7JkdKHax7NwBM9GUb/IvWrbEZ85HIjs9/xu6 6GuGW+N9B/JqPU06juQ06aTlPCYbNKr+jNdLRAYVQHJxOFXC1F+nPeUJr4mrew7/kKJFy r8oKD/BCkTj+iBCLM78E3xb7Pe1za3HrOBY+BoJchDx8l7cEFauZuk8vpfLSBzGW4/UjI PqSH6U1QRp0HKshHlOBQKHTx+mAqrpWLM5Zpttt1c7TFP6Wn2kSpeGn1IXqNltKUUSA== ARC-Authentication-Results: i=1; smtp.kernel.org; arc=none smtp.remote-ip=100.80.115.77 Received: from lkml.kernel.org (nexus.subspace.kernel.org [100.80.115.77]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.kernel.org (Postfix) with ESMTPS id 8FF561F01180; Thu, 22 Oct 2026 23:28:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1792711693; bh=/ahL4TP/omD5Vlmg3sgYIZkznIxNyj2E4z7Lb7O0L7o=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To; b=akznfBkvda1EdCIgc0eTx9SRFSTr4nATaEn74QtSOTL86CsikVlWtlBIQ+Bn9L4Om Drma/nw1sXBRwyXpVLgOPmaxK29E3ZaHlN3TYkz3wYT4d3nWsl7Pm7e91Os/d9ZlMl /bu5e+hCkEjrFgA8ViyBvVwMfWBmNOvsXNgtskfZ9kmlh10uCjuPK9J39Z9i3seTyc JLbh2aW/boGfbP7HWRy+7rJsFcpuLwYBGRv9KTDI/N9utZ+aERyNXEBaOjhZXpyS6r t3fldebW3ujBUfqVScQCQH1pwogeo6N0M9kqsKhXaVk8wmFrD1kK/sqyQIKUJP2put NUb1rZQbHzmjA== Received: from nexus.subspace.kernel.org (localhost [IPv6:::1]) by lkml.kernel.org (Postfix) with ESMTP id BE966420C0; Thu, 22 Oct 2026 23:27:49 +0000 (UTC) From: Ackerley Tng via B4 Relay Date: Thu, 22 Oct 2026 16:28:03 -0700 Subject: [PATCH RFC v2 31/50] KVM: guest_memfd: Support getting PFNs for stage 2 from providers X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Message-Id: <20261022-gmem-alternative-providers-v2-31-5dd1dc6c660a@google.com> References: <20261022-gmem-alternative-providers-v2-0-5dd1dc6c660a@google.com> In-Reply-To: <20261022-gmem-alternative-providers-v2-0-5dd1dc6c660a@google.com> To: Alex Williamson , Alexander Graf , Alexander Viro , Alexey Kardashevskiy , Andrew Morton , "Aneesh Kumar K.V" , Ashish Kalra , Baolin Wang , Baolu Lu , Bill Wendling , Borislav Petkov , Catalin Marinas , Christian Brauner , =?utf-8?q?Christian_K=C3=B6nig?= , Connor Williamson , Dave Hansen , Dave Jiang , David Hildenbrand , David Rientjes , David Woodhouse , Erdem Aktas , Frank van der Linden , Fred Griffoul , Fred Griffoul , Gregory Price , "H. Peter Anvin" , Hugh Dickins , Ingo Molnar , Jacob Pan , James Houghton , Jan Kara , Jason Gunthorpe , Jianxiong Gao , Joerg Roedel , Joey Gouly , John Starks , Jonathan Corbet , Justin Stitt , Kevin Tian , Lorenzo Stoakes , Marc Zyngier , Michael Roth , Mike Rapoport , Nathan Chancellor , Nick Desaulniers , Nicolin Chen , Oliver Upton , Paolo Bonzini , Pratyush Yadav , Randy Dunlap , Robin Murphy , Samiullah Khawaja , Sean Christopherson , Shuah Khan , Steffen Eiden , Steven Price , Suzuki K Poulose , Tarun Sahu , Thomas Gleixner , Tom Lendacky , Tycho Andersen , Vishal Annapurve , Vlastimil Babka , Will Deacon , Xu Yilun , Yan Zhao , Zenghui Yu , x86@kernel.org, Shuah Khan , Fuad Tabba Cc: kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org, llvm@lists.linux.dev, Ackerley Tng X-Mailer: b4 0.17-dev X-Developer-Signature: v=1; a=ed25519-sha256; t=1792711665; l=6020; i=ackerleytng@google.com; s=20260225; h=from:subject:message-id; bh=jEkr/nY1nFVQLtsltdN4AJnwp36Iu4m7TarLTGyPZVc=; b=vAkluFarmlZI1TwtSGhLOd+jHlS0DLSrWj3cCriODu55Bs8Tz1V4Ot2NifETUEWZCMUMWV2GD CtaY4a2NaZCCpOvCQwRHzJ6wEKfOMC4mO8bqs82RiiNQXQnqSLT2A0P X-Developer-Key: i=ackerleytng@google.com; a=ed25519; pk=sAZDYXdm6Iz8FHitpHeFlCMXwabodTm7p8/3/8xUxuU= X-Endpoint-Received: by B4 Relay for ackerleytng@google.com/20260225 with auth_id=649 X-Original-From: Ackerley Tng Reply-To: ackerleytng@google.com Content-Transfer-Encoding: 7bit From: Ackerley Tng Add .get_pfn callback to struct guest_memfd_provider_operations to support physical memory providers (e.g. devices, DAX, or pre-allocated ranges) that supply PFNs directly without folio allocation or page cache insertion. Define GUEST_MEMFD_FLAG_PFN_MODE in uapi/linux/kvm.h and define kvm_gmem_is_pfn_mode() to check for this flag in gi->flags. In __kvm_gmem_get_pfn(), query .get_pfn() directly when in PFN mode and return NULL on success (instead of a struct folio *). Note that .alloc_folio is still required by kvm_gmem_attach_resource() and GUEST_MEMFD_FLAG_PFN_MODE is not yet enabled for userspace. Subsequent patches will update the rest of guest_memfd (e.g. mmap, fallocate, truncation, and attributes) to support PFN mode before enabling the flag and allowing external PFN-backed providers to be attached. Signed-off-by: Ackerley Tng --- include/linux/guest_memfd.h | 8 ++++++++ include/uapi/linux/kvm.h | 1 + virt/kvm/guest_memfd.c | 42 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/include/linux/guest_memfd.h b/include/linux/guest_memfd.h index f3e6077c39ac3..10c48f41a6d7e 100644 --- a/include/linux/guest_memfd.h +++ b/include/linux/guest_memfd.h @@ -18,6 +18,12 @@ struct mempolicy; * Must return a pointer to a struct folio on success, or an * ERR_PTR() error code on failure. Must never return NULL. * @invalidate_folio: Notify provider that a folio has been invalidated. + * @get_pfn: Obtain a PFN for a given index. The provider must ensure backing + * memory is present and is responsible for its contents, such as + * zeroing if necessary. On success, return 0 with the physical frame + * number in @pfn and, if @max_order is non-NULL, the maximum page + * order of contiguous backing memory containing @pfn. Returns a + * negative error code on failure. * * Used by filesystems and device drivers that provide memory for guest_memfd. */ @@ -27,6 +33,8 @@ struct guest_memfd_provider_operations { struct folio *(*alloc_folio)(void *provider, pgoff_t index, struct mempolicy *mpol); void (*invalidate_folio)(void *provider, struct folio *folio); + int (*get_pfn)(void *provider, pgoff_t index, unsigned long *pfn, + int *max_order); }; #endif /* _LINUX_GUEST_MEMFD_H */ diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index f4108bf7e3192..6798056f50e32 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1675,6 +1675,7 @@ struct kvm_memory_attributes2 { #define GUEST_MEMFD_FLAG_MMAP (1ULL << 0) #define GUEST_MEMFD_FLAG_INIT_SHARED (1ULL << 1) #define GUEST_MEMFD_FLAG_USE_RESOURCE (1ULL << 2) +#define GUEST_MEMFD_FLAG_PFN_MODE (1ULL << 3) struct kvm_create_guest_memfd { __u64 size; diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c index 84877beed6701..3d89bc76f3867 100644 --- a/virt/kvm/guest_memfd.c +++ b/virt/kvm/guest_memfd.c @@ -54,6 +54,11 @@ static __always_inline struct gmem_inode *GMEM_I(struct inode *inode) return container_of(inode, struct gmem_inode, vfs_inode); } +static bool kvm_gmem_is_pfn_mode(struct gmem_inode *gi) +{ + return gi->flags & GUEST_MEMFD_FLAG_PFN_MODE; +} + static void *gmem_native_attach(struct inode *gmem_inode, struct file *resource_file) { @@ -124,6 +129,20 @@ static struct folio *gmem_provider_alloc_folio(struct gmem_inode *gi, return ERR_PTR(-EOPNOTSUPP); } +static int gmem_provider_get_pfn(struct gmem_inode *gi, pgoff_t index, + kvm_pfn_t *pfn, int *max_order) +{ + unsigned long raw_pfn; + int r; + + r = gi->provider_ops->get_pfn(gi->provider, index, &raw_pfn, max_order); + if (r) + return r; + + *pfn = raw_pfn; + return 0; +} + static void gmem_provider_invalidate_folio(struct gmem_inode *gi, struct folio *folio) { @@ -1270,15 +1289,17 @@ void kvm_gmem_unbind(struct kvm_memory_slot *slot) filemap_invalidate_unlock(file->f_mapping); } -/* Returns a locked folio on success. */ +/* On success, return a locked folio in folio mode and NULL in PFN mode. */ static struct folio *__kvm_gmem_get_pfn(struct file *file, struct kvm_memory_slot *slot, pgoff_t index, kvm_pfn_t *pfn, int *max_order) { struct file *slot_file = READ_ONCE(slot->gmem.file); + struct gmem_inode *gi = GMEM_I(file_inode(file)); struct gmem_file *f = file->private_data; struct folio *folio; + int r; if (file != slot_file) { WARN_ON_ONCE(slot_file); @@ -1290,6 +1311,13 @@ static struct folio *__kvm_gmem_get_pfn(struct file *file, return ERR_PTR(-EIO); } + if (kvm_gmem_is_pfn_mode(gi)) { + r = gmem_provider_get_pfn(gi, index, pfn, max_order); + if (r) + return ERR_PTR(r); + return NULL; + } + folio = kvm_gmem_get_folio(file_inode(file), index); if (IS_ERR(folio)) return folio; @@ -1338,8 +1366,10 @@ int kvm_gmem_get_pfn(struct kvm *kvm, struct kvm_memory_slot *slot, r = kvm_arch_gmem_make_private(kvm, gfn, *pfn, (kvm_pfn_t)1 << *max_order); - folio_unlock(folio); - folio_put(folio); + if (folio) { + folio_unlock(folio); + folio_put(folio); + } out: filemap_invalidate_unlock_shared(file_inode(file)->i_mapping); @@ -1366,7 +1396,8 @@ static long __kvm_gmem_populate(struct kvm *kvm, struct kvm_memory_slot *slot, goto out_unlock; } - folio_unlock(folio); + if (folio) + folio_unlock(folio); if (!kvm_is_private_gfn(kvm, gfn)) { ret = -EINVAL; @@ -1376,7 +1407,8 @@ static long __kvm_gmem_populate(struct kvm *kvm, struct kvm_memory_slot *slot, ret = post_populate(kvm, gfn, pfn, src_page, opaque); out_put_folio: - folio_put(folio); + if (folio) + folio_put(folio); out_unlock: filemap_invalidate_unlock(file->f_mapping); return ret; -- 2.56.0.257.gf7497c7d27-goog