From: Nicolin Chen <nicolinc@nvidia.com>
To: Will Deacon <will@kernel.org>, Jason Gunthorpe <jgg@nvidia.com>
Cc: Robin Murphy <robin.murphy@arm.com>, <joro@8bytes.org>,
Kevin Tian <kevin.tian@intel.com>,
David Woodhouse <dwmw2@infradead.org>,
Lu Baolu <baolu.lu@linux.intel.com>,
<linux-arm-kernel@lists.infradead.org>, <iommu@lists.linux.dev>,
<linux-kernel@vger.kernel.org>,
Pranjal Shrivastava <praan@google.com>
Subject: [PATCH v6 4/5] iommu/arm-smmu-v3-iommufd: Convert cache invalidation to the core array loop
Date: Sun, 30 Aug 2026 15:26:41 -0700 [thread overview]
Message-ID: <5223275dbc8ef00af233f3fee01efa09e45f26b5.1788127877.git.nicolinc@nvidia.com> (raw)
In-Reply-To: <cover.1788127877.git.nicolinc@nvidia.com>
arm_vsmmu_cache_invalidate() allocated a buffer for the entire user request
array, walked the array converting each of the commands, and issued those
converted commands to the cmdq in CMDQ_BATCH_ENTRIES sized chunks, carrying
the sub-array bookkeeping all on its own.
The iommufd core now iterates the invalidation array and re-invokes the op
with the not-yet-handled sub-array, so the driver only has to proceed with
a single chunk per call.
Instead of a per-array allocation, use a fixed on-stack batch to copy from
the userspace array. If the copy fails due to nonzero padding (VMM violates
the ABI), fail the entire batch.
Convert the whole batch before issuing any of it: a malformed command is a
userspace bug, so the first illegal command fails the batch as a unit,
issuing nothing and leaving array->entry_num at zero, the same way the copy
above bails on nonzero padding. A batch that converts cleanly is issued in
full, so the op returns either a handled count with no error or zero with
an error.
A zero-length array now returns success once the data type gets validated,
matching the documented probe behavior, rather than the -EINVAL that the
full-array copy helper would previously return.
This also fixes two long-standing bugs:
1) On a conversion failure the old code reported commands that it had
converted but not yet issued, so user space advanced its consumer
index past invalidations that never reached the cmdq.
2) A zero-length array was rejected with -EINVAL, although the uAPI
documents it as a valid request that only probes the data type.
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Pranjal Shrivastava <praan@google.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
---
.../arm/arm-smmu-v3/arm-smmu-v3-iommufd.c | 68 +++++++++++--------
1 file changed, 38 insertions(+), 30 deletions(-)
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
index 747b9d47ff7e4..ab1078a97d801 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
@@ -478,49 +478,57 @@ int arm_vsmmu_cache_invalidate(struct iommufd_viommu *viommu,
struct iommu_user_data_array *array)
{
struct arm_vsmmu *vsmmu = container_of(viommu, struct arm_vsmmu, core);
+ struct arm_vsmmu_invalidation_cmd cmds[CMDQ_BATCH_ENTRIES - 1];
struct arm_smmu_device *smmu = vsmmu->smmu;
- struct arm_vsmmu_invalidation_cmd *last;
- struct arm_vsmmu_invalidation_cmd *cmds;
- struct arm_vsmmu_invalidation_cmd *cur;
- struct arm_vsmmu_invalidation_cmd *end;
+ struct iommu_user_data_array batch = {
+ .type = array->type,
+ .uptr = array->uptr,
+ .entry_len = array->entry_len,
+ };
+ u32 processed = 0;
int ret;
-
- cmds = kzalloc_objs(*cmds, array->entry_num);
- if (!cmds)
- return -ENOMEM;
- cur = cmds;
- end = cmds + array->entry_num;
+ u32 i;
static_assert(sizeof(*cmds) == 2 * sizeof(u64));
+
+ if (array->type != IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* A zero-length array only probes the type, validated above */
+ if (!array->entry_num)
+ return 0;
+
+ /*
+ * The core re-invokes this op for the remaining requests, so copy one
+ * cmdq batch worth of commands into a fixed on-stack buffer rather than
+ * allocating for the whole array.
+ */
+ batch.entry_num = min_t(u32, array->entry_num, ARRAY_SIZE(cmds));
ret = iommu_copy_struct_from_full_user_array(
- cmds, sizeof(*cmds), array,
+ cmds, sizeof(*cmds), &batch,
IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3);
if (ret)
goto out;
- last = cmds;
- while (cur != end) {
- ret = arm_vsmmu_convert_user_cmd(vsmmu, cur);
+ /*
+ * Convert the whole batch. Sending an illegal command is a VMM bug, so
+ * a single one fails the entire batch, issuing nothing.
+ */
+ for (i = 0; i < batch.entry_num; i++) {
+ ret = arm_vsmmu_convert_user_cmd(vsmmu, &cmds[i]);
if (ret)
goto out;
-
- /* FIXME work in blocks of CMDQ_BATCH_ENTRIES and copy each block? */
- cur++;
- if (cur != end && (cur - last) != CMDQ_BATCH_ENTRIES - 1)
- continue;
-
- /* FIXME always uses the main cmdq rather than trying to group by type */
- ret = __arm_smmu_cmdq_issue_cmdlist(smmu, &smmu->cmdq, &last->cmd,
- cur - last, true);
- if (ret) {
- cur--;
- goto out;
- }
- last = cur;
}
+
+ /* FIXME always uses the main cmdq rather than trying to group by type */
+ ret = __arm_smmu_cmdq_issue_cmdlist(smmu, &smmu->cmdq, &cmds->cmd,
+ batch.entry_num, true);
+ if (!ret)
+ processed = batch.entry_num;
out:
- array->entry_num = cur - cmds;
- kfree(cmds);
+ array->entry_num = processed;
return ret;
}
--
2.43.0
next prev parent reply other threads:[~2026-08-30 22:27 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-30 22:26 [PATCH v6 0/5] iommufd: Iterate the cache invalidation array in the core Nicolin Chen
2026-08-30 22:26 ` [PATCH v6 1/5] iommu/arm-smmu-v3-iommufd: Reject unsupported bits in invalidation commands Nicolin Chen
2026-08-30 22:26 ` [PATCH v6 2/5] iommufd: Iterate the cache invalidation array in the core Nicolin Chen
2026-08-30 22:26 ` [PATCH v6 3/5] iommufd/selftest: Convert cache invalidation mocks to the core array loop Nicolin Chen
2026-08-30 22:26 ` Nicolin Chen [this message]
2026-08-30 22:26 ` [PATCH v6 5/5] iommu/vt-d: Convert nested cache invalidation " Nicolin Chen
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=5223275dbc8ef00af233f3fee01efa09e45f26b5.1788127877.git.nicolinc@nvidia.com \
--to=nicolinc@nvidia.com \
--cc=baolu.lu@linux.intel.com \
--cc=dwmw2@infradead.org \
--cc=iommu@lists.linux.dev \
--cc=jgg@nvidia.com \
--cc=joro@8bytes.org \
--cc=kevin.tian@intel.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=praan@google.com \
--cc=robin.murphy@arm.com \
--cc=will@kernel.org \
/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