ext4: allocate struct ext4_allocation_context from a kmem cache

struct ext4_allocation_context is rather large, and this bloats
the stack of many functions which use it. Allocating it from
a named slab cache will alleviate this.

For example, with this change (on top of the noinline patch sent earlier):

-ext4_mb_new_blocks 200
+ext4_mb_new_blocks 40

-ext4_mb_free_blocks 344
+ext4_mb_free_blocks 168

-ext4_mb_release_inode_pa 216
+ext4_mb_release_inode_pa 40

-ext4_mb_release_group_pa 192
+ext4_mb_release_group_pa 24

Most of these stack-allocated structs are actually used only for
mballoc history; and in those cases often a smaller struct would do.
So changing that may be another way around it, at least for those
functions, if preferred. For now, in those cases where the ac
is only for history, an allocation failure simply skips the history
recording, and does not cause any other failures.


Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Mingming Cao <cmm@us.ibm.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>


authored by Eric Sandeen and committed by Theodore Ts'o 256bdb49 c4e35e07

+82 -45
+82 -45
fs/ext4/mballoc.c
··· 420 420 #define MB_DEFAULT_GROUP_PREALLOC 512 421 421 422 422 static struct kmem_cache *ext4_pspace_cachep; 423 + static struct kmem_cache *ext4_ac_cachep; 423 424 424 425 #ifdef EXT4_BB_MAX_BLOCKS 425 426 #undef EXT4_BB_MAX_BLOCKS ··· 2960 2959 if (ext4_pspace_cachep == NULL) 2961 2960 return -ENOMEM; 2962 2961 2962 + ext4_ac_cachep = 2963 + kmem_cache_create("ext4_alloc_context", 2964 + sizeof(struct ext4_allocation_context), 2965 + 0, SLAB_RECLAIM_ACCOUNT, NULL); 2966 + if (ext4_ac_cachep == NULL) { 2967 + kmem_cache_destroy(ext4_pspace_cachep); 2968 + return -ENOMEM; 2969 + } 2963 2970 #ifdef CONFIG_PROC_FS 2964 2971 proc_root_ext4 = proc_mkdir(EXT4_ROOT, proc_root_fs); 2965 2972 if (proc_root_ext4 == NULL) 2966 2973 printk(KERN_ERR "EXT4-fs: Unable to create %s\n", EXT4_ROOT); 2967 2974 #endif 2968 - 2969 2975 return 0; 2970 2976 } 2971 2977 ··· 2980 2972 { 2981 2973 /* XXX: synchronize_rcu(); */ 2982 2974 kmem_cache_destroy(ext4_pspace_cachep); 2975 + kmem_cache_destroy(ext4_ac_cachep); 2983 2976 #ifdef CONFIG_PROC_FS 2984 2977 remove_proc_entry(EXT4_ROOT, proc_root_fs); 2985 2978 #endif ··· 3708 3699 struct buffer_head *bitmap_bh, 3709 3700 struct ext4_prealloc_space *pa) 3710 3701 { 3711 - struct ext4_allocation_context ac; 3702 + struct ext4_allocation_context *ac; 3712 3703 struct super_block *sb = e4b->bd_sb; 3713 3704 struct ext4_sb_info *sbi = EXT4_SB(sb); 3714 3705 unsigned long end; ··· 3724 3715 BUG_ON(group != e4b->bd_group && pa->pa_len != 0); 3725 3716 end = bit + pa->pa_len; 3726 3717 3727 - ac.ac_sb = sb; 3728 - ac.ac_inode = pa->pa_inode; 3729 - ac.ac_op = EXT4_MB_HISTORY_DISCARD; 3718 + ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); 3719 + 3720 + if (ac) { 3721 + ac->ac_sb = sb; 3722 + ac->ac_inode = pa->pa_inode; 3723 + ac->ac_op = EXT4_MB_HISTORY_DISCARD; 3724 + } 3730 3725 3731 3726 while (bit < end) { 3732 3727 bit = ext4_find_next_zero_bit(bitmap_bh->b_data, end, bit); ··· 3746 3733 (unsigned) group); 3747 3734 free += next - bit; 3748 3735 3749 - ac.ac_b_ex.fe_group = group; 3750 - ac.ac_b_ex.fe_start = bit; 3751 - ac.ac_b_ex.fe_len = next - bit; 3752 - ac.ac_b_ex.fe_logical = 0; 3753 - ext4_mb_store_history(&ac); 3736 + if (ac) { 3737 + ac->ac_b_ex.fe_group = group; 3738 + ac->ac_b_ex.fe_start = bit; 3739 + ac->ac_b_ex.fe_len = next - bit; 3740 + ac->ac_b_ex.fe_logical = 0; 3741 + ext4_mb_store_history(ac); 3742 + } 3754 3743 3755 3744 mb_free_blocks(pa->pa_inode, e4b, bit, next - bit); 3756 3745 bit = next + 1; ··· 3766 3751 } 3767 3752 BUG_ON(free != pa->pa_free); 3768 3753 atomic_add(free, &sbi->s_mb_discarded); 3754 + if (ac) 3755 + kmem_cache_free(ext4_ac_cachep, ac); 3769 3756 3770 3757 return err; 3771 3758 } ··· 3775 3758 static int ext4_mb_release_group_pa(struct ext4_buddy *e4b, 3776 3759 struct ext4_prealloc_space *pa) 3777 3760 { 3778 - struct ext4_allocation_context ac; 3761 + struct ext4_allocation_context *ac; 3779 3762 struct super_block *sb = e4b->bd_sb; 3780 3763 ext4_group_t group; 3781 3764 ext4_grpblk_t bit; 3782 3765 3783 - ac.ac_op = EXT4_MB_HISTORY_DISCARD; 3766 + ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); 3767 + 3768 + if (ac) 3769 + ac->ac_op = EXT4_MB_HISTORY_DISCARD; 3784 3770 3785 3771 BUG_ON(pa->pa_deleted == 0); 3786 3772 ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, &bit); ··· 3791 3771 mb_free_blocks(pa->pa_inode, e4b, bit, pa->pa_len); 3792 3772 atomic_add(pa->pa_len, &EXT4_SB(sb)->s_mb_discarded); 3793 3773 3794 - ac.ac_sb = sb; 3795 - ac.ac_inode = NULL; 3796 - ac.ac_b_ex.fe_group = group; 3797 - ac.ac_b_ex.fe_start = bit; 3798 - ac.ac_b_ex.fe_len = pa->pa_len; 3799 - ac.ac_b_ex.fe_logical = 0; 3800 - ext4_mb_store_history(&ac); 3774 + if (ac) { 3775 + ac->ac_sb = sb; 3776 + ac->ac_inode = NULL; 3777 + ac->ac_b_ex.fe_group = group; 3778 + ac->ac_b_ex.fe_start = bit; 3779 + ac->ac_b_ex.fe_len = pa->pa_len; 3780 + ac->ac_b_ex.fe_logical = 0; 3781 + ext4_mb_store_history(ac); 3782 + kmem_cache_free(ext4_ac_cachep, ac); 3783 + } 3801 3784 3802 3785 return 0; 3803 3786 } ··· 4254 4231 ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, 4255 4232 struct ext4_allocation_request *ar, int *errp) 4256 4233 { 4257 - struct ext4_allocation_context ac; 4234 + struct ext4_allocation_context *ac = NULL; 4258 4235 struct ext4_sb_info *sbi; 4259 4236 struct super_block *sb; 4260 4237 ext4_fsblk_t block = 0; ··· 4280 4257 } 4281 4258 inquota = ar->len; 4282 4259 4260 + ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); 4261 + if (!ac) { 4262 + *errp = -ENOMEM; 4263 + return 0; 4264 + } 4265 + 4283 4266 ext4_mb_poll_new_transaction(sb, handle); 4284 4267 4285 - *errp = ext4_mb_initialize_context(&ac, ar); 4268 + *errp = ext4_mb_initialize_context(ac, ar); 4286 4269 if (*errp) { 4287 4270 ar->len = 0; 4288 4271 goto out; 4289 4272 } 4290 4273 4291 - ac.ac_op = EXT4_MB_HISTORY_PREALLOC; 4292 - if (!ext4_mb_use_preallocated(&ac)) { 4274 + ac->ac_op = EXT4_MB_HISTORY_PREALLOC; 4275 + if (!ext4_mb_use_preallocated(ac)) { 4293 4276 4294 - ac.ac_op = EXT4_MB_HISTORY_ALLOC; 4295 - ext4_mb_normalize_request(&ac, ar); 4277 + ac->ac_op = EXT4_MB_HISTORY_ALLOC; 4278 + ext4_mb_normalize_request(ac, ar); 4296 4279 4297 4280 repeat: 4298 4281 /* allocate space in core */ 4299 - ext4_mb_regular_allocator(&ac); 4282 + ext4_mb_regular_allocator(ac); 4300 4283 4301 4284 /* as we've just preallocated more space than 4302 4285 * user requested orinally, we store allocated 4303 4286 * space in a special descriptor */ 4304 - if (ac.ac_status == AC_STATUS_FOUND && 4305 - ac.ac_o_ex.fe_len < ac.ac_b_ex.fe_len) 4306 - ext4_mb_new_preallocation(&ac); 4287 + if (ac->ac_status == AC_STATUS_FOUND && 4288 + ac->ac_o_ex.fe_len < ac->ac_b_ex.fe_len) 4289 + ext4_mb_new_preallocation(ac); 4307 4290 } 4308 4291 4309 - if (likely(ac.ac_status == AC_STATUS_FOUND)) { 4310 - ext4_mb_mark_diskspace_used(&ac, handle); 4292 + if (likely(ac->ac_status == AC_STATUS_FOUND)) { 4293 + ext4_mb_mark_diskspace_used(ac, handle); 4311 4294 *errp = 0; 4312 - block = ext4_grp_offs_to_block(sb, &ac.ac_b_ex); 4313 - ar->len = ac.ac_b_ex.fe_len; 4295 + block = ext4_grp_offs_to_block(sb, &ac->ac_b_ex); 4296 + ar->len = ac->ac_b_ex.fe_len; 4314 4297 } else { 4315 - freed = ext4_mb_discard_preallocations(sb, ac.ac_o_ex.fe_len); 4298 + freed = ext4_mb_discard_preallocations(sb, ac->ac_o_ex.fe_len); 4316 4299 if (freed) 4317 4300 goto repeat; 4318 4301 *errp = -ENOSPC; 4319 - ac.ac_b_ex.fe_len = 0; 4302 + ac->ac_b_ex.fe_len = 0; 4320 4303 ar->len = 0; 4321 - ext4_mb_show_ac(&ac); 4304 + ext4_mb_show_ac(ac); 4322 4305 } 4323 4306 4324 - ext4_mb_release_context(&ac); 4307 + ext4_mb_release_context(ac); 4325 4308 4326 4309 out: 4327 4310 if (ar->len < inquota) 4328 4311 DQUOT_FREE_BLOCK(ar->inode, inquota - ar->len); 4329 4312 4313 + kmem_cache_free(ext4_ac_cachep, ac); 4330 4314 return block; 4331 4315 } 4332 4316 static void ext4_mb_poll_new_transaction(struct super_block *sb, ··· 4437 4407 { 4438 4408 struct buffer_head *bitmap_bh = 0; 4439 4409 struct super_block *sb = inode->i_sb; 4440 - struct ext4_allocation_context ac; 4410 + struct ext4_allocation_context *ac = NULL; 4441 4411 struct ext4_group_desc *gdp; 4442 4412 struct ext4_super_block *es; 4443 4413 unsigned long overflow; ··· 4466 4436 4467 4437 ext4_debug("freeing block %lu\n", block); 4468 4438 4469 - ac.ac_op = EXT4_MB_HISTORY_FREE; 4470 - ac.ac_inode = inode; 4471 - ac.ac_sb = sb; 4439 + ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); 4440 + if (ac) { 4441 + ac->ac_op = EXT4_MB_HISTORY_FREE; 4442 + ac->ac_inode = inode; 4443 + ac->ac_sb = sb; 4444 + } 4472 4445 4473 4446 do_more: 4474 4447 overflow = 0; ··· 4537 4504 BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); 4538 4505 err = ext4_journal_dirty_metadata(handle, bitmap_bh); 4539 4506 4540 - ac.ac_b_ex.fe_group = block_group; 4541 - ac.ac_b_ex.fe_start = bit; 4542 - ac.ac_b_ex.fe_len = count; 4543 - ext4_mb_store_history(&ac); 4507 + if (ac) { 4508 + ac->ac_b_ex.fe_group = block_group; 4509 + ac->ac_b_ex.fe_start = bit; 4510 + ac->ac_b_ex.fe_len = count; 4511 + ext4_mb_store_history(ac); 4512 + } 4544 4513 4545 4514 if (metadata) { 4546 4515 /* blocks being freed are metadata. these blocks shouldn't ··· 4583 4548 error_return: 4584 4549 brelse(bitmap_bh); 4585 4550 ext4_std_error(sb, err); 4551 + if (ac) 4552 + kmem_cache_free(ext4_ac_cachep, ac); 4586 4553 return; 4587 4554 }