summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>2008-04-29 22:03:59 -0400
committerTheodore Ts'o <tytso@mit.edu>2008-04-29 22:03:59 -0400
commit161e7b7c1d24112d188df9a7b30d468a8d135b96 (patch)
treebac6cea21f4a3bb96b8d16660ec9a503427c01a8
parent1a89734d4057066344356e9c7e13b6379497aebe (diff)
downloadlinux-3.10-161e7b7c1d24112d188df9a7b30d468a8d135b96.tar.gz
linux-3.10-161e7b7c1d24112d188df9a7b30d468a8d135b96.tar.bz2
linux-3.10-161e7b7c1d24112d188df9a7b30d468a8d135b96.zip
ext4: Cache the correct extent length for uninit extents
When we convert an uninitialized extent to an initialized extent we need to make sure we return the number of blocks in the extent from the file system block corresponding to logical file block. Otherwise we cache wrong extent details and this results in file system corruption. Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: Mingming Cao <cmm@us.ibm.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r--fs/ext4/extents.c48
1 files changed, 43 insertions, 5 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 7733e294336..c7c42c9c7bf 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -2266,7 +2266,8 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
ex->ee_len = orig_ex.ee_len;
ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
ext4_ext_dirty(handle, inode, path + depth);
- return le16_to_cpu(ex->ee_len);
+ /* zeroed the full extent */
+ return allocated;
}
/* ex1: ee_block to iblock - 1 : uninitialized */
@@ -2311,11 +2312,45 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
ex->ee_len = orig_ex.ee_len;
ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
ext4_ext_dirty(handle, inode, path + depth);
- return le16_to_cpu(ex->ee_len);
+ /* zeroed the full extent */
+ return allocated;
} else if (err)
goto fix_extent_len;
+ /*
+ * We need to zero out the second half because
+ * an fallocate request can update file size and
+ * converting the second half to initialized extent
+ * implies that we can leak some junk data to user
+ * space.
+ */
+ err = ext4_ext_zeroout(inode, ex3);
+ if (err) {
+ /*
+ * We should actually mark the
+ * second half as uninit and return error
+ * Insert would have changed the extent
+ */
+ depth = ext_depth(inode);
+ ext4_ext_drop_refs(path);
+ path = ext4_ext_find_extent(inode,
+ iblock, path);
+ if (IS_ERR(path)) {
+ err = PTR_ERR(path);
+ return err;
+ }
+ ex = path[depth].p_ext;
+ err = ext4_ext_get_access(handle, inode,
+ path + depth);
+ if (err)
+ return err;
+ ext4_ext_mark_uninitialized(ex);
+ ext4_ext_dirty(handle, inode, path + depth);
+ return err;
+ }
+
+ /* zeroed the second half */
return allocated;
}
ex3 = &newex;
@@ -2333,7 +2368,8 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
ex->ee_len = orig_ex.ee_len;
ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
ext4_ext_dirty(handle, inode, path + depth);
- return le16_to_cpu(ex->ee_len);
+ /* zeroed the full extent */
+ return allocated;
} else if (err)
goto fix_extent_len;
@@ -2381,7 +2417,8 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
ex->ee_len = orig_ex.ee_len;
ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
ext4_ext_dirty(handle, inode, path + depth);
- return le16_to_cpu(ex->ee_len);
+ /* zero out the first half */
+ return allocated;
}
}
/*
@@ -2448,7 +2485,8 @@ insert:
ex->ee_len = orig_ex.ee_len;
ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
ext4_ext_dirty(handle, inode, path + depth);
- return le16_to_cpu(ex->ee_len);
+ /* zero out the first half */
+ return allocated;
} else if (err)
goto fix_extent_len;
out: