ext4: Retry block allocation if new blocks are allocated from system zone.

If the block allocator gets blocks out of system zone ext4 calls
ext4_error. But if the file system is mounted with errors=continue
retry block allocation. We need to mark the system zone blocks as
in use to make sure retry don't pick them again

System zone is the block range mapping block bitmap, inode bitmap and inode
table.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Mingming Cao <cmm@us.ibm.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>

authored by Aneesh Kumar K.V and committed by Theodore Ts'o 519deca0 1930479c

+47 -17
+11 -6
fs/ext4/balloc.c
··· 287 (int)block_group, (unsigned long long)bitmap_blk); 288 return NULL; 289 } 290 - if (!ext4_valid_block_bitmap(sb, desc, block_group, bh)) { 291 - put_bh(bh); 292 - return NULL; 293 - } 294 - 295 return bh; 296 } 297 /* ··· 1770 "Allocating block in system zone - " 1771 "blocks from %llu, length %lu", 1772 ret_block, num); 1773 - goto out; 1774 } 1775 1776 performed_allocation = 1;
··· 287 (int)block_group, (unsigned long long)bitmap_blk); 288 return NULL; 289 } 290 + ext4_valid_block_bitmap(sb, desc, block_group, bh); 291 + /* 292 + * file system mounted not to panic on error, 293 + * continue with corrupt bitmap 294 + */ 295 return bh; 296 } 297 /* ··· 1770 "Allocating block in system zone - " 1771 "blocks from %llu, length %lu", 1772 ret_block, num); 1773 + /* 1774 + * claim_block marked the blocks we allocated 1775 + * as in use. So we may want to selectively 1776 + * mark some of the blocks as free 1777 + */ 1778 + goto retry_alloc; 1779 } 1780 1781 performed_allocation = 1;
+36 -11
fs/ext4/mballoc.c
··· 2736 struct ext4_sb_info *sbi; 2737 struct super_block *sb; 2738 ext4_fsblk_t block; 2739 - int err; 2740 2741 BUG_ON(ac->ac_status != AC_STATUS_FOUND); 2742 BUG_ON(ac->ac_b_ex.fe_len <= 0); ··· 2770 + ac->ac_b_ex.fe_start 2771 + le32_to_cpu(es->s_first_data_block); 2772 2773 - if (block == ext4_block_bitmap(sb, gdp) || 2774 - block == ext4_inode_bitmap(sb, gdp) || 2775 - in_range(block, ext4_inode_table(sb, gdp), 2776 - EXT4_SB(sb)->s_itb_per_group)) { 2777 - 2778 ext4_error(sb, __func__, 2779 "Allocating block in system zone - block = %llu", 2780 block); 2781 } 2782 #ifdef AGGRESSIVE_CHECK 2783 { ··· 4045 4046 ac->ac_op = EXT4_MB_HISTORY_ALLOC; 4047 ext4_mb_normalize_request(ac, ar); 4048 - 4049 repeat: 4050 /* allocate space in core */ 4051 ext4_mb_regular_allocator(ac); ··· 4058 } 4059 4060 if (likely(ac->ac_status == AC_STATUS_FOUND)) { 4061 - ext4_mb_mark_diskspace_used(ac, handle); 4062 - *errp = 0; 4063 - block = ext4_grp_offs_to_block(sb, &ac->ac_b_ex); 4064 - ar->len = ac->ac_b_ex.fe_len; 4065 } else { 4066 freed = ext4_mb_discard_preallocations(sb, ac->ac_o_ex.fe_len); 4067 if (freed) ··· 4259 ext4_error(sb, __func__, 4260 "Freeing blocks in system zone - " 4261 "Block = %lu, count = %lu", block, count); 4262 } 4263 4264 BUFFER_TRACE(bitmap_bh, "getting write access");
··· 2736 struct ext4_sb_info *sbi; 2737 struct super_block *sb; 2738 ext4_fsblk_t block; 2739 + int err, len; 2740 2741 BUG_ON(ac->ac_status != AC_STATUS_FOUND); 2742 BUG_ON(ac->ac_b_ex.fe_len <= 0); ··· 2770 + ac->ac_b_ex.fe_start 2771 + le32_to_cpu(es->s_first_data_block); 2772 2773 + len = ac->ac_b_ex.fe_len; 2774 + if (in_range(ext4_block_bitmap(sb, gdp), block, len) || 2775 + in_range(ext4_inode_bitmap(sb, gdp), block, len) || 2776 + in_range(block, ext4_inode_table(sb, gdp), 2777 + EXT4_SB(sb)->s_itb_per_group) || 2778 + in_range(block + len - 1, ext4_inode_table(sb, gdp), 2779 + EXT4_SB(sb)->s_itb_per_group)) { 2780 ext4_error(sb, __func__, 2781 "Allocating block in system zone - block = %llu", 2782 block); 2783 + /* File system mounted not to panic on error 2784 + * Fix the bitmap and repeat the block allocation 2785 + * We leak some of the blocks here. 2786 + */ 2787 + mb_set_bits(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group), 2788 + bitmap_bh->b_data, ac->ac_b_ex.fe_start, 2789 + ac->ac_b_ex.fe_len); 2790 + err = ext4_journal_dirty_metadata(handle, bitmap_bh); 2791 + if (!err) 2792 + err = -EAGAIN; 2793 + goto out_err; 2794 } 2795 #ifdef AGGRESSIVE_CHECK 2796 { ··· 4032 4033 ac->ac_op = EXT4_MB_HISTORY_ALLOC; 4034 ext4_mb_normalize_request(ac, ar); 4035 repeat: 4036 /* allocate space in core */ 4037 ext4_mb_regular_allocator(ac); ··· 4046 } 4047 4048 if (likely(ac->ac_status == AC_STATUS_FOUND)) { 4049 + *errp = ext4_mb_mark_diskspace_used(ac, handle); 4050 + if (*errp == -EAGAIN) { 4051 + ac->ac_b_ex.fe_group = 0; 4052 + ac->ac_b_ex.fe_start = 0; 4053 + ac->ac_b_ex.fe_len = 0; 4054 + ac->ac_status = AC_STATUS_CONTINUE; 4055 + goto repeat; 4056 + } else if (*errp) { 4057 + ac->ac_b_ex.fe_len = 0; 4058 + ar->len = 0; 4059 + ext4_mb_show_ac(ac); 4060 + } else { 4061 + block = ext4_grp_offs_to_block(sb, &ac->ac_b_ex); 4062 + ar->len = ac->ac_b_ex.fe_len; 4063 + } 4064 } else { 4065 freed = ext4_mb_discard_preallocations(sb, ac->ac_o_ex.fe_len); 4066 if (freed) ··· 4236 ext4_error(sb, __func__, 4237 "Freeing blocks in system zone - " 4238 "Block = %lu, count = %lu", block, count); 4239 + /* err = 0. ext4_std_error should be a no op */ 4240 + goto error_return; 4241 } 4242 4243 BUFFER_TRACE(bitmap_bh, "getting write access");