diff options
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/ext4.h | 3 | ||||
-rw-r--r-- | fs/ext4/ialloc.c | 29 |
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 | ||
321 | error_return: | 329 | error_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 | ||
778 | repeat_in_this_group: | 799 | repeat_in_this_group: |
779 | ino = ext4_find_next_zero_bit((unsigned long *) | 800 | ino = ext4_find_next_zero_bit((unsigned long *) |