]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
firmware: ensure the firmware cache is not used on incompatible calls
authorLuis R. Rodriguez <mcgrof@kernel.org>
Sat, 10 Mar 2018 14:14:59 +0000 (06:14 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 20 Mar 2018 08:28:47 +0000 (09:28 +0100)
request_firmware_into_buf() explicitly disables the firmware cache,
meanwhile the firmware cache cannot be used when request_firmware_nowait()
is used without the uevent. Enforce a sanity check for this to avoid future
issues undocumented behaviours should misuses of the firmware cache
happen later.

One of the reasons we want to enforce this is the firmware cache is
used for helping with suspend/resume, and if incompatible calls use it
they can stall suspend.

Signed-off-by: Luis R. Rodriguez <mcgrof@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/base/firmware_loader/main.c

index b569d8a093926ceaa3a44ef1113578e9961df4b9..2913bb0e5e7b065c6a1b2a5aff57a2ac8653b4b8 100644 (file)
@@ -431,6 +431,11 @@ static int fw_add_devm_name(struct device *dev, const char *name)
        return 0;
 }
 #else
+static bool fw_cache_is_setup(struct device *dev, const char *name)
+{
+       return false;
+}
+
 static int fw_add_devm_name(struct device *dev, const char *name)
 {
        return 0;
@@ -672,6 +677,9 @@ request_firmware_into_buf(const struct firmware **firmware_p, const char *name,
 {
        int ret;
 
+       if (fw_cache_is_setup(device, name))
+               return -EOPNOTSUPP;
+
        __module_get(THIS_MODULE);
        ret = _request_firmware(firmware_p, name, device, buf, size,
                                FW_OPT_UEVENT | FW_OPT_NOCACHE);
@@ -769,6 +777,12 @@ request_firmware_nowait(
        fw_work->opt_flags = FW_OPT_NOWAIT |
                (uevent ? FW_OPT_UEVENT : FW_OPT_USERHELPER);
 
+       if (!uevent && fw_cache_is_setup(device, name)) {
+               kfree_const(fw_work->name);
+               kfree(fw_work);
+               return -EOPNOTSUPP;
+       }
+
        if (!try_module_get(module)) {
                kfree_const(fw_work->name);
                kfree(fw_work);