linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/1] iommu/vt-d: Fix possible recursive locking in intel_iommu_init()
@ 2022-07-18 23:53 Lu Baolu
  2022-07-21  7:39 ` Tian, Kevin
  0 siblings, 1 reply; 7+ messages in thread
From: Lu Baolu @ 2022-07-18 23:53 UTC (permalink / raw)
  To: iommu
  Cc: Joerg Roedel, Will Deacon, Robin Murphy, Kevin Tian,
	linux-kernel, Lu Baolu

The global rwsem dmar_global_lock was introduced by commit 3a5670e8ac932
("iommu/vt-d: Introduce a rwsem to protect global data structures"). It
is used to protect DMAR related global data from DMAR and PCI devices
hotplug operations.

The dmar_global_lock used in the intel_iommu_init() might cause recursive
locking issue, where 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() is unnecessary since it is
unlikely that any IO board must be hot added during the early boot stage.
This fixes the possible recursive locking issue by moving down DMAR and
PCI devices hotplug support after the IOMMU is initialized and removing
the dmar_global_lock uses in intel_iommu_init().

Fixes: d5692d4af08cd ("iommu/vt-d: Fix suspicious RCU usage in probe_acpi_namespace_devices()")
Reported-by: Robin Murphy <robin.murphy@arm.com>
Link: https://lore.kernel.org/linux-iommu/894db0ccae854b35c73814485569b634237b5538.1657034828.git.robin.murphy@arm.com/
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 include/linux/dmar.h        |  4 +++-
 drivers/iommu/intel/dmar.c  |  7 +++++++
 drivers/iommu/intel/iommu.c | 27 ++-------------------------
 3 files changed, 12 insertions(+), 26 deletions(-)

diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index d81a51978d01..8917a32173c4 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -65,6 +65,7 @@ struct dmar_pci_notify_info {
 
 extern struct rw_semaphore dmar_global_lock;
 extern struct list_head dmar_drhd_units;
+extern int intel_iommu_enabled;
 
 #define for_each_drhd_unit(drhd)					\
 	list_for_each_entry_rcu(drhd, &dmar_drhd_units, list,		\
@@ -88,7 +89,8 @@ extern struct list_head dmar_drhd_units;
 static inline bool dmar_rcu_check(void)
 {
 	return rwsem_is_locked(&dmar_global_lock) ||
-	       system_state == SYSTEM_BOOTING;
+	       system_state == SYSTEM_BOOTING ||
+	       (IS_ENABLED(CONFIG_INTEL_IOMMU) && !intel_iommu_enabled);
 }
 
 #define	dmar_rcu_dereference(p)	rcu_dereference_check((p), dmar_rcu_check())
diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
index 6327b34f5aa7..63f32dfece82 100644
--- a/drivers/iommu/intel/dmar.c
+++ b/drivers/iommu/intel/dmar.c
@@ -2349,6 +2349,13 @@ static int dmar_device_hotplug(acpi_handle handle, bool insert)
 	if (!dmar_in_use())
 		return 0;
 
+	/*
+	 * It's unlikely that any I/O board is hot added before the IOMMU
+	 * subsystem is initialized.
+	 */
+	if (IS_ENABLED(CONFIG_INTEL_IOMMU) && !intel_iommu_enabled)
+		return -EOPNOTSUPP;
+
 	if (dmar_detect_dsm(handle, DMAR_DSM_FUNC_DRHD)) {
 		tmp = handle;
 	} else {
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 7cca030a508e..59064cf92e7b 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -3013,13 +3013,7 @@ static int __init init_dmars(void)
 
 #ifdef CONFIG_INTEL_IOMMU_SVM
 		if (pasid_supported(iommu) && ecap_prs(iommu->ecap)) {
-			/*
-			 * Call dmar_alloc_hwirq() with dmar_global_lock held,
-			 * could cause possible lock race condition.
-			 */
-			up_write(&dmar_global_lock);
 			ret = intel_svm_enable_prq(iommu);
-			down_write(&dmar_global_lock);
 			if (ret)
 				goto free_iommu;
 		}
@@ -3932,7 +3926,6 @@ int __init intel_iommu_init(void)
 	force_on = (!intel_iommu_tboot_noforce && tboot_force_iommu()) ||
 		    platform_optin_force_iommu();
 
-	down_write(&dmar_global_lock);
 	if (dmar_table_init()) {
 		if (force_on)
 			panic("tboot: Failed to initialize DMAR table\n");
@@ -3945,16 +3938,6 @@ int __init intel_iommu_init(void)
 		goto out_free_dmar;
 	}
 
-	up_write(&dmar_global_lock);
-
-	/*
-	 * The bus notifier takes the dmar_global_lock, so lockdep will
-	 * complain later when we register it under the lock.
-	 */
-	dmar_register_bus_notifier();
-
-	down_write(&dmar_global_lock);
-
 	if (!no_iommu)
 		intel_iommu_debugfs_init();
 
@@ -3999,11 +3982,9 @@ int __init intel_iommu_init(void)
 		pr_err("Initialization failed\n");
 		goto out_free_dmar;
 	}
-	up_write(&dmar_global_lock);
 
 	init_iommu_pm_ops();
 
-	down_read(&dmar_global_lock);
 	for_each_active_iommu(iommu, drhd) {
 		/*
 		 * The flush queue implementation does not perform
@@ -4021,13 +4002,11 @@ int __init intel_iommu_init(void)
 				       "%s", iommu->name);
 		iommu_device_register(&iommu->iommu, &intel_iommu_ops, NULL);
 	}
-	up_read(&dmar_global_lock);
 
 	bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
 	if (si_domain && !hw_pass_through)
 		register_memory_notifier(&intel_iommu_memory_nb);
 
-	down_read(&dmar_global_lock);
 	if (probe_acpi_namespace_devices())
 		pr_warn("ACPI name space devices didn't probe correctly\n");
 
@@ -4038,17 +4017,15 @@ int __init intel_iommu_init(void)
 
 		iommu_disable_protect_mem_regions(iommu);
 	}
-	up_read(&dmar_global_lock);
-
-	pr_info("Intel(R) Virtualization Technology for Directed I/O\n");
 
 	intel_iommu_enabled = 1;
+	dmar_register_bus_notifier();
+	pr_info("Intel(R) Virtualization Technology for Directed I/O\n");
 
 	return 0;
 
 out_free_dmar:
 	intel_iommu_free_dmars();
-	up_write(&dmar_global_lock);
 	return ret;
 }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* RE: [PATCH 1/1] iommu/vt-d: Fix possible recursive locking in intel_iommu_init()
  2022-07-18 23:53 [PATCH 1/1] iommu/vt-d: Fix possible recursive locking in intel_iommu_init() Lu Baolu
@ 2022-07-21  7:39 ` Tian, Kevin
  2022-07-24  2:59   ` Baolu Lu
  0 siblings, 1 reply; 7+ messages in thread
From: Tian, Kevin @ 2022-07-21  7:39 UTC (permalink / raw)
  To: Lu Baolu, iommu; +Cc: Joerg Roedel, Will Deacon, Robin Murphy, linux-kernel

> From: Lu Baolu <baolu.lu@linux.intel.com>
> Sent: Tuesday, July 19, 2022 7:53 AM
> 
> @@ -88,7 +89,8 @@ extern struct list_head dmar_drhd_units;
>  static inline bool dmar_rcu_check(void)
>  {
>  	return rwsem_is_locked(&dmar_global_lock) ||
> -	       system_state == SYSTEM_BOOTING;
> +	       system_state == SYSTEM_BOOTING ||
> +	       (IS_ENABLED(CONFIG_INTEL_IOMMU)
> && !intel_iommu_enabled);
>  }

intel_iommu_enabled is 0 if CONFIG_INTEL_IOMMU is not set.

same for other similar checks.



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/1] iommu/vt-d: Fix possible recursive locking in intel_iommu_init()
  2022-07-21  7:39 ` Tian, Kevin
@ 2022-07-24  2:59   ` Baolu Lu
  2022-07-25  7:40     ` Tian, Kevin
  0 siblings, 1 reply; 7+ messages in thread
From: Baolu Lu @ 2022-07-24  2:59 UTC (permalink / raw)
  To: Tian, Kevin, iommu
  Cc: baolu.lu, Joerg Roedel, Will Deacon, Robin Murphy, linux-kernel

Hi Kevin,

On 2022/7/21 15:39, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Tuesday, July 19, 2022 7:53 AM
>>
>> @@ -88,7 +89,8 @@ extern struct list_head dmar_drhd_units;
>>   static inline bool dmar_rcu_check(void)
>>   {
>>   	return rwsem_is_locked(&dmar_global_lock) ||
>> -	       system_state == SYSTEM_BOOTING;
>> +	       system_state == SYSTEM_BOOTING ||
>> +	       (IS_ENABLED(CONFIG_INTEL_IOMMU)
>> && !intel_iommu_enabled);
>>   }
> 
> intel_iommu_enabled is 0 if CONFIG_INTEL_IOMMU is not set.
> 
> same for other similar checks.

Sorry that I didn't get your point. If CONFIG_INTEL_IOMMU is not set,
IS_ENABLED(CONFIG_INTEL_IOMMU) is 0. The adding check has no effect. Did
I miss anything?

Best regards,
baolu


^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: [PATCH 1/1] iommu/vt-d: Fix possible recursive locking in intel_iommu_init()
  2022-07-24  2:59   ` Baolu Lu
@ 2022-07-25  7:40     ` Tian, Kevin
  2022-07-25  9:39       ` Baolu Lu
  0 siblings, 1 reply; 7+ messages in thread
From: Tian, Kevin @ 2022-07-25  7:40 UTC (permalink / raw)
  To: Baolu Lu, iommu; +Cc: Joerg Roedel, Will Deacon, Robin Murphy, linux-kernel

> From: Baolu Lu <baolu.lu@linux.intel.com>
> Sent: Sunday, July 24, 2022 11:00 AM
> 
> Hi Kevin,
> 
> On 2022/7/21 15:39, Tian, Kevin wrote:
> >> From: Lu Baolu <baolu.lu@linux.intel.com>
> >> Sent: Tuesday, July 19, 2022 7:53 AM
> >>
> >> @@ -88,7 +89,8 @@ extern struct list_head dmar_drhd_units;
> >>   static inline bool dmar_rcu_check(void)
> >>   {
> >>   	return rwsem_is_locked(&dmar_global_lock) ||
> >> -	       system_state == SYSTEM_BOOTING;
> >> +	       system_state == SYSTEM_BOOTING ||
> >> +	       (IS_ENABLED(CONFIG_INTEL_IOMMU)
> >> && !intel_iommu_enabled);
> >>   }
> >
> > intel_iommu_enabled is 0 if CONFIG_INTEL_IOMMU is not set.
> >
> > same for other similar checks.
> 
> Sorry that I didn't get your point. If CONFIG_INTEL_IOMMU is not set,
> IS_ENABLED(CONFIG_INTEL_IOMMU) is 0. The adding check has no effect.
> Did
> I miss anything?
> 

My point was that the check on CONFIG_INTEL_IOMMU is unnecessary.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/1] iommu/vt-d: Fix possible recursive locking in intel_iommu_init()
  2022-07-25  7:40     ` Tian, Kevin
@ 2022-07-25  9:39       ` Baolu Lu
  2022-09-08  6:13         ` Baolu Lu
  0 siblings, 1 reply; 7+ messages in thread
From: Baolu Lu @ 2022-07-25  9:39 UTC (permalink / raw)
  To: Tian, Kevin, iommu
  Cc: baolu.lu, Joerg Roedel, Will Deacon, Robin Murphy, linux-kernel

On 2022/7/25 15:40, Tian, Kevin wrote:
>> From: Baolu Lu <baolu.lu@linux.intel.com>
>> Sent: Sunday, July 24, 2022 11:00 AM
>>
>> Hi Kevin,
>>
>> On 2022/7/21 15:39, Tian, Kevin wrote:
>>>> From: Lu Baolu <baolu.lu@linux.intel.com>
>>>> Sent: Tuesday, July 19, 2022 7:53 AM
>>>>
>>>> @@ -88,7 +89,8 @@ extern struct list_head dmar_drhd_units;
>>>>    static inline bool dmar_rcu_check(void)
>>>>    {
>>>>    	return rwsem_is_locked(&dmar_global_lock) ||
>>>> -	       system_state == SYSTEM_BOOTING;
>>>> +	       system_state == SYSTEM_BOOTING ||
>>>> +	       (IS_ENABLED(CONFIG_INTEL_IOMMU)
>>>> && !intel_iommu_enabled);
>>>>    }
>>>
>>> intel_iommu_enabled is 0 if CONFIG_INTEL_IOMMU is not set.
>>>
>>> same for other similar checks.
>>
>> Sorry that I didn't get your point. If CONFIG_INTEL_IOMMU is not set,
>> IS_ENABLED(CONFIG_INTEL_IOMMU) is 0. The adding check has no effect.
>> Did
>> I miss anything?
>>
> 
> My point was that the check on CONFIG_INTEL_IOMMU is unnecessary.

Oh, if INTEL_IOMMU is not configured, the interrupt remapping could also
be supported, so we still need the rcu protection. We only relax the rcu
check when INTEL_IOMMU is configured, but not enabled yet.

Best regards,
baolu


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/1] iommu/vt-d: Fix possible recursive locking in intel_iommu_init()
  2022-07-25  9:39       ` Baolu Lu
@ 2022-09-08  6:13         ` Baolu Lu
  2022-09-08  6:31           ` Tian, Kevin
  0 siblings, 1 reply; 7+ messages in thread
From: Baolu Lu @ 2022-09-08  6:13 UTC (permalink / raw)
  To: Tian, Kevin, iommu
  Cc: baolu.lu, Joerg Roedel, Will Deacon, Robin Murphy, linux-kernel

Hi Kevin,

On 2022/7/25 17:39, Baolu Lu wrote:
> On 2022/7/25 15:40, Tian, Kevin wrote:
>>> From: Baolu Lu <baolu.lu@linux.intel.com>
>>> Sent: Sunday, July 24, 2022 11:00 AM
>>>
>>> Hi Kevin,
>>>
>>> On 2022/7/21 15:39, Tian, Kevin wrote:
>>>>> From: Lu Baolu <baolu.lu@linux.intel.com>
>>>>> Sent: Tuesday, July 19, 2022 7:53 AM
>>>>>
>>>>> @@ -88,7 +89,8 @@ extern struct list_head dmar_drhd_units;
>>>>>    static inline bool dmar_rcu_check(void)
>>>>>    {
>>>>>        return rwsem_is_locked(&dmar_global_lock) ||
>>>>> -           system_state == SYSTEM_BOOTING;
>>>>> +           system_state == SYSTEM_BOOTING ||
>>>>> +           (IS_ENABLED(CONFIG_INTEL_IOMMU)
>>>>> && !intel_iommu_enabled);
>>>>>    }
>>>>
>>>> intel_iommu_enabled is 0 if CONFIG_INTEL_IOMMU is not set.
>>>>
>>>> same for other similar checks.
>>>
>>> Sorry that I didn't get your point. If CONFIG_INTEL_IOMMU is not set,
>>> IS_ENABLED(CONFIG_INTEL_IOMMU) is 0. The adding check has no effect.
>>> Did
>>> I miss anything?
>>>
>>
>> My point was that the check on CONFIG_INTEL_IOMMU is unnecessary.
> 
> Oh, if INTEL_IOMMU is not configured, the interrupt remapping could also
> be supported, so we still need the rcu protection. We only relax the rcu
> check when INTEL_IOMMU is configured, but not enabled yet.

The next stepping, we will tie INTEL_IOMMU and VT-d IRQ_REMAPPING
together, that will make the VT-d software simpler.

Joerg also proposed this in another discussion thread:

https://lore.kernel.org/all/YrVPelnOi9nql%2F8C@8bytes.org/

After that, we have no need to add above check anymore. As this is a
quick fix for lockdep splat, we don't need to wait until that done.

Does this work for you?

Best regards,
baolu

^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: [PATCH 1/1] iommu/vt-d: Fix possible recursive locking in intel_iommu_init()
  2022-09-08  6:13         ` Baolu Lu
@ 2022-09-08  6:31           ` Tian, Kevin
  0 siblings, 0 replies; 7+ messages in thread
From: Tian, Kevin @ 2022-09-08  6:31 UTC (permalink / raw)
  To: Baolu Lu, iommu; +Cc: Joerg Roedel, Will Deacon, Robin Murphy, linux-kernel

> From: Baolu Lu <baolu.lu@linux.intel.com>
> Sent: Thursday, September 8, 2022 2:13 PM
> 
> Hi Kevin,
> 
> On 2022/7/25 17:39, Baolu Lu wrote:
> > On 2022/7/25 15:40, Tian, Kevin wrote:
> >>> From: Baolu Lu <baolu.lu@linux.intel.com>
> >>> Sent: Sunday, July 24, 2022 11:00 AM
> >>>
> >>> Hi Kevin,
> >>>
> >>> On 2022/7/21 15:39, Tian, Kevin wrote:
> >>>>> From: Lu Baolu <baolu.lu@linux.intel.com>
> >>>>> Sent: Tuesday, July 19, 2022 7:53 AM
> >>>>>
> >>>>> @@ -88,7 +89,8 @@ extern struct list_head dmar_drhd_units;
> >>>>>    static inline bool dmar_rcu_check(void)
> >>>>>    {
> >>>>>        return rwsem_is_locked(&dmar_global_lock) ||
> >>>>> -           system_state == SYSTEM_BOOTING;
> >>>>> +           system_state == SYSTEM_BOOTING ||
> >>>>> +           (IS_ENABLED(CONFIG_INTEL_IOMMU)
> >>>>> && !intel_iommu_enabled);
> >>>>>    }
> >>>>
> >>>> intel_iommu_enabled is 0 if CONFIG_INTEL_IOMMU is not set.
> >>>>
> >>>> same for other similar checks.
> >>>
> >>> Sorry that I didn't get your point. If CONFIG_INTEL_IOMMU is not set,
> >>> IS_ENABLED(CONFIG_INTEL_IOMMU) is 0. The adding check has no
> effect.
> >>> Did
> >>> I miss anything?
> >>>
> >>
> >> My point was that the check on CONFIG_INTEL_IOMMU is unnecessary.
> >
> > Oh, if INTEL_IOMMU is not configured, the interrupt remapping could also
> > be supported, so we still need the rcu protection. We only relax the rcu
> > check when INTEL_IOMMU is configured, but not enabled yet.
> 
> The next stepping, we will tie INTEL_IOMMU and VT-d IRQ_REMAPPING
> together, that will make the VT-d software simpler.
> 
> Joerg also proposed this in another discussion thread:
> 
> https://lore.kernel.org/all/YrVPelnOi9nql%2F8C@8bytes.org/
> 
> After that, we have no need to add above check anymore. As this is a
> quick fix for lockdep splat, we don't need to wait until that done.
> 
> Does this work for you?
> 

Yes. With above I'm fine with it given Robin's series has been merged.

Reviewed-by: Kevin Tian <kevin.tian@intel.com>

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2022-09-08  6:31 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-18 23:53 [PATCH 1/1] iommu/vt-d: Fix possible recursive locking in intel_iommu_init() Lu Baolu
2022-07-21  7:39 ` Tian, Kevin
2022-07-24  2:59   ` Baolu Lu
2022-07-25  7:40     ` Tian, Kevin
2022-07-25  9:39       ` Baolu Lu
2022-09-08  6:13         ` Baolu Lu
2022-09-08  6:31           ` Tian, Kevin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).