diff options
author | Amit Pundir <amit.pundir@linaro.org> | 2014-08-18 11:59:18 +0530 |
---|---|---|
committer | Amit Pundir <amit.pundir@linaro.org> | 2014-08-18 11:59:18 +0530 |
commit | b04d002dfd6cb8c115a7afa59032c7313502b17a (patch) | |
tree | d385b717840fccb217d1b33cd2688c6803e51e22 /drivers | |
parent | b738a3e88049258f2c3de4e3fcf181100cb558a5 (diff) | |
parent | 28cb7116eebfa0e4b36b154df0f1c6a251f3b97b (diff) |
Merge branch 'upstream/android-3.10' into linaro-fixes/android-3.10
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/base/firmware_class.c | 43 | ||||
-rw-r--r-- | drivers/staging/android/ashmem.c | 4 |
2 files changed, 43 insertions, 4 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 01e21037d8fe..55d682e6ecea 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -27,6 +27,7 @@ #include <linux/pm.h> #include <linux/suspend.h> #include <linux/syscore_ops.h> +#include <linux/reboot.h> #include <generated/utsrelease.h> @@ -130,6 +131,7 @@ struct firmware_buf { struct page **pages; int nr_pages; int page_array_size; + struct list_head pending_list; #endif char fw_id[]; }; @@ -171,6 +173,9 @@ static struct firmware_buf *__allocate_fw_buf(const char *fw_name, 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); @@ -446,10 +451,8 @@ static struct firmware_priv *to_firmware_priv(struct device *dev) 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 +460,16 @@ static void fw_load_abort(struct firmware_priv *fw_priv) 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,6 +478,25 @@ static void fw_load_abort(struct firmware_priv *fw_priv) #define is_fw_load_aborted(buf) \ test_bit(FW_STATUS_ABORT, &(buf)->status) +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 firmware_timeout_show(struct class *class, struct class_attribute *attr, char *buf) @@ -619,6 +649,7 @@ static ssize_t firmware_loading_store(struct device *dev, * is completed. * */ fw_map_pages_buf(fw_buf); + list_del_init(&fw_buf->pending_list); complete_all(&fw_buf->completion); break; } @@ -868,6 +899,10 @@ 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); @@ -1526,6 +1561,7 @@ static int __init firmware_class_init(void) { fw_cache_init(); #ifdef CONFIG_FW_LOADER_USER_HELPER + register_reboot_notifier(&fw_shutdown_nb); return class_register(&firmware_class); #else return 0; @@ -1539,6 +1575,7 @@ static void __exit firmware_class_exit(void) 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 } diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index 3511b0840362..ccaef8b48eba 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -363,7 +363,9 @@ static int ashmem_shrink(struct shrinker *s, struct shrink_control *sc) if (!sc->nr_to_scan) return lru_count; - mutex_lock(&ashmem_mutex); + if (!mutex_trylock(&ashmem_mutex)) + return -1; + list_for_each_entry_safe(range, next, &ashmem_lru_list, lru) { loff_t start = range->pgstart * PAGE_SIZE; loff_t end = (range->pgend + 1) * PAGE_SIZE; |