Fix ext4_ext_find_extent() to already pre-allocate ext4_ext_path[] array of the max depth instead of current depth. This will avoid racy cases of concurrent ext_depth() growth in current and unsafe implementation with ext4_ext_path[] array re-[sizing,allocation], even with more recent and related patches that will be integrated in more recent Kernels. Index: linux-2.6.32-504.el6.x86_64/fs/ext4/ext4.h =================================================================== --- linux-2.6.32-504.el6.x86_64.orig/fs/ext4/ext4.h +++ linux-2.6.32-504.el6.x86_64/fs/ext4/ext4.h @@ -1147,6 +1147,9 @@ unsigned long s_ext_extents; #endif + /* maximum possible extents tree depth, to be computed at mount time */ + unsigned int s_max_ext_tree_depth; + /* for buddy allocator */ struct ext4_group_info ***s_group_info; struct inode *s_buddy_cache; Index: linux-2.6.32-504.el6.x86_64/fs/ext4/super.c =================================================================== --- linux-2.6.32-504.el6.x86_64.orig/fs/ext4/super.c +++ linux-2.6.32-504.el6.x86_64/fs/ext4/super.c @@ -4038,6 +4038,8 @@ if (ext4_multi_mount_protect(sb, le64_to_cpu(es->s_mmp_block))) goto failed_mount3; + ext4_ext_init(sb); /* needed before using extent-mapped journal */ + /* * The first inode we look at is the journal inode. Don't try * root first: it may be modified in the journal! @@ -4200,7 +4202,6 @@ goto failed_mount4a; } - ext4_ext_init(sb); err = ext4_mb_init(sb); if (err) { ext4_msg(sb, KERN_ERR, "failed to initialize mballoc (%d)", Index: linux-2.6.32-504.el6.x86_64/fs/ext4/extents.c =================================================================== --- linux-2.6.32-504.el6.x86_64.orig/fs/ext4/extents.c +++ linux-2.6.32-504.el6.x86_64/fs/ext4/extents.c @@ -699,8 +699,9 @@ /* account possible depth increase */ if (!path) { - path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 2), - GFP_NOFS); + path = kzalloc(sizeof(struct ext4_ext_path) * + EXT4_SB(inode->i_sb)->s_max_ext_tree_depth, + GFP_NOFS); if (!path) return ERR_PTR(-ENOMEM); alloc = 1; @@ -1915,11 +1916,8 @@ /* find extent for this block */ down_read(&EXT4_I(inode)->i_data_sem); - if (path && ext_depth(inode) != depth) { - /* depth was changed. we have to realloc path */ - kfree(path); - path = NULL; - } + /* path of max possible depth will be allocated during + * first pass, so its space can be re-used for each loop */ path = ext4_ext_find_extent(inode, block, path); if (IS_ERR(path)) { @@ -2664,8 +2662,9 @@ path[k].p_block = le16_to_cpu(path[k].p_hdr->eh_entries)+1; } else { - path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1), - GFP_NOFS); + path = kzalloc(sizeof(struct ext4_ext_path) * + EXT4_SB(inode->i_sb)->s_max_ext_tree_depth, + GFP_NOFS); if (path == NULL) { ext4_journal_stop(handle); return -ENOMEM; @@ -3048,13 +3034,14 @@ */ void ext4_ext_init(struct super_block *sb) { + ext4_fsblk_t maxblocks; + /* * possible initialization would be here */ if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) { -#if defined(AGGRESSIVE_TEST) || defined(CHECK_BINSEARCH) || defined(EXTENTS_STATS) - printk(KERN_INFO "EXT4-fs: file extents enabled" + printk(KERN_INFO "EXT4-fs (%s): file extents enabled" #ifdef AGGRESSIVE_TEST ", aggressive tests" #endif @@ -3064,8 +3051,31 @@ #ifdef EXTENTS_STATS ", stats" #endif - "\n"); -#endif + , sb->s_id); + EXT4_SB(sb)->s_max_ext_tree_depth = 1; + + maxblocks = sb->s_maxbytes / sb->s_blocksize; + + /* 1st/root level/node of extents tree stands in i_data and + * entries stored in tree nodes can be of type ext4_extent + * (leaf node) or ext4_extent_idx (internal node) */ + maxblocks /= (sizeof(((struct ext4_inode_info *)0x0)->i_data) - + sizeof(struct ext4_extent_header)) / + max(sizeof(struct ext4_extent), + sizeof(struct ext4_extent_idx)); + + /* compute maximum extents tree depth for a fully populated + * file of max size made of only minimal/1-block extents */ + while (maxblocks > 0) { + maxblocks /= (sb->s_blocksize - + sizeof(struct ext4_extent_header)) / + max(sizeof(struct ext4_extent), + sizeof(struct ext4_extent_idx)); + EXT4_SB(sb)->s_max_ext_tree_depth++; + } + + printk(", maximum tree depth=%u\n", + EXT4_SB(sb)->s_max_ext_tree_depth); #ifdef EXTENTS_STATS spin_lock_init(&EXT4_SB(sb)->s_ext_stats_lock); EXT4_SB(sb)->s_ext_min = 1 << 30;