summaryrefslogtreecommitdiffstats
path: root/drivers/base/firmware_class.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2012-03-28 23:29:55 +0200
committerRafael J. Wysocki <rjw@sisk.pl>2012-03-28 23:29:55 +0200
commit811fa4004485dec8977176bf605a5b0508ee206c (patch)
treeafa0924a75f217a27f7438e34758747413ba635a /drivers/base/firmware_class.c
parentfe2e39d8782d885755139304d8dba0b3e5bfa878 (diff)
downloadlinux-811fa4004485dec8977176bf605a5b0508ee206c.tar.gz
linux-811fa4004485dec8977176bf605a5b0508ee206c.tar.bz2
linux-811fa4004485dec8977176bf605a5b0508ee206c.zip
firmware_class: Split _request_firmware() into three functions, v2
Split _request_firmware() into three functions, _request_firmware_prepare() doing preparatory work that need not be done under umhelper_sem, _request_firmware_cleanup() doing the post-error cleanup and _request_firmware() carrying out the remaining operations. This change is requisite for moving the acquisition of umhelper_sem from _request_firmware() to the callers, which is going to be done subsequently. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Reviewed-by: Stephen Boyd <sboyd@codeaurora.org> Cc: stable@vger.kernel.org
Diffstat (limited to 'drivers/base/firmware_class.c')
-rw-r--r--drivers/base/firmware_class.c58
1 files changed, 41 insertions, 17 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index deee871e509c..60290671f04a 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -435,7 +435,7 @@ static void firmware_class_timeout(u_long data)
}
static struct firmware_priv *
-fw_create_instance(struct firmware *firmware, const char *fw_name,
+fw_create_instance(const struct firmware *firmware, const char *fw_name,
struct device *device, bool uevent, bool nowait)
{
struct firmware_priv *fw_priv;
@@ -449,7 +449,7 @@ fw_create_instance(struct firmware *firmware, const char *fw_name,
goto err_out;
}
- fw_priv->fw = firmware;
+ fw_priv->fw = (struct firmware *)firmware;
fw_priv->nowait = nowait;
strcpy(fw_priv->fw_id, fw_name);
init_completion(&fw_priv->completion);
@@ -510,13 +510,10 @@ static void fw_destroy_instance(struct firmware_priv *fw_priv)
device_unregister(f_dev);
}
-static int _request_firmware(const struct firmware **firmware_p,
- const char *name, struct device *device,
- bool uevent, bool nowait)
+static int _request_firmware_prepare(const struct firmware **firmware_p,
+ const char *name, struct device *device)
{
- struct firmware_priv *fw_priv;
struct firmware *firmware;
- int retval = 0;
if (!firmware_p)
return -EINVAL;
@@ -533,10 +530,26 @@ static int _request_firmware(const struct firmware **firmware_p,
return 0;
}
+ return 1;
+}
+
+static void _request_firmware_cleanup(const struct firmware **firmware_p)
+{
+ release_firmware(*firmware_p);
+ *firmware_p = NULL;
+}
+
+static int _request_firmware(const struct firmware *firmware,
+ const char *name, struct device *device,
+ bool uevent, bool nowait)
+{
+ 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);
- goto out_nolock;
+ return retval;
}
if (uevent)
@@ -572,13 +585,6 @@ static int _request_firmware(const struct firmware **firmware_p,
out:
usermodehelper_read_unlock();
-
-out_nolock:
- if (retval) {
- release_firmware(firmware);
- *firmware_p = NULL;
- }
-
return retval;
}
@@ -601,7 +607,17 @@ int
request_firmware(const struct firmware **firmware_p, const char *name,
struct device *device)
{
- return _request_firmware(firmware_p, name, device, true, false);
+ int ret;
+
+ ret = _request_firmware_prepare(firmware_p, name, device);
+ if (ret <= 0)
+ return ret;
+
+ ret = _request_firmware(*firmware_p, name, device, true, false);
+ if (ret)
+ _request_firmware_cleanup(firmware_p);
+
+ return ret;
}
/**
@@ -639,8 +655,16 @@ static int request_firmware_work_func(void *arg)
return 0;
}
- ret = _request_firmware(&fw, fw_work->name, fw_work->device,
+ ret = _request_firmware_prepare(&fw, fw_work->name, fw_work->device);
+ if (ret <= 0)
+ goto out;
+
+ ret = _request_firmware(fw, fw_work->name, fw_work->device,
fw_work->uevent, true);
+ if (ret)
+ _request_firmware_cleanup(&fw);
+
+ out:
fw_work->cont(fw, fw_work->context);
module_put(fw_work->module);