diff options
author | Theodore Ts'o <tytso@mit.edu> | 2014-09-01 14:40:09 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2014-09-01 14:40:09 -0400 |
commit | 10809df84a4d868db61af621bae3658494165279 (patch) | |
tree | 07058f847b286c07f27c82033e7b2d8c0fc1af7a /fs | |
parent | b7ea89ad0a6b855172158a999d3f5008403f4011 (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.h | 1 | ||||
-rw-r--r-- | fs/ext4/extents.c | 20 |
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) | |||
123 | struct ext4_ext_path { | 123 | struct 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 | ||