From 6d0b48896247dc70b16482a8ff4123d570285a2a Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 5 May 2019 16:43:33 -0400 Subject: [PATCH] e2fsck: check and fix tails of all bitmap blocks References: bsc#1128383 Currently, e2fsck effectively checks only tail of the last inode and block bitmap in the filesystem. Thus if some previous bitmap has unset bits it goes unnoticed. Mostly these tail bits in the bitmap are ignored; however, if blocks_per_group are smaller than 8*blocksize, the multi-block allocator in the kernel can get confused when the tail bits are unset and return bogus free extent. Add support to libext2fs to check these bitmap tails when loading bitmaps (as that's about the only place which has access to the bitmap tail bits) and make e2fsck use this functionality to detect buggy bitmap tails and fix them (by rewriting the bitmaps). Reported-by: Jan Kara Signed-off-by: Theodore Ts'o --- e2fsck/pass5.c | 40 ++++++++++++++++--- lib/ext2fs/ext2fs.h | 2 + lib/ext2fs/rw_bitmaps.c | 26 +++++++++++- tests/f_bitmaps/expect.1 | 2 + tests/f_dup/expect.1 | 2 + tests/f_dup2/expect.1 | 2 + tests/f_dup3/expect.1 | 2 + tests/f_end-bitmap/expect.1 | 2 + tests/f_illbbitmap/expect.1 | 2 + tests/f_illibitmap/expect.1 | 2 + tests/f_illitable_flexbg/expect.1 | 2 + tests/f_lpf/expect.1 | 2 + tests/f_overfsblks/expect.1 | 2 + tests/f_super_bad_csum/expect.1 | 4 +- tests/j_corrupt_ext_jnl_sb_csum/expect | 2 + tests/j_ext_long_trans/expect | 2 + tests/j_long_trans/expect | 2 + tests/j_long_trans_mcsum_32bit/expect | 2 + tests/j_long_trans_mcsum_64bit/expect | 2 + tests/j_recover_csum2_32bit/expect.1 | 2 + tests/j_recover_csum2_64bit/expect.1 | 2 + tests/j_short_trans/expect | 2 + tests/j_short_trans_64bit/expect | 2 + tests/j_short_trans_mcsum_64bit/expect | 2 + tests/j_short_trans_old_csum/expect | 2 + tests/j_short_trans_open_recover/expect | 2 + tests/j_short_trans_recover/expect | 2 + .../j_short_trans_recover_mcsum_64bit/expect | 2 + tests/t_replay_and_set/expect | 2 + 29 files changed, 113 insertions(+), 9 deletions(-) Index: e2fsprogs-1.42.11/e2fsck/pass5.c =================================================================== --- e2fsprogs-1.42.11.orig/e2fsck/pass5.c +++ e2fsprogs-1.42.11/e2fsck/pass5.c @@ -731,6 +731,7 @@ static void check_inode_end(e2fsck_t ctx ext2_filsys fs = ctx->fs; ext2_ino_t end, save_inodes_count, i; struct problem_context pctx; + int asked = 0; clear_problem_context(&pctx); @@ -744,11 +745,12 @@ static void check_inode_end(e2fsck_t ctx return; } if (save_inodes_count == end) - return; + goto check_intra_bg_tail; /* protect loop from wrap-around if end is maxed */ for (i = save_inodes_count + 1; i <= end && i > save_inodes_count; i++) { if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) { + asked = 1; if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) { for (; i <= end; i++) ext2fs_mark_inode_bitmap(fs->inode_map, @@ -768,6 +770,20 @@ static void check_inode_end(e2fsck_t ctx ctx->flags |= E2F_FLAG_ABORT; /* fatal */ return; } + /* + * If the number of inodes per block group != blocksize, we + * can also have a potential problem with the tail bits in + * each individual inode bitmap block. If there is a problem, + * it would have been noticed when the bitmap was loaded. And + * fixing this is easy; all we need to do force the bitmap to + * be written back to disk. + */ +check_intra_bg_tail: + if (!asked && fs->flags & EXT2_FLAG_IBITMAP_TAIL_PROBLEM) + if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) + ext2fs_mark_ib_dirty(fs); + else + ext2fs_unmark_valid(fs); } static void check_block_end(e2fsck_t ctx) @@ -775,6 +791,7 @@ static void check_block_end(e2fsck_t ctx ext2_filsys fs = ctx->fs; blk64_t end, save_blocks_count, i; struct problem_context pctx; + int asked = 0; clear_problem_context(&pctx); @@ -789,12 +806,13 @@ static void check_block_end(e2fsck_t ctx return; } if (save_blocks_count == end) - return; + goto check_intra_bg_tail; /* Protect loop from wrap-around if end is maxed */ for (i = save_blocks_count + 1; i <= end && i > save_blocks_count; i++) { if (!ext2fs_test_block_bitmap2(fs->block_map, EXT2FS_C2B(fs, i))) { + asked = 1; if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) { for (; i <= end; i++) ext2fs_mark_block_bitmap2(fs->block_map, @@ -814,7 +832,19 @@ static void check_block_end(e2fsck_t ctx ctx->flags |= E2F_FLAG_ABORT; /* fatal */ return; } + /* + * If the number of blocks per block group != blocksize, we + * can also have a potential problem with the tail bits in + * each individual block bitmap block. If there is a problem, + * it would have been noticed when the bitmap was loaded. And + * fixing this is easy; all we need to do force the bitmap to + * be written back to disk. + */ +check_intra_bg_tail: + if (!asked && fs->flags & EXT2_FLAG_BBITMAP_TAIL_PROBLEM) { + if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) + ext2fs_mark_bb_dirty(fs); + else + ext2fs_unmark_valid(fs); + } } - - - Index: e2fsprogs-1.42.11/lib/ext2fs/ext2fs.h =================================================================== --- e2fsprogs-1.42.11.orig/lib/ext2fs/ext2fs.h +++ e2fsprogs-1.42.11/lib/ext2fs/ext2fs.h @@ -192,6 +192,8 @@ typedef struct ext2_file *ext2_file_t; #define EXT2_FLAG_PRINT_PROGRESS 0x40000 #define EXT2_FLAG_DIRECT_IO 0x80000 #define EXT2_FLAG_SKIP_MMP 0x100000 +#define EXT2_FLAG_BBITMAP_TAIL_PROBLEM 0x1000000 +#define EXT2_FLAG_IBITMAP_TAIL_PROBLEM 0x2000000 /* * Special flag in the ext2 inode i_flag field that means that this is Index: e2fsprogs-1.42.11/lib/ext2fs/rw_bitmaps.c =================================================================== --- e2fsprogs-1.42.11.orig/lib/ext2fs/rw_bitmaps.c +++ e2fsprogs-1.42.11/lib/ext2fs/rw_bitmaps.c @@ -182,6 +182,16 @@ static errcode_t mark_uninit_bg_group_bl return 0; } +static int bitmap_tail_verify(unsigned char *bitmap, int first, int last) +{ + int i; + + for (i = first; i <= last; i++) + if (bitmap[i] != 0xff) + return 0; + return 1; +} + static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) { dgrp_t i; @@ -190,6 +200,7 @@ static errcode_t read_bitmaps(ext2_filsy errcode_t retval; int block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8; int inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8; + int tail_flags = 0; int csum_flag = 0; unsigned int cnt; blk64_t blk; @@ -297,6 +308,9 @@ static errcode_t read_bitmaps(ext2_filsy retval = EXT2_ET_BLOCK_BITMAP_READ; goto cleanup; } + if (!bitmap_tail_verify(block_bitmap, + block_nbytes, fs->blocksize - 1)) + tail_flags |= EXT2_FLAG_BBITMAP_TAIL_PROBLEM; } else memset(block_bitmap, 0, block_nbytes); cnt = block_nbytes << 3; @@ -319,6 +333,9 @@ static errcode_t read_bitmaps(ext2_filsy retval = EXT2_ET_INODE_BITMAP_READ; goto cleanup; } + if (!bitmap_tail_verify(inode_bitmap, + inode_nbytes, fs->blocksize - 1)) + tail_flags |= EXT2_FLAG_IBITMAP_TAIL_PROBLEM; } else memset(inode_bitmap, 0, inode_nbytes); cnt = inode_nbytes << 3; @@ -338,10 +355,15 @@ static errcode_t read_bitmaps(ext2_filsy } success_cleanup: - if (inode_bitmap) + if (inode_bitmap) { ext2fs_free_mem(&inode_bitmap); - if (block_bitmap) + fs->flags &= ~EXT2_FLAG_IBITMAP_TAIL_PROBLEM; + } + if (block_bitmap) { ext2fs_free_mem(&block_bitmap); + fs->flags &= ~EXT2_FLAG_BBITMAP_TAIL_PROBLEM; + } + fs->flags |= tail_flags; return 0; cleanup: Index: e2fsprogs-1.42.11/tests/f_bitmaps/expect.1 =================================================================== --- e2fsprogs-1.42.11.orig/tests/f_bitmaps/expect.1 +++ e2fsprogs-1.42.11/tests/f_bitmaps/expect.1 @@ -11,6 +11,8 @@ Fix? yes Inode bitmap differences: +11 -15 Fix? yes +Padding at end of inode bitmap is not set. Fix? yes + test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 11/32 files (9.1% non-contiguous), 22/100 blocks Index: e2fsprogs-1.42.11/tests/f_dup/expect.1 =================================================================== --- e2fsprogs-1.42.11.orig/tests/f_dup/expect.1 +++ e2fsprogs-1.42.11/tests/f_dup/expect.1 @@ -30,6 +30,8 @@ Fix? yes Free blocks count wrong (62, counted=60). Fix? yes +Padding at end of inode bitmap is not set. Fix? yes + Padding at end of block bitmap is not set. Fix? yes Index: e2fsprogs-1.42.11/tests/f_dup2/expect.1 =================================================================== --- e2fsprogs-1.42.11.orig/tests/f_dup2/expect.1 +++ e2fsprogs-1.42.11/tests/f_dup2/expect.1 @@ -37,6 +37,8 @@ Fix? yes Free blocks count wrong (26, counted=22). Fix? yes +Padding at end of inode bitmap is not set. Fix? yes + Padding at end of block bitmap is not set. Fix? yes Index: e2fsprogs-1.42.11/tests/f_dup3/expect.1 =================================================================== --- e2fsprogs-1.42.11.orig/tests/f_dup3/expect.1 +++ e2fsprogs-1.42.11/tests/f_dup3/expect.1 @@ -39,6 +39,8 @@ Fix? yes Free blocks count wrong (20, counted=19). Fix? yes +Padding at end of inode bitmap is not set. Fix? yes + test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 16/16 files (25.0% non-contiguous), 81/100 blocks Index: e2fsprogs-1.42.11/tests/f_end-bitmap/expect.1 =================================================================== --- e2fsprogs-1.42.11.orig/tests/f_end-bitmap/expect.1 +++ e2fsprogs-1.42.11/tests/f_end-bitmap/expect.1 @@ -8,6 +8,8 @@ Pass 5: Checking group summary informati Free blocks count wrong for group #0 (44, counted=63). Fix? yes +Padding at end of inode bitmap is not set. Fix? yes + Padding at end of block bitmap is not set. Fix? yes Index: e2fsprogs-1.42.11/tests/f_illbbitmap/expect.1 =================================================================== --- e2fsprogs-1.42.11.orig/tests/f_illbbitmap/expect.1 +++ e2fsprogs-1.42.11/tests/f_illbbitmap/expect.1 @@ -22,6 +22,8 @@ Fix? yes Inode bitmap differences: -(12--21) Fix? yes +Padding at end of inode bitmap is not set. Fix? yes + test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 11/32 files (0.0% non-contiguous), 22/100 blocks Index: e2fsprogs-1.42.11/tests/f_illibitmap/expect.1 =================================================================== --- e2fsprogs-1.42.11.orig/tests/f_illibitmap/expect.1 +++ e2fsprogs-1.42.11/tests/f_illibitmap/expect.1 @@ -19,6 +19,8 @@ Pass 5: Checking group summary informati Inode bitmap differences: +(1--11) Fix? yes +Padding at end of inode bitmap is not set. Fix? yes + test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 11/32 files (0.0% non-contiguous), 22/100 blocks Index: e2fsprogs-1.42.11/tests/f_illitable_flexbg/expect.1 =================================================================== --- e2fsprogs-1.42.11.orig/tests/f_illitable_flexbg/expect.1 +++ e2fsprogs-1.42.11/tests/f_illitable_flexbg/expect.1 @@ -18,6 +18,8 @@ Pass 5: Checking group summary informati Inode bitmap differences: -(65--128) Fix? yes +Padding at end of inode bitmap is not set. Fix? yes + test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 12/256 files (0.0% non-contiguous), 31163/32768 blocks Index: e2fsprogs-1.42.11/tests/f_lpf/expect.1 =================================================================== --- e2fsprogs-1.42.11.orig/tests/f_lpf/expect.1 +++ e2fsprogs-1.42.11/tests/f_lpf/expect.1 @@ -42,6 +42,8 @@ Fix? yes Free inodes count wrong (1, counted=0). Fix? yes +Padding at end of inode bitmap is not set. Fix? yes + test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 16/16 files (12.5% non-contiguous), 67/100 blocks Index: e2fsprogs-1.42.11/tests/f_overfsblks/expect.1 =================================================================== --- e2fsprogs-1.42.11.orig/tests/f_overfsblks/expect.1 +++ e2fsprogs-1.42.11/tests/f_overfsblks/expect.1 @@ -13,6 +13,8 @@ Pass 5: Checking group summary informati Inode bitmap differences: -(12--21) Fix? yes +Padding at end of inode bitmap is not set. Fix? yes + test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: 11/32 files (0.0% non-contiguous), 22/100 blocks