aboutsummaryrefslogtreecommitdiff
path: root/lib/ext2fs
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2019-05-05 16:43:33 -0400
committerTheodore Ts'o <tytso@mit.edu>2019-05-06 10:15:29 -0400
commitd0efd17a436aacda85aae86bb6dfed4226a9e0a9 (patch)
treef1f7cc33613501f95133aea64792cf099f8c24fd /lib/ext2fs
parent4a274baf2a6fcd0d73865f4b60529ff4dfa569bd (diff)
downloade2fsprogs-d0efd17a436aacda85aae86bb6dfed4226a9e0a9.tar.gz
e2fsck: check and fix tails of all bitmap blocks
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 <jack@suse.cz> Signed-off-by: Theodore Ts'o <tytso@mit.edu> Reviewed-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'lib/ext2fs')
-rw-r--r--lib/ext2fs/ext2fs.h2
-rw-r--r--lib/ext2fs/rw_bitmaps.c26
2 files changed, 26 insertions, 2 deletions
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 7d7c346d..59fd9742 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -204,6 +204,8 @@ typedef struct ext2_file *ext2_file_t;
#define EXT2_FLAG_IGNORE_CSUM_ERRORS 0x200000
#define EXT2_FLAG_SHARE_DUP 0x400000
#define EXT2_FLAG_IGNORE_SB_ERRORS 0x800000
+#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
diff --git a/lib/ext2fs/rw_bitmaps.c b/lib/ext2fs/rw_bitmaps.c
index e86bacd5..f1c4188b 100644
--- a/lib/ext2fs/rw_bitmaps.c
+++ b/lib/ext2fs/rw_bitmaps.c
@@ -195,6 +195,16 @@ static errcode_t mark_uninit_bg_group_blocks(ext2_filsys fs)
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;
@@ -203,6 +213,7 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
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;
unsigned int cnt;
blk64_t blk;
@@ -315,6 +326,9 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
EXT2_ET_BLOCK_BITMAP_CSUM_INVALID;
goto cleanup;
}
+ if (!bitmap_tail_verify((unsigned char *) 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;
@@ -347,6 +361,9 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
EXT2_ET_INODE_BITMAP_CSUM_INVALID;
goto cleanup;
}
+ if (!bitmap_tail_verify((unsigned char *) 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;
@@ -366,10 +383,15 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
}
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: