Commit 94a91b50 authored by Donald Dutile's avatar Donald Dutile Committed by David Woodhouse
Browse files

intel-iommu: iommu init error path bug fixes



The kcalloc() failure path in iommu_init_domains() calls
free_dmar_iommu(), which assumes that ->domains, ->domain_ids,
and ->lock have been properly initialized.

Add checks in free_[dmar]_iommu to not use ->domains,->domain_ids
if not alloced. Move the lock init to prior to the kcalloc()'s,
so it is valid in free_context_table() when free_dmar_iommu() invokes
it at the end.

Patch based on iommu-2.6,
commit 13203227

Signed-off-by: default avatarDonald Dutile <ddutile@redhat.com>
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent 071e1374
Loading
Loading
Loading
Loading
+18 −17
Original line number Original line Diff line number Diff line
@@ -1158,6 +1158,8 @@ static int iommu_init_domains(struct intel_iommu *iommu)
	pr_debug("Number of Domains supportd <%ld>\n", ndomains);
	pr_debug("Number of Domains supportd <%ld>\n", ndomains);
	nlongs = BITS_TO_LONGS(ndomains);
	nlongs = BITS_TO_LONGS(ndomains);


	spin_lock_init(&iommu->lock);

	/* TBD: there might be 64K domains,
	/* TBD: there might be 64K domains,
	 * consider other allocation for future chip
	 * consider other allocation for future chip
	 */
	 */
@@ -1170,12 +1172,9 @@ static int iommu_init_domains(struct intel_iommu *iommu)
			GFP_KERNEL);
			GFP_KERNEL);
	if (!iommu->domains) {
	if (!iommu->domains) {
		printk(KERN_ERR "Allocating domain array failed\n");
		printk(KERN_ERR "Allocating domain array failed\n");
		kfree(iommu->domain_ids);
		return -ENOMEM;
		return -ENOMEM;
	}
	}


	spin_lock_init(&iommu->lock);

	/*
	/*
	 * if Caching mode is set, then invalid translations are tagged
	 * if Caching mode is set, then invalid translations are tagged
	 * with domainid 0. Hence we need to pre-allocate it.
	 * with domainid 0. Hence we need to pre-allocate it.
@@ -1195,6 +1194,7 @@ void free_dmar_iommu(struct intel_iommu *iommu)
	int i;
	int i;
	unsigned long flags;
	unsigned long flags;


	if ((iommu->domains) && (iommu->domain_ids)) {
		i = find_first_bit(iommu->domain_ids, cap_ndoms(iommu->cap));
		i = find_first_bit(iommu->domain_ids, cap_ndoms(iommu->cap));
		for (; i < cap_ndoms(iommu->cap); ) {
		for (; i < cap_ndoms(iommu->cap); ) {
			domain = iommu->domains[i];
			domain = iommu->domains[i];
@@ -1212,6 +1212,7 @@ void free_dmar_iommu(struct intel_iommu *iommu)
			i = find_next_bit(iommu->domain_ids,
			i = find_next_bit(iommu->domain_ids,
				cap_ndoms(iommu->cap), i+1);
				cap_ndoms(iommu->cap), i+1);
		}
		}
	}


	if (iommu->gcmd & DMA_GCMD_TE)
	if (iommu->gcmd & DMA_GCMD_TE)
		iommu_disable_translation(iommu);
		iommu_disable_translation(iommu);