aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/mballoc.c
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2009-11-23 07:17:05 -0500
committerTheodore Ts'o <tytso@mit.edu>2009-11-23 07:17:05 -0500
commite6362609b6c71c5b802026be9cf263bbdd67a50e (patch)
treebe908b6b0566f70d31378bf11b548a0d59ae0218 /fs/ext4/mballoc.c
parent4433871130f36585fde38e7dd817433296648945 (diff)
ext4: call ext4_forget() from ext4_free_blocks()
Add the facility for ext4_forget() to be called from ext4_free_blocks(). This simplifies the code in a large number of places, and centralizes most of the work of calling ext4_forget() into a single place. Also fix a bug in the extents migration code; it wasn't calling ext4_forget() when releasing the indirect blocks during the conversion. As a result, if the system cashed during or shortly after the extents migration, and the released indirect blocks get reused as data blocks, the journal replay would corrupt the data blocks. With this new patch, fixing this bug was as simple as adding the EXT4_FREE_BLOCKS_FORGET flags to the call to ext4_free_blocks(). Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Cc: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
Diffstat (limited to 'fs/ext4/mballoc.c')
-rw-r--r--fs/ext4/mballoc.c49
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 */
4438void ext4_free_blocks(handle_t *handle, struct inode *inode, 4438void 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