summaryrefslogtreecommitdiff
path: root/drivers/base
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2026-05-29 15:09:06 +0000
committerDanilo Krummrich <dakr@kernel.org>2026-06-08 20:21:27 +0200
commitd3ec78f8f8d48a04a9fac38d47275c34645e5103 (patch)
treeb991f8e6f90815f4cccafe7302e43b4bf3b9092b /drivers/base
parentfda8355f13ea3c0f9499acdeff3024995b474948 (diff)
downloadlinux-next-d3ec78f8f8d48a04a9fac38d47275c34645e5103.tar.gz
linux-next-d3ec78f8f8d48a04a9fac38d47275c34645e5103.zip
firmware_loader: Fix recursive lock in device_cache_fw_images()
A recursive locking deadlock can occur in the firmware loader's power management notification handler. During system suspend or hibernation preparation, fw_pm_notify() calls device_cache_fw_images(). This function acquires fw_lock to set the firmware cache state to FW_LOADER_START_CACHE and then iterates over all devices using dpm_for_each_dev() while still holding the lock. For each device, dev_cache_fw_image() schedules asynchronous work to cache the firmware. If memory allocation for the async work entry fails (e.g., in out-of-memory conditions), async_schedule_node_domain() falls back to executing the work function synchronously in the current thread. The synchronous execution path (__async_dev_cache_fw_image() -> cache_firmware() -> request_firmware() -> assign_fw()) attempts to acquire fw_lock again. Since the current thread already holds fw_lock, this results in a recursive locking deadlock. Fix this by releasing fw_lock immediately after updating the cache state and before calling dpm_for_each_dev(). The lock is only needed to protect the state update. Concurrent firmware requests will correctly see the FW_LOADER_START_CACHE state and use the piggyback mechanism, which is independently protected by its own fwc->name_lock. Fixes: ac39b3ea73aa ("firmware loader: let caching firmware piggyback on loading firmware") Assisted-by: Gemini:gemini-3.1-pro-preview Gemini:gemini-3-flash-preview syzbot Reported-by: syzbot+e70e4c6f6eee43357ba7@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=e70e4c6f6eee43357ba7 Link: https://syzkaller.appspot.com/ai_job?id=8b4af9fd-24af-423f-8acb-1159fd34c1a5 Signed-off-by: Dmitry Vyukov <dvyukov@google.com> Link: https://patch.msgid.link/48b092a5-f49d-48a4-95f4-f65bebfc6bc3@mail.kernel.org Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/firmware_loader/main.c3
1 files changed, 2 insertions, 1 deletions
diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c
index a11b30dda23b..c96312ac2be7 100644
--- a/drivers/base/firmware_loader/main.c
+++ b/drivers/base/firmware_loader/main.c
@@ -1503,9 +1503,10 @@ static void device_cache_fw_images(void)
mutex_lock(&fw_lock);
fwc->state = FW_LOADER_START_CACHE;
- dpm_for_each_dev(NULL, dev_cache_fw_image);
mutex_unlock(&fw_lock);
+ dpm_for_each_dev(NULL, dev_cache_fw_image);
+
/* wait for completion of caching firmware for all devices */
async_synchronize_full_domain(&fw_cache_domain);