From 10120b0270b540d4d8e4a45f83fc183a6c90918c Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Thu, 26 Oct 2023 19:57:38 +0530 Subject: [PATCH 1/2] UPSTREAM: firmware_loader: Refactor kill_pending_fw_fallback_reqs() Rename 'only_kill_custom' and refactor logic related to it to be more meaningful. Bug: 309378049 Change-Id: I119d2f8c29b9b624e6c1d8546c1533d76a2cc51d Signed-off-by: Mukesh Ojha Acked-by: Luis Chamberlain Link: https://lore.kernel.org/r/1698330459-31776-1-git-send-email-quic_mojha@quicinc.com Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 87ffa98eeee8d62a56afdad80ea697e7a6e5c354) Signed-off-by: Srinivasarao Pathipati --- drivers/base/firmware_loader/fallback.c | 4 ++-- drivers/base/firmware_loader/fallback.h | 4 ++-- drivers/base/firmware_loader/main.c | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/base/firmware_loader/fallback.c b/drivers/base/firmware_loader/fallback.c index 0fdd18ce2c52..37a26edc4113 100644 --- a/drivers/base/firmware_loader/fallback.c +++ b/drivers/base/firmware_loader/fallback.c @@ -106,7 +106,7 @@ static void fw_load_abort(struct fw_sysfs *fw_sysfs) static LIST_HEAD(pending_fw_head); -void kill_pending_fw_fallback_reqs(bool only_kill_custom) +void kill_pending_fw_fallback_reqs(bool kill_all) { struct fw_priv *fw_priv; struct fw_priv *next; @@ -114,7 +114,7 @@ void kill_pending_fw_fallback_reqs(bool only_kill_custom) mutex_lock(&fw_lock); list_for_each_entry_safe(fw_priv, next, &pending_fw_head, pending_list) { - if (!fw_priv->need_uevent || !only_kill_custom) + if (kill_all || !fw_priv->need_uevent) __fw_load_abort(fw_priv); } mutex_unlock(&fw_lock); diff --git a/drivers/base/firmware_loader/fallback.h b/drivers/base/firmware_loader/fallback.h index 3af7205b302f..1d9476d16a01 100644 --- a/drivers/base/firmware_loader/fallback.h +++ b/drivers/base/firmware_loader/fallback.h @@ -35,7 +35,7 @@ int firmware_fallback_sysfs(struct firmware *fw, const char *name, struct device *device, u32 opt_flags, int ret); -void kill_pending_fw_fallback_reqs(bool only_kill_custom); +void kill_pending_fw_fallback_reqs(bool kill_all); void fw_fallback_set_cache_timeout(void); void fw_fallback_set_default_timeout(void); @@ -52,7 +52,7 @@ static inline int firmware_fallback_sysfs(struct firmware *fw, const char *name, return ret; } -static inline void kill_pending_fw_fallback_reqs(bool only_kill_custom) { } +static inline void kill_pending_fw_fallback_reqs(bool kill_all) { } static inline void fw_fallback_set_cache_timeout(void) { } static inline void fw_fallback_set_default_timeout(void) { } diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 1372f40d0371..1d3067097481 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -1442,10 +1442,10 @@ static int fw_pm_notify(struct notifier_block *notify_block, case PM_SUSPEND_PREPARE: case PM_RESTORE_PREPARE: /* - * kill pending fallback requests with a custom fallback - * to avoid stalling suspend. + * Here, kill pending fallback requests will only kill + * non-uevent firmware request to avoid stalling suspend. */ - kill_pending_fw_fallback_reqs(true); + kill_pending_fw_fallback_reqs(false); device_cache_fw_images(); break; @@ -1530,7 +1530,7 @@ static int fw_shutdown_notify(struct notifier_block *unused1, * Kill all pending fallback requests to avoid both stalling shutdown, * and avoid a deadlock with the usermode_lock. */ - kill_pending_fw_fallback_reqs(false); + kill_pending_fw_fallback_reqs(true); return NOTIFY_DONE; } From ba88bbf1bb7e22d7b18ad233afd948c4e98923be Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Thu, 26 Oct 2023 19:57:39 +0530 Subject: [PATCH 2/2] BACKPORT: 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() Bug: 309378049 Change-Id: I61eb91f21a01460f340f890b25c60de7597a87ff 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 (cherry picked from commit effd7c70eaa0440688b60b9d419243695ede3c45) Signed-off-by: Srinivasarao Pathipati --- 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(-) diff --git a/drivers/base/firmware_loader/fallback.c b/drivers/base/firmware_loader/fallback.c index 37a26edc4113..45dfb6e09c24 100644 --- a/drivers/base/firmware_loader/fallback.c +++ b/drivers/base/firmware_loader/fallback.c @@ -117,6 +117,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); } @@ -511,7 +515,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 a3014e9e2c85..53e08de04b86 100644 --- a/drivers/base/firmware_loader/firmware.h +++ b/drivers/base/firmware_loader/firmware.h @@ -87,6 +87,7 @@ struct fw_priv { }; extern struct mutex fw_lock; +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 1d3067097481..9dbfdf9a5645 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -91,6 +91,7 @@ static inline struct fw_priv *to_fw_priv(struct kref *ref) DEFINE_MUTEX(fw_lock); static struct firmware_cache fw_cache; +bool fw_load_abort_all; /* Builtin firmware support */