diff options
author | Amit Arora <aarora@in.ibm.com> | 2007-05-24 13:04:13 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2007-05-31 16:20:15 -0400 |
commit | 25d14f983f70ddbeb15fa2d0f32f6b70bca42a15 (patch) | |
tree | 322e219240fc4b527b5c5b16d1f7a97b5dd0917b | |
parent | 8a9dc94498f39c259b011d0abcb89bdf73cafa2d (diff) |
ext4: Extent overlap bugfix
This patch adds a check for overlap of extents and cuts short the
new extent to be inserted, if there is a chance of overlap.
Signed-off-by: Amit Arora <aarora@in.ibm.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r-- | fs/ext4/extents.c | 60 | ||||
-rw-r--r-- | include/linux/ext4_fs_extents.h | 1 |
2 files changed, 59 insertions, 2 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 1630317817b8..03c777abf01f 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -1128,6 +1128,55 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, | |||
1128 | } | 1128 | } |
1129 | 1129 | ||
1130 | /* | 1130 | /* |
1131 | * check if a portion of the "newext" extent overlaps with an | ||
1132 | * existing extent. | ||
1133 | * | ||
1134 | * If there is an overlap discovered, it updates the length of the newext | ||
1135 | * such that there will be no overlap, and then returns 1. | ||
1136 | * If there is no overlap found, it returns 0. | ||
1137 | */ | ||
1138 | unsigned int ext4_ext_check_overlap(struct inode *inode, | ||
1139 | struct ext4_extent *newext, | ||
1140 | struct ext4_ext_path *path) | ||
1141 | { | ||
1142 | unsigned long b1, b2; | ||
1143 | unsigned int depth, len1; | ||
1144 | unsigned int ret = 0; | ||
1145 | |||
1146 | b1 = le32_to_cpu(newext->ee_block); | ||
1147 | len1 = le16_to_cpu(newext->ee_len); | ||
1148 | depth = ext_depth(inode); | ||
1149 | if (!path[depth].p_ext) | ||
1150 | goto out; | ||
1151 | b2 = le32_to_cpu(path[depth].p_ext->ee_block); | ||
1152 | |||
1153 | /* | ||
1154 | * get the next allocated block if the extent in the path | ||
1155 | * is before the requested block(s) | ||
1156 | */ | ||
1157 | if (b2 < b1) { | ||
1158 | b2 = ext4_ext_next_allocated_block(path); | ||
1159 | if (b2 == EXT_MAX_BLOCK) | ||
1160 | goto out; | ||
1161 | } | ||
1162 | |||
1163 | /* check for wrap through zero */ | ||
1164 | if (b1 + len1 < b1) { | ||
1165 | len1 = EXT_MAX_BLOCK - b1; | ||
1166 | newext->ee_len = cpu_to_le16(len1); | ||
1167 | ret = 1; | ||
1168 | } | ||
1169 | |||
1170 | /* check for overlap */ | ||
1171 | if (b1 + len1 > b2) { | ||
1172 | newext->ee_len = cpu_to_le16(b2 - b1); | ||
1173 | ret = 1; | ||
1174 | } | ||
1175 | out: | ||
1176 | return ret; | ||
1177 | } | ||
1178 | |||
1179 | /* | ||
1131 | * ext4_ext_insert_extent: | 1180 | * ext4_ext_insert_extent: |
1132 | * tries to merge requsted extent into the existing extent or | 1181 | * tries to merge requsted extent into the existing extent or |
1133 | * inserts requested extent as new one into the tree, | 1182 | * inserts requested extent as new one into the tree, |
@@ -2031,7 +2080,15 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | |||
2031 | 2080 | ||
2032 | /* allocate new block */ | 2081 | /* allocate new block */ |
2033 | goal = ext4_ext_find_goal(inode, path, iblock); | 2082 | goal = ext4_ext_find_goal(inode, path, iblock); |
2034 | allocated = max_blocks; | 2083 | |
2084 | /* Check if we can really insert (iblock)::(iblock+max_blocks) extent */ | ||
2085 | newex.ee_block = cpu_to_le32(iblock); | ||
2086 | newex.ee_len = cpu_to_le16(max_blocks); | ||
2087 | err = ext4_ext_check_overlap(inode, &newex, path); | ||
2088 | if (err) | ||
2089 | allocated = le16_to_cpu(newex.ee_len); | ||
2090 | else | ||
2091 | allocated = max_blocks; | ||
2035 | newblock = ext4_new_blocks(handle, inode, goal, &allocated, &err); | 2092 | newblock = ext4_new_blocks(handle, inode, goal, &allocated, &err); |
2036 | if (!newblock) | 2093 | if (!newblock) |
2037 | goto out2; | 2094 | goto out2; |
@@ -2039,7 +2096,6 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | |||
2039 | goal, newblock, allocated); | 2096 | goal, newblock, allocated); |
2040 | 2097 | ||
2041 | /* try to insert new extent into found leaf and return */ | 2098 | /* try to insert new extent into found leaf and return */ |
2042 | newex.ee_block = cpu_to_le32(iblock); | ||
2043 | ext4_ext_store_pblock(&newex, newblock); | 2099 | ext4_ext_store_pblock(&newex, newblock); |
2044 | newex.ee_len = cpu_to_le16(allocated); | 2100 | newex.ee_len = cpu_to_le16(allocated); |
2045 | err = ext4_ext_insert_extent(handle, inode, path, &newex); | 2101 | err = ext4_ext_insert_extent(handle, inode, path, &newex); |
diff --git a/include/linux/ext4_fs_extents.h b/include/linux/ext4_fs_extents.h index da23233a6627..acfe59740b03 100644 --- a/include/linux/ext4_fs_extents.h +++ b/include/linux/ext4_fs_extents.h | |||
@@ -190,6 +190,7 @@ ext4_ext_invalidate_cache(struct inode *inode) | |||
190 | 190 | ||
191 | extern int ext4_extent_tree_init(handle_t *, struct inode *); | 191 | extern int ext4_extent_tree_init(handle_t *, struct inode *); |
192 | extern int ext4_ext_calc_credits_for_insert(struct inode *, struct ext4_ext_path *); | 192 | extern int ext4_ext_calc_credits_for_insert(struct inode *, struct ext4_ext_path *); |
193 | extern unsigned int ext4_ext_check_overlap(struct inode *, struct ext4_extent *, struct ext4_ext_path *); | ||
193 | extern int ext4_ext_insert_extent(handle_t *, struct inode *, struct ext4_ext_path *, struct ext4_extent *); | 194 | extern int ext4_ext_insert_extent(handle_t *, struct inode *, struct ext4_ext_path *, struct ext4_extent *); |
194 | extern int ext4_ext_walk_space(struct inode *, unsigned long, unsigned long, ext_prepare_callback, void *); | 195 | extern int ext4_ext_walk_space(struct inode *, unsigned long, unsigned long, ext_prepare_callback, void *); |
195 | extern struct ext4_ext_path * ext4_ext_find_extent(struct inode *, int, struct ext4_ext_path *); | 196 | extern struct ext4_ext_path * ext4_ext_find_extent(struct inode *, int, struct ext4_ext_path *); |