From: "Aneesh Kumar K.V (Arm)" <aneesh.kumar@kernel.org>
To: linux-coco@lists.linux.dev
Cc: "Aneesh Kumar K.V (Arm)" <aneesh.kumar@kernel.org>,
Ackerley Tng <ackerleytng@google.com>,
David Woodhouse <dwmw2@infradead.org>,
David Hildenbrand <david@kernel.org>,
Jason Gunthorpe <jgg@ziepe.ca>, Kevin Tian <kevin.tian@intel.com>,
Paolo Bonzini <pbonzini@redhat.com>,
Sean Christopherson <seanjc@google.com>,
Alexey Kardashevskiy <aik@amd.com>,
Xu Yilun <yilun.xu@linux.intel.com>,
Catalin Marinas <catalin.marinas@arm.com>,
Suzuki K Poulose <suzuki.poulose@arm.com>,
Steven Price <steven.price@arm.com>,
Fred Griffoul <griffoul@gmail.com>,
iommu@lists.linux.dev, kvm@vger.kernel.org,
patches@lists.linux.dev
Subject: [RFC PATCH v5 04/16] KVM: guest_memfd: Add provider PFN range lookup
Date: Thu, 12 Nov 2026 13:11:08 +0530 [thread overview]
Message-ID: <20261112074120.1570072-5-aneesh.kumar@kernel.org> (raw)
In-Reply-To: <20261112074120.1570072-1-aneesh.kumar@kernel.org>
Provide nonallocating folio range lookup and carry PFN attributes separately
from requested KVM memory attributes
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
include/linux/guest_memfd.h | 10 ++++--
samples/kvm/mem_provider_sample.c | 6 ++--
virt/kvm/guest_memfd.c | 60 ++++++++++++++++++++++++++-----
3 files changed, 63 insertions(+), 13 deletions(-)
diff --git a/include/linux/guest_memfd.h b/include/linux/guest_memfd.h
index b63ca59773f9..d3b153a3d891 100644
--- a/include/linux/guest_memfd.h
+++ b/include/linux/guest_memfd.h
@@ -60,7 +60,10 @@ struct guest_memfd_handle {
* is present. If backing memory is not available, return
* -ENOENT. Return a negative error code on other failure.
* The provider must define @get_pfn when @lookup_pfn_range
- * is defined.
+ * is defined, or omit both to use the folio helper.
+ * Lookup must not allocate memory or prepare it for access.
+ * PFNs remain stable under the inode invalidate lock and
+ * any provider lock held by conversion/reclaim callers.
* @put_pfn_range: Release a range of PFNs previously obtained for a given
* index. The provider does not need to ensure that backing
* memory is present. If backing memory is not available, the
@@ -79,8 +82,9 @@ struct guest_memfd_provider_operations {
void (*invalidate_folio)(void *provider, struct folio *folio);
int (*get_pfn)(struct inode *inode, void *provider, pgoff_t index,
struct guest_memfd_handle *handle);
- int (*lookup_pfn_range)(void *provider, pgoff_t index,
- unsigned long *pfn, size_t *nr_pages);
+ int (*lookup_pfn_range)(struct inode *inode, void *provider, pgoff_t index,
+ unsigned long *pfn, size_t *nr_pages,
+ u64 *pfn_attrs);
void (*put_pfn_range)(void *provider, pgoff_t index, size_t nr_pages);
};
diff --git a/samples/kvm/mem_provider_sample.c b/samples/kvm/mem_provider_sample.c
index f1b0698268c0..8eca914c49ef 100644
--- a/samples/kvm/mem_provider_sample.c
+++ b/samples/kvm/mem_provider_sample.c
@@ -197,8 +197,9 @@ static int mps_gmem_get_pfn(struct inode *inode, void *provider,
return 0;
}
-static int mps_gmem_lookup_pfn_range(void *provider, pgoff_t index,
- unsigned long *pfn, size_t *nr_pages)
+static int mps_gmem_lookup_pfn_range(struct inode *inode, void *provider,
+ pgoff_t index, unsigned long *pfn,
+ size_t *nr_pages, u64 *pfn_attrs)
{
struct file *resource_file = provider;
struct mps_info *info = resource_file->private_data;
@@ -211,6 +212,7 @@ static int mps_gmem_lookup_pfn_range(void *provider, pgoff_t index,
*pfn = info->base_pfn + index;
*nr_pages = 1;
+ *pfn_attrs = 0;
return 0;
}
diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index 5fda14a53488..ad9cc1bbe5d7 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -52,6 +52,8 @@ struct gmem_inode {
static int gmem_folio_get_pfn(struct inode *inode, void *provider, pgoff_t index,
struct guest_memfd_handle *handle);
+static int gmem_folio_lookup_pfn_range(struct inode *inode, void *provider,
+ pgoff_t index, unsigned long *pfn, size_t *nr_pages, u64 *pfn_attrs);
static __always_inline struct gmem_inode *GMEM_I(struct inode *inode)
{
@@ -88,6 +90,7 @@ static const struct guest_memfd_provider_operations gmem_native_provider_ops = {
.attach = gmem_native_attach,
.alloc_folio = gmem_native_alloc_folio,
.get_pfn = gmem_folio_get_pfn,
+ .lookup_pfn_range = gmem_folio_lookup_pfn_range,
};
static bool gmem_provider_ops_valid(struct gmem_inode *gi,
@@ -129,8 +132,10 @@ static void gmem_provider_init_ops(struct gmem_inode *gi,
{
gi->provider_operations = *ops;
if (ops->alloc_folio) {
- if (!ops->get_pfn)
+ if (!ops->get_pfn) {
gi->provider_operations.get_pfn = gmem_folio_get_pfn;
+ gi->provider_operations.lookup_pfn_range = gmem_folio_lookup_pfn_range;
+ }
}
gi->provider_ops = &gi->provider_operations;
}
@@ -239,13 +244,15 @@ static void gmem_put_handle(struct guest_memfd_handle *handle)
#if defined(CONFIG_HAVE_KVM_ARCH_GMEM_CONVERT) || defined(CONFIG_HAVE_KVM_ARCH_GMEM_RECLAIM)
static int gmem_provider_lookup_pfn_range(struct gmem_inode *gi, pgoff_t index,
- kvm_pfn_t *pfn, size_t *nr_pages)
+ kvm_pfn_t *pfn, size_t *nr_pages, u64 *pfn_attrs)
{
unsigned long raw_pfn;
int r;
- r = gi->provider_ops->lookup_pfn_range(gi->provider, index, &raw_pfn,
- nr_pages);
+ /* Initialize the length in case an error leaves it unset by the provider. */
+ *nr_pages = 0;
+ r = gi->provider_ops->lookup_pfn_range(&gi->vfs_inode, gi->provider, index, &raw_pfn,
+ nr_pages, pfn_attrs);
if (r)
return r;
@@ -433,6 +440,38 @@ static struct folio *kvm_gmem_get_folio(struct inode *inode, pgoff_t index)
return folio;
}
+/* Conversion holds invalidate_lock for write, excluding truncation/allocation. */
+static int gmem_folio_lookup_pfn_range(struct inode *inode, void *provider,
+ pgoff_t index, unsigned long *pfn, size_t *nr_pages, u64 *pfn_attrs)
+{
+ struct folio *folio;
+
+ lockdep_assert_held_write(&inode->i_mapping->invalidate_lock);
+ folio = filemap_get_folio(inode->i_mapping, index);
+ if (IS_ERR(folio)) {
+ struct folio_batch fbatch;
+ pgoff_t end = i_size_read(inode) >> PAGE_SHIFT;
+ pgoff_t next = index;
+
+ if (PTR_ERR(folio) != -ENOENT)
+ return PTR_ERR(folio);
+
+ folio_batch_init(&fbatch);
+ if (filemap_get_folios(inode->i_mapping, &next, end - 1, &fbatch)) {
+ end = fbatch.folios[0]->index;
+ folio_batch_release(&fbatch);
+ }
+ *nr_pages = end - index;
+ return -ENOENT;
+ }
+
+ *pfn = folio_file_pfn(folio, index);
+ *nr_pages = folio_next_index(folio) - index;
+ *pfn_attrs = 0;
+ folio_put(folio);
+ return 0;
+}
+
static enum kvm_gfn_range_filter kvm_gmem_get_all_gfns_filter(struct inode *inode)
{
if (gmem_in_place_conversion)
@@ -525,11 +564,14 @@ static void kvm_gmem_pfn_reclaim(struct gmem_inode *gi, pgoff_t start, pgoff_t e
size_t step = 1;
size_t nr_pages;
kvm_pfn_t pfn;
+ u64 pfn_attrs;
+ int ret;
- if (!gmem_provider_lookup_pfn_range(gi, index, &pfn, &nr_pages)) {
- step = min_t(size_t, nr_pages, end - index);
+ ret = gmem_provider_lookup_pfn_range(gi, index, &pfn, &nr_pages,
+ &pfn_attrs);
+ step = min_t(size_t, max_t(size_t, nr_pages, 1), end - index);
+ if (!ret && !(pfn_attrs & GUEST_MEMFD_PFN_MMIO))
kvm_arch_gmem_reclaim(pfn, step);
- }
index += step;
cond_resched();
@@ -1068,8 +1110,10 @@ static void kvm_gmem_make_shared(struct inode *inode, pgoff_t start, pgoff_t end
size_t step = 1;
size_t nr_pages;
kvm_pfn_t pfn;
+ u64 pfn_attrs;
- if (!gmem_provider_lookup_pfn_range(gi, index, &pfn, &nr_pages)) {
+ if (!gmem_provider_lookup_pfn_range(gi, index, &pfn, &nr_pages,
+ &pfn_attrs)) {
step = min_t(size_t, nr_pages, end - index);
kvm_arch_gmem_make_shared(pfn, step);
}
--
2.43.0
next prev parent reply other threads:[~2026-11-12 7:41 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-12 7:41 [RFC PATCH v5 00/16] KVM: guest_memfd: Add a common framework for device memory providers Aneesh Kumar K.V (Arm)
2026-11-12 7:41 ` [RFC PATCH v5 01/16] KVM: guest_memfd: Add a handle for provider PFNs Aneesh Kumar K.V (Arm)
2026-11-12 7:41 ` [RFC PATCH v5 02/16] KVM: guest_memfd: Get PFNs through common provider operations Aneesh Kumar K.V (Arm)
2026-11-12 7:41 ` [RFC PATCH v5 03/16] KVM: guest_memfd: Let providers coordinate mapping changes Aneesh Kumar K.V (Arm)
2026-11-12 7:41 ` Aneesh Kumar K.V (Arm) [this message]
2026-11-12 7:41 ` [RFC PATCH v5 05/16] KVM: guest_memfd: Let providers validate attribute changes Aneesh Kumar K.V (Arm)
2026-11-12 7:41 ` [RFC PATCH v5 06/16] KVM: guest_memfd: Share memory through provider range lookup Aneesh Kumar K.V (Arm)
2026-11-12 7:41 ` [RFC PATCH v5 07/16] KVM: guest_memfd: Release and revoke memory through provider operations Aneesh Kumar K.V (Arm)
2026-11-12 7:41 ` [RFC PATCH v5 08/16] KVM: guest_memfd: Use provider operations for fallocate allocation Aneesh Kumar K.V (Arm)
2026-11-12 7:41 ` [RFC PATCH v5 09/16] KVM: guest_memfd: Use provider operations for host mappings and faults Aneesh Kumar K.V (Arm)
2026-11-12 7:41 ` [RFC PATCH v5 10/16] KVM: guest_memfd: Let providers prepare memory regions Aneesh Kumar K.V (Arm)
2026-11-12 7:41 ` [RFC PATCH v5 11/16] KVM: guest_memfd: Pass KVM explicitly to provider attach Aneesh Kumar K.V (Arm)
2026-11-12 7:41 ` [RFC PATCH v5 12/16] KVM: guest_memfd: Support devices through common provider operations Aneesh Kumar K.V (Arm)
2026-11-12 7:41 ` [RFC PATCH v5 13/16] KVM: guest_memfd: Notify providers after private attribute updates Aneesh Kumar K.V (Arm)
2026-11-12 7:41 ` [RFC PATCH v5 14/16] KVM: guest_memfd: Enable shared host mappings for device providers Aneesh Kumar K.V (Arm)
2026-11-12 7:41 ` [RFC PATCH v5 15/16] KVM: guest_memfd: Notify providers during file release Aneesh Kumar K.V (Arm)
2026-11-12 7:41 ` [RFC PATCH v5 16/16] KVM: guest_memfd: Invalidate mappings before memslot unbind Aneesh Kumar K.V (Arm)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261112074120.1570072-5-aneesh.kumar@kernel.org \
--to=aneesh.kumar@kernel.org \
--cc=ackerleytng@google.com \
--cc=aik@amd.com \
--cc=catalin.marinas@arm.com \
--cc=david@kernel.org \
--cc=dwmw2@infradead.org \
--cc=griffoul@gmail.com \
--cc=iommu@lists.linux.dev \
--cc=jgg@ziepe.ca \
--cc=kevin.tian@intel.com \
--cc=kvm@vger.kernel.org \
--cc=linux-coco@lists.linux.dev \
--cc=patches@lists.linux.dev \
--cc=pbonzini@redhat.com \
--cc=seanjc@google.com \
--cc=steven.price@arm.com \
--cc=suzuki.poulose@arm.com \
--cc=yilun.xu@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.