* [PATCH v7 1/4] vfio: Do not allow !ops->dma_unmap in vfio_pin/unpin_pages()
2023-05-09 4:44 [PATCH v7 0/4] Add IO page table replacement support Nicolin Chen
@ 2023-05-09 4:44 ` Nicolin Chen
2023-05-09 4:44 ` [PATCH v7 2/4] iommufd: Add iommufd_access_replace() API Nicolin Chen
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Nicolin Chen @ 2023-05-09 4:44 UTC (permalink / raw)
To: jgg, kevin.tian, alex.williamson
Cc: yi.l.liu, joro, will, robin.murphy, shuah, linux-kernel, iommu,
kvm, linux-kselftest, mjrosato, farman
A driver that doesn't implement ops->dma_unmap shouldn't be allowed to do
vfio_pin/unpin_pages(), though it can use vfio_dma_rw() to access an iova
range. Deny !ops->dma_unmap cases in vfio_pin/unpin_pages().
Suggested-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Yi Liu <yi.l.liu@intel.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
---
drivers/vfio/vfio_main.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c
index 3b046023ac15..b1e69b389e31 100644
--- a/drivers/vfio/vfio_main.c
+++ b/drivers/vfio/vfio_main.c
@@ -1454,6 +1454,8 @@ int vfio_pin_pages(struct vfio_device *device, dma_addr_t iova,
/* group->container cannot change while a vfio device is open */
if (!pages || !npage || WARN_ON(!vfio_assert_device_open(device)))
return -EINVAL;
+ if (!device->ops->dma_unmap)
+ return -EINVAL;
if (vfio_device_has_container(device))
return vfio_device_container_pin_pages(device, iova,
npage, prot, pages);
@@ -1491,6 +1493,8 @@ void vfio_unpin_pages(struct vfio_device *device, dma_addr_t iova, int npage)
{
if (WARN_ON(!vfio_assert_device_open(device)))
return;
+ if (WARN_ON(!device->ops->dma_unmap))
+ return;
if (vfio_device_has_container(device)) {
vfio_device_container_unpin_pages(device, iova, npage);
--
2.40.1
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v7 2/4] iommufd: Add iommufd_access_replace() API
2023-05-09 4:44 [PATCH v7 0/4] Add IO page table replacement support Nicolin Chen
2023-05-09 4:44 ` [PATCH v7 1/4] vfio: Do not allow !ops->dma_unmap in vfio_pin/unpin_pages() Nicolin Chen
@ 2023-05-09 4:44 ` Nicolin Chen
2023-05-09 4:44 ` [PATCH v7 3/4] iommufd/selftest: Add IOMMU_TEST_OP_ACCESS_REPLACE_IOAS coverage Nicolin Chen
2023-05-09 4:44 ` [PATCH v7 4/4] vfio: Support IO page table replacement Nicolin Chen
3 siblings, 0 replies; 5+ messages in thread
From: Nicolin Chen @ 2023-05-09 4:44 UTC (permalink / raw)
To: jgg, kevin.tian, alex.williamson
Cc: yi.l.liu, joro, will, robin.murphy, shuah, linux-kernel, iommu,
kvm, linux-kselftest, mjrosato, farman
Extract all common procedure, between the iommufd_access_attach() API and
the new iommufd_access_replace() API, to an iommufd_access_change_pt()
helper.
Add iommufd_access_replace() function for VFIO emulated pathway to use.
Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
---
drivers/iommu/iommufd/device.c | 53 ++++++++++++++++++++++++++--------
include/linux/iommufd.h | 1 +
2 files changed, 42 insertions(+), 12 deletions(-)
diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c
index 989bd485f92f..051bd8e99858 100644
--- a/drivers/iommu/iommufd/device.c
+++ b/drivers/iommu/iommufd/device.c
@@ -769,38 +769,67 @@ void iommufd_access_detach(struct iommufd_access *access)
}
EXPORT_SYMBOL_NS_GPL(iommufd_access_detach, IOMMUFD);
-int iommufd_access_attach(struct iommufd_access *access, u32 ioas_id)
+static int iommufd_access_change_pt(struct iommufd_access *access, u32 ioas_id)
{
struct iommufd_ioas *new_ioas;
- int rc = 0;
+ int rc;
- mutex_lock(&access->ioas_lock);
- if (access->ioas) {
- mutex_unlock(&access->ioas_lock);
- return -EINVAL;
- }
+ lockdep_assert_held(&access->ioas_lock);
new_ioas = iommufd_get_ioas(access->ictx, ioas_id);
- if (IS_ERR(new_ioas)) {
- mutex_unlock(&access->ioas_lock);
+ if (IS_ERR(new_ioas))
return PTR_ERR(new_ioas);
- }
rc = iopt_add_access(&new_ioas->iopt, access);
if (rc) {
- mutex_unlock(&access->ioas_lock);
iommufd_put_object(&new_ioas->obj);
return rc;
}
iommufd_ref_to_users(&new_ioas->obj);
+ if (access->ioas)
+ __iommufd_access_detach(access);
access->ioas = new_ioas;
access->ioas_unpin = new_ioas;
- mutex_unlock(&access->ioas_lock);
return 0;
}
+
+int iommufd_access_attach(struct iommufd_access *access, u32 ioas_id)
+{
+ int rc;
+
+ mutex_lock(&access->ioas_lock);
+ if (access->ioas) {
+ mutex_unlock(&access->ioas_lock);
+ return -EINVAL;
+ }
+
+ rc = iommufd_access_change_pt(access, ioas_id);
+ mutex_unlock(&access->ioas_lock);
+ return rc;
+}
EXPORT_SYMBOL_NS_GPL(iommufd_access_attach, IOMMUFD);
+int iommufd_access_replace(struct iommufd_access *access, u32 ioas_id)
+{
+ int rc;
+
+ mutex_lock(&access->ioas_lock);
+ if (!access->ioas) {
+ mutex_unlock(&access->ioas_lock);
+ return -ENOENT;
+ }
+ if (access->ioas->obj.id == ioas_id) {
+ mutex_unlock(&access->ioas_lock);
+ return 0;
+ }
+
+ rc = iommufd_access_change_pt(access, ioas_id);
+ mutex_unlock(&access->ioas_lock);
+ return rc;
+}
+EXPORT_SYMBOL_NS_GPL(iommufd_access_replace, IOMMUFD);
+
/**
* iommufd_access_notify_unmap - Notify users of an iopt to stop using it
* @iopt: iopt to work on
diff --git a/include/linux/iommufd.h b/include/linux/iommufd.h
index d25fbd3a80b1..ea3e704dde8d 100644
--- a/include/linux/iommufd.h
+++ b/include/linux/iommufd.h
@@ -48,6 +48,7 @@ iommufd_access_create(struct iommufd_ctx *ictx,
const struct iommufd_access_ops *ops, void *data, u32 *id);
void iommufd_access_destroy(struct iommufd_access *access);
int iommufd_access_attach(struct iommufd_access *access, u32 ioas_id);
+int iommufd_access_replace(struct iommufd_access *access, u32 ioas_id);
void iommufd_access_detach(struct iommufd_access *access);
struct iommufd_ctx *iommufd_access_to_ictx(struct iommufd_access *access);
--
2.40.1
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v7 3/4] iommufd/selftest: Add IOMMU_TEST_OP_ACCESS_REPLACE_IOAS coverage
2023-05-09 4:44 [PATCH v7 0/4] Add IO page table replacement support Nicolin Chen
2023-05-09 4:44 ` [PATCH v7 1/4] vfio: Do not allow !ops->dma_unmap in vfio_pin/unpin_pages() Nicolin Chen
2023-05-09 4:44 ` [PATCH v7 2/4] iommufd: Add iommufd_access_replace() API Nicolin Chen
@ 2023-05-09 4:44 ` Nicolin Chen
2023-05-09 4:44 ` [PATCH v7 4/4] vfio: Support IO page table replacement Nicolin Chen
3 siblings, 0 replies; 5+ messages in thread
From: Nicolin Chen @ 2023-05-09 4:44 UTC (permalink / raw)
To: jgg, kevin.tian, alex.williamson
Cc: yi.l.liu, joro, will, robin.murphy, shuah, linux-kernel, iommu,
kvm, linux-kselftest, mjrosato, farman
Add a new IOMMU_TEST_OP_ACCESS_REPLACE_IOAS to allow replacing the
access->ioas, corresponding to the iommufd_access_replace() helper.
Then add a replace coverage as a part of user_copy test case, which
basically repeats the copy test after replacing the old ioas with a
new one.
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
---
drivers/iommu/iommufd/iommufd_test.h | 4 +++
drivers/iommu/iommufd/selftest.c | 19 ++++++++++++
tools/testing/selftests/iommu/iommufd.c | 29 +++++++++++++++++--
tools/testing/selftests/iommu/iommufd_utils.h | 19 ++++++++++++
4 files changed, 69 insertions(+), 2 deletions(-)
diff --git a/drivers/iommu/iommufd/iommufd_test.h b/drivers/iommu/iommufd/iommufd_test.h
index dd9168a20ddf..258de2253b61 100644
--- a/drivers/iommu/iommufd/iommufd_test.h
+++ b/drivers/iommu/iommufd/iommufd_test.h
@@ -18,6 +18,7 @@ enum {
IOMMU_TEST_OP_ACCESS_RW,
IOMMU_TEST_OP_SET_TEMP_MEMORY_LIMIT,
IOMMU_TEST_OP_MOCK_DOMAIN_REPLACE,
+ IOMMU_TEST_OP_ACCESS_REPLACE_IOAS,
};
enum {
@@ -91,6 +92,9 @@ struct iommu_test_cmd {
struct {
__u32 limit;
} memory_limit;
+ struct {
+ __u32 ioas_id;
+ } access_replace_ioas;
};
__u32 last;
};
diff --git a/drivers/iommu/iommufd/selftest.c b/drivers/iommu/iommufd/selftest.c
index 9d43334e4faf..bb2cd54ca7b6 100644
--- a/drivers/iommu/iommufd/selftest.c
+++ b/drivers/iommu/iommufd/selftest.c
@@ -785,6 +785,22 @@ static int iommufd_test_create_access(struct iommufd_ucmd *ucmd,
return rc;
}
+static int iommufd_test_access_replace_ioas(struct iommufd_ucmd *ucmd,
+ unsigned int access_id,
+ unsigned int ioas_id)
+{
+ struct selftest_access *staccess;
+ int rc;
+
+ staccess = iommufd_access_get(access_id);
+ if (IS_ERR(staccess))
+ return PTR_ERR(staccess);
+
+ rc = iommufd_access_replace(staccess->access, ioas_id);
+ fput(staccess->file);
+ return rc;
+}
+
/* Check that the pages in a page array match the pages in the user VA */
static int iommufd_test_check_pages(void __user *uptr, struct page **pages,
size_t npages)
@@ -1000,6 +1016,9 @@ int iommufd_test(struct iommufd_ucmd *ucmd)
case IOMMU_TEST_OP_CREATE_ACCESS:
return iommufd_test_create_access(ucmd, cmd->id,
cmd->create_access.flags);
+ case IOMMU_TEST_OP_ACCESS_REPLACE_IOAS:
+ return iommufd_test_access_replace_ioas(
+ ucmd, cmd->id, cmd->access_replace_ioas.ioas_id);
case IOMMU_TEST_OP_ACCESS_PAGES:
return iommufd_test_access_pages(
ucmd, cmd->id, cmd->access_pages.iova,
diff --git a/tools/testing/selftests/iommu/iommufd.c b/tools/testing/selftests/iommu/iommufd.c
index dc09c1de319f..8acd0af37aa5 100644
--- a/tools/testing/selftests/iommu/iommufd.c
+++ b/tools/testing/selftests/iommu/iommufd.c
@@ -1283,7 +1283,13 @@ TEST_F(iommufd_mock_domain, user_copy)
.dst_iova = MOCK_APERTURE_START,
.length = BUFFER_SIZE,
};
- unsigned int ioas_id;
+ struct iommu_ioas_unmap unmap_cmd = {
+ .size = sizeof(unmap_cmd),
+ .ioas_id = self->ioas_id,
+ .iova = MOCK_APERTURE_START,
+ .length = BUFFER_SIZE,
+ };
+ unsigned int new_ioas_id, ioas_id;
/* Pin the pages in an IOAS with no domains then copy to an IOAS with domains */
test_ioctl_ioas_alloc(&ioas_id);
@@ -1301,11 +1307,30 @@ TEST_F(iommufd_mock_domain, user_copy)
ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_COPY, ©_cmd));
check_mock_iova(buffer, MOCK_APERTURE_START, BUFFER_SIZE);
+ /* Now replace the ioas with a new one */
+ test_ioctl_ioas_alloc(&new_ioas_id);
+ test_ioctl_ioas_map_id(new_ioas_id, buffer, BUFFER_SIZE,
+ ©_cmd.src_iova);
+ test_cmd_access_replace_ioas(access_cmd.id, new_ioas_id);
+
+ /* Destroy the old ioas and cleanup copied mapping */
+ ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_UNMAP, &unmap_cmd));
+ test_ioctl_destroy(ioas_id);
+
+ /* Then run the same test again with the new ioas */
+ access_cmd.access_pages.iova = copy_cmd.src_iova;
+ ASSERT_EQ(0,
+ ioctl(self->fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_PAGES),
+ &access_cmd));
+ copy_cmd.src_ioas_id = new_ioas_id;
+ ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_COPY, ©_cmd));
+ check_mock_iova(buffer, MOCK_APERTURE_START, BUFFER_SIZE);
+
test_cmd_destroy_access_pages(
access_cmd.id, access_cmd.access_pages.out_access_pages_id);
test_cmd_destroy_access(access_cmd.id);
- test_ioctl_destroy(ioas_id);
+ test_ioctl_destroy(new_ioas_id);
}
TEST_F(iommufd_mock_domain, replace)
diff --git a/tools/testing/selftests/iommu/iommufd_utils.h b/tools/testing/selftests/iommu/iommufd_utils.h
index 53b4d3f2d9fc..70353e68e599 100644
--- a/tools/testing/selftests/iommu/iommufd_utils.h
+++ b/tools/testing/selftests/iommu/iommufd_utils.h
@@ -119,6 +119,25 @@ static int _test_cmd_hwpt_alloc(int fd, __u32 device_id, __u32 pt_id,
#define test_cmd_hwpt_alloc(device_id, pt_id, hwpt_id) \
ASSERT_EQ(0, _test_cmd_hwpt_alloc(self->fd, device_id, pt_id, hwpt_id))
+static int _test_cmd_access_replace_ioas(int fd, __u32 access_id,
+ unsigned int ioas_id)
+{
+ struct iommu_test_cmd cmd = {
+ .size = sizeof(cmd),
+ .op = IOMMU_TEST_OP_ACCESS_REPLACE_IOAS,
+ .id = access_id,
+ .access_replace_ioas = { .ioas_id = ioas_id },
+ };
+ int ret;
+
+ ret = ioctl(fd, IOMMU_TEST_CMD, &cmd);
+ if (ret)
+ return ret;
+ return 0;
+}
+#define test_cmd_access_replace_ioas(access_id, ioas_id) \
+ ASSERT_EQ(0, _test_cmd_access_replace_ioas(self->fd, access_id, ioas_id))
+
static int _test_cmd_create_access(int fd, unsigned int ioas_id,
__u32 *access_id, unsigned int flags)
{
--
2.40.1
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v7 4/4] vfio: Support IO page table replacement
2023-05-09 4:44 [PATCH v7 0/4] Add IO page table replacement support Nicolin Chen
` (2 preceding siblings ...)
2023-05-09 4:44 ` [PATCH v7 3/4] iommufd/selftest: Add IOMMU_TEST_OP_ACCESS_REPLACE_IOAS coverage Nicolin Chen
@ 2023-05-09 4:44 ` Nicolin Chen
3 siblings, 0 replies; 5+ messages in thread
From: Nicolin Chen @ 2023-05-09 4:44 UTC (permalink / raw)
To: jgg, kevin.tian, alex.williamson
Cc: yi.l.liu, joro, will, robin.murphy, shuah, linux-kernel, iommu,
kvm, linux-kselftest, mjrosato, farman
Now both the physical path and the emulated path should support an IO page
table replacement. Call iommufd_device_replace/iommufd_access_replace(),
when vdev->iommufd_attached is true.
Also update the VFIO_DEVICE_ATTACH_IOMMUFD_PT kdoc in the uAPI header.
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
---
drivers/vfio/iommufd.c | 11 ++++++-----
include/uapi/linux/vfio.h | 6 ++++++
2 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/drivers/vfio/iommufd.c b/drivers/vfio/iommufd.c
index 00c14821bfa5..99eaf03e337b 100644
--- a/drivers/vfio/iommufd.c
+++ b/drivers/vfio/iommufd.c
@@ -161,9 +161,9 @@ int vfio_iommufd_physical_attach_ioas(struct vfio_device *vdev, u32 *pt_id)
return -EINVAL;
if (vdev->iommufd_attached)
- return -EBUSY;
-
- rc = iommufd_device_attach(vdev->iommufd_device, pt_id);
+ rc = iommufd_device_replace(vdev->iommufd_device, pt_id);
+ else
+ rc = iommufd_device_attach(vdev->iommufd_device, pt_id);
if (rc)
return rc;
vdev->iommufd_attached = true;
@@ -243,8 +243,9 @@ int vfio_iommufd_emulated_attach_ioas(struct vfio_device *vdev, u32 *pt_id)
lockdep_assert_held(&vdev->dev_set->lock);
if (vdev->iommufd_attached)
- return -EBUSY;
- rc = iommufd_access_attach(vdev->iommufd_access, *pt_id);
+ rc = iommufd_access_replace(vdev->iommufd_access, *pt_id);
+ else
+ rc = iommufd_access_attach(vdev->iommufd_access, *pt_id);
if (rc)
return rc;
vdev->iommufd_attached = true;
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index 62bd41c214fd..e57112f63760 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -234,6 +234,12 @@ struct vfio_device_bind_iommufd {
*
* Undo by VFIO_DEVICE_DETACH_IOMMUFD_PT or device fd close.
*
+ * If a vfio device is currently attached to a valid hw_pagetable, without doing
+ * a VFIO_DEVICE_DETACH_IOMMUFD_PT, a second VFIO_DEVICE_ATTACH_IOMMUFD_PT ioctl
+ * passing in another hw_pagetable (hwpt) id is allowed. This action, also known
+ * as a hw_pagetable replacement, will replace the device's currently attached
+ * hw_pagetable with a new hw_pagetable corresponding to the given pt_id.
+ *
* @argsz: user filled size of this data.
* @flags: must be 0.
* @pt_id: Input the target id which can represent an ioas or a hwpt
--
2.40.1
^ permalink raw reply related [flat|nested] 5+ messages in thread