[PATCH RFC v2 36/50] KVM: guest_memfd: Support preallocating memory via fallocate in PFN mode

From: Ackerley Tng via B4 Relay

Date: Thu Oct 22 2026 - 19:49:49 EST


From: Ackerley Tng <ackerleytng@xxxxxxxxxx>

In PFN mode, memory is not backed by page cache folios, so attempting
to allocate folios during fallocate fails.

Support preallocating backing memory in PFN mode by querying the
provider for PFNs across the requested range. Step forward by the
contiguous order reported by the provider so that large contiguous
allocations do not require redundant per-page calls.

Signed-off-by: Ackerley Tng <ackerleytng@xxxxxxxxxx>
---
virt/kvm/guest_memfd.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)

diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index 734107dad63ee..f0c5162cc7a7f 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -405,6 +405,7 @@ static long kvm_gmem_punch_hole(struct inode *inode, loff_t offset, loff_t len)
static long kvm_gmem_allocate(struct inode *inode, loff_t offset, loff_t len)
{
struct address_space *mapping = inode->i_mapping;
+ struct gmem_inode *gi = GMEM_I(inode);
pgoff_t start, index, end;
int r;

@@ -418,6 +419,30 @@ static long kvm_gmem_allocate(struct inode *inode, loff_t offset, loff_t len)
end = (offset + len) >> PAGE_SHIFT;

r = 0;
+ if (kvm_gmem_is_pfn_mode(gi)) {
+ for (index = start; index < end; ) {
+ pgoff_t next_boundary;
+ pgoff_t max_nr_pages;
+ int max_order = 0;
+ kvm_pfn_t pfn;
+
+ if (signal_pending(current)) {
+ r = -EINTR;
+ break;
+ }
+
+ r = gmem_provider_get_pfn(gi, index, &pfn, &max_order);
+ if (r)
+ break;
+
+ max_nr_pages = 1UL << max_order;
+ next_boundary = ALIGN_DOWN(index + max_nr_pages, max_nr_pages);
+ index += min_t(size_t, next_boundary - index, end - index);
+ cond_resched();
+ }
+ goto out_unlock;
+ }
+
for (index = start; index < end; ) {
struct folio *folio;

@@ -444,6 +469,7 @@ static long kvm_gmem_allocate(struct inode *inode, loff_t offset, loff_t len)
cond_resched();
}

+out_unlock:
filemap_invalidate_unlock_shared(mapping);

return r;

--
2.56.0.257.gf7497c7d27-goog