Skip to content

Commit 5f64ce5

Browse files
eaugerjoergroedel
authored andcommitted
iommu/vt-d: Duplicate iommu_resv_region objects per device list
intel_iommu_get_resv_regions() aims to return the list of reserved regions accessible by a given @device. However several devices can access the same reserved memory region and when building the list it is not safe to use a single iommu_resv_region object, whose container is the RMRR. This iommu_resv_region must be duplicated per device reserved region list. Let's remove the struct iommu_resv_region from the RMRR unit and allocate the iommu_resv_region directly in intel_iommu_get_resv_regions(). We hold the dmar_global_lock instead of the rcu-lock to allow sleeping. Fixes: 0659b8d ("iommu/vt-d: Implement reserved region get/put callbacks") Signed-off-by: Eric Auger <[email protected]> Reviewed-by: Lu Baolu <[email protected]> Signed-off-by: Joerg Roedel <[email protected]>
1 parent ad0834d commit 5f64ce5

File tree

1 file changed

+17
-17
lines changed

1 file changed

+17
-17
lines changed

drivers/iommu/intel-iommu.c

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,6 @@ struct dmar_rmrr_unit {
324324
u64 end_address; /* reserved end address */
325325
struct dmar_dev_scope *devices; /* target devices */
326326
int devices_cnt; /* target device count */
327-
struct iommu_resv_region *resv; /* reserved region handle */
328327
};
329328

330329
struct dmar_atsr_unit {
@@ -4050,7 +4049,6 @@ static inline void init_iommu_pm_ops(void) {}
40504049
int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg)
40514050
{
40524051
struct acpi_dmar_reserved_memory *rmrr;
4053-
int prot = DMA_PTE_READ|DMA_PTE_WRITE;
40544052
struct dmar_rmrr_unit *rmrru;
40554053
size_t length;
40564054

@@ -4064,22 +4062,16 @@ int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg)
40644062
rmrru->end_address = rmrr->end_address;
40654063

40664064
length = rmrr->end_address - rmrr->base_address + 1;
4067-
rmrru->resv = iommu_alloc_resv_region(rmrr->base_address, length, prot,
4068-
IOMMU_RESV_DIRECT);
4069-
if (!rmrru->resv)
4070-
goto free_rmrru;
40714065

40724066
rmrru->devices = dmar_alloc_dev_scope((void *)(rmrr + 1),
40734067
((void *)rmrr) + rmrr->header.length,
40744068
&rmrru->devices_cnt);
40754069
if (rmrru->devices_cnt && rmrru->devices == NULL)
4076-
goto free_all;
4070+
goto free_rmrru;
40774071

40784072
list_add(&rmrru->list, &dmar_rmrr_units);
40794073

40804074
return 0;
4081-
free_all:
4082-
kfree(rmrru->resv);
40834075
free_rmrru:
40844076
kfree(rmrru);
40854077
out:
@@ -4297,7 +4289,6 @@ static void intel_iommu_free_dmars(void)
42974289
list_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) {
42984290
list_del(&rmrru->list);
42994291
dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt);
4300-
kfree(rmrru->resv);
43014292
kfree(rmrru);
43024293
}
43034294

@@ -5400,22 +5391,33 @@ static void intel_iommu_remove_device(struct device *dev)
54005391
static void intel_iommu_get_resv_regions(struct device *device,
54015392
struct list_head *head)
54025393
{
5394+
int prot = DMA_PTE_READ | DMA_PTE_WRITE;
54035395
struct iommu_resv_region *reg;
54045396
struct dmar_rmrr_unit *rmrr;
54055397
struct device *i_dev;
54065398
int i;
54075399

5408-
rcu_read_lock();
5400+
down_read(&dmar_global_lock);
54095401
for_each_rmrr_units(rmrr) {
54105402
for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt,
54115403
i, i_dev) {
5404+
struct iommu_resv_region *resv;
5405+
size_t length;
5406+
54125407
if (i_dev != device)
54135408
continue;
54145409

5415-
list_add_tail(&rmrr->resv->list, head);
5410+
length = rmrr->end_address - rmrr->base_address + 1;
5411+
resv = iommu_alloc_resv_region(rmrr->base_address,
5412+
length, prot,
5413+
IOMMU_RESV_DIRECT);
5414+
if (!resv)
5415+
break;
5416+
5417+
list_add_tail(&resv->list, head);
54165418
}
54175419
}
5418-
rcu_read_unlock();
5420+
up_read(&dmar_global_lock);
54195421

54205422
#ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA
54215423
if (dev_is_pci(device)) {
@@ -5443,10 +5445,8 @@ static void intel_iommu_put_resv_regions(struct device *dev,
54435445
{
54445446
struct iommu_resv_region *entry, *next;
54455447

5446-
list_for_each_entry_safe(entry, next, head, list) {
5447-
if (entry->type == IOMMU_RESV_MSI)
5448-
kfree(entry);
5449-
}
5448+
list_for_each_entry_safe(entry, next, head, list)
5449+
kfree(entry);
54505450
}
54515451

54525452
int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct device *dev)

0 commit comments

Comments
 (0)