in vfio_iommu_type1.c [2454:2536]
static void vfio_iommu_type1_detach_group(void *iommu_data,
struct iommu_group *iommu_group)
{
struct vfio_iommu *iommu = iommu_data;
struct vfio_domain *domain;
struct vfio_iommu_group *group;
bool update_dirty_scope = false;
LIST_HEAD(iova_copy);
mutex_lock(&iommu->lock);
list_for_each_entry(group, &iommu->emulated_iommu_groups, next) {
if (group->iommu_group != iommu_group)
continue;
update_dirty_scope = !group->pinned_page_dirty_scope;
list_del(&group->next);
kfree(group);
if (list_empty(&iommu->emulated_iommu_groups) &&
list_empty(&iommu->domain_list)) {
WARN_ON(iommu->notifier.head);
vfio_iommu_unmap_unpin_all(iommu);
}
goto detach_group_done;
}
/*
* Get a copy of iova list. This will be used to update
* and to replace the current one later. Please note that
* we will leave the original list as it is if update fails.
*/
vfio_iommu_iova_get_copy(iommu, &iova_copy);
list_for_each_entry(domain, &iommu->domain_list, next) {
group = find_iommu_group(domain, iommu_group);
if (!group)
continue;
iommu_detach_group(domain->domain, group->iommu_group);
update_dirty_scope = !group->pinned_page_dirty_scope;
list_del(&group->next);
kfree(group);
/*
* Group ownership provides privilege, if the group list is
* empty, the domain goes away. If it's the last domain with
* iommu and external domain doesn't exist, then all the
* mappings go away too. If it's the last domain with iommu and
* external domain exist, update accounting
*/
if (list_empty(&domain->group_list)) {
if (list_is_singular(&iommu->domain_list)) {
if (list_empty(&iommu->emulated_iommu_groups)) {
WARN_ON(iommu->notifier.head);
vfio_iommu_unmap_unpin_all(iommu);
} else {
vfio_iommu_unmap_unpin_reaccount(iommu);
}
}
iommu_domain_free(domain->domain);
list_del(&domain->next);
kfree(domain);
vfio_iommu_aper_expand(iommu, &iova_copy);
vfio_update_pgsize_bitmap(iommu);
}
break;
}
if (!vfio_iommu_resv_refresh(iommu, &iova_copy))
vfio_iommu_iova_insert_copy(iommu, &iova_copy);
else
vfio_iommu_iova_free(&iova_copy);
detach_group_done:
/*
* Removal of a group without dirty tracking may allow the iommu scope
* to be promoted.
*/
if (update_dirty_scope) {
iommu->num_non_pinned_groups--;
if (iommu->dirty_page_tracking)
vfio_iommu_populate_bitmap_full(iommu);
}
mutex_unlock(&iommu->lock);
}