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