From: Mahmoud Adam <mngyadam@amazon.de>
To: <kvm@vger.kernel.org>
Cc: <alex.williamson@redhat.com>, <jgg@ziepe.ca>, <kbusch@kernel.org>,
<benh@kernel.crashing.org>, David Woodhouse <dwmw@amazon.co.uk>,
<pravkmr@amazon.de>, <nagy@khwaternagy.com>,
<linux-kernel@vger.kernel.org>
Subject: [RFC PATCH 7/7] vfio-pci-core: implement FEATURE_ALIAS_REGION uapi
Date: Wed, 24 Sep 2025 16:09:58 +0200 [thread overview]
Message-ID: <20250924141018.80202-8-mngyadam@amazon.de> (raw)
In-Reply-To: <20250924141018.80202-1-mngyadam@amazon.de>
This implements the new DEVICE_FEATURE_ALIAS_REGION. As of right now
Alias is only needed for mmaping. So we will allow aliasing mmap
supported regions only.
If the user requested a similar alias (same flags and aliased
index). re-use the old index instead by returning it to the
user. Since creating another alias gives no extra value for the
user. The region with the new flag (WC), will allow the user to
mmap the aliased region with WC enabled.
We also supports probing. When the user probe a region index, we
return the region flags supported to be enabled for this
region. Initially we are supporting WC only when the region is
mmap-able.
add vfio_pci_core_register_dev_region_locked to allow externally
locking the mutex. So that we can check for if a similar region exists
and add a new region under the same mutex lock, to avoid racing.
Signed-off-by: Mahmoud Adam <mngyadam@amazon.de>
---
drivers/vfio/pci/vfio_pci_core.c | 173 ++++++++++++++++++++++++++++---
1 file changed, 161 insertions(+), 12 deletions(-)
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index 962d3eda1ea9f..3c162cf47a1eb 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -882,20 +882,14 @@ static int msix_mmappable_cap(struct vfio_pci_core_device *vdev,
return vfio_info_add_capability(caps, &header, sizeof(header));
}
-/*
- * Registers a new region to vfio_pci_core_device. region_lock should
- * be held when multiple registers could happen.
- * Returns region index on success or a negative errno.
- */
-int vfio_pci_core_register_dev_region(struct vfio_pci_core_device *vdev,
- unsigned int type, unsigned int subtype,
- const struct vfio_pci_regops *ops,
- size_t size, u32 flags, void *data)
+static int vfio_pci_core_register_dev_region_locked(
+ struct vfio_pci_core_device *vdev,
+ unsigned int type, unsigned int subtype,
+ const struct vfio_pci_regops *ops,
+ size_t size, u32 flags, void *data)
{
struct vfio_pci_region *region, *old_region;
int num_regions;
-
- mutex_lock(&vdev->region_lock);
num_regions = READ_ONCE(vdev->num_regions);
region = kmalloc((num_regions + 1) * sizeof(*region),
@@ -919,10 +913,29 @@ int vfio_pci_core_register_dev_region(struct vfio_pci_core_device *vdev,
rcu_assign_pointer(vdev->region, region);
synchronize_rcu();
WRITE_ONCE(vdev->num_regions, READ_ONCE(vdev->num_regions) + 1);
- mutex_unlock(&vdev->region_lock);
kfree(old_region);
return num_regions;
}
+
+/*
+ * Registers a new region to vfio_pci_core_device. region_lock should
+ * be held when multiple registers could happen.
+ * Returns region index on success or a negative errno.
+ */
+int vfio_pci_core_register_dev_region(struct vfio_pci_core_device *vdev,
+ unsigned int type, unsigned int subtype,
+ const struct vfio_pci_regops *ops,
+ size_t size, u32 flags, void *data)
+{
+ int index;
+
+ mutex_lock(&vdev->region_lock);
+ index = vfio_pci_core_register_dev_region_locked(vdev, type, subtype,
+ ops,
+ size, flags, data);
+ mutex_unlock(&vdev->region_lock);
+ return index;
+}
EXPORT_SYMBOL_GPL(vfio_pci_core_register_dev_region);
static int vfio_pci_info_atomic_cap(struct vfio_pci_core_device *vdev,
@@ -1528,6 +1541,48 @@ static int vfio_pci_core_feature_token(struct vfio_device *device, u32 flags,
return 0;
}
+static bool vfio_pci_region_is_mmap_supported(struct vfio_pci_core_device *vdev,
+ int index)
+{
+ if (index <= VFIO_PCI_BAR5_REGION_INDEX)
+ return vdev->bar_mmap_supported[index];
+
+ if (index >= VFIO_PCI_NUM_REGIONS) {
+ int i = index - VFIO_PCI_NUM_REGIONS;
+ bool is_mmap;
+ struct vfio_pci_region *region;
+
+ rcu_read_lock();
+ region = &rcu_dereference(vdev->region)[i];
+ is_mmap = (region->flags & VFIO_REGION_INFO_FLAG_MMAP) &&
+ region->ops && region->ops->mmap;
+ rcu_read_unlock();
+ return is_mmap;
+ }
+ return false;
+}
+
+static bool vfio_pci_region_alias_exists(struct vfio_pci_core_device *vdev,
+ u32 flags, int index, int *alias_index)
+{
+ int i;
+
+ for (i = 0; i < READ_ONCE(vdev->num_regions); i++) {
+ struct vfio_pci_region *region;
+
+ region = &rcu_dereference_protected(
+ vdev->region, lockdep_is_held(&vdev->region_lock))[i];
+ if (!(region->flags & VFIO_REGION_INFO_FLAG_ALIAS))
+ continue;
+ if ((int)(uintptr_t) region->data == index &&
+ region->flags == flags) {
+ *alias_index = i + VFIO_PCI_NUM_REGIONS;
+ return true;
+ }
+ }
+ return false;
+}
+
static int vfio_pci_alias_region_mmap(struct vfio_pci_core_device *vdev,
struct vfio_pci_region *region,
struct vm_area_struct *vma)
@@ -1555,6 +1610,97 @@ struct vfio_pci_regops vfio_pci_alias_region_ops = {
.mmap = vfio_pci_alias_region_mmap,
};
+static int vfio_pci_core_feature_alias_region(
+ struct vfio_device *device, u32 flags,
+ struct vfio_device_feature_alias_region __user *arg,
+ size_t argsz)
+{
+ struct vfio_pci_core_device *vdev =
+ container_of(device, struct vfio_pci_core_device, vdev);
+ struct pci_dev *pdev = vdev->pdev;
+ bool is_probe = false;
+ u32 region_flags;
+ struct vfio_device_feature_alias_region request_region;
+ int ret, index, new_index;
+ size_t size;
+
+ ret = vfio_check_feature(flags, argsz, VFIO_DEVICE_FEATURE_SET,
+ sizeof(request_region));
+ if (ret < 0)
+ return ret;
+
+ if (ret == 0) /* probing only */
+ is_probe = true;
+
+ if (copy_from_user(&request_region, arg, sizeof(request_region)))
+ return -EFAULT;
+
+ if (request_region.index >= VFIO_PCI_NUM_REGIONS +
+ READ_ONCE(vdev->num_regions))
+ return -EINVAL;
+
+ index = array_index_nospec(request_region.index,
+ VFIO_PCI_NUM_REGIONS +
+ READ_ONCE(vdev->num_regions));
+
+ /* make sure we are not aliasing an alias region */
+ if (index >= VFIO_PCI_NUM_REGIONS) {
+ int i;
+
+ rcu_read_lock();
+ i = index - VFIO_PCI_NUM_REGIONS;
+ if (rcu_dereference(vdev->region)[i].flags &
+ VFIO_REGION_INFO_FLAG_ALIAS) {
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+ rcu_read_unlock();
+ }
+
+ /* For now we only allow aliasing mmap supported regions. */
+ if (!vfio_pci_region_is_mmap_supported(vdev, index))
+ return -EINVAL;
+
+ if (is_probe) {
+ request_region.flags = VFIO_REGION_INFO_FLAG_WC;
+ goto out_copy;
+ }
+
+ if (request_region.flags & ~VFIO_REGION_INFO_FLAG_WC)
+ return -EINVAL;
+
+ region_flags = VFIO_REGION_INFO_FLAG_ALIAS |
+ VFIO_REGION_INFO_FLAG_MMAP | VFIO_REGION_INFO_FLAG_WC;
+
+ mutex_lock(&vdev->region_lock);
+ if (vfio_pci_region_alias_exists(vdev, region_flags,
+ index, &new_index)) {
+ request_region.alias_index = new_index;
+ goto out_copy_unlock;
+ }
+
+ if (index <= VFIO_PCI_BAR5_REGION_INDEX)
+ size = pci_resource_len(pdev, index);
+ else
+ size = vdev->region[index].size;
+
+ new_index = vfio_pci_core_register_dev_region_locked(
+ vdev, 0, 0, &vfio_pci_alias_region_ops, size, region_flags,
+ (void *)(uintptr_t)index);
+
+ if (new_index < 0) {
+ mutex_unlock(&vdev->region_lock);
+ return new_index;
+ }
+ request_region.alias_index = new_index + VFIO_PCI_NUM_REGIONS;
+
+out_copy_unlock:
+ mutex_unlock(&vdev->region_lock);
+out_copy:
+ ret = copy_to_user(arg, &request_region, sizeof(request_region));
+ return ret ? -EFAULT : 0;
+}
+
int vfio_pci_core_ioctl_feature(struct vfio_device *device, u32 flags,
void __user *arg, size_t argsz)
{
@@ -1568,6 +1714,9 @@ int vfio_pci_core_ioctl_feature(struct vfio_device *device, u32 flags,
return vfio_pci_core_pm_exit(device, flags, arg, argsz);
case VFIO_DEVICE_FEATURE_PCI_VF_TOKEN:
return vfio_pci_core_feature_token(device, flags, arg, argsz);
+ case VFIO_DEVICE_FEATURE_ALIAS_REGION:
+ return vfio_pci_core_feature_alias_region(device, flags,
+ arg, argsz);
default:
return -ENOTTY;
}
--
2.47.3
Amazon Web Services Development Center Germany GmbH
Tamara-Danz-Str. 13
10243 Berlin
Geschaeftsfuehrung: Christian Schlaeger
Eingetragen am Amtsgericht Charlottenburg unter HRB 257764 B
Sitz: Berlin
Ust-ID: DE 365 538 597
next prev parent reply other threads:[~2025-09-24 14:13 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-24 14:09 [RFC PATCH 0/7] vfio: Add alias region uapi for device feature Mahmoud Adam
2025-09-24 14:09 ` [RFC PATCH 1/7] vfio/pci: refactor region dereferences for RCU Mahmoud Adam
2025-09-24 14:09 ` [RFC PATCH 2/7] vfio_pci_core: split krealloc to allow use RCU & return index Mahmoud Adam
2025-09-24 14:09 ` [RFC PATCH 3/7] vfio/pci: add RCU locking for regions access Mahmoud Adam
2025-09-24 16:15 ` Mahmoud Nagy Adam
2025-09-24 14:09 ` [RFC PATCH 4/7] vfio: add FEATURE_ALIAS_REGION uapi Mahmoud Adam
2025-09-24 14:09 ` [RFC PATCH 5/7] vfio_pci_core: allow regions with no release op Mahmoud Adam
2025-09-24 14:09 ` [RFC PATCH 6/7] vfio-pci: add alias_region mmap ops Mahmoud Adam
2025-09-24 14:09 ` Mahmoud Adam [this message]
2025-10-03 21:58 ` [RFC PATCH 0/7] vfio: Add alias region uapi for device feature David Matlack
2025-10-05 10:16 ` Mahmoud Nagy Adam
2025-10-15 19:36 ` Alex Williamson
2025-10-27 16:32 ` David Matlack
2025-10-27 18:19 ` Mahmoud Nagy Adam
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=20250924141018.80202-8-mngyadam@amazon.de \
--to=mngyadam@amazon.de \
--cc=alex.williamson@redhat.com \
--cc=benh@kernel.crashing.org \
--cc=dwmw@amazon.co.uk \
--cc=jgg@ziepe.ca \
--cc=kbusch@kernel.org \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=nagy@khwaternagy.com \
--cc=pravkmr@amazon.de \
/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