NSM: Remove !nsm check from nsm_release()
[safe/jmp/linux-2.6] / fs / ext4 / mballoc.c
index 21ee6d4..444ad99 100644 (file)
@@ -477,9 +477,10 @@ static void mb_cmp_bitmaps(struct ext4_buddy *e4b, void *bitmap)
                b2 = (unsigned char *) bitmap;
                for (i = 0; i < e4b->bd_sb->s_blocksize; i++) {
                        if (b1[i] != b2[i]) {
-                               printk("corruption in group %lu at byte %u(%u):"
-                                      " %x in copy != %x on disk/prealloc\n",
-                                       e4b->bd_group, i, i * 8, b1[i], b2[i]);
+                               printk(KERN_ERR "corruption in group %lu "
+                                      "at byte %u(%u): %x in copy != %x "
+                                      "on disk/prealloc\n",
+                                      e4b->bd_group, i, i * 8, b1[i], b2[i]);
                                BUG();
                        }
                }
@@ -533,9 +534,6 @@ static int __mb_check_buddy(struct ext4_buddy *e4b, char *file,
        void *buddy;
        void *buddy2;
 
-       if (!test_opt(sb, MBALLOC))
-               return 0;
-
        {
                static int mb_check_counter;
                if (mb_check_counter++ % 100 != 0)
@@ -784,16 +782,21 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
                if (bh[i] == NULL)
                        goto out;
 
-               if (bh_uptodate_or_lock(bh[i]))
+               if (buffer_uptodate(bh[i]) &&
+                   !(desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)))
                        continue;
 
+               lock_buffer(bh[i]);
+               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_buffer_uptodate(bh[i]);
                        unlock_buffer(bh[i]);
+                       spin_unlock(sb_bgl_lock(EXT4_SB(sb), first_group + i));
                        continue;
                }
+               spin_unlock(sb_bgl_lock(EXT4_SB(sb), first_group + i));
                get_bh(bh[i]);
                bh[i]->b_end_io = end_buffer_read_sync;
                submit_bh(READ, bh[i]);
@@ -1051,7 +1054,7 @@ static void mb_set_bits(spinlock_t *lock, void *bm, int cur, int len)
        }
 }
 
-static int mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
+static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
                          int first, int count)
 {
        int block = 0;
@@ -1091,11 +1094,12 @@ static int mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
                        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"
                                   " %lu's block %llu(bit %u in group %lu)\n",
                                   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]++;
@@ -1133,8 +1137,6 @@ static int mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
                } while (1);
        }
        mb_check_buddy(e4b);
-
-       return 0;
 }
 
 static int mb_find_extent(struct ext4_buddy *e4b, int order, int block,
@@ -2167,9 +2169,10 @@ static void ext4_mb_history_release(struct super_block *sb)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
 
-       remove_proc_entry("mb_groups", sbi->s_mb_proc);
-       remove_proc_entry("mb_history", sbi->s_mb_proc);
-
+       if (sbi->s_proc != NULL) {
+               remove_proc_entry("mb_groups", sbi->s_proc);
+               remove_proc_entry("mb_history", sbi->s_proc);
+       }
        kfree(sbi->s_mb_history);
 }
 
@@ -2178,10 +2181,10 @@ static void ext4_mb_history_init(struct super_block *sb)
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        int i;
 
-       if (sbi->s_mb_proc != NULL) {
-               proc_create_data("mb_history", S_IRUGO, sbi->s_mb_proc,
+       if (sbi->s_proc != NULL) {
+               proc_create_data("mb_history", S_IRUGO, sbi->s_proc,
                                 &ext4_mb_seq_history_fops, sb);
-               proc_create_data("mb_groups", S_IRUGO, sbi->s_mb_proc,
+               proc_create_data("mb_groups", S_IRUGO, sbi->s_proc,
                                 &ext4_mb_seq_groups_fops, sb);
        }
 
@@ -2237,21 +2240,193 @@ ext4_mb_store_history(struct ext4_allocation_context *ac)
 #define ext4_mb_history_init(sb)
 #endif
 
+
+/* Create and initialize ext4_group_info data for the given group. */
+int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
+                         struct ext4_group_desc *desc)
+{
+       int i, len;
+       int metalen = 0;
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       struct ext4_group_info **meta_group_info;
+
+       /*
+        * First check if this group is the first of a reserved block.
+        * If it's true, we have to allocate a new table of pointers
+        * to ext4_group_info structures
+        */
+       if (group % EXT4_DESC_PER_BLOCK(sb) == 0) {
+               metalen = sizeof(*meta_group_info) <<
+                       EXT4_DESC_PER_BLOCK_BITS(sb);
+               meta_group_info = kmalloc(metalen, GFP_KERNEL);
+               if (meta_group_info == NULL) {
+                       printk(KERN_ERR "EXT4-fs: can't allocate mem for a "
+                              "buddy group\n");
+                       goto exit_meta_group_info;
+               }
+               sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)] =
+                       meta_group_info;
+       }
+
+       /*
+        * calculate needed size. if change bb_counters size,
+        * don't forget about ext4_mb_generate_buddy()
+        */
+       len = offsetof(typeof(**meta_group_info),
+                      bb_counters[sb->s_blocksize_bits + 2]);
+
+       meta_group_info =
+               sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)];
+       i = group & (EXT4_DESC_PER_BLOCK(sb) - 1);
+
+       meta_group_info[i] = kzalloc(len, GFP_KERNEL);
+       if (meta_group_info[i] == NULL) {
+               printk(KERN_ERR "EXT4-fs: can't allocate buddy mem\n");
+               goto exit_group_info;
+       }
+       set_bit(EXT4_GROUP_INFO_NEED_INIT_BIT,
+               &(meta_group_info[i]->bb_state));
+
+       /*
+        * initialize bb_free to be able to skip
+        * empty groups without initialization
+        */
+       if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
+               meta_group_info[i]->bb_free =
+                       ext4_free_blocks_after_init(sb, group, desc);
+       } else {
+               meta_group_info[i]->bb_free =
+                       le16_to_cpu(desc->bg_free_blocks_count);
+       }
+
+       INIT_LIST_HEAD(&meta_group_info[i]->bb_prealloc_list);
+       meta_group_info[i]->bb_free_root.rb_node = NULL;;
+
+#ifdef DOUBLE_CHECK
+       {
+               struct buffer_head *bh;
+               meta_group_info[i]->bb_bitmap =
+                       kmalloc(sb->s_blocksize, GFP_KERNEL);
+               BUG_ON(meta_group_info[i]->bb_bitmap == NULL);
+               bh = ext4_read_block_bitmap(sb, group);
+               BUG_ON(bh == NULL);
+               memcpy(meta_group_info[i]->bb_bitmap, bh->b_data,
+                       sb->s_blocksize);
+               put_bh(bh);
+       }
+#endif
+
+       return 0;
+
+exit_group_info:
+       /* If a meta_group_info table has been allocated, release it now */
+       if (group % EXT4_DESC_PER_BLOCK(sb) == 0)
+               kfree(sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)]);
+exit_meta_group_info:
+       return -ENOMEM;
+} /* ext4_mb_add_groupinfo */
+
+/*
+ * Add a group to the existing groups.
+ * This function is used for online resize
+ */
+int ext4_mb_add_more_groupinfo(struct super_block *sb, ext4_group_t group,
+                              struct ext4_group_desc *desc)
+{
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       struct inode *inode = sbi->s_buddy_cache;
+       int blocks_per_page;
+       int block;
+       int pnum;
+       struct page *page;
+       int err;
+
+       /* Add group based on group descriptor*/
+       err = ext4_mb_add_groupinfo(sb, group, desc);
+       if (err)
+               return err;
+
+       /*
+        * Cache pages containing dynamic mb_alloc datas (buddy and bitmap
+        * datas) are set not up to date so that they will be re-initilaized
+        * during the next call to ext4_mb_load_buddy
+        */
+
+       /* Set buddy page as not up to date */
+       blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize;
+       block = group * 2;
+       pnum = block / blocks_per_page;
+       page = find_get_page(inode->i_mapping, pnum);
+       if (page != NULL) {
+               ClearPageUptodate(page);
+               page_cache_release(page);
+       }
+
+       /* Set bitmap page as not up to date */
+       block++;
+       pnum = block / blocks_per_page;
+       page = find_get_page(inode->i_mapping, pnum);
+       if (page != NULL) {
+               ClearPageUptodate(page);
+               page_cache_release(page);
+       }
+
+       return 0;
+}
+
+/*
+ * Update an existing group.
+ * This function is used for online resize
+ */
+void ext4_mb_update_group_info(struct ext4_group_info *grp, ext4_grpblk_t add)
+{
+       grp->bb_free += add;
+}
+
 static int ext4_mb_init_backend(struct super_block *sb)
 {
        ext4_group_t i;
-       int j, len, metalen;
+       int metalen;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
-       int num_meta_group_infos =
-               (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) >>
-                       EXT4_DESC_PER_BLOCK_BITS(sb);
+       struct ext4_super_block *es = sbi->s_es;
+       int num_meta_group_infos;
+       int num_meta_group_infos_max;
+       int array_size;
        struct ext4_group_info **meta_group_info;
+       struct ext4_group_desc *desc;
+
+       /* This is the number of blocks used by GDT */
+       num_meta_group_infos = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) -
+                               1) >> EXT4_DESC_PER_BLOCK_BITS(sb);
+
+       /*
+        * This is the total number of blocks used by GDT including
+        * the number of reserved blocks for GDT.
+        * The s_group_info array is allocated with this value
+        * to allow a clean online resize without a complex
+        * manipulation of pointer.
+        * The drawback is the unused memory when no resize
+        * occurs but it's very low in terms of pages
+        * (see comments below)
+        * Need to handle this properly when META_BG resizing is allowed
+        */
+       num_meta_group_infos_max = num_meta_group_infos +
+                               le16_to_cpu(es->s_reserved_gdt_blocks);
 
+       /*
+        * array_size is the size of s_group_info array. We round it
+        * to the next power of two because this approximation is done
+        * internally by kmalloc so we can have some more memory
+        * for free here (e.g. may be used for META_BG resize).
+        */
+       array_size = 1;
+       while (array_size < sizeof(*sbi->s_group_info) *
+              num_meta_group_infos_max)
+               array_size = array_size << 1;
        /* An 8TB filesystem with 64-bit pointers requires a 4096 byte
         * kmalloc. A 128kb malloc should suffice for a 256TB filesystem.
         * So a two level scheme suffices for now. */
-       sbi->s_group_info = kmalloc(sizeof(*sbi->s_group_info) *
-                                   num_meta_group_infos, GFP_KERNEL);
+       sbi->s_group_info = kmalloc(array_size, GFP_KERNEL);
        if (sbi->s_group_info == NULL) {
                printk(KERN_ERR "EXT4-fs: can't allocate buddy meta group\n");
                return -ENOMEM;
@@ -2278,62 +2453,15 @@ static int ext4_mb_init_backend(struct super_block *sb)
                sbi->s_group_info[i] = meta_group_info;
        }
 
-       /*
-        * calculate needed size. if change bb_counters size,
-        * don't forget about ext4_mb_generate_buddy()
-        */
-       len = sizeof(struct ext4_group_info);
-       len += sizeof(unsigned short) * (sb->s_blocksize_bits + 2);
        for (i = 0; i < sbi->s_groups_count; i++) {
-               struct ext4_group_desc *desc;
-
-               meta_group_info =
-                       sbi->s_group_info[i >> EXT4_DESC_PER_BLOCK_BITS(sb)];
-               j = i & (EXT4_DESC_PER_BLOCK(sb) - 1);
-
-               meta_group_info[j] = kzalloc(len, GFP_KERNEL);
-               if (meta_group_info[j] == NULL) {
-                       printk(KERN_ERR "EXT4-fs: can't allocate buddy mem\n");
-                       goto err_freebuddy;
-               }
                desc = ext4_get_group_desc(sb, i, NULL);
                if (desc == NULL) {
                        printk(KERN_ERR
                                "EXT4-fs: can't read descriptor %lu\n", i);
-                       i++;
                        goto err_freebuddy;
                }
-               set_bit(EXT4_GROUP_INFO_NEED_INIT_BIT,
-                       &(meta_group_info[j]->bb_state));
-
-               /*
-                * initialize bb_free to be able to skip
-                * empty groups without initialization
-                */
-               if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
-                       meta_group_info[j]->bb_free =
-                               ext4_free_blocks_after_init(sb, i, desc);
-               } else {
-                       meta_group_info[j]->bb_free =
-                               le16_to_cpu(desc->bg_free_blocks_count);
-               }
-
-               INIT_LIST_HEAD(&meta_group_info[j]->bb_prealloc_list);
-
-#ifdef DOUBLE_CHECK
-               {
-                       struct buffer_head *bh;
-                       meta_group_info[j]->bb_bitmap =
-                               kmalloc(sb->s_blocksize, GFP_KERNEL);
-                       BUG_ON(meta_group_info[j]->bb_bitmap == NULL);
-                       bh = ext4_read_block_bitmap(sb, i);
-                       BUG_ON(bh == NULL);
-                       memcpy(meta_group_info[j]->bb_bitmap, bh->b_data,
-                                       sb->s_blocksize);
-                       put_bh(bh);
-               }
-#endif
-
+               if (ext4_mb_add_groupinfo(sb, i, desc) != 0)
+                       goto err_freebuddy;
        }
 
        return 0;
@@ -2354,24 +2482,19 @@ err_freesgi:
 int ext4_mb_init(struct super_block *sb, int needs_recovery)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
-       unsigned i;
+       unsigned i, j;
        unsigned offset;
        unsigned max;
        int ret;
 
-       if (!test_opt(sb, MBALLOC))
-               return 0;
-
        i = (sb->s_blocksize_bits + 2) * sizeof(unsigned short);
 
        sbi->s_mb_offsets = kmalloc(i, GFP_KERNEL);
        if (sbi->s_mb_offsets == NULL) {
-               clear_opt(sbi->s_mount_opt, MBALLOC);
                return -ENOMEM;
        }
        sbi->s_mb_maxs = kmalloc(i, GFP_KERNEL);
        if (sbi->s_mb_maxs == NULL) {
-               clear_opt(sbi->s_mount_opt, MBALLOC);
                kfree(sbi->s_mb_maxs);
                return -ENOMEM;
        }
@@ -2394,16 +2517,12 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
        /* init file for buddy data */
        ret = ext4_mb_init_backend(sb);
        if (ret != 0) {
-               clear_opt(sbi->s_mount_opt, MBALLOC);
                kfree(sbi->s_mb_offsets);
                kfree(sbi->s_mb_maxs);
                return ret;
        }
 
        spin_lock_init(&sbi->s_md_lock);
-       INIT_LIST_HEAD(&sbi->s_active_transaction);
-       INIT_LIST_HEAD(&sbi->s_closed_transaction);
-       INIT_LIST_HEAD(&sbi->s_committed_transaction);
        spin_lock_init(&sbi->s_bal_lock);
 
        sbi->s_mb_max_to_scan = MB_DEFAULT_MAX_TO_SCAN;
@@ -2414,26 +2533,27 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
        sbi->s_mb_history_filter = EXT4_MB_HISTORY_DEFAULT;
        sbi->s_mb_group_prealloc = MB_DEFAULT_GROUP_PREALLOC;
 
-       i = sizeof(struct ext4_locality_group) * NR_CPUS;
-       sbi->s_locality_groups = kmalloc(i, GFP_KERNEL);
+       sbi->s_locality_groups = alloc_percpu(struct ext4_locality_group);
        if (sbi->s_locality_groups == NULL) {
-               clear_opt(sbi->s_mount_opt, MBALLOC);
                kfree(sbi->s_mb_offsets);
                kfree(sbi->s_mb_maxs);
                return -ENOMEM;
        }
-       for (i = 0; i < NR_CPUS; i++) {
+       for_each_possible_cpu(i) {
                struct ext4_locality_group *lg;
-               lg = &sbi->s_locality_groups[i];
+               lg = per_cpu_ptr(sbi->s_locality_groups, i);
                mutex_init(&lg->lg_mutex);
-               INIT_LIST_HEAD(&lg->lg_prealloc_list);
+               for (j = 0; j < PREALLOC_TB_SIZE; j++)
+                       INIT_LIST_HEAD(&lg->lg_prealloc_list[j]);
                spin_lock_init(&lg->lg_prealloc_lock);
        }
 
        ext4_mb_init_per_dev_proc(sb);
        ext4_mb_history_init(sb);
 
-       printk("EXT4-fs: mballoc enabled\n");
+       sbi->s_journal->j_commit_callback = release_blocks_on_commit;
+
+       printk(KERN_INFO "EXT4-fs: mballoc enabled\n");
        return 0;
 }
 
@@ -2448,7 +2568,7 @@ static void ext4_mb_cleanup_pa(struct ext4_group_info *grp)
                pa = list_entry(cur, struct ext4_prealloc_space, pa_group_list);
                list_del(&pa->pa_group_list);
                count++;
-               kfree(pa);
+               kmem_cache_free(ext4_pspace_cachep, pa);
        }
        if (count)
                mb_debug("mballoc: %u PAs left\n", count);
@@ -2462,18 +2582,6 @@ int ext4_mb_release(struct super_block *sb)
        struct ext4_group_info *grinfo;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
 
-       if (!test_opt(sb, MBALLOC))
-               return 0;
-
-       /* release freed, non-committed blocks */
-       spin_lock(&sbi->s_md_lock);
-       list_splice_init(&sbi->s_closed_transaction,
-                       &sbi->s_committed_transaction);
-       list_splice_init(&sbi->s_active_transaction,
-                       &sbi->s_committed_transaction);
-       spin_unlock(&sbi->s_md_lock);
-       ext4_mb_free_committed_blocks(sb);
-
        if (sbi->s_group_info) {
                for (i = 0; i < sbi->s_groups_count; i++) {
                        grinfo = ext4_get_group_info(sb, i);
@@ -2520,70 +2628,64 @@ int ext4_mb_release(struct super_block *sb)
                                atomic_read(&sbi->s_mb_discarded));
        }
 
-       kfree(sbi->s_locality_groups);
-
+       free_percpu(sbi->s_locality_groups);
        ext4_mb_history_release(sb);
        ext4_mb_destroy_per_dev_proc(sb);
 
        return 0;
 }
 
-static noinline_for_stack void
-ext4_mb_free_committed_blocks(struct super_block *sb)
+/*
+ * This function is called by the jbd2 layer once the commit has finished,
+ * so we know we can free the blocks that were released with that commit.
+ */
+static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)
 {
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
-       int err;
-       int i;
-       int count = 0;
-       int count2 = 0;
-       struct ext4_free_metadata *md;
+       struct super_block *sb = journal->j_private;
        struct ext4_buddy e4b;
+       struct ext4_group_info *db;
+       int err, count = 0, count2 = 0;
+       struct ext4_free_data *entry;
+       ext4_fsblk_t discard_block;
+       struct list_head *l, *ltmp;
 
-       if (list_empty(&sbi->s_committed_transaction))
-               return;
-
-       /* there is committed blocks to be freed yet */
-       do {
-               /* get next array of blocks */
-               md = NULL;
-               spin_lock(&sbi->s_md_lock);
-               if (!list_empty(&sbi->s_committed_transaction)) {
-                       md = list_entry(sbi->s_committed_transaction.next,
-                                       struct ext4_free_metadata, list);
-                       list_del(&md->list);
-               }
-               spin_unlock(&sbi->s_md_lock);
-
-               if (md == NULL)
-                       break;
+       list_for_each_safe(l, ltmp, &txn->t_private_list) {
+               entry = list_entry(l, struct ext4_free_data, list);
 
                mb_debug("gonna free %u blocks in group %lu (0x%p):",
-                               md->num, md->group, md);
+                        entry->count, entry->group, entry);
 
-               err = ext4_mb_load_buddy(sb, md->group, &e4b);
+               err = ext4_mb_load_buddy(sb, entry->group, &e4b);
                /* we expect to find existing buddy because it's pinned */
                BUG_ON(err != 0);
 
+               db = e4b.bd_info;
                /* there are blocks to put in buddy to make them really free */
-               count += md->num;
+               count += entry->count;
                count2++;
-               ext4_lock_group(sb, md->group);
-               for (i = 0; i < md->num; i++) {
-                       mb_debug(" %u", md->blocks[i]);
-                       err = mb_free_blocks(NULL, &e4b, md->blocks[i], 1);
-                       BUG_ON(err != 0);
+               ext4_lock_group(sb, entry->group);
+               /* Take it out of per group rb tree */
+               rb_erase(&entry->node, &(db->bb_free_root));
+               mb_free_blocks(NULL, &e4b, entry->start_blk, entry->count);
+
+               if (!db->bb_free_root.rb_node) {
+                       /* No more items in the per group rb tree
+                        * balance refcounts from ext4_mb_free_metadata()
+                        */
+                       page_cache_release(e4b.bd_buddy_page);
+                       page_cache_release(e4b.bd_bitmap_page);
                }
-               mb_debug("\n");
-               ext4_unlock_group(sb, md->group);
-
-               /* balance refcounts from ext4_mb_free_metadata() */
-               page_cache_release(e4b.bd_buddy_page);
-               page_cache_release(e4b.bd_bitmap_page);
-
-               kfree(md);
+               ext4_unlock_group(sb, entry->group);
+               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);
+               sb_issue_discard(sb, discard_block, entry->count);
+
+               kmem_cache_free(ext4_free_ext_cachep, entry);
                ext4_mb_release_desc(&e4b);
-
-       } while (md);
+       }
 
        mb_debug("freed %u blocks in %u structures\n", count, count2);
 }
@@ -2595,115 +2697,52 @@ ext4_mb_free_committed_blocks(struct super_block *sb)
 #define EXT4_MB_STREAM_REQ             "stream_req"
 #define EXT4_MB_GROUP_PREALLOC         "group_prealloc"
 
-
-
-#define MB_PROC_FOPS(name)                                     \
-static int ext4_mb_##name##_proc_show(struct seq_file *m, void *v)     \
-{                                                              \
-       struct ext4_sb_info *sbi = m->private;                  \
-                                                               \
-       seq_printf(m, "%ld\n", sbi->s_mb_##name);               \
-       return 0;                                               \
-}                                                              \
-                                                               \
-static int ext4_mb_##name##_proc_open(struct inode *inode, struct file *file)\
-{                                                              \
-       return single_open(file, ext4_mb_##name##_proc_show, PDE(inode)->data);\
-}                                                              \
-                                                               \
-static ssize_t ext4_mb_##name##_proc_write(struct file *file,  \
-               const char __user *buf, size_t cnt, loff_t *ppos)       \
-{                                                              \
-       struct ext4_sb_info *sbi = PDE(file->f_path.dentry->d_inode)->data;\
-       char str[32];                                           \
-       long value;                                             \
-       if (cnt >= sizeof(str))                                 \
-               return -EINVAL;                                 \
-       if (copy_from_user(str, buf, cnt))                      \
-               return -EFAULT;                                 \
-       value = simple_strtol(str, NULL, 0);                    \
-       if (value <= 0)                                         \
-               return -ERANGE;                                 \
-       sbi->s_mb_##name = value;                               \
-       return cnt;                                             \
-}                                                              \
-                                                               \
-static const struct file_operations ext4_mb_##name##_proc_fops = {     \
-       .owner          = THIS_MODULE,                          \
-       .open           = ext4_mb_##name##_proc_open,           \
-       .read           = seq_read,                             \
-       .llseek         = seq_lseek,                            \
-       .release        = single_release,                       \
-       .write          = ext4_mb_##name##_proc_write,          \
-};
-
-MB_PROC_FOPS(stats);
-MB_PROC_FOPS(max_to_scan);
-MB_PROC_FOPS(min_to_scan);
-MB_PROC_FOPS(order2_reqs);
-MB_PROC_FOPS(stream_request);
-MB_PROC_FOPS(group_prealloc);
-
-#define        MB_PROC_HANDLER(name, var)                                      \
-do {                                                                   \
-       proc = proc_create_data(name, mode, sbi->s_mb_proc,             \
-                               &ext4_mb_##var##_proc_fops, sbi);       \
-       if (proc == NULL) {                                             \
-               printk(KERN_ERR "EXT4-fs: can't to create %s\n", name); \
-               goto err_out;                                           \
-       }                                                               \
-} while (0)
-
 static int ext4_mb_init_per_dev_proc(struct super_block *sb)
 {
+#ifdef CONFIG_PROC_FS
        mode_t mode = S_IFREG | S_IRUGO | S_IWUSR;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct proc_dir_entry *proc;
-       char devname[64];
-
-       bdevname(sb->s_bdev, devname);
-       sbi->s_mb_proc = proc_mkdir(devname, proc_root_ext4);
 
-       MB_PROC_HANDLER(EXT4_MB_STATS_NAME, stats);
-       MB_PROC_HANDLER(EXT4_MB_MAX_TO_SCAN_NAME, max_to_scan);
-       MB_PROC_HANDLER(EXT4_MB_MIN_TO_SCAN_NAME, min_to_scan);
-       MB_PROC_HANDLER(EXT4_MB_ORDER2_REQ, order2_reqs);
-       MB_PROC_HANDLER(EXT4_MB_STREAM_REQ, stream_request);
-       MB_PROC_HANDLER(EXT4_MB_GROUP_PREALLOC, group_prealloc);
+       if (sbi->s_proc == NULL)
+               return -EINVAL;
 
+       EXT4_PROC_HANDLER(EXT4_MB_STATS_NAME, mb_stats);
+       EXT4_PROC_HANDLER(EXT4_MB_MAX_TO_SCAN_NAME, mb_max_to_scan);
+       EXT4_PROC_HANDLER(EXT4_MB_MIN_TO_SCAN_NAME, mb_min_to_scan);
+       EXT4_PROC_HANDLER(EXT4_MB_ORDER2_REQ, mb_order2_reqs);
+       EXT4_PROC_HANDLER(EXT4_MB_STREAM_REQ, mb_stream_request);
+       EXT4_PROC_HANDLER(EXT4_MB_GROUP_PREALLOC, mb_group_prealloc);
        return 0;
 
 err_out:
-       printk(KERN_ERR "EXT4-fs: Unable to create %s\n", devname);
-       remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_mb_proc);
-       remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_mb_proc);
-       remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_mb_proc);
-       remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_mb_proc);
-       remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_mb_proc);
-       remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_mb_proc);
-       remove_proc_entry(devname, proc_root_ext4);
-       sbi->s_mb_proc = NULL;
-
+       remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_proc);
+       remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_proc);
+       remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_proc);
+       remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_proc);
+       remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_proc);
+       remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_proc);
        return -ENOMEM;
+#else
+       return 0;
+#endif
 }
 
 static int ext4_mb_destroy_per_dev_proc(struct super_block *sb)
 {
+#ifdef CONFIG_PROC_FS
        struct ext4_sb_info *sbi = EXT4_SB(sb);
-       char devname[64];
 
-       if (sbi->s_mb_proc == NULL)
+       if (sbi->s_proc == NULL)
                return -EINVAL;
 
-       bdevname(sb->s_bdev, devname);
-       remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_mb_proc);
-       remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_mb_proc);
-       remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_mb_proc);
-       remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_mb_proc);
-       remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_mb_proc);
-       remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_mb_proc);
-       remove_proc_entry(devname, proc_root_ext4);
-
+       remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_proc);
+       remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_proc);
+       remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_proc);
+       remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_proc);
+       remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_proc);
+       remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_proc);
+#endif
        return 0;
 }
 
@@ -2724,11 +2763,16 @@ int __init init_ext4_mballoc(void)
                kmem_cache_destroy(ext4_pspace_cachep);
                return -ENOMEM;
        }
-#ifdef CONFIG_PROC_FS
-       proc_root_ext4 = proc_mkdir("fs/ext4", NULL);
-       if (proc_root_ext4 == NULL)
-               printk(KERN_ERR "EXT4-fs: Unable to create fs/ext4\n");
-#endif
+
+       ext4_free_ext_cachep =
+               kmem_cache_create("ext4_free_block_extents",
+                                    sizeof(struct ext4_free_data),
+                                    0, SLAB_RECLAIM_ACCOUNT, NULL);
+       if (ext4_free_ext_cachep == NULL) {
+               kmem_cache_destroy(ext4_pspace_cachep);
+               kmem_cache_destroy(ext4_ac_cachep);
+               return -ENOMEM;
+       }
        return 0;
 }
 
@@ -2737,9 +2781,7 @@ void exit_ext4_mballoc(void)
        /* XXX: synchronize_rcu(); */
        kmem_cache_destroy(ext4_pspace_cachep);
        kmem_cache_destroy(ext4_ac_cachep);
-#ifdef CONFIG_PROC_FS
-       remove_proc_entry("fs/ext4", NULL);
-#endif
+       kmem_cache_destroy(ext4_free_ext_cachep);
 }
 
 
@@ -2749,7 +2791,7 @@ void exit_ext4_mballoc(void)
  */
 static noinline_for_stack int
 ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
-                               handle_t *handle)
+                               handle_t *handle, unsigned long reserv_blks)
 {
        struct buffer_head *bitmap_bh = NULL;
        struct ext4_super_block *es;
@@ -2839,6 +2881,23 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
        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);
+       /*
+        * Now reduce the dirty block count also. Should not go negative
+        */
+       if (!(ac->ac_flags & EXT4_MB_DELALLOC_RESERVED))
+               /* release all the reserved blocks if non delalloc */
+               percpu_counter_sub(&sbi->s_dirtyblocks_counter, reserv_blks);
+       else
+               percpu_counter_sub(&sbi->s_dirtyblocks_counter,
+                                               ac->ac_b_ex.fe_len);
+
+       if (sbi->s_log_groups_per_flex) {
+               ext4_group_t flex_group = ext4_flex_group(sbi,
+                                                         ac->ac_b_ex.fe_group);
+               spin_lock(sb_bgl_lock(sbi, flex_group));
+               sbi->s_flex_groups[flex_group].free_blocks -= ac->ac_b_ex.fe_len;
+               spin_unlock(sb_bgl_lock(sbi, flex_group));
+       }
 
        err = ext4_journal_dirty_metadata(handle, bitmap_bh);
        if (err)
@@ -3118,6 +3177,7 @@ static void ext4_mb_use_group_pa(struct ext4_allocation_context *ac,
                                struct ext4_prealloc_space *pa)
 {
        unsigned int len = ac->ac_o_ex.fe_len;
+
        ext4_get_group_no_and_offset(ac->ac_sb, pa->pa_pstart,
                                        &ac->ac_b_ex.fe_group,
                                        &ac->ac_b_ex.fe_start);
@@ -3135,14 +3195,45 @@ static void ext4_mb_use_group_pa(struct ext4_allocation_context *ac,
 }
 
 /*
+ * Return the prealloc space that have minimal distance
+ * from the goal block. @cpa is the prealloc
+ * space that is having currently known minimal distance
+ * from the goal block.
+ */
+static struct ext4_prealloc_space *
+ext4_mb_check_group_pa(ext4_fsblk_t goal_block,
+                       struct ext4_prealloc_space *pa,
+                       struct ext4_prealloc_space *cpa)
+{
+       ext4_fsblk_t cur_distance, new_distance;
+
+       if (cpa == NULL) {
+               atomic_inc(&pa->pa_count);
+               return pa;
+       }
+       cur_distance = abs(goal_block - cpa->pa_pstart);
+       new_distance = abs(goal_block - pa->pa_pstart);
+
+       if (cur_distance < new_distance)
+               return cpa;
+
+       /* drop the previous reference */
+       atomic_dec(&cpa->pa_count);
+       atomic_inc(&pa->pa_count);
+       return pa;
+}
+
+/*
  * search goal blocks in preallocated space
  */
 static noinline_for_stack int
 ext4_mb_use_preallocated(struct ext4_allocation_context *ac)
 {
+       int order, i;
        struct ext4_inode_info *ei = EXT4_I(ac->ac_inode);
        struct ext4_locality_group *lg;
-       struct ext4_prealloc_space *pa;
+       struct ext4_prealloc_space *pa, *cpa = NULL;
+       ext4_fsblk_t goal_block;
 
        /* only data can be preallocated */
        if (!(ac->ac_flags & EXT4_MB_HINT_DATA))
@@ -3180,22 +3271,38 @@ ext4_mb_use_preallocated(struct ext4_allocation_context *ac)
        lg = ac->ac_lg;
        if (lg == NULL)
                return 0;
+       order  = fls(ac->ac_o_ex.fe_len) - 1;
+       if (order > PREALLOC_TB_SIZE - 1)
+               /* The max size of hash table is PREALLOC_TB_SIZE */
+               order = PREALLOC_TB_SIZE - 1;
+
+       goal_block = ac->ac_g_ex.fe_group * EXT4_BLOCKS_PER_GROUP(ac->ac_sb) +
+                    ac->ac_g_ex.fe_start +
+                    le32_to_cpu(EXT4_SB(ac->ac_sb)->s_es->s_first_data_block);
+       /*
+        * search for the prealloc space that is having
+        * minimal distance from the goal block.
+        */
+       for (i = order; i < PREALLOC_TB_SIZE; i++) {
+               rcu_read_lock();
+               list_for_each_entry_rcu(pa, &lg->lg_prealloc_list[i],
+                                       pa_inode_list) {
+                       spin_lock(&pa->pa_lock);
+                       if (pa->pa_deleted == 0 &&
+                                       pa->pa_free >= ac->ac_o_ex.fe_len) {
 
-       rcu_read_lock();
-       list_for_each_entry_rcu(pa, &lg->lg_prealloc_list, pa_inode_list) {
-               spin_lock(&pa->pa_lock);
-               if (pa->pa_deleted == 0 && pa->pa_free >= ac->ac_o_ex.fe_len) {
-                       atomic_inc(&pa->pa_count);
-                       ext4_mb_use_group_pa(ac, pa);
+                               cpa = ext4_mb_check_group_pa(goal_block,
+                                                               pa, cpa);
+                       }
                        spin_unlock(&pa->pa_lock);
-                       ac->ac_criteria = 20;
-                       rcu_read_unlock();
-                       return 1;
                }
-               spin_unlock(&pa->pa_lock);
+               rcu_read_unlock();
+       }
+       if (cpa) {
+               ext4_mb_use_group_pa(ac, cpa);
+               ac->ac_criteria = 20;
+               return 1;
        }
-       rcu_read_unlock();
-
        return 0;
 }
 
@@ -3418,6 +3525,7 @@ ext4_mb_new_group_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);
        pa->pa_deleted = 0;
        pa->pa_linear = 1;
 
@@ -3438,10 +3546,10 @@ ext4_mb_new_group_pa(struct ext4_allocation_context *ac)
        list_add(&pa->pa_group_list, &grp->bb_prealloc_list);
        ext4_unlock_group(sb, ac->ac_b_ex.fe_group);
 
-       spin_lock(pa->pa_obj_lock);
-       list_add_tail_rcu(&pa->pa_inode_list, &lg->lg_prealloc_list);
-       spin_unlock(pa->pa_obj_lock);
-
+       /*
+        * We will later add the new pa to the right bucket
+        * after updating the pa_free in ext4_mb_release_context
+        */
        return 0;
 }
 
@@ -3591,20 +3699,23 @@ ext4_mb_discard_group_preallocations(struct super_block *sb,
 
        bitmap_bh = ext4_read_block_bitmap(sb, group);
        if (bitmap_bh == NULL) {
-               /* error handling here */
-               ext4_mb_release_desc(&e4b);
-               BUG_ON(bitmap_bh == NULL);
+               ext4_error(sb, __func__, "Error in reading block "
+                               "bitmap for %lu\n", group);
+               return 0;
        }
 
        err = ext4_mb_load_buddy(sb, group, &e4b);
-       BUG_ON(err != 0); /* error handling here */
+       if (err) {
+               ext4_error(sb, __func__, "Error in loading buddy "
+                               "information for %lu\n", group);
+               put_bh(bitmap_bh);
+               return 0;
+       }
 
        if (needed == 0)
                needed = EXT4_BLOCKS_PER_GROUP(sb) + 1;
 
-       grp = ext4_get_group_info(sb, group);
        INIT_LIST_HEAD(&list);
-
        ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);
 repeat:
        ext4_lock_group(sb, group);
@@ -3686,7 +3797,7 @@ out:
  *
  * FIXME!! Make sure it is valid at all the call sites
  */
-void ext4_mb_discard_inode_preallocations(struct inode *inode)
+void ext4_discard_preallocations(struct inode *inode)
 {
        struct ext4_inode_info *ei = EXT4_I(inode);
        struct super_block *sb = inode->i_sb;
@@ -3698,7 +3809,7 @@ void ext4_mb_discard_inode_preallocations(struct inode *inode)
        struct ext4_buddy e4b;
        int err;
 
-       if (!test_opt(sb, MBALLOC) || !S_ISREG(inode->i_mode)) {
+       if (!S_ISREG(inode->i_mode)) {
                /*BUG_ON(!list_empty(&ei->i_prealloc_list));*/
                return;
        }
@@ -3761,13 +3872,18 @@ repeat:
                ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, NULL);
 
                err = ext4_mb_load_buddy(sb, group, &e4b);
-               BUG_ON(err != 0); /* error handling here */
+               if (err) {
+                       ext4_error(sb, __func__, "Error in loading buddy "
+                                       "information for %lu\n", group);
+                       continue;
+               }
 
                bitmap_bh = ext4_read_block_bitmap(sb, group);
                if (bitmap_bh == NULL) {
-                       /* error handling here */
+                       ext4_error(sb, __func__, "Error in reading block "
+                                       "bitmap for %lu\n", group);
                        ext4_mb_release_desc(&e4b);
-                       BUG_ON(bitmap_bh == NULL);
+                       continue;
                }
 
                ext4_lock_group(sb, group);
@@ -3891,8 +4007,7 @@ static void ext4_mb_group_or_file(struct ext4_allocation_context *ac)
         * per cpu locality group is to reduce the contention between block
         * request from multiple CPUs.
         */
-       ac->ac_lg = &sbi->s_locality_groups[get_cpu()];
-       put_cpu();
+       ac->ac_lg = per_cpu_ptr(sbi->s_locality_groups, raw_smp_processor_id());
 
        /* we're going to use group allocation */
        ac->ac_flags |= EXT4_MB_HINT_GROUP_ALLOC;
@@ -3970,22 +4085,168 @@ ext4_mb_initialize_context(struct ext4_allocation_context *ac,
 
 }
 
+static noinline_for_stack void
+ext4_mb_discard_lg_preallocations(struct super_block *sb,
+                                       struct ext4_locality_group *lg,
+                                       int order, int total_entries)
+{
+       ext4_group_t group = 0;
+       struct ext4_buddy e4b;
+       struct list_head discard_list;
+       struct ext4_prealloc_space *pa, *tmp;
+       struct ext4_allocation_context *ac;
+
+       mb_debug("discard locality group preallocation\n");
+
+       INIT_LIST_HEAD(&discard_list);
+       ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);
+
+       spin_lock(&lg->lg_prealloc_lock);
+       list_for_each_entry_rcu(pa, &lg->lg_prealloc_list[order],
+                                               pa_inode_list) {
+               spin_lock(&pa->pa_lock);
+               if (atomic_read(&pa->pa_count)) {
+                       /*
+                        * This is the pa that we just used
+                        * for block allocation. So don't
+                        * free that
+                        */
+                       spin_unlock(&pa->pa_lock);
+                       continue;
+               }
+               if (pa->pa_deleted) {
+                       spin_unlock(&pa->pa_lock);
+                       continue;
+               }
+               /* only lg prealloc space */
+               BUG_ON(!pa->pa_linear);
+
+               /* seems this one can be freed ... */
+               pa->pa_deleted = 1;
+               spin_unlock(&pa->pa_lock);
+
+               list_del_rcu(&pa->pa_inode_list);
+               list_add(&pa->u.pa_tmp_list, &discard_list);
+
+               total_entries--;
+               if (total_entries <= 5) {
+                       /*
+                        * we want to keep only 5 entries
+                        * allowing it to grow to 8. This
+                        * mak sure we don't call discard
+                        * soon for this list.
+                        */
+                       break;
+               }
+       }
+       spin_unlock(&lg->lg_prealloc_lock);
+
+       list_for_each_entry_safe(pa, tmp, &discard_list, u.pa_tmp_list) {
+
+               ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, NULL);
+               if (ext4_mb_load_buddy(sb, group, &e4b)) {
+                       ext4_error(sb, __func__, "Error in loading buddy "
+                                       "information for %lu\n", group);
+                       continue;
+               }
+               ext4_lock_group(sb, group);
+               list_del(&pa->pa_group_list);
+               ext4_mb_release_group_pa(&e4b, pa, ac);
+               ext4_unlock_group(sb, group);
+
+               ext4_mb_release_desc(&e4b);
+               list_del(&pa->u.pa_tmp_list);
+               call_rcu(&(pa)->u.pa_rcu, ext4_mb_pa_callback);
+       }
+       if (ac)
+               kmem_cache_free(ext4_ac_cachep, ac);
+}
+
+/*
+ * We have incremented pa_count. So it cannot be freed at this
+ * point. Also we hold lg_mutex. So no parallel allocation is
+ * possible from this lg. That means pa_free cannot be updated.
+ *
+ * A parallel ext4_mb_discard_group_preallocations is possible.
+ * which can cause the lg_prealloc_list to be updated.
+ */
+
+static void ext4_mb_add_n_trim(struct ext4_allocation_context *ac)
+{
+       int order, added = 0, lg_prealloc_count = 1;
+       struct super_block *sb = ac->ac_sb;
+       struct ext4_locality_group *lg = ac->ac_lg;
+       struct ext4_prealloc_space *tmp_pa, *pa = ac->ac_pa;
+
+       order = fls(pa->pa_free) - 1;
+       if (order > PREALLOC_TB_SIZE - 1)
+               /* The max size of hash table is PREALLOC_TB_SIZE */
+               order = PREALLOC_TB_SIZE - 1;
+       /* Add the prealloc space to lg */
+       rcu_read_lock();
+       list_for_each_entry_rcu(tmp_pa, &lg->lg_prealloc_list[order],
+                                               pa_inode_list) {
+               spin_lock(&tmp_pa->pa_lock);
+               if (tmp_pa->pa_deleted) {
+                       spin_unlock(&pa->pa_lock);
+                       continue;
+               }
+               if (!added && pa->pa_free < tmp_pa->pa_free) {
+                       /* Add to the tail of the previous entry */
+                       list_add_tail_rcu(&pa->pa_inode_list,
+                                               &tmp_pa->pa_inode_list);
+                       added = 1;
+                       /*
+                        * we want to count the total
+                        * number of entries in the list
+                        */
+               }
+               spin_unlock(&tmp_pa->pa_lock);
+               lg_prealloc_count++;
+       }
+       if (!added)
+               list_add_tail_rcu(&pa->pa_inode_list,
+                                       &lg->lg_prealloc_list[order]);
+       rcu_read_unlock();
+
+       /* Now trim the list to be not more than 8 elements */
+       if (lg_prealloc_count > 8) {
+               ext4_mb_discard_lg_preallocations(sb, lg,
+                                               order, lg_prealloc_count);
+               return;
+       }
+       return ;
+}
+
 /*
  * release all resource we used in allocation
  */
 static int ext4_mb_release_context(struct ext4_allocation_context *ac)
 {
-       if (ac->ac_pa) {
-               if (ac->ac_pa->pa_linear) {
+       struct ext4_prealloc_space *pa = ac->ac_pa;
+       if (pa) {
+               if (pa->pa_linear) {
                        /* see comment in ext4_mb_use_group_pa() */
-                       spin_lock(&ac->ac_pa->pa_lock);
-                       ac->ac_pa->pa_pstart += ac->ac_b_ex.fe_len;
-                       ac->ac_pa->pa_lstart += ac->ac_b_ex.fe_len;
-                       ac->ac_pa->pa_free -= ac->ac_b_ex.fe_len;
-                       ac->ac_pa->pa_len -= ac->ac_b_ex.fe_len;
-                       spin_unlock(&ac->ac_pa->pa_lock);
+                       spin_lock(&pa->pa_lock);
+                       pa->pa_pstart += ac->ac_b_ex.fe_len;
+                       pa->pa_lstart += ac->ac_b_ex.fe_len;
+                       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);
+                       }
                }
-               ext4_mb_put_pa(ac, ac->ac_sb, ac->ac_pa);
+               ext4_mb_put_pa(ac, ac->ac_sb, pa);
        }
        if (ac->ac_bitmap_page)
                page_cache_release(ac->ac_bitmap_page);
@@ -4020,22 +4281,32 @@ static int ext4_mb_discard_preallocations(struct super_block *sb, int needed)
 ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
                                 struct ext4_allocation_request *ar, int *errp)
 {
+       int freed;
        struct ext4_allocation_context *ac = NULL;
        struct ext4_sb_info *sbi;
        struct super_block *sb;
        ext4_fsblk_t block = 0;
-       int freed;
-       int inquota;
+       unsigned long inquota;
+       unsigned long reserv_blks = 0;
 
        sb = ar->inode->i_sb;
        sbi = EXT4_SB(sb);
 
-       if (!test_opt(sb, MBALLOC)) {
-               block = ext4_new_blocks_old(handle, ar->inode, ar->goal,
-                                           &(ar->len), errp);
-               return block;
+       if (!EXT4_I(ar->inode)->i_delalloc_reserved_flag) {
+               /*
+                * With delalloc we already reserved the blocks
+                */
+               while (ar->len && ext4_claim_free_blocks(sbi, ar->len)) {
+                       /* let others to free the space */
+                       yield();
+                       ar->len = ar->len >> 1;
+               }
+               if (!ar->len) {
+                       *errp = -ENOSPC;
+                       return 0;
+               }
+               reserv_blks = ar->len;
        }
-
        while (ar->len && DQUOT_ALLOC_BLOCK(ar->inode, ar->len)) {
                ar->flags |= EXT4_MB_HINT_NOPREALLOC;
                ar->len--;
@@ -4046,23 +4317,24 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
        }
        inquota = ar->len;
 
+       if (EXT4_I(ar->inode)->i_delalloc_reserved_flag)
+               ar->flags |= EXT4_MB_DELALLOC_RESERVED;
+
        ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);
        if (!ac) {
+               ar->len = 0;
                *errp = -ENOMEM;
-               return 0;
+               goto out1;
        }
 
-       ext4_mb_poll_new_transaction(sb, handle);
-
        *errp = ext4_mb_initialize_context(ac, ar);
        if (*errp) {
                ar->len = 0;
-               goto out;
+               goto out2;
        }
 
        ac->ac_op = EXT4_MB_HISTORY_PREALLOC;
        if (!ext4_mb_use_preallocated(ac)) {
-
                ac->ac_op = EXT4_MB_HISTORY_ALLOC;
                ext4_mb_normalize_request(ac, ar);
 repeat:
@@ -4078,7 +4350,7 @@ repeat:
        }
 
        if (likely(ac->ac_status == AC_STATUS_FOUND)) {
-               *errp = ext4_mb_mark_diskspace_used(ac, handle);
+               *errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_blks);
                if (*errp ==  -EAGAIN) {
                        ac->ac_b_ex.fe_group = 0;
                        ac->ac_b_ex.fe_start = 0;
@@ -4105,42 +4377,28 @@ repeat:
 
        ext4_mb_release_context(ac);
 
-out:
+out2:
+       kmem_cache_free(ext4_ac_cachep, ac);
+out1:
        if (ar->len < inquota)
                DQUOT_FREE_BLOCK(ar->inode, inquota - ar->len);
 
-       kmem_cache_free(ext4_ac_cachep, ac);
        return block;
 }
-static void ext4_mb_poll_new_transaction(struct super_block *sb,
-                                               handle_t *handle)
-{
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
-
-       if (sbi->s_last_transaction == handle->h_transaction->t_tid)
-               return;
-
-       /* new transaction! time to close last one and free blocks for
-        * committed transaction. we know that only transaction can be
-        * active, so previos transaction can be being logged and we
-        * know that transaction before previous is known to be already
-        * logged. this means that now we may free blocks freed in all
-        * transactions before previous one. hope I'm clear enough ... */
-
-       spin_lock(&sbi->s_md_lock);
-       if (sbi->s_last_transaction != handle->h_transaction->t_tid) {
-               mb_debug("new transaction %lu, old %lu\n",
-                               (unsigned long) handle->h_transaction->t_tid,
-                               (unsigned long) sbi->s_last_transaction);
-               list_splice_init(&sbi->s_closed_transaction,
-                               &sbi->s_committed_transaction);
-               list_splice_init(&sbi->s_active_transaction,
-                               &sbi->s_closed_transaction);
-               sbi->s_last_transaction = handle->h_transaction->t_tid;
-       }
-       spin_unlock(&sbi->s_md_lock);
 
-       ext4_mb_free_committed_blocks(sb);
+/*
+ * We can merge two free data extents only if the physical blocks
+ * are contiguous, AND the extents were freed by the same transaction,
+ * AND the blocks are associated with the same group.
+ */
+static int can_merge(struct ext4_free_data *entry1,
+                       struct ext4_free_data *entry2)
+{
+       if ((entry1->t_tid == entry2->t_tid) &&
+           (entry1->group == entry2->group) &&
+           ((entry1->start_blk + entry1->count) == entry2->start_blk))
+               return 1;
+       return 0;
 }
 
 static noinline_for_stack int
@@ -4150,57 +4408,81 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
        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_metadata *md;
-       int i;
+       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;
+
 
        BUG_ON(e4b->bd_bitmap_page == NULL);
        BUG_ON(e4b->bd_buddy_page == NULL);
 
-       ext4_lock_group(sb, group);
-       for (i = 0; i < count; i++) {
-               md = db->bb_md_cur;
-               if (md && db->bb_tid != handle->h_transaction->t_tid) {
-                       db->bb_md_cur = NULL;
-                       md = 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;
 
-               if (md == NULL) {
+       ext4_lock_group(sb, group);
+       if (!*n) {
+               /* first free block exent. We need to
+                  protect buddy cache from being freed,
+                * otherwise we'll refresh it from
+                * on-disk bitmap and lose not-yet-available
+                * blocks */
+               page_cache_get(e4b->bd_buddy_page);
+               page_cache_get(e4b->bd_bitmap_page);
+       }
+       while (*n) {
+               parent = *n;
+               entry = rb_entry(parent, struct ext4_free_data, node);
+               if (block < entry->start_blk)
+                       n = &(*n)->rb_left;
+               else if (block >= (entry->start_blk + entry->count))
+                       n = &(*n)->rb_right;
+               else {
                        ext4_unlock_group(sb, group);
-                       md = kmalloc(sizeof(*md), GFP_NOFS);
-                       if (md == NULL)
-                               return -ENOMEM;
-                       md->num = 0;
-                       md->group = group;
+                       ext4_error(sb, __func__,
+                           "Double free of blocks %d (%d %d)\n",
+                           block, entry->start_blk, entry->count);
+                       return 0;
+               }
+       }
 
-                       ext4_lock_group(sb, group);
-                       if (db->bb_md_cur == NULL) {
-                               spin_lock(&sbi->s_md_lock);
-                               list_add(&md->list, &sbi->s_active_transaction);
-                               spin_unlock(&sbi->s_md_lock);
-                               /* protect buddy cache from being freed,
-                                * otherwise we'll refresh it from
-                                * on-disk bitmap and lose not-yet-available
-                                * blocks */
-                               page_cache_get(e4b->bd_buddy_page);
-                               page_cache_get(e4b->bd_bitmap_page);
-                               db->bb_md_cur = md;
-                               db->bb_tid = handle->h_transaction->t_tid;
-                               mb_debug("new md 0x%p for group %lu\n",
-                                               md, md->group);
-                       } else {
-                               kfree(md);
-                               md = db->bb_md_cur;
-                       }
+       rb_link_node(new_node, parent, n);
+       rb_insert_color(new_node, &db->bb_free_root);
+
+       /* Now try to see the extent can be merged to left and right */
+       node = rb_prev(new_node);
+       if (node) {
+               entry = rb_entry(node, struct ext4_free_data, node);
+               if (can_merge(entry, new_entry)) {
+                       new_entry->start_blk = entry->start_blk;
+                       new_entry->count += entry->count;
+                       rb_erase(node, &(db->bb_free_root));
+                       spin_lock(&sbi->s_md_lock);
+                       list_del(&entry->list);
+                       spin_unlock(&sbi->s_md_lock);
+                       kmem_cache_free(ext4_free_ext_cachep, entry);
                }
+       }
 
-               BUG_ON(md->num >= EXT4_BB_MAX_BLOCKS);
-               md->blocks[md->num] = block + i;
-               md->num++;
-               if (md->num == EXT4_BB_MAX_BLOCKS) {
-                       /* no more space, put full container on a sb's list */
-                       db->bb_md_cur = NULL;
+       node = rb_next(new_node);
+       if (node) {
+               entry = rb_entry(node, struct ext4_free_data, node);
+               if (can_merge(new_entry, entry)) {
+                       new_entry->count += entry->count;
+                       rb_erase(node, &(db->bb_free_root));
+                       spin_lock(&sbi->s_md_lock);
+                       list_del(&entry->list);
+                       spin_unlock(&sbi->s_md_lock);
+                       kmem_cache_free(ext4_free_ext_cachep, entry);
                }
        }
+       /* Add the extent to transaction's private list */
+       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;
 }
@@ -4228,8 +4510,6 @@ void ext4_mb_free_blocks(handle_t *handle, struct inode *inode,
 
        *freed = 0;
 
-       ext4_mb_poll_new_transaction(sb, handle);
-
        sbi = EXT4_SB(sb);
        es = EXT4_SB(sb)->s_es;
        if (block < le32_to_cpu(es->s_first_data_block) ||
@@ -4263,11 +4543,15 @@ do_more:
                count -= overflow;
        }
        bitmap_bh = ext4_read_block_bitmap(sb, block_group);
-       if (!bitmap_bh)
+       if (!bitmap_bh) {
+               err = -EIO;
                goto error_return;
+       }
        gdp = ext4_get_group_desc(sb, block_group, &gd_bh);
-       if (!gdp)
+       if (!gdp) {
+               err = -EIO;
                goto error_return;
+       }
 
        if (in_range(ext4_block_bitmap(sb, gdp), block, count) ||
            in_range(ext4_inode_bitmap(sb, gdp), block, count) ||
@@ -4329,10 +4613,9 @@ do_more:
                ext4_mb_free_metadata(handle, &e4b, block_group, bit, count);
        } else {
                ext4_lock_group(sb, block_group);
-               err = mb_free_blocks(inode, &e4b, bit, count);
+               mb_free_blocks(inode, &e4b, bit, count);
                ext4_mb_return_to_preallocation(inode, &e4b, block, count);
                ext4_unlock_group(sb, block_group);
-               BUG_ON(err != 0);
        }
 
        spin_lock(sb_bgl_lock(sbi, block_group));
@@ -4341,6 +4624,13 @@ do_more:
        spin_unlock(sb_bgl_lock(sbi, block_group));
        percpu_counter_add(&sbi->s_freeblocks_counter, count);
 
+       if (sbi->s_log_groups_per_flex) {
+               ext4_group_t flex_group = ext4_flex_group(sbi, block_group);
+               spin_lock(sb_bgl_lock(sbi, flex_group));
+               sbi->s_flex_groups[flex_group].free_blocks += count;
+               spin_unlock(sb_bgl_lock(sbi, flex_group));
+       }
+
        ext4_mb_release_desc(&e4b);
 
        *freed += count;