aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2009-02-04 09:23:45 -0500
committerChris Mason <chris.mason@oracle.com>2009-02-04 09:23:45 -0500
commitb7a9f29fcf4e53e9ca7982331649fa2013e69c99 (patch)
tree544a1f9ca00af73fd22380610fd2d6961e066218 /fs/btrfs/extent-tree.c
parentb51912c91fcf7581cc7b4550f1bb96422809d9ed (diff)
Btrfs: sort references by byte number during btrfs_inc_ref
When a block goes through cow, we update the reference counts of everything that block points to. The internal pointers of the block can be in just about any order, and it is likely to have clusters of things that are close together and clusters of things that are not. To help reduce the seeks that come with updating all of these reference counts, sort them by byte number before actual updates are done. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r--fs/btrfs/extent-tree.c85
1 files changed, 79 insertions, 6 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 3b26f0980946..7a22f2e6ec47 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -19,6 +19,7 @@
19#include <linux/pagemap.h> 19#include <linux/pagemap.h>
20#include <linux/writeback.h> 20#include <linux/writeback.h>
21#include <linux/blkdev.h> 21#include <linux/blkdev.h>
22#include <linux/sort.h>
22#include "compat.h" 23#include "compat.h"
23#include "hash.h" 24#include "hash.h"
24#include "crc32c.h" 25#include "crc32c.h"
@@ -1521,15 +1522,50 @@ out:
1521 return ret; 1522 return ret;
1522} 1523}
1523 1524
1524int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, 1525/* when a block goes through cow, we update the reference counts of
1525 struct extent_buffer *orig_buf, struct extent_buffer *buf, 1526 * everything that block points to. The internal pointers of the block
1526 u32 *nr_extents) 1527 * can be in just about any order, and it is likely to have clusters of
1528 * things that are close together and clusters of things that are not.
1529 *
1530 * To help reduce the seeks that come with updating all of these reference
1531 * counts, sort them by byte number before actual updates are done.
1532 *
1533 * struct refsort is used to match byte number to slot in the btree block.
1534 * we sort based on the byte number and then use the slot to actually
1535 * find the item.
1536 */
1537struct refsort {
1538 u64 bytenr;
1539 u32 slot;
1540};
1541
1542/*
1543 * for passing into sort()
1544 */
1545static int refsort_cmp(const void *a_void, const void *b_void)
1546{
1547 const struct refsort *a = a_void;
1548 const struct refsort *b = b_void;
1549
1550 if (a->bytenr < b->bytenr)
1551 return -1;
1552 if (a->bytenr > b->bytenr)
1553 return 1;
1554 return 0;
1555}
1556
1557
1558noinline int btrfs_inc_ref(struct btrfs_trans_handle *trans,
1559 struct btrfs_root *root,
1560 struct extent_buffer *orig_buf,
1561 struct extent_buffer *buf, u32 *nr_extents)
1527{ 1562{
1528 u64 bytenr; 1563 u64 bytenr;
1529 u64 ref_root; 1564 u64 ref_root;
1530 u64 orig_root; 1565 u64 orig_root;
1531 u64 ref_generation; 1566 u64 ref_generation;
1532 u64 orig_generation; 1567 u64 orig_generation;
1568 struct refsort *sorted;
1533 u32 nritems; 1569 u32 nritems;
1534 u32 nr_file_extents = 0; 1570 u32 nr_file_extents = 0;
1535 struct btrfs_key key; 1571 struct btrfs_key key;
@@ -1538,6 +1574,8 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
1538 int level; 1574 int level;
1539 int ret = 0; 1575 int ret = 0;
1540 int faili = 0; 1576 int faili = 0;
1577 int refi = 0;
1578 int slot;
1541 int (*process_func)(struct btrfs_trans_handle *, struct btrfs_root *, 1579 int (*process_func)(struct btrfs_trans_handle *, struct btrfs_root *,
1542 u64, u64, u64, u64, u64, u64, u64, u64); 1580 u64, u64, u64, u64, u64, u64, u64, u64);
1543 1581
@@ -1549,6 +1587,9 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
1549 nritems = btrfs_header_nritems(buf); 1587 nritems = btrfs_header_nritems(buf);
1550 level = btrfs_header_level(buf); 1588 level = btrfs_header_level(buf);
1551 1589
1590 sorted = kmalloc(sizeof(struct refsort) * nritems, GFP_NOFS);
1591 BUG_ON(!sorted);
1592
1552 if (root->ref_cows) { 1593 if (root->ref_cows) {
1553 process_func = __btrfs_inc_extent_ref; 1594 process_func = __btrfs_inc_extent_ref;
1554 } else { 1595 } else {
@@ -1561,6 +1602,11 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
1561 process_func = __btrfs_update_extent_ref; 1602 process_func = __btrfs_update_extent_ref;
1562 } 1603 }
1563 1604
1605 /*
1606 * we make two passes through the items. In the first pass we
1607 * only record the byte number and slot. Then we sort based on
1608 * byte number and do the actual work based on the sorted results
1609 */
1564 for (i = 0; i < nritems; i++) { 1610 for (i = 0; i < nritems; i++) {
1565 cond_resched(); 1611 cond_resched();
1566 if (level == 0) { 1612 if (level == 0) {
@@ -1577,6 +1623,32 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
1577 continue; 1623 continue;
1578 1624
1579 nr_file_extents++; 1625 nr_file_extents++;
1626 sorted[refi].bytenr = bytenr;
1627 sorted[refi].slot = i;
1628 refi++;
1629 } else {
1630 bytenr = btrfs_node_blockptr(buf, i);
1631 sorted[refi].bytenr = bytenr;
1632 sorted[refi].slot = i;
1633 refi++;
1634 }
1635 }
1636 /*
1637 * if refi == 0, we didn't actually put anything into the sorted
1638 * array and we're done
1639 */
1640 if (refi == 0)
1641 goto out;
1642
1643 sort(sorted, refi, sizeof(struct refsort), refsort_cmp, NULL);
1644
1645 for (i = 0; i < refi; i++) {
1646 cond_resched();
1647 slot = sorted[i].slot;
1648 bytenr = sorted[i].bytenr;
1649
1650 if (level == 0) {
1651 btrfs_item_key_to_cpu(buf, &key, slot);
1580 1652
1581 ret = process_func(trans, root, bytenr, 1653 ret = process_func(trans, root, bytenr,
1582 orig_buf->start, buf->start, 1654 orig_buf->start, buf->start,
@@ -1585,25 +1657,25 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
1585 key.objectid); 1657 key.objectid);
1586 1658
1587 if (ret) { 1659 if (ret) {
1588 faili = i; 1660 faili = slot;
1589 WARN_ON(1); 1661 WARN_ON(1);
1590 goto fail; 1662 goto fail;
1591 } 1663 }
1592 } else { 1664 } else {
1593 bytenr = btrfs_node_blockptr(buf, i);
1594 ret = process_func(trans, root, bytenr, 1665 ret = process_func(trans, root, bytenr,
1595 orig_buf->start, buf->start, 1666 orig_buf->start, buf->start,
1596 orig_root, ref_root, 1667 orig_root, ref_root,
1597 orig_generation, ref_generation, 1668 orig_generation, ref_generation,
1598 level - 1); 1669 level - 1);
1599 if (ret) { 1670 if (ret) {
1600 faili = i; 1671 faili = slot;
1601 WARN_ON(1); 1672 WARN_ON(1);
1602 goto fail; 1673 goto fail;
1603 } 1674 }
1604 } 1675 }
1605 } 1676 }
1606out: 1677out:
1678 kfree(sorted);
1607 if (nr_extents) { 1679 if (nr_extents) {
1608 if (level == 0) 1680 if (level == 0)
1609 *nr_extents = nr_file_extents; 1681 *nr_extents = nr_file_extents;
@@ -1612,6 +1684,7 @@ out:
1612 } 1684 }
1613 return 0; 1685 return 0;
1614fail: 1686fail:
1687 kfree(sorted);
1615 WARN_ON(1); 1688 WARN_ON(1);
1616 return ret; 1689 return ret;
1617} 1690}