Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ext4: don't call ext4_error while block group is locked

While in ext4_validate_block_bitmap(), if an block allocation bitmap
is found to be invalid, we call ext4_error() while the block group is
still locked. This causes ext4_commit_super() to call a function
which might sleep while in an atomic context.

There's no need to keep the block group locked at this point, so hoist
the ext4_error() call up to ext4_validate_block_bitmap() and release
the block group spinlock before calling ext4_error().

The reported stack trace can be found at:

http://article.gmane.org/gmane.comp.file-systems.ext4/33731

Reported-by: Dave Jones <davej@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Cc: stable@vger.kernel.org

+37 -26
+37 -25
fs/ext4/balloc.c
··· 280 280 return desc; 281 281 } 282 282 283 - static int ext4_valid_block_bitmap(struct super_block *sb, 284 - struct ext4_group_desc *desc, 285 - unsigned int block_group, 286 - struct buffer_head *bh) 283 + /* 284 + * Return the block number which was discovered to be invalid, or 0 if 285 + * the block bitmap is valid. 286 + */ 287 + static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb, 288 + struct ext4_group_desc *desc, 289 + unsigned int block_group, 290 + struct buffer_head *bh) 287 291 { 288 292 ext4_grpblk_t offset; 289 293 ext4_grpblk_t next_zero_bit; 290 - ext4_fsblk_t bitmap_blk; 294 + ext4_fsblk_t blk; 291 295 ext4_fsblk_t group_first_block; 292 296 293 297 if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) { ··· 301 297 * or it has to also read the block group where the bitmaps 302 298 * are located to verify they are set. 303 299 */ 304 - return 1; 300 + return 0; 305 301 } 306 302 group_first_block = ext4_group_first_block_no(sb, block_group); 307 303 308 304 /* check whether block bitmap block number is set */ 309 - bitmap_blk = ext4_block_bitmap(sb, desc); 310 - offset = bitmap_blk - group_first_block; 305 + blk = ext4_block_bitmap(sb, desc); 306 + offset = blk - group_first_block; 311 307 if (!ext4_test_bit(offset, bh->b_data)) 312 308 /* bad block bitmap */ 313 - goto err_out; 309 + return blk; 314 310 315 311 /* check whether the inode bitmap block number is set */ 316 - bitmap_blk = ext4_inode_bitmap(sb, desc); 317 - offset = bitmap_blk - group_first_block; 312 + blk = ext4_inode_bitmap(sb, desc); 313 + offset = blk - group_first_block; 318 314 if (!ext4_test_bit(offset, bh->b_data)) 319 315 /* bad block bitmap */ 320 - goto err_out; 316 + return blk; 321 317 322 318 /* check whether the inode table block number is set */ 323 - bitmap_blk = ext4_inode_table(sb, desc); 324 - offset = bitmap_blk - group_first_block; 319 + blk = ext4_inode_table(sb, desc); 320 + offset = blk - group_first_block; 325 321 next_zero_bit = ext4_find_next_zero_bit(bh->b_data, 326 322 offset + EXT4_SB(sb)->s_itb_per_group, 327 323 offset); 328 - if (next_zero_bit >= offset + EXT4_SB(sb)->s_itb_per_group) 329 - /* good bitmap for inode tables */ 330 - return 1; 331 - 332 - err_out: 333 - ext4_error(sb, "Invalid block bitmap - block_group = %d, block = %llu", 334 - block_group, bitmap_blk); 324 + if (next_zero_bit < offset + EXT4_SB(sb)->s_itb_per_group) 325 + /* bad bitmap for inode tables */ 326 + return blk; 335 327 return 0; 336 328 } 337 329 ··· 336 336 unsigned int block_group, 337 337 struct buffer_head *bh) 338 338 { 339 + ext4_fsblk_t blk; 340 + 339 341 if (buffer_verified(bh)) 340 342 return; 341 343 342 344 ext4_lock_group(sb, block_group); 343 - if (ext4_valid_block_bitmap(sb, desc, block_group, bh) && 344 - ext4_block_bitmap_csum_verify(sb, block_group, desc, bh, 345 - EXT4_BLOCKS_PER_GROUP(sb) / 8)) 346 - set_buffer_verified(bh); 345 + blk = ext4_valid_block_bitmap(sb, desc, block_group, bh); 346 + if (unlikely(blk != 0)) { 347 + ext4_unlock_group(sb, block_group); 348 + ext4_error(sb, "bg %u: block %llu: invalid block bitmap", 349 + block_group, blk); 350 + return; 351 + } 352 + if (unlikely(!ext4_block_bitmap_csum_verify(sb, block_group, 353 + desc, bh, EXT4_BLOCKS_PER_GROUP(sb) / 8))) { 354 + ext4_unlock_group(sb, block_group); 355 + ext4_error(sb, "bg %u: bad block bitmap checksum", block_group); 356 + return; 357 + } 358 + set_buffer_verified(bh); 347 359 ext4_unlock_group(sb, block_group); 348 360 } 349 361
-1
fs/ext4/bitmap.c
··· 79 79 if (provided == calculated) 80 80 return 1; 81 81 82 - ext4_error(sb, "Bad block bitmap checksum: block_group = %u", group); 83 82 return 0; 84 83 } 85 84