diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-11-07 13:31:03 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:03:57 -0400 |
commit | 34a3821873aeabff2607c8093bce82cd1fbcfd60 (patch) | |
tree | bf204e4a0b45fd764b7fadea23e45034021675c4 /fs | |
parent | e644d021e328d3902559e5db687383f2da85993c (diff) |
Btrfs: Change push_leaf_{leaf,right} to empty the src leave during item deletion
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ctree.c | 74 |
1 files changed, 50 insertions, 24 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index ea9b46699349..1b47fe71e0b4 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -1394,19 +1394,21 @@ int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf) | |||
1394 | * room, 0 if everything worked out and < 0 if there were major errors. | 1394 | * room, 0 if everything worked out and < 0 if there were major errors. |
1395 | */ | 1395 | */ |
1396 | static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root | 1396 | static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root |
1397 | *root, struct btrfs_path *path, int data_size) | 1397 | *root, struct btrfs_path *path, int data_size, |
1398 | int empty) | ||
1398 | { | 1399 | { |
1399 | struct extent_buffer *left = path->nodes[0]; | 1400 | struct extent_buffer *left = path->nodes[0]; |
1400 | struct extent_buffer *right; | 1401 | struct extent_buffer *right; |
1401 | struct extent_buffer *upper; | 1402 | struct extent_buffer *upper; |
1402 | struct btrfs_disk_key disk_key; | 1403 | struct btrfs_disk_key disk_key; |
1403 | int slot; | 1404 | int slot; |
1404 | int i; | 1405 | u32 i; |
1405 | int free_space; | 1406 | int free_space; |
1406 | int push_space = 0; | 1407 | int push_space = 0; |
1407 | int push_items = 0; | 1408 | int push_items = 0; |
1408 | struct btrfs_item *item; | 1409 | struct btrfs_item *item; |
1409 | u32 left_nritems; | 1410 | u32 left_nritems; |
1411 | u32 nr; | ||
1410 | u32 right_nritems; | 1412 | u32 right_nritems; |
1411 | u32 data_end; | 1413 | u32 data_end; |
1412 | u32 this_item_size; | 1414 | u32 this_item_size; |
@@ -1447,7 +1449,13 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1447 | return 1; | 1449 | return 1; |
1448 | } | 1450 | } |
1449 | 1451 | ||
1450 | for (i = left_nritems - 1; i >= 1; i--) { | 1452 | if (empty) |
1453 | nr = 0; | ||
1454 | else | ||
1455 | nr = 1; | ||
1456 | |||
1457 | i = left_nritems - 1; | ||
1458 | while (i >= nr) { | ||
1451 | item = btrfs_item_nr(left, i); | 1459 | item = btrfs_item_nr(left, i); |
1452 | 1460 | ||
1453 | if (path->slots[0] == i) | 1461 | if (path->slots[0] == i) |
@@ -1466,6 +1474,9 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1466 | break; | 1474 | break; |
1467 | push_items++; | 1475 | push_items++; |
1468 | push_space += this_item_size + sizeof(*item); | 1476 | push_space += this_item_size + sizeof(*item); |
1477 | if (i == 0) | ||
1478 | break; | ||
1479 | i--; | ||
1469 | } | 1480 | } |
1470 | if (left->map_token) { | 1481 | if (left->map_token) { |
1471 | unmap_extent_buffer(left, left->map_token, KM_USER1); | 1482 | unmap_extent_buffer(left, left->map_token, KM_USER1); |
@@ -1477,11 +1488,12 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1477 | return 1; | 1488 | return 1; |
1478 | } | 1489 | } |
1479 | 1490 | ||
1480 | if (push_items == left_nritems) | 1491 | if (!empty && push_items == left_nritems) |
1481 | WARN_ON(1); | 1492 | WARN_ON(1); |
1482 | 1493 | ||
1483 | /* push left to right */ | 1494 | /* push left to right */ |
1484 | right_nritems = btrfs_header_nritems(right); | 1495 | right_nritems = btrfs_header_nritems(right); |
1496 | |||
1485 | push_space = btrfs_item_end_nr(left, left_nritems - push_items); | 1497 | push_space = btrfs_item_end_nr(left, left_nritems - push_items); |
1486 | push_space -= leaf_data_end(root, left); | 1498 | push_space -= leaf_data_end(root, left); |
1487 | 1499 | ||
@@ -1511,7 +1523,6 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1511 | right_nritems += push_items; | 1523 | right_nritems += push_items; |
1512 | btrfs_set_header_nritems(right, right_nritems); | 1524 | btrfs_set_header_nritems(right, right_nritems); |
1513 | push_space = BTRFS_LEAF_DATA_SIZE(root); | 1525 | push_space = BTRFS_LEAF_DATA_SIZE(root); |
1514 | |||
1515 | for (i = 0; i < right_nritems; i++) { | 1526 | for (i = 0; i < right_nritems; i++) { |
1516 | item = btrfs_item_nr(right, i); | 1527 | item = btrfs_item_nr(right, i); |
1517 | if (!right->map_token) { | 1528 | if (!right->map_token) { |
@@ -1532,7 +1543,8 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1532 | left_nritems -= push_items; | 1543 | left_nritems -= push_items; |
1533 | btrfs_set_header_nritems(left, left_nritems); | 1544 | btrfs_set_header_nritems(left, left_nritems); |
1534 | 1545 | ||
1535 | btrfs_mark_buffer_dirty(left); | 1546 | if (left_nritems) |
1547 | btrfs_mark_buffer_dirty(left); | ||
1536 | btrfs_mark_buffer_dirty(right); | 1548 | btrfs_mark_buffer_dirty(right); |
1537 | 1549 | ||
1538 | btrfs_item_key(right, &disk_key, 0); | 1550 | btrfs_item_key(right, &disk_key, 0); |
@@ -1555,7 +1567,8 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1555 | * least data_size bytes. returns zero if the push worked, nonzero otherwise | 1567 | * least data_size bytes. returns zero if the push worked, nonzero otherwise |
1556 | */ | 1568 | */ |
1557 | static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root | 1569 | static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root |
1558 | *root, struct btrfs_path *path, int data_size) | 1570 | *root, struct btrfs_path *path, int data_size, |
1571 | int empty) | ||
1559 | { | 1572 | { |
1560 | struct btrfs_disk_key disk_key; | 1573 | struct btrfs_disk_key disk_key; |
1561 | struct extent_buffer *right = path->nodes[0]; | 1574 | struct extent_buffer *right = path->nodes[0]; |
@@ -1568,6 +1581,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1568 | struct btrfs_item *item; | 1581 | struct btrfs_item *item; |
1569 | u32 old_left_nritems; | 1582 | u32 old_left_nritems; |
1570 | u32 right_nritems; | 1583 | u32 right_nritems; |
1584 | u32 nr; | ||
1571 | int ret = 0; | 1585 | int ret = 0; |
1572 | int wret; | 1586 | int wret; |
1573 | u32 this_item_size; | 1587 | u32 this_item_size; |
@@ -1607,7 +1621,12 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1607 | return 1; | 1621 | return 1; |
1608 | } | 1622 | } |
1609 | 1623 | ||
1610 | for (i = 0; i < right_nritems - 1; i++) { | 1624 | if (empty) |
1625 | nr = right_nritems; | ||
1626 | else | ||
1627 | nr = right_nritems - 1; | ||
1628 | |||
1629 | for (i = 0; i < nr; i++) { | ||
1611 | item = btrfs_item_nr(right, i); | 1630 | item = btrfs_item_nr(right, i); |
1612 | if (!right->map_token) { | 1631 | if (!right->map_token) { |
1613 | map_extent_buffer(right, (unsigned long)item, | 1632 | map_extent_buffer(right, (unsigned long)item, |
@@ -1637,7 +1656,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1637 | free_extent_buffer(left); | 1656 | free_extent_buffer(left); |
1638 | return 1; | 1657 | return 1; |
1639 | } | 1658 | } |
1640 | if (push_items == btrfs_header_nritems(right)) | 1659 | if (!empty && push_items == btrfs_header_nritems(right)) |
1641 | WARN_ON(1); | 1660 | WARN_ON(1); |
1642 | 1661 | ||
1643 | /* push data from right to left */ | 1662 | /* push data from right to left */ |
@@ -1681,20 +1700,26 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1681 | } | 1700 | } |
1682 | 1701 | ||
1683 | /* fixup right node */ | 1702 | /* fixup right node */ |
1684 | push_space = btrfs_item_offset_nr(right, push_items - 1) - | 1703 | if (push_items > right_nritems) { |
1685 | leaf_data_end(root, right); | 1704 | printk("push items %d nr %u\n", push_items, right_nritems); |
1686 | memmove_extent_buffer(right, btrfs_leaf_data(right) + | 1705 | WARN_ON(1); |
1687 | BTRFS_LEAF_DATA_SIZE(root) - push_space, | 1706 | } |
1688 | btrfs_leaf_data(right) + | 1707 | |
1689 | leaf_data_end(root, right), push_space); | 1708 | if (push_items < right_nritems) { |
1690 | 1709 | push_space = btrfs_item_offset_nr(right, push_items - 1) - | |
1691 | memmove_extent_buffer(right, btrfs_item_nr_offset(0), | 1710 | leaf_data_end(root, right); |
1711 | memmove_extent_buffer(right, btrfs_leaf_data(right) + | ||
1712 | BTRFS_LEAF_DATA_SIZE(root) - push_space, | ||
1713 | btrfs_leaf_data(right) + | ||
1714 | leaf_data_end(root, right), push_space); | ||
1715 | |||
1716 | memmove_extent_buffer(right, btrfs_item_nr_offset(0), | ||
1692 | btrfs_item_nr_offset(push_items), | 1717 | btrfs_item_nr_offset(push_items), |
1693 | (btrfs_header_nritems(right) - push_items) * | 1718 | (btrfs_header_nritems(right) - push_items) * |
1694 | sizeof(struct btrfs_item)); | 1719 | sizeof(struct btrfs_item)); |
1695 | 1720 | ||
1696 | right_nritems = btrfs_header_nritems(right) - push_items; | 1721 | } |
1697 | btrfs_set_header_nritems(right, right_nritems); | 1722 | btrfs_set_header_nritems(right, right_nritems - push_items); |
1698 | push_space = BTRFS_LEAF_DATA_SIZE(root); | 1723 | push_space = BTRFS_LEAF_DATA_SIZE(root); |
1699 | 1724 | ||
1700 | for (i = 0; i < right_nritems; i++) { | 1725 | for (i = 0; i < right_nritems; i++) { |
@@ -1717,7 +1742,8 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1717 | } | 1742 | } |
1718 | 1743 | ||
1719 | btrfs_mark_buffer_dirty(left); | 1744 | btrfs_mark_buffer_dirty(left); |
1720 | btrfs_mark_buffer_dirty(right); | 1745 | if (right_nritems) |
1746 | btrfs_mark_buffer_dirty(right); | ||
1721 | 1747 | ||
1722 | btrfs_item_key(right, &disk_key, 0); | 1748 | btrfs_item_key(right, &disk_key, 0); |
1723 | wret = fixup_low_keys(trans, root, path, &disk_key, 1); | 1749 | wret = fixup_low_keys(trans, root, path, &disk_key, 1); |
@@ -1768,12 +1794,12 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1768 | 1794 | ||
1769 | /* first try to make some room by pushing left and right */ | 1795 | /* first try to make some room by pushing left and right */ |
1770 | if (ins_key->type != BTRFS_DIR_ITEM_KEY) { | 1796 | if (ins_key->type != BTRFS_DIR_ITEM_KEY) { |
1771 | wret = push_leaf_right(trans, root, path, data_size); | 1797 | wret = push_leaf_right(trans, root, path, data_size, 0); |
1772 | if (wret < 0) { | 1798 | if (wret < 0) { |
1773 | return wret; | 1799 | return wret; |
1774 | } | 1800 | } |
1775 | if (wret) { | 1801 | if (wret) { |
1776 | wret = push_leaf_left(trans, root, path, data_size); | 1802 | wret = push_leaf_left(trans, root, path, data_size, 0); |
1777 | if (wret < 0) | 1803 | if (wret < 0) |
1778 | return wret; | 1804 | return wret; |
1779 | } | 1805 | } |
@@ -2403,13 +2429,13 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
2403 | slot = path->slots[1]; | 2429 | slot = path->slots[1]; |
2404 | extent_buffer_get(leaf); | 2430 | extent_buffer_get(leaf); |
2405 | 2431 | ||
2406 | wret = push_leaf_right(trans, root, path, 1); | 2432 | wret = push_leaf_right(trans, root, path, 1, 1); |
2407 | if (wret < 0 && wret != -ENOSPC) | 2433 | if (wret < 0 && wret != -ENOSPC) |
2408 | ret = wret; | 2434 | ret = wret; |
2409 | 2435 | ||
2410 | if (path->nodes[0] == leaf && | 2436 | if (path->nodes[0] == leaf && |
2411 | btrfs_header_nritems(leaf)) { | 2437 | btrfs_header_nritems(leaf)) { |
2412 | wret = push_leaf_left(trans, root, path, 1); | 2438 | wret = push_leaf_left(trans, root, path, 1, 1); |
2413 | if (wret < 0 && wret != -ENOSPC) | 2439 | if (wret < 0 && wret != -ENOSPC) |
2414 | ret = wret; | 2440 | ret = wret; |
2415 | } | 2441 | } |