aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/extents.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/extents.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/extents.c')
-rw-r--r--fs/ext4/extents.c24
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:
1957static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, 1958static 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