aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-08-07 15:52:19 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-08-07 15:52:19 -0400
commit9f3a742736cecda5a8778be70faa2f779458839f (patch)
tree500ef3701521e63254dbe82e5c71e7ccff746275 /fs/btrfs/extent-tree.c
parent8578f0f1fda41f8429a1037022b720275102ca65 (diff)
Btrfs: Do snapshot deletion in smaller chunks.
Before, snapshot deletion was a single atomic unit. This caused considerable lock contention and required an unbounded amount of space. Now, the drop_progress field in the root item is used to indicate how far along snapshot deletion is, and to resume where it left off. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r--fs/btrfs/extent-tree.c45
1 files changed, 41 insertions, 4 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 5ace2c33f1aa..9455974dabea 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -1561,12 +1561,21 @@ static int walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root
1561 int i; 1561 int i;
1562 int slot; 1562 int slot;
1563 int ret; 1563 int ret;
1564 struct btrfs_root_item *root_item = &root->root_item;
1565
1564 for(i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) { 1566 for(i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) {
1565 slot = path->slots[i]; 1567 slot = path->slots[i];
1566 if (slot < btrfs_header_nritems( 1568 if (slot < btrfs_header_nritems(
1567 btrfs_buffer_header(path->nodes[i])) - 1) { 1569 btrfs_buffer_header(path->nodes[i])) - 1) {
1570 struct btrfs_node *node;
1571 node = btrfs_buffer_node(path->nodes[i]);
1568 path->slots[i]++; 1572 path->slots[i]++;
1569 *level = i; 1573 *level = i;
1574 WARN_ON(*level == 0);
1575 memcpy(&root_item->drop_progress,
1576 &node->ptrs[path->slots[i]].key,
1577 sizeof(root_item->drop_progress));
1578 root_item->drop_level = i;
1570 return 0; 1579 return 0;
1571 } else { 1580 } else {
1572 ret = btrfs_free_extent(trans, root, 1581 ret = btrfs_free_extent(trans, root,
@@ -1587,7 +1596,7 @@ static int walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root
1587 * decremented. 1596 * decremented.
1588 */ 1597 */
1589int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root 1598int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
1590 *root, struct buffer_head *snap) 1599 *root)
1591{ 1600{
1592 int ret = 0; 1601 int ret = 0;
1593 int wret; 1602 int wret;
@@ -1595,14 +1604,33 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
1595 struct btrfs_path *path; 1604 struct btrfs_path *path;
1596 int i; 1605 int i;
1597 int orig_level; 1606 int orig_level;
1607 int num_walks = 0;
1608 struct btrfs_root_item *root_item = &root->root_item;
1598 1609
1599 path = btrfs_alloc_path(); 1610 path = btrfs_alloc_path();
1600 BUG_ON(!path); 1611 BUG_ON(!path);
1601 1612
1602 level = btrfs_header_level(btrfs_buffer_header(snap)); 1613 level = btrfs_header_level(btrfs_buffer_header(root->node));
1603 orig_level = level; 1614 orig_level = level;
1604 path->nodes[level] = snap; 1615 if (btrfs_disk_key_objectid(&root_item->drop_progress) == 0) {
1605 path->slots[level] = 0; 1616 path->nodes[level] = root->node;
1617 path->slots[level] = 0;
1618 } else {
1619 struct btrfs_key key;
1620 struct btrfs_disk_key *found_key;
1621 struct btrfs_node *node;
1622 btrfs_disk_key_to_cpu(&key, &root_item->drop_progress);
1623 wret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
1624 if (ret < 0) {
1625 ret = wret;
1626 goto out;
1627 }
1628 level = root_item->drop_level;
1629 node = btrfs_buffer_node(path->nodes[level]);
1630 found_key = &node->ptrs[path->slots[level]].key;
1631 WARN_ON(memcmp(found_key, &root_item->drop_progress,
1632 sizeof(*found_key)));
1633 }
1606 while(1) { 1634 while(1) {
1607 wret = walk_down_tree(trans, root, path, &level); 1635 wret = walk_down_tree(trans, root, path, &level);
1608 if (wret > 0) 1636 if (wret > 0)
@@ -1615,12 +1643,21 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
1615 break; 1643 break;
1616 if (wret < 0) 1644 if (wret < 0)
1617 ret = wret; 1645 ret = wret;
1646 num_walks++;
1647 if (num_walks > 10) {
1648 struct btrfs_key key;
1649 btrfs_disk_key_to_cpu(&key, &root_item->drop_progress);
1650 ret = -EAGAIN;
1651 get_bh(root->node);
1652 break;
1653 }
1618 } 1654 }
1619 for (i = 0; i <= orig_level; i++) { 1655 for (i = 0; i <= orig_level; i++) {
1620 if (path->nodes[i]) { 1656 if (path->nodes[i]) {
1621 btrfs_block_release(root, path->nodes[i]); 1657 btrfs_block_release(root, path->nodes[i]);
1622 } 1658 }
1623 } 1659 }
1660out:
1624 btrfs_free_path(path); 1661 btrfs_free_path(path);
1625 return ret; 1662 return ret;
1626} 1663}