diff options
Diffstat (limited to 'fs/ext4/mballoc.c')
-rw-r--r-- | fs/ext4/mballoc.c | 49 |
1 files changed, 36 insertions, 13 deletions
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 0dca90be1afb..78de5d3c5dce 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -4436,8 +4436,8 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b, | |||
4436 | * @metadata: Are these metadata blocks | 4436 | * @metadata: Are these metadata blocks |
4437 | */ | 4437 | */ |
4438 | void ext4_free_blocks(handle_t *handle, struct inode *inode, | 4438 | void ext4_free_blocks(handle_t *handle, struct inode *inode, |
4439 | ext4_fsblk_t block, unsigned long count, | 4439 | struct buffer_head *bh, ext4_fsblk_t block, |
4440 | int metadata) | 4440 | unsigned long count, int flags) |
4441 | { | 4441 | { |
4442 | struct buffer_head *bitmap_bh = NULL; | 4442 | struct buffer_head *bitmap_bh = NULL; |
4443 | struct super_block *sb = inode->i_sb; | 4443 | struct super_block *sb = inode->i_sb; |
@@ -4454,15 +4454,12 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode, | |||
4454 | int err = 0; | 4454 | int err = 0; |
4455 | int ret; | 4455 | int ret; |
4456 | 4456 | ||
4457 | /* | 4457 | if (bh) { |
4458 | * We need to make sure we don't reuse the freed block until | 4458 | if (block) |
4459 | * after the transaction is committed, which we can do by | 4459 | BUG_ON(block != bh->b_blocknr); |
4460 | * treating the block as metadata, below. We make an | 4460 | else |
4461 | * exception if the inode is to be written in writeback mode | 4461 | block = bh->b_blocknr; |
4462 | * since writeback mode has weak data consistency guarantees. | 4462 | } |
4463 | */ | ||
4464 | if (!ext4_should_writeback_data(inode)) | ||
4465 | metadata = 1; | ||
4466 | 4463 | ||
4467 | sbi = EXT4_SB(sb); | 4464 | sbi = EXT4_SB(sb); |
4468 | es = EXT4_SB(sb)->s_es; | 4465 | es = EXT4_SB(sb)->s_es; |
@@ -4476,7 +4473,32 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode, | |||
4476 | } | 4473 | } |
4477 | 4474 | ||
4478 | ext4_debug("freeing block %llu\n", block); | 4475 | ext4_debug("freeing block %llu\n", block); |
4479 | trace_ext4_free_blocks(inode, block, count, metadata); | 4476 | trace_ext4_free_blocks(inode, block, count, flags); |
4477 | |||
4478 | if (flags & EXT4_FREE_BLOCKS_FORGET) { | ||
4479 | struct buffer_head *tbh = bh; | ||
4480 | int i; | ||
4481 | |||
4482 | BUG_ON(bh && (count > 1)); | ||
4483 | |||
4484 | for (i = 0; i < count; i++) { | ||
4485 | if (!bh) | ||
4486 | tbh = sb_find_get_block(inode->i_sb, | ||
4487 | block + i); | ||
4488 | ext4_forget(handle, flags & EXT4_FREE_BLOCKS_METADATA, | ||
4489 | inode, tbh, block + i); | ||
4490 | } | ||
4491 | } | ||
4492 | |||
4493 | /* | ||
4494 | * We need to make sure we don't reuse the freed block until | ||
4495 | * after the transaction is committed, which we can do by | ||
4496 | * treating the block as metadata, below. We make an | ||
4497 | * exception if the inode is to be written in writeback mode | ||
4498 | * since writeback mode has weak data consistency guarantees. | ||
4499 | */ | ||
4500 | if (!ext4_should_writeback_data(inode)) | ||
4501 | flags |= EXT4_FREE_BLOCKS_METADATA; | ||
4480 | 4502 | ||
4481 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); | 4503 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); |
4482 | if (ac) { | 4504 | if (ac) { |
@@ -4552,7 +4574,8 @@ do_more: | |||
4552 | err = ext4_mb_load_buddy(sb, block_group, &e4b); | 4574 | err = ext4_mb_load_buddy(sb, block_group, &e4b); |
4553 | if (err) | 4575 | if (err) |
4554 | goto error_return; | 4576 | goto error_return; |
4555 | if (metadata && ext4_handle_valid(handle)) { | 4577 | |
4578 | if ((flags & EXT4_FREE_BLOCKS_METADATA) && ext4_handle_valid(handle)) { | ||
4556 | struct ext4_free_data *new_entry; | 4579 | struct ext4_free_data *new_entry; |
4557 | /* | 4580 | /* |
4558 | * blocks being freed are metadata. these blocks shouldn't | 4581 | * blocks being freed are metadata. these blocks shouldn't |