[PATCH v5 4/6] iommufd/selftest: Convert cache invalidation mocks to the core array loop
Nicolin Chen <[email protected]> Tue, 28 Jul 2026 10:33:36 -0700
| Newsgroups | dev.linux.lists.iommu,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <88ac1ce437afbef24368c9b9926b06b4aa445e91.1785258826.git.nicolinc@nvidia.com> |
The vIOMMU and the nested-domain selftest invalidation mocks each used to walk the whole request array on their own, with the vIOMMU mock even allocating a buffer sized to the entire array in order to do so first. The iommufd core now iterates the request array itself and re-invokes the op with the not-yet-handled sub-array, so handle just a single request per call out of the front of that sub-array and report one handled entry via the array->entry_num. Drop both of the loops and the kzalloc_objs() in the viommu callback function, and keep returning a success for an empty array as a probe of the selftest data type. Reviewed-by: Kevin Tian <[email protected]> Reviewed-by: Pranjal Shrivastava <[email protected]> Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Nicolin Chen <[email protected]> --- drivers/iommu/iommufd/selftest.c | 147 +++++++++++++++---------------- 1 file changed, 72 insertions(+), 75 deletions(-) diff --git a/drivers/iommu/iommufd/selftest.c b/drivers/iommu/iommufd/selftest.c index af07c642a5260..75846cf1f9c44 100644 --- a/drivers/iommu/iommufd/selftest.c +++ b/drivers/iommu/iommufd/selftest.c @@ -631,70 +631,63 @@ mock_viommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags, static int mock_viommu_cache_invalidate(struct iommufd_viommu *viommu, struct iommu_user_data_array *array) { - struct iommu_viommu_invalidate_selftest *cmds; - struct iommu_viommu_invalidate_selftest *cur; - struct iommu_viommu_invalidate_selftest *end; - int rc; + struct iommu_viommu_invalidate_selftest cmd; + struct mock_dev *mdev; + struct device *dev; + u32 processed = 0; + int rc = 0; + int i; - /* A zero-length array is allowed to validate the array type */ - if (array->entry_num == 0 && - array->type == IOMMU_VIOMMU_INVALIDATE_DATA_SELFTEST) { - array->entry_num = 0; - return 0; + if (array->type != IOMMU_VIOMMU_INVALIDATE_DATA_SELFTEST) { + rc = -EINVAL; + goto out; } - cmds = kzalloc_objs(*cmds, array->entry_num); - if (!cmds) - return -ENOMEM; - cur = cmds; - end = cmds + array->entry_num; + /* + * The core re-invokes this op for the remaining requests, so handle one + * request per call. A zero-length array only probes the type, validated + * above. + */ + if (!array->entry_num) + return 0; - static_assert(sizeof(*cmds) == 3 * sizeof(u32)); - rc = iommu_copy_struct_from_full_user_array( - cmds, sizeof(*cmds), array, - IOMMU_VIOMMU_INVALIDATE_DATA_SELFTEST); + rc = iommu_copy_struct_from_user_array( + &cmd, array, IOMMU_VIOMMU_INVALIDATE_DATA_SELFTEST, 0, + cache_id); if (rc) goto out; - while (cur != end) { - struct mock_dev *mdev; - struct device *dev; - int i; - - if (cur->flags & ~IOMMU_TEST_INVALIDATE_FLAG_ALL) { - rc = -EOPNOTSUPP; - goto out; - } - - if (cur->cache_id > MOCK_DEV_CACHE_ID_MAX) { - rc = -EINVAL; - goto out; - } + if (cmd.flags & ~IOMMU_TEST_INVALIDATE_FLAG_ALL) { + rc = -EOPNOTSUPP; + goto out; + } - xa_lock(&viommu->vdevs); - dev = iommufd_viommu_find_dev(viommu, - (unsigned long)cur->vdev_id); - if (!dev) { - xa_unlock(&viommu->vdevs); - rc = -EINVAL; - goto out; - } - mdev = container_of(dev, struct mock_dev, dev); + if (cmd.cache_id > MOCK_DEV_CACHE_ID_MAX) { + rc = -EINVAL; + goto out; + } - if (cur->flags & IOMMU_TEST_INVALIDATE_FLAG_ALL) { - /* Invalidate all cache entries and ignore cache_id */ - for (i = 0; i < MOCK_DEV_CACHE_NUM; i++) - mdev->cache[i] = 0; - } else { - mdev->cache[cur->cache_id] = 0; - } + xa_lock(&viommu->vdevs); + dev = iommufd_viommu_find_dev(viommu, (unsigned long)cmd.vdev_id); + if (!dev) { xa_unlock(&viommu->vdevs); - - cur++; + rc = -EINVAL; + goto out; + } + mdev = container_of(dev, struct mock_dev, dev); + + if (cmd.flags & IOMMU_TEST_INVALIDATE_FLAG_ALL) { + /* Invalidate all cache entries and ignore cache_id */ + for (i = 0; i < MOCK_DEV_CACHE_NUM; i++) + mdev->cache[i] = 0; + } else { + mdev->cache[cmd.cache_id] = 0; } + xa_unlock(&viommu->vdevs); + + processed = 1; out: - array->entry_num = cur - cmds; - kfree(cmds); + array->entry_num = processed; return rc; } @@ -875,42 +868,46 @@ mock_domain_cache_invalidate_user(struct iommu_domain *domain, struct mock_iommu_domain_nested *mock_nested = to_mock_nested(domain); struct iommu_hwpt_invalidate_selftest inv; u32 processed = 0; - int i = 0, j; int rc = 0; + int i; if (array->type != IOMMU_HWPT_INVALIDATE_DATA_SELFTEST) { rc = -EINVAL; goto out; } - for ( ; i < array->entry_num; i++) { - rc = iommu_copy_struct_from_user_array(&inv, array, - IOMMU_HWPT_INVALIDATE_DATA_SELFTEST, - i, iotlb_id); - if (rc) - break; + /* + * The core re-invokes this op for the remaining requests, so handle one + * request per call. A zero-length array only probes the type, validated + * above. + */ + if (!array->entry_num) + return 0; - if (inv.flags & ~IOMMU_TEST_INVALIDATE_FLAG_ALL) { - rc = -EOPNOTSUPP; - break; - } + rc = iommu_copy_struct_from_user_array( + &inv, array, IOMMU_HWPT_INVALIDATE_DATA_SELFTEST, 0, iotlb_id); + if (rc) + goto out; - if (inv.iotlb_id > MOCK_NESTED_DOMAIN_IOTLB_ID_MAX) { - rc = -EINVAL; - break; - } + if (inv.flags & ~IOMMU_TEST_INVALIDATE_FLAG_ALL) { + rc = -EOPNOTSUPP; + goto out; + } - if (inv.flags & IOMMU_TEST_INVALIDATE_FLAG_ALL) { - /* Invalidate all mock iotlb entries and ignore iotlb_id */ - for (j = 0; j < MOCK_NESTED_DOMAIN_IOTLB_NUM; j++) - mock_nested->iotlb[j] = 0; - } else { - mock_nested->iotlb[inv.iotlb_id] = 0; - } + if (inv.iotlb_id > MOCK_NESTED_DOMAIN_IOTLB_ID_MAX) { + rc = -EINVAL; + goto out; + } - processed++; + if (inv.flags & IOMMU_TEST_INVALIDATE_FLAG_ALL) { + /* Invalidate all mock iotlb entries and ignore iotlb_id */ + for (i = 0; i < MOCK_NESTED_DOMAIN_IOTLB_NUM; i++) + mock_nested->iotlb[i] = 0; + } else { + mock_nested->iotlb[inv.iotlb_id] = 0; } + processed = 1; out: array->entry_num = processed; return rc; -- 2.43.0