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 287 (int)block_group, (unsigned long long)bitmap_blk); 288 288 return NULL; 289 289 } 290 - if (!ext4_valid_block_bitmap(sb, desc, block_group, bh)) { 291 - put_bh(bh); 292 - return NULL; 293 - } 294 - 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 295 return bh; 296 296 } 297 297 /* ··· 1770 1770 "Allocating block in system zone - " 1771 1771 "blocks from %llu, length %lu", 1772 1772 ret_block, num); 1773 - goto out; 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; 1774 1779 } 1775 1780 1776 1781 performed_allocation = 1;
+36 -11
fs/ext4/mballoc.c
··· 2736 2736 struct ext4_sb_info *sbi; 2737 2737 struct super_block *sb; 2738 2738 ext4_fsblk_t block; 2739 - int err; 2739 + int err, len; 2740 2740 2741 2741 BUG_ON(ac->ac_status != AC_STATUS_FOUND); 2742 2742 BUG_ON(ac->ac_b_ex.fe_len <= 0); ··· 2770 2770 + ac->ac_b_ex.fe_start 2771 2771 + le32_to_cpu(es->s_first_data_block); 2772 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 - 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)) { 2778 2780 ext4_error(sb, __func__, 2779 2781 "Allocating block in system zone - block = %llu", 2780 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; 2781 2794 } 2782 2795 #ifdef AGGRESSIVE_CHECK 2783 2796 { ··· 4045 4032 4046 4033 ac->ac_op = EXT4_MB_HISTORY_ALLOC; 4047 4034 ext4_mb_normalize_request(ac, ar); 4048 - 4049 4035 repeat: 4050 4036 /* allocate space in core */ 4051 4037 ext4_mb_regular_allocator(ac); ··· 4058 4046 } 4059 4047 4060 4048 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; 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 + } 4065 4064 } else { 4066 4065 freed = ext4_mb_discard_preallocations(sb, ac->ac_o_ex.fe_len); 4067 4066 if (freed) ··· 4259 4236 ext4_error(sb, __func__, 4260 4237 "Freeing blocks in system zone - " 4261 4238 "Block = %lu, count = %lu", block, count); 4239 + /* err = 0. ext4_std_error should be a no op */ 4240 + goto error_return; 4262 4241 } 4263 4242 4264 4243 BUFFER_TRACE(bitmap_bh, "getting write access");