summaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2012-03-28 23:30:02 +0200
committerRafael J. Wysocki <rjw@sisk.pl>2012-03-28 23:30:02 +0200
commit9b78c1da60b3c62ccdd1509f0902ad19ceaf776b (patch)
tree1e662bb29f04c2b875207d907db917476ddce60b /drivers/base
parent811fa4004485dec8977176bf605a5b0508ee206c (diff)
firmware_class: Do not warn that system is not ready from async loads
If firmware is requested asynchronously, by calling request_firmware_nowait(), there is no reason to fail the request (and warn the user) when the system is (presumably temporarily) unready to handle it (because user space is not available yet or frozen). For this reason, introduce an alternative routine for read-locking umhelper_sem, usermodehelper_read_lock_wait(), that will wait for usermodehelper_disabled to be unset (possibly with a timeout) and make request_firmware_work_func() use it instead of usermodehelper_read_trylock(). Accordingly, modify request_firmware() so that it uses usermodehelper_read_trylock() to acquire umhelper_sem and remove the code related to that lock from _request_firmware(). Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: stable@vger.kernel.org
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/firmware_class.c51
1 files changed, 30 insertions, 21 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 60290671f04..72c644b191a 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -81,6 +81,11 @@ enum {
static int loading_timeout = 60; /* In seconds */
+static inline long firmware_loading_timeout(void)
+{
+ return loading_timeout > 0 ? loading_timeout * HZ : MAX_SCHEDULE_TIMEOUT;
+}
+
/* fw_lock could be moved to 'struct firmware_priv' but since it is just
* guarding for corner cases a global lock should be OK */
static DEFINE_MUTEX(fw_lock);
@@ -541,31 +546,22 @@ static void _request_firmware_cleanup(const struct firmware **firmware_p)
static int _request_firmware(const struct firmware *firmware,
const char *name, struct device *device,
- bool uevent, bool nowait)
+ bool uevent, bool nowait, long timeout)
{
struct firmware_priv *fw_priv;
- int retval;
-
- retval = usermodehelper_read_trylock();
- if (WARN_ON(retval)) {
- dev_err(device, "firmware: %s will not be loaded\n", name);
- return retval;
- }
+ int retval = 0;
if (uevent)
dev_dbg(device, "firmware: requesting %s\n", name);
fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
- if (IS_ERR(fw_priv)) {
- retval = PTR_ERR(fw_priv);
- goto out;
- }
+ if (IS_ERR(fw_priv))
+ return PTR_ERR(fw_priv);
if (uevent) {
- if (loading_timeout > 0)
+ if (timeout != MAX_SCHEDULE_TIMEOUT)
mod_timer(&fw_priv->timeout,
- round_jiffies_up(jiffies +
- loading_timeout * HZ));
+ round_jiffies_up(jiffies + timeout));
kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
}
@@ -582,9 +578,6 @@ static int _request_firmware(const struct firmware *firmware,
mutex_unlock(&fw_lock);
fw_destroy_instance(fw_priv);
-
-out:
- usermodehelper_read_unlock();
return retval;
}
@@ -613,7 +606,14 @@ request_firmware(const struct firmware **firmware_p, const char *name,
if (ret <= 0)
return ret;
- ret = _request_firmware(*firmware_p, name, device, true, false);
+ ret = usermodehelper_read_trylock();
+ if (WARN_ON(ret)) {
+ dev_err(device, "firmware: %s will not be loaded\n", name);
+ } else {
+ ret = _request_firmware(*firmware_p, name, device, true, false,
+ firmware_loading_timeout());
+ usermodehelper_read_unlock();
+ }
if (ret)
_request_firmware_cleanup(firmware_p);
@@ -648,6 +648,7 @@ static int request_firmware_work_func(void *arg)
{
struct firmware_work *fw_work = arg;
const struct firmware *fw;
+ long timeout;
int ret;
if (!arg) {
@@ -659,8 +660,16 @@ static int request_firmware_work_func(void *arg)
if (ret <= 0)
goto out;
- ret = _request_firmware(fw, fw_work->name, fw_work->device,
- fw_work->uevent, true);
+ timeout = usermodehelper_read_lock_wait(firmware_loading_timeout());
+ if (timeout) {
+ ret = _request_firmware(fw, fw_work->name, fw_work->device,
+ fw_work->uevent, true, timeout);
+ usermodehelper_read_unlock();
+ } else {
+ dev_dbg(fw_work->device, "firmware: %s loading timed out\n",
+ fw_work->name);
+ ret = -EAGAIN;
+ }
if (ret)
_request_firmware_cleanup(&fw);