diff options
-rw-r--r-- | fs/ext4/mballoc.c | 82 |
1 files changed, 60 insertions, 22 deletions
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index c17063ddb307..860766421fe8 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -335,6 +335,8 @@ static struct kmem_cache *ext4_ac_cachep; | |||
335 | static struct kmem_cache *ext4_free_ext_cachep; | 335 | static struct kmem_cache *ext4_free_ext_cachep; |
336 | static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap, | 336 | static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap, |
337 | ext4_group_t group); | 337 | ext4_group_t group); |
338 | static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap, | ||
339 | ext4_group_t group); | ||
338 | static int ext4_mb_init_per_dev_proc(struct super_block *sb); | 340 | static int ext4_mb_init_per_dev_proc(struct super_block *sb); |
339 | static int ext4_mb_destroy_per_dev_proc(struct super_block *sb); | 341 | static int ext4_mb_destroy_per_dev_proc(struct super_block *sb); |
340 | static void release_blocks_on_commit(journal_t *journal, transaction_t *txn); | 342 | static void release_blocks_on_commit(journal_t *journal, transaction_t *txn); |
@@ -858,7 +860,9 @@ static int ext4_mb_init_cache(struct page *page, char *incore) | |||
858 | /* | 860 | /* |
859 | * incore got set to the group block bitmap below | 861 | * incore got set to the group block bitmap below |
860 | */ | 862 | */ |
863 | ext4_lock_group(sb, group); | ||
861 | ext4_mb_generate_buddy(sb, data, incore, group); | 864 | ext4_mb_generate_buddy(sb, data, incore, group); |
865 | ext4_unlock_group(sb, group); | ||
862 | incore = NULL; | 866 | incore = NULL; |
863 | } else { | 867 | } else { |
864 | /* this is block of bitmap */ | 868 | /* this is block of bitmap */ |
@@ -872,6 +876,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore) | |||
872 | 876 | ||
873 | /* mark all preallocated blks used in in-core bitmap */ | 877 | /* mark all preallocated blks used in in-core bitmap */ |
874 | ext4_mb_generate_from_pa(sb, data, group); | 878 | ext4_mb_generate_from_pa(sb, data, group); |
879 | ext4_mb_generate_from_freelist(sb, data, group); | ||
875 | ext4_unlock_group(sb, group); | 880 | ext4_unlock_group(sb, group); |
876 | 881 | ||
877 | /* set incore so that the buddy information can be | 882 | /* set incore so that the buddy information can be |
@@ -3472,6 +3477,32 @@ ext4_mb_use_preallocated(struct ext4_allocation_context *ac) | |||
3472 | } | 3477 | } |
3473 | 3478 | ||
3474 | /* | 3479 | /* |
3480 | * the function goes through all block freed in the group | ||
3481 | * but not yet committed and marks them used in in-core bitmap. | ||
3482 | * buddy must be generated from this bitmap | ||
3483 | * Need to be called with ext4 group lock (ext4_lock_group) | ||
3484 | */ | ||
3485 | static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap, | ||
3486 | ext4_group_t group) | ||
3487 | { | ||
3488 | struct rb_node *n; | ||
3489 | struct ext4_group_info *grp; | ||
3490 | struct ext4_free_data *entry; | ||
3491 | |||
3492 | grp = ext4_get_group_info(sb, group); | ||
3493 | n = rb_first(&(grp->bb_free_root)); | ||
3494 | |||
3495 | while (n) { | ||
3496 | entry = rb_entry(n, struct ext4_free_data, node); | ||
3497 | mb_set_bits(sb_bgl_lock(EXT4_SB(sb), group), | ||
3498 | bitmap, entry->start_blk, | ||
3499 | entry->count); | ||
3500 | n = rb_next(n); | ||
3501 | } | ||
3502 | return; | ||
3503 | } | ||
3504 | |||
3505 | /* | ||
3475 | * the function goes through all preallocation in this group and marks them | 3506 | * the function goes through all preallocation in this group and marks them |
3476 | * used in in-core bitmap. buddy must be generated from this bitmap | 3507 | * used in in-core bitmap. buddy must be generated from this bitmap |
3477 | * Need to be called with ext4 group lock (ext4_lock_group) | 3508 | * Need to be called with ext4 group lock (ext4_lock_group) |
@@ -4568,12 +4599,13 @@ static int can_merge(struct ext4_free_data *entry1, | |||
4568 | 4599 | ||
4569 | static noinline_for_stack int | 4600 | static noinline_for_stack int |
4570 | ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b, | 4601 | ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b, |
4571 | ext4_group_t group, ext4_grpblk_t block, int count) | 4602 | struct ext4_free_data *new_entry) |
4572 | { | 4603 | { |
4604 | ext4_grpblk_t block; | ||
4605 | struct ext4_free_data *entry; | ||
4573 | struct ext4_group_info *db = e4b->bd_info; | 4606 | struct ext4_group_info *db = e4b->bd_info; |
4574 | struct super_block *sb = e4b->bd_sb; | 4607 | struct super_block *sb = e4b->bd_sb; |
4575 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 4608 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
4576 | struct ext4_free_data *entry, *new_entry; | ||
4577 | struct rb_node **n = &db->bb_free_root.rb_node, *node; | 4609 | struct rb_node **n = &db->bb_free_root.rb_node, *node; |
4578 | struct rb_node *parent = NULL, *new_node; | 4610 | struct rb_node *parent = NULL, *new_node; |
4579 | 4611 | ||
@@ -4581,14 +4613,9 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b, | |||
4581 | BUG_ON(e4b->bd_bitmap_page == NULL); | 4613 | BUG_ON(e4b->bd_bitmap_page == NULL); |
4582 | BUG_ON(e4b->bd_buddy_page == NULL); | 4614 | BUG_ON(e4b->bd_buddy_page == NULL); |
4583 | 4615 | ||
4584 | new_entry = kmem_cache_alloc(ext4_free_ext_cachep, GFP_NOFS); | ||
4585 | new_entry->start_blk = block; | ||
4586 | new_entry->group = group; | ||
4587 | new_entry->count = count; | ||
4588 | new_entry->t_tid = handle->h_transaction->t_tid; | ||
4589 | new_node = &new_entry->node; | 4616 | new_node = &new_entry->node; |
4617 | block = new_entry->start_blk; | ||
4590 | 4618 | ||
4591 | ext4_lock_group(sb, group); | ||
4592 | if (!*n) { | 4619 | if (!*n) { |
4593 | /* first free block exent. We need to | 4620 | /* first free block exent. We need to |
4594 | protect buddy cache from being freed, | 4621 | protect buddy cache from being freed, |
@@ -4606,7 +4633,6 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b, | |||
4606 | else if (block >= (entry->start_blk + entry->count)) | 4633 | else if (block >= (entry->start_blk + entry->count)) |
4607 | n = &(*n)->rb_right; | 4634 | n = &(*n)->rb_right; |
4608 | else { | 4635 | else { |
4609 | ext4_unlock_group(sb, group); | ||
4610 | ext4_error(sb, __func__, | 4636 | ext4_error(sb, __func__, |
4611 | "Double free of blocks %d (%d %d)", | 4637 | "Double free of blocks %d (%d %d)", |
4612 | block, entry->start_blk, entry->count); | 4638 | block, entry->start_blk, entry->count); |
@@ -4648,7 +4674,6 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b, | |||
4648 | spin_lock(&sbi->s_md_lock); | 4674 | spin_lock(&sbi->s_md_lock); |
4649 | list_add(&new_entry->list, &handle->h_transaction->t_private_list); | 4675 | list_add(&new_entry->list, &handle->h_transaction->t_private_list); |
4650 | spin_unlock(&sbi->s_md_lock); | 4676 | spin_unlock(&sbi->s_md_lock); |
4651 | ext4_unlock_group(sb, group); | ||
4652 | return 0; | 4677 | return 0; |
4653 | } | 4678 | } |
4654 | 4679 | ||
@@ -4753,15 +4778,6 @@ do_more: | |||
4753 | BUG_ON(!mb_test_bit(bit + i, bitmap_bh->b_data)); | 4778 | BUG_ON(!mb_test_bit(bit + i, bitmap_bh->b_data)); |
4754 | } | 4779 | } |
4755 | #endif | 4780 | #endif |
4756 | mb_clear_bits(sb_bgl_lock(sbi, block_group), bitmap_bh->b_data, | ||
4757 | bit, count); | ||
4758 | |||
4759 | /* We dirtied the bitmap block */ | ||
4760 | BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); | ||
4761 | err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh); | ||
4762 | if (err) | ||
4763 | goto error_return; | ||
4764 | |||
4765 | if (ac) { | 4781 | if (ac) { |
4766 | ac->ac_b_ex.fe_group = block_group; | 4782 | ac->ac_b_ex.fe_group = block_group; |
4767 | ac->ac_b_ex.fe_start = bit; | 4783 | ac->ac_b_ex.fe_start = bit; |
@@ -4773,11 +4789,29 @@ do_more: | |||
4773 | if (err) | 4789 | if (err) |
4774 | goto error_return; | 4790 | goto error_return; |
4775 | if (metadata && ext4_handle_valid(handle)) { | 4791 | if (metadata && ext4_handle_valid(handle)) { |
4776 | /* blocks being freed are metadata. these blocks shouldn't | 4792 | struct ext4_free_data *new_entry; |
4777 | * be used until this transaction is committed */ | 4793 | /* |
4778 | ext4_mb_free_metadata(handle, &e4b, block_group, bit, count); | 4794 | * blocks being freed are metadata. these blocks shouldn't |
4795 | * be used until this transaction is committed | ||
4796 | */ | ||
4797 | new_entry = kmem_cache_alloc(ext4_free_ext_cachep, GFP_NOFS); | ||
4798 | new_entry->start_blk = bit; | ||
4799 | new_entry->group = block_group; | ||
4800 | new_entry->count = count; | ||
4801 | new_entry->t_tid = handle->h_transaction->t_tid; | ||
4802 | ext4_lock_group(sb, block_group); | ||
4803 | mb_clear_bits(sb_bgl_lock(sbi, block_group), bitmap_bh->b_data, | ||
4804 | bit, count); | ||
4805 | ext4_mb_free_metadata(handle, &e4b, new_entry); | ||
4806 | ext4_unlock_group(sb, block_group); | ||
4779 | } else { | 4807 | } else { |
4780 | ext4_lock_group(sb, block_group); | 4808 | ext4_lock_group(sb, block_group); |
4809 | /* need to update group_info->bb_free and bitmap | ||
4810 | * with group lock held. generate_buddy look at | ||
4811 | * them with group lock_held | ||
4812 | */ | ||
4813 | mb_clear_bits(sb_bgl_lock(sbi, block_group), bitmap_bh->b_data, | ||
4814 | bit, count); | ||
4781 | mb_free_blocks(inode, &e4b, bit, count); | 4815 | mb_free_blocks(inode, &e4b, bit, count); |
4782 | ext4_mb_return_to_preallocation(inode, &e4b, block, count); | 4816 | ext4_mb_return_to_preallocation(inode, &e4b, block, count); |
4783 | ext4_unlock_group(sb, block_group); | 4817 | ext4_unlock_group(sb, block_group); |
@@ -4800,6 +4834,10 @@ do_more: | |||
4800 | 4834 | ||
4801 | *freed += count; | 4835 | *freed += count; |
4802 | 4836 | ||
4837 | /* We dirtied the bitmap block */ | ||
4838 | BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); | ||
4839 | err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh); | ||
4840 | |||
4803 | /* And the group descriptor block */ | 4841 | /* And the group descriptor block */ |
4804 | BUFFER_TRACE(gd_bh, "dirtied group descriptor block"); | 4842 | BUFFER_TRACE(gd_bh, "dirtied group descriptor block"); |
4805 | ret = ext4_handle_dirty_metadata(handle, NULL, gd_bh); | 4843 | ret = ext4_handle_dirty_metadata(handle, NULL, gd_bh); |