aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2013-03-07 14:22:04 -0500
committerJosef Bacik <jbacik@fusionio.com>2013-05-06 15:54:18 -0400
commit3173a18f70554fe7880bb2d85c7da566e364eb3c (patch)
tree0a23b42a8d275d3499fac2b90ded76276c64c1c1
parentbe283b2e674a09457d4563729015adb637ce7cc1 (diff)
Btrfs: add a incompatible format change for smaller metadata extent refs
We currently store the first key of the tree block inside the reference for the tree block in the extent tree. This takes up quite a bit of space. Make a new key type for metadata which holds the level as the offset and completely removes storing the btrfs_tree_block_info inside the extent ref. This reduces the size from 51 bytes to 33 bytes per extent reference for each tree block. In practice this results in a 30-35% decrease in the size of our extent tree, which means we COW less and can keep more of the extent tree in memory which makes our heavy metadata operations go much faster. This is not an automatic format change, you must enable it at mkfs time or with btrfstune. This patch deals with having metadata stored as either the old format or the new format so it is easy to convert. Thanks, Signed-off-by: Josef Bacik <jbacik@fusionio.com>
-rw-r--r--fs/btrfs/ctree.c3
-rw-r--r--fs/btrfs/ctree.h22
-rw-r--r--fs/btrfs/disk-io.c3
-rw-r--r--fs/btrfs/extent-tree.c224
-rw-r--r--fs/btrfs/inode.c2
-rw-r--r--fs/btrfs/relocation.c73
-rw-r--r--fs/btrfs/scrub.c30
7 files changed, 290 insertions, 67 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index ca9d8f1a3bb6..fe032ab6bd8a 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -867,7 +867,8 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
867 867
868 if (btrfs_block_can_be_shared(root, buf)) { 868 if (btrfs_block_can_be_shared(root, buf)) {
869 ret = btrfs_lookup_extent_info(trans, root, buf->start, 869 ret = btrfs_lookup_extent_info(trans, root, buf->start,
870 buf->len, &refs, &flags); 870 btrfs_header_level(buf), 1,
871 &refs, &flags);
871 if (ret) 872 if (ret)
872 return ret; 873 return ret;
873 if (refs == 0) { 874 if (refs == 0) {
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index e2f14b5258b6..efb2feb7cd4a 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -509,6 +509,7 @@ struct btrfs_super_block {
509 509
510#define BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF (1ULL << 6) 510#define BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF (1ULL << 6)
511#define BTRFS_FEATURE_INCOMPAT_RAID56 (1ULL << 7) 511#define BTRFS_FEATURE_INCOMPAT_RAID56 (1ULL << 7)
512#define BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA (1ULL << 8)
512 513
513#define BTRFS_FEATURE_COMPAT_SUPP 0ULL 514#define BTRFS_FEATURE_COMPAT_SUPP 0ULL
514#define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL 515#define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL
@@ -519,7 +520,8 @@ struct btrfs_super_block {
519 BTRFS_FEATURE_INCOMPAT_BIG_METADATA | \ 520 BTRFS_FEATURE_INCOMPAT_BIG_METADATA | \
520 BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO | \ 521 BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO | \
521 BTRFS_FEATURE_INCOMPAT_RAID56 | \ 522 BTRFS_FEATURE_INCOMPAT_RAID56 | \
522 BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF) 523 BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF | \
524 BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA)
523 525
524/* 526/*
525 * A leaf is full of items. offset and size tell us where to find 527 * A leaf is full of items. offset and size tell us where to find
@@ -1809,6 +1811,12 @@ struct btrfs_ioctl_defrag_range_args {
1809 */ 1811 */
1810#define BTRFS_EXTENT_ITEM_KEY 168 1812#define BTRFS_EXTENT_ITEM_KEY 168
1811 1813
1814/*
1815 * The same as the BTRFS_EXTENT_ITEM_KEY, except it's metadata we already know
1816 * the length, so we save the level in key->offset instead of the length.
1817 */
1818#define BTRFS_METADATA_ITEM_KEY 169
1819
1812#define BTRFS_TREE_BLOCK_REF_KEY 176 1820#define BTRFS_TREE_BLOCK_REF_KEY 176
1813 1821
1814#define BTRFS_EXTENT_DATA_REF_KEY 178 1822#define BTRFS_EXTENT_DATA_REF_KEY 178
@@ -3006,7 +3014,7 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
3006int btrfs_lookup_extent(struct btrfs_root *root, u64 start, u64 len); 3014int btrfs_lookup_extent(struct btrfs_root *root, u64 start, u64 len);
3007int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans, 3015int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
3008 struct btrfs_root *root, u64 bytenr, 3016 struct btrfs_root *root, u64 bytenr,
3009 u64 num_bytes, u64 *refs, u64 *flags); 3017 u64 offset, int metadata, u64 *refs, u64 *flags);
3010int btrfs_pin_extent(struct btrfs_root *root, 3018int btrfs_pin_extent(struct btrfs_root *root,
3011 u64 bytenr, u64 num, int reserved); 3019 u64 bytenr, u64 num, int reserved);
3012int btrfs_pin_extent_for_log_replay(struct btrfs_root *root, 3020int btrfs_pin_extent_for_log_replay(struct btrfs_root *root,
@@ -3669,6 +3677,16 @@ static inline void __btrfs_set_fs_incompat(struct btrfs_fs_info *fs_info,
3669 } 3677 }
3670} 3678}
3671 3679
3680#define btrfs_fs_incompat(fs_info, opt) \
3681 __btrfs_fs_incompat((fs_info), BTRFS_FEATURE_INCOMPAT_##opt)
3682
3683static inline int __btrfs_fs_incompat(struct btrfs_fs_info *fs_info, u64 flag)
3684{
3685 struct btrfs_super_block *disk_super;
3686 disk_super = fs_info->super_copy;
3687 return !!(btrfs_super_incompat_flags(disk_super) & flag);
3688}
3689
3672/* 3690/*
3673 * Call btrfs_abort_transaction as early as possible when an error condition is 3691 * Call btrfs_abort_transaction as early as possible when an error condition is
3674 * detected, that way the exact line number is reported. 3692 * detected, that way the exact line number is reported.
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index e0665488e512..f47754a2fee4 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2290,6 +2290,9 @@ int open_ctree(struct super_block *sb,
2290 if (tree_root->fs_info->compress_type == BTRFS_COMPRESS_LZO) 2290 if (tree_root->fs_info->compress_type == BTRFS_COMPRESS_LZO)
2291 features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO; 2291 features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO;
2292 2292
2293 if (features & BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA)
2294 printk(KERN_ERR "btrfs: has skinny extents\n");
2295
2293 /* 2296 /*
2294 * flag our filesystem as having big metadata blocks if 2297 * flag our filesystem as having big metadata blocks if
2295 * they are bigger than the page size 2298 * they are bigger than the page size
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 3d551231caba..7505856df9f3 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -442,11 +442,16 @@ again:
442 block_group->key.offset) 442 block_group->key.offset)
443 break; 443 break;
444 444
445 if (key.type == BTRFS_EXTENT_ITEM_KEY) { 445 if (key.type == BTRFS_EXTENT_ITEM_KEY ||
446 key.type == BTRFS_METADATA_ITEM_KEY) {
446 total_found += add_new_free_space(block_group, 447 total_found += add_new_free_space(block_group,
447 fs_info, last, 448 fs_info, last,
448 key.objectid); 449 key.objectid);
449 last = key.objectid + key.offset; 450 if (key.type == BTRFS_METADATA_ITEM_KEY)
451 last = key.objectid +
452 fs_info->tree_root->leafsize;
453 else
454 last = key.objectid + key.offset;
450 455
451 if (total_found > (1024 * 1024 * 2)) { 456 if (total_found > (1024 * 1024 * 2)) {
452 total_found = 0; 457 total_found = 0;
@@ -718,15 +723,21 @@ int btrfs_lookup_extent(struct btrfs_root *root, u64 start, u64 len)
718 723
719 key.objectid = start; 724 key.objectid = start;
720 key.offset = len; 725 key.offset = len;
721 btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); 726 key.type = BTRFS_EXTENT_ITEM_KEY;
722 ret = btrfs_search_slot(NULL, root->fs_info->extent_root, &key, path, 727 ret = btrfs_search_slot(NULL, root->fs_info->extent_root, &key, path,
723 0, 0); 728 0, 0);
729 if (ret > 0) {
730 btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
731 if (key.objectid == start &&
732 key.type == BTRFS_METADATA_ITEM_KEY)
733 ret = 0;
734 }
724 btrfs_free_path(path); 735 btrfs_free_path(path);
725 return ret; 736 return ret;
726} 737}
727 738
728/* 739/*
729 * helper function to lookup reference count and flags of extent. 740 * helper function to lookup reference count and flags of a tree block.
730 * 741 *
731 * the head node for delayed ref is used to store the sum of all the 742 * the head node for delayed ref is used to store the sum of all the
732 * reference count modifications queued up in the rbtree. the head 743 * reference count modifications queued up in the rbtree. the head
@@ -736,7 +747,7 @@ int btrfs_lookup_extent(struct btrfs_root *root, u64 start, u64 len)
736 */ 747 */
737int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans, 748int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
738 struct btrfs_root *root, u64 bytenr, 749 struct btrfs_root *root, u64 bytenr,
739 u64 num_bytes, u64 *refs, u64 *flags) 750 u64 offset, int metadata, u64 *refs, u64 *flags)
740{ 751{
741 struct btrfs_delayed_ref_head *head; 752 struct btrfs_delayed_ref_head *head;
742 struct btrfs_delayed_ref_root *delayed_refs; 753 struct btrfs_delayed_ref_root *delayed_refs;
@@ -749,13 +760,29 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
749 u64 extent_flags; 760 u64 extent_flags;
750 int ret; 761 int ret;
751 762
763 /*
764 * If we don't have skinny metadata, don't bother doing anything
765 * different
766 */
767 if (metadata && !btrfs_fs_incompat(root->fs_info, SKINNY_METADATA)) {
768 offset = root->leafsize;
769 metadata = 0;
770 }
771
752 path = btrfs_alloc_path(); 772 path = btrfs_alloc_path();
753 if (!path) 773 if (!path)
754 return -ENOMEM; 774 return -ENOMEM;
755 775
756 key.objectid = bytenr; 776 if (metadata) {
757 key.type = BTRFS_EXTENT_ITEM_KEY; 777 key.objectid = bytenr;
758 key.offset = num_bytes; 778 key.type = BTRFS_METADATA_ITEM_KEY;
779 key.offset = offset;
780 } else {
781 key.objectid = bytenr;
782 key.type = BTRFS_EXTENT_ITEM_KEY;
783 key.offset = offset;
784 }
785
759 if (!trans) { 786 if (!trans) {
760 path->skip_locking = 1; 787 path->skip_locking = 1;
761 path->search_commit_root = 1; 788 path->search_commit_root = 1;
@@ -766,6 +793,13 @@ again:
766 if (ret < 0) 793 if (ret < 0)
767 goto out_free; 794 goto out_free;
768 795
796 if (ret > 0 && metadata && key.type == BTRFS_METADATA_ITEM_KEY) {
797 key.type = BTRFS_EXTENT_ITEM_KEY;
798 key.offset = root->leafsize;
799 btrfs_release_path(path);
800 goto again;
801 }
802
769 if (ret == 0) { 803 if (ret == 0) {
770 leaf = path->nodes[0]; 804 leaf = path->nodes[0];
771 item_size = btrfs_item_size_nr(leaf, path->slots[0]); 805 item_size = btrfs_item_size_nr(leaf, path->slots[0]);
@@ -1453,6 +1487,8 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
1453 int want; 1487 int want;
1454 int ret; 1488 int ret;
1455 int err = 0; 1489 int err = 0;
1490 bool skinny_metadata = btrfs_fs_incompat(root->fs_info,
1491 SKINNY_METADATA);
1456 1492
1457 key.objectid = bytenr; 1493 key.objectid = bytenr;
1458 key.type = BTRFS_EXTENT_ITEM_KEY; 1494 key.type = BTRFS_EXTENT_ITEM_KEY;
@@ -1464,11 +1500,46 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
1464 path->keep_locks = 1; 1500 path->keep_locks = 1;
1465 } else 1501 } else
1466 extra_size = -1; 1502 extra_size = -1;
1503
1504 /*
1505 * Owner is our parent level, so we can just add one to get the level
1506 * for the block we are interested in.
1507 */
1508 if (skinny_metadata && owner < BTRFS_FIRST_FREE_OBJECTID) {
1509 key.type = BTRFS_METADATA_ITEM_KEY;
1510 key.offset = owner;
1511 }
1512
1513again:
1467 ret = btrfs_search_slot(trans, root, &key, path, extra_size, 1); 1514 ret = btrfs_search_slot(trans, root, &key, path, extra_size, 1);
1468 if (ret < 0) { 1515 if (ret < 0) {
1469 err = ret; 1516 err = ret;
1470 goto out; 1517 goto out;
1471 } 1518 }
1519
1520 /*
1521 * We may be a newly converted file system which still has the old fat
1522 * extent entries for metadata, so try and see if we have one of those.
1523 */
1524 if (ret > 0 && skinny_metadata) {
1525 skinny_metadata = false;
1526 if (path->slots[0]) {
1527 path->slots[0]--;
1528 btrfs_item_key_to_cpu(path->nodes[0], &key,
1529 path->slots[0]);
1530 if (key.objectid == bytenr &&
1531 key.type == BTRFS_EXTENT_ITEM_KEY &&
1532 key.offset == num_bytes)
1533 ret = 0;
1534 }
1535 if (ret) {
1536 key.type = BTRFS_EXTENT_ITEM_KEY;
1537 key.offset = num_bytes;
1538 btrfs_release_path(path);
1539 goto again;
1540 }
1541 }
1542
1472 if (ret && !insert) { 1543 if (ret && !insert) {
1473 err = -ENOENT; 1544 err = -ENOENT;
1474 goto out; 1545 goto out;
@@ -1504,11 +1575,9 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
1504 ptr = (unsigned long)(ei + 1); 1575 ptr = (unsigned long)(ei + 1);
1505 end = (unsigned long)ei + item_size; 1576 end = (unsigned long)ei + item_size;
1506 1577
1507 if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { 1578 if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK && !skinny_metadata) {
1508 ptr += sizeof(struct btrfs_tree_block_info); 1579 ptr += sizeof(struct btrfs_tree_block_info);
1509 BUG_ON(ptr > end); 1580 BUG_ON(ptr > end);
1510 } else {
1511 BUG_ON(!(flags & BTRFS_EXTENT_FLAG_DATA));
1512 } 1581 }
1513 1582
1514 err = -ENOENT; 1583 err = -ENOENT;
@@ -1973,10 +2042,8 @@ static int run_delayed_data_ref(struct btrfs_trans_handle *trans,
1973 ref_root = ref->root; 2042 ref_root = ref->root;
1974 2043
1975 if (node->action == BTRFS_ADD_DELAYED_REF && insert_reserved) { 2044 if (node->action == BTRFS_ADD_DELAYED_REF && insert_reserved) {
1976 if (extent_op) { 2045 if (extent_op)
1977 BUG_ON(extent_op->update_key);
1978 flags |= extent_op->flags_to_set; 2046 flags |= extent_op->flags_to_set;
1979 }
1980 ret = alloc_reserved_file_extent(trans, root, 2047 ret = alloc_reserved_file_extent(trans, root,
1981 parent, ref_root, flags, 2048 parent, ref_root, flags,
1982 ref->objectid, ref->offset, 2049 ref->objectid, ref->offset,
@@ -2029,18 +2096,33 @@ static int run_delayed_extent_op(struct btrfs_trans_handle *trans,
2029 u32 item_size; 2096 u32 item_size;
2030 int ret; 2097 int ret;
2031 int err = 0; 2098 int err = 0;
2099 int metadata = (node->type == BTRFS_TREE_BLOCK_REF_KEY ||
2100 node->type == BTRFS_SHARED_BLOCK_REF_KEY);
2032 2101
2033 if (trans->aborted) 2102 if (trans->aborted)
2034 return 0; 2103 return 0;
2035 2104
2105 if (metadata && !btrfs_fs_incompat(root->fs_info, SKINNY_METADATA))
2106 metadata = 0;
2107
2036 path = btrfs_alloc_path(); 2108 path = btrfs_alloc_path();
2037 if (!path) 2109 if (!path)
2038 return -ENOMEM; 2110 return -ENOMEM;
2039 2111
2040 key.objectid = node->bytenr; 2112 key.objectid = node->bytenr;
2041 key.type = BTRFS_EXTENT_ITEM_KEY;
2042 key.offset = node->num_bytes;
2043 2113
2114 if (metadata) {
2115 struct btrfs_delayed_tree_ref *tree_ref;
2116
2117 tree_ref = btrfs_delayed_node_to_tree_ref(node);
2118 key.type = BTRFS_METADATA_ITEM_KEY;
2119 key.offset = tree_ref->level;
2120 } else {
2121 key.type = BTRFS_EXTENT_ITEM_KEY;
2122 key.offset = node->num_bytes;
2123 }
2124
2125again:
2044 path->reada = 1; 2126 path->reada = 1;
2045 path->leave_spinning = 1; 2127 path->leave_spinning = 1;
2046 ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, 2128 ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key,
@@ -2050,6 +2132,14 @@ static int run_delayed_extent_op(struct btrfs_trans_handle *trans,
2050 goto out; 2132 goto out;
2051 } 2133 }
2052 if (ret > 0) { 2134 if (ret > 0) {
2135 if (metadata) {
2136 btrfs_release_path(path);
2137 metadata = 0;
2138
2139 key.offset = node->num_bytes;
2140 key.type = BTRFS_EXTENT_ITEM_KEY;
2141 goto again;
2142 }
2053 err = -EIO; 2143 err = -EIO;
2054 goto out; 2144 goto out;
2055 } 2145 }
@@ -2089,10 +2179,8 @@ static int run_delayed_tree_ref(struct btrfs_trans_handle *trans,
2089 struct btrfs_key ins; 2179 struct btrfs_key ins;
2090 u64 parent = 0; 2180 u64 parent = 0;
2091 u64 ref_root = 0; 2181 u64 ref_root = 0;
2092 2182 bool skinny_metadata = btrfs_fs_incompat(root->fs_info,
2093 ins.objectid = node->bytenr; 2183 SKINNY_METADATA);
2094 ins.offset = node->num_bytes;
2095 ins.type = BTRFS_EXTENT_ITEM_KEY;
2096 2184
2097 ref = btrfs_delayed_node_to_tree_ref(node); 2185 ref = btrfs_delayed_node_to_tree_ref(node);
2098 if (node->type == BTRFS_SHARED_BLOCK_REF_KEY) 2186 if (node->type == BTRFS_SHARED_BLOCK_REF_KEY)
@@ -2100,10 +2188,18 @@ static int run_delayed_tree_ref(struct btrfs_trans_handle *trans,
2100 else 2188 else
2101 ref_root = ref->root; 2189 ref_root = ref->root;
2102 2190
2191 ins.objectid = node->bytenr;
2192 if (skinny_metadata) {
2193 ins.offset = ref->level;
2194 ins.type = BTRFS_METADATA_ITEM_KEY;
2195 } else {
2196 ins.offset = node->num_bytes;
2197 ins.type = BTRFS_EXTENT_ITEM_KEY;
2198 }
2199
2103 BUG_ON(node->ref_mod != 1); 2200 BUG_ON(node->ref_mod != 1);
2104 if (node->action == BTRFS_ADD_DELAYED_REF && insert_reserved) { 2201 if (node->action == BTRFS_ADD_DELAYED_REF && insert_reserved) {
2105 BUG_ON(!extent_op || !extent_op->update_flags || 2202 BUG_ON(!extent_op || !extent_op->update_flags);
2106 !extent_op->update_key);
2107 ret = alloc_reserved_tree_block(trans, root, 2203 ret = alloc_reserved_tree_block(trans, root,
2108 parent, ref_root, 2204 parent, ref_root,
2109 extent_op->flags_to_set, 2205 extent_op->flags_to_set,
@@ -5312,6 +5408,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
5312 int num_to_del = 1; 5408 int num_to_del = 1;
5313 u32 item_size; 5409 u32 item_size;
5314 u64 refs; 5410 u64 refs;
5411 bool skinny_metadata = btrfs_fs_incompat(root->fs_info,
5412 SKINNY_METADATA);
5315 5413
5316 path = btrfs_alloc_path(); 5414 path = btrfs_alloc_path();
5317 if (!path) 5415 if (!path)
@@ -5323,6 +5421,9 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
5323 is_data = owner_objectid >= BTRFS_FIRST_FREE_OBJECTID; 5421 is_data = owner_objectid >= BTRFS_FIRST_FREE_OBJECTID;
5324 BUG_ON(!is_data && refs_to_drop != 1); 5422 BUG_ON(!is_data && refs_to_drop != 1);
5325 5423
5424 if (is_data)
5425 skinny_metadata = 0;
5426
5326 ret = lookup_extent_backref(trans, extent_root, path, &iref, 5427 ret = lookup_extent_backref(trans, extent_root, path, &iref,
5327 bytenr, num_bytes, parent, 5428 bytenr, num_bytes, parent,
5328 root_objectid, owner_objectid, 5429 root_objectid, owner_objectid,
@@ -5339,6 +5440,11 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
5339 found_extent = 1; 5440 found_extent = 1;
5340 break; 5441 break;
5341 } 5442 }
5443 if (key.type == BTRFS_METADATA_ITEM_KEY &&
5444 key.offset == owner_objectid) {
5445 found_extent = 1;
5446 break;
5447 }
5342 if (path->slots[0] - extent_slot > 5) 5448 if (path->slots[0] - extent_slot > 5)
5343 break; 5449 break;
5344 extent_slot--; 5450 extent_slot--;
@@ -5364,8 +5470,36 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
5364 key.type = BTRFS_EXTENT_ITEM_KEY; 5470 key.type = BTRFS_EXTENT_ITEM_KEY;
5365 key.offset = num_bytes; 5471 key.offset = num_bytes;
5366 5472
5473 if (!is_data && skinny_metadata) {
5474 key.type = BTRFS_METADATA_ITEM_KEY;
5475 key.offset = owner_objectid;
5476 }
5477
5367 ret = btrfs_search_slot(trans, extent_root, 5478 ret = btrfs_search_slot(trans, extent_root,
5368 &key, path, -1, 1); 5479 &key, path, -1, 1);
5480 if (ret > 0 && skinny_metadata && path->slots[0]) {
5481 /*
5482 * Couldn't find our skinny metadata item,
5483 * see if we have ye olde extent item.
5484 */
5485 path->slots[0]--;
5486 btrfs_item_key_to_cpu(path->nodes[0], &key,
5487 path->slots[0]);
5488 if (key.objectid == bytenr &&
5489 key.type == BTRFS_EXTENT_ITEM_KEY &&
5490 key.offset == num_bytes)
5491 ret = 0;
5492 }
5493
5494 if (ret > 0 && skinny_metadata) {
5495 skinny_metadata = false;
5496 key.type = BTRFS_EXTENT_ITEM_KEY;
5497 key.offset = num_bytes;
5498 btrfs_release_path(path);
5499 ret = btrfs_search_slot(trans, extent_root,
5500 &key, path, -1, 1);
5501 }
5502
5369 if (ret) { 5503 if (ret) {
5370 printk(KERN_ERR "umm, got %d back from search" 5504 printk(KERN_ERR "umm, got %d back from search"
5371 ", was looking for %llu\n", ret, 5505 ", was looking for %llu\n", ret,
@@ -5435,7 +5569,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
5435 BUG_ON(item_size < sizeof(*ei)); 5569 BUG_ON(item_size < sizeof(*ei));
5436 ei = btrfs_item_ptr(leaf, extent_slot, 5570 ei = btrfs_item_ptr(leaf, extent_slot,
5437 struct btrfs_extent_item); 5571 struct btrfs_extent_item);
5438 if (owner_objectid < BTRFS_FIRST_FREE_OBJECTID) { 5572 if (owner_objectid < BTRFS_FIRST_FREE_OBJECTID &&
5573 key.type == BTRFS_EXTENT_ITEM_KEY) {
5439 struct btrfs_tree_block_info *bi; 5574 struct btrfs_tree_block_info *bi;
5440 BUG_ON(item_size < sizeof(*ei) + sizeof(*bi)); 5575 BUG_ON(item_size < sizeof(*ei) + sizeof(*bi));
5441 bi = (struct btrfs_tree_block_info *)(ei + 1); 5576 bi = (struct btrfs_tree_block_info *)(ei + 1);
@@ -6349,7 +6484,12 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
6349 struct btrfs_extent_inline_ref *iref; 6484 struct btrfs_extent_inline_ref *iref;
6350 struct btrfs_path *path; 6485 struct btrfs_path *path;
6351 struct extent_buffer *leaf; 6486 struct extent_buffer *leaf;
6352 u32 size = sizeof(*extent_item) + sizeof(*block_info) + sizeof(*iref); 6487 u32 size = sizeof(*extent_item) + sizeof(*iref);
6488 bool skinny_metadata = btrfs_fs_incompat(root->fs_info,
6489 SKINNY_METADATA);
6490
6491 if (!skinny_metadata)
6492 size += sizeof(*block_info);
6353 6493
6354 path = btrfs_alloc_path(); 6494 path = btrfs_alloc_path();
6355 if (!path) 6495 if (!path)
@@ -6370,12 +6510,16 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
6370 btrfs_set_extent_generation(leaf, extent_item, trans->transid); 6510 btrfs_set_extent_generation(leaf, extent_item, trans->transid);
6371 btrfs_set_extent_flags(leaf, extent_item, 6511 btrfs_set_extent_flags(leaf, extent_item,
6372 flags | BTRFS_EXTENT_FLAG_TREE_BLOCK); 6512 flags | BTRFS_EXTENT_FLAG_TREE_BLOCK);
6373 block_info = (struct btrfs_tree_block_info *)(extent_item + 1);
6374 6513
6375 btrfs_set_tree_block_key(leaf, block_info, key); 6514 if (skinny_metadata) {
6376 btrfs_set_tree_block_level(leaf, block_info, level); 6515 iref = (struct btrfs_extent_inline_ref *)(extent_item + 1);
6516 } else {
6517 block_info = (struct btrfs_tree_block_info *)(extent_item + 1);
6518 btrfs_set_tree_block_key(leaf, block_info, key);
6519 btrfs_set_tree_block_level(leaf, block_info, level);
6520 iref = (struct btrfs_extent_inline_ref *)(block_info + 1);
6521 }
6377 6522
6378 iref = (struct btrfs_extent_inline_ref *)(block_info + 1);
6379 if (parent > 0) { 6523 if (parent > 0) {
6380 BUG_ON(!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)); 6524 BUG_ON(!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF));
6381 btrfs_set_extent_inline_ref_type(leaf, iref, 6525 btrfs_set_extent_inline_ref_type(leaf, iref,
@@ -6390,7 +6534,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
6390 btrfs_mark_buffer_dirty(leaf); 6534 btrfs_mark_buffer_dirty(leaf);
6391 btrfs_free_path(path); 6535 btrfs_free_path(path);
6392 6536
6393 ret = update_block_group(root, ins->objectid, ins->offset, 1); 6537 ret = update_block_group(root, ins->objectid, root->leafsize, 1);
6394 if (ret) { /* -ENOENT, logic error */ 6538 if (ret) { /* -ENOENT, logic error */
6395 printk(KERN_ERR "btrfs update block group failed for %llu " 6539 printk(KERN_ERR "btrfs update block group failed for %llu "
6396 "%llu\n", (unsigned long long)ins->objectid, 6540 "%llu\n", (unsigned long long)ins->objectid,
@@ -6594,7 +6738,8 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
6594 struct extent_buffer *buf; 6738 struct extent_buffer *buf;
6595 u64 flags = 0; 6739 u64 flags = 0;
6596 int ret; 6740 int ret;
6597 6741 bool skinny_metadata = btrfs_fs_incompat(root->fs_info,
6742 SKINNY_METADATA);
6598 6743
6599 block_rsv = use_block_rsv(trans, root, blocksize); 6744 block_rsv = use_block_rsv(trans, root, blocksize);
6600 if (IS_ERR(block_rsv)) 6745 if (IS_ERR(block_rsv))
@@ -6627,7 +6772,10 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
6627 else 6772 else
6628 memset(&extent_op->key, 0, sizeof(extent_op->key)); 6773 memset(&extent_op->key, 0, sizeof(extent_op->key));
6629 extent_op->flags_to_set = flags; 6774 extent_op->flags_to_set = flags;
6630 extent_op->update_key = 1; 6775 if (skinny_metadata)
6776 extent_op->update_key = 0;
6777 else
6778 extent_op->update_key = 1;
6631 extent_op->update_flags = 1; 6779 extent_op->update_flags = 1;
6632 extent_op->is_data = 0; 6780 extent_op->is_data = 0;
6633 6781
@@ -6704,8 +6852,9 @@ static noinline void reada_walk_down(struct btrfs_trans_handle *trans,
6704 continue; 6852 continue;
6705 6853
6706 /* We don't lock the tree block, it's OK to be racy here */ 6854 /* We don't lock the tree block, it's OK to be racy here */
6707 ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize, 6855 ret = btrfs_lookup_extent_info(trans, root, bytenr,
6708 &refs, &flags); 6856 wc->level - 1, 1, &refs,
6857 &flags);
6709 /* We don't care about errors in readahead. */ 6858 /* We don't care about errors in readahead. */
6710 if (ret < 0) 6859 if (ret < 0)
6711 continue; 6860 continue;
@@ -6772,7 +6921,7 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
6772 (wc->stage == UPDATE_BACKREF && !(wc->flags[level] & flag)))) { 6921 (wc->stage == UPDATE_BACKREF && !(wc->flags[level] & flag)))) {
6773 BUG_ON(!path->locks[level]); 6922 BUG_ON(!path->locks[level]);
6774 ret = btrfs_lookup_extent_info(trans, root, 6923 ret = btrfs_lookup_extent_info(trans, root,
6775 eb->start, eb->len, 6924 eb->start, level, 1,
6776 &wc->refs[level], 6925 &wc->refs[level],
6777 &wc->flags[level]); 6926 &wc->flags[level]);
6778 BUG_ON(ret == -ENOMEM); 6927 BUG_ON(ret == -ENOMEM);
@@ -6870,7 +7019,7 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
6870 btrfs_tree_lock(next); 7019 btrfs_tree_lock(next);
6871 btrfs_set_lock_blocking(next); 7020 btrfs_set_lock_blocking(next);
6872 7021
6873 ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize, 7022 ret = btrfs_lookup_extent_info(trans, root, bytenr, level - 1, 1,
6874 &wc->refs[level - 1], 7023 &wc->refs[level - 1],
6875 &wc->flags[level - 1]); 7024 &wc->flags[level - 1]);
6876 if (ret < 0) { 7025 if (ret < 0) {
@@ -7001,7 +7150,7 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
7001 path->locks[level] = BTRFS_WRITE_LOCK_BLOCKING; 7150 path->locks[level] = BTRFS_WRITE_LOCK_BLOCKING;
7002 7151
7003 ret = btrfs_lookup_extent_info(trans, root, 7152 ret = btrfs_lookup_extent_info(trans, root,
7004 eb->start, eb->len, 7153 eb->start, level, 1,
7005 &wc->refs[level], 7154 &wc->refs[level],
7006 &wc->flags[level]); 7155 &wc->flags[level]);
7007 if (ret < 0) { 7156 if (ret < 0) {
@@ -7211,8 +7360,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
7211 7360
7212 ret = btrfs_lookup_extent_info(trans, root, 7361 ret = btrfs_lookup_extent_info(trans, root,
7213 path->nodes[level]->start, 7362 path->nodes[level]->start,
7214 path->nodes[level]->len, 7363 level, 1, &wc->refs[level],
7215 &wc->refs[level],
7216 &wc->flags[level]); 7364 &wc->flags[level]);
7217 if (ret < 0) { 7365 if (ret < 0) {
7218 err = ret; 7366 err = ret;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 24e8a356a36c..c69145b66ea4 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3660,7 +3660,7 @@ static int check_path_shared(struct btrfs_root *root,
3660 eb = path->nodes[level]; 3660 eb = path->nodes[level];
3661 if (!btrfs_block_can_be_shared(root, eb)) 3661 if (!btrfs_block_can_be_shared(root, eb))
3662 continue; 3662 continue;
3663 ret = btrfs_lookup_extent_info(NULL, root, eb->start, eb->len, 3663 ret = btrfs_lookup_extent_info(NULL, root, eb->start, level, 1,
3664 &refs, NULL); 3664 &refs, NULL);
3665 if (refs > 1) 3665 if (refs > 1)
3666 return 1; 3666 return 1;
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index b67171e6d688..86f192ffc212 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -619,10 +619,13 @@ static noinline_for_stack
619int find_inline_backref(struct extent_buffer *leaf, int slot, 619int find_inline_backref(struct extent_buffer *leaf, int slot,
620 unsigned long *ptr, unsigned long *end) 620 unsigned long *ptr, unsigned long *end)
621{ 621{
622 struct btrfs_key key;
622 struct btrfs_extent_item *ei; 623 struct btrfs_extent_item *ei;
623 struct btrfs_tree_block_info *bi; 624 struct btrfs_tree_block_info *bi;
624 u32 item_size; 625 u32 item_size;
625 626
627 btrfs_item_key_to_cpu(leaf, &key, slot);
628
626 item_size = btrfs_item_size_nr(leaf, slot); 629 item_size = btrfs_item_size_nr(leaf, slot);
627#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 630#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
628 if (item_size < sizeof(*ei)) { 631 if (item_size < sizeof(*ei)) {
@@ -634,13 +637,18 @@ int find_inline_backref(struct extent_buffer *leaf, int slot,
634 WARN_ON(!(btrfs_extent_flags(leaf, ei) & 637 WARN_ON(!(btrfs_extent_flags(leaf, ei) &
635 BTRFS_EXTENT_FLAG_TREE_BLOCK)); 638 BTRFS_EXTENT_FLAG_TREE_BLOCK));
636 639
637 if (item_size <= sizeof(*ei) + sizeof(*bi)) { 640 if (key.type == BTRFS_EXTENT_ITEM_KEY &&
641 item_size <= sizeof(*ei) + sizeof(*bi)) {
638 WARN_ON(item_size < sizeof(*ei) + sizeof(*bi)); 642 WARN_ON(item_size < sizeof(*ei) + sizeof(*bi));
639 return 1; 643 return 1;
640 } 644 }
641 645
642 bi = (struct btrfs_tree_block_info *)(ei + 1); 646 if (key.type == BTRFS_EXTENT_ITEM_KEY) {
643 *ptr = (unsigned long)(bi + 1); 647 bi = (struct btrfs_tree_block_info *)(ei + 1);
648 *ptr = (unsigned long)(bi + 1);
649 } else {
650 *ptr = (unsigned long)(ei + 1);
651 }
644 *end = (unsigned long)ei + item_size; 652 *end = (unsigned long)ei + item_size;
645 return 0; 653 return 0;
646} 654}
@@ -708,7 +716,7 @@ again:
708 end = 0; 716 end = 0;
709 ptr = 0; 717 ptr = 0;
710 key.objectid = cur->bytenr; 718 key.objectid = cur->bytenr;
711 key.type = BTRFS_EXTENT_ITEM_KEY; 719 key.type = BTRFS_METADATA_ITEM_KEY;
712 key.offset = (u64)-1; 720 key.offset = (u64)-1;
713 721
714 path1->search_commit_root = 1; 722 path1->search_commit_root = 1;
@@ -766,7 +774,8 @@ again:
766 break; 774 break;
767 } 775 }
768 776
769 if (key.type == BTRFS_EXTENT_ITEM_KEY) { 777 if (key.type == BTRFS_EXTENT_ITEM_KEY ||
778 key.type == BTRFS_METADATA_ITEM_KEY) {
770 ret = find_inline_backref(eb, path1->slots[0], 779 ret = find_inline_backref(eb, path1->slots[0],
771 &ptr, &end); 780 &ptr, &end);
772 if (ret) 781 if (ret)
@@ -2768,8 +2777,13 @@ static int reada_tree_block(struct reloc_control *rc,
2768 struct tree_block *block) 2777 struct tree_block *block)
2769{ 2778{
2770 BUG_ON(block->key_ready); 2779 BUG_ON(block->key_ready);
2771 readahead_tree_block(rc->extent_root, block->bytenr, 2780 if (block->key.type == BTRFS_METADATA_ITEM_KEY)
2772 block->key.objectid, block->key.offset); 2781 readahead_tree_block(rc->extent_root, block->bytenr,
2782 block->key.objectid,
2783 rc->extent_root->leafsize);
2784 else
2785 readahead_tree_block(rc->extent_root, block->bytenr,
2786 block->key.objectid, block->key.offset);
2773 return 0; 2787 return 0;
2774} 2788}
2775 2789
@@ -3176,12 +3190,17 @@ static int add_tree_block(struct reloc_control *rc,
3176 eb = path->nodes[0]; 3190 eb = path->nodes[0];
3177 item_size = btrfs_item_size_nr(eb, path->slots[0]); 3191 item_size = btrfs_item_size_nr(eb, path->slots[0]);
3178 3192
3179 if (item_size >= sizeof(*ei) + sizeof(*bi)) { 3193 if (extent_key->type == BTRFS_METADATA_ITEM_KEY ||
3194 item_size >= sizeof(*ei) + sizeof(*bi)) {
3180 ei = btrfs_item_ptr(eb, path->slots[0], 3195 ei = btrfs_item_ptr(eb, path->slots[0],
3181 struct btrfs_extent_item); 3196 struct btrfs_extent_item);
3182 bi = (struct btrfs_tree_block_info *)(ei + 1); 3197 if (extent_key->type == BTRFS_EXTENT_ITEM_KEY) {
3198 bi = (struct btrfs_tree_block_info *)(ei + 1);
3199 level = btrfs_tree_block_level(eb, bi);
3200 } else {
3201 level = (int)extent_key->offset;
3202 }
3183 generation = btrfs_extent_generation(eb, ei); 3203 generation = btrfs_extent_generation(eb, ei);
3184 level = btrfs_tree_block_level(eb, bi);
3185 } else { 3204 } else {
3186#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 3205#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
3187 u64 ref_owner; 3206 u64 ref_owner;
@@ -3210,7 +3229,7 @@ static int add_tree_block(struct reloc_control *rc,
3210 return -ENOMEM; 3229 return -ENOMEM;
3211 3230
3212 block->bytenr = extent_key->objectid; 3231 block->bytenr = extent_key->objectid;
3213 block->key.objectid = extent_key->offset; 3232 block->key.objectid = rc->extent_root->leafsize;
3214 block->key.offset = generation; 3233 block->key.offset = generation;
3215 block->level = level; 3234 block->level = level;
3216 block->key_ready = 0; 3235 block->key_ready = 0;
@@ -3252,9 +3271,15 @@ static int __add_tree_block(struct reloc_control *rc,
3252 ret = btrfs_search_slot(NULL, rc->extent_root, &key, path, 0, 0); 3271 ret = btrfs_search_slot(NULL, rc->extent_root, &key, path, 0, 0);
3253 if (ret < 0) 3272 if (ret < 0)
3254 goto out; 3273 goto out;
3255 BUG_ON(ret);
3256 3274
3257 btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); 3275 btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
3276 if (ret > 0) {
3277 if (key.objectid == bytenr &&
3278 key.type == BTRFS_METADATA_ITEM_KEY)
3279 ret = 0;
3280 }
3281 BUG_ON(ret);
3282
3258 ret = add_tree_block(rc, &key, path, blocks); 3283 ret = add_tree_block(rc, &key, path, blocks);
3259out: 3284out:
3260 btrfs_free_path(path); 3285 btrfs_free_path(path);
@@ -3275,7 +3300,8 @@ static int block_use_full_backref(struct reloc_control *rc,
3275 return 1; 3300 return 1;
3276 3301
3277 ret = btrfs_lookup_extent_info(NULL, rc->extent_root, 3302 ret = btrfs_lookup_extent_info(NULL, rc->extent_root,
3278 eb->start, eb->len, NULL, &flags); 3303 eb->start, btrfs_header_level(eb), 1,
3304 NULL, &flags);
3279 BUG_ON(ret); 3305 BUG_ON(ret);
3280 3306
3281 if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) 3307 if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)
@@ -3644,12 +3670,25 @@ next:
3644 break; 3670 break;
3645 } 3671 }
3646 3672
3647 if (key.type != BTRFS_EXTENT_ITEM_KEY || 3673 if (key.type != BTRFS_EXTENT_ITEM_KEY &&
3674 key.type != BTRFS_METADATA_ITEM_KEY) {
3675 path->slots[0]++;
3676 goto next;
3677 }
3678
3679 if (key.type == BTRFS_EXTENT_ITEM_KEY &&
3648 key.objectid + key.offset <= rc->search_start) { 3680 key.objectid + key.offset <= rc->search_start) {
3649 path->slots[0]++; 3681 path->slots[0]++;
3650 goto next; 3682 goto next;
3651 } 3683 }
3652 3684
3685 if (key.type == BTRFS_METADATA_ITEM_KEY &&
3686 key.objectid + rc->extent_root->leafsize <=
3687 rc->search_start) {
3688 path->slots[0]++;
3689 goto next;
3690 }
3691
3653 ret = find_first_extent_bit(&rc->processed_blocks, 3692 ret = find_first_extent_bit(&rc->processed_blocks,
3654 key.objectid, &start, &end, 3693 key.objectid, &start, &end,
3655 EXTENT_DIRTY, NULL); 3694 EXTENT_DIRTY, NULL);
@@ -3658,7 +3697,11 @@ next:
3658 btrfs_release_path(path); 3697 btrfs_release_path(path);
3659 rc->search_start = end + 1; 3698 rc->search_start = end + 1;
3660 } else { 3699 } else {
3661 rc->search_start = key.objectid + key.offset; 3700 if (key.type == BTRFS_EXTENT_ITEM_KEY)
3701 rc->search_start = key.objectid + key.offset;
3702 else
3703 rc->search_start = key.objectid +
3704 rc->extent_root->leafsize;
3662 memcpy(extent_key, &key, sizeof(key)); 3705 memcpy(extent_key, &key, sizeof(key));
3663 return 0; 3706 return 0;
3664 } 3707 }
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 3d29d60bdaf8..28db5dcde0aa 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -2312,8 +2312,8 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
2312 key_start.type = BTRFS_EXTENT_ITEM_KEY; 2312 key_start.type = BTRFS_EXTENT_ITEM_KEY;
2313 key_start.offset = (u64)0; 2313 key_start.offset = (u64)0;
2314 key_end.objectid = base + offset + nstripes * increment; 2314 key_end.objectid = base + offset + nstripes * increment;
2315 key_end.type = BTRFS_EXTENT_ITEM_KEY; 2315 key_end.type = BTRFS_METADATA_ITEM_KEY;
2316 key_end.offset = (u64)0; 2316 key_end.offset = (u64)-1;
2317 reada1 = btrfs_reada_add(root, &key_start, &key_end); 2317 reada1 = btrfs_reada_add(root, &key_start, &key_end);
2318 2318
2319 key_start.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 2319 key_start.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
@@ -2401,6 +2401,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
2401 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); 2401 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
2402 if (ret < 0) 2402 if (ret < 0)
2403 goto out; 2403 goto out;
2404
2404 if (ret > 0) { 2405 if (ret > 0) {
2405 ret = btrfs_previous_item(root, path, 0, 2406 ret = btrfs_previous_item(root, path, 0,
2406 BTRFS_EXTENT_ITEM_KEY); 2407 BTRFS_EXTENT_ITEM_KEY);
@@ -2418,6 +2419,8 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
2418 } 2419 }
2419 2420
2420 while (1) { 2421 while (1) {
2422 u64 bytes;
2423
2421 l = path->nodes[0]; 2424 l = path->nodes[0];
2422 slot = path->slots[0]; 2425 slot = path->slots[0];
2423 if (slot >= btrfs_header_nritems(l)) { 2426 if (slot >= btrfs_header_nritems(l)) {
@@ -2431,14 +2434,21 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
2431 } 2434 }
2432 btrfs_item_key_to_cpu(l, &key, slot); 2435 btrfs_item_key_to_cpu(l, &key, slot);
2433 2436
2434 if (key.objectid + key.offset <= logical) 2437 if (key.type != BTRFS_EXTENT_ITEM_KEY &&
2438 key.type != BTRFS_METADATA_ITEM_KEY)
2439 goto next;
2440
2441 if (key.type == BTRFS_METADATA_ITEM_KEY)
2442 bytes = root->leafsize;
2443 else
2444 bytes = key.offset;
2445
2446 if (key.objectid + bytes <= logical)
2435 goto next; 2447 goto next;
2436 2448
2437 if (key.objectid >= logical + map->stripe_len) 2449 if (key.objectid >= logical + map->stripe_len)
2438 break; 2450 break;
2439 2451
2440 if (btrfs_key_type(&key) != BTRFS_EXTENT_ITEM_KEY)
2441 goto next;
2442 2452
2443 extent = btrfs_item_ptr(l, slot, 2453 extent = btrfs_item_ptr(l, slot,
2444 struct btrfs_extent_item); 2454 struct btrfs_extent_item);
@@ -2459,18 +2469,18 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
2459 * trim extent to this stripe 2469 * trim extent to this stripe
2460 */ 2470 */
2461 if (key.objectid < logical) { 2471 if (key.objectid < logical) {
2462 key.offset -= logical - key.objectid; 2472 bytes -= logical - key.objectid;
2463 key.objectid = logical; 2473 key.objectid = logical;
2464 } 2474 }
2465 if (key.objectid + key.offset > 2475 if (key.objectid + bytes >
2466 logical + map->stripe_len) { 2476 logical + map->stripe_len) {
2467 key.offset = logical + map->stripe_len - 2477 bytes = logical + map->stripe_len -
2468 key.objectid; 2478 key.objectid;
2469 } 2479 }
2470 2480
2471 extent_logical = key.objectid; 2481 extent_logical = key.objectid;
2472 extent_physical = key.objectid - logical + physical; 2482 extent_physical = key.objectid - logical + physical;
2473 extent_len = key.offset; 2483 extent_len = bytes;
2474 extent_dev = scrub_dev; 2484 extent_dev = scrub_dev;
2475 extent_mirror_num = mirror_num; 2485 extent_mirror_num = mirror_num;
2476 if (is_dev_replace) 2486 if (is_dev_replace)