ext4: Add a tracepoint for ext4_alloc_da_blocks()
[safe/jmp/linux-2.6] / fs / ext4 / mballoc.c
index cf99720..e9c6189 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include "mballoc.h"
+#include <linux/debugfs.h>
 #include <trace/events/ext4.h>
 
 /*
@@ -622,13 +623,13 @@ static int __mb_check_buddy(struct ext4_buddy *e4b, char *file,
 
 /* FIXME!! need more doc */
 static void ext4_mb_mark_free_simple(struct super_block *sb,
-                               void *buddy, unsigned first, int len,
+                               void *buddy, ext4_grpblk_t first, ext4_grpblk_t len,
                                        struct ext4_group_info *grp)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
-       unsigned short min;
-       unsigned short max;
-       unsigned short chunk;
+       ext4_grpblk_t min;
+       ext4_grpblk_t max;
+       ext4_grpblk_t chunk;
        unsigned short border;
 
        BUG_ON(len > EXT4_BLOCKS_PER_GROUP(sb));
@@ -662,10 +663,10 @@ void ext4_mb_generate_buddy(struct super_block *sb,
                                void *buddy, void *bitmap, ext4_group_t group)
 {
        struct ext4_group_info *grp = ext4_get_group_info(sb, group);
-       unsigned short max = EXT4_BLOCKS_PER_GROUP(sb);
-       unsigned short i = 0;
-       unsigned short first;
-       unsigned short len;
+       ext4_grpblk_t max = EXT4_BLOCKS_PER_GROUP(sb);
+       ext4_grpblk_t i = 0;
+       ext4_grpblk_t first;
+       ext4_grpblk_t len;
        unsigned free = 0;
        unsigned fragments = 0;
        unsigned long long period = get_cycles();
@@ -743,7 +744,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
        char *data;
        char *bitmap;
 
-       mb_debug("init page %lu\n", page->index);
+       mb_debug(1, "init page %lu\n", page->index);
 
        inode = page->mapping->host;
        sb = inode->i_sb;
@@ -822,7 +823,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
                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);
+               mb_debug(1, "read bitmap for group %u\n", first_group + i);
        }
 
        /* wait for I/O completion */
@@ -862,12 +863,13 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
                if ((first_block + i) & 1) {
                        /* this is block of buddy */
                        BUG_ON(incore == NULL);
-                       mb_debug("put buddy for group %u in page %lu/%x\n",
+                       mb_debug(1, "put buddy for group %u in page %lu/%x\n",
                                group, page->index, i * blocksize);
                        grinfo = ext4_get_group_info(sb, group);
                        grinfo->bb_fragments = 0;
                        memset(grinfo->bb_counters, 0,
-                              sizeof(unsigned short)*(sb->s_blocksize_bits+2));
+                              sizeof(*grinfo->bb_counters) *
+                               (sb->s_blocksize_bits+2));
                        /*
                         * incore got set to the group block bitmap below
                         */
@@ -878,7 +880,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
                } else {
                        /* this is block of bitmap */
                        BUG_ON(incore != NULL);
-                       mb_debug("put bitmap for group %u in page %lu/%x\n",
+                       mb_debug(1, "put bitmap for group %u in page %lu/%x\n",
                                group, page->index, i * blocksize);
 
                        /* see comments in ext4_mb_put_pa() */
@@ -908,6 +910,100 @@ out:
        return err;
 }
 
+static noinline_for_stack
+int ext4_mb_init_group(struct super_block *sb, ext4_group_t group)
+{
+
+       int ret = 0;
+       void *bitmap;
+       int blocks_per_page;
+       int block, pnum, poff;
+       int num_grp_locked = 0;
+       struct ext4_group_info *this_grp;
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       struct inode *inode = sbi->s_buddy_cache;
+       struct page *page = NULL, *bitmap_page = NULL;
+
+       mb_debug(1, "init group %u\n", group);
+       blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize;
+       this_grp = ext4_get_group_info(sb, group);
+       /*
+        * This ensures that we don't reinit the buddy cache
+        * page which map to the group from which we are already
+        * allocating. If we are looking at the buddy cache we would
+        * have taken a reference using ext4_mb_load_buddy and that
+        * would have taken the alloc_sem lock.
+        */
+       num_grp_locked =  ext4_mb_get_buddy_cache_lock(sb, group);
+       if (!EXT4_MB_GRP_NEED_INIT(this_grp)) {
+               /*
+                * somebody initialized the group
+                * return without doing anything
+                */
+               ret = 0;
+               goto err;
+       }
+       /*
+        * the buddy cache inode stores the block bitmap
+        * and buddy information in consecutive blocks.
+        * So for each group we need two blocks.
+        */
+       block = group * 2;
+       pnum = block / blocks_per_page;
+       poff = block % blocks_per_page;
+       page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS);
+       if (page) {
+               BUG_ON(page->mapping != inode->i_mapping);
+               ret = ext4_mb_init_cache(page, NULL);
+               if (ret) {
+                       unlock_page(page);
+                       goto err;
+               }
+               unlock_page(page);
+       }
+       if (page == NULL || !PageUptodate(page)) {
+               ret = -EIO;
+               goto err;
+       }
+       mark_page_accessed(page);
+       bitmap_page = page;
+       bitmap = page_address(page) + (poff * sb->s_blocksize);
+
+       /* init buddy cache */
+       block++;
+       pnum = block / blocks_per_page;
+       poff = block % blocks_per_page;
+       page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS);
+       if (page == bitmap_page) {
+               /*
+                * If both the bitmap and buddy are in
+                * the same page we don't need to force
+                * init the buddy
+                */
+               unlock_page(page);
+       } else if (page) {
+               BUG_ON(page->mapping != inode->i_mapping);
+               ret = ext4_mb_init_cache(page, bitmap);
+               if (ret) {
+                       unlock_page(page);
+                       goto err;
+               }
+               unlock_page(page);
+       }
+       if (page == NULL || !PageUptodate(page)) {
+               ret = -EIO;
+               goto err;
+       }
+       mark_page_accessed(page);
+err:
+       ext4_mb_put_buddy_cache_lock(sb, group, num_grp_locked);
+       if (bitmap_page)
+               page_cache_release(bitmap_page);
+       if (page)
+               page_cache_release(page);
+       return ret;
+}
+
 static noinline_for_stack int
 ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
                                        struct ext4_buddy *e4b)
@@ -922,7 +1018,7 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct inode *inode = sbi->s_buddy_cache;
 
-       mb_debug("load group %u\n", group);
+       mb_debug(1, "load group %u\n", group);
 
        blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize;
        grp = ext4_get_group_info(sb, group);
@@ -941,8 +1037,26 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
         * groups mapped by the page is blocked
         * till we are done with allocation
         */
+repeat_load_buddy:
        down_read(e4b->alloc_semp);
 
+       if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) {
+               /* we need to check for group need init flag
+                * with alloc_semp held so that we can be sure
+                * that new blocks didn't get added to the group
+                * when we are loading the buddy cache
+                */
+               up_read(e4b->alloc_semp);
+               /*
+                * we need full data about the group
+                * to make a good selection
+                */
+               ret = ext4_mb_init_group(sb, group);
+               if (ret)
+                       return ret;
+               goto repeat_load_buddy;
+       }
+
        /*
         * the buddy cache inode stores the block bitmap
         * and buddy information in consecutive blocks.
@@ -1360,7 +1474,7 @@ static void ext4_mb_use_best_found(struct ext4_allocation_context *ac,
        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)) {
+       if (ac->ac_flags & EXT4_MB_STREAM_ALLOC) {
                spin_lock(&sbi->s_md_lock);
                sbi->s_mb_last_group = ac->ac_f_ex.fe_group;
                sbi->s_mb_last_start = ac->ac_f_ex.fe_start;
@@ -1837,97 +1951,6 @@ void ext4_mb_put_buddy_cache_lock(struct super_block *sb,
 
 }
 
-static noinline_for_stack
-int ext4_mb_init_group(struct super_block *sb, ext4_group_t group)
-{
-
-       int ret;
-       void *bitmap;
-       int blocks_per_page;
-       int block, pnum, poff;
-       int num_grp_locked = 0;
-       struct ext4_group_info *this_grp;
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
-       struct inode *inode = sbi->s_buddy_cache;
-       struct page *page = NULL, *bitmap_page = NULL;
-
-       mb_debug("init group %lu\n", group);
-       blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize;
-       this_grp = ext4_get_group_info(sb, group);
-       /*
-        * This ensures we don't add group
-        * to this buddy cache via resize
-        */
-       num_grp_locked =  ext4_mb_get_buddy_cache_lock(sb, group);
-       if (!EXT4_MB_GRP_NEED_INIT(this_grp)) {
-               /*
-                * somebody initialized the group
-                * return without doing anything
-                */
-               ret = 0;
-               goto err;
-       }
-       /*
-        * the buddy cache inode stores the block bitmap
-        * and buddy information in consecutive blocks.
-        * So for each group we need two blocks.
-        */
-       block = group * 2;
-       pnum = block / blocks_per_page;
-       poff = block % blocks_per_page;
-       page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS);
-       if (page) {
-               BUG_ON(page->mapping != inode->i_mapping);
-               ret = ext4_mb_init_cache(page, NULL);
-               if (ret) {
-                       unlock_page(page);
-                       goto err;
-               }
-               unlock_page(page);
-       }
-       if (page == NULL || !PageUptodate(page)) {
-               ret = -EIO;
-               goto err;
-       }
-       mark_page_accessed(page);
-       bitmap_page = page;
-       bitmap = page_address(page) + (poff * sb->s_blocksize);
-
-       /* init buddy cache */
-       block++;
-       pnum = block / blocks_per_page;
-       poff = block % blocks_per_page;
-       page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS);
-       if (page == bitmap_page) {
-               /*
-                * If both the bitmap and buddy are in
-                * the same page we don't need to force
-                * init the buddy
-                */
-               unlock_page(page);
-       } else if (page) {
-               BUG_ON(page->mapping != inode->i_mapping);
-               ret = ext4_mb_init_cache(page, bitmap);
-               if (ret) {
-                       unlock_page(page);
-                       goto err;
-               }
-               unlock_page(page);
-       }
-       if (page == NULL || !PageUptodate(page)) {
-               ret = -EIO;
-               goto err;
-       }
-       mark_page_accessed(page);
-err:
-       ext4_mb_put_buddy_cache_lock(sb, group, num_grp_locked);
-       if (bitmap_page)
-               page_cache_release(bitmap_page);
-       if (page)
-               page_cache_release(page);
-       return ret;
-}
-
 static noinline_for_stack int
 ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
 {
@@ -1938,11 +1961,14 @@ ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
        struct ext4_sb_info *sbi;
        struct super_block *sb;
        struct ext4_buddy e4b;
-       loff_t size, isize;
 
        sb = ac->ac_sb;
        sbi = EXT4_SB(sb);
        ngroups = ext4_get_groups_count(sb);
+       /* non-extent files are limited to low blocks/groups */
+       if (!(EXT4_I(ac->ac_inode)->i_flags & EXT4_EXTENTS_FL))
+               ngroups = sbi->s_blockfile_groups;
+
        BUG_ON(ac->ac_status == AC_STATUS_FOUND);
 
        /* first, try the goal */
@@ -1974,20 +2000,16 @@ ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
        }
 
        bsbits = ac->ac_sb->s_blocksize_bits;
-       /* if stream allocation is enabled, use global goal */
-       size = ac->ac_o_ex.fe_logical + ac->ac_o_ex.fe_len;
-       isize = i_size_read(ac->ac_inode) >> bsbits;
-       if (size < isize)
-               size = isize;
 
-       if (size < sbi->s_mb_stream_request &&
-                       (ac->ac_flags & EXT4_MB_HINT_DATA)) {
+       /* if stream allocation is enabled, use global goal */
+       if (ac->ac_flags & EXT4_MB_STREAM_ALLOC) {
                /* TBD: may be hot point */
                spin_lock(&sbi->s_md_lock);
                ac->ac_g_ex.fe_group = sbi->s_mb_last_group;
                ac->ac_g_ex.fe_start = sbi->s_mb_last_start;
                spin_unlock(&sbi->s_md_lock);
        }
+
        /* Let's just scan groups to find more-less suitable blocks */
        cr = ac->ac_2order ? 0 : 1;
        /*
@@ -2015,27 +2037,6 @@ repeat:
                        if (grp->bb_free == 0)
                                continue;
 
-                       /*
-                        * if the group is already init we check whether it is
-                        * a good group and if not we don't load the buddy
-                        */
-                       if (EXT4_MB_GRP_NEED_INIT(grp)) {
-                               /*
-                                * we need full data about the group
-                                * to make a good selection
-                                */
-                               err = ext4_mb_init_group(sb, group);
-                               if (err)
-                                       goto out;
-                       }
-
-                       /*
-                        * If the particular group doesn't satisfy our
-                        * criteria we continue with the next group
-                        */
-                       if (!ext4_mb_good_group(ac, group, cr))
-                               continue;
-
                        err = ext4_mb_load_buddy(sb, group, &e4b);
                        if (err)
                                goto out;
@@ -2156,7 +2157,7 @@ static int ext4_mb_seq_history_show(struct seq_file *seq, void *v)
 
        if (v == SEQ_START_TOKEN) {
                seq_printf(seq, "%-5s %-8s %-23s %-23s %-23s %-5s "
-                               "%-5s %-2s %-5s %-5s %-5s %-6s\n",
+                               "%-5s %-2s %-6s %-5s %-5s %-6s\n",
                          "pid", "inode", "original", "goal", "result", "found",
                           "grps", "cr", "flags", "merge", "tail", "broken");
                return 0;
@@ -2164,7 +2165,7 @@ static int ext4_mb_seq_history_show(struct seq_file *seq, void *v)
 
        if (hs->op == EXT4_MB_HISTORY_ALLOC) {
                fmt = "%-5u %-8u %-23s %-23s %-23s %-5u %-5u %-2u "
-                       "%-5u %-5s %-5u %-6u\n";
+                       "0x%04x %-5s %-5u %-6u\n";
                sprintf(buf2, "%u/%d/%u@%u", hs->result.fe_group,
                        hs->result.fe_start, hs->result.fe_len,
                        hs->result.fe_logical);
@@ -2205,7 +2206,7 @@ static void ext4_mb_seq_history_stop(struct seq_file *seq, void *v)
 {
 }
 
-static struct seq_operations ext4_mb_seq_history_ops = {
+static const struct seq_operations ext4_mb_seq_history_ops = {
        .start  = ext4_mb_seq_history_start,
        .next   = ext4_mb_seq_history_next,
        .stop   = ext4_mb_seq_history_stop,
@@ -2287,7 +2288,7 @@ static ssize_t ext4_mb_seq_history_write(struct file *file,
        return count;
 }
 
-static struct file_operations ext4_mb_seq_history_fops = {
+static const struct file_operations ext4_mb_seq_history_fops = {
        .owner          = THIS_MODULE,
        .open           = ext4_mb_seq_history_open,
        .read           = seq_read,
@@ -2328,7 +2329,7 @@ static int ext4_mb_seq_groups_show(struct seq_file *seq, void *v)
        struct ext4_buddy e4b;
        struct sg {
                struct ext4_group_info info;
-               unsigned short counters[16];
+               ext4_grpblk_t counters[16];
        } sg;
 
        group--;
@@ -2366,7 +2367,7 @@ static void ext4_mb_seq_groups_stop(struct seq_file *seq, void *v)
 {
 }
 
-static struct seq_operations ext4_mb_seq_groups_ops = {
+static const struct seq_operations ext4_mb_seq_groups_ops = {
        .start  = ext4_mb_seq_groups_start,
        .next   = ext4_mb_seq_groups_next,
        .stop   = ext4_mb_seq_groups_stop,
@@ -2387,7 +2388,7 @@ static int ext4_mb_seq_groups_open(struct inode *inode, struct file *file)
 
 }
 
-static struct file_operations ext4_mb_seq_groups_fops = {
+static const struct file_operations ext4_mb_seq_groups_fops = {
        .owner          = THIS_MODULE,
        .open           = ext4_mb_seq_groups_open,
        .read           = seq_read,
@@ -2532,7 +2533,7 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
 
        INIT_LIST_HEAD(&meta_group_info[i]->bb_prealloc_list);
        init_rwsem(&meta_group_info[i]->alloc_sem);
-       meta_group_info[i]->bb_free_root.rb_node = NULL;;
+       meta_group_info[i]->bb_free_root.rb_node = NULL;
 
 #ifdef DOUBLE_CHECK
        {
@@ -2558,15 +2559,6 @@ exit_meta_group_info:
        return -ENOMEM;
 } /* ext4_mb_add_groupinfo */
 
-/*
- * 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 ngroups = ext4_get_groups_count(sb);
@@ -2653,14 +2645,14 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
        unsigned max;
        int ret;
 
-       i = (sb->s_blocksize_bits + 2) * sizeof(unsigned short);
+       i = (sb->s_blocksize_bits + 2) * sizeof(*sbi->s_mb_offsets);
 
        sbi->s_mb_offsets = kmalloc(i, GFP_KERNEL);
        if (sbi->s_mb_offsets == NULL) {
                return -ENOMEM;
        }
 
-       i = (sb->s_blocksize_bits + 2) * sizeof(unsigned int);
+       i = (sb->s_blocksize_bits + 2) * sizeof(*sbi->s_mb_maxs);
        sbi->s_mb_maxs = kmalloc(i, GFP_KERNEL);
        if (sbi->s_mb_maxs == NULL) {
                kfree(sbi->s_mb_offsets);
@@ -2739,7 +2731,7 @@ static void ext4_mb_cleanup_pa(struct ext4_group_info *grp)
                kmem_cache_free(ext4_pspace_cachep, pa);
        }
        if (count)
-               mb_debug("mballoc: %u PAs left\n", count);
+               mb_debug(1, "mballoc: %u PAs left\n", count);
 
 }
 
@@ -2820,7 +2812,7 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)
        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 %u (0x%p):",
+               mb_debug(1, "gonna free %u blocks in group %u (0x%p):",
                         entry->count, entry->group, entry);
 
                err = ext4_mb_load_buddy(sb, entry->group, &e4b);
@@ -2855,9 +2847,43 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)
                ext4_mb_release_desc(&e4b);
        }
 
-       mb_debug("freed %u blocks in %u structures\n", count, count2);
+       mb_debug(1, "freed %u blocks in %u structures\n", count, count2);
+}
+
+#ifdef CONFIG_EXT4_DEBUG
+u8 mb_enable_debug __read_mostly;
+
+static struct dentry *debugfs_dir;
+static struct dentry *debugfs_debug;
+
+static void __init ext4_create_debugfs_entry(void)
+{
+       debugfs_dir = debugfs_create_dir("ext4", NULL);
+       if (debugfs_dir)
+               debugfs_debug = debugfs_create_u8("mballoc-debug",
+                                                 S_IRUGO | S_IWUSR,
+                                                 debugfs_dir,
+                                                 &mb_enable_debug);
+}
+
+static void ext4_remove_debugfs_entry(void)
+{
+       debugfs_remove(debugfs_debug);
+       debugfs_remove(debugfs_dir);
 }
 
+#else
+
+static void __init ext4_create_debugfs_entry(void)
+{
+}
+
+static void ext4_remove_debugfs_entry(void)
+{
+}
+
+#endif
+
 int __init init_ext4_mballoc(void)
 {
        ext4_pspace_cachep =
@@ -2885,6 +2911,7 @@ int __init init_ext4_mballoc(void)
                kmem_cache_destroy(ext4_ac_cachep);
                return -ENOMEM;
        }
+       ext4_create_debugfs_entry();
        return 0;
 }
 
@@ -2898,6 +2925,7 @@ void exit_ext4_mballoc(void)
        kmem_cache_destroy(ext4_pspace_cachep);
        kmem_cache_destroy(ext4_ac_cachep);
        kmem_cache_destroy(ext4_free_ext_cachep);
+       ext4_remove_debugfs_entry();
 }
 
 
@@ -3042,7 +3070,7 @@ static void ext4_mb_normalize_group_request(struct ext4_allocation_context *ac)
                ac->ac_g_ex.fe_len = EXT4_SB(sb)->s_stripe;
        else
                ac->ac_g_ex.fe_len = EXT4_SB(sb)->s_mb_group_prealloc;
-       mb_debug("#%u: goal %u blocks for locality group\n",
+       mb_debug(1, "#%u: goal %u blocks for locality group\n",
                current->pid, ac->ac_g_ex.fe_len);
 }
 
@@ -3161,23 +3189,18 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac,
                BUG_ON(!(ac->ac_o_ex.fe_logical >= pa_end ||
                        ac->ac_o_ex.fe_logical < pa->pa_lstart));
 
-               /* skip PA normalized request doesn't overlap with */
-               if (pa->pa_lstart >= end) {
-                       spin_unlock(&pa->pa_lock);
-                       continue;
-               }
-               if (pa_end <= start) {
+               /* skip PAs this normalized request doesn't overlap with */
+               if (pa->pa_lstart >= end || pa_end <= start) {
                        spin_unlock(&pa->pa_lock);
                        continue;
                }
                BUG_ON(pa->pa_lstart <= start && pa_end >= end);
 
+               /* adjust start or end to be adjacent to this pa */
                if (pa_end <= ac->ac_o_ex.fe_logical) {
                        BUG_ON(pa_end < start);
                        start = pa_end;
-               }
-
-               if (pa->pa_lstart > ac->ac_o_ex.fe_logical) {
+               } else if (pa->pa_lstart > ac->ac_o_ex.fe_logical) {
                        BUG_ON(pa->pa_lstart > end);
                        end = pa->pa_lstart;
                }
@@ -3232,7 +3255,7 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac,
                ac->ac_flags |= EXT4_MB_HINT_TRY_GOAL;
        }
 
-       mb_debug("goal: %u(was %u) blocks at %u\n", (unsigned) size,
+       mb_debug(1, "goal: %u(was %u) blocks at %u\n", (unsigned) size,
                (unsigned) orig_size, (unsigned) start);
 }
 
@@ -3281,7 +3304,7 @@ static void ext4_mb_use_inode_pa(struct ext4_allocation_context *ac,
        BUG_ON(pa->pa_free < len);
        pa->pa_free -= len;
 
-       mb_debug("use %llu/%u from inode pa %p\n", start, len, pa);
+       mb_debug(1, "use %llu/%u from inode pa %p\n", start, len, pa);
 }
 
 /*
@@ -3305,7 +3328,7 @@ static void ext4_mb_use_group_pa(struct ext4_allocation_context *ac,
         * in on-disk bitmap -- see ext4_mb_release_context()
         * Other CPUs are prevented from allocating from this pa by lg_mutex
         */
-       mb_debug("use %u/%u from group pa %p\n", pa->pa_lstart-len, len, pa);
+       mb_debug(1, "use %u/%u from group pa %p\n", pa->pa_lstart-len, len, pa);
 }
 
 /*
@@ -3363,6 +3386,11 @@ ext4_mb_use_preallocated(struct ext4_allocation_context *ac)
                        ac->ac_o_ex.fe_logical >= pa->pa_lstart + pa->pa_len)
                        continue;
 
+               /* non-extent files can't have physical blocks past 2^32 */
+               if (!(EXT4_I(ac->ac_inode)->i_flags & EXT4_EXTENTS_FL) &&
+                       pa->pa_pstart + pa->pa_len > EXT4_MAX_BLOCK_FILE_PHYS)
+                       continue;
+
                /* found preallocated blocks, use them */
                spin_lock(&pa->pa_lock);
                if (pa->pa_deleted == 0 && pa->pa_free) {
@@ -3484,7 +3512,7 @@ void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
                preallocated += len;
                count++;
        }
-       mb_debug("prellocated %u for group %u\n", preallocated, group);
+       mb_debug(1, "prellocated %u for group %u\n", preallocated, group);
 }
 
 static void ext4_mb_pa_callback(struct rcu_head *head)
@@ -3619,7 +3647,7 @@ ext4_mb_new_inode_pa(struct ext4_allocation_context *ac)
        pa->pa_deleted = 0;
        pa->pa_type = MB_INODE_PA;
 
-       mb_debug("new inode pa %p: %llu/%u for %u\n", pa,
+       mb_debug(1, "new inode pa %p: %llu/%u for %u\n", pa,
                        pa->pa_pstart, pa->pa_len, pa->pa_lstart);
        trace_ext4_mb_new_inode_pa(ac, pa);
 
@@ -3679,7 +3707,7 @@ ext4_mb_new_group_pa(struct ext4_allocation_context *ac)
        pa->pa_deleted = 0;
        pa->pa_type = MB_GROUP_PA;
 
-       mb_debug("new group pa %p: %llu/%u for %u\n", pa,
+       mb_debug(1, "new group pa %p: %llu/%u for %u\n", pa,
                        pa->pa_pstart, pa->pa_len, pa->pa_lstart);
        trace_ext4_mb_new_group_pa(ac, pa);
 
@@ -3758,7 +3786,7 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
                next = mb_find_next_bit(bitmap_bh->b_data, end, bit);
                start = group * EXT4_BLOCKS_PER_GROUP(sb) + bit +
                                le32_to_cpu(sbi->s_es->s_first_data_block);
-               mb_debug("    free preallocated %u/%u in group %u\n",
+               mb_debug(1, "    free preallocated %u/%u in group %u\n",
                                (unsigned) start, (unsigned) next - bit,
                                (unsigned) group);
                free += next - bit;
@@ -3849,7 +3877,7 @@ ext4_mb_discard_group_preallocations(struct super_block *sb,
        int busy = 0;
        int free = 0;
 
-       mb_debug("discard preallocation for group %u\n", group);
+       mb_debug(1, "discard preallocation for group %u\n", group);
 
        if (list_empty(&grp->bb_prealloc_list))
                return 0;
@@ -3973,7 +4001,7 @@ void ext4_discard_preallocations(struct inode *inode)
                return;
        }
 
-       mb_debug("discard preallocation for inode %lu\n", inode->i_ino);
+       mb_debug(1, "discard preallocation for inode %lu\n", inode->i_ino);
        trace_ext4_discard_preallocations(inode);
 
        INIT_LIST_HEAD(&list);
@@ -4078,7 +4106,7 @@ static void ext4_mb_return_to_preallocation(struct inode *inode,
 {
        BUG_ON(!list_empty(&EXT4_I(inode)->i_prealloc_list));
 }
-#ifdef MB_DEBUG
+#ifdef CONFIG_EXT4_DEBUG
 static void ext4_mb_show_ac(struct ext4_allocation_context *ac)
 {
        struct super_block *sb = ac->ac_sb;
@@ -4120,14 +4148,14 @@ static void ext4_mb_show_ac(struct ext4_allocation_context *ac)
                        ext4_get_group_no_and_offset(sb, pa->pa_pstart,
                                                     NULL, &start);
                        spin_unlock(&pa->pa_lock);
-                       printk(KERN_ERR "PA:%lu:%d:%u \n", i,
-                                                       start, pa->pa_len);
+                       printk(KERN_ERR "PA:%u:%d:%u \n", i,
+                              start, pa->pa_len);
                }
                ext4_unlock_group(sb, i);
 
                if (grp->bb_free == 0)
                        continue;
-               printk(KERN_ERR "%lu: %d/%d \n",
+               printk(KERN_ERR "%u: %d/%d \n",
                       i, grp->bb_free, grp->bb_fragments);
        }
        printk(KERN_ERR "\n");
@@ -4155,16 +4183,26 @@ static void ext4_mb_group_or_file(struct ext4_allocation_context *ac)
        if (!(ac->ac_flags & EXT4_MB_HINT_DATA))
                return;
 
+       if (unlikely(ac->ac_flags & EXT4_MB_HINT_GOAL_ONLY))
+               return;
+
        size = ac->ac_o_ex.fe_logical + ac->ac_o_ex.fe_len;
-       isize = i_size_read(ac->ac_inode) >> bsbits;
+       isize = (i_size_read(ac->ac_inode) + ac->ac_sb->s_blocksize - 1)
+               >> bsbits;
        size = max(size, isize);
 
-       /* don't use group allocation for large files */
-       if (size >= sbi->s_mb_stream_request)
+       if ((size == isize) &&
+           !ext4_fs_is_busy(sbi) &&
+           (atomic_read(&ac->ac_inode->i_writecount) == 0)) {
+               ac->ac_flags |= EXT4_MB_HINT_NOPREALLOC;
                return;
+       }
 
-       if (unlikely(ac->ac_flags & EXT4_MB_HINT_GOAL_ONLY))
+       /* don't use group allocation for large files */
+       if (size >= sbi->s_mb_stream_request) {
+               ac->ac_flags |= EXT4_MB_STREAM_ALLOC;
                return;
+       }
 
        BUG_ON(ac->ac_lg != NULL);
        /*
@@ -4227,7 +4265,7 @@ ext4_mb_initialize_context(struct ext4_allocation_context *ac,
         * locality group. this is a policy, actually */
        ext4_mb_group_or_file(ac);
 
-       mb_debug("init ac: %u blocks @ %u, goal %u, flags %x, 2^%d, "
+       mb_debug(1, "init ac: %u blocks @ %u, goal %u, flags %x, 2^%d, "
                        "left: %u/%u, right %u/%u to %swritable\n",
                        (unsigned) ar->len, (unsigned) ar->logical,
                        (unsigned) ar->goal, ac->ac_flags, ac->ac_2order,
@@ -4249,7 +4287,7 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb,
        struct ext4_prealloc_space *pa, *tmp;
        struct ext4_allocation_context *ac;
 
-       mb_debug("discard locality group preallocation\n");
+       mb_debug(1, "discard locality group preallocation\n");
 
        INIT_LIST_HEAD(&discard_list);
        ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);