aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2013-08-28 18:32:58 -0400
committerTheodore Ts'o <tytso@mit.edu>2013-08-28 18:32:58 -0400
commit87a39389be3e3b007d341be510a7e4a0542bdf05 (patch)
treed0e02154419ef9b8fa77e1801e5a693734aff3d4 /fs/ext4
parent163a203ddb36c36d4a1c942aececda0cc8d06aa7 (diff)
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 <darrick.wong@oracle.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/ext4.h3
-rw-r--r--fs/ext4/ialloc.c29
2 files changed, 28 insertions, 4 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 02b764b4e635..06b488dca666 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -2481,11 +2481,14 @@ struct ext4_group_info {
2481#define EXT4_GROUP_INFO_NEED_INIT_BIT 0 2481#define EXT4_GROUP_INFO_NEED_INIT_BIT 0
2482#define EXT4_GROUP_INFO_WAS_TRIMMED_BIT 1 2482#define EXT4_GROUP_INFO_WAS_TRIMMED_BIT 1
2483#define EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT 2 2483#define EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT 2
2484#define EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT 3
2484 2485
2485#define EXT4_MB_GRP_NEED_INIT(grp) \ 2486#define EXT4_MB_GRP_NEED_INIT(grp) \
2486 (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state))) 2487 (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state)))
2487#define EXT4_MB_GRP_BBITMAP_CORRUPT(grp) \ 2488#define EXT4_MB_GRP_BBITMAP_CORRUPT(grp) \
2488 (test_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &((grp)->bb_state))) 2489 (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)))
2489 2492
2490#define EXT4_MB_GRP_WAS_TRIMMED(grp) \ 2493#define EXT4_MB_GRP_WAS_TRIMMED(grp) \
2491 (test_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state))) 2494 (test_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state)))
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 666a5ed48bcc..d5106078595e 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -117,6 +117,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
117 struct ext4_group_desc *desc; 117 struct ext4_group_desc *desc;
118 struct buffer_head *bh = NULL; 118 struct buffer_head *bh = NULL;
119 ext4_fsblk_t bitmap_blk; 119 ext4_fsblk_t bitmap_blk;
120 struct ext4_group_info *grp;
120 121
121 desc = ext4_get_group_desc(sb, block_group, NULL); 122 desc = ext4_get_group_desc(sb, block_group, NULL);
122 if (!desc) 123 if (!desc)
@@ -185,6 +186,8 @@ verify:
185 put_bh(bh); 186 put_bh(bh);
186 ext4_error(sb, "Corrupt inode bitmap - block_group = %u, " 187 ext4_error(sb, "Corrupt inode bitmap - block_group = %u, "
187 "inode_bitmap = %llu", block_group, bitmap_blk); 188 "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);
188 return NULL; 191 return NULL;
189 } 192 }
190 ext4_unlock_group(sb, block_group); 193 ext4_unlock_group(sb, block_group);
@@ -221,6 +224,7 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
221 struct ext4_super_block *es; 224 struct ext4_super_block *es;
222 struct ext4_sb_info *sbi; 225 struct ext4_sb_info *sbi;
223 int fatal = 0, err, count, cleared; 226 int fatal = 0, err, count, cleared;
227 struct ext4_group_info *grp;
224 228
225 if (!sb) { 229 if (!sb) {
226 printk(KERN_ERR "EXT4-fs: %s:%d: inode on " 230 printk(KERN_ERR "EXT4-fs: %s:%d: inode on "
@@ -266,7 +270,9 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
266 block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb); 270 block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
267 bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb); 271 bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb);
268 bitmap_bh = ext4_read_inode_bitmap(sb, block_group); 272 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)
270 goto error_return; 276 goto error_return;
271 277
272 BUFFER_TRACE(bitmap_bh, "get_write_access"); 278 BUFFER_TRACE(bitmap_bh, "get_write_access");
@@ -315,8 +321,10 @@ out:
315 err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh); 321 err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
316 if (!fatal) 322 if (!fatal)
317 fatal = err; 323 fatal = err;
318 } else 324 } else {
319 ext4_error(sb, "bit already cleared for inode %lu", ino); 325 ext4_error(sb, "bit already cleared for inode %lu", ino);
326 set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
327 }
320 328
321error_return: 329error_return:
322 brelse(bitmap_bh); 330 brelse(bitmap_bh);
@@ -697,6 +705,7 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
697 struct inode *ret; 705 struct inode *ret;
698 ext4_group_t i; 706 ext4_group_t i;
699 ext4_group_t flex_group; 707 ext4_group_t flex_group;
708 struct ext4_group_info *grp;
700 709
701 /* Cannot create files in a deleted directory */ 710 /* Cannot create files in a deleted directory */
702 if (!dir || !dir->i_nlink) 711 if (!dir || !dir->i_nlink)
@@ -770,10 +779,22 @@ got_group:
770 continue; 779 continue;
771 } 780 }
772 781
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
773 brelse(inode_bitmap_bh); 790 brelse(inode_bitmap_bh);
774 inode_bitmap_bh = ext4_read_inode_bitmap(sb, group); 791 inode_bitmap_bh = ext4_read_inode_bitmap(sb, group);
775 if (!inode_bitmap_bh) 792 /* Skip groups with suspicious inode tables */
776 goto out; 793 if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp) || !inode_bitmap_bh) {
794 if (++group == ngroups)
795 group = 0;
796 continue;
797 }
777 798
778repeat_in_this_group: 799repeat_in_this_group:
779 ino = ext4_find_next_zero_bit((unsigned long *) 800 ino = ext4_find_next_zero_bit((unsigned long *)