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/extents.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/extents.c')
-rw-r--r-- | fs/ext4/extents.c | 24 |
1 files changed, 9 insertions, 15 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 74dcff84c3a8..2c4a9321fb14 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -1007,7 +1007,8 @@ cleanup: | |||
1007 | for (i = 0; i < depth; i++) { | 1007 | for (i = 0; i < depth; i++) { |
1008 | if (!ablocks[i]) | 1008 | if (!ablocks[i]) |
1009 | continue; | 1009 | continue; |
1010 | ext4_free_blocks(handle, inode, ablocks[i], 1, 1); | 1010 | ext4_free_blocks(handle, inode, 0, ablocks[i], 1, |
1011 | EXT4_FREE_BLOCKS_METADATA); | ||
1011 | } | 1012 | } |
1012 | } | 1013 | } |
1013 | kfree(ablocks); | 1014 | kfree(ablocks); |
@@ -1957,7 +1958,6 @@ errout: | |||
1957 | static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, | 1958 | static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, |
1958 | struct ext4_ext_path *path) | 1959 | struct ext4_ext_path *path) |
1959 | { | 1960 | { |
1960 | struct buffer_head *bh; | ||
1961 | int err; | 1961 | int err; |
1962 | ext4_fsblk_t leaf; | 1962 | ext4_fsblk_t leaf; |
1963 | 1963 | ||
@@ -1973,9 +1973,8 @@ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, | |||
1973 | if (err) | 1973 | if (err) |
1974 | return err; | 1974 | return err; |
1975 | ext_debug("index is empty, remove it, free block %llu\n", leaf); | 1975 | ext_debug("index is empty, remove it, free block %llu\n", leaf); |
1976 | bh = sb_find_get_block(inode->i_sb, leaf); | 1976 | ext4_free_blocks(handle, inode, 0, leaf, 1, |
1977 | ext4_forget(handle, 1, inode, bh, leaf); | 1977 | EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET); |
1978 | ext4_free_blocks(handle, inode, leaf, 1, 1); | ||
1979 | return err; | 1978 | return err; |
1980 | } | 1979 | } |
1981 | 1980 | ||
@@ -2042,12 +2041,11 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode, | |||
2042 | struct ext4_extent *ex, | 2041 | struct ext4_extent *ex, |
2043 | ext4_lblk_t from, ext4_lblk_t to) | 2042 | ext4_lblk_t from, ext4_lblk_t to) |
2044 | { | 2043 | { |
2045 | struct buffer_head *bh; | ||
2046 | unsigned short ee_len = ext4_ext_get_actual_len(ex); | 2044 | unsigned short ee_len = ext4_ext_get_actual_len(ex); |
2047 | int i, metadata = 0; | 2045 | int flags = EXT4_FREE_BLOCKS_FORGET; |
2048 | 2046 | ||
2049 | if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) | 2047 | if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) |
2050 | metadata = 1; | 2048 | flags |= EXT4_FREE_BLOCKS_METADATA; |
2051 | #ifdef EXTENTS_STATS | 2049 | #ifdef EXTENTS_STATS |
2052 | { | 2050 | { |
2053 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); | 2051 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); |
@@ -2072,11 +2070,7 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode, | |||
2072 | num = le32_to_cpu(ex->ee_block) + ee_len - from; | 2070 | num = le32_to_cpu(ex->ee_block) + ee_len - from; |
2073 | start = ext_pblock(ex) + ee_len - num; | 2071 | start = ext_pblock(ex) + ee_len - num; |
2074 | ext_debug("free last %u blocks starting %llu\n", num, start); | 2072 | ext_debug("free last %u blocks starting %llu\n", num, start); |
2075 | for (i = 0; i < num; i++) { | 2073 | ext4_free_blocks(handle, inode, 0, start, num, flags); |
2076 | bh = sb_find_get_block(inode->i_sb, start + i); | ||
2077 | ext4_forget(handle, metadata, inode, bh, start + i); | ||
2078 | } | ||
2079 | ext4_free_blocks(handle, inode, start, num, metadata); | ||
2080 | } else if (from == le32_to_cpu(ex->ee_block) | 2074 | } else if (from == le32_to_cpu(ex->ee_block) |
2081 | && to <= le32_to_cpu(ex->ee_block) + ee_len - 1) { | 2075 | && to <= le32_to_cpu(ex->ee_block) + ee_len - 1) { |
2082 | printk(KERN_INFO "strange request: removal %u-%u from %u:%u\n", | 2076 | printk(KERN_INFO "strange request: removal %u-%u from %u:%u\n", |
@@ -3319,8 +3313,8 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | |||
3319 | /* not a good idea to call discard here directly, | 3313 | /* not a good idea to call discard here directly, |
3320 | * but otherwise we'd need to call it every free() */ | 3314 | * but otherwise we'd need to call it every free() */ |
3321 | ext4_discard_preallocations(inode); | 3315 | ext4_discard_preallocations(inode); |
3322 | ext4_free_blocks(handle, inode, ext_pblock(&newex), | 3316 | ext4_free_blocks(handle, inode, 0, ext_pblock(&newex), |
3323 | ext4_ext_get_actual_len(&newex), 0); | 3317 | ext4_ext_get_actual_len(&newex), 0); |
3324 | goto out2; | 3318 | goto out2; |
3325 | } | 3319 | } |
3326 | 3320 | ||