aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
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}