aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent_map.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-01-22 16:47:59 -0500
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:03:59 -0400
commit5f56406aabdf5444d040c5955effc665b1d0dbaf (patch)
tree59c82cc7f5d5de3b65b6eba24b505684eb7941d6 /fs/btrfs/extent_map.c
parentc1e32da616a17813f11b701a7a87775d35c12e3a (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.c45
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
206static struct rb_node *__tree_search(struct rb_root *root, u64 offset, 206static 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 }
359found:
333 atomic_inc(&em->refs); 360 atomic_inc(&em->refs);
334out: 361out:
335 read_unlock_irq(&tree->lock); 362 read_unlock_irq(&tree->lock);