static void vfio_iommu_type1_detach_group()

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);
}