Merge branch 'upstream/android-3.10' into linaro-fixes/android-3.10
authorAmit Pundir <amit.pundir@linaro.org>
Mon, 18 Aug 2014 06:29:18 +0000 (11:59 +0530)
committerAmit Pundir <amit.pundir@linaro.org>
Mon, 18 Aug 2014 06:29:18 +0000 (11:59 +0530)
drivers/base/firmware_class.c
drivers/staging/android/ashmem.c
fs/ext4/ext4.h
fs/ext4/ioctl.c
fs/ext4/mballoc.c
include/uapi/linux/fs.h

index 01e21037d8feb5c04e6aedee608e9cdedc0d87bd..55d682e6ecea92b183997f2ecfa2858df7d567ba 100644 (file)
@@ -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
 }
index 3511b0840362b88c878abcd1d2de885d005f053c..ccaef8b48ebaaafc72d244edf6c1063270367902 100644 (file)
@@ -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;
index 5aae3d12d4004109cff811b77011486abbaed1b5..09ace38b451aa450051ab0a561c0002bb1d576d0 100644 (file)
@@ -2050,7 +2050,8 @@ extern int ext4_mb_add_groupinfo(struct super_block *sb,
                ext4_group_t i, struct ext4_group_desc *desc);
 extern int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
                                ext4_fsblk_t block, unsigned long count);
-extern int ext4_trim_fs(struct super_block *, struct fstrim_range *);
+extern int ext4_trim_fs(struct super_block *, struct fstrim_range *,
+                               unsigned long blkdev_flags);
 
 /* inode.c */
 struct buffer_head *ext4_getblk(handle_t *, struct inode *,
index 9491ac0590f746b9abe56e484e7646022a0bd1c3..d01a05593be5782c08e92378a1a1e287c4ab3430 100644 (file)
@@ -594,11 +594,13 @@ resizefs_out:
                return err;
        }
 
+       case FIDTRIM:
        case FITRIM:
        {
                struct request_queue *q = bdev_get_queue(sb->s_bdev);
                struct fstrim_range range;
                int ret = 0;
+               int flags  = cmd == FIDTRIM ? BLKDEV_DISCARD_SECURE : 0;
 
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
@@ -606,13 +608,15 @@ resizefs_out:
                if (!blk_queue_discard(q))
                        return -EOPNOTSUPP;
 
+               if ((flags & BLKDEV_DISCARD_SECURE) && !blk_queue_secdiscard(q))
+                       return -EOPNOTSUPP;
                if (copy_from_user(&range, (struct fstrim_range __user *)arg,
                    sizeof(range)))
                        return -EFAULT;
 
                range.minlen = max((unsigned int)range.minlen,
                                   q->limits.discard_granularity);
-               ret = ext4_trim_fs(sb, &range);
+               ret = ext4_trim_fs(sb, &range, flags);
                if (ret < 0)
                        return ret;
 
index def84082a9a9b73deadc0d369c63a7ef981d8ea9..50375b0f60221fe9b4df99ebac480fd10fecf857 100644 (file)
@@ -2705,7 +2705,8 @@ int ext4_mb_release(struct super_block *sb)
 }
 
 static inline int ext4_issue_discard(struct super_block *sb,
-               ext4_group_t block_group, ext4_grpblk_t cluster, int count)
+               ext4_group_t block_group, ext4_grpblk_t cluster, int count,
+               unsigned long flags)
 {
        ext4_fsblk_t discard_block;
 
@@ -2714,7 +2715,7 @@ static inline int ext4_issue_discard(struct super_block *sb,
        count = EXT4_C2B(EXT4_SB(sb), count);
        trace_ext4_discard_blocks(sb,
                        (unsigned long long) discard_block, count);
-       return sb_issue_discard(sb, discard_block, count, GFP_NOFS, 0);
+       return sb_issue_discard(sb, discard_block, count, GFP_NOFS, flags);
 }
 
 /*
@@ -2736,7 +2737,7 @@ static void ext4_free_data_callback(struct super_block *sb,
        if (test_opt(sb, DISCARD)) {
                err = ext4_issue_discard(sb, entry->efd_group,
                                         entry->efd_start_cluster,
-                                        entry->efd_count);
+                                        entry->efd_count, 0);
                if (err && err != -EOPNOTSUPP)
                        ext4_msg(sb, KERN_WARNING, "discard request in"
                                 " group:%d block:%d count:%d failed"
@@ -4755,7 +4756,8 @@ do_more:
                 * them with group lock_held
                 */
                if (test_opt(sb, DISCARD)) {
-                       err = ext4_issue_discard(sb, block_group, bit, count);
+                       err = ext4_issue_discard(sb, block_group, bit, count,
+                                                0);
                        if (err && err != -EOPNOTSUPP)
                                ext4_msg(sb, KERN_WARNING, "discard request in"
                                         " group:%d block:%d count:%lu failed"
@@ -4950,13 +4952,15 @@ error_return:
  * @count:     number of blocks to TRIM
  * @group:     alloc. group we are working with
  * @e4b:       ext4 buddy for the group
+ * @blkdev_flags: flags for the block device
  *
  * Trim "count" blocks starting at "start" in the "group". To assure that no
  * one will allocate those blocks, mark it as used in buddy bitmap. This must
  * be called with under the group lock.
  */
 static int ext4_trim_extent(struct super_block *sb, int start, int count,
-                            ext4_group_t group, struct ext4_buddy *e4b)
+                           ext4_group_t group, struct ext4_buddy *e4b,
+                           unsigned long blkdev_flags)
 {
        struct ext4_free_extent ex;
        int ret = 0;
@@ -4975,7 +4979,7 @@ static int ext4_trim_extent(struct super_block *sb, int start, int count,
         */
        mb_mark_used(e4b, &ex);
        ext4_unlock_group(sb, group);
-       ret = ext4_issue_discard(sb, group, start, count);
+       ret = ext4_issue_discard(sb, group, start, count, blkdev_flags);
        ext4_lock_group(sb, group);
        mb_free_blocks(NULL, e4b, start, ex.fe_len);
        return ret;
@@ -4988,6 +4992,7 @@ static int ext4_trim_extent(struct super_block *sb, int start, int count,
  * @start:             first group block to examine
  * @max:               last group block to examine
  * @minblocks:         minimum extent block count
+ * @blkdev_flags:      flags for the block device
  *
  * ext4_trim_all_free walks through group's buddy bitmap searching for free
  * extents. When the free block is found, ext4_trim_extent is called to TRIM
@@ -5002,7 +5007,7 @@ static int ext4_trim_extent(struct super_block *sb, int start, int count,
 static ext4_grpblk_t
 ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
                   ext4_grpblk_t start, ext4_grpblk_t max,
-                  ext4_grpblk_t minblocks)
+                  ext4_grpblk_t minblocks, unsigned long blkdev_flags)
 {
        void *bitmap;
        ext4_grpblk_t next, count = 0, free_count = 0;
@@ -5035,7 +5040,8 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
 
                if ((next - start) >= minblocks) {
                        ret = ext4_trim_extent(sb, start,
-                                              next - start, group, &e4b);
+                                              next - start, group, &e4b,
+                                              blkdev_flags);
                        if (ret && ret != -EOPNOTSUPP)
                                break;
                        ret = 0;
@@ -5077,6 +5083,7 @@ out:
  * ext4_trim_fs() -- trim ioctl handle function
  * @sb:                        superblock for filesystem
  * @range:             fstrim_range structure
+ * @blkdev_flags:      flags for the block device
  *
  * start:      First Byte to trim
  * len:                number of Bytes to trim from start
@@ -5085,7 +5092,8 @@ out:
  * start to start+len. For each such a group ext4_trim_all_free function
  * is invoked to trim all free space.
  */
-int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
+int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range,
+                       unsigned long blkdev_flags)
 {
        struct ext4_group_info *grp;
        ext4_group_t group, first_group, last_group;
@@ -5141,7 +5149,7 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
 
                if (grp->bb_free >= minlen) {
                        cnt = ext4_trim_all_free(sb, group, first_cluster,
-                                               end, minlen);
+                                               end, minlen, blkdev_flags);
                        if (cnt < 0) {
                                ret = cnt;
                                break;
index a4ed56cf0eac5f1e5c1b90edf2a1d3b6093d9e02..5014a5c472ed1447bf4237a0da534cabe8ce517a 100644 (file)
@@ -154,6 +154,8 @@ struct inodes_stat_t {
 #define FITHAW         _IOWR('X', 120, int)    /* Thaw */
 #define FITRIM         _IOWR('X', 121, struct fstrim_range)    /* Trim */
 
+#define FIDTRIM        _IOWR('f', 128, struct fstrim_range)    /* Deep discard trim */
+
 #define        FS_IOC_GETFLAGS                 _IOR('f', 1, long)
 #define        FS_IOC_SETFLAGS                 _IOW('f', 2, long)
 #define        FS_IOC_GETVERSION               _IOR('v', 1, long)