]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/ext4/mballoc.c
Merge branch 'core-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-omap-h63xx.git] / fs / ext4 / mballoc.c
index d2b1bcaf88ecb994ef8be9c1e91b1ca204fbbd94..4415beeb0b620c46611348c7092fa75c42cf2337 100644 (file)
  * inode as:
  *
  *  {                        page                        }
- *  [ group 0 buddy][ group 0 bitmap] [group 1][ group 1]...
+ *  [ group 0 bitmap][ group 0 buddy] [group 1][ group 1]...
  *
  *
  * one block each for bitmap and buddy information.  So for each group we
  *        object
  *
  */
+static struct kmem_cache *ext4_pspace_cachep;
+static struct kmem_cache *ext4_ac_cachep;
+static struct kmem_cache *ext4_free_ext_cachep;
+static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
+                                       ext4_group_t group);
+static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap,
+                                               ext4_group_t group);
+static int ext4_mb_init_per_dev_proc(struct super_block *sb);
+static int ext4_mb_destroy_per_dev_proc(struct super_block *sb);
+static void release_blocks_on_commit(journal_t *journal, transaction_t *txn);
+
+
 
 static inline void *mb_correct_addr_and_bit(int *bit, void *addr)
 {
@@ -445,8 +457,8 @@ static void mb_free_blocks_double(struct inode *inode, struct ext4_buddy *e4b,
                        blocknr += first + i;
                        blocknr +=
                            le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
-
-                       ext4_error(sb, __func__, "double-free of inode"
+                       ext4_grp_locked_error(sb, e4b->bd_group,
+                                  __func__, "double-free of inode"
                                   " %lu's block %llu(bit %u in group %u)",
                                   inode ? inode->i_ino : 0, blocknr,
                                   first + i, e4b->bd_group);
@@ -690,7 +702,7 @@ static void ext4_mb_generate_buddy(struct super_block *sb,
        grp->bb_fragments = fragments;
 
        if (free != grp->bb_free) {
-               ext4_error(sb, __func__,
+               ext4_grp_locked_error(sb, group,  __func__,
                        "EXT4-fs: group %u: %u blocks in bitmap, %u in gd",
                        group, free, grp->bb_free);
                /*
@@ -716,7 +728,7 @@ static void ext4_mb_generate_buddy(struct super_block *sb,
  * stored in the inode as
  *
  * {                        page                        }
- * [ group 0 buddy][ group 0 bitmap] [group 1][ group 1]...
+ * [ group 0 bitmap][ group 0 buddy] [group 1][ group 1]...
  *
  *
  * one block each for bitmap and buddy information.
@@ -782,22 +794,42 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
                if (bh[i] == NULL)
                        goto out;
 
-               if (buffer_uptodate(bh[i]) &&
-                   !(desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)))
+               if (bitmap_uptodate(bh[i]))
                        continue;
 
                lock_buffer(bh[i]);
+               if (bitmap_uptodate(bh[i])) {
+                       unlock_buffer(bh[i]);
+                       continue;
+               }
                spin_lock(sb_bgl_lock(EXT4_SB(sb), first_group + i));
                if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
                        ext4_init_block_bitmap(sb, bh[i],
                                                first_group + i, desc);
+                       set_bitmap_uptodate(bh[i]);
                        set_buffer_uptodate(bh[i]);
-                       unlock_buffer(bh[i]);
                        spin_unlock(sb_bgl_lock(EXT4_SB(sb), first_group + i));
+                       unlock_buffer(bh[i]);
                        continue;
                }
                spin_unlock(sb_bgl_lock(EXT4_SB(sb), first_group + i));
+               if (buffer_uptodate(bh[i])) {
+                       /*
+                        * if not uninit if bh is uptodate,
+                        * bitmap is also uptodate
+                        */
+                       set_bitmap_uptodate(bh[i]);
+                       unlock_buffer(bh[i]);
+                       continue;
+               }
                get_bh(bh[i]);
+               /*
+                * submit the buffer_head for read. We can
+                * safely mark the bitmap as uptodate now.
+                * We do it here so the bitmap uptodate bit
+                * get set with buffer lock held.
+                */
+               set_bitmap_uptodate(bh[i]);
                bh[i]->b_end_io = end_buffer_read_sync;
                submit_bh(READ, bh[i]);
                mb_debug("read bitmap for group %u\n", first_group + i);
@@ -814,6 +846,8 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
 
        err = 0;
        first_block = page->index * blocks_per_page;
+       /* init the page  */
+       memset(page_address(page), 0xff, PAGE_CACHE_SIZE);
        for (i = 0; i < blocks_per_page; i++) {
                int group;
                struct ext4_group_info *grinfo;
@@ -840,7 +874,6 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
                        BUG_ON(incore == NULL);
                        mb_debug("put buddy for group %u in page %lu/%x\n",
                                group, page->index, i * blocksize);
-                       memset(data, 0xff, blocksize);
                        grinfo = ext4_get_group_info(sb, group);
                        grinfo->bb_fragments = 0;
                        memset(grinfo->bb_counters, 0,
@@ -848,7 +881,9 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
                        /*
                         * incore got set to the group block bitmap below
                         */
+                       ext4_lock_group(sb, group);
                        ext4_mb_generate_buddy(sb, data, incore, group);
+                       ext4_unlock_group(sb, group);
                        incore = NULL;
                } else {
                        /* this is block of bitmap */
@@ -862,6 +897,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
 
                        /* mark all preallocated blks used in in-core bitmap */
                        ext4_mb_generate_from_pa(sb, data, group);
+                       ext4_mb_generate_from_freelist(sb, data, group);
                        ext4_unlock_group(sb, group);
 
                        /* set incore so that the buddy information can be
@@ -1017,7 +1053,8 @@ static void ext4_mb_release_desc(struct ext4_buddy *e4b)
        if (e4b->bd_buddy_page)
                page_cache_release(e4b->bd_buddy_page);
        /* Done with the buddy cache */
-       up_read(e4b->alloc_semp);
+       if (e4b->alloc_semp)
+               up_read(e4b->alloc_semp);
 }
 
 
@@ -1055,7 +1092,10 @@ static void mb_clear_bits(spinlock_t *lock, void *bm, int cur, int len)
                        cur += 32;
                        continue;
                }
-               mb_clear_bit_atomic(lock, cur, bm);
+               if (lock)
+                       mb_clear_bit_atomic(lock, cur, bm);
+               else
+                       mb_clear_bit(cur, bm);
                cur++;
        }
 }
@@ -1073,15 +1113,16 @@ static void mb_set_bits(spinlock_t *lock, void *bm, int cur, int len)
                        cur += 32;
                        continue;
                }
-               mb_set_bit_atomic(lock, cur, bm);
+               if (lock)
+                       mb_set_bit_atomic(lock, cur, bm);
+               else
+                       mb_set_bit(cur, bm);
                cur++;
        }
 }
 
 static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
                          int first, int count)
-__releases(bitlock)
-__acquires(bitlock)
 {
        int block = 0;
        int max = 0;
@@ -1120,12 +1161,11 @@ __acquires(bitlock)
                        blocknr += block;
                        blocknr +=
                            le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
-                       ext4_unlock_group(sb, e4b->bd_group);
-                       ext4_error(sb, __func__, "double-free of inode"
+                       ext4_grp_locked_error(sb, e4b->bd_group,
+                                  __func__, "double-free of inode"
                                   " %lu's block %llu(bit %u in group %u)",
                                   inode ? inode->i_ino : 0, blocknr, block,
                                   e4b->bd_group);
-                       ext4_lock_group(sb, e4b->bd_group);
                }
                mb_clear_bit(block, EXT4_MB_BITMAP(e4b));
                e4b->bd_info->bb_counters[order]++;
@@ -1322,13 +1362,20 @@ static void ext4_mb_use_best_found(struct ext4_allocation_context *ac,
        ac->ac_tail = ret & 0xffff;
        ac->ac_buddy = ret >> 16;
 
-       /* XXXXXXX: SUCH A HORRIBLE **CK */
-       /*FIXME!! Why ? */
+       /*
+        * take the page reference. We want the page to be pinned
+        * so that we don't get a ext4_mb_init_cache_call for this
+        * group until we update the bitmap. That would mean we
+        * double allocate blocks. The reference is dropped
+        * in ext4_mb_release_context
+        */
        ac->ac_bitmap_page = e4b->bd_bitmap_page;
        get_page(ac->ac_bitmap_page);
        ac->ac_buddy_page = e4b->bd_buddy_page;
        get_page(ac->ac_buddy_page);
-
+       /* on allocation we use ac to track the held semaphore */
+       ac->alloc_semp =  e4b->alloc_semp;
+       e4b->alloc_semp = NULL;
        /* store last allocated for subsequent stream allocation */
        if ((ac->ac_flags & EXT4_MB_HINT_DATA)) {
                spin_lock(&sbi->s_md_lock);
@@ -1603,7 +1650,8 @@ static void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac,
                         * free blocks even though group info says we
                         * we have free blocks
                         */
-                       ext4_error(sb, __func__, "%d free blocks as per "
+                       ext4_grp_locked_error(sb, e4b->bd_group,
+                                       __func__, "%d free blocks as per "
                                        "group info. But bitmap says 0",
                                        free);
                        break;
@@ -1612,7 +1660,8 @@ static void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac,
                mb_find_extent(e4b, 0, i, ac->ac_g_ex.fe_len, &ex);
                BUG_ON(ex.fe_len <= 0);
                if (free < ex.fe_len) {
-                       ext4_error(sb, __func__, "%d free blocks as per "
+                       ext4_grp_locked_error(sb, e4b->bd_group,
+                                       __func__, "%d free blocks as per "
                                        "group info. But got %d blocks",
                                        free, ex.fe_len);
                        /*
@@ -1760,7 +1809,7 @@ int ext4_mb_get_buddy_cache_lock(struct super_block *sb, ext4_group_t group)
                 * no block allocation going on in any
                 * of that groups
                 */
-               down_write(&grp->alloc_sem);
+               down_write_nested(&grp->alloc_sem, i);
        }
        return i;
 }
@@ -2490,7 +2539,7 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
                        ext4_free_blocks_after_init(sb, group, desc);
        } else {
                meta_group_info[i]->bb_free =
-                       le16_to_cpu(desc->bg_free_blocks_count);
+                       ext4_free_blks_count(sb, desc);
        }
 
        INIT_LIST_HEAD(&meta_group_info[i]->bb_prealloc_list);
@@ -2829,8 +2878,9 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)
                discard_block = (ext4_fsblk_t) entry->group * EXT4_BLOCKS_PER_GROUP(sb)
                        + entry->start_blk
                        + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
-               trace_mark(ext4_discard_blocks, "dev %s blk %llu count %u", sb->s_id,
-                          (unsigned long long) discard_block, entry->count);
+               trace_mark(ext4_discard_blocks, "dev %s blk %llu count %u",
+                          sb->s_id, (unsigned long long) discard_block,
+                          entry->count);
                sb_issue_discard(sb, discard_block, entry->count);
 
                kmem_cache_free(ext4_free_ext_cachep, entry);
@@ -2975,7 +3025,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
                goto out_err;
 
        ext4_debug("using block group %u(%d)\n", ac->ac_b_ex.fe_group,
-                       gdp->bg_free_blocks_count);
+                       ext4_free_blks_count(sb, gdp));
 
        err = ext4_journal_get_write_access(handle, gdp_bh);
        if (err)
@@ -2993,8 +3043,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
            in_range(block + len - 1, ext4_inode_table(sb, gdp),
                     EXT4_SB(sb)->s_itb_per_group)) {
                ext4_error(sb, __func__,
-                          "Allocating block in system zone - block = %llu",
-                          block);
+                          "Allocating block %llu in system zone of %d group\n",
+                          block, ac->ac_b_ex.fe_group);
                /* File system mounted not to panic on error
                 * Fix the bitmap and repeat the block allocation
                 * We leak some of the blocks here.
@@ -3016,18 +3066,17 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
                }
        }
 #endif
-       mb_set_bits(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group), bitmap_bh->b_data,
-                               ac->ac_b_ex.fe_start, ac->ac_b_ex.fe_len);
-
        spin_lock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group));
+       mb_set_bits(NULL, bitmap_bh->b_data,
+                               ac->ac_b_ex.fe_start, ac->ac_b_ex.fe_len);
        if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
                gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
-               gdp->bg_free_blocks_count =
-                       cpu_to_le16(ext4_free_blocks_after_init(sb,
-                                               ac->ac_b_ex.fe_group,
-                                               gdp));
+               ext4_free_blks_set(sb, gdp,
+                                       ext4_free_blocks_after_init(sb,
+                                       ac->ac_b_ex.fe_group, gdp));
        }
-       le16_add_cpu(&gdp->bg_free_blocks_count, -ac->ac_b_ex.fe_len);
+       len = ext4_free_blks_count(sb, gdp) - ac->ac_b_ex.fe_len;
+       ext4_free_blks_set(sb, gdp, len);
        gdp->bg_checksum = ext4_group_desc_csum(sbi, ac->ac_b_ex.fe_group, gdp);
        spin_unlock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group));
        percpu_counter_sub(&sbi->s_freeblocks_counter, ac->ac_b_ex.fe_len);
@@ -3456,6 +3505,32 @@ ext4_mb_use_preallocated(struct ext4_allocation_context *ac)
        return 0;
 }
 
+/*
+ * the function goes through all block freed in the group
+ * but not yet committed and marks them used in in-core bitmap.
+ * buddy must be generated from this bitmap
+ * Need to be called with ext4 group lock (ext4_lock_group)
+ */
+static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap,
+                                               ext4_group_t group)
+{
+       struct rb_node *n;
+       struct ext4_group_info *grp;
+       struct ext4_free_data *entry;
+
+       grp = ext4_get_group_info(sb, group);
+       n = rb_first(&(grp->bb_free_root));
+
+       while (n) {
+               entry = rb_entry(n, struct ext4_free_data, node);
+               mb_set_bits(sb_bgl_lock(EXT4_SB(sb), group),
+                               bitmap, entry->start_blk,
+                               entry->count);
+               n = rb_next(n);
+       }
+       return;
+}
+
 /*
  * the function goes through all preallocation in this group and marks them
  * used in in-core bitmap. buddy must be generated from this bitmap
@@ -3618,11 +3693,17 @@ ext4_mb_new_inode_pa(struct ext4_allocation_context *ac)
        pa->pa_free = pa->pa_len;
        atomic_set(&pa->pa_count, 1);
        spin_lock_init(&pa->pa_lock);
+       INIT_LIST_HEAD(&pa->pa_inode_list);
+       INIT_LIST_HEAD(&pa->pa_group_list);
        pa->pa_deleted = 0;
        pa->pa_linear = 0;
 
        mb_debug("new inode pa %p: %llu/%u for %u\n", pa,
                        pa->pa_pstart, pa->pa_len, pa->pa_lstart);
+       trace_mark(ext4_mb_new_inode_pa,
+                  "dev %s ino %lu pstart %llu len %u lstart %u",
+                  sb->s_id, ac->ac_inode->i_ino,
+                  pa->pa_pstart, pa->pa_len, pa->pa_lstart);
 
        ext4_mb_use_inode_pa(ac, pa);
        atomic_add(pa->pa_free, &EXT4_SB(sb)->s_mb_preallocated);
@@ -3676,11 +3757,14 @@ ext4_mb_new_group_pa(struct ext4_allocation_context *ac)
        atomic_set(&pa->pa_count, 1);
        spin_lock_init(&pa->pa_lock);
        INIT_LIST_HEAD(&pa->pa_inode_list);
+       INIT_LIST_HEAD(&pa->pa_group_list);
        pa->pa_deleted = 0;
        pa->pa_linear = 1;
 
        mb_debug("new group pa %p: %llu/%u for %u\n", pa,
-                       pa->pa_pstart, pa->pa_len, pa->pa_lstart);
+                pa->pa_pstart, pa->pa_len, pa->pa_lstart);
+       trace_mark(ext4_mb_new_group_pa, "dev %s pstart %llu len %u lstart %u",
+                  sb->s_id, pa->pa_pstart, pa->pa_len, pa->pa_lstart);
 
        ext4_mb_use_group_pa(ac, pa);
        atomic_add(pa->pa_free, &EXT4_SB(sb)->s_mb_preallocated);
@@ -3733,12 +3817,14 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
        unsigned int next;
        ext4_group_t group;
        ext4_grpblk_t bit;
+       unsigned long long grp_blk_start;
        sector_t start;
        int err = 0;
        int free = 0;
 
        BUG_ON(pa->pa_deleted == 0);
        ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, &bit);
+       grp_blk_start = pa->pa_pstart - bit;
        BUG_ON(group != e4b->bd_group && pa->pa_len != 0);
        end = bit + pa->pa_len;
 
@@ -3768,6 +3854,10 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
                        ext4_mb_store_history(ac);
                }
 
+               trace_mark(ext4_mb_release_inode_pa,
+                          "dev %s ino %lu block %llu count %u",
+                          sb->s_id, pa->pa_inode->i_ino, grp_blk_start + bit,
+                          next - bit);
                mb_free_blocks(pa->pa_inode, e4b, bit, next - bit);
                bit = next + 1;
        }
@@ -3776,8 +3866,9 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
                        pa, (unsigned long) pa->pa_lstart,
                        (unsigned long) pa->pa_pstart,
                        (unsigned long) pa->pa_len);
-               ext4_error(sb, __func__, "free %u, pa_free %u",
-                                               free, pa->pa_free);
+               ext4_grp_locked_error(sb, group,
+                                       __func__, "free %u, pa_free %u",
+                                       free, pa->pa_free);
                /*
                 * pa is already deleted so we use the value obtained
                 * from the bitmap and continue.
@@ -3800,6 +3891,8 @@ ext4_mb_release_group_pa(struct ext4_buddy *e4b,
        if (ac)
                ac->ac_op = EXT4_MB_HISTORY_DISCARD;
 
+       trace_mark(ext4_mb_release_group_pa, "dev %s pstart %llu len %d",
+                  sb->s_id, pa->pa_pstart, pa->pa_len);
        BUG_ON(pa->pa_deleted == 0);
        ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, &bit);
        BUG_ON(group != e4b->bd_group && pa->pa_len != 0);
@@ -3965,6 +4058,8 @@ void ext4_discard_preallocations(struct inode *inode)
        }
 
        mb_debug("discard preallocation for inode %lu\n", inode->i_ino);
+       trace_mark(ext4_discard_preallocations, "dev %s ino %lu", sb->s_id,
+                  inode->i_ino);
 
        INIT_LIST_HEAD(&list);
 
@@ -4218,6 +4313,7 @@ ext4_mb_initialize_context(struct ext4_allocation_context *ac,
        ac->ac_pa = NULL;
        ac->ac_bitmap_page = NULL;
        ac->ac_buddy_page = NULL;
+       ac->alloc_semp = NULL;
        ac->ac_lg = NULL;
 
        /* we have to define context: we'll we work with a file or
@@ -4383,18 +4479,23 @@ static int ext4_mb_release_context(struct ext4_allocation_context *ac)
                        pa->pa_free -= ac->ac_b_ex.fe_len;
                        pa->pa_len -= ac->ac_b_ex.fe_len;
                        spin_unlock(&pa->pa_lock);
-                       /*
-                        * We want to add the pa to the right bucket.
-                        * Remove it from the list and while adding
-                        * make sure the list to which we are adding
-                        * doesn't grow big.
-                        */
-                       if (likely(pa->pa_free)) {
-                               spin_lock(pa->pa_obj_lock);
-                               list_del_rcu(&pa->pa_inode_list);
-                               spin_unlock(pa->pa_obj_lock);
-                               ext4_mb_add_n_trim(ac);
-                       }
+               }
+       }
+       if (ac->alloc_semp)
+               up_read(ac->alloc_semp);
+       if (pa) {
+               /*
+                * We want to add the pa to the right bucket.
+                * Remove it from the list and while adding
+                * make sure the list to which we are adding
+                * doesn't grow big.  We need to release
+                * alloc_semp before calling ext4_mb_add_n_trim()
+                */
+               if (pa->pa_linear && likely(pa->pa_free)) {
+                       spin_lock(pa->pa_obj_lock);
+                       list_del_rcu(&pa->pa_inode_list);
+                       spin_unlock(pa->pa_obj_lock);
+                       ext4_mb_add_n_trim(ac);
                }
                ext4_mb_put_pa(ac, ac->ac_sb, pa);
        }
@@ -4414,6 +4515,8 @@ static int ext4_mb_discard_preallocations(struct super_block *sb, int needed)
        int ret;
        int freed = 0;
 
+       trace_mark(ext4_mb_discard_preallocations, "dev %s needed %d",
+                  sb->s_id, needed);
        for (i = 0; i < EXT4_SB(sb)->s_groups_count && needed > 0; i++) {
                ret = ext4_mb_discard_group_preallocations(sb, i, needed);
                freed += ret;
@@ -4442,6 +4545,18 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
        sb = ar->inode->i_sb;
        sbi = EXT4_SB(sb);
 
+       trace_mark(ext4_request_blocks, "dev %s flags %u len %u ino %lu "
+                  "lblk %llu goal %llu lleft %llu lright %llu "
+                  "pleft %llu pright %llu ",
+                  sb->s_id, ar->flags, ar->len,
+                  ar->inode ? ar->inode->i_ino : 0,
+                  (unsigned long long) ar->logical,
+                  (unsigned long long) ar->goal,
+                  (unsigned long long) ar->lleft,
+                  (unsigned long long) ar->lright,
+                  (unsigned long long) ar->pleft,
+                  (unsigned long long) ar->pright);
+
        if (!EXT4_I(ar->inode)->i_delalloc_reserved_flag) {
                /*
                 * With delalloc we already reserved the blocks
@@ -4463,7 +4578,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
        }
        if (ar->len == 0) {
                *errp = -EDQUOT;
-               return 0;
+               goto out3;
        }
        inquota = ar->len;
 
@@ -4498,10 +4613,14 @@ repeat:
                                ac->ac_o_ex.fe_len < ac->ac_b_ex.fe_len)
                        ext4_mb_new_preallocation(ac);
        }
-
        if (likely(ac->ac_status == AC_STATUS_FOUND)) {
                *errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_blks);
                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;
@@ -4532,6 +4651,26 @@ out2:
 out1:
        if (ar->len < inquota)
                DQUOT_FREE_BLOCK(ar->inode, inquota - ar->len);
+out3:
+       if (!ar->len) {
+               if (!EXT4_I(ar->inode)->i_delalloc_reserved_flag)
+                       /* release all the reserved blocks if non delalloc */
+                       percpu_counter_sub(&sbi->s_dirtyblocks_counter,
+                                               reserv_blks);
+       }
+
+       trace_mark(ext4_allocate_blocks,
+                  "dev %s block %llu flags %u len %u ino %lu "
+                  "logical %llu goal %llu lleft %llu lright %llu "
+                  "pleft %llu pright %llu ",
+                  sb->s_id, (unsigned long long) block,
+                  ar->flags, ar->len, ar->inode ? ar->inode->i_ino : 0,
+                  (unsigned long long) ar->logical,
+                  (unsigned long long) ar->goal,
+                  (unsigned long long) ar->lleft,
+                  (unsigned long long) ar->lright,
+                  (unsigned long long) ar->pleft,
+                  (unsigned long long) ar->pright);
 
        return block;
 }
@@ -4553,12 +4692,13 @@ static int can_merge(struct ext4_free_data *entry1,
 
 static noinline_for_stack int
 ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
-                         ext4_group_t group, ext4_grpblk_t block, int count)
+                     struct ext4_free_data *new_entry)
 {
+       ext4_grpblk_t block;
+       struct ext4_free_data *entry;
        struct ext4_group_info *db = e4b->bd_info;
        struct super_block *sb = e4b->bd_sb;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
-       struct ext4_free_data *entry, *new_entry;
        struct rb_node **n = &db->bb_free_root.rb_node, *node;
        struct rb_node *parent = NULL, *new_node;
 
@@ -4566,14 +4706,9 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
        BUG_ON(e4b->bd_bitmap_page == NULL);
        BUG_ON(e4b->bd_buddy_page == NULL);
 
-       new_entry  = kmem_cache_alloc(ext4_free_ext_cachep, GFP_NOFS);
-       new_entry->start_blk = block;
-       new_entry->group  = group;
-       new_entry->count = count;
-       new_entry->t_tid = handle->h_transaction->t_tid;
        new_node = &new_entry->node;
+       block = new_entry->start_blk;
 
-       ext4_lock_group(sb, group);
        if (!*n) {
                /* first free block exent. We need to
                   protect buddy cache from being freed,
@@ -4591,10 +4726,9 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
                else if (block >= (entry->start_blk + entry->count))
                        n = &(*n)->rb_right;
                else {
-                       ext4_unlock_group(sb, group);
-                       ext4_error(sb, __func__,
-                           "Double free of blocks %d (%d %d)",
-                           block, entry->start_blk, entry->count);
+                       ext4_grp_locked_error(sb, e4b->bd_group, __func__,
+                                       "Double free of blocks %d (%d %d)",
+                                       block, entry->start_blk, entry->count);
                        return 0;
                }
        }
@@ -4633,7 +4767,6 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
        spin_lock(&sbi->s_md_lock);
        list_add(&new_entry->list, &handle->h_transaction->t_private_list);
        spin_unlock(&sbi->s_md_lock);
-       ext4_unlock_group(sb, group);
        return 0;
 }
 
@@ -4672,6 +4805,10 @@ void ext4_mb_free_blocks(handle_t *handle, struct inode *inode,
        }
 
        ext4_debug("freeing block %lu\n", block);
+       trace_mark(ext4_free_blocks,
+                  "dev %s block %llu count %lu metadata %d ino %lu",
+                  sb->s_id, (unsigned long long) block, count, metadata,
+                  inode ? inode->i_ino : 0);
 
        ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);
        if (ac) {
@@ -4738,15 +4875,6 @@ do_more:
                        BUG_ON(!mb_test_bit(bit + i, bitmap_bh->b_data));
        }
 #endif
-       mb_clear_bits(sb_bgl_lock(sbi, block_group), bitmap_bh->b_data,
-                       bit, count);
-
-       /* We dirtied the bitmap block */
-       BUFFER_TRACE(bitmap_bh, "dirtied bitmap block");
-       err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
-       if (err)
-               goto error_return;
-
        if (ac) {
                ac->ac_b_ex.fe_group = block_group;
                ac->ac_b_ex.fe_start = bit;
@@ -4758,18 +4886,37 @@ do_more:
        if (err)
                goto error_return;
        if (metadata && ext4_handle_valid(handle)) {
-               /* blocks being freed are metadata. these blocks shouldn't
-                * be used until this transaction is committed */
-               ext4_mb_free_metadata(handle, &e4b, block_group, bit, count);
+               struct ext4_free_data *new_entry;
+               /*
+                * blocks being freed are metadata. these blocks shouldn't
+                * be used until this transaction is committed
+                */
+               new_entry  = kmem_cache_alloc(ext4_free_ext_cachep, GFP_NOFS);
+               new_entry->start_blk = bit;
+               new_entry->group  = block_group;
+               new_entry->count = count;
+               new_entry->t_tid = handle->h_transaction->t_tid;
+               ext4_lock_group(sb, block_group);
+               mb_clear_bits(sb_bgl_lock(sbi, block_group), bitmap_bh->b_data,
+                               bit, count);
+               ext4_mb_free_metadata(handle, &e4b, new_entry);
+               ext4_unlock_group(sb, block_group);
        } else {
                ext4_lock_group(sb, block_group);
+               /* need to update group_info->bb_free and bitmap
+                * with group lock held. generate_buddy look at
+                * them with group lock_held
+                */
+               mb_clear_bits(sb_bgl_lock(sbi, block_group), bitmap_bh->b_data,
+                               bit, count);
                mb_free_blocks(inode, &e4b, bit, count);
                ext4_mb_return_to_preallocation(inode, &e4b, block, count);
                ext4_unlock_group(sb, block_group);
        }
 
        spin_lock(sb_bgl_lock(sbi, block_group));
-       le16_add_cpu(&gdp->bg_free_blocks_count, count);
+       ret = ext4_free_blks_count(sb, gdp) + count;
+       ext4_free_blks_set(sb, gdp, ret);
        gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp);
        spin_unlock(sb_bgl_lock(sbi, block_group));
        percpu_counter_add(&sbi->s_freeblocks_counter, count);
@@ -4785,6 +4932,10 @@ do_more:
 
        *freed += count;
 
+       /* We dirtied the bitmap block */
+       BUFFER_TRACE(bitmap_bh, "dirtied bitmap block");
+       err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
+
        /* And the group descriptor block */
        BUFFER_TRACE(gd_bh, "dirtied group descriptor block");
        ret = ext4_handle_dirty_metadata(handle, NULL, gd_bh);