diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/extent_map.c | 29 |
1 files changed, 22 insertions, 7 deletions
diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c index 1a5c69071df6..fcd4475d1f89 100644 --- a/fs/ocfs2/extent_map.c +++ b/fs/ocfs2/extent_map.c | |||
@@ -298,7 +298,7 @@ static int ocfs2_extent_map_find_leaf(struct inode *inode, | |||
298 | 298 | ||
299 | ret = ocfs2_extent_map_insert(inode, rec, | 299 | ret = ocfs2_extent_map_insert(inode, rec, |
300 | le16_to_cpu(el->l_tree_depth)); | 300 | le16_to_cpu(el->l_tree_depth)); |
301 | if (ret) { | 301 | if (ret && (ret != -EEXIST)) { |
302 | mlog_errno(ret); | 302 | mlog_errno(ret); |
303 | goto out_free; | 303 | goto out_free; |
304 | } | 304 | } |
@@ -427,6 +427,11 @@ static int ocfs2_extent_map_insert_entry(struct ocfs2_extent_map *em, | |||
427 | /* | 427 | /* |
428 | * Simple rule: on any return code other than -EAGAIN, anything left | 428 | * Simple rule: on any return code other than -EAGAIN, anything left |
429 | * in the insert_context will be freed. | 429 | * in the insert_context will be freed. |
430 | * | ||
431 | * Simple rule #2: A return code of -EEXIST from this function or | ||
432 | * its calls to ocfs2_extent_map_insert_entry() signifies that another | ||
433 | * thread beat us to the insert. It is not an actual error, but it | ||
434 | * tells the caller we have no more work to do. | ||
430 | */ | 435 | */ |
431 | static int ocfs2_extent_map_try_insert(struct inode *inode, | 436 | static int ocfs2_extent_map_try_insert(struct inode *inode, |
432 | struct ocfs2_extent_rec *rec, | 437 | struct ocfs2_extent_rec *rec, |
@@ -448,22 +453,32 @@ static int ocfs2_extent_map_try_insert(struct inode *inode, | |||
448 | goto out_unlock; | 453 | goto out_unlock; |
449 | } | 454 | } |
450 | 455 | ||
456 | /* Since insert_entry failed, the map MUST have old_ent */ | ||
451 | old_ent = ocfs2_extent_map_lookup(em, le32_to_cpu(rec->e_cpos), | 457 | old_ent = ocfs2_extent_map_lookup(em, le32_to_cpu(rec->e_cpos), |
452 | le32_to_cpu(rec->e_clusters), NULL, | 458 | le32_to_cpu(rec->e_clusters), |
453 | NULL); | 459 | NULL, NULL); |
454 | 460 | ||
455 | BUG_ON(!old_ent); | 461 | BUG_ON(!old_ent); |
456 | 462 | ||
457 | ret = -EEXIST; | 463 | if (old_ent->e_tree_depth < tree_depth) { |
458 | if (old_ent->e_tree_depth < tree_depth) | 464 | /* Another thread beat us to the lower tree_depth */ |
465 | ret = -EEXIST; | ||
459 | goto out_unlock; | 466 | goto out_unlock; |
467 | } | ||
460 | 468 | ||
461 | if (old_ent->e_tree_depth == tree_depth) { | 469 | if (old_ent->e_tree_depth == tree_depth) { |
470 | /* | ||
471 | * Another thread beat us to this tree_depth. | ||
472 | * Let's make sure we agree with that thread (the | ||
473 | * extent_rec should be identical). | ||
474 | */ | ||
462 | if (!memcmp(rec, &old_ent->e_rec, | 475 | if (!memcmp(rec, &old_ent->e_rec, |
463 | sizeof(struct ocfs2_extent_rec))) | 476 | sizeof(struct ocfs2_extent_rec))) |
464 | ret = 0; | 477 | ret = 0; |
478 | else | ||
479 | /* FIXME: Should this be ESRCH/EBADR??? */ | ||
480 | ret = -EEXIST; | ||
465 | 481 | ||
466 | /* FIXME: Should this be ESRCH/EBADR??? */ | ||
467 | goto out_unlock; | 482 | goto out_unlock; |
468 | } | 483 | } |
469 | 484 | ||
@@ -599,7 +614,7 @@ static int ocfs2_extent_map_insert(struct inode *inode, | |||
599 | tree_depth, &ctxt); | 614 | tree_depth, &ctxt); |
600 | } while (ret == -EAGAIN); | 615 | } while (ret == -EAGAIN); |
601 | 616 | ||
602 | if (ret < 0) | 617 | if ((ret < 0) && (ret != -EEXIST)) |
603 | mlog_errno(ret); | 618 | mlog_errno(ret); |
604 | 619 | ||
605 | if (ctxt.left_ent) | 620 | if (ctxt.left_ent) |