[PATCH RFC v2 2/4] KVM: guest_memfd: implement folio migration for non-confidential VMs

From: Shivank Garg

Date: Tue Jul 28 2026 - 05:10:55 EST


Implement kvm_gmem_migrate_folio() using filemap_migrate_folio() for
non-confidential VMs but don't enable it yet. guest_memfd mappings
are still marked unmovable, so MM never calls it.

Migration invokes ->migrate_folio() callback with folios already
locked and acquires the invalidate lock afterwards. While
kvm_gmem_punch_hole() acquires the invalidate lock and takes folio
lock afterwards during truncation. This could invert the lock order
and cause an ABBA-deadlock situation. Use
filemap_invalidate_trylock_shared() to avoid this.

A subsequent patch adds an opt-in flag to change the mapping to
movable and enable migration. Non-confidential VMs can use
host-side copy via folio_mc_copy(), whereas confidential VMs will
require firmware-assisted copying before they can opt in.

Signed-off-by: Shivank Garg <shivankg@xxxxxxx>
---
virt/kvm/guest_memfd.c | 36 ++++++++++++++++++++++++++++++++++--
1 file changed, 34 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index d3b1186b03b3..ec881cabe8e3 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -488,13 +488,45 @@ static struct file_operations kvm_gmem_fops = {
.fallocate = kvm_gmem_fallocate,
};

+#ifdef CONFIG_MIGRATION
static int kvm_gmem_migrate_folio(struct address_space *mapping,
struct folio *dst, struct folio *src,
enum migrate_mode mode)
{
- WARN_ON_ONCE(1);
- return -EINVAL;
+ struct inode *inode = mapping->host;
+ pgoff_t start, end;
+ int ret;
+
+ /*
+ * Migration invokes ->migrate_folio() while holding the folio lock.
+ * Use a non-blocking trylock to avoid inverting the lock order with
+ * truncation, which takes the invalidate lock before locking the
+ * folios.
+ */
+ if (!filemap_invalidate_trylock_shared(mapping))
+ return -EAGAIN;
+
+ start = src->index;
+ end = start + folio_nr_pages(src);
+
+ kvm_gmem_invalidate_start(inode, start, end);
+
+ /*
+ * For non-confidential guests the folio is host-readable, so
+ * filemap_migrate_folio() can copy the contents itself via
+ * folio_mc_copy().
+ * For confidential guests, this would need firmware assistance.
+ */
+ ret = filemap_migrate_folio(mapping, dst, src, mode);
+
+ kvm_gmem_invalidate_end(inode, start, end);
+
+ filemap_invalidate_unlock_shared(mapping);
+ return ret;
}
+#else
+#define kvm_gmem_migrate_folio NULL
+#endif

static int kvm_gmem_error_folio(struct address_space *mapping, struct folio *folio)
{

--
2.43.0