[PATCH v3 3/9] KVM: guest_memfd: implement folio migration for non-confidential VMs
Shivank Garg <[email protected]> Wed, 5 Aug 2026 06:40:32 +0000
| Newsgroups | gmane.linux.documentation,gmane.linux.file-systems,gmane.linux.kernel.mm,gmane.linux.kernel,gmane.comp.emulators.kvm.devel |
|---|---|
| Message-ID | <[email protected]> |
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. MM invokes ->migrate_folio() callback with folios already locked and acquires the invalidate lock afterwards. kvm_gmem_punch_hole() takes the invalidate lock before locking folios during truncation, so taking invalidate lock in migration callback can 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 <[email protected]> --- 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 169f75f95433..583341d593c9 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