On Sun, Jun 16, 2024 at 02:11:49PM +0800, Lu Baolu wrote: > +int iommu_replace_group_handle(struct iommu_group *group, > + struct iommu_domain *new_domain, > + struct iommu_attach_handle *handle) > +{ > + struct iommu_domain *old_domain = group->domain; > + void *curr; > + int ret; > + > + if (!new_domain) > + return -EINVAL; > + > + mutex_lock(&group->mutex); > + ret = __iommu_group_set_domain(group, new_domain); > + if (ret) > + goto err_unlock; > + xa_erase(&group->pasid_array, IOMMU_NO_PASID); > + if (handle) { > + curr = xa_store(&group->pasid_array, IOMMU_NO_PASID, handle, GFP_KERNEL); > + if (xa_err(curr)) { > + ret = xa_err(curr); > + goto err_restore; But this error unwind doesn't work because the xa_erase() already happened and there may have been a handle there that we don't put back. Something like this - store to a reserved entry cannot fail: int iommu_replace_group_handle(struct iommu_group *group, struct iommu_domain *new_domain, struct iommu_attach_handle *handle) { void *curr; int ret; if (!new_domain) return -EINVAL; mutex_lock(&group->mutex); if (handle) { ret = xa_reserve(&group->pasid_array, IOMMU_NO_PASID, GFP_KERNEL); if (ret) goto err_unlock; } ret = __iommu_group_set_domain(group, new_domain); if (ret) goto err_release; curr = xa_store(&group->pasid_array, IOMMU_NO_PASID, handle, GFP_KERNEL); WARN_ON(xa_is_err(curr)); mutex_unlock(&group->mutex); return 0; err_release: xa_release(&group->pasid_array, IOMMU_NO_PASID); err_unlock: mutex_unlock(&group->mutex); return ret; } Jason