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-stage/fs/ext4/ext4.h =================================================================== --- linux-stage.orig/fs/ext4/ext4.h 2016-07-15 10:55:51.000000000 +0300 +++ linux-stage/fs/ext4/ext4.h 2016-07-15 10:56:19.000000000 +0300 @@ -1153,6 +1153,9 @@ struct ext4_sb_info { 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-stage/fs/ext4/extents.c =================================================================== --- linux-stage.orig/fs/ext4/extents.c 2016-07-15 10:55:51.000000000 +0300 +++ linux-stage/fs/ext4/extents.c 2016-07-15 10:56:19.000000000 +0300 @@ -698,8 +698,9 @@ ext4_ext_find_extent(struct inode *inode /* 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; @@ -1907,11 +1908,8 @@ static int ext4_fill_fiemap_extents(stru /* 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)) { @@ -2656,7 +2654,8 @@ again: path[k].p_block = le16_to_cpu(path[k].p_hdr->eh_entries)+1; } else { - path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1), + 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); @@ -2781,13 +2780,15 @@ out: */ 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", + sb->s_id); #ifdef AGGRESSIVE_TEST printk(", aggressive tests"); #endif @@ -2796,14 +2797,35 @@ void ext4_ext_init(struct super_block *s #endif #ifdef EXTENTS_STATS printk(", stats"); -#endif - printk("\n"); -#endif -#ifdef EXTENTS_STATS spin_lock_init(&EXT4_SB(sb)->s_ext_stats_lock); EXT4_SB(sb)->s_ext_min = 1 << 30; EXT4_SB(sb)->s_ext_max = 0; #endif + 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", + EXT4_SB(sb)->s_max_ext_tree_depth); + printk("\n"); } } Index: linux-stage/fs/ext4/super.c =================================================================== --- linux-stage.orig/fs/ext4/super.c 2016-07-15 10:55:51.000000000 +0300 +++ linux-stage/fs/ext4/super.c 2016-07-15 10:56:19.000000000 +0300 @@ -3529,6 +3529,8 @@ static int ext4_fill_super(struct super_ 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! @@ -3722,7 +3724,6 @@ no_journal: goto failed_mount4a; } - ext4_ext_init(sb); err = ext4_mb_init(sb, needs_recovery); if (err) { ext4_msg(sb, KERN_ERR, "failed to initalize mballoc (%d)",