diff options
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r-- | fs/btrfs/ctree.c | 93 |
1 files changed, 47 insertions, 46 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 9caeb377de63..73899d0f9d8f 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -287,7 +287,7 @@ int noinline __btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
287 | /* | 287 | /* |
288 | * There are only two places that can drop reference to | 288 | * There are only two places that can drop reference to |
289 | * tree blocks owned by living reloc trees, one is here, | 289 | * tree blocks owned by living reloc trees, one is here, |
290 | * the other place is btrfs_merge_path. In both places, | 290 | * the other place is btrfs_drop_subtree. In both places, |
291 | * we check reference count while tree block is locked. | 291 | * we check reference count while tree block is locked. |
292 | * Furthermore, if reference count is one, it won't get | 292 | * Furthermore, if reference count is one, it won't get |
293 | * increased by someone else. | 293 | * increased by someone else. |
@@ -312,9 +312,6 @@ int noinline __btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
312 | } | 312 | } |
313 | 313 | ||
314 | if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) { | 314 | if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) { |
315 | ret = btrfs_add_reloc_mapping(root, buf->start, | ||
316 | buf->len, cow->start); | ||
317 | BUG_ON(ret); | ||
318 | ret = btrfs_reloc_tree_cache_ref(trans, root, cow, buf->start); | 315 | ret = btrfs_reloc_tree_cache_ref(trans, root, cow, buf->start); |
319 | WARN_ON(ret); | 316 | WARN_ON(ret); |
320 | } | 317 | } |
@@ -1627,61 +1624,57 @@ int btrfs_merge_path(struct btrfs_trans_handle *trans, | |||
1627 | btrfs_node_key_to_cpu(eb, &key, slot); | 1624 | btrfs_node_key_to_cpu(eb, &key, slot); |
1628 | key_match = !memcmp(&key, &node_keys[level - 1], sizeof(key)); | 1625 | key_match = !memcmp(&key, &node_keys[level - 1], sizeof(key)); |
1629 | 1626 | ||
1627 | if (generation == trans->transid) { | ||
1628 | eb = read_tree_block(root, bytenr, blocksize, | ||
1629 | generation); | ||
1630 | btrfs_tree_lock(eb); | ||
1631 | } | ||
1632 | |||
1630 | /* | 1633 | /* |
1631 | * if node keys match and node pointer hasn't been modified | 1634 | * if node keys match and node pointer hasn't been modified |
1632 | * in the running transaction, we can merge the path. for | 1635 | * in the running transaction, we can merge the path. for |
1633 | * reloc trees, the node pointer check is skipped, this is | 1636 | * blocks owened by reloc trees, the node pointer check is |
1634 | * because the reloc trees are fully controlled by the space | 1637 | * skipped, this is because these blocks are fully controlled |
1635 | * balance code, no one else can modify them. | 1638 | * by the space balance code, no one else can modify them. |
1636 | */ | 1639 | */ |
1637 | if (!nodes[level - 1] || !key_match || | 1640 | if (!nodes[level - 1] || !key_match || |
1638 | (generation == trans->transid && | 1641 | (generation == trans->transid && |
1639 | root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID)) { | 1642 | btrfs_header_owner(eb) != BTRFS_TREE_RELOC_OBJECTID)) { |
1640 | next_level: | 1643 | if (level == 1 || level == lowest_level + 1) { |
1641 | if (level == 1 || level == lowest_level + 1) | 1644 | if (generation == trans->transid) { |
1645 | btrfs_tree_unlock(eb); | ||
1646 | free_extent_buffer(eb); | ||
1647 | } | ||
1642 | break; | 1648 | break; |
1649 | } | ||
1643 | 1650 | ||
1644 | eb = read_tree_block(root, bytenr, blocksize, | 1651 | if (generation != trans->transid) { |
1645 | generation); | 1652 | eb = read_tree_block(root, bytenr, blocksize, |
1646 | btrfs_tree_lock(eb); | 1653 | generation); |
1654 | btrfs_tree_lock(eb); | ||
1655 | } | ||
1647 | 1656 | ||
1648 | ret = btrfs_cow_block(trans, root, eb, parent, slot, | 1657 | ret = btrfs_cow_block(trans, root, eb, parent, slot, |
1649 | &eb, 0); | 1658 | &eb, 0); |
1650 | BUG_ON(ret); | 1659 | BUG_ON(ret); |
1651 | 1660 | ||
1661 | if (root->root_key.objectid == | ||
1662 | BTRFS_TREE_RELOC_OBJECTID) { | ||
1663 | if (!nodes[level - 1]) { | ||
1664 | nodes[level - 1] = eb->start; | ||
1665 | memcpy(&node_keys[level - 1], &key, | ||
1666 | sizeof(node_keys[0])); | ||
1667 | } else { | ||
1668 | WARN_ON(1); | ||
1669 | } | ||
1670 | } | ||
1671 | |||
1652 | btrfs_tree_unlock(parent); | 1672 | btrfs_tree_unlock(parent); |
1653 | free_extent_buffer(parent); | 1673 | free_extent_buffer(parent); |
1654 | parent = eb; | 1674 | parent = eb; |
1655 | continue; | 1675 | continue; |
1656 | } | 1676 | } |
1657 | 1677 | ||
1658 | if (generation == trans->transid) { | ||
1659 | u32 refs; | ||
1660 | BUG_ON(btrfs_header_owner(eb) != | ||
1661 | BTRFS_TREE_RELOC_OBJECTID); | ||
1662 | /* | ||
1663 | * lock the block to keep __btrfs_cow_block from | ||
1664 | * changing the reference count. | ||
1665 | */ | ||
1666 | eb = read_tree_block(root, bytenr, blocksize, | ||
1667 | generation); | ||
1668 | btrfs_tree_lock(eb); | ||
1669 | |||
1670 | ret = btrfs_lookup_extent_ref(trans, root, bytenr, | ||
1671 | blocksize, &refs); | ||
1672 | BUG_ON(ret); | ||
1673 | /* | ||
1674 | * if replace block whose reference count is one, | ||
1675 | * we have to "drop the subtree". so skip it for | ||
1676 | * simplicity | ||
1677 | */ | ||
1678 | if (refs == 1) { | ||
1679 | btrfs_tree_unlock(eb); | ||
1680 | free_extent_buffer(eb); | ||
1681 | goto next_level; | ||
1682 | } | ||
1683 | } | ||
1684 | |||
1685 | btrfs_set_node_blockptr(parent, slot, nodes[level - 1]); | 1678 | btrfs_set_node_blockptr(parent, slot, nodes[level - 1]); |
1686 | btrfs_set_node_ptr_generation(parent, slot, trans->transid); | 1679 | btrfs_set_node_ptr_generation(parent, slot, trans->transid); |
1687 | btrfs_mark_buffer_dirty(parent); | 1680 | btrfs_mark_buffer_dirty(parent); |
@@ -1693,16 +1686,24 @@ next_level: | |||
1693 | btrfs_header_generation(parent), | 1686 | btrfs_header_generation(parent), |
1694 | level - 1); | 1687 | level - 1); |
1695 | BUG_ON(ret); | 1688 | BUG_ON(ret); |
1696 | ret = btrfs_free_extent(trans, root, bytenr, | ||
1697 | blocksize, parent->start, | ||
1698 | btrfs_header_owner(parent), | ||
1699 | btrfs_header_generation(parent), | ||
1700 | level - 1, 1); | ||
1701 | BUG_ON(ret); | ||
1702 | 1689 | ||
1690 | /* | ||
1691 | * If the block was created in the running transaction, | ||
1692 | * it's possible this is the last reference to it, so we | ||
1693 | * should drop the subtree. | ||
1694 | */ | ||
1703 | if (generation == trans->transid) { | 1695 | if (generation == trans->transid) { |
1696 | ret = btrfs_drop_subtree(trans, root, eb, parent); | ||
1697 | BUG_ON(ret); | ||
1704 | btrfs_tree_unlock(eb); | 1698 | btrfs_tree_unlock(eb); |
1705 | free_extent_buffer(eb); | 1699 | free_extent_buffer(eb); |
1700 | } else { | ||
1701 | ret = btrfs_free_extent(trans, root, bytenr, | ||
1702 | blocksize, parent->start, | ||
1703 | btrfs_header_owner(parent), | ||
1704 | btrfs_header_generation(parent), | ||
1705 | level - 1, 1); | ||
1706 | BUG_ON(ret); | ||
1706 | } | 1707 | } |
1707 | break; | 1708 | break; |
1708 | } | 1709 | } |