diff options
author | Theodore Ts'o <tytso@mit.edu> | 2009-11-23 07:17:05 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2009-11-23 07:17:05 -0500 |
commit | e6362609b6c71c5b802026be9cf263bbdd67a50e (patch) | |
tree | be908b6b0566f70d31378bf11b548a0d59ae0218 /fs/ext4/inode.c | |
parent | 4433871130f36585fde38e7dd817433296648945 (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/inode.c')
-rw-r--r-- | fs/ext4/inode.c | 67 |
1 files changed, 26 insertions, 41 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 72c694323492..3b28e1fbfc90 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -669,7 +669,7 @@ allocated: | |||
669 | return ret; | 669 | return ret; |
670 | failed_out: | 670 | failed_out: |
671 | for (i = 0; i < index; i++) | 671 | for (i = 0; i < index; i++) |
672 | ext4_free_blocks(handle, inode, new_blocks[i], 1, 0); | 672 | ext4_free_blocks(handle, inode, 0, new_blocks[i], 1, 0); |
673 | return ret; | 673 | return ret; |
674 | } | 674 | } |
675 | 675 | ||
@@ -765,20 +765,20 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode, | |||
765 | return err; | 765 | return err; |
766 | failed: | 766 | failed: |
767 | /* Allocation failed, free what we already allocated */ | 767 | /* Allocation failed, free what we already allocated */ |
768 | ext4_free_blocks(handle, inode, 0, new_blocks[0], 1, 0); | ||
768 | for (i = 1; i <= n ; i++) { | 769 | for (i = 1; i <= n ; i++) { |
769 | BUFFER_TRACE(branch[i].bh, "call jbd2_journal_forget"); | ||
770 | /* | 770 | /* |
771 | * Note: is_metadata is 0 because branch[i].bh is | 771 | * branch[i].bh is newly allocated, so there is no |
772 | * newly allocated, so there is no need to revoke the | 772 | * need to revoke the block, which is why we don't |
773 | * block. If we do, it's harmless, but not necessary. | 773 | * need to set EXT4_FREE_BLOCKS_METADATA. |
774 | */ | 774 | */ |
775 | ext4_forget(handle, 0, inode, branch[i].bh, | 775 | ext4_free_blocks(handle, inode, 0, new_blocks[i], 1, |
776 | branch[i].bh->b_blocknr); | 776 | EXT4_FREE_BLOCKS_FORGET); |
777 | } | 777 | } |
778 | for (i = 0; i < indirect_blks; i++) | 778 | for (i = n+1; i < indirect_blks; i++) |
779 | ext4_free_blocks(handle, inode, new_blocks[i], 1, 0); | 779 | ext4_free_blocks(handle, inode, 0, new_blocks[i], 1, 0); |
780 | 780 | ||
781 | ext4_free_blocks(handle, inode, new_blocks[i], num, 0); | 781 | ext4_free_blocks(handle, inode, 0, new_blocks[i], num, 0); |
782 | 782 | ||
783 | return err; | 783 | return err; |
784 | } | 784 | } |
@@ -857,18 +857,16 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode, | |||
857 | 857 | ||
858 | err_out: | 858 | err_out: |
859 | for (i = 1; i <= num; i++) { | 859 | for (i = 1; i <= num; i++) { |
860 | BUFFER_TRACE(where[i].bh, "call jbd2_journal_forget"); | ||
861 | /* | 860 | /* |
862 | * Note: is_metadata is 0 because branch[i].bh is | 861 | * branch[i].bh is newly allocated, so there is no |
863 | * newly allocated, so there is no need to revoke the | 862 | * need to revoke the block, which is why we don't |
864 | * block. If we do, it's harmless, but not necessary. | 863 | * need to set EXT4_FREE_BLOCKS_METADATA. |
865 | */ | 864 | */ |
866 | ext4_forget(handle, 0, inode, where[i].bh, | 865 | ext4_free_blocks(handle, inode, where[i].bh, 0, 1, |
867 | where[i].bh->b_blocknr); | 866 | EXT4_FREE_BLOCKS_FORGET); |
868 | ext4_free_blocks(handle, inode, | ||
869 | le32_to_cpu(where[i-1].key), 1, 0); | ||
870 | } | 867 | } |
871 | ext4_free_blocks(handle, inode, le32_to_cpu(where[num].key), blks, 0); | 868 | ext4_free_blocks(handle, inode, 0, le32_to_cpu(where[num].key), |
869 | blks, 0); | ||
872 | 870 | ||
873 | return err; | 871 | return err; |
874 | } | 872 | } |
@@ -4080,7 +4078,10 @@ static void ext4_clear_blocks(handle_t *handle, struct inode *inode, | |||
4080 | __le32 *last) | 4078 | __le32 *last) |
4081 | { | 4079 | { |
4082 | __le32 *p; | 4080 | __le32 *p; |
4083 | int is_metadata = S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode); | 4081 | int flags = EXT4_FREE_BLOCKS_FORGET; |
4082 | |||
4083 | if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) | ||
4084 | flags |= EXT4_FREE_BLOCKS_METADATA; | ||
4084 | 4085 | ||
4085 | if (try_to_extend_transaction(handle, inode)) { | 4086 | if (try_to_extend_transaction(handle, inode)) { |
4086 | if (bh) { | 4087 | if (bh) { |
@@ -4096,27 +4097,10 @@ static void ext4_clear_blocks(handle_t *handle, struct inode *inode, | |||
4096 | } | 4097 | } |
4097 | } | 4098 | } |
4098 | 4099 | ||
4099 | /* | 4100 | for (p = first; p < last; p++) |
4100 | * Any buffers which are on the journal will be in memory. We | 4101 | *p = 0; |
4101 | * find them on the hash table so jbd2_journal_revoke() will | ||
4102 | * run jbd2_journal_forget() on them. We've already detached | ||
4103 | * each block from the file, so bforget() in | ||
4104 | * jbd2_journal_forget() should be safe. | ||
4105 | * | ||
4106 | * AKPM: turn on bforget in jbd2_journal_forget()!!! | ||
4107 | */ | ||
4108 | for (p = first; p < last; p++) { | ||
4109 | u32 nr = le32_to_cpu(*p); | ||
4110 | if (nr) { | ||
4111 | struct buffer_head *tbh; | ||
4112 | |||
4113 | *p = 0; | ||
4114 | tbh = sb_find_get_block(inode->i_sb, nr); | ||
4115 | ext4_forget(handle, is_metadata, inode, tbh, nr); | ||
4116 | } | ||
4117 | } | ||
4118 | 4102 | ||
4119 | ext4_free_blocks(handle, inode, block_to_free, count, is_metadata); | 4103 | ext4_free_blocks(handle, inode, 0, block_to_free, count, flags); |
4120 | } | 4104 | } |
4121 | 4105 | ||
4122 | /** | 4106 | /** |
@@ -4304,7 +4288,8 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode, | |||
4304 | blocks_for_truncate(inode)); | 4288 | blocks_for_truncate(inode)); |
4305 | } | 4289 | } |
4306 | 4290 | ||
4307 | ext4_free_blocks(handle, inode, nr, 1, 1); | 4291 | ext4_free_blocks(handle, inode, 0, nr, 1, |
4292 | EXT4_FREE_BLOCKS_METADATA); | ||
4308 | 4293 | ||
4309 | if (parent_bh) { | 4294 | if (parent_bh) { |
4310 | /* | 4295 | /* |