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@nvidia.com>,
"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>,
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 v4 07/25] KVM: guest_memfd: Support private/shared conversion of device memory
Date: Wed, 4 Nov 2026 20:33:04 +0530 [thread overview]
Message-ID: <20261104150322.3516320-8-aneesh.kumar@kernel.org> (raw)
In-Reply-To: <20261104150322.3516320-1-aneesh.kumar@kernel.org>
Allow device-backed guest_memfd ranges to be converted between shared
and private memory using file offsets. Use the common attribute conversion
path for inode locking, maple-tree allocation, guest invalidation and
attribute publication.
Reuse PFN attribute preparation to revoke host mappings before private
conversion. Resolve guest addresses through memslot bindings and obtain
physical addresses through the provider's get_pfn() callback.
Install private device mappings during attribute conversion because
device mapping validation needs them before the guest's request is
completed. That validation does not require a preceding guest PFN
lookup, so a prepare_pfn() callback cannot be the sole place that
installs mappings. Use the architecture device-map hook before
publishing private attributes, independently of guest faults. The VMM
validates guest MMIO requests against its BAR layout before setting the
corresponding range private.
Sharing also completes before publishing attributes. Generic
invalidation with KVM_FILTER_PRIVATE has already removed the protected
device mappings, so the device conversion callback needs no additional
shared operation. Shared host and guest mappings can be installed by
their normal fault paths.
Leave revoke() and populate() unset, so full revocation, hole punching
and preallocation remain unsupported at this point in the series.
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>
---
Documentation/virt/kvm/api.rst | 5 ++
include/linux/kvm_host.h | 2 +
virt/kvm/guest_memfd.c | 103 ++++++++++++++++++++++++++++++++-
3 files changed, 107 insertions(+), 3 deletions(-)
diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 8455a9c7c971..4482d34ec281 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -6540,6 +6540,11 @@ provider. PFN_MODE selects the PFN callbacks; providers that supply device
operations additionally require INIT_SHARED and a VM supporting protected
device mappings.
+KVM_SET_MEMORY_ATTRIBUTES2 converts device memory using guest_memfd offsets.
+For private conversion, KVM resolves the guest address through the memslot
+binding and obtains the physical address from the provider. Shared conversion
+removes the protected device mappings before publishing shared attributes.
+
When the KVM MMU performs a PFN lookup to service a guest fault, the fault will
always be consumed from guest_memfd, regardless of whether it is a shared or a
private fault (unless in-place conversion is disabled and the backing
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index f2dd387ab0fa..c7831356b913 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -2618,6 +2618,8 @@ struct guest_memfd_device_binding;
bool kvm_arch_gmem_device_supported(struct kvm *kvm);
void kvm_arch_gmem_device_bind(struct kvm_memory_slot *slot,
const struct guest_memfd_device_binding *binding);
+int kvm_arch_gmem_device_map(struct kvm *kvm, const struct kvm_memory_slot *slot,
+ u64 gpa, u64 size, u64 pa);
bool kvm_gmem_is_private_gfn(struct kvm *kvm, gfn_t gfn);
bool kvm_arch_supports_gmem_init_shared(struct kvm *kvm);
diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index 397ead84bdb3..a06abb6dda82 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -99,6 +99,9 @@ static bool gmem_provider_is_device(struct gmem_inode *gi)
return gi->provider_ops && gi->provider_ops->device_memory;
}
+static int kvm_gmem_device_convert_attributes(struct inode *inode, pgoff_t start,
+ pgoff_t end, u64 attrs);
+
static bool kvm_gmem_is_pfn_mode(struct gmem_inode *gi)
{
return gi->flags & GUEST_MEMFD_FLAG_PFN_MODE;
@@ -1158,8 +1161,8 @@ static int kvm_gmem_folio_prepare_attributes(struct inode *inode, pgoff_t start,
return 0;
}
-static int kvm_gmem_ram_pfn_prepare_attributes(struct inode *inode, pgoff_t start,
- size_t nr_pages, u64 attrs, pgoff_t *err_index)
+static int kvm_gmem_pfn_prepare_attributes(struct inode *inode, pgoff_t start,
+ size_t nr_pages, u64 attrs, pgoff_t *err_index)
{
if (!(attrs & KVM_MEMORY_ATTRIBUTE_PRIVATE))
return 0;
@@ -1188,14 +1191,22 @@ static const struct kvm_gmem_backing_ops kvm_gmem_folio_backing_ops = {
static const struct kvm_gmem_backing_ops kvm_gmem_ram_pfn_backing_ops = {
.populate = kvm_gmem_ram_pfn_populate,
.revoke = kvm_gmem_ram_pfn_revoke,
- .prepare_attributes = kvm_gmem_ram_pfn_prepare_attributes,
+ .prepare_attributes = kvm_gmem_pfn_prepare_attributes,
.convert_attributes = kvm_gmem_ram_pfn_convert_attributes,
.prepare_pfn = kvm_gmem_ram_prepare_pfn,
};
+static const struct kvm_gmem_backing_ops kvm_gmem_device_backing_ops = {
+ .prepare_attributes = kvm_gmem_pfn_prepare_attributes,
+ .convert_attributes = kvm_gmem_device_convert_attributes,
+};
+
static const struct kvm_gmem_backing_ops *
kvm_gmem_select_backing_ops(struct gmem_inode *gi)
{
+ if (gmem_provider_is_device(gi))
+ return &kvm_gmem_device_backing_ops;
+
if (kvm_gmem_is_pfn_mode(gi))
return &kvm_gmem_ram_pfn_backing_ops;
@@ -1491,6 +1502,92 @@ void __weak kvm_arch_gmem_device_bind(struct kvm_memory_slot *slot,
{
}
+int __weak kvm_arch_gmem_device_map(struct kvm *kvm,
+ const struct kvm_memory_slot *slot,
+ u64 gpa, u64 size, u64 pa)
+{
+ return -EOPNOTSUPP;
+}
+
+/*
+ * Install protected device mappings for the provider PFNs when making a range
+ * private. Protected device-mapping validation needs these mappings in place
+ * before the guest's request is completed. That validation does not require a
+ * preceding kvm_gmem_get_pfn() call, so prepare_pfn() cannot be the sole place
+ * that installs them. Install them here with kvm_arch_gmem_device_map() before
+ * publishing private attributes, so validation can use the existing mappings.
+ *
+ * Sharing also completes before publishing attributes, but needs no additional
+ * operation here. kvm_gmem_invalidate_start() has already removed the private
+ * device mappings with KVM_FILTER_PRIVATE. Shared host and guest mappings can
+ * then be installed by their normal fault paths.
+ *
+ * Caller holds inode->i_mapping->invalidate_lock for write, which protects
+ * the attributes and offset-to-GPA bindings. The gmem_provider_lock()
+ * prevents device unlock from racing with conversion and publication of
+ * attributes.
+ */
+static int kvm_gmem_device_convert_attributes(struct inode *inode, pgoff_t start,
+ pgoff_t end, u64 attrs)
+{
+ struct gmem_inode *gi = GMEM_I(inode);
+ struct gmem_file *f;
+ void *entry;
+
+ MA_STATE(mas, &gi->attributes, start, start);
+
+ if (!(attrs & KVM_MEMORY_ATTRIBUTE_PRIVATE))
+ return 0;
+
+ mas_for_each(&mas, entry, end - 1) {
+ pgoff_t first = max(start, mas.index);
+ pgoff_t last = min(end, mas.last + 1);
+
+ if (kvm_gmem_get_attributes(inode, entry) & KVM_MEMORY_ATTRIBUTE_PRIVATE)
+ continue;
+
+ while (first < last) {
+ struct kvm_memory_slot *slot = NULL;
+ kvm_pfn_t pfn, next_pfn;
+ pgoff_t high, next;
+ u64 gpa;
+ int ret;
+
+ kvm_gmem_for_each_file(f, inode) {
+ slot = xa_load(&f->bindings, first);
+ if (slot)
+ break;
+ }
+ if (!slot)
+ return -EINVAL;
+
+ high = min(last, slot->gmem.pgoff + slot->npages);
+ gpa = (slot->base_gfn + first - slot->gmem.pgoff) << PAGE_SHIFT;
+ ret = gmem_provider_get_pfn(gi, first, &pfn, NULL);
+ if (ret)
+ return ret;
+
+ /* Map a contiguous provider PFN run within this binding. */
+ for (next = first + 1; next < high; next++) {
+ ret = gmem_provider_get_pfn(gi, next, &next_pfn, NULL);
+ if (ret)
+ return ret;
+ if (next_pfn != pfn + next - first)
+ break;
+ }
+ high = next;
+ ret = kvm_arch_gmem_device_map(gi->device.kvm, slot, gpa,
+ (u64)(high - first) << PAGE_SHIFT,
+ PFN_PHYS(pfn));
+ if (ret)
+ return ret;
+
+ first = high;
+ }
+ }
+ return 0;
+}
+
static int __kvm_gmem_create(struct kvm *kvm, loff_t size, u64 flags, int resource_fd)
{
static const char *name = "[kvm-gmem]";
--
2.43.0
next prev parent reply other threads:[~2026-11-04 15:04 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-04 15:02 [RFC PATCH v4 00/25] KVM/VFIO: Add guest_memfd support for device MMIO Aneesh Kumar K.V (Arm)
2026-11-04 15:02 ` [RFC PATCH v4 01/25] KVM: guest_memfd: Let providers prepare memory regions Aneesh Kumar K.V (Arm)
2026-11-04 15:02 ` [RFC PATCH v4 02/25] KVM: guest_memfd: Dispatch conversion through backing operations Aneesh Kumar K.V (Arm)
2026-11-04 15:03 ` [RFC PATCH v4 03/25] KVM: guest_memfd: Let providers coordinate mapping changes Aneesh Kumar K.V (Arm)
2026-11-04 15:03 ` [RFC PATCH v4 04/25] KVM: guest_memfd: Dispatch revocation through backing operations Aneesh Kumar K.V (Arm)
2026-11-04 15:03 ` [RFC PATCH v4 05/25] KVM: guest_memfd: Split population by backing type Aneesh Kumar K.V (Arm)
2026-11-04 15:03 ` [RFC PATCH v4 06/25] KVM: guest_memfd: Support device-backed PFN providers Aneesh Kumar K.V (Arm)
2026-11-04 18:37 ` Fred Griffoul
2026-11-04 15:03 ` Aneesh Kumar K.V (Arm) [this message]
2026-11-04 15:03 ` [RFC PATCH v4 08/25] KVM: guest_memfd: Track private device ranges after attribute updates Aneesh Kumar K.V (Arm)
2026-11-04 15:03 ` [RFC PATCH v4 09/25] KVM: guest_memfd: Support range revocation of device mappings Aneesh Kumar K.V (Arm)
2026-11-04 15:03 ` [RFC PATCH v4 10/25] KVM: guest_memfd: Add shared device mmap through PFN providers Aneesh Kumar K.V (Arm)
2026-11-04 15:03 ` [RFC PATCH v4 11/25] KVM: guest_memfd: Clear private device state on final close Aneesh Kumar K.V (Arm)
2026-11-04 15:03 ` [RFC PATCH v4 12/25] KVM: guest_memfd: Invalidate mappings before memslot unbind Aneesh Kumar K.V (Arm)
2026-11-04 15:03 ` [RFC PATCH v4 13/25] vfio: Track device use by guest_memfd Aneesh Kumar K.V (Arm)
2026-11-04 15:03 ` [RFC PATCH v4 14/25] vfio/pci: Add helpers to check and serialize BAR state changes Aneesh Kumar K.V (Arm)
2026-11-04 15:03 ` [RFC PATCH v4 15/25] vfio/pci: Check command enable changes before updating device state Aneesh Kumar K.V (Arm)
2026-11-04 15:03 ` [RFC PATCH v4 16/25] vfio/pci: Check whether BAR state changes are allowed before reset Aneesh Kumar K.V (Arm)
2026-11-04 15:03 ` [RFC PATCH v4 17/25] vfio/pci: Check low-power requests before updating device state Aneesh Kumar K.V (Arm)
2026-11-04 15:03 ` [RFC PATCH v4 18/25] vfio/pci: Track userspace BAR mappings Aneesh Kumar K.V (Arm)
2026-11-04 15:03 ` [RFC PATCH v4 19/25] vfio/pci: Restrict host BAR access for guest_memfd providers Aneesh Kumar K.V (Arm)
2026-11-04 15:03 ` [RFC PATCH v4 20/25] vfio: Dispatch guest_memfd provider operations through the device file Aneesh Kumar K.V (Arm)
2026-11-04 15:03 ` [RFC PATCH v4 21/25] vfio: Serialize guest_memfd attachment with device file operations Aneesh Kumar K.V (Arm)
2026-11-04 15:03 ` [RFC PATCH v4 22/25] vfio/pci: Require D0 before providing guest_memfd BAR backing Aneesh Kumar K.V (Arm)
2026-11-04 15:03 ` [RFC PATCH v4 23/25] iommufd: Support MMIO provider attachment to vDEVICEs Aneesh Kumar K.V (Arm)
2026-11-04 15:03 ` [RFC PATCH v4 24/25] vfio/pci: Add a guest_memfd resource provider for MMIO BARs Aneesh Kumar K.V (Arm)
2026-11-04 15:03 ` [RFC PATCH v4 25/25] KVM: Document device-backed guest_memfd and VFIO usage 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=20261104150322.3516320-8-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@nvidia.com \
--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=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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox