Merge tag 'v3.10.103' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / fs / ext4 / mballoc.c
index 16bb6591561b38ce36826ce6bc17b690f7ac4d07..d01573cc7f0101b670c3a8ee2961f1246638165c 100644 (file)
@@ -1232,6 +1232,7 @@ static void ext4_mb_unload_buddy(struct ext4_buddy *e4b)
 static int mb_find_order_for_block(struct ext4_buddy *e4b, int block)
 {
        int order = 1;
+       int bb_incr = 1 << (e4b->bd_blkbits - 1);
        void *bb;
 
        BUG_ON(e4b->bd_bitmap == e4b->bd_buddy);
@@ -1244,7 +1245,8 @@ static int mb_find_order_for_block(struct ext4_buddy *e4b, int block)
                        /* this block is part of buddy of order 'order' */
                        return order;
                }
-               bb += 1 << (e4b->bd_blkbits - order);
+               bb += bb_incr;
+               bb_incr >>= 1;
                order++;
        }
        return 0;
@@ -1396,6 +1398,8 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
        int last = first + count - 1;
        struct super_block *sb = e4b->bd_sb;
 
+       if (WARN_ON(count == 0))
+               return;
        BUG_ON(last >= (sb->s_blocksize << 3));
        assert_spin_locked(ext4_group_lock_ptr(sb, e4b->bd_group));
        mb_check_buddy(e4b);
@@ -2512,7 +2516,7 @@ int ext4_mb_init(struct super_block *sb)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        unsigned i, j;
-       unsigned offset;
+       unsigned offset, offset_incr;
        unsigned max;
        int ret;
 
@@ -2541,11 +2545,13 @@ int ext4_mb_init(struct super_block *sb)
 
        i = 1;
        offset = 0;
+       offset_incr = 1 << (sb->s_blocksize_bits - 1);
        max = sb->s_blocksize << 2;
        do {
                sbi->s_mb_offsets[i] = offset;
                sbi->s_mb_maxs[i] = max;
-               offset += 1 << (sb->s_blocksize_bits - i);
+               offset += offset_incr;
+               offset_incr = offset_incr >> 1;
                max = max >> 1;
                i++;
        } while (i <= sb->s_blocksize_bits + 1);
@@ -2705,7 +2711,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 +2721,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 +2743,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"
@@ -2870,7 +2877,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
                ext4_error(sb, "Allocating blocks %llu-%llu which overlap "
                           "fs metadata", block, block+len);
                /* File system mounted not to panic on error
-                * Fix the bitmap and repeat the block allocation
+                * Fix the bitmap and return EUCLEAN
                 * We leak some of the blocks here.
                 */
                ext4_lock_group(sb, ac->ac_b_ex.fe_group);
@@ -2879,7 +2886,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
                ext4_unlock_group(sb, ac->ac_b_ex.fe_group);
                err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
                if (!err)
-                       err = -EAGAIN;
+                       err = -EUCLEAN;
                goto out_err;
        }
 
@@ -3177,8 +3184,30 @@ static void ext4_mb_collect_stats(struct ext4_allocation_context *ac)
 static void ext4_discard_allocated_blocks(struct ext4_allocation_context *ac)
 {
        struct ext4_prealloc_space *pa = ac->ac_pa;
+       struct ext4_buddy e4b;
+       int err;
 
-       if (pa && pa->pa_type == MB_INODE_PA)
+       if (pa == NULL) {
+               if (ac->ac_f_ex.fe_len == 0)
+                       return;
+               err = ext4_mb_load_buddy(ac->ac_sb, ac->ac_f_ex.fe_group, &e4b);
+               if (err) {
+                       /*
+                        * This should never happen since we pin the
+                        * pages in the ext4_allocation_context so
+                        * ext4_mb_load_buddy() should never fail.
+                        */
+                       WARN(1, "mb_load_buddy failed (%d)", err);
+                       return;
+               }
+               ext4_lock_group(ac->ac_sb, ac->ac_f_ex.fe_group);
+               mb_free_blocks(ac->ac_inode, &e4b, ac->ac_f_ex.fe_start,
+                              ac->ac_f_ex.fe_len);
+               ext4_unlock_group(ac->ac_sb, ac->ac_f_ex.fe_group);
+               ext4_mb_unload_buddy(&e4b);
+               return;
+       }
+       if (pa->pa_type == MB_INODE_PA)
                pa->pa_free += ac->ac_b_ex.fe_len;
 }
 
@@ -4424,18 +4453,7 @@ repeat:
        }
        if (likely(ac->ac_status == AC_STATUS_FOUND)) {
                *errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_clstrs);
-               if (*errp == -EAGAIN) {
-                       /*
-                        * drop the reference that we took
-                        * in ext4_mb_use_best_found
-                        */
-                       ext4_mb_release_context(ac);
-                       ac->ac_b_ex.fe_group = 0;
-                       ac->ac_b_ex.fe_start = 0;
-                       ac->ac_b_ex.fe_len = 0;
-                       ac->ac_status = AC_STATUS_CONTINUE;
-                       goto repeat;
-               } else if (*errp) {
+               if (*errp) {
                        ext4_discard_allocated_blocks(ac);
                        goto errout;
                } else {
@@ -4586,6 +4604,7 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
        struct buffer_head *gd_bh;
        ext4_group_t block_group;
        struct ext4_sb_info *sbi;
+       struct ext4_inode_info *ei = EXT4_I(inode);
        struct ext4_buddy e4b;
        unsigned int count_clusters;
        int err = 0;
@@ -4739,18 +4758,12 @@ do_more:
                /*
                 * blocks being freed are metadata. these blocks shouldn't
                 * be used until this transaction is committed
+                *
+                * We use __GFP_NOFAIL because ext4_free_blocks() is not allowed
+                * to fail.
                 */
-       retry:
-               new_entry = kmem_cache_alloc(ext4_free_data_cachep, GFP_NOFS);
-               if (!new_entry) {
-                       /*
-                        * We use a retry loop because
-                        * ext4_free_blocks() is not allowed to fail.
-                        */
-                       cond_resched();
-                       congestion_wait(BLK_RW_ASYNC, HZ/50);
-                       goto retry;
-               }
+               new_entry = kmem_cache_alloc(ext4_free_data_cachep,
+                               GFP_NOFS|__GFP_NOFAIL);
                new_entry->efd_start_cluster = bit;
                new_entry->efd_group = block_group;
                new_entry->efd_count = count_clusters;
@@ -4765,7 +4778,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"
@@ -4784,7 +4798,6 @@ do_more:
        ext4_block_bitmap_csum_set(sb, block_group, gdp, bitmap_bh);
        ext4_group_desc_csum_set(sb, block_group, gdp);
        ext4_unlock_group(sb, block_group);
-       percpu_counter_add(&sbi->s_freeclusters_counter, count_clusters);
 
        if (sbi->s_log_groups_per_flex) {
                ext4_group_t flex_group = ext4_flex_group(sbi, block_group);
@@ -4792,10 +4805,23 @@ do_more:
                             &sbi->s_flex_groups[flex_group].free_clusters);
        }
 
-       ext4_mb_unload_buddy(&e4b);
-
-       if (!(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE))
+       if (flags & EXT4_FREE_BLOCKS_RESERVE && ei->i_reserved_data_blocks) {
+               percpu_counter_add(&sbi->s_dirtyclusters_counter,
+                                  count_clusters);
+               spin_lock(&ei->i_block_reservation_lock);
+               if (flags & EXT4_FREE_BLOCKS_METADATA)
+                       ei->i_reserved_meta_blocks += count_clusters;
+               else
+                       ei->i_reserved_data_blocks += count_clusters;
+               spin_unlock(&ei->i_block_reservation_lock);
+               if (!(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE))
+                       dquot_reclaim_block(inode,
+                                       EXT4_C2B(sbi, count_clusters));
+       } else if (!(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE))
                dquot_free_block(inode, EXT4_C2B(sbi, count_clusters));
+       percpu_counter_add(&sbi->s_freeclusters_counter, count_clusters);
+
+       ext4_mb_unload_buddy(&e4b);
 
        /* We dirtied the bitmap block */
        BUFFER_TRACE(bitmap_bh, "dirtied bitmap block");
@@ -4960,13 +4986,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;
@@ -4985,7 +5013,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;
@@ -4998,6 +5026,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
@@ -5012,7 +5041,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;
@@ -5045,7 +5074,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;
@@ -5087,6 +5117,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
@@ -5095,7 +5126,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;
@@ -5151,7 +5183,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;