aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/firmware_class.c
diff options
context:
space:
mode:
authorLuis R. Rodriguez <mcgrof@kernel.org>2017-05-02 04:31:07 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-06-03 06:15:50 -0400
commit06a45a93e7d34aab34522cc49479e1caecf3298c (patch)
tree80efa66e6b721e7a428fb57e4c16a83620737a49 /drivers/base/firmware_class.c
parent8509adcaa9286636ef8ec874ed9ffd9717afe545 (diff)
firmware: move umh try locks into the umh code
This moves the usermode helper locks into only code paths that use the usermode helper API from the kernel. The usermode helper locks were originally added to prevent stalling suspend, later the firmware cache was added to help with this, and further later direct filesystem lookup was added by Linus to completely bypass udev due to the amount of issues the umh approach had. The usermode helper locks were kept even when the direct filesystem lookup mechanism is used though. A lot has changed since the original usermode helper locks were added but the recent commit which added the code for firmware_enabled() are intended to address any possible races cured only as collateral by using the locks as though side consequence of code evolution and this not being addressed any time sooner. With the firmware_enabled() code in place we are a bit more sure to move the usermode helper locks to UMH only code. There is a bit of history here so let's recap a bit of it to ensure nothing is lost and things are clear. The direct filesystem approach to loading firmware is rather new, it was added via commit abb139e75c2cdb ("firmware: teach the kernel to load firmware files directly from the filesystem") by Linus merged on the v3.7 release, to enable to bypass udev. usermodehelper_read_lock_wait() was added earlier via commit 9b78c1da60b3c ("firmware_class: Do not warn that system is not ready from async loads") merged on v3.4, after Rafael noted that the async firmware API call request_firmware_nowait() should not be penalized to fail if userspace is not available yet or frozen, it'd allow for a timeout grace period before giving up. The WARN_ON() was kept for the sync firmware API call though on request_firmware(). At this time there was no direct filesystem lookup for firmware though. The original usermode helper lock came from commit a144c6a6c924a ("PM: Print a warning if firmware is requested when tasks are frozen") merged on the v3.0 kernel by Rafael to print a warning back when firmware requests were used on resume(), thaw() or restore() callbacks and there was no direct fs lookups or the firmware cache. Signed-off-by: Luis R. Rodriguez <mcgrof@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/base/firmware_class.c')
-rw-r--r--drivers/base/firmware_class.c68
1 files changed, 36 insertions, 32 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 7722943025f3..b9f907eedbf7 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -1102,23 +1102,51 @@ err_put_dev:
1102 1102
1103static int fw_load_from_user_helper(struct firmware *firmware, 1103static int fw_load_from_user_helper(struct firmware *firmware,
1104 const char *name, struct device *device, 1104 const char *name, struct device *device,
1105 unsigned int opt_flags, long timeout) 1105 unsigned int opt_flags)
1106{ 1106{
1107 struct firmware_priv *fw_priv; 1107 struct firmware_priv *fw_priv;
1108 long timeout;
1109 int ret;
1110
1111 timeout = firmware_loading_timeout();
1112 if (opt_flags & FW_OPT_NOWAIT) {
1113 timeout = usermodehelper_read_lock_wait(timeout);
1114 if (!timeout) {
1115 dev_dbg(device, "firmware: %s loading timed out\n",
1116 name);
1117 return -EBUSY;
1118 }
1119 } else {
1120 ret = usermodehelper_read_trylock();
1121 if (WARN_ON(ret)) {
1122 dev_err(device, "firmware: %s will not be loaded\n",
1123 name);
1124 return ret;
1125 }
1126 }
1108 1127
1109 fw_priv = fw_create_instance(firmware, name, device, opt_flags); 1128 fw_priv = fw_create_instance(firmware, name, device, opt_flags);
1110 if (IS_ERR(fw_priv)) 1129 if (IS_ERR(fw_priv)) {
1111 return PTR_ERR(fw_priv); 1130 ret = PTR_ERR(fw_priv);
1131 goto out_unlock;
1132 }
1112 1133
1113 fw_priv->buf = firmware->priv; 1134 fw_priv->buf = firmware->priv;
1114 return _request_firmware_load(fw_priv, opt_flags, timeout); 1135 ret = _request_firmware_load(fw_priv, opt_flags, timeout);
1136
1137 if (!ret)
1138 ret = assign_firmware_buf(firmware, device, opt_flags);
1139
1140out_unlock:
1141 usermodehelper_read_unlock();
1142
1143 return ret;
1115} 1144}
1116 1145
1117#else /* CONFIG_FW_LOADER_USER_HELPER */ 1146#else /* CONFIG_FW_LOADER_USER_HELPER */
1118static inline int 1147static inline int
1119fw_load_from_user_helper(struct firmware *firmware, const char *name, 1148fw_load_from_user_helper(struct firmware *firmware, const char *name,
1120 struct device *device, unsigned int opt_flags, 1149 struct device *device, unsigned int opt_flags)
1121 long timeout)
1122{ 1150{
1123 return -ENOENT; 1151 return -ENOENT;
1124} 1152}
@@ -1179,7 +1207,6 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
1179 unsigned int opt_flags) 1207 unsigned int opt_flags)
1180{ 1208{
1181 struct firmware *fw = NULL; 1209 struct firmware *fw = NULL;
1182 long timeout;
1183 int ret; 1210 int ret;
1184 1211
1185 if (!firmware_p) 1212 if (!firmware_p)
@@ -1200,25 +1227,6 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
1200 goto out; 1227 goto out;
1201 } 1228 }
1202 1229
1203 ret = 0;
1204 timeout = firmware_loading_timeout();
1205 if (opt_flags & FW_OPT_NOWAIT) {
1206 timeout = usermodehelper_read_lock_wait(timeout);
1207 if (!timeout) {
1208 dev_dbg(device, "firmware: %s loading timed out\n",
1209 name);
1210 ret = -EBUSY;
1211 goto out;
1212 }
1213 } else {
1214 ret = usermodehelper_read_trylock();
1215 if (WARN_ON(ret)) {
1216 dev_err(device, "firmware: %s will not be loaded\n",
1217 name);
1218 goto out;
1219 }
1220 }
1221
1222 ret = fw_get_filesystem_firmware(device, fw->priv); 1230 ret = fw_get_filesystem_firmware(device, fw->priv);
1223 if (ret) { 1231 if (ret) {
1224 if (!(opt_flags & FW_OPT_NO_WARN)) 1232 if (!(opt_flags & FW_OPT_NO_WARN))
@@ -1228,15 +1236,11 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
1228 if (opt_flags & FW_OPT_USERHELPER) { 1236 if (opt_flags & FW_OPT_USERHELPER) {
1229 dev_warn(device, "Falling back to user helper\n"); 1237 dev_warn(device, "Falling back to user helper\n");
1230 ret = fw_load_from_user_helper(fw, name, device, 1238 ret = fw_load_from_user_helper(fw, name, device,
1231 opt_flags, timeout); 1239 opt_flags);
1232 } 1240 }
1233 } 1241 } else
1234
1235 if (!ret)
1236 ret = assign_firmware_buf(fw, device, opt_flags); 1242 ret = assign_firmware_buf(fw, device, opt_flags);
1237 1243
1238 usermodehelper_read_unlock();
1239
1240 out: 1244 out:
1241 if (ret < 0) { 1245 if (ret < 0) {
1242 release_firmware(fw); 1246 release_firmware(fw);