From effd7c70eaa0440688b60b9d419243695ede3c45 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Thu, 26 Oct 2023 19:57:39 +0530 Subject: firmware_loader: Abort all upcoming firmware load request once reboot triggered There could be following scenario where there is a ongoing reboot is going from processA which tries to call all the reboot notifier callback and one of them is firmware reboot call which tries to abort all the ongoing firmware userspace request under fw_lock but there could be another processB which tries to do request firmware, which came just after abort done from ProcessA and ask for userspace to load the firmware and this can stop the ongoing reboot ProcessA to stall for next 60s(default timeout) which may not be expected behaviour everyone like to see, instead we should abort any firmware load request which came once firmware knows about the reboot through notification. ProcessA ProcessB kernel_restart_prepare blocking_notifier_call_chain fw_shutdown_notify kill_pending_fw_fallback_reqs __fw_load_abort fw_state_aborted request_firmware __fw_state_set firmware_fallback_sysfs ... fw_load_from_user_helper .. ... . .. usermodehelper_read_trylock fw_load_sysfs_fallback fw_sysfs_wait_timeout usermodehelper_disable __usermodehelper_disable down_write() Signed-off-by: Mukesh Ojha Acked-by: Luis Chamberlain Link: https://lore.kernel.org/r/1698330459-31776-2-git-send-email-quic_mojha@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware_loader/fallback.c | 6 +++++- drivers/base/firmware_loader/firmware.h | 1 + drivers/base/firmware_loader/main.c | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/base') diff --git a/drivers/base/firmware_loader/fallback.c b/drivers/base/firmware_loader/fallback.c index b3ce07160281..3ef0b312ae71 100644 --- a/drivers/base/firmware_loader/fallback.c +++ b/drivers/base/firmware_loader/fallback.c @@ -57,6 +57,10 @@ void kill_pending_fw_fallback_reqs(bool kill_all) if (kill_all || !fw_priv->need_uevent) __fw_load_abort(fw_priv); } + + if (kill_all) + fw_load_abort_all = true; + mutex_unlock(&fw_lock); } @@ -86,7 +90,7 @@ static int fw_load_sysfs_fallback(struct fw_sysfs *fw_sysfs, long timeout) } mutex_lock(&fw_lock); - if (fw_state_is_aborted(fw_priv)) { + if (fw_load_abort_all || fw_state_is_aborted(fw_priv)) { mutex_unlock(&fw_lock); retval = -EINTR; goto out; diff --git a/drivers/base/firmware_loader/firmware.h b/drivers/base/firmware_loader/firmware.h index bf549d6500d7..e891742ba264 100644 --- a/drivers/base/firmware_loader/firmware.h +++ b/drivers/base/firmware_loader/firmware.h @@ -86,6 +86,7 @@ struct fw_priv { extern struct mutex fw_lock; extern struct firmware_cache fw_cache; +extern bool fw_load_abort_all; static inline bool __fw_state_check(struct fw_priv *fw_priv, enum fw_status status) diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 522ccee781b4..ea28102d421e 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -93,6 +93,7 @@ static inline struct fw_priv *to_fw_priv(struct kref *ref) DEFINE_MUTEX(fw_lock); struct firmware_cache fw_cache; +bool fw_load_abort_all; void fw_state_init(struct fw_priv *fw_priv) { -- cgit v1.2.3