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>,
Alex Williamson <alex@shazbot.org>,
David Woodhouse <dwmw2@infradead.org>,
David Hildenbrand <david@kernel.org>,
Jason Gunthorpe <jgg@ziepe.ca>,
"Joerg Roedel (AMD)" <joro@8bytes.org>,
Kevin Tian <kevin.tian@intel.com>,
Paolo Bonzini <pbonzini@redhat.com>,
Robin Murphy <robin.murphy@arm.com>,
Sean Christopherson <seanjc@google.com>,
Will Deacon <will@kernel.org>, 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 v2 04/13] KVM: guest_memfd: Add device provider access callbacks
Date: Sat, 17 Oct 2026 13:01:40 +0530 [thread overview]
Message-ID: <20261017073149.1303738-5-aneesh.kumar@kernel.org> (raw)
In-Reply-To: <20261017073149.1303738-1-aneesh.kumar@kernel.org>
Expose callbacks for device providers to check whether a range is shared,
query whether private ranges remain, and invalidate shared guest mappings.
Use a nonblocking acquisition of the inode invalidate lock for host
access checks, avoiding deadlock with conversion while a provider holds
its memory lock. Invalidate shared mappings under SRCU and the KVM MMU
lock, advancing the MMU invalidation sequence so concurrent faults retry.
Initialize callback state before attaching the provider and publish the
guest_memfd file after creation completes.
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Sean Christopherson <seanjc@google.com>
Cc: David Hildenbrand <david@kernel.org>
Cc: kvm@vger.kernel.org
Cc: patches@lists.linux.dev
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
include/linux/guest_memfd.h | 6 ++
virt/kvm/guest_memfd.c | 117 ++++++++++++++++++++++++++++++++++++
2 files changed, 123 insertions(+)
diff --git a/include/linux/guest_memfd.h b/include/linux/guest_memfd.h
index 7ae8df07a26e..f0c62889f823 100644
--- a/include/linux/guest_memfd.h
+++ b/include/linux/guest_memfd.h
@@ -26,6 +26,12 @@ struct guest_memfd {
struct kvm *kvm;
u64 size;
u64 flags;
+ struct file *gmem_file;
+
+ /* Revoke shared guest translations synchronously. */
+ void (*invalidate)(struct guest_memfd *gmem);
+ bool (*has_private)(struct guest_memfd *gmem);
+ bool (*host_accessible)(struct guest_memfd *gmem, u64 offset, u64 size);
};
/**
diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index b2782e64e9c8..d2b1e2e9dfee 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -1066,6 +1066,118 @@ int __weak kvm_arch_gmem_device_unmap(struct kvm *kvm, u64 gpa, u64 size)
return -EOPNOTSUPP;
}
+static bool gmem_device_host_accessible(struct guest_memfd *gdev,
+ u64 offset, u64 size)
+{
+ struct file *file = READ_ONCE(gdev->gmem_file);
+ struct inode *inode;
+ pgoff_t first, last;
+ bool shared;
+
+ if (!file)
+ return false;
+
+ /* Unwrapped BAR offsets have no private guest_memfd mappings. */
+ if (offset >= gdev->size)
+ return true;
+
+ size = min(size, gdev->size - offset);
+ if (!size)
+ return false;
+
+ first = offset >> PAGE_SHIFT;
+ last = ((offset + size - 1) >> PAGE_SHIFT) + 1;
+ inode = file_inode(file);
+ /*
+ * Keep guest_memfd attributes stable against conversion while checking
+ * host access. This check only reads attributes, so a shared lock lets
+ * other access checks run concurrently.
+ *
+ * VFIO callers hold memory_lock, but conversion takes the invalidate
+ * lock exclusively before taking memory_lock for writing.
+ * Waiting here could deadlock with conversion. Try the shared lock and
+ * deny access if it cannot be acquired.
+ */
+ if (!filemap_invalidate_trylock_shared(inode->i_mapping))
+ return false;
+
+ shared = __kvm_gmem_range_has_attributes(inode, first, last - first, 0);
+ filemap_invalidate_unlock_shared(inode->i_mapping);
+ return shared;
+}
+
+/**
+ * gmem_device_invalidate() - invalidate shared guest mappings of device memory
+ * @gdev: device guest_memfd whose provider is revoking access
+ *
+ * VFIO invokes this callback when zapping BAR mappings. Removing host BAR
+ * mappings alone leaves guest stage-2 mappings intact, so unmap the shared
+ * ranges in memslots backed by this guest_memfd and flush guest TLBs as needed.
+ * Advance the MMU invalidation sequence so faults that obtained a provider PFN
+ * before revocation retry instead of installing a stale mapping.
+ *
+ * SRCU protects memslot traversal, and the KVM MMU lock serializes unmapping
+ * with guest faults. Do not acquire the inode invalidate lock: conversion may
+ * already hold it, and VFIO callers hold memory_lock in the reverse order.
+ *
+ * Caller holds the provider memory lock to exclude new provider PFN
+ * lookups during invalidation.
+ */
+static void gmem_device_invalidate(struct guest_memfd *gdev)
+{
+ struct file *file = gdev->gmem_file;
+ struct kvm *kvm = gdev->kvm;
+ struct kvm_memory_slot *slot;
+ struct kvm_memslots *slots;
+ int srcu_idx, bkt, as;
+ bool flush = false, found_memslot = false;
+
+ if (!file)
+ return;
+
+ srcu_idx = srcu_read_lock(&kvm->srcu);
+ KVM_MMU_LOCK(kvm);
+
+ for (as = 0; as < kvm_arch_nr_memslot_as_ids(kvm); as++) {
+ slots = __kvm_memslots(kvm, as);
+ kvm_for_each_memslot(slot, bkt, slots) {
+ struct kvm_gfn_range range = {
+ .slot = slot,
+ .start = slot->base_gfn,
+ .end = slot->base_gfn + slot->npages,
+ .attr_filter = KVM_FILTER_SHARED,
+ .may_block = false,
+ };
+
+ if (READ_ONCE(slot->gmem.file) != file)
+ continue;
+
+ if (!found_memslot) {
+ found_memslot = true;
+ kvm_mmu_invalidate_start(kvm);
+ }
+
+ flush |= kvm_mmu_unmap_gfn_range(kvm, &range);
+ }
+ }
+ if (flush)
+ kvm_flush_remote_tlbs(kvm);
+
+ if (found_memslot)
+ kvm_mmu_invalidate_end(kvm);
+
+ KVM_MMU_UNLOCK(kvm);
+ srcu_read_unlock(&kvm->srcu, srcu_idx);
+}
+
+/* The attribute tree owns mapping state; this summary is read under provider locks. */
+static bool gmem_device_has_private(struct guest_memfd *gdev)
+{
+ struct gmem_inode *gi = container_of(gdev, struct gmem_inode, device);
+
+ return READ_ONCE(gi->device_has_private);
+}
+
static void kvm_gmem_device_update_private(struct gmem_inode *gi)
{
MA_STATE(mas, &gi->attributes, 0, 0);
@@ -1291,6 +1403,9 @@ static int kvm_gmem_attach_resource(struct kvm *kvm,
gi->device.size = i_size_read(inode);
/* The provider needs creation flags before attachment is published. */
gi->device.flags = gi->flags;
+ gi->device.invalidate = gmem_device_invalidate;
+ gi->device.host_accessible = gmem_device_host_accessible;
+ gi->device.has_private = gmem_device_has_private;
provider = ops->attach(resource_file, &gi->device);
if (IS_ERR(provider)) {
ret = PTR_ERR(provider);
@@ -1359,6 +1474,7 @@ static int __kvm_gmem_create(struct kvm *kvm, loff_t size, u64 flags, int resour
xa_init(&f->bindings);
list_add(&f->entry, &GMEM_I(inode)->gmem_file_list);
+ WRITE_ONCE(GMEM_I(inode)->device.gmem_file, file);
fd_install(fd, file);
return fd;
@@ -1743,6 +1859,7 @@ static struct inode *kvm_gmem_alloc_inode(struct super_block *sb)
gi->provider = NULL;
gi->provider_ops = NULL;
gi->device_has_private = false;
+ memset(&gi->device, 0, sizeof(gi->device));
INIT_LIST_HEAD(&gi->gmem_file_list);
return &gi->vfs_inode;
}
--
2.43.0
next prev parent reply other threads:[~2026-10-17 7:32 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-17 7:31 [RFC PATCH v2 00/13] KVM/VFIO: guest_memfd support for device MMIO resources Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 01/13] KVM: guest_memfd: Support PFN-backed resource providers Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 02/13] KVM: guest_memfd: Support private/shared conversion of device memory Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 03/13] iommufd: Support MMIO provider attachment to vDEVICEs Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` Aneesh Kumar K.V (Arm) [this message]
2026-10-17 7:31 ` [RFC PATCH v2 05/13] vfio/pci: Track userspace BAR mappings Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 06/13] vfio: Dispatch guest_memfd provider operations through the filesystem Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 07/13] vfio/pci: Restrict host BAR access for guest_memfd providers Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 08/13] vfio/pci: Provide guest_memfd backing for PCI BARs Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 09/13] KVM: guest_memfd: Add a provider detach callback Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 10/13] vfio/pci: Detach guest_memfd access before teardown Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 11/13] KVM: guest_memfd: Remove device mappings on final close Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 12/13] KVM: Invalidate guest_memfd mappings before removing memslot bindings Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 13/13] vfio/pci: Allow VFIO BAR mmap with an attached guest_memfd 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=20261017073149.1303738-5-aneesh.kumar@kernel.org \
--to=aneesh.kumar@kernel.org \
--cc=ackerleytng@google.com \
--cc=aik@amd.com \
--cc=alex@shazbot.org \
--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=joro@8bytes.org \
--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=robin.murphy@arm.com \
--cc=seanjc@google.com \
--cc=steven.price@arm.com \
--cc=suzuki.poulose@arm.com \
--cc=will@kernel.org \
--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.