--- zzzz-none-000/linux-3.10.107/drivers/base/firmware_class.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/base/firmware_class.c 2021-02-04 17:41:59.000000000 +0000 @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include @@ -92,9 +94,24 @@ static inline long firmware_loading_timeout(void) { - return loading_timeout > 0 ? loading_timeout * HZ : MAX_SCHEDULE_TIMEOUT; + return loading_timeout > 0 ? loading_timeout * HZ : MAX_JIFFY_OFFSET; } +/* firmware behavior options */ +#define FW_OPT_UEVENT (1U << 0) +#define FW_OPT_NOWAIT (1U << 1) +#ifdef CONFIG_FW_LOADER_USER_HELPER +#define FW_OPT_USERHELPER (1U << 2) +#else +#define FW_OPT_USERHELPER 0 +#endif +#ifdef CONFIG_FW_LOADER_USER_HELPER_FALLBACK +#define FW_OPT_FALLBACK FW_OPT_USERHELPER +#else +#define FW_OPT_FALLBACK 0 +#endif +#define FW_OPT_NO_WARN (1U << 3) + struct firmware_cache { /* firmware_buf instance will be added into the below list */ spinlock_t lock; @@ -127,21 +144,23 @@ size_t size; #ifdef CONFIG_FW_LOADER_USER_HELPER bool is_paged_buf; + bool need_uevent; struct page **pages; int nr_pages; int page_array_size; + struct list_head pending_list; #endif - char fw_id[]; + const char *fw_id; }; struct fw_cache_entry { struct list_head list; - char name[]; + const char *name; }; struct fw_name_devm { unsigned long magic; - char name[]; + const char *name; }; #define to_fwbuf(d) container_of(d, struct firmware_buf, ref) @@ -162,15 +181,22 @@ { struct firmware_buf *buf; - buf = kzalloc(sizeof(*buf) + strlen(fw_name) + 1 , GFP_ATOMIC); - + buf = kzalloc(sizeof(*buf), GFP_ATOMIC); if (!buf) - return buf; + return NULL; + + buf->fw_id = kstrdup_const(fw_name, GFP_ATOMIC); + if (!buf->fw_id) { + kfree(buf); + return NULL; + } kref_init(&buf->ref); - strcpy(buf->fw_id, fw_name); buf->fwc = fwc; init_completion(&buf->completion); +#ifdef CONFIG_FW_LOADER_USER_HELPER + INIT_LIST_HEAD(&buf->pending_list); +#endif pr_debug("%s: fw-%s buf=%p\n", __func__, fw_name, buf); @@ -212,19 +238,8 @@ return tmp ? 0 : -ENOMEM; } -static struct firmware_buf *fw_lookup_buf(const char *fw_name) -{ - struct firmware_buf *tmp; - struct firmware_cache *fwc = &fw_cache; - - spin_lock(&fwc->lock); - tmp = __fw_lookup_buf(fw_name); - spin_unlock(&fwc->lock); - - return tmp; -} - static void __fw_free_buf(struct kref *ref) + __releases(&fwc->lock) { struct firmware_buf *buf = to_fwbuf(ref); struct firmware_cache *fwc = buf->fwc; @@ -246,6 +261,7 @@ } else #endif vfree(buf->data); + kfree_const(buf->fw_id); kfree(buf); } @@ -275,45 +291,47 @@ module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644); MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path"); -/* Don't inline this: 'struct kstat' is biggish */ -static noinline_for_stack long fw_file_size(struct file *file) +static int fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf) { - struct kstat st; - if (vfs_getattr(&file->f_path, &st)) - return -1; - if (!S_ISREG(st.mode)) - return -1; - if (st.size != (long)st.size) - return -1; - return st.size; -} - -static bool fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf) -{ - long size; + int size; char *buf; + int rc; - size = fw_file_size(file); + if (!S_ISREG(file_inode(file)->i_mode)) + return -EINVAL; + size = i_size_read(file_inode(file)); if (size <= 0) - return false; + return -EINVAL; buf = vmalloc(size); if (!buf) - return false; - if (kernel_read(file, 0, buf, size) != size) { - vfree(buf); - return false; - } + return -ENOMEM; + rc = kernel_read(file, 0, buf, size); + if (rc != size) { + if (rc > 0) + rc = -EIO; + goto fail; + } + rc = security_kernel_fw_from_file(file, buf, size); + if (rc) + goto fail; fw_buf->data = buf; fw_buf->size = size; - return true; + return 0; +fail: + vfree(buf); + return rc; } -static bool fw_get_filesystem_firmware(struct device *device, +static int fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf) { - int i; - bool success = false; - char *path = __getname(); + int i, len; + int rc = -ENOENT; + char *path; + + path = __getname(); + if (!path) + return -ENOMEM; for (i = 0; i < ARRAY_SIZE(fw_path); i++) { struct file *file; @@ -322,19 +340,27 @@ if (!fw_path[i][0]) continue; - snprintf(path, PATH_MAX, "%s/%s", fw_path[i], buf->fw_id); + len = snprintf(path, PATH_MAX, "%s/%s", + fw_path[i], buf->fw_id); + if (len >= PATH_MAX) { + rc = -ENAMETOOLONG; + break; + } file = filp_open(path, O_RDONLY, 0); if (IS_ERR(file)) continue; - success = fw_read_file_contents(file, buf); + rc = fw_read_file_contents(file, buf); fput(file); - if (success) + if (rc) + dev_warn(device, "firmware, attempted to load %s, but failed with error %d\n", + path, rc); + else break; } __putname(path); - if (success) { + if (!rc) { dev_dbg(device, "firmware: direct-loading firmware %s\n", buf->fw_id); mutex_lock(&fw_lock); @@ -343,7 +369,7 @@ mutex_unlock(&fw_lock); } - return success; + return rc; } /* firmware holds the ownership of pages */ @@ -380,6 +406,7 @@ if (fwn->magic == (unsigned long)&fw_cache) pr_debug("%s: fw_name-%s devm-%p released\n", __func__, fwn->name, res); + kfree_const(fwn->name); } static int fw_devm_match(struct device *dev, void *res, @@ -410,13 +437,17 @@ if (fwn) return 1; - fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm) + - strlen(name) + 1, GFP_KERNEL); + fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm), + GFP_KERNEL); if (!fwn) return -ENOMEM; + fwn->name = kstrdup_const(name, GFP_KERNEL); + if (!fwn->name) { + devres_free(fwn); + return -ENOMEM; + } fwn->magic = (unsigned long)&fw_cache; - strcpy(fwn->name, name); devres_add(dev, fwn); return 0; @@ -434,7 +465,6 @@ */ #ifdef CONFIG_FW_LOADER_USER_HELPER struct firmware_priv { - struct delayed_work timeout_work; bool nowait; struct device dev; struct firmware_buf *buf; @@ -446,10 +476,8 @@ return container_of(dev, struct firmware_priv, dev); } -static void fw_load_abort(struct firmware_priv *fw_priv) +static void __fw_load_abort(struct firmware_buf *buf) { - struct firmware_buf *buf = fw_priv->buf; - /* * There is a small window in which user can write to 'loading' * between loading done and disappearance of 'loading' @@ -457,8 +485,16 @@ if (test_bit(FW_STATUS_DONE, &buf->status)) return; + list_del_init(&buf->pending_list); set_bit(FW_STATUS_ABORT, &buf->status); complete_all(&buf->completion); +} + +static void fw_load_abort(struct firmware_priv *fw_priv) +{ + struct firmware_buf *buf = fw_priv->buf; + + __fw_load_abort(buf); /* avoid user action after loading abort */ fw_priv->buf = NULL; @@ -467,9 +503,27 @@ #define is_fw_load_aborted(buf) \ test_bit(FW_STATUS_ABORT, &(buf)->status) -static ssize_t firmware_timeout_show(struct class *class, - struct class_attribute *attr, - char *buf) +static LIST_HEAD(pending_fw_head); + +/* reboot notifier for avoid deadlock with usermode_lock */ +static int fw_shutdown_notify(struct notifier_block *unused1, + unsigned long unused2, void *unused3) +{ + mutex_lock(&fw_lock); + while (!list_empty(&pending_fw_head)) + __fw_load_abort(list_first_entry(&pending_fw_head, + struct firmware_buf, + pending_list)); + mutex_unlock(&fw_lock); + return NOTIFY_DONE; +} + +static struct notifier_block fw_shutdown_nb = { + .notifier_call = fw_shutdown_notify, +}; + +static ssize_t timeout_show(struct class *class, struct class_attribute *attr, + char *buf) { return sprintf(buf, "%d\n", loading_timeout); } @@ -487,9 +541,8 @@ * * Note: zero means 'wait forever'. **/ -static ssize_t firmware_timeout_store(struct class *class, - struct class_attribute *attr, - const char *buf, size_t count) +static ssize_t timeout_store(struct class *class, struct class_attribute *attr, + const char *buf, size_t count) { loading_timeout = simple_strtol(buf, NULL, 10); if (loading_timeout < 0) @@ -499,8 +552,7 @@ } static struct class_attribute firmware_class_attrs[] = { - __ATTR(timeout, S_IWUSR | S_IRUGO, - firmware_timeout_show, firmware_timeout_store), + __ATTR_RW(timeout), __ATTR_NULL }; @@ -509,8 +561,6 @@ struct firmware_priv *fw_priv = to_firmware_priv(dev); kfree(fw_priv); - - module_put(THIS_MODULE); } static int do_firmware_uevent(struct firmware_priv *fw_priv, struct kobj_uevent_env *env) @@ -569,8 +619,7 @@ if (!buf->is_paged_buf) return 0; - if (buf->data) - vunmap(buf->data); + vunmap(buf->data); buf->data = vmap(buf->pages, buf->nr_pages, 0, PAGE_KERNEL_RO); if (!buf->data) return -ENOMEM; @@ -596,6 +645,7 @@ { struct firmware_priv *fw_priv = to_firmware_priv(dev); struct firmware_buf *fw_buf; + ssize_t written = count; int loading = simple_strtol(buf, NULL, 10); int i; @@ -619,6 +669,8 @@ break; case 0: if (test_bit(FW_STATUS_LOADING, &fw_buf->status)) { + int rc; + set_bit(FW_STATUS_DONE, &fw_buf->status); clear_bit(FW_STATUS_LOADING, &fw_buf->status); @@ -628,7 +680,23 @@ * see the mapped 'buf->data' once the loading * is completed. * */ - fw_map_pages_buf(fw_buf); + rc = fw_map_pages_buf(fw_buf); + if (rc) + dev_err(dev, "%s: map pages failed\n", + __func__); + else + rc = security_kernel_fw_from_file(NULL, + fw_buf->data, fw_buf->size); + + /* + * Same logic as fw_load_abort, only the DONE bit + * is ignored and we set ABORT only on failure. + */ + list_del_init(&fw_buf->pending_list); + if (rc) { + set_bit(FW_STATUS_ABORT, &fw_buf->status); + written = rc; + } complete_all(&fw_buf->completion); break; } @@ -642,7 +710,7 @@ } out: mutex_unlock(&fw_lock); - return count; + return written; } static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store); @@ -694,7 +762,7 @@ static int fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size) { struct firmware_buf *buf = fw_priv->buf; - int pages_needed = ALIGN(min_size, PAGE_SIZE) >> PAGE_SHIFT; + int pages_needed = PAGE_ALIGN(min_size) >> PAGE_SHIFT; /* If the array of pages is too small, grow it... */ if (buf->page_array_size < pages_needed) { @@ -796,48 +864,55 @@ .write = firmware_data_write, }; -static void firmware_class_timeout_work(struct work_struct *work) -{ - struct firmware_priv *fw_priv = container_of(work, - struct firmware_priv, timeout_work.work); +static struct attribute *fw_dev_attrs[] = { + &dev_attr_loading.attr, + NULL +}; - mutex_lock(&fw_lock); - fw_load_abort(fw_priv); - mutex_unlock(&fw_lock); -} +static struct bin_attribute *fw_dev_bin_attrs[] = { + &firmware_attr_data, + NULL +}; + +static const struct attribute_group fw_dev_attr_group = { + .attrs = fw_dev_attrs, + .bin_attrs = fw_dev_bin_attrs, +}; + +static const struct attribute_group *fw_dev_attr_groups[] = { + &fw_dev_attr_group, + NULL +}; static struct firmware_priv * fw_create_instance(struct firmware *firmware, const char *fw_name, - struct device *device, bool uevent, bool nowait) + struct device *device, unsigned int opt_flags) { struct firmware_priv *fw_priv; struct device *f_dev; fw_priv = kzalloc(sizeof(*fw_priv), GFP_KERNEL); if (!fw_priv) { - dev_err(device, "%s: kmalloc failed\n", __func__); fw_priv = ERR_PTR(-ENOMEM); goto exit; } - fw_priv->nowait = nowait; + fw_priv->nowait = !!(opt_flags & FW_OPT_NOWAIT); fw_priv->fw = firmware; - INIT_DELAYED_WORK(&fw_priv->timeout_work, - firmware_class_timeout_work); - f_dev = &fw_priv->dev; device_initialize(f_dev); dev_set_name(f_dev, "%s", fw_name); f_dev->parent = device; f_dev->class = &firmware_class; + f_dev->groups = fw_dev_attr_groups; exit: return fw_priv; } /* load a firmware via user helper */ -static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, - long timeout) +static int _request_firmware_load(struct firmware_priv *fw_priv, + unsigned int opt_flags, long timeout) { int retval = 0; struct device *f_dev = &fw_priv->dev; @@ -848,44 +923,41 @@ dev_set_uevent_suppress(f_dev, true); - /* Need to pin this module until class device is destroyed */ - __module_get(THIS_MODULE); - retval = device_add(f_dev); if (retval) { dev_err(f_dev, "%s: device_register failed\n", __func__); goto err_put_dev; } - retval = device_create_bin_file(f_dev, &firmware_attr_data); - if (retval) { - dev_err(f_dev, "%s: sysfs_create_bin_file failed\n", __func__); - goto err_del_dev; - } - - retval = device_create_file(f_dev, &dev_attr_loading); - if (retval) { - dev_err(f_dev, "%s: device_create_file failed\n", __func__); - goto err_del_bin_attr; - } + mutex_lock(&fw_lock); + list_add(&buf->pending_list, &pending_fw_head); + mutex_unlock(&fw_lock); - if (uevent) { + if (opt_flags & FW_OPT_UEVENT) { + buf->need_uevent = true; dev_set_uevent_suppress(f_dev, false); dev_dbg(f_dev, "firmware: requesting %s\n", buf->fw_id); - if (timeout != MAX_SCHEDULE_TIMEOUT) - schedule_delayed_work(&fw_priv->timeout_work, timeout); - kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD); + } else { + timeout = MAX_JIFFY_OFFSET; } - wait_for_completion(&buf->completion); + timeout = wait_for_completion_interruptible_timeout(&buf->completion, + timeout); + if (timeout == -ERESTARTSYS || !timeout) { + retval = timeout; + mutex_lock(&fw_lock); + fw_load_abort(fw_priv); + mutex_unlock(&fw_lock); + } else if (timeout > 0) { + retval = 0; + } - cancel_delayed_work_sync(&fw_priv->timeout_work); + if (is_fw_load_aborted(buf)) + retval = -EAGAIN; + else if (!buf->data) + retval = -ENOMEM; - device_remove_file(f_dev, &dev_attr_loading); -err_del_bin_attr: - device_remove_bin_file(f_dev, &firmware_attr_data); -err_del_dev: device_del(f_dev); err_put_dev: put_device(f_dev); @@ -894,21 +966,38 @@ static int fw_load_from_user_helper(struct firmware *firmware, const char *name, struct device *device, - bool uevent, bool nowait, long timeout) + unsigned int opt_flags, long timeout) { struct firmware_priv *fw_priv; - fw_priv = fw_create_instance(firmware, name, device, uevent, nowait); + fw_priv = fw_create_instance(firmware, name, device, opt_flags); if (IS_ERR(fw_priv)) return PTR_ERR(fw_priv); fw_priv->buf = firmware->priv; - return _request_firmware_load(fw_priv, uevent, timeout); + return _request_firmware_load(fw_priv, opt_flags, timeout); +} + +#ifdef CONFIG_PM_SLEEP +/* kill pending requests without uevent to avoid blocking suspend */ +static void kill_requests_without_uevent(void) +{ + struct firmware_buf *buf; + struct firmware_buf *next; + + mutex_lock(&fw_lock); + list_for_each_entry_safe(buf, next, &pending_fw_head, pending_list) { + if (!buf->need_uevent) + __fw_load_abort(buf); + } + mutex_unlock(&fw_lock); } +#endif + #else /* CONFIG_FW_LOADER_USER_HELPER */ static inline int fw_load_from_user_helper(struct firmware *firmware, const char *name, - struct device *device, bool uevent, bool nowait, + struct device *device, unsigned int opt_flags, long timeout) { return -ENOENT; @@ -917,6 +1006,10 @@ /* No abort during direct loading */ #define is_fw_load_aborted(buf) false +#ifdef CONFIG_PM_SLEEP +static inline void kill_requests_without_uevent(void) { } +#endif + #endif /* CONFIG_FW_LOADER_USER_HELPER */ @@ -932,7 +1025,7 @@ break; } mutex_unlock(&fw_lock); - wait_for_completion(&buf->completion); + ret = wait_for_completion_interruptible(&buf->completion); mutex_lock(&fw_lock); } mutex_unlock(&fw_lock); @@ -984,7 +1077,8 @@ return 1; /* need to load */ } -static int assign_firmware_buf(struct firmware *fw, struct device *device) +static int assign_firmware_buf(struct firmware *fw, struct device *device, + unsigned int opt_flags) { struct firmware_buf *buf = fw->priv; @@ -1001,7 +1095,8 @@ * device may has been deleted already, but the problem * should be fixed in devres or driver core. */ - if (device) + /* don't cache firmware handled without uevent */ + if (device && (opt_flags & FW_OPT_UEVENT)) fw_add_devm_name(device, buf->fw_id); /* @@ -1022,7 +1117,7 @@ /* called from request_firmware() and request_firmware_work_func() */ static int _request_firmware(const struct firmware **firmware_p, const char *name, - struct device *device, bool uevent, bool nowait) + struct device *device, unsigned int opt_flags) { struct firmware *fw; long timeout; @@ -1040,7 +1135,7 @@ ret = 0; timeout = firmware_loading_timeout(); - if (nowait) { + if (opt_flags & FW_OPT_NOWAIT) { timeout = usermodehelper_read_lock_wait(timeout); if (!timeout) { dev_dbg(device, "firmware: %s loading timed out\n", @@ -1057,11 +1152,21 @@ } } - if (!fw_get_filesystem_firmware(device, fw->priv)) - ret = fw_load_from_user_helper(fw, name, device, - uevent, nowait, timeout); + ret = fw_get_filesystem_firmware(device, fw->priv); + if (ret) { + if (!(opt_flags & FW_OPT_NO_WARN)) + dev_warn(device, + "Direct firmware load for %s failed with error %d\n", + name, ret); + if (opt_flags & FW_OPT_USERHELPER) { + dev_warn(device, "Falling back to user helper\n"); + ret = fw_load_from_user_helper(fw, name, device, + opt_flags, timeout); + } + } + if (!ret) - ret = assign_firmware_buf(fw, device); + ret = assign_firmware_buf(fw, device, opt_flags); usermodehelper_read_unlock(); @@ -1097,10 +1202,42 @@ **/ int request_firmware(const struct firmware **firmware_p, const char *name, - struct device *device) + struct device *device) { - return _request_firmware(firmware_p, name, device, true, false); + int ret; + + /* Need to pin this module until return */ + __module_get(THIS_MODULE); + ret = _request_firmware(firmware_p, name, device, + FW_OPT_UEVENT | FW_OPT_FALLBACK); + module_put(THIS_MODULE); + return ret; } +EXPORT_SYMBOL(request_firmware); + +/** + * request_firmware_direct: - load firmware directly without usermode helper + * @firmware_p: pointer to firmware image + * @name: name of firmware file + * @device: device for which firmware is being loaded + * + * This function works pretty much like request_firmware(), but this doesn't + * fall back to usermode helper even if the firmware couldn't be loaded + * directly from fs. Hence it's useful for loading optional firmwares, which + * aren't always present, without extra long timeouts of udev. + **/ +int request_firmware_direct(const struct firmware **firmware_p, + const char *name, struct device *device) +{ + int ret; + + __module_get(THIS_MODULE); + ret = _request_firmware(firmware_p, name, device, + FW_OPT_UEVENT | FW_OPT_NO_WARN); + module_put(THIS_MODULE); + return ret; +} +EXPORT_SYMBOL_GPL(request_firmware_direct); /** * release_firmware: - release the resource associated with a firmware image @@ -1114,6 +1251,7 @@ kfree(fw); } } +EXPORT_SYMBOL(release_firmware); /* Async support */ struct firmware_work { @@ -1123,7 +1261,7 @@ struct device *device; void *context; void (*cont)(const struct firmware *fw, void *context); - bool uevent; + unsigned int opt_flags; }; static void request_firmware_work_func(struct work_struct *work) @@ -1134,11 +1272,12 @@ fw_work = container_of(work, struct firmware_work, work); _request_firmware(&fw, fw_work->name, fw_work->device, - fw_work->uevent, true); + fw_work->opt_flags); fw_work->cont(fw, fw_work->context); put_device(fw_work->device); /* taken in request_firmware_nowait() */ module_put(fw_work->module); + kfree_const(fw_work->name); kfree(fw_work); } @@ -1173,18 +1312,24 @@ { struct firmware_work *fw_work; - fw_work = kzalloc(sizeof (struct firmware_work), gfp); + fw_work = kzalloc(sizeof(struct firmware_work), gfp); if (!fw_work) return -ENOMEM; fw_work->module = module; - fw_work->name = name; + fw_work->name = kstrdup_const(name, gfp); + if (!fw_work->name) { + kfree(fw_work); + return -ENOMEM; + } fw_work->device = device; fw_work->context = context; fw_work->cont = cont; - fw_work->uevent = uevent; + fw_work->opt_flags = FW_OPT_NOWAIT | FW_OPT_FALLBACK | + (uevent ? FW_OPT_UEVENT : FW_OPT_USERHELPER); if (!try_module_get(module)) { + kfree_const(fw_work->name); kfree(fw_work); return -EFAULT; } @@ -1194,6 +1339,10 @@ schedule_work(&fw_work->work); return 0; } +EXPORT_SYMBOL(request_firmware_nowait); + +#ifdef CONFIG_PM_SLEEP +static ASYNC_DOMAIN_EXCLUSIVE(fw_cache_domain); /** * cache_firmware - cache one firmware image in kernel memory space @@ -1209,7 +1358,7 @@ * Return !0 otherwise * */ -int cache_firmware(const char *fw_name) +static int cache_firmware(const char *fw_name) { int ret; const struct firmware *fw; @@ -1225,6 +1374,18 @@ return ret; } +static struct firmware_buf *fw_lookup_buf(const char *fw_name) +{ + struct firmware_buf *tmp; + struct firmware_cache *fwc = &fw_cache; + + spin_lock(&fwc->lock); + tmp = __fw_lookup_buf(fw_name); + spin_unlock(&fwc->lock); + + return tmp; +} + /** * uncache_firmware - remove one cached firmware image * @fw_name: the firmware image name @@ -1236,7 +1397,7 @@ * Return !0 otherwise * */ -int uncache_firmware(const char *fw_name) +static int uncache_firmware(const char *fw_name) { struct firmware_buf *buf; struct firmware fw; @@ -1255,18 +1416,20 @@ return -EINVAL; } -#ifdef CONFIG_PM_SLEEP -static ASYNC_DOMAIN_EXCLUSIVE(fw_cache_domain); - static struct fw_cache_entry *alloc_fw_cache_entry(const char *name) { struct fw_cache_entry *fce; - fce = kzalloc(sizeof(*fce) + strlen(name) + 1, GFP_ATOMIC); + fce = kzalloc(sizeof(*fce), GFP_ATOMIC); if (!fce) goto exit; - strcpy(fce->name, name); + fce->name = kstrdup_const(name, GFP_ATOMIC); + if (!fce->name) { + kfree(fce); + fce = NULL; + goto exit; + } exit: return fce; } @@ -1306,6 +1469,7 @@ static void free_fw_cache_entry(struct fw_cache_entry *fce) { + kfree_const(fce->name); kfree(fce); } @@ -1467,8 +1631,8 @@ */ static void device_uncache_fw_images_delay(unsigned long delay) { - schedule_delayed_work(&fw_cache.work, - msecs_to_jiffies(delay)); + queue_delayed_work(system_power_efficient_wq, &fw_cache.work, + msecs_to_jiffies(delay)); } static int fw_pm_notify(struct notifier_block *notify_block, @@ -1477,6 +1641,8 @@ switch (mode) { case PM_HIBERNATION_PREPARE: case PM_SUSPEND_PREPARE: + case PM_RESTORE_PREPARE: + kill_requests_without_uevent(); device_cache_fw_images(); break; @@ -1539,6 +1705,7 @@ { fw_cache_init(); #ifdef CONFIG_FW_LOADER_USER_HELPER + register_reboot_notifier(&fw_shutdown_nb); return class_register(&firmware_class); #else return 0; @@ -1552,15 +1719,10 @@ unregister_pm_notifier(&fw_cache.pm_notify); #endif #ifdef CONFIG_FW_LOADER_USER_HELPER + unregister_reboot_notifier(&fw_shutdown_nb); class_unregister(&firmware_class); #endif } fs_initcall(firmware_class_init); module_exit(firmware_class_exit); - -EXPORT_SYMBOL(release_firmware); -EXPORT_SYMBOL(request_firmware); -EXPORT_SYMBOL(request_firmware_nowait); -EXPORT_SYMBOL_GPL(cache_firmware); -EXPORT_SYMBOL_GPL(uncache_firmware);