Skip to content

Commit f15d9a9

Browse files
committed
iommu/amd: Remove domain->updated
This struct member was used to track whether a domain change requires updates to the device-table and IOMMU cache flushes. The problem is, that access to this field is racy since locking in the common mapping code-paths has been eliminated. Move the updated field to the stack to get rid of all potential races and remove the field from the struct. Fixes: 92d420e ("iommu/amd: Relax locking in dma_ops path") Reviewed-by: Filippo Sironi <[email protected]> Reviewed-by: Jerry Snitselaar <[email protected]> Signed-off-by: Joerg Roedel <[email protected]>
1 parent 0b15e02 commit f15d9a9

File tree

2 files changed

+25
-25
lines changed

2 files changed

+25
-25
lines changed

drivers/iommu/amd_iommu.c

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,10 +1458,11 @@ static void free_pagetable(struct protection_domain *domain)
14581458
* another level increases the size of the address space by 9 bits to a size up
14591459
* to 64 bits.
14601460
*/
1461-
static void increase_address_space(struct protection_domain *domain,
1461+
static bool increase_address_space(struct protection_domain *domain,
14621462
gfp_t gfp)
14631463
{
14641464
unsigned long flags;
1465+
bool ret = false;
14651466
u64 *pte;
14661467

14671468
spin_lock_irqsave(&domain->lock, flags);
@@ -1478,27 +1479,29 @@ static void increase_address_space(struct protection_domain *domain,
14781479
iommu_virt_to_phys(domain->pt_root));
14791480
domain->pt_root = pte;
14801481
domain->mode += 1;
1481-
domain->updated = true;
1482+
1483+
ret = true;
14821484

14831485
out:
14841486
spin_unlock_irqrestore(&domain->lock, flags);
14851487

1486-
return;
1488+
return ret;
14871489
}
14881490

14891491
static u64 *alloc_pte(struct protection_domain *domain,
14901492
unsigned long address,
14911493
unsigned long page_size,
14921494
u64 **pte_page,
1493-
gfp_t gfp)
1495+
gfp_t gfp,
1496+
bool *updated)
14941497
{
14951498
int level, end_lvl;
14961499
u64 *pte, *page;
14971500

14981501
BUG_ON(!is_power_of_2(page_size));
14991502

15001503
while (address > PM_LEVEL_SIZE(domain->mode))
1501-
increase_address_space(domain, gfp);
1504+
*updated = increase_address_space(domain, gfp) || *updated;
15021505

15031506
level = domain->mode - 1;
15041507
pte = &domain->pt_root[PM_LEVEL_INDEX(level, address)];
@@ -1530,7 +1533,7 @@ static u64 *alloc_pte(struct protection_domain *domain,
15301533
for (i = 0; i < count; ++i)
15311534
cmpxchg64(&lpte[i], __pte, 0ULL);
15321535

1533-
domain->updated = true;
1536+
*updated = true;
15341537
continue;
15351538
}
15361539

@@ -1547,7 +1550,7 @@ static u64 *alloc_pte(struct protection_domain *domain,
15471550
if (cmpxchg64(pte, __pte, __npte) != __pte)
15481551
free_page((unsigned long)page);
15491552
else if (IOMMU_PTE_PRESENT(__pte))
1550-
domain->updated = true;
1553+
*updated = true;
15511554

15521555
continue;
15531556
}
@@ -1656,28 +1659,29 @@ static int iommu_map_page(struct protection_domain *dom,
16561659
gfp_t gfp)
16571660
{
16581661
struct page *freelist = NULL;
1662+
bool updated = false;
16591663
u64 __pte, *pte;
1660-
int i, count;
1664+
int ret, i, count;
16611665

16621666
BUG_ON(!IS_ALIGNED(bus_addr, page_size));
16631667
BUG_ON(!IS_ALIGNED(phys_addr, page_size));
16641668

1669+
ret = -EINVAL;
16651670
if (!(prot & IOMMU_PROT_MASK))
1666-
return -EINVAL;
1671+
goto out;
16671672

16681673
count = PAGE_SIZE_PTE_COUNT(page_size);
1669-
pte = alloc_pte(dom, bus_addr, page_size, NULL, gfp);
1674+
pte = alloc_pte(dom, bus_addr, page_size, NULL, gfp, &updated);
16701675

1671-
if (!pte) {
1672-
update_domain(dom);
1673-
return -ENOMEM;
1674-
}
1676+
ret = -ENOMEM;
1677+
if (!pte)
1678+
goto out;
16751679

16761680
for (i = 0; i < count; ++i)
16771681
freelist = free_clear_pte(&pte[i], pte[i], freelist);
16781682

16791683
if (freelist != NULL)
1680-
dom->updated = true;
1684+
updated = true;
16811685

16821686
if (count > 1) {
16831687
__pte = PAGE_SIZE_PTE(__sme_set(phys_addr), page_size);
@@ -1693,12 +1697,16 @@ static int iommu_map_page(struct protection_domain *dom,
16931697
for (i = 0; i < count; ++i)
16941698
pte[i] = __pte;
16951699

1696-
update_domain(dom);
1700+
ret = 0;
1701+
1702+
out:
1703+
if (updated)
1704+
update_domain(dom);
16971705

16981706
/* Everything flushed out, free pages now */
16991707
free_page_list(freelist);
17001708

1701-
return 0;
1709+
return ret;
17021710
}
17031711

17041712
static unsigned long iommu_unmap_page(struct protection_domain *dom,
@@ -2399,15 +2407,10 @@ static void update_device_table(struct protection_domain *domain)
23992407

24002408
static void update_domain(struct protection_domain *domain)
24012409
{
2402-
if (!domain->updated)
2403-
return;
2404-
24052410
update_device_table(domain);
24062411

24072412
domain_flush_devices(domain);
24082413
domain_flush_tlb_pde(domain);
2409-
2410-
domain->updated = false;
24112414
}
24122415

24132416
static int dir2prot(enum dma_data_direction direction)
@@ -3333,7 +3336,6 @@ void amd_iommu_domain_direct_map(struct iommu_domain *dom)
33333336

33343337
/* Update data structure */
33353338
domain->mode = PAGE_MODE_NONE;
3336-
domain->updated = true;
33373339

33383340
/* Make changes visible to IOMMUs */
33393341
update_domain(domain);
@@ -3379,7 +3381,6 @@ int amd_iommu_domain_enable_v2(struct iommu_domain *dom, int pasids)
33793381

33803382
domain->glx = levels;
33813383
domain->flags |= PD_IOMMUV2_MASK;
3382-
domain->updated = true;
33833384

33843385
update_domain(domain);
33853386

drivers/iommu/amd_iommu_types.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,6 @@ struct protection_domain {
475475
int glx; /* Number of levels for GCR3 table */
476476
u64 *gcr3_tbl; /* Guest CR3 table */
477477
unsigned long flags; /* flags to find out type of domain */
478-
bool updated; /* complete domain flush required */
479478
unsigned dev_cnt; /* devices assigned to this domain */
480479
unsigned dev_iommu[MAX_IOMMUS]; /* per-IOMMU reference count */
481480
};

0 commit comments

Comments
 (0)