]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/ext4/balloc.c
ext4: Signed arithmetic fix
[linux-2.6-omap-h63xx.git] / fs / ext4 / balloc.c
index 9cc80b9cc8d8fa874659f7d4280d0f0e6fba5eca..a425e78c73ebfafc7b27206940a1e2a615f7dd8d 100644 (file)
@@ -47,7 +47,7 @@ static int ext4_block_in_group(struct super_block *sb, ext4_fsblk_t block,
                        ext4_group_t block_group)
 {
        ext4_group_t actual_group;
-       ext4_get_group_no_and_offset(sb, block, &actual_group, 0);
+       ext4_get_group_no_and_offset(sb, block, &actual_group, NULL);
        if (actual_group == block_group)
                return 1;
        return 0;
@@ -121,12 +121,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
                                le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks);
                }
        } else { /* For META_BG_BLOCK_GROUPS */
-               int group_rel = (block_group -
-                                le32_to_cpu(sbi->s_es->s_first_meta_bg)) %
-                               EXT4_DESC_PER_BLOCK(sb);
-               if (group_rel == 0 || group_rel == 1 ||
-                   (group_rel == EXT4_DESC_PER_BLOCK(sb) - 1))
-                       bit_max += 1;
+               bit_max += ext4_bg_num_gdb(sb, block_group);
        }
 
        if (block_group == sbi->s_groups_count - 1) {
@@ -137,7 +132,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
                 */
                group_blocks = ext4_blocks_count(sbi->s_es) -
                        le32_to_cpu(sbi->s_es->s_first_data_block) -
-                       (EXT4_BLOCKS_PER_GROUP(sb) * (sbi->s_groups_count -1));
+                       (EXT4_BLOCKS_PER_GROUP(sb) * (sbi->s_groups_count - 1));
        } else {
                group_blocks = EXT4_BLOCKS_PER_GROUP(sb);
        }
@@ -205,20 +200,20 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
  * @bh:                        pointer to the buffer head to store the block
  *                     group descriptor
  */
-struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
+struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
                                             ext4_group_t block_group,
-                                            struct buffer_head ** bh)
+                                            struct buffer_head **bh)
 {
        unsigned long group_desc;
        unsigned long offset;
-       struct ext4_group_desc * desc;
+       struct ext4_group_desc *desc;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
 
        if (block_group >= sbi->s_groups_count) {
-               ext4_error (sb, "ext4_get_group_desc",
-                           "block_group >= groups_count - "
-                           "block_group = %lu, groups_count = %lu",
-                           block_group, sbi->s_groups_count);
+               ext4_error(sb, "ext4_get_group_desc",
+                          "block_group >= groups_count - "
+                          "block_group = %lu, groups_count = %lu",
+                          block_group, sbi->s_groups_count);
 
                return NULL;
        }
@@ -227,10 +222,10 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
        group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
        offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
        if (!sbi->s_group_desc[group_desc]) {
-               ext4_error (sb, "ext4_get_group_desc",
-                           "Group descriptor not loaded - "
-                           "block_group = %lu, group_desc = %lu, desc = %lu",
-                            block_group, group_desc, offset);
+               ext4_error(sb, "ext4_get_group_desc",
+                          "Group descriptor not loaded - "
+                          "block_group = %lu, group_desc = %lu, desc = %lu",
+                          block_group, group_desc, offset);
                return NULL;
        }
 
@@ -295,7 +290,7 @@ err_out:
        return 0;
 }
 /**
- * read_block_bitmap()
+ * ext4_read_block_bitmap()
  * @sb:                        super block
  * @block_group:       given block group
  *
@@ -305,10 +300,10 @@ err_out:
  * Return buffer_head on success or NULL in case of failure.
  */
 struct buffer_head *
-read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
+ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
 {
-       struct ext4_group_desc * desc;
-       struct buffer_head * bh = NULL;
+       struct ext4_group_desc *desc;
+       struct buffer_head *bh = NULL;
        ext4_fsblk_t bitmap_blk;
 
        desc = ext4_get_group_desc(sb, block_group, NULL);
@@ -319,25 +314,28 @@ read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
        if (unlikely(!bh)) {
                ext4_error(sb, __func__,
                            "Cannot read block bitmap - "
-                           "block_group = %d, block_bitmap = %llu",
-                           (int)block_group, (unsigned long long)bitmap_blk);
+                           "block_group = %lu, block_bitmap = %llu",
+                           block_group, bitmap_blk);
                return NULL;
        }
        if (bh_uptodate_or_lock(bh))
                return bh;
 
+       spin_lock(sb_bgl_lock(EXT4_SB(sb), block_group));
        if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
                ext4_init_block_bitmap(sb, bh, block_group, desc);
                set_buffer_uptodate(bh);
                unlock_buffer(bh);
+               spin_unlock(sb_bgl_lock(EXT4_SB(sb), block_group));
                return bh;
        }
+       spin_unlock(sb_bgl_lock(EXT4_SB(sb), block_group));
        if (bh_submit_read(bh) < 0) {
                put_bh(bh);
                ext4_error(sb, __func__,
                            "Cannot read block bitmap - "
-                           "block_group = %d, block_bitmap = %llu",
-                           (int)block_group, (unsigned long long)bitmap_blk);
+                           "block_group = %lu, block_bitmap = %llu",
+                           block_group, bitmap_blk);
                return NULL;
        }
        ext4_valid_block_bitmap(sb, desc, block_group, bh);
@@ -381,26 +379,28 @@ restart:
        bad = 0;
        prev = NULL;
 
-       printk("Block Allocation Reservation Windows Map (%s):\n", fn);
+       printk(KERN_DEBUG "Block Allocation Reservation "
+              "Windows Map (%s):\n", fn);
        while (n) {
                rsv = rb_entry(n, struct ext4_reserve_window_node, rsv_node);
                if (verbose)
-                       printk("reservation window 0x%p "
+                       printk(KERN_DEBUG "reservation window 0x%p "
                               "start:  %llu, end:  %llu\n",
                               rsv, rsv->rsv_start, rsv->rsv_end);
                if (rsv->rsv_start && rsv->rsv_start >= rsv->rsv_end) {
-                       printk("Bad reservation %p (start >= end)\n",
+                       printk(KERN_DEBUG "Bad reservation %p (start >= end)\n",
                               rsv);
                        bad = 1;
                }
                if (prev && prev->rsv_end >= rsv->rsv_start) {
-                       printk("Bad reservation %p (prev->end >= start)\n",
-                              rsv);
+                       printk(KERN_DEBUG "Bad reservation %p "
+                              "(prev->end >= start)\n", rsv);
                        bad = 1;
                }
                if (bad) {
                        if (!verbose) {
-                               printk("Restarting reservation walk in verbose mode\n");
+                               printk(KERN_DEBUG "Restarting reservation "
+                                      "walk in verbose mode\n");
                                verbose = 1;
                                goto restart;
                        }
@@ -408,9 +408,8 @@ restart:
                n = rb_next(n);
                prev = rsv;
        }
-       printk("Window map complete.\n");
-       if (bad)
-               BUG();
+       printk(KERN_DEBUG "Window map complete.\n");
+       BUG_ON(bad);
 }
 #define rsv_window_dump(root, verbose) \
        __rsv_window_dump((root), (verbose), __func__)
@@ -507,8 +506,8 @@ void ext4_rsv_window_add(struct super_block *sb,
        struct rb_node *node = &rsv->rsv_node;
        ext4_fsblk_t start = rsv->rsv_start;
 
-       struct rb_node ** p = &root->rb_node;
-       struct rb_node * parent = NULL;
+       struct rb_node **p = &root->rb_node;
+       struct rb_node *parent = NULL;
        struct ext4_reserve_window_node *this;
 
        while (*p)
@@ -662,8 +661,8 @@ void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb,
        ext4_grpblk_t bit;
        unsigned long i;
        unsigned long overflow;
-       struct ext4_group_desc * desc;
-       struct ext4_super_block * es;
+       struct ext4_group_desc *desc;
+       struct ext4_super_block *es;
        struct ext4_sb_info *sbi;
        int err = 0, ret;
        ext4_grpblk_t group_freed;
@@ -674,13 +673,13 @@ void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb,
        if (block < le32_to_cpu(es->s_first_data_block) ||
            block + count < block ||
            block + count > ext4_blocks_count(es)) {
-               ext4_error (sb, "ext4_free_blocks",
-                           "Freeing blocks not in datazone - "
-                           "block = %llu, count = %lu", block, count);
+               ext4_error(sb, "ext4_free_blocks",
+                          "Freeing blocks not in datazone - "
+                          "block = %llu, count = %lu", block, count);
                goto error_return;
        }
 
-       ext4_debug ("freeing block(s) %llu-%llu\n", block, block + count - 1);
+       ext4_debug("freeing block(s) %llu-%llu\n", block, block + count - 1);
 
 do_more:
        overflow = 0;
@@ -694,10 +693,10 @@ do_more:
                count -= overflow;
        }
        brelse(bitmap_bh);
-       bitmap_bh = read_block_bitmap(sb, block_group);
+       bitmap_bh = ext4_read_block_bitmap(sb, block_group);
        if (!bitmap_bh)
                goto error_return;
-       desc = ext4_get_group_desc (sb, block_group, &gd_bh);
+       desc = ext4_get_group_desc(sb, block_group, &gd_bh);
        if (!desc)
                goto error_return;
 
@@ -706,10 +705,10 @@ do_more:
            in_range(block, ext4_inode_table(sb, desc), sbi->s_itb_per_group) ||
            in_range(block + count - 1, ext4_inode_table(sb, desc),
                     sbi->s_itb_per_group)) {
-               ext4_error (sb, "ext4_free_blocks",
-                           "Freeing blocks in system zones - "
-                           "Block = %llu, count = %lu",
-                           block, count);
+               ext4_error(sb, "ext4_free_blocks",
+                          "Freeing blocks in system zones - "
+                          "Block = %llu, count = %lu",
+                          block, count);
                goto error_return;
        }
 
@@ -810,6 +809,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));
+       }
+
        /* We dirtied the bitmap block */
        BUFFER_TRACE(bitmap_bh, "dirtied bitmap block");
        err = ext4_journal_dirty_metadata(handle, bitmap_bh);
@@ -844,7 +850,7 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
                        ext4_fsblk_t block, unsigned long count,
                        int metadata)
 {
-       struct super_block * sb;
+       struct super_block *sb;
        unsigned long dquot_freed_blocks;
 
        /* this isn't the right place to decide whether block is metadata
@@ -1013,7 +1019,7 @@ claim_block(spinlock_t *lock, ext4_grpblk_t block, struct buffer_head *bh)
        if (ext4_set_bit_atomic(lock, block, bh->b_data))
                return 0;
        jbd_lock_bh_state(bh);
-       if (jh->b_committed_data && ext4_test_bit(block,jh->b_committed_data)) {
+       if (jh->b_committed_data && ext4_test_bit(block, jh->b_committed_data)) {
                ext4_clear_bit_atomic(lock, block, bh->b_data);
                ret = 0;
        } else {
@@ -1164,7 +1170,7 @@ fail_access:
 static int find_next_reservable_window(
                                struct ext4_reserve_window_node *search_head,
                                struct ext4_reserve_window_node *my_rsv,
-                               struct super_block * sb,
+                               struct super_block *sb,
                                ext4_fsblk_t start_block,
                                ext4_fsblk_t last_block)
 {
@@ -1198,7 +1204,7 @@ static int find_next_reservable_window(
 
                prev = rsv;
                next = rb_next(&rsv->rsv_node);
-               rsv = rb_entry(next,struct ext4_reserve_window_node,rsv_node);
+               rsv = rb_entry(next, struct ext4_reserve_window_node, rsv_node);
 
                /*
                 * Reached the last reservation, we can just append to the
@@ -1336,7 +1342,7 @@ static int alloc_new_reservation(struct ext4_reserve_window_node *my_rsv,
                        size = size * 2;
                        if (size > EXT4_MAX_RESERVE_BLOCKS)
                                size = EXT4_MAX_RESERVE_BLOCKS;
-                       my_rsv->rsv_goal_size= size;
+                       my_rsv->rsv_goal_size = size;
                }
        }
 
@@ -1485,7 +1491,7 @@ static ext4_grpblk_t
 ext4_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
                        ext4_group_t group, struct buffer_head *bitmap_bh,
                        ext4_grpblk_t grp_goal,
-                       struct ext4_reserve_window_node * my_rsv,
+                       struct ext4_reserve_window_node *my_rsv,
                        unsigned long *count, int *errp)
 {
        ext4_fsblk_t group_first_block, group_last_block;
@@ -1513,7 +1519,7 @@ ext4_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
         * or the file is not a regular file
         * or last attempt to allocate a block with reservation turned on failed
         */
-       if (my_rsv == NULL ) {
+       if (my_rsv == NULL) {
                ret = ext4_try_to_allocate(sb, handle, group, bitmap_bh,
                                                grp_goal, count, NULL);
                goto out;
@@ -1596,26 +1602,84 @@ out:
        return ret;
 }
 
+int ext4_claim_free_blocks(struct ext4_sb_info *sbi,
+                                               s64 nblocks)
+{
+       s64 free_blocks, dirty_blocks;
+       s64 root_blocks = 0;
+       struct percpu_counter *fbc = &sbi->s_freeblocks_counter;
+       struct percpu_counter *dbc = &sbi->s_dirtyblocks_counter;
+
+       free_blocks  = percpu_counter_read_positive(fbc);
+       dirty_blocks = percpu_counter_read_positive(dbc);
+
+       if (!capable(CAP_SYS_RESOURCE) &&
+               sbi->s_resuid != current->fsuid &&
+               (sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid)))
+               root_blocks = ext4_r_blocks_count(sbi->s_es);
+
+       if (free_blocks - (nblocks + root_blocks + dirty_blocks) <
+                                               EXT4_FREEBLOCKS_WATERMARK) {
+               free_blocks  = percpu_counter_sum(fbc);
+               dirty_blocks = percpu_counter_sum(dbc);
+               if (dirty_blocks < 0) {
+                       printk(KERN_CRIT "Dirty block accounting "
+                                       "went wrong %lld\n",
+                                       dirty_blocks);
+               }
+       }
+       /* Check whether we have space after
+        * accounting for current dirty blocks
+        */
+       if (free_blocks < ((root_blocks + nblocks) + dirty_blocks))
+               /* we don't have free space */
+               return -ENOSPC;
+
+       /* Add the blocks to nblocks */
+       percpu_counter_add(dbc, nblocks);
+       return 0;
+}
+
 /**
  * ext4_has_free_blocks()
- * @sbi:               in-core super block structure.
+ * @sbi:       in-core super block structure.
+ * @nblocks:   number of neeed blocks
  *
- * Check if filesystem has at least 1 free block available for allocation.
+ * Check if filesystem has free blocks available for allocation.
+ * Return the number of blocks avaible for allocation for this request
+ * On success, return nblocks
  */
-static int ext4_has_free_blocks(struct ext4_sb_info *sbi)
+ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi,
+                                               s64 nblocks)
 {
-       ext4_fsblk_t free_blocks, root_blocks;
+       s64 free_blocks, dirty_blocks;
+       s64 root_blocks = 0;
+       struct percpu_counter *fbc = &sbi->s_freeblocks_counter;
+       struct percpu_counter *dbc = &sbi->s_dirtyblocks_counter;
 
-       free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
-       root_blocks = ext4_r_blocks_count(sbi->s_es);
-       if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&
+       free_blocks  = percpu_counter_read_positive(fbc);
+       dirty_blocks = percpu_counter_read_positive(dbc);
+
+       if (!capable(CAP_SYS_RESOURCE) &&
                sbi->s_resuid != current->fsuid &&
-               (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
-               return 0;
+               (sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid)))
+               root_blocks = ext4_r_blocks_count(sbi->s_es);
+
+       if (free_blocks - (nblocks + root_blocks + dirty_blocks) <
+                                               EXT4_FREEBLOCKS_WATERMARK) {
+               free_blocks  = percpu_counter_sum(fbc);
+               dirty_blocks = percpu_counter_sum(dbc);
        }
-       return 1;
+       if (free_blocks <= (root_blocks + dirty_blocks))
+               /* we don't have free space */
+               return 0;
+
+       if (free_blocks - (root_blocks + dirty_blocks) < nblocks)
+               return free_blocks - (root_blocks + dirty_blocks);
+       return nblocks;
 }
 
+
 /**
  * ext4_should_retry_alloc()
  * @sb:                        super block
@@ -1630,7 +1694,7 @@ static int ext4_has_free_blocks(struct ext4_sb_info *sbi)
  */
 int ext4_should_retry_alloc(struct super_block *sb, int *retries)
 {
-       if (!ext4_has_free_blocks(EXT4_SB(sb)) || (*retries)++ > 3)
+       if (!ext4_has_free_blocks(EXT4_SB(sb), 1) || (*retries)++ > 3)
                return 0;
 
        jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id);
@@ -1639,20 +1703,24 @@ int ext4_should_retry_alloc(struct super_block *sb, int *retries)
 }
 
 /**
- * ext4_new_blocks_old() -- core block(s) allocation function
+ * ext4_old_new_blocks() -- core block bitmap based block allocation function
+ *
  * @handle:            handle to this transaction
  * @inode:             file inode
  * @goal:              given target block(filesystem wide)
  * @count:             target number of blocks to allocate
  * @errp:              error code
  *
- * ext4_new_blocks uses a goal block to assist allocation.  It tries to
- * allocate block(s) from the block group contains the goal block first. If that
- * fails, it will try to allocate block(s) from other block groups without
- * any specific goal block.
+ * ext4_old_new_blocks uses a goal block to assist allocation and look up
+ * the block bitmap directly to do block allocation.  It tries to
+ * allocate block(s) from the block group contains the goal block first. If
+ * that fails, it will try to allocate block(s) from other block groups
+ * without any specific goal block.
+ *
+ * This function is called when -o nomballoc mount option is enabled
  *
  */
-ext4_fsblk_t ext4_new_blocks_old(handle_t *handle, struct inode *inode,
+ext4_fsblk_t ext4_old_new_blocks(handle_t *handle, struct inode *inode,
                        ext4_fsblk_t goal, unsigned long *count, int *errp)
 {
        struct buffer_head *bitmap_bh = NULL;
@@ -1676,13 +1744,29 @@ ext4_fsblk_t ext4_new_blocks_old(handle_t *handle, struct inode *inode,
        ext4_group_t ngroups;
        unsigned long num = *count;
 
-       *errp = -ENOSPC;
        sb = inode->i_sb;
        if (!sb) {
-               printk("ext4_new_block: nonexistent device");
+               *errp = -ENODEV;
+               printk(KERN_ERR "ext4_new_block: nonexistent superblock");
                return 0;
        }
 
+       sbi = EXT4_SB(sb);
+       if (!EXT4_I(inode)->i_delalloc_reserved_flag) {
+               /*
+                * With delalloc we already reserved the blocks
+                */
+               while (*count && ext4_claim_free_blocks(sbi, *count)) {
+                       /* let others to free the space */
+                       yield();
+                       *count = *count >> 1;
+               }
+               if (!*count) {
+                       *errp = -ENOSPC;
+                       return 0;       /*return with ENOSPC error */
+               }
+               num = *count;
+       }
        /*
         * Check quota for allocation of this block.
         */
@@ -1706,11 +1790,6 @@ ext4_fsblk_t ext4_new_blocks_old(handle_t *handle, struct inode *inode,
        if (block_i && ((windowsz = block_i->rsv_window_node.rsv_goal_size) > 0))
                my_rsv = &block_i->rsv_window_node;
 
-       if (!ext4_has_free_blocks(sbi)) {
-               *errp = -ENOSPC;
-               goto out;
-       }
-
        /*
         * First, test whether the goal block is free.
         */
@@ -1734,7 +1813,7 @@ retry_alloc:
                my_rsv = NULL;
 
        if (free_blocks > 0) {
-               bitmap_bh = read_block_bitmap(sb, group_no);
+               bitmap_bh = ext4_read_block_bitmap(sb, group_no);
                if (!bitmap_bh)
                        goto io_error;
                grp_alloc_blk = ext4_try_to_allocate_with_rsv(sb, handle,
@@ -1770,7 +1849,7 @@ retry_alloc:
                        continue;
 
                brelse(bitmap_bh);
-               bitmap_bh = read_block_bitmap(sb, group_no);
+               bitmap_bh = ext4_read_block_bitmap(sb, group_no);
                if (!bitmap_bh)
                        goto io_error;
                /*
@@ -1853,8 +1932,8 @@ allocated:
                for (i = 0; i < num; i++) {
                        if (ext4_test_bit(grp_alloc_blk+i,
                                        bh2jh(bitmap_bh)->b_committed_data)) {
-                               printk("%s: block was unexpectedly set in "
-                                       "b_committed_data\n", __func__);
+                               printk(KERN_ERR "%s: block was unexpectedly "
+                                      "set in b_committed_data\n", __func__);
                        }
                }
        }
@@ -1883,6 +1962,19 @@ allocated:
        gdp->bg_checksum = ext4_group_desc_csum(sbi, group_no, gdp);
        spin_unlock(sb_bgl_lock(sbi, group_no));
        percpu_counter_sub(&sbi->s_freeblocks_counter, num);
+       /*
+        * Now reduce the dirty block count also. Should not go negative
+        */
+       if (!EXT4_I(inode)->i_delalloc_reserved_flag)
+               percpu_counter_sub(&sbi->s_dirtyblocks_counter, *count);
+       else
+               percpu_counter_sub(&sbi->s_dirtyblocks_counter, num);
+       if (sbi->s_log_groups_per_flex) {
+               ext4_group_t flex_group = ext4_flex_group(sbi, group_no);
+               spin_lock(sb_bgl_lock(sbi, flex_group));
+               sbi->s_flex_groups[flex_group].free_blocks -= num;
+               spin_unlock(sb_bgl_lock(sbi, flex_group));
+       }
 
        BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor");
        err = ext4_journal_dirty_metadata(handle, gdp_bh);
@@ -1915,46 +2007,104 @@ out:
        return 0;
 }
 
-ext4_fsblk_t ext4_new_block(handle_t *handle, struct inode *inode,
-               ext4_fsblk_t goal, int *errp)
+#define EXT4_META_BLOCK 0x1
+
+static ext4_fsblk_t do_blk_alloc(handle_t *handle, struct inode *inode,
+                               ext4_lblk_t iblock, ext4_fsblk_t goal,
+                               unsigned long *count, int *errp, int flags)
 {
        struct ext4_allocation_request ar;
        ext4_fsblk_t ret;
 
        if (!test_opt(inode->i_sb, MBALLOC)) {
-               unsigned long count = 1;
-               ret = ext4_new_blocks_old(handle, inode, goal, &count, errp);
-               return ret;
+               return ext4_old_new_blocks(handle, inode, goal, count, errp);
        }
 
        memset(&ar, 0, sizeof(ar));
+       /* Fill with neighbour allocated blocks */
+
        ar.inode = inode;
        ar.goal = goal;
-       ar.len = 1;
+       ar.len = *count;
+       ar.logical = iblock;
+
+       if (S_ISREG(inode->i_mode) && !(flags & EXT4_META_BLOCK))
+               /* enable in-core preallocation for data block allocation */
+               ar.flags = EXT4_MB_HINT_DATA;
+       else
+               /* disable in-core preallocation for non-regular files */
+               ar.flags = 0;
+
        ret = ext4_mb_new_blocks(handle, &ar, errp);
+       *count = ar.len;
        return ret;
 }
 
-ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode,
+/*
+ * ext4_new_meta_blocks() -- allocate block for meta data (indexing) blocks
+ *
+ * @handle:             handle to this transaction
+ * @inode:              file inode
+ * @goal:               given target block(filesystem wide)
+ * @count:             total number of blocks need
+ * @errp:               error code
+ *
+ * Return 1st allocated block numberon success, *count stores total account
+ * error stores in errp pointer
+ */
+ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode,
                ext4_fsblk_t goal, unsigned long *count, int *errp)
 {
-       struct ext4_allocation_request ar;
        ext4_fsblk_t ret;
-
-       if (!test_opt(inode->i_sb, MBALLOC)) {
-               ret = ext4_new_blocks_old(handle, inode, goal, count, errp);
-               return ret;
+       ret = do_blk_alloc(handle, inode, 0, goal,
+                               count, errp, EXT4_META_BLOCK);
+       /*
+        * Account for the allocated meta blocks
+        */
+       if (!(*errp)) {
+               spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
+               EXT4_I(inode)->i_allocated_meta_blocks += *count;
+               spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
        }
-
-       memset(&ar, 0, sizeof(ar));
-       ar.inode = inode;
-       ar.goal = goal;
-       ar.len = *count;
-       ret = ext4_mb_new_blocks(handle, &ar, errp);
-       *count = ar.len;
        return ret;
 }
 
+/*
+ * ext4_new_meta_block() -- allocate block for meta data (indexing) blocks
+ *
+ * @handle:             handle to this transaction
+ * @inode:              file inode
+ * @goal:               given target block(filesystem wide)
+ * @errp:               error code
+ *
+ * Return allocated block number on success
+ */
+ext4_fsblk_t ext4_new_meta_block(handle_t *handle, struct inode *inode,
+               ext4_fsblk_t goal, int *errp)
+{
+       unsigned long count = 1;
+       return ext4_new_meta_blocks(handle, inode, goal, &count, errp);
+}
+
+/*
+ * ext4_new_blocks() -- allocate data blocks
+ *
+ * @handle:             handle to this transaction
+ * @inode:              file inode
+ * @goal:               given target block(filesystem wide)
+ * @count:             total number of blocks need
+ * @errp:               error code
+ *
+ * Return 1st allocated block numberon success, *count stores total account
+ * error stores in errp pointer
+ */
+
+ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode,
+                               ext4_lblk_t iblock, ext4_fsblk_t goal,
+                               unsigned long *count, int *errp)
+{
+       return do_blk_alloc(handle, inode, iblock, goal, count, errp, 0);
+}
 
 /**
  * ext4_count_free_blocks() -- count filesystem free blocks
@@ -1986,7 +2136,7 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
                        continue;
                desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
                brelse(bitmap_bh);
-               bitmap_bh = read_block_bitmap(sb, i);
+               bitmap_bh = ext4_read_block_bitmap(sb, i);
                if (bitmap_bh == NULL)
                        continue;
 
@@ -1996,10 +2146,9 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
                bitmap_count += x;
        }
        brelse(bitmap_bh);
-       printk("ext4_count_free_blocks: stored = %llu"
-               ", computed = %llu, %llu\n",
-               ext4_free_blocks_count(es),
-               desc_count, bitmap_count);
+       printk(KERN_DEBUG "ext4_count_free_blocks: stored = %llu"
+               ", computed = %llu, %llu\n", ext4_free_blocks_count(es),
+              desc_count, bitmap_count);
        return bitmap_count;
 #else
        desc_count = 0;
@@ -2086,7 +2235,7 @@ unsigned long ext4_bg_num_gdb(struct super_block *sb, ext4_group_t group)
 
        if (!EXT4_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_META_BG) ||
                        metagroup < first_meta_bg)
-               return ext4_bg_num_gdb_nometa(sb,group);
+               return ext4_bg_num_gdb_nometa(sb, group);
 
        return ext4_bg_num_gdb_meta(sb,group);