diff options
Diffstat (limited to 'fs/ext4/mballoc.c')
-rw-r--r-- | fs/ext4/mballoc.c | 30 |
1 files changed, 23 insertions, 7 deletions
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 6e5a23a2cc25..0dca90be1afb 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -4427,18 +4427,24 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b, | |||
4427 | return 0; | 4427 | return 0; |
4428 | } | 4428 | } |
4429 | 4429 | ||
4430 | /* | 4430 | /** |
4431 | * Main entry point into mballoc to free blocks | 4431 | * ext4_free_blocks() -- Free given blocks and update quota |
4432 | * @handle: handle for this transaction | ||
4433 | * @inode: inode | ||
4434 | * @block: start physical block to free | ||
4435 | * @count: number of blocks to count | ||
4436 | * @metadata: Are these metadata blocks | ||
4432 | */ | 4437 | */ |
4433 | void ext4_mb_free_blocks(handle_t *handle, struct inode *inode, | 4438 | void ext4_free_blocks(handle_t *handle, struct inode *inode, |
4434 | ext4_fsblk_t block, unsigned long count, | 4439 | ext4_fsblk_t block, unsigned long count, |
4435 | int metadata, unsigned long *freed) | 4440 | int metadata) |
4436 | { | 4441 | { |
4437 | struct buffer_head *bitmap_bh = NULL; | 4442 | struct buffer_head *bitmap_bh = NULL; |
4438 | struct super_block *sb = inode->i_sb; | 4443 | struct super_block *sb = inode->i_sb; |
4439 | struct ext4_allocation_context *ac = NULL; | 4444 | struct ext4_allocation_context *ac = NULL; |
4440 | struct ext4_group_desc *gdp; | 4445 | struct ext4_group_desc *gdp; |
4441 | struct ext4_super_block *es; | 4446 | struct ext4_super_block *es; |
4447 | unsigned long freed = 0; | ||
4442 | unsigned int overflow; | 4448 | unsigned int overflow; |
4443 | ext4_grpblk_t bit; | 4449 | ext4_grpblk_t bit; |
4444 | struct buffer_head *gd_bh; | 4450 | struct buffer_head *gd_bh; |
@@ -4448,7 +4454,15 @@ void ext4_mb_free_blocks(handle_t *handle, struct inode *inode, | |||
4448 | int err = 0; | 4454 | int err = 0; |
4449 | int ret; | 4455 | int ret; |
4450 | 4456 | ||
4451 | *freed = 0; | 4457 | /* |
4458 | * We need to make sure we don't reuse the freed block until | ||
4459 | * after the transaction is committed, which we can do by | ||
4460 | * treating the block as metadata, below. We make an | ||
4461 | * exception if the inode is to be written in writeback mode | ||
4462 | * since writeback mode has weak data consistency guarantees. | ||
4463 | */ | ||
4464 | if (!ext4_should_writeback_data(inode)) | ||
4465 | metadata = 1; | ||
4452 | 4466 | ||
4453 | sbi = EXT4_SB(sb); | 4467 | sbi = EXT4_SB(sb); |
4454 | es = EXT4_SB(sb)->s_es; | 4468 | es = EXT4_SB(sb)->s_es; |
@@ -4577,7 +4591,7 @@ do_more: | |||
4577 | 4591 | ||
4578 | ext4_mb_release_desc(&e4b); | 4592 | ext4_mb_release_desc(&e4b); |
4579 | 4593 | ||
4580 | *freed += count; | 4594 | freed += count; |
4581 | 4595 | ||
4582 | /* We dirtied the bitmap block */ | 4596 | /* We dirtied the bitmap block */ |
4583 | BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); | 4597 | BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); |
@@ -4597,6 +4611,8 @@ do_more: | |||
4597 | } | 4611 | } |
4598 | sb->s_dirt = 1; | 4612 | sb->s_dirt = 1; |
4599 | error_return: | 4613 | error_return: |
4614 | if (freed) | ||
4615 | vfs_dq_free_block(inode, freed); | ||
4600 | brelse(bitmap_bh); | 4616 | brelse(bitmap_bh); |
4601 | ext4_std_error(sb, err); | 4617 | ext4_std_error(sb, err); |
4602 | if (ac) | 4618 | if (ac) |