iommu/vt-d: Fix suspicious RCU usage
authorLu Baolu <baolu.lu@linux.intel.com>
Fri, 28 Feb 2025 10:27:26 +0000 (18:27 +0800)
committerJoerg Roedel <jroedel@suse.de>
Fri, 28 Feb 2025 11:19:01 +0000 (12:19 +0100)
Commit <d74169ceb0d2> ("iommu/vt-d: Allocate DMAR fault interrupts
locally") moved the call to enable_drhd_fault_handling() to a code
path that does not hold any lock while traversing the drhd list. Fix
it by ensuring the dmar_global_lock lock is held when traversing the
drhd list.

Without this fix, the following warning is triggered:
 =============================
 WARNING: suspicious RCU usage
 6.14.0-rc3 #55 Not tainted
 -----------------------------
 drivers/iommu/intel/dmar.c:2046 RCU-list traversed in non-reader section!!
               other info that might help us debug this:
               rcu_scheduler_active = 1, debug_locks = 1
 2 locks held by cpuhp/1/23:
 #0: ffffffff84a67c50 (cpu_hotplug_lock){++++}-{0:0}, at: cpuhp_thread_fun+0x87/0x2c0
 #1: ffffffff84a6a380 (cpuhp_state-up){+.+.}-{0:0}, at: cpuhp_thread_fun+0x87/0x2c0
 stack backtrace:
 CPU: 1 UID: 0 PID: 23 Comm: cpuhp/1 Not tainted 6.14.0-rc3 #55
 Call Trace:
  <TASK>
  dump_stack_lvl+0xb7/0xd0
  lockdep_rcu_suspicious+0x159/0x1f0
  ? __pfx_enable_drhd_fault_handling+0x10/0x10
  enable_drhd_fault_handling+0x151/0x180
  cpuhp_invoke_callback+0x1df/0x990
  cpuhp_thread_fun+0x1ea/0x2c0
  smpboot_thread_fn+0x1f5/0x2e0
  ? __pfx_smpboot_thread_fn+0x10/0x10
  kthread+0x12a/0x2d0
  ? __pfx_kthread+0x10/0x10
  ret_from_fork+0x4a/0x60
  ? __pfx_kthread+0x10/0x10
  ret_from_fork_asm+0x1a/0x30
  </TASK>

Holding the lock in enable_drhd_fault_handling() triggers a lockdep splat
about a possible deadlock between dmar_global_lock and cpu_hotplug_lock.
This is avoided by not holding dmar_global_lock when calling
iommu_device_register(), which initiates the device probe process.

Fixes: d74169ceb0d2 ("iommu/vt-d: Allocate DMAR fault interrupts locally")
Reported-and-tested-by: Ido Schimmel <idosch@nvidia.com>
Closes: https://lore.kernel.org/linux-iommu/Zx9OwdLIc_VoQ0-a@shredder.mtl.com/
Tested-by: Breno Leitao <leitao@debian.org>
Cc: stable@vger.kernel.org
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Link: https://lore.kernel.org/r/20250218022422.2315082-1-baolu.lu@linux.intel.com
Tested-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/intel/dmar.c
drivers/iommu/intel/iommu.c

index 9f424acf474e9400ed91fa3aaa1f4b2cb498922b..e540092d664d27a6823db5934b8a2126862922c2 100644 (file)
@@ -2043,6 +2043,7 @@ int enable_drhd_fault_handling(unsigned int cpu)
        /*
         * Enable fault control interrupt.
         */
+       guard(rwsem_read)(&dmar_global_lock);
        for_each_iommu(iommu, drhd) {
                u32 fault_status;
                int ret;
index 4d8d4593c9c81cc5cf0b680aee59310af32236ca..bf1f0c81434830c87614883a72853bbd0cb105e4 100644 (file)
@@ -3146,7 +3146,14 @@ int __init intel_iommu_init(void)
                iommu_device_sysfs_add(&iommu->iommu, NULL,
                                       intel_iommu_groups,
                                       "%s", iommu->name);
+               /*
+                * The iommu device probe is protected by the iommu_probe_device_lock.
+                * Release the dmar_global_lock before entering the device probe path
+                * to avoid unnecessary lock order splat.
+                */
+               up_read(&dmar_global_lock);
                iommu_device_register(&iommu->iommu, &intel_iommu_ops, NULL);
+               down_read(&dmar_global_lock);
 
                iommu_pmu_register(iommu);
        }