diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-01-22 16:47:59 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:03:59 -0400 |
commit | 5f56406aabdf5444d040c5955effc665b1d0dbaf (patch) | |
tree | 59c82cc7f5d5de3b65b6eba24b505684eb7941d6 /fs/btrfs/extent_map.c | |
parent | c1e32da616a17813f11b701a7a87775d35c12e3a (diff) |
Btrfs: Fix hole insertion corner cases
There were a few places that could cause duplicate extent insertion,
this adjusts the code that creates holes to avoid it.
lookup_extent_map is changed to correctly return all of the extents in a
range, even when there are none matching at the start of the range.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent_map.c')
-rw-r--r-- | fs/btrfs/extent_map.c | 45 |
1 files changed, 36 insertions, 9 deletions
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index 485cf0719b3c..010a287fbd71 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c | |||
@@ -204,10 +204,12 @@ static struct rb_node *tree_insert(struct rb_root *root, u64 offset, | |||
204 | } | 204 | } |
205 | 205 | ||
206 | static struct rb_node *__tree_search(struct rb_root *root, u64 offset, | 206 | static struct rb_node *__tree_search(struct rb_root *root, u64 offset, |
207 | struct rb_node **prev_ret) | 207 | struct rb_node **prev_ret, |
208 | struct rb_node **next_ret) | ||
208 | { | 209 | { |
209 | struct rb_node * n = root->rb_node; | 210 | struct rb_node * n = root->rb_node; |
210 | struct rb_node *prev = NULL; | 211 | struct rb_node *prev = NULL; |
212 | struct rb_node *orig_prev = NULL; | ||
211 | struct tree_entry *entry; | 213 | struct tree_entry *entry; |
212 | struct tree_entry *prev_entry = NULL; | 214 | struct tree_entry *prev_entry = NULL; |
213 | 215 | ||
@@ -223,13 +225,25 @@ static struct rb_node *__tree_search(struct rb_root *root, u64 offset, | |||
223 | else | 225 | else |
224 | return n; | 226 | return n; |
225 | } | 227 | } |
226 | if (!prev_ret) | 228 | |
227 | return NULL; | 229 | if (prev_ret) { |
228 | while(prev && offset > prev_entry->end) { | 230 | orig_prev = prev; |
229 | prev = rb_next(prev); | 231 | while(prev && offset > prev_entry->end) { |
232 | prev = rb_next(prev); | ||
233 | prev_entry = rb_entry(prev, struct tree_entry, rb_node); | ||
234 | } | ||
235 | *prev_ret = prev; | ||
236 | prev = orig_prev; | ||
237 | } | ||
238 | |||
239 | if (next_ret) { | ||
230 | prev_entry = rb_entry(prev, struct tree_entry, rb_node); | 240 | prev_entry = rb_entry(prev, struct tree_entry, rb_node); |
241 | while(prev && offset < prev_entry->start) { | ||
242 | prev = rb_prev(prev); | ||
243 | prev_entry = rb_entry(prev, struct tree_entry, rb_node); | ||
244 | } | ||
245 | *next_ret = prev; | ||
231 | } | 246 | } |
232 | *prev_ret = prev; | ||
233 | return NULL; | 247 | return NULL; |
234 | } | 248 | } |
235 | 249 | ||
@@ -237,7 +251,7 @@ static inline struct rb_node *tree_search(struct rb_root *root, u64 offset) | |||
237 | { | 251 | { |
238 | struct rb_node *prev; | 252 | struct rb_node *prev; |
239 | struct rb_node *ret; | 253 | struct rb_node *ret; |
240 | ret = __tree_search(root, offset, &prev); | 254 | ret = __tree_search(root, offset, &prev, NULL); |
241 | if (!ret) | 255 | if (!ret) |
242 | return prev; | 256 | return prev; |
243 | return ret; | 257 | return ret; |
@@ -248,7 +262,7 @@ static int tree_delete(struct rb_root *root, u64 offset) | |||
248 | struct rb_node *node; | 262 | struct rb_node *node; |
249 | struct tree_entry *entry; | 263 | struct tree_entry *entry; |
250 | 264 | ||
251 | node = __tree_search(root, offset, NULL); | 265 | node = __tree_search(root, offset, NULL, NULL); |
252 | if (!node) | 266 | if (!node) |
253 | return -ENOENT; | 267 | return -ENOENT; |
254 | entry = rb_entry(node, struct tree_entry, rb_node); | 268 | entry = rb_entry(node, struct tree_entry, rb_node); |
@@ -314,9 +328,21 @@ struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree, | |||
314 | { | 328 | { |
315 | struct extent_map *em; | 329 | struct extent_map *em; |
316 | struct rb_node *rb_node; | 330 | struct rb_node *rb_node; |
331 | struct rb_node *prev = NULL; | ||
332 | struct rb_node *next = NULL; | ||
317 | 333 | ||
318 | read_lock_irq(&tree->lock); | 334 | read_lock_irq(&tree->lock); |
319 | rb_node = tree_search(&tree->map, start); | 335 | rb_node = __tree_search(&tree->map, start, &prev, &next); |
336 | if (!rb_node && prev) { | ||
337 | em = rb_entry(prev, struct extent_map, rb_node); | ||
338 | if (em->start <= end && em->end >= start) | ||
339 | goto found; | ||
340 | } | ||
341 | if (!rb_node && next) { | ||
342 | em = rb_entry(next, struct extent_map, rb_node); | ||
343 | if (em->start <= end && em->end >= start) | ||
344 | goto found; | ||
345 | } | ||
320 | if (!rb_node) { | 346 | if (!rb_node) { |
321 | em = NULL; | 347 | em = NULL; |
322 | goto out; | 348 | goto out; |
@@ -330,6 +356,7 @@ struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree, | |||
330 | em = NULL; | 356 | em = NULL; |
331 | goto out; | 357 | goto out; |
332 | } | 358 | } |
359 | found: | ||
333 | atomic_inc(&em->refs); | 360 | atomic_inc(&em->refs); |
334 | out: | 361 | out: |
335 | read_unlock_irq(&tree->lock); | 362 | read_unlock_irq(&tree->lock); |