diff options
author | Jan Kara <jack@suse.cz> | 2016-02-11 23:15:12 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2016-02-11 23:15:12 -0500 |
commit | 05145bd799e498ce4e3b5145894174ee881f02b0 (patch) | |
tree | abcedec57a068d5f586ac4c6d16c7629ffca07db /fs | |
parent | ff978b09f973db0d0597704eba350a994d7729e6 (diff) |
ext4: fix scheduling in atomic on group checksum failure
When block group checksum is wrong, we call ext4_error() while holding
group spinlock from ext4_init_block_bitmap() or
ext4_init_inode_bitmap() which results in scheduling while in atomic.
Fix the issue by calling ext4_error() later after dropping the spinlock.
CC: stable@vger.kernel.org
Reported-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/balloc.c | 7 | ||||
-rw-r--r-- | fs/ext4/ialloc.c | 6 |
2 files changed, 8 insertions, 5 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index ec0668a60678..fe1f50fe764f 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
@@ -191,7 +191,6 @@ static int ext4_init_block_bitmap(struct super_block *sb, | |||
191 | /* If checksum is bad mark all blocks used to prevent allocation | 191 | /* If checksum is bad mark all blocks used to prevent allocation |
192 | * essentially implementing a per-group read-only flag. */ | 192 | * essentially implementing a per-group read-only flag. */ |
193 | if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) { | 193 | if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) { |
194 | ext4_error(sb, "Checksum bad for group %u", block_group); | ||
195 | grp = ext4_get_group_info(sb, block_group); | 194 | grp = ext4_get_group_info(sb, block_group); |
196 | if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) | 195 | if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) |
197 | percpu_counter_sub(&sbi->s_freeclusters_counter, | 196 | percpu_counter_sub(&sbi->s_freeclusters_counter, |
@@ -442,14 +441,16 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) | |||
442 | } | 441 | } |
443 | ext4_lock_group(sb, block_group); | 442 | ext4_lock_group(sb, block_group); |
444 | if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { | 443 | if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { |
445 | |||
446 | err = ext4_init_block_bitmap(sb, bh, block_group, desc); | 444 | err = ext4_init_block_bitmap(sb, bh, block_group, desc); |
447 | set_bitmap_uptodate(bh); | 445 | set_bitmap_uptodate(bh); |
448 | set_buffer_uptodate(bh); | 446 | set_buffer_uptodate(bh); |
449 | ext4_unlock_group(sb, block_group); | 447 | ext4_unlock_group(sb, block_group); |
450 | unlock_buffer(bh); | 448 | unlock_buffer(bh); |
451 | if (err) | 449 | if (err) { |
450 | ext4_error(sb, "Failed to init block bitmap for group " | ||
451 | "%u: %d", block_group, err); | ||
452 | goto out; | 452 | goto out; |
453 | } | ||
453 | goto verify; | 454 | goto verify; |
454 | } | 455 | } |
455 | ext4_unlock_group(sb, block_group); | 456 | ext4_unlock_group(sb, block_group); |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 3fcfd50a2e8a..acc0ad56bf2f 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
@@ -76,7 +76,6 @@ static int ext4_init_inode_bitmap(struct super_block *sb, | |||
76 | /* If checksum is bad mark all blocks and inodes use to prevent | 76 | /* If checksum is bad mark all blocks and inodes use to prevent |
77 | * allocation, essentially implementing a per-group read-only flag. */ | 77 | * allocation, essentially implementing a per-group read-only flag. */ |
78 | if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) { | 78 | if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) { |
79 | ext4_error(sb, "Checksum bad for group %u", block_group); | ||
80 | grp = ext4_get_group_info(sb, block_group); | 79 | grp = ext4_get_group_info(sb, block_group); |
81 | if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) | 80 | if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) |
82 | percpu_counter_sub(&sbi->s_freeclusters_counter, | 81 | percpu_counter_sub(&sbi->s_freeclusters_counter, |
@@ -191,8 +190,11 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) | |||
191 | set_buffer_verified(bh); | 190 | set_buffer_verified(bh); |
192 | ext4_unlock_group(sb, block_group); | 191 | ext4_unlock_group(sb, block_group); |
193 | unlock_buffer(bh); | 192 | unlock_buffer(bh); |
194 | if (err) | 193 | if (err) { |
194 | ext4_error(sb, "Failed to init inode bitmap for group " | ||
195 | "%u: %d", block_group, err); | ||
195 | goto out; | 196 | goto out; |
197 | } | ||
196 | return bh; | 198 | return bh; |
197 | } | 199 | } |
198 | ext4_unlock_group(sb, block_group); | 200 | ext4_unlock_group(sb, block_group); |