Skip to content

Commit 87a3938

Browse files
djwongtytso
authored andcommitted
ext4: mark block group as corrupt on inode bitmap error
If we detect either a discrepancy between the inode bitmap and the inode counts or the inode bitmap fails to pass validation checks, mark the block group corrupt and refuse to allocate or deallocate inodes from the group. Signed-off-by: Darrick J. Wong <[email protected]> Signed-off-by: "Theodore Ts'o" <[email protected]>
1 parent 163a203 commit 87a3938

File tree

2 files changed

+28
-4
lines changed

2 files changed

+28
-4
lines changed

fs/ext4/ext4.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2481,11 +2481,14 @@ struct ext4_group_info {
24812481
#define EXT4_GROUP_INFO_NEED_INIT_BIT 0
24822482
#define EXT4_GROUP_INFO_WAS_TRIMMED_BIT 1
24832483
#define EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT 2
2484+
#define EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT 3
24842485

24852486
#define EXT4_MB_GRP_NEED_INIT(grp) \
24862487
(test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state)))
24872488
#define EXT4_MB_GRP_BBITMAP_CORRUPT(grp) \
24882489
(test_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &((grp)->bb_state)))
2490+
#define EXT4_MB_GRP_IBITMAP_CORRUPT(grp) \
2491+
(test_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &((grp)->bb_state)))
24892492

24902493
#define EXT4_MB_GRP_WAS_TRIMMED(grp) \
24912494
(test_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state)))

fs/ext4/ialloc.c

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
117117
struct ext4_group_desc *desc;
118118
struct buffer_head *bh = NULL;
119119
ext4_fsblk_t bitmap_blk;
120+
struct ext4_group_info *grp;
120121

121122
desc = ext4_get_group_desc(sb, block_group, NULL);
122123
if (!desc)
@@ -185,6 +186,8 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
185186
put_bh(bh);
186187
ext4_error(sb, "Corrupt inode bitmap - block_group = %u, "
187188
"inode_bitmap = %llu", block_group, bitmap_blk);
189+
grp = ext4_get_group_info(sb, block_group);
190+
set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
188191
return NULL;
189192
}
190193
ext4_unlock_group(sb, block_group);
@@ -221,6 +224,7 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
221224
struct ext4_super_block *es;
222225
struct ext4_sb_info *sbi;
223226
int fatal = 0, err, count, cleared;
227+
struct ext4_group_info *grp;
224228

225229
if (!sb) {
226230
printk(KERN_ERR "EXT4-fs: %s:%d: inode on "
@@ -266,7 +270,9 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
266270
block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
267271
bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb);
268272
bitmap_bh = ext4_read_inode_bitmap(sb, block_group);
269-
if (!bitmap_bh)
273+
/* Don't bother if the inode bitmap is corrupt. */
274+
grp = ext4_get_group_info(sb, block_group);
275+
if (unlikely(EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) || !bitmap_bh)
270276
goto error_return;
271277

272278
BUFFER_TRACE(bitmap_bh, "get_write_access");
@@ -315,8 +321,10 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
315321
err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
316322
if (!fatal)
317323
fatal = err;
318-
} else
324+
} else {
319325
ext4_error(sb, "bit already cleared for inode %lu", ino);
326+
set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
327+
}
320328

321329
error_return:
322330
brelse(bitmap_bh);
@@ -697,6 +705,7 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
697705
struct inode *ret;
698706
ext4_group_t i;
699707
ext4_group_t flex_group;
708+
struct ext4_group_info *grp;
700709

701710
/* Cannot create files in a deleted directory */
702711
if (!dir || !dir->i_nlink)
@@ -770,10 +779,22 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
770779
continue;
771780
}
772781

782+
grp = ext4_get_group_info(sb, group);
783+
/* Skip groups with already-known suspicious inode tables */
784+
if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
785+
if (++group == ngroups)
786+
group = 0;
787+
continue;
788+
}
789+
773790
brelse(inode_bitmap_bh);
774791
inode_bitmap_bh = ext4_read_inode_bitmap(sb, group);
775-
if (!inode_bitmap_bh)
776-
goto out;
792+
/* Skip groups with suspicious inode tables */
793+
if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp) || !inode_bitmap_bh) {
794+
if (++group == ngroups)
795+
group = 0;
796+
continue;
797+
}
777798

778799
repeat_in_this_group:
779800
ino = ext4_find_next_zero_bit((unsigned long *)

0 commit comments

Comments
 (0)