diff options
-rw-r--r-- | fs/btrfs/inode-item.c | 9 | ||||
-rw-r--r-- | fs/btrfs/tree-log.c | 39 |
2 files changed, 43 insertions, 5 deletions
diff --git a/fs/btrfs/inode-item.c b/fs/btrfs/inode-item.c index 8ffa4783cbf4..265e03c73f4d 100644 --- a/fs/btrfs/inode-item.c +++ b/fs/btrfs/inode-item.c | |||
@@ -344,6 +344,7 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, | |||
344 | return -ENOMEM; | 344 | return -ENOMEM; |
345 | 345 | ||
346 | path->leave_spinning = 1; | 346 | path->leave_spinning = 1; |
347 | path->skip_release_on_error = 1; | ||
347 | ret = btrfs_insert_empty_item(trans, root, path, &key, | 348 | ret = btrfs_insert_empty_item(trans, root, path, &key, |
348 | ins_len); | 349 | ins_len); |
349 | if (ret == -EEXIST) { | 350 | if (ret == -EEXIST) { |
@@ -362,8 +363,12 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, | |||
362 | ptr = (unsigned long)(ref + 1); | 363 | ptr = (unsigned long)(ref + 1); |
363 | ret = 0; | 364 | ret = 0; |
364 | } else if (ret < 0) { | 365 | } else if (ret < 0) { |
365 | if (ret == -EOVERFLOW) | 366 | if (ret == -EOVERFLOW) { |
366 | ret = -EMLINK; | 367 | if (find_name_in_backref(path, name, name_len, &ref)) |
368 | ret = -EEXIST; | ||
369 | else | ||
370 | ret = -EMLINK; | ||
371 | } | ||
367 | goto out; | 372 | goto out; |
368 | } else { | 373 | } else { |
369 | ref = btrfs_item_ptr(path->nodes[0], path->slots[0], | 374 | ref = btrfs_item_ptr(path->nodes[0], path->slots[0], |
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 533cdb02978a..a26658756537 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -453,11 +453,13 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans, | |||
453 | insert: | 453 | insert: |
454 | btrfs_release_path(path); | 454 | btrfs_release_path(path); |
455 | /* try to insert the key into the destination tree */ | 455 | /* try to insert the key into the destination tree */ |
456 | path->skip_release_on_error = 1; | ||
456 | ret = btrfs_insert_empty_item(trans, root, path, | 457 | ret = btrfs_insert_empty_item(trans, root, path, |
457 | key, item_size); | 458 | key, item_size); |
459 | path->skip_release_on_error = 0; | ||
458 | 460 | ||
459 | /* make sure any existing item is the correct size */ | 461 | /* make sure any existing item is the correct size */ |
460 | if (ret == -EEXIST) { | 462 | if (ret == -EEXIST || ret == -EOVERFLOW) { |
461 | u32 found_size; | 463 | u32 found_size; |
462 | found_size = btrfs_item_size_nr(path->nodes[0], | 464 | found_size = btrfs_item_size_nr(path->nodes[0], |
463 | path->slots[0]); | 465 | path->slots[0]); |
@@ -844,7 +846,7 @@ out: | |||
844 | static noinline int backref_in_log(struct btrfs_root *log, | 846 | static noinline int backref_in_log(struct btrfs_root *log, |
845 | struct btrfs_key *key, | 847 | struct btrfs_key *key, |
846 | u64 ref_objectid, | 848 | u64 ref_objectid, |
847 | char *name, int namelen) | 849 | const char *name, int namelen) |
848 | { | 850 | { |
849 | struct btrfs_path *path; | 851 | struct btrfs_path *path; |
850 | struct btrfs_inode_ref *ref; | 852 | struct btrfs_inode_ref *ref; |
@@ -1556,6 +1558,30 @@ static noinline int insert_one_name(struct btrfs_trans_handle *trans, | |||
1556 | } | 1558 | } |
1557 | 1559 | ||
1558 | /* | 1560 | /* |
1561 | * Return true if an inode reference exists in the log for the given name, | ||
1562 | * inode and parent inode. | ||
1563 | */ | ||
1564 | static bool name_in_log_ref(struct btrfs_root *log_root, | ||
1565 | const char *name, const int name_len, | ||
1566 | const u64 dirid, const u64 ino) | ||
1567 | { | ||
1568 | struct btrfs_key search_key; | ||
1569 | |||
1570 | search_key.objectid = ino; | ||
1571 | search_key.type = BTRFS_INODE_REF_KEY; | ||
1572 | search_key.offset = dirid; | ||
1573 | if (backref_in_log(log_root, &search_key, dirid, name, name_len)) | ||
1574 | return true; | ||
1575 | |||
1576 | search_key.type = BTRFS_INODE_EXTREF_KEY; | ||
1577 | search_key.offset = btrfs_extref_hash(dirid, name, name_len); | ||
1578 | if (backref_in_log(log_root, &search_key, dirid, name, name_len)) | ||
1579 | return true; | ||
1580 | |||
1581 | return false; | ||
1582 | } | ||
1583 | |||
1584 | /* | ||
1559 | * take a single entry in a log directory item and replay it into | 1585 | * take a single entry in a log directory item and replay it into |
1560 | * the subvolume. | 1586 | * the subvolume. |
1561 | * | 1587 | * |
@@ -1665,10 +1691,17 @@ out: | |||
1665 | return ret; | 1691 | return ret; |
1666 | 1692 | ||
1667 | insert: | 1693 | insert: |
1694 | if (name_in_log_ref(root->log_root, name, name_len, | ||
1695 | key->objectid, log_key.objectid)) { | ||
1696 | /* The dentry will be added later. */ | ||
1697 | ret = 0; | ||
1698 | update_size = false; | ||
1699 | goto out; | ||
1700 | } | ||
1668 | btrfs_release_path(path); | 1701 | btrfs_release_path(path); |
1669 | ret = insert_one_name(trans, root, path, key->objectid, key->offset, | 1702 | ret = insert_one_name(trans, root, path, key->objectid, key->offset, |
1670 | name, name_len, log_type, &log_key); | 1703 | name, name_len, log_type, &log_key); |
1671 | if (ret && ret != -ENOENT) | 1704 | if (ret && ret != -ENOENT && ret != -EEXIST) |
1672 | goto out; | 1705 | goto out; |
1673 | update_size = false; | 1706 | update_size = false; |
1674 | ret = 0; | 1707 | ret = 0; |