Skip to content

Commit 9cd4f14

Browse files
LuBaolujoergroedel
authored andcommitted
iommu/vt-d: Fix possible recursive locking in intel_iommu_init()
The global rwsem dmar_global_lock was introduced by commit 3a5670e ("iommu/vt-d: Introduce a rwsem to protect global data structures"). It is used to protect DMAR related global data from DMAR hotplug operations. The dmar_global_lock used in the intel_iommu_init() might cause recursive locking issue, for example, intel_iommu_get_resv_regions() is taking the dmar_global_lock from within a section where intel_iommu_init() already holds it via probe_acpi_namespace_devices(). Using dmar_global_lock in intel_iommu_init() could be relaxed since it is unlikely that any IO board must be hot added before the IOMMU subsystem is initialized. This eliminates the possible recursive locking issue by moving down DMAR hotplug support after the IOMMU is initialized and removing the uses of dmar_global_lock in intel_iommu_init(). Fixes: d5692d4 ("iommu/vt-d: Fix suspicious RCU usage in probe_acpi_namespace_devices()") Reported-by: Robin Murphy <[email protected]> Signed-off-by: Lu Baolu <[email protected]> Reviewed-by: Kevin Tian <[email protected]> Link: https://lore.kernel.org/r/894db0ccae854b35c73814485569b634237b5538.1657034828.git.robin.murphy@arm.com Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent 91c98fe commit 9cd4f14

File tree

3 files changed

+12
-26
lines changed

3 files changed

+12
-26
lines changed

drivers/iommu/intel/dmar.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2349,6 +2349,13 @@ static int dmar_device_hotplug(acpi_handle handle, bool insert)
23492349
if (!dmar_in_use())
23502350
return 0;
23512351

2352+
/*
2353+
* It's unlikely that any I/O board is hot added before the IOMMU
2354+
* subsystem is initialized.
2355+
*/
2356+
if (IS_ENABLED(CONFIG_INTEL_IOMMU) && !intel_iommu_enabled)
2357+
return -EOPNOTSUPP;
2358+
23522359
if (dmar_detect_dsm(handle, DMAR_DSM_FUNC_DRHD)) {
23532360
tmp = handle;
23542361
} else {

drivers/iommu/intel/iommu.c

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3019,13 +3019,7 @@ static int __init init_dmars(void)
30193019

30203020
#ifdef CONFIG_INTEL_IOMMU_SVM
30213021
if (pasid_supported(iommu) && ecap_prs(iommu->ecap)) {
3022-
/*
3023-
* Call dmar_alloc_hwirq() with dmar_global_lock held,
3024-
* could cause possible lock race condition.
3025-
*/
3026-
up_write(&dmar_global_lock);
30273022
ret = intel_svm_enable_prq(iommu);
3028-
down_write(&dmar_global_lock);
30293023
if (ret)
30303024
goto free_iommu;
30313025
}
@@ -3938,7 +3932,6 @@ int __init intel_iommu_init(void)
39383932
force_on = (!intel_iommu_tboot_noforce && tboot_force_iommu()) ||
39393933
platform_optin_force_iommu();
39403934

3941-
down_write(&dmar_global_lock);
39423935
if (dmar_table_init()) {
39433936
if (force_on)
39443937
panic("tboot: Failed to initialize DMAR table\n");
@@ -3951,16 +3944,6 @@ int __init intel_iommu_init(void)
39513944
goto out_free_dmar;
39523945
}
39533946

3954-
up_write(&dmar_global_lock);
3955-
3956-
/*
3957-
* The bus notifier takes the dmar_global_lock, so lockdep will
3958-
* complain later when we register it under the lock.
3959-
*/
3960-
dmar_register_bus_notifier();
3961-
3962-
down_write(&dmar_global_lock);
3963-
39643947
if (!no_iommu)
39653948
intel_iommu_debugfs_init();
39663949

@@ -4005,11 +3988,9 @@ int __init intel_iommu_init(void)
40053988
pr_err("Initialization failed\n");
40063989
goto out_free_dmar;
40073990
}
4008-
up_write(&dmar_global_lock);
40093991

40103992
init_iommu_pm_ops();
40113993

4012-
down_read(&dmar_global_lock);
40133994
for_each_active_iommu(iommu, drhd) {
40143995
/*
40153996
* The flush queue implementation does not perform
@@ -4027,13 +4008,11 @@ int __init intel_iommu_init(void)
40274008
"%s", iommu->name);
40284009
iommu_device_register(&iommu->iommu, &intel_iommu_ops, NULL);
40294010
}
4030-
up_read(&dmar_global_lock);
40314011

40324012
bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
40334013
if (si_domain && !hw_pass_through)
40344014
register_memory_notifier(&intel_iommu_memory_nb);
40354015

4036-
down_read(&dmar_global_lock);
40374016
if (probe_acpi_namespace_devices())
40384017
pr_warn("ACPI name space devices didn't probe correctly\n");
40394018

@@ -4044,17 +4023,15 @@ int __init intel_iommu_init(void)
40444023

40454024
iommu_disable_protect_mem_regions(iommu);
40464025
}
4047-
up_read(&dmar_global_lock);
4048-
4049-
pr_info("Intel(R) Virtualization Technology for Directed I/O\n");
40504026

40514027
intel_iommu_enabled = 1;
4028+
dmar_register_bus_notifier();
4029+
pr_info("Intel(R) Virtualization Technology for Directed I/O\n");
40524030

40534031
return 0;
40544032

40554033
out_free_dmar:
40564034
intel_iommu_free_dmars();
4057-
up_write(&dmar_global_lock);
40584035
return ret;
40594036
}
40604037

include/linux/dmar.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ struct dmar_pci_notify_info {
6565

6666
extern struct rw_semaphore dmar_global_lock;
6767
extern struct list_head dmar_drhd_units;
68+
extern int intel_iommu_enabled;
6869

6970
#define for_each_drhd_unit(drhd) \
7071
list_for_each_entry_rcu(drhd, &dmar_drhd_units, list, \
@@ -88,7 +89,8 @@ extern struct list_head dmar_drhd_units;
8889
static inline bool dmar_rcu_check(void)
8990
{
9091
return rwsem_is_locked(&dmar_global_lock) ||
91-
system_state == SYSTEM_BOOTING;
92+
system_state == SYSTEM_BOOTING ||
93+
(IS_ENABLED(CONFIG_INTEL_IOMMU) && !intel_iommu_enabled);
9294
}
9395

9496
#define dmar_rcu_dereference(p) rcu_dereference_check((p), dmar_rcu_check())

0 commit comments

Comments
 (0)