From 14adbe5307a4110af7d1e95fb604a1abcdaa6cce Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 23 Aug 2013 17:08:48 -0700 Subject: driver core: firmware: use __ATTR_RW() Use __ATTR_RW() instead of __ATTR() to make it more obvious what the type of attribute is being created. Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware_class.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers/base/firmware_class.c') diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index a439602ea91..e4107d5f036 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -486,9 +486,8 @@ static struct notifier_block fw_shutdown_nb = { .notifier_call = fw_shutdown_notify, }; -static ssize_t firmware_timeout_show(struct class *class, - struct class_attribute *attr, - char *buf) +static ssize_t timeout_show(struct class *class, struct class_attribute *attr, + char *buf) { return sprintf(buf, "%d\n", loading_timeout); } @@ -506,9 +505,8 @@ static ssize_t firmware_timeout_show(struct class *class, * * 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) @@ -518,8 +516,7 @@ static ssize_t firmware_timeout_store(struct class *class, } static struct class_attribute firmware_class_attrs[] = { - __ATTR(timeout, S_IWUSR | S_IRUGO, - firmware_timeout_show, firmware_timeout_store), + __ATTR_RW(timeout), __ATTR_NULL }; -- cgit v1.2.3-70-g09d2 From 1eeeef153c02f5856ec109fa532eb5f31c39f85c Mon Sep 17 00:00:00 2001 From: Maxime Bizon Date: Thu, 29 Aug 2013 20:28:13 +0200 Subject: firmware loader: fix pending_fw_head list corruption Got the following oops just before reboot: Unable to handle kernel NULL pointer dereference at virtual address 00000000 [<8028d300>] (__list_del_entry+0x44/0xac) [<802e3320>] (__fw_load_abort.part.13+0x1c/0x50) [<802e337c>] (fw_shutdown_notify+0x28/0x50) [<80034f80>] (notifier_call_chain.isra.1+0x5c/0x9c) [<800350ec>] (__blocking_notifier_call_chain+0x44/0x58) [<80035114>] (blocking_notifier_call_chain+0x14/0x18) [<80035d64>] (kernel_restart_prepare+0x14/0x38) [<80035d94>] (kernel_restart+0xc/0x50) The following race condition triggers here: _request_firmware_load() device_create_file(...) kobject_uevent(...) (schedule) (resume) firmware_loading_store(1) firmware_loading_store(0) list_del_init(&buf->pending_list) (schedule) (resume) list_add(&buf->pending_list, &pending_fw_head); wait_for_completion(&buf->completion); causing an oops later when walking pending_list after the firmware has been released. The proposed fix is to move the list_add() before sysfs attribute creation. Signed-off-by: Maxime Bizon Acked-by: Ming Lei Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware_class.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/base/firmware_class.c') diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index e4107d5f036..10a4467c63f 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -865,8 +865,15 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, goto err_del_dev; } + mutex_lock(&fw_lock); + list_add(&buf->pending_list, &pending_fw_head); + mutex_unlock(&fw_lock); + retval = device_create_file(f_dev, &dev_attr_loading); if (retval) { + mutex_lock(&fw_lock); + list_del_init(&buf->pending_list); + mutex_unlock(&fw_lock); dev_err(f_dev, "%s: device_create_file failed\n", __func__); goto err_del_bin_attr; } @@ -881,10 +888,6 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD); } - mutex_lock(&fw_lock); - list_add(&buf->pending_list, &pending_fw_head); - mutex_unlock(&fw_lock); - wait_for_completion(&buf->completion); cancel_delayed_work_sync(&fw_priv->timeout_work); -- cgit v1.2.3-70-g09d2