aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2014-09-01 14:40:09 -0400
committerTheodore Ts'o <tytso@mit.edu>2014-09-01 14:40:09 -0400
commit10809df84a4d868db61af621bae3658494165279 (patch)
tree07058f847b286c07f27c82033e7b2d8c0fc1af7a /fs
parentb7ea89ad0a6b855172158a999d3f5008403f4011 (diff)
ext4: teach ext4_ext_find_extent() to realloc path if necessary
This adds additional safety in case for some reason we end reusing a path structure which isn't big enough for current depth of the inode. Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'fs')
-rw-r--r--fs/ext4/ext4_extents.h1
-rw-r--r--fs/ext4/extents.c20
2 files changed, 11 insertions, 10 deletions
diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h
index a867f5ca9991..3c9381547094 100644
--- a/fs/ext4/ext4_extents.h
+++ b/fs/ext4/ext4_extents.h
@@ -123,6 +123,7 @@ find_ext4_extent_tail(struct ext4_extent_header *eh)
123struct ext4_ext_path { 123struct ext4_ext_path {
124 ext4_fsblk_t p_block; 124 ext4_fsblk_t p_block;
125 __u16 p_depth; 125 __u16 p_depth;
126 __u16 p_maxdepth;
126 struct ext4_extent *p_ext; 127 struct ext4_extent *p_ext;
127 struct ext4_extent_idx *p_idx; 128 struct ext4_extent_idx *p_idx;
128 struct ext4_extent_header *p_hdr; 129 struct ext4_extent_header *p_hdr;
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 538f9a4d96ff..c94c7480053e 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -869,14 +869,20 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block,
869 eh = ext_inode_hdr(inode); 869 eh = ext_inode_hdr(inode);
870 depth = ext_depth(inode); 870 depth = ext_depth(inode);
871 871
872 if (path) 872 if (path) {
873 ext4_ext_drop_refs(path); 873 ext4_ext_drop_refs(path);
874 else { 874 if (depth > path[0].p_maxdepth) {
875 kfree(path);
876 *orig_path = path = NULL;
877 }
878 }
879 if (!path) {
875 /* account possible depth increase */ 880 /* account possible depth increase */
876 path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 2), 881 path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 2),
877 GFP_NOFS); 882 GFP_NOFS);
878 if (unlikely(!path)) 883 if (unlikely(!path))
879 return ERR_PTR(-ENOMEM); 884 return ERR_PTR(-ENOMEM);
885 path[0].p_maxdepth = depth + 1;
880 } 886 }
881 path[0].p_hdr = eh; 887 path[0].p_hdr = eh;
882 path[0].p_bh = NULL; 888 path[0].p_bh = NULL;
@@ -1820,6 +1826,7 @@ static void ext4_ext_try_to_merge_up(handle_t *handle,
1820 sizeof(struct ext4_extent_idx); 1826 sizeof(struct ext4_extent_idx);
1821 s += sizeof(struct ext4_extent_header); 1827 s += sizeof(struct ext4_extent_header);
1822 1828
1829 path[1].p_maxdepth = path[0].p_maxdepth;
1823 memcpy(path[0].p_hdr, path[1].p_hdr, s); 1830 memcpy(path[0].p_hdr, path[1].p_hdr, s);
1824 path[0].p_depth = 0; 1831 path[0].p_depth = 0;
1825 path[0].p_ext = EXT_FIRST_EXTENT(path[0].p_hdr) + 1832 path[0].p_ext = EXT_FIRST_EXTENT(path[0].p_hdr) +
@@ -2150,12 +2157,6 @@ static int ext4_fill_fiemap_extents(struct inode *inode,
2150 /* find extent for this block */ 2157 /* find extent for this block */
2151 down_read(&EXT4_I(inode)->i_data_sem); 2158 down_read(&EXT4_I(inode)->i_data_sem);
2152 2159
2153 if (path && ext_depth(inode) != depth) {
2154 /* depth was changed. we have to realloc path */
2155 kfree(path);
2156 path = NULL;
2157 }
2158
2159 path = ext4_ext_find_extent(inode, block, &path, 0); 2160 path = ext4_ext_find_extent(inode, block, &path, 0);
2160 if (IS_ERR(path)) { 2161 if (IS_ERR(path)) {
2161 up_read(&EXT4_I(inode)->i_data_sem); 2162 up_read(&EXT4_I(inode)->i_data_sem);
@@ -2173,7 +2174,6 @@ static int ext4_fill_fiemap_extents(struct inode *inode,
2173 } 2174 }
2174 ex = path[depth].p_ext; 2175 ex = path[depth].p_ext;
2175 next = ext4_ext_next_allocated_block(path); 2176 next = ext4_ext_next_allocated_block(path);
2176 ext4_ext_drop_refs(path);
2177 2177
2178 flags = 0; 2178 flags = 0;
2179 exists = 0; 2179 exists = 0;
@@ -2897,7 +2897,7 @@ again:
2897 ext4_journal_stop(handle); 2897 ext4_journal_stop(handle);
2898 return -ENOMEM; 2898 return -ENOMEM;
2899 } 2899 }
2900 path[0].p_depth = depth; 2900 path[0].p_maxdepth = path[0].p_depth = depth;
2901 path[0].p_hdr = ext_inode_hdr(inode); 2901 path[0].p_hdr = ext_inode_hdr(inode);
2902 i = 0; 2902 i = 0;
2903 2903