--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Qu Wenruo <quwenruo.btrfs@gmx.com>
+Date: Wed, 23 Aug 2017 16:57:59 +0900
+Subject: btrfs: Add checker for EXTENT_CSUM
+
+From: Qu Wenruo <quwenruo.btrfs@gmx.com>
+
+commit 4b865cab96fe2a30ed512cf667b354bd291b3b0a upstream.
+
+EXTENT_CSUM checker is a relatively easy one, only needs to check:
+
+1) Objectid
+ Fixed to BTRFS_EXTENT_CSUM_OBJECTID
+
+2) Key offset alignment
+ Must be aligned to sectorsize
+
+3) Item size alignedment
+ Must be aligned to csum size
+
+Signed-off-by: Qu Wenruo <quwenruo.btrfs@gmx.com>
+Reviewed-by: Nikolay Borisov <nborisov@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+[bwh: Backported to 4.4: Use root->sectorsize instead of
+ root->fs_info->sectorsize]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/disk-io.c | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -605,6 +605,27 @@ static int check_extent_data_item(struct
+ return 0;
+ }
+
++static int check_csum_item(struct btrfs_root *root, struct extent_buffer *leaf,
++ struct btrfs_key *key, int slot)
++{
++ u32 sectorsize = root->sectorsize;
++ u32 csumsize = btrfs_super_csum_size(root->fs_info->super_copy);
++
++ if (key->objectid != BTRFS_EXTENT_CSUM_OBJECTID) {
++ CORRUPT("invalid objectid for csum item", leaf, root, slot);
++ return -EUCLEAN;
++ }
++ if (!IS_ALIGNED(key->offset, sectorsize)) {
++ CORRUPT("unaligned key offset for csum item", leaf, root, slot);
++ return -EUCLEAN;
++ }
++ if (!IS_ALIGNED(btrfs_item_size_nr(leaf, slot), csumsize)) {
++ CORRUPT("unaligned csum item size", leaf, root, slot);
++ return -EUCLEAN;
++ }
++ return 0;
++}
++
+ /*
+ * Common point to switch the item-specific validation.
+ */
+@@ -618,6 +639,9 @@ static int check_leaf_item(struct btrfs_
+ case BTRFS_EXTENT_DATA_KEY:
+ ret = check_extent_data_item(root, leaf, key, slot);
+ break;
++ case BTRFS_EXTENT_CSUM_KEY:
++ ret = check_csum_item(root, leaf, key, slot);
++ break;
+ }
+ return ret;
+ }
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Qu Wenruo <quwenruo.btrfs@gmx.com>
+Date: Wed, 23 Aug 2017 16:57:58 +0900
+Subject: btrfs: Add sanity check for EXTENT_DATA when reading out leaf
+
+From: Qu Wenruo <quwenruo.btrfs@gmx.com>
+
+commit 40c3c40947324d9f40bf47830c92c59a9bbadf4a upstream.
+
+Add extra checks for item with EXTENT_DATA type. This checks the
+following thing:
+
+0) Key offset
+ All key offsets must be aligned to sectorsize.
+ Inline extent must have 0 for key offset.
+
+1) Item size
+ Uncompressed inline file extent size must match item size.
+ (Compressed inline file extent has no information about its on-disk size.)
+ Regular/preallocated file extent size must be a fixed value.
+
+2) Every member of regular file extent item
+ Including alignment for bytenr and offset, possible value for
+ compression/encryption/type.
+
+3) Type/compression/encode must be one of the valid values.
+
+This should be the most comprehensive and strict check in the context
+of btrfs_item for EXTENT_DATA.
+
+Signed-off-by: Qu Wenruo <quwenruo.btrfs@gmx.com>
+Reviewed-by: Nikolay Borisov <nborisov@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+[ switch to BTRFS_FILE_EXTENT_TYPES, similar to what
+ BTRFS_COMPRESS_TYPES does ]
+Signed-off-by: David Sterba <dsterba@suse.com>
+[bwh: Backported to 4.4:
+ - Use root->sectorsize instead of root->fs_info->sectorsize
+ - Adjust filename]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/ctree.h | 1
+ fs/btrfs/disk-io.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 104 insertions(+)
+
+--- a/fs/btrfs/ctree.h
++++ b/fs/btrfs/ctree.h
+@@ -897,6 +897,7 @@ struct btrfs_balance_item {
+ #define BTRFS_FILE_EXTENT_INLINE 0
+ #define BTRFS_FILE_EXTENT_REG 1
+ #define BTRFS_FILE_EXTENT_PREALLOC 2
++#define BTRFS_FILE_EXTENT_TYPES 2
+
+ struct btrfs_file_extent_item {
+ /*
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -528,6 +528,100 @@ static int check_tree_block_fsid(struct
+ btrfs_header_level(eb) == 0 ? "leaf" : "node",\
+ reason, btrfs_header_bytenr(eb), root->objectid, slot)
+
++static int check_extent_data_item(struct btrfs_root *root,
++ struct extent_buffer *leaf,
++ struct btrfs_key *key, int slot)
++{
++ struct btrfs_file_extent_item *fi;
++ u32 sectorsize = root->sectorsize;
++ u32 item_size = btrfs_item_size_nr(leaf, slot);
++
++ if (!IS_ALIGNED(key->offset, sectorsize)) {
++ CORRUPT("unaligned key offset for file extent",
++ leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
++
++ if (btrfs_file_extent_type(leaf, fi) > BTRFS_FILE_EXTENT_TYPES) {
++ CORRUPT("invalid file extent type", leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ /*
++ * Support for new compression/encrption must introduce incompat flag,
++ * and must be caught in open_ctree().
++ */
++ if (btrfs_file_extent_compression(leaf, fi) > BTRFS_COMPRESS_TYPES) {
++ CORRUPT("invalid file extent compression", leaf, root, slot);
++ return -EUCLEAN;
++ }
++ if (btrfs_file_extent_encryption(leaf, fi)) {
++ CORRUPT("invalid file extent encryption", leaf, root, slot);
++ return -EUCLEAN;
++ }
++ if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
++ /* Inline extent must have 0 as key offset */
++ if (key->offset) {
++ CORRUPT("inline extent has non-zero key offset",
++ leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ /* Compressed inline extent has no on-disk size, skip it */
++ if (btrfs_file_extent_compression(leaf, fi) !=
++ BTRFS_COMPRESS_NONE)
++ return 0;
++
++ /* Uncompressed inline extent size must match item size */
++ if (item_size != BTRFS_FILE_EXTENT_INLINE_DATA_START +
++ btrfs_file_extent_ram_bytes(leaf, fi)) {
++ CORRUPT("plaintext inline extent has invalid size",
++ leaf, root, slot);
++ return -EUCLEAN;
++ }
++ return 0;
++ }
++
++ /* Regular or preallocated extent has fixed item size */
++ if (item_size != sizeof(*fi)) {
++ CORRUPT(
++ "regluar or preallocated extent data item size is invalid",
++ leaf, root, slot);
++ return -EUCLEAN;
++ }
++ if (!IS_ALIGNED(btrfs_file_extent_ram_bytes(leaf, fi), sectorsize) ||
++ !IS_ALIGNED(btrfs_file_extent_disk_bytenr(leaf, fi), sectorsize) ||
++ !IS_ALIGNED(btrfs_file_extent_disk_num_bytes(leaf, fi), sectorsize) ||
++ !IS_ALIGNED(btrfs_file_extent_offset(leaf, fi), sectorsize) ||
++ !IS_ALIGNED(btrfs_file_extent_num_bytes(leaf, fi), sectorsize)) {
++ CORRUPT(
++ "regular or preallocated extent data item has unaligned value",
++ leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ return 0;
++}
++
++/*
++ * Common point to switch the item-specific validation.
++ */
++static int check_leaf_item(struct btrfs_root *root,
++ struct extent_buffer *leaf,
++ struct btrfs_key *key, int slot)
++{
++ int ret = 0;
++
++ switch (key->type) {
++ case BTRFS_EXTENT_DATA_KEY:
++ ret = check_extent_data_item(root, leaf, key, slot);
++ break;
++ }
++ return ret;
++}
++
+ static noinline int check_leaf(struct btrfs_root *root,
+ struct extent_buffer *leaf)
+ {
+@@ -583,9 +677,13 @@ static noinline int check_leaf(struct bt
+ * 1) key order
+ * 2) item offset and size
+ * No overlap, no hole, all inside the leaf.
++ * 3) item content
++ * If possible, do comprehensive sanity check.
++ * NOTE: All checks must only rely on the item data itself.
+ */
+ for (slot = 0; slot < nritems; slot++) {
+ u32 item_end_expected;
++ int ret;
+
+ btrfs_item_key_to_cpu(leaf, &key, slot);
+
+@@ -628,6 +726,11 @@ static noinline int check_leaf(struct bt
+ return -EUCLEAN;
+ }
+
++ /* Check if the item size and content meet other criteria */
++ ret = check_leaf_item(root, leaf, &key, slot);
++ if (ret < 0)
++ return ret;
++
+ prev_key.objectid = key.objectid;
+ prev_key.type = key.type;
+ prev_key.offset = key.offset;
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Liu Bo <bo.li.liu@oracle.com>
+Date: Fri, 3 Jun 2016 12:05:15 -0700
+Subject: Btrfs: add validadtion checks for chunk loading
+
+From: Liu Bo <bo.li.liu@oracle.com>
+
+commit e06cd3dd7cea50e87663a88acdfdb7ac1c53a5ca upstream.
+
+To prevent fuzzed filesystem images from panic the whole system,
+we need various validation checks to refuse to mount such an image
+if btrfs finds any invalid value during loading chunks, including
+both sys_array and regular chunks.
+
+Note that these checks may not be sufficient to cover all corner cases,
+feel free to add more checks.
+
+Reported-by: Vegard Nossum <vegard.nossum@oracle.com>
+Reported-by: Quentin Casasnovas <quentin.casasnovas@oracle.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/volumes.c | 82 +++++++++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 67 insertions(+), 15 deletions(-)
+
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -6208,27 +6208,23 @@ struct btrfs_device *btrfs_alloc_device(
+ return dev;
+ }
+
+-static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
+- struct extent_buffer *leaf,
+- struct btrfs_chunk *chunk)
++/* Return -EIO if any error, otherwise return 0. */
++static int btrfs_check_chunk_valid(struct btrfs_root *root,
++ struct extent_buffer *leaf,
++ struct btrfs_chunk *chunk, u64 logical)
+ {
+- struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree;
+- struct map_lookup *map;
+- struct extent_map *em;
+- u64 logical;
+ u64 length;
+ u64 stripe_len;
+- u64 devid;
+- u8 uuid[BTRFS_UUID_SIZE];
+- int num_stripes;
+- int ret;
+- int i;
++ u16 num_stripes;
++ u16 sub_stripes;
++ u64 type;
+
+- logical = key->offset;
+ length = btrfs_chunk_length(leaf, chunk);
+ stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
+ num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
+- /* Validation check */
++ sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk);
++ type = btrfs_chunk_type(leaf, chunk);
++
+ if (!num_stripes) {
+ btrfs_err(root->fs_info, "invalid chunk num_stripes: %u",
+ num_stripes);
+@@ -6239,6 +6235,11 @@ static int read_one_chunk(struct btrfs_r
+ "invalid chunk logical %llu", logical);
+ return -EIO;
+ }
++ if (btrfs_chunk_sector_size(leaf, chunk) != root->sectorsize) {
++ btrfs_err(root->fs_info, "invalid chunk sectorsize %u",
++ btrfs_chunk_sector_size(leaf, chunk));
++ return -EIO;
++ }
+ if (!length || !IS_ALIGNED(length, root->sectorsize)) {
+ btrfs_err(root->fs_info,
+ "invalid chunk length %llu", length);
+@@ -6250,13 +6251,54 @@ static int read_one_chunk(struct btrfs_r
+ return -EIO;
+ }
+ if (~(BTRFS_BLOCK_GROUP_TYPE_MASK | BTRFS_BLOCK_GROUP_PROFILE_MASK) &
+- btrfs_chunk_type(leaf, chunk)) {
++ type) {
+ btrfs_err(root->fs_info, "unrecognized chunk type: %llu",
+ ~(BTRFS_BLOCK_GROUP_TYPE_MASK |
+ BTRFS_BLOCK_GROUP_PROFILE_MASK) &
+ btrfs_chunk_type(leaf, chunk));
+ return -EIO;
+ }
++ if ((type & BTRFS_BLOCK_GROUP_RAID10 && sub_stripes != 2) ||
++ (type & BTRFS_BLOCK_GROUP_RAID1 && num_stripes < 1) ||
++ (type & BTRFS_BLOCK_GROUP_RAID5 && num_stripes < 2) ||
++ (type & BTRFS_BLOCK_GROUP_RAID6 && num_stripes < 3) ||
++ (type & BTRFS_BLOCK_GROUP_DUP && num_stripes > 2) ||
++ ((type & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0 &&
++ num_stripes != 1)) {
++ btrfs_err(root->fs_info,
++ "invalid num_stripes:sub_stripes %u:%u for profile %llu",
++ num_stripes, sub_stripes,
++ type & BTRFS_BLOCK_GROUP_PROFILE_MASK);
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
++ struct extent_buffer *leaf,
++ struct btrfs_chunk *chunk)
++{
++ struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree;
++ struct map_lookup *map;
++ struct extent_map *em;
++ u64 logical;
++ u64 length;
++ u64 stripe_len;
++ u64 devid;
++ u8 uuid[BTRFS_UUID_SIZE];
++ int num_stripes;
++ int ret;
++ int i;
++
++ logical = key->offset;
++ length = btrfs_chunk_length(leaf, chunk);
++ stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
++ num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
++
++ ret = btrfs_check_chunk_valid(root, leaf, chunk, logical);
++ if (ret)
++ return ret;
+
+ read_lock(&map_tree->map_tree.lock);
+ em = lookup_extent_mapping(&map_tree->map_tree, logical, 1);
+@@ -6504,6 +6546,7 @@ int btrfs_read_sys_array(struct btrfs_ro
+ u32 array_size;
+ u32 len = 0;
+ u32 cur_offset;
++ u64 type;
+ struct btrfs_key key;
+
+ ASSERT(BTRFS_SUPER_INFO_SIZE <= root->nodesize);
+@@ -6569,6 +6612,15 @@ int btrfs_read_sys_array(struct btrfs_ro
+ ret = -EIO;
+ break;
+ }
++
++ type = btrfs_chunk_type(sb, chunk);
++ if ((type & BTRFS_BLOCK_GROUP_SYSTEM) == 0) {
++ btrfs_err(root->fs_info,
++ "invalid chunk type %llu in sys_array at offset %u",
++ type, cur_offset);
++ ret = -EIO;
++ break;
++ }
+
+ len = btrfs_chunk_item_size(num_stripes);
+ if (cur_offset + len > array_size)
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Liu Bo <bo.li.liu@oracle.com>
+Date: Tue, 23 Aug 2016 17:37:45 -0700
+Subject: Btrfs: check btree node's nritems
+
+From: Liu Bo <bo.li.liu@oracle.com>
+
+commit 053ab70f0604224c7893b43f9d9d5efa283580d6 upstream.
+
+When btree node (level = 1) has nritems which equals to zero,
+we can end up with panic due to insert_ptr()'s
+
+BUG_ON(slot > nritems);
+
+where slot is 1 and nritems is 0, as copy_for_split() calls
+insert_ptr(.., path->slots[1] + 1, ...);
+
+A invalid value results in the whole mess, this adds the check
+for btree's node nritems so that we stop reading block when
+when something is wrong.
+
+Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Chris Mason <clm@fb.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/disk-io.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -609,6 +609,19 @@ static noinline int check_leaf(struct bt
+ return 0;
+ }
+
++static int check_node(struct btrfs_root *root, struct extent_buffer *node)
++{
++ unsigned long nr = btrfs_header_nritems(node);
++
++ if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root)) {
++ btrfs_crit(root->fs_info,
++ "corrupt node: block %llu root %llu nritems %lu",
++ node->start, root->objectid, nr);
++ return -EIO;
++ }
++ return 0;
++}
++
+ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
+ u64 phy_offset, struct page *page,
+ u64 start, u64 end, int mirror)
+@@ -680,6 +693,9 @@ static int btree_readpage_end_io_hook(st
+ ret = -EIO;
+ }
+
++ if (found_level > 0 && check_node(root, eb))
++ ret = -EIO;
++
+ if (!ret)
+ set_extent_buffer_uptodate(eb);
+ err:
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Qu Wenruo <quwenruo.btrfs@gmx.com>
+Date: Wed, 23 Aug 2017 16:57:57 +0900
+Subject: btrfs: Check if item pointer overlaps with the item itself
+
+From: Qu Wenruo <quwenruo.btrfs@gmx.com>
+
+commit 7f43d4affb2a254d421ab20b0cf65ac2569909fb upstream.
+
+Function check_leaf() checks if any item pointer points outside of the
+leaf, but it doesn't check if the pointer overlaps with the item itself.
+
+Normally only the last item may be the victim, but adding such check is
+never a bad idea anyway.
+
+Signed-off-by: Qu Wenruo <quwenruo.btrfs@gmx.com>
+Reviewed-by: Nikolay Borisov <nborisov@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/disk-io.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -621,6 +621,13 @@ static noinline int check_leaf(struct bt
+ return -EUCLEAN;
+ }
+
++ /* Also check if the item pointer overlaps with btrfs item. */
++ if (btrfs_item_nr_offset(slot) + sizeof(struct btrfs_item) >
++ btrfs_item_ptr_offset(leaf, slot)) {
++ CORRUPT("slot overlap with its data", leaf, root, slot);
++ return -EUCLEAN;
++ }
++
+ prev_key.objectid = key.objectid;
+ prev_key.type = key.type;
+ prev_key.offset = key.offset;
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Liu Bo <bo.li.liu@oracle.com>
+Date: Wed, 22 Jun 2016 18:31:27 -0700
+Subject: Btrfs: check inconsistence between chunk and block group
+
+From: Liu Bo <bo.li.liu@oracle.com>
+
+commit 6fb37b756acce6d6e045f79c3764206033f617b4 upstream.
+
+With btrfs-corrupt-block, one can drop one chunk item and mounting
+will end up with a panic in btrfs_full_stripe_len().
+
+This doesn't not remove the BUG_ON, but instead checks it a bit
+earlier when we find the block group item.
+
+Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/extent-tree.c | 17 ++++++++++++++++-
+ 1 file changed, 16 insertions(+), 1 deletion(-)
+
+--- a/fs/btrfs/extent-tree.c
++++ b/fs/btrfs/extent-tree.c
+@@ -9502,7 +9502,22 @@ static int find_first_block_group(struct
+
+ if (found_key.objectid >= key->objectid &&
+ found_key.type == BTRFS_BLOCK_GROUP_ITEM_KEY) {
+- ret = 0;
++ struct extent_map_tree *em_tree;
++ struct extent_map *em;
++
++ em_tree = &root->fs_info->mapping_tree.map_tree;
++ read_lock(&em_tree->lock);
++ em = lookup_extent_mapping(em_tree, found_key.objectid,
++ found_key.offset);
++ read_unlock(&em_tree->lock);
++ if (!em) {
++ btrfs_err(root->fs_info,
++ "logical %llu len %llu found bg but no related chunk",
++ found_key.objectid, found_key.offset);
++ ret = -ENOENT;
++ } else {
++ ret = 0;
++ }
+ goto out;
+ }
+ path->slots[0]++;
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Qu Wenruo <wqu@suse.com>
+Date: Wed, 1 Aug 2018 10:37:16 +0800
+Subject: btrfs: Check that each block group has corresponding chunk at mount time
+
+From: Qu Wenruo <wqu@suse.com>
+
+commit 514c7dca85a0bf40be984dab0b477403a6db901f upstream.
+
+A crafted btrfs image with incorrect chunk<->block group mapping will
+trigger a lot of unexpected things as the mapping is essential.
+
+Although the problem can be caught by block group item checker
+added in "btrfs: tree-checker: Verify block_group_item", it's still not
+sufficient. A sufficiently valid block group item can pass the check
+added by the mentioned patch but could fail to match the existing chunk.
+
+This patch will add extra block group -> chunk mapping check, to ensure
+we have a completely matching (start, len, flags) chunk for each block
+group at mount time.
+
+Here we reuse the original helper find_first_block_group(), which is
+already doing the basic bg -> chunk checks, adding further checks of the
+start/len and type flags.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=199837
+Reported-by: Xu Wen <wen.xu@gatech.edu>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: Su Yue <suy.fnst@cn.fujitsu.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+[bwh: Backported to 4.4: Use root->fs_info instead of fs_info]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/extent-tree.c | 28 +++++++++++++++++++++++++++-
+ 1 file changed, 27 insertions(+), 1 deletion(-)
+
+--- a/fs/btrfs/extent-tree.c
++++ b/fs/btrfs/extent-tree.c
+@@ -9487,6 +9487,8 @@ static int find_first_block_group(struct
+ int ret = 0;
+ struct btrfs_key found_key;
+ struct extent_buffer *leaf;
++ struct btrfs_block_group_item bg;
++ u64 flags;
+ int slot;
+
+ ret = btrfs_search_slot(NULL, root, key, path, 0, 0);
+@@ -9521,8 +9523,32 @@ static int find_first_block_group(struct
+ "logical %llu len %llu found bg but no related chunk",
+ found_key.objectid, found_key.offset);
+ ret = -ENOENT;
++ } else if (em->start != found_key.objectid ||
++ em->len != found_key.offset) {
++ btrfs_err(root->fs_info,
++ "block group %llu len %llu mismatch with chunk %llu len %llu",
++ found_key.objectid, found_key.offset,
++ em->start, em->len);
++ ret = -EUCLEAN;
+ } else {
+- ret = 0;
++ read_extent_buffer(leaf, &bg,
++ btrfs_item_ptr_offset(leaf, slot),
++ sizeof(bg));
++ flags = btrfs_block_group_flags(&bg) &
++ BTRFS_BLOCK_GROUP_TYPE_MASK;
++
++ if (flags != (em->map_lookup->type &
++ BTRFS_BLOCK_GROUP_TYPE_MASK)) {
++ btrfs_err(root->fs_info,
++"block group %llu len %llu type flags 0x%llx mismatch with chunk type flags 0x%llx",
++ found_key.objectid,
++ found_key.offset, flags,
++ (BTRFS_BLOCK_GROUP_TYPE_MASK &
++ em->map_lookup->type));
++ ret = -EUCLEAN;
++ } else {
++ ret = 0;
++ }
+ }
+ free_extent_map(em);
+ goto out;
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Jeff Mahoney <jeffm@suse.com>
+Date: Wed, 3 Jun 2015 10:55:48 -0400
+Subject: btrfs: cleanup, stop casting for extent_map->lookup everywhere
+
+From: Jeff Mahoney <jeffm@suse.com>
+
+commit 95617d69326ce386c95e33db7aeb832b45ee9f8f upstream.
+
+Overloading extent_map->bdev to struct map_lookup * might have started out
+as a means to an end, but it's a pattern that's used all over the place
+now. Let's get rid of the casting and just add a union instead.
+
+Signed-off-by: Jeff Mahoney <jeffm@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/dev-replace.c | 2 +-
+ fs/btrfs/extent-tree.c | 2 +-
+ fs/btrfs/extent_map.c | 2 +-
+ fs/btrfs/extent_map.h | 10 +++++++++-
+ fs/btrfs/scrub.c | 2 +-
+ fs/btrfs/volumes.c | 24 ++++++++++++------------
+ 6 files changed, 25 insertions(+), 17 deletions(-)
+
+--- a/fs/btrfs/dev-replace.c
++++ b/fs/btrfs/dev-replace.c
+@@ -620,7 +620,7 @@ static void btrfs_dev_replace_update_dev
+ em = lookup_extent_mapping(em_tree, start, (u64)-1);
+ if (!em)
+ break;
+- map = (struct map_lookup *)em->bdev;
++ map = em->map_lookup;
+ for (i = 0; i < map->num_stripes; i++)
+ if (srcdev == map->stripes[i].dev)
+ map->stripes[i].dev = tgtdev;
+--- a/fs/btrfs/extent-tree.c
++++ b/fs/btrfs/extent-tree.c
+@@ -10388,7 +10388,7 @@ btrfs_start_trans_remove_block_group(str
+ * more device items and remove one chunk item), but this is done at
+ * btrfs_remove_chunk() through a call to check_system_chunk().
+ */
+- map = (struct map_lookup *)em->bdev;
++ map = em->map_lookup;
+ num_items = 3 + map->num_stripes;
+ free_extent_map(em);
+
+--- a/fs/btrfs/extent_map.c
++++ b/fs/btrfs/extent_map.c
+@@ -76,7 +76,7 @@ void free_extent_map(struct extent_map *
+ WARN_ON(extent_map_in_tree(em));
+ WARN_ON(!list_empty(&em->list));
+ if (test_bit(EXTENT_FLAG_FS_MAPPING, &em->flags))
+- kfree(em->bdev);
++ kfree(em->map_lookup);
+ kmem_cache_free(extent_map_cache, em);
+ }
+ }
+--- a/fs/btrfs/extent_map.h
++++ b/fs/btrfs/extent_map.h
+@@ -32,7 +32,15 @@ struct extent_map {
+ u64 block_len;
+ u64 generation;
+ unsigned long flags;
+- struct block_device *bdev;
++ union {
++ struct block_device *bdev;
++
++ /*
++ * used for chunk mappings
++ * flags & EXTENT_FLAG_FS_MAPPING must be set
++ */
++ struct map_lookup *map_lookup;
++ };
+ atomic_t refs;
+ unsigned int compress_type;
+ struct list_head list;
+--- a/fs/btrfs/scrub.c
++++ b/fs/btrfs/scrub.c
+@@ -3460,7 +3460,7 @@ static noinline_for_stack int scrub_chun
+ return ret;
+ }
+
+- map = (struct map_lookup *)em->bdev;
++ map = em->map_lookup;
+ if (em->start != chunk_offset)
+ goto out;
+
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -1184,7 +1184,7 @@ again:
+ struct map_lookup *map;
+ int i;
+
+- map = (struct map_lookup *)em->bdev;
++ map = em->map_lookup;
+ for (i = 0; i < map->num_stripes; i++) {
+ u64 end;
+
+@@ -2757,7 +2757,7 @@ int btrfs_remove_chunk(struct btrfs_tran
+ free_extent_map(em);
+ return -EINVAL;
+ }
+- map = (struct map_lookup *)em->bdev;
++ map = em->map_lookup;
+ lock_chunks(root->fs_info->chunk_root);
+ check_system_chunk(trans, extent_root, map->type);
+ unlock_chunks(root->fs_info->chunk_root);
+@@ -4731,7 +4731,7 @@ static int __btrfs_alloc_chunk(struct bt
+ goto error;
+ }
+ set_bit(EXTENT_FLAG_FS_MAPPING, &em->flags);
+- em->bdev = (struct block_device *)map;
++ em->map_lookup = map;
+ em->start = start;
+ em->len = num_bytes;
+ em->block_start = 0;
+@@ -4826,7 +4826,7 @@ int btrfs_finish_chunk_alloc(struct btrf
+ return -EINVAL;
+ }
+
+- map = (struct map_lookup *)em->bdev;
++ map = em->map_lookup;
+ item_size = btrfs_chunk_item_size(map->num_stripes);
+ stripe_size = em->orig_block_len;
+
+@@ -4968,7 +4968,7 @@ int btrfs_chunk_readonly(struct btrfs_ro
+ if (!em)
+ return 1;
+
+- map = (struct map_lookup *)em->bdev;
++ map = em->map_lookup;
+ for (i = 0; i < map->num_stripes; i++) {
+ if (map->stripes[i].dev->missing) {
+ miss_ndevs++;
+@@ -5048,7 +5048,7 @@ int btrfs_num_copies(struct btrfs_fs_inf
+ return 1;
+ }
+
+- map = (struct map_lookup *)em->bdev;
++ map = em->map_lookup;
+ if (map->type & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1))
+ ret = map->num_stripes;
+ else if (map->type & BTRFS_BLOCK_GROUP_RAID10)
+@@ -5091,7 +5091,7 @@ unsigned long btrfs_full_stripe_len(stru
+ BUG_ON(!em);
+
+ BUG_ON(em->start > logical || em->start + em->len < logical);
+- map = (struct map_lookup *)em->bdev;
++ map = em->map_lookup;
+ if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
+ len = map->stripe_len * nr_data_stripes(map);
+ free_extent_map(em);
+@@ -5112,7 +5112,7 @@ int btrfs_is_parity_mirror(struct btrfs_
+ BUG_ON(!em);
+
+ BUG_ON(em->start > logical || em->start + em->len < logical);
+- map = (struct map_lookup *)em->bdev;
++ map = em->map_lookup;
+ if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
+ ret = 1;
+ free_extent_map(em);
+@@ -5271,7 +5271,7 @@ static int __btrfs_map_block(struct btrf
+ return -EINVAL;
+ }
+
+- map = (struct map_lookup *)em->bdev;
++ map = em->map_lookup;
+ offset = logical - em->start;
+
+ stripe_len = map->stripe_len;
+@@ -5813,7 +5813,7 @@ int btrfs_rmap_block(struct btrfs_mappin
+ free_extent_map(em);
+ return -EIO;
+ }
+- map = (struct map_lookup *)em->bdev;
++ map = em->map_lookup;
+
+ length = em->len;
+ rmap_len = map->stripe_len;
+@@ -6249,7 +6249,7 @@ static int read_one_chunk(struct btrfs_r
+ }
+
+ set_bit(EXTENT_FLAG_FS_MAPPING, &em->flags);
+- em->bdev = (struct block_device *)map;
++ em->map_lookup = map;
+ em->start = logical;
+ em->len = length;
+ em->orig_start = 0;
+@@ -6948,7 +6948,7 @@ void btrfs_update_commit_device_bytes_us
+ /* In order to kick the device replace finish process */
+ lock_chunks(root);
+ list_for_each_entry(em, &transaction->pending_chunks, list) {
+- map = (struct map_lookup *)em->bdev;
++ map = em->map_lookup;
+
+ for (i = 0; i < map->num_stripes; i++) {
+ dev = map->stripes[i].dev;
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Liu Bo <bo.li.liu@oracle.com>
+Date: Tue, 23 Aug 2016 15:22:58 -0700
+Subject: Btrfs: detect corruption when non-root leaf has zero item
+
+From: Liu Bo <bo.li.liu@oracle.com>
+
+commit 1ba98d086fe3a14d6a31f2f66dbab70c45d00f63 upstream.
+
+Right now we treat leaf which has zero item as a valid one
+because we could have an empty tree, that is, a root that is
+also a leaf without any item, however, in the same case but
+when the leaf is not a root, we can end up with hitting the
+BUG_ON(1) in btrfs_extend_item() called by
+setup_inline_extent_backref().
+
+This makes us check the situation as a corruption if leaf is
+not its own root.
+
+Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Chris Mason <clm@fb.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/disk-io.c | 23 ++++++++++++++++++++++-
+ 1 file changed, 22 insertions(+), 1 deletion(-)
+
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -535,8 +535,29 @@ static noinline int check_leaf(struct bt
+ u32 nritems = btrfs_header_nritems(leaf);
+ int slot;
+
+- if (nritems == 0)
++ if (nritems == 0) {
++ struct btrfs_root *check_root;
++
++ key.objectid = btrfs_header_owner(leaf);
++ key.type = BTRFS_ROOT_ITEM_KEY;
++ key.offset = (u64)-1;
++
++ check_root = btrfs_get_fs_root(root->fs_info, &key, false);
++ /*
++ * The only reason we also check NULL here is that during
++ * open_ctree() some roots has not yet been set up.
++ */
++ if (!IS_ERR_OR_NULL(check_root)) {
++ /* if leaf is the root, then it's fine */
++ if (leaf->start !=
++ btrfs_root_bytenr(&check_root->root_item)) {
++ CORRUPT("non-root leaf's nritems is 0",
++ leaf, root, 0);
++ return -EIO;
++ }
++ }
+ return 0;
++ }
+
+ /* Check the 0 item */
+ if (btrfs_item_offset_nr(leaf, 0) + btrfs_item_size_nr(leaf, 0) !=
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Qu Wenruo <quwenruo@cn.fujitsu.com>
+Date: Tue, 15 Dec 2015 09:14:37 +0800
+Subject: btrfs: Enhance chunk validation check
+
+From: Qu Wenruo <quwenruo@cn.fujitsu.com>
+
+commit f04b772bfc17f502703794f4d100d12155c1a1a9 upstream.
+
+Enhance chunk validation:
+1) Num_stripes
+ We already have such check but it's only in super block sys chunk
+ array.
+ Now check all on-disk chunks.
+
+2) Chunk logical
+ It should be aligned to sector size.
+ This behavior should be *DOUBLE CHECKED* for 64K sector size like
+ PPC64 or AArch64.
+ Maybe we can found some hidden bugs.
+
+3) Chunk length
+ Same as chunk logical, should be aligned to sector size.
+
+4) Stripe length
+ It should be power of 2.
+
+5) Chunk type
+ Any bit out of TYPE_MAS | PROFILE_MASK is invalid.
+
+With all these much restrict rules, several fuzzed image reported in
+mail list should no longer cause kernel panic.
+
+Reported-by: Vegard Nossum <vegard.nossum@oracle.com>
+Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
+Signed-off-by: Chris Mason <clm@fb.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/volumes.c | 33 ++++++++++++++++++++++++++++++++-
+ 1 file changed, 32 insertions(+), 1 deletion(-)
+
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -6217,6 +6217,7 @@ static int read_one_chunk(struct btrfs_r
+ struct extent_map *em;
+ u64 logical;
+ u64 length;
++ u64 stripe_len;
+ u64 devid;
+ u8 uuid[BTRFS_UUID_SIZE];
+ int num_stripes;
+@@ -6225,6 +6226,37 @@ static int read_one_chunk(struct btrfs_r
+
+ logical = key->offset;
+ length = btrfs_chunk_length(leaf, chunk);
++ stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
++ num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
++ /* Validation check */
++ if (!num_stripes) {
++ btrfs_err(root->fs_info, "invalid chunk num_stripes: %u",
++ num_stripes);
++ return -EIO;
++ }
++ if (!IS_ALIGNED(logical, root->sectorsize)) {
++ btrfs_err(root->fs_info,
++ "invalid chunk logical %llu", logical);
++ return -EIO;
++ }
++ if (!length || !IS_ALIGNED(length, root->sectorsize)) {
++ btrfs_err(root->fs_info,
++ "invalid chunk length %llu", length);
++ return -EIO;
++ }
++ if (!is_power_of_2(stripe_len)) {
++ btrfs_err(root->fs_info, "invalid chunk stripe length: %llu",
++ stripe_len);
++ return -EIO;
++ }
++ if (~(BTRFS_BLOCK_GROUP_TYPE_MASK | BTRFS_BLOCK_GROUP_PROFILE_MASK) &
++ btrfs_chunk_type(leaf, chunk)) {
++ btrfs_err(root->fs_info, "unrecognized chunk type: %llu",
++ ~(BTRFS_BLOCK_GROUP_TYPE_MASK |
++ BTRFS_BLOCK_GROUP_PROFILE_MASK) &
++ btrfs_chunk_type(leaf, chunk));
++ return -EIO;
++ }
+
+ read_lock(&map_tree->map_tree.lock);
+ em = lookup_extent_mapping(&map_tree->map_tree, logical, 1);
+@@ -6241,7 +6273,6 @@ static int read_one_chunk(struct btrfs_r
+ em = alloc_extent_map();
+ if (!em)
+ return -ENOMEM;
+- num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
+ map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
+ if (!map) {
+ free_extent_map(em);
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Liu Bo <bo.li.liu@oracle.com>
+Date: Fri, 2 Sep 2016 12:35:34 -0700
+Subject: Btrfs: fix BUG_ON in btrfs_mark_buffer_dirty
+
+From: Liu Bo <bo.li.liu@oracle.com>
+
+commit ef85b25e982b5bba1530b936e283ef129f02ab9d upstream.
+
+This can only happen with CONFIG_BTRFS_FS_CHECK_INTEGRITY=y.
+
+Commit 1ba98d0 ("Btrfs: detect corruption when non-root leaf has zero item")
+assumes that a leaf is its root when leaf->bytenr == btrfs_root_bytenr(root),
+however, we should not use btrfs_root_bytenr(root) since it's mainly got
+updated during committing transaction. So the check can fail when doing
+COW on this leaf while it is a root.
+
+This changes to use "if (leaf == btrfs_root_node(root))" instead, just like
+how we check whether leaf is a root in __btrfs_cow_block().
+
+Fixes: 1ba98d086fe3 (Btrfs: detect corruption when non-root leaf has zero item)
+Reported-by: Jeff Mahoney <jeffm@suse.com>
+Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
+Reviewed-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/disk-io.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -548,13 +548,17 @@ static noinline int check_leaf(struct bt
+ * open_ctree() some roots has not yet been set up.
+ */
+ if (!IS_ERR_OR_NULL(check_root)) {
++ struct extent_buffer *eb;
++
++ eb = btrfs_root_node(check_root);
+ /* if leaf is the root, then it's fine */
+- if (leaf->start !=
+- btrfs_root_bytenr(&check_root->root_item)) {
++ if (leaf != eb) {
+ CORRUPT("non-root leaf's nritems is 0",
+- leaf, root, 0);
++ leaf, check_root, 0);
++ free_extent_buffer(eb);
+ return -EIO;
+ }
++ free_extent_buffer(eb);
+ }
+ return 0;
+ }
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Josef Bacik <jbacik@fb.com>
+Date: Thu, 18 Aug 2016 15:30:06 -0400
+Subject: Btrfs: fix em leak in find_first_block_group
+
+From: Josef Bacik <jbacik@fb.com>
+
+commit 187ee58c62c1d0d238d3dc4835869d33e1869906 upstream.
+
+We need to call free_extent_map() on the em we look up.
+
+Signed-off-by: Josef Bacik <jbacik@fb.com>
+Reviewed-by: Omar Sandoval <osandov@fb.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Chris Mason <clm@fb.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/extent-tree.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/fs/btrfs/extent-tree.c
++++ b/fs/btrfs/extent-tree.c
+@@ -9518,6 +9518,7 @@ static int find_first_block_group(struct
+ } else {
+ ret = 0;
+ }
++ free_extent_map(em);
+ goto out;
+ }
+ path->slots[0]++;
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Filipe Manana <fdmanana@suse.com>
+Date: Wed, 23 Nov 2016 16:21:18 +0000
+Subject: Btrfs: fix emptiness check for dirtied extent buffers at check_leaf()
+
+From: Filipe Manana <fdmanana@suse.com>
+
+commit f177d73949bf758542ca15a1c1945bd2e802cc65 upstream.
+
+We can not simply use the owner field from an extent buffer's header to
+get the id of the respective tree when the extent buffer is from a
+relocation tree. When we create the root for a relocation tree we leave
+(on purpose) the owner field with the same value as the subvolume's tree
+root (we do this at ctree.c:btrfs_copy_root()). So we must ignore extent
+buffers from relocation trees, which have the BTRFS_HEADER_FLAG_RELOC
+flag set, because otherwise we will always consider the extent buffer
+as not being the root of the tree (the root of original subvolume tree
+is always different from the root of the respective relocation tree).
+
+This lead to assertion failures when running with the integrity checker
+enabled (CONFIG_BTRFS_FS_CHECK_INTEGRITY=y) such as the following:
+
+[ 643.393409] BTRFS critical (device sdg): corrupt leaf, non-root leaf's nritems is 0: block=38506496, root=260, slot=0
+[ 643.397609] BTRFS info (device sdg): leaf 38506496 total ptrs 0 free space 3995
+[ 643.407075] assertion failed: 0, file: fs/btrfs/disk-io.c, line: 4078
+[ 643.408425] ------------[ cut here ]------------
+[ 643.409112] kernel BUG at fs/btrfs/ctree.h:3419!
+[ 643.409773] invalid opcode: 0000 [#1] PREEMPT SMP
+[ 643.410447] Modules linked in: dm_flakey dm_mod crc32c_generic btrfs xor raid6_pq ppdev psmouse acpi_cpufreq parport_pc evdev parport tpm_tis tpm_tis_core pcspkr serio_raw i2c_piix4 sg tpm i2c_core button processor loop autofs4 ext4 crc16 jbd2 mbcache sr_mod cdrom sd_mod ata_generic virtio_scsi ata_piix libata virtio_pci virtio_ring scsi_mod virtio e1000 floppy
+[ 643.414356] CPU: 11 PID: 32726 Comm: btrfs Not tainted 4.8.0-rc8-btrfs-next-35+ #1
+[ 643.414356] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.9.1-0-gb3ef39f-prebuilt.qemu-project.org 04/01/2014
+[ 643.414356] task: ffff880145e95b00 task.stack: ffff88014826c000
+[ 643.414356] RIP: 0010:[<ffffffffa0352759>] [<ffffffffa0352759>] assfail.constprop.41+0x1c/0x1e [btrfs]
+[ 643.414356] RSP: 0018:ffff88014826fa28 EFLAGS: 00010292
+[ 643.414356] RAX: 0000000000000039 RBX: ffff88014e2d7c38 RCX: 0000000000000001
+[ 643.414356] RDX: ffff88023f4d2f58 RSI: ffffffff81806c63 RDI: 00000000ffffffff
+[ 643.414356] RBP: ffff88014826fa28 R08: 0000000000000001 R09: 0000000000000000
+[ 643.414356] R10: ffff88014826f918 R11: ffffffff82f3c5ed R12: ffff880172910000
+[ 643.414356] R13: ffff880233992230 R14: ffff8801a68a3310 R15: fffffffffffffff8
+[ 643.414356] FS: 00007f9ca305e8c0(0000) GS:ffff88023f4c0000(0000) knlGS:0000000000000000
+[ 643.414356] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 643.414356] CR2: 00007f9ca3071000 CR3: 000000015d01b000 CR4: 00000000000006e0
+[ 643.414356] Stack:
+[ 643.414356] ffff88014826fa50 ffffffffa02d655a 000000000000000a ffff88014e2d7c38
+[ 643.414356] 0000000000000000 ffff88014826faa8 ffffffffa02b72f3 ffff88014826fab8
+[ 643.414356] 00ffffffa03228e4 0000000000000000 0000000000000000 ffff8801bbd4e000
+[ 643.414356] Call Trace:
+[ 643.414356] [<ffffffffa02d655a>] btrfs_mark_buffer_dirty+0xdf/0xe5 [btrfs]
+[ 643.414356] [<ffffffffa02b72f3>] btrfs_copy_root+0x18a/0x1d1 [btrfs]
+[ 643.414356] [<ffffffffa0322921>] create_reloc_root+0x72/0x1ba [btrfs]
+[ 643.414356] [<ffffffffa03267c2>] btrfs_init_reloc_root+0x7b/0xa7 [btrfs]
+[ 643.414356] [<ffffffffa02d9e44>] record_root_in_trans+0xdf/0xed [btrfs]
+[ 643.414356] [<ffffffffa02db04e>] btrfs_record_root_in_trans+0x50/0x6a [btrfs]
+[ 643.414356] [<ffffffffa030ad2b>] create_subvol+0x472/0x773 [btrfs]
+[ 643.414356] [<ffffffffa030b406>] btrfs_mksubvol+0x3da/0x463 [btrfs]
+[ 643.414356] [<ffffffffa030b406>] ? btrfs_mksubvol+0x3da/0x463 [btrfs]
+[ 643.414356] [<ffffffff810781ac>] ? preempt_count_add+0x65/0x68
+[ 643.414356] [<ffffffff811a6e97>] ? __mnt_want_write+0x62/0x77
+[ 643.414356] [<ffffffffa030b55d>] btrfs_ioctl_snap_create_transid+0xce/0x187 [btrfs]
+[ 643.414356] [<ffffffffa030b67d>] btrfs_ioctl_snap_create+0x67/0x81 [btrfs]
+[ 643.414356] [<ffffffffa030ecfd>] btrfs_ioctl+0x508/0x20dd [btrfs]
+[ 643.414356] [<ffffffff81293e39>] ? __this_cpu_preempt_check+0x13/0x15
+[ 643.414356] [<ffffffff81155eca>] ? handle_mm_fault+0x976/0x9ab
+[ 643.414356] [<ffffffff81091300>] ? arch_local_irq_save+0x9/0xc
+[ 643.414356] [<ffffffff8119a2b0>] vfs_ioctl+0x18/0x34
+[ 643.414356] [<ffffffff8119a8e8>] do_vfs_ioctl+0x581/0x600
+[ 643.414356] [<ffffffff814b9552>] ? entry_SYSCALL_64_fastpath+0x5/0xa8
+[ 643.414356] [<ffffffff81093fe9>] ? trace_hardirqs_on_caller+0x17b/0x197
+[ 643.414356] [<ffffffff8119a9be>] SyS_ioctl+0x57/0x79
+[ 643.414356] [<ffffffff814b9565>] entry_SYSCALL_64_fastpath+0x18/0xa8
+[ 643.414356] [<ffffffff81091b08>] ? trace_hardirqs_off_caller+0x3f/0xaa
+[ 643.414356] Code: 89 83 88 00 00 00 31 c0 5b 41 5c 41 5d 5d c3 55 89 f1 48 c7 c2 98 bc 35 a0 48 89 fe 48 c7 c7 05 be 35 a0 48 89 e5 e8 13 46 dd e0 <0f> 0b 55 89 f1 48 c7 c2 9f d3 35 a0 48 89 fe 48 c7 c7 7a d5 35
+[ 643.414356] RIP [<ffffffffa0352759>] assfail.constprop.41+0x1c/0x1e [btrfs]
+[ 643.414356] RSP <ffff88014826fa28>
+[ 643.468267] ---[ end trace 6a1b3fb1a9d7d6e3 ]---
+
+This can be easily reproduced by running xfstests with the integrity
+checker enabled.
+
+Fixes: 1ba98d086fe3 (Btrfs: detect corruption when non-root leaf has zero item)
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Reviewed-by: Liu Bo <bo.li.liu@oracle.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/disk-io.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -536,7 +536,15 @@ static noinline int check_leaf(struct bt
+ u32 nritems = btrfs_header_nritems(leaf);
+ int slot;
+
+- if (nritems == 0) {
++ /*
++ * Extent buffers from a relocation tree have a owner field that
++ * corresponds to the subvolume tree they are based on. So just from an
++ * extent buffer alone we can not find out what is the id of the
++ * corresponding subvolume tree, so we can not figure out if the extent
++ * buffer corresponds to the root of the relocation tree or not. So skip
++ * this check for relocation trees.
++ */
++ if (nritems == 0 && !btrfs_header_flag(leaf, BTRFS_HEADER_FLAG_RELOC)) {
+ struct btrfs_root *check_root;
+
+ key.objectid = btrfs_header_owner(leaf);
+@@ -564,6 +572,9 @@ static noinline int check_leaf(struct bt
+ return 0;
+ }
+
++ if (nritems == 0)
++ return 0;
++
+ /* Check the 0 item */
+ if (btrfs_item_offset_nr(leaf, 0) + btrfs_item_size_nr(leaf, 0) !=
+ BTRFS_LEAF_DATA_SIZE(root)) {
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Liu Bo <bo.li.liu@oracle.com>
+Date: Wed, 14 Sep 2016 17:23:24 -0700
+Subject: Btrfs: improve check_node to avoid reading corrupted nodes
+
+From: Liu Bo <bo.li.liu@oracle.com>
+
+commit 6b722c1747d533ac6d4df110dc8233db46918b65 upstream.
+
+We need to check items in a node to make sure that we're reading
+a valid one, otherwise we could get various crashes while processing
+delayed_refs.
+
+Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/disk-io.c | 32 ++++++++++++++++++++++++++++----
+ 1 file changed, 28 insertions(+), 4 deletions(-)
+
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -523,9 +523,10 @@ static int check_tree_block_fsid(struct
+ }
+
+ #define CORRUPT(reason, eb, root, slot) \
+- btrfs_crit(root->fs_info, "corrupt leaf, %s: block=%llu," \
+- "root=%llu, slot=%d", reason, \
+- btrfs_header_bytenr(eb), root->objectid, slot)
++ btrfs_crit(root->fs_info, "corrupt %s, %s: block=%llu," \
++ " root=%llu, slot=%d", \
++ btrfs_header_level(eb) == 0 ? "leaf" : "node",\
++ reason, btrfs_header_bytenr(eb), root->objectid, slot)
+
+ static noinline int check_leaf(struct btrfs_root *root,
+ struct extent_buffer *leaf)
+@@ -616,6 +617,10 @@ static noinline int check_leaf(struct bt
+ static int check_node(struct btrfs_root *root, struct extent_buffer *node)
+ {
+ unsigned long nr = btrfs_header_nritems(node);
++ struct btrfs_key key, next_key;
++ int slot;
++ u64 bytenr;
++ int ret = 0;
+
+ if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root)) {
+ btrfs_crit(root->fs_info,
+@@ -623,7 +628,26 @@ static int check_node(struct btrfs_root
+ node->start, root->objectid, nr);
+ return -EIO;
+ }
+- return 0;
++
++ for (slot = 0; slot < nr - 1; slot++) {
++ bytenr = btrfs_node_blockptr(node, slot);
++ btrfs_node_key_to_cpu(node, &key, slot);
++ btrfs_node_key_to_cpu(node, &next_key, slot + 1);
++
++ if (!bytenr) {
++ CORRUPT("invalid item slot", node, root, slot);
++ ret = -EIO;
++ goto out;
++ }
++
++ if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) {
++ CORRUPT("bad key order", node, root, slot);
++ ret = -EIO;
++ goto out;
++ }
++ }
++out:
++ return ret;
+ }
+
+ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Liu Bo <bo.li.liu@oracle.com>
+Date: Wed, 14 Sep 2016 19:19:05 -0700
+Subject: Btrfs: kill BUG_ON in run_delayed_tree_ref
+
+From: Liu Bo <bo.li.liu@oracle.com>
+
+commit 02794222c4132ac003e7281fb71f4ec1645ffc87 upstream.
+
+In a corrupted btrfs image, we can come across this BUG_ON and
+get an unreponsive system, but if we return errors instead,
+its caller can handle everything gracefully by aborting the current
+transaction.
+
+Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/extent-tree.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/fs/btrfs/extent-tree.c
++++ b/fs/btrfs/extent-tree.c
+@@ -2342,7 +2342,13 @@ static int run_delayed_tree_ref(struct b
+ ins.type = BTRFS_EXTENT_ITEM_KEY;
+ }
+
+- BUG_ON(node->ref_mod != 1);
++ if (node->ref_mod != 1) {
++ btrfs_err(root->fs_info,
++ "btree block(%llu) has %d references rather than 1: action %d ref_root %llu parent %llu",
++ node->bytenr, node->ref_mod, node->action, ref_root,
++ parent);
++ return -EIO;
++ }
+ if (node->action == BTRFS_ADD_DELAYED_REF && insert_reserved) {
+ BUG_ON(!extent_op || !extent_op->update_flags);
+ ret = alloc_reserved_tree_block(trans, root,
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Liu Bo <bo.li.liu@oracle.com>
+Date: Fri, 23 Sep 2016 13:44:44 -0700
+Subject: Btrfs: memset to avoid stale content in btree leaf
+
+From: Liu Bo <bo.li.liu@oracle.com>
+
+commit 851cd173f06045816528176001cf82948282029c upstream.
+
+This is an additional patch to
+"Btrfs: memset to avoid stale content in btree node block".
+
+This uses memset to initialize the unused space in a leaf to avoid
+potential stale content, which may be incurred by pushing items
+between sibling leaves.
+
+Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/ctree.c | 14 --------------
+ fs/btrfs/ctree.h | 15 +++++++++++++++
+ fs/btrfs/extent_io.c | 18 +++++++++++++-----
+ 3 files changed, 28 insertions(+), 19 deletions(-)
+
+--- a/fs/btrfs/ctree.c
++++ b/fs/btrfs/ctree.c
+@@ -1726,20 +1726,6 @@ int btrfs_realloc_node(struct btrfs_tran
+ return err;
+ }
+
+-/*
+- * The leaf data grows from end-to-front in the node.
+- * this returns the address of the start of the last item,
+- * which is the stop of the leaf data stack
+- */
+-static inline unsigned int leaf_data_end(struct btrfs_root *root,
+- struct extent_buffer *leaf)
+-{
+- u32 nr = btrfs_header_nritems(leaf);
+- if (nr == 0)
+- return BTRFS_LEAF_DATA_SIZE(root);
+- return btrfs_item_offset_nr(leaf, nr - 1);
+-}
+-
+
+ /*
+ * search for key in the extent_buffer. The items start at offset p,
+--- a/fs/btrfs/ctree.h
++++ b/fs/btrfs/ctree.h
+@@ -3158,6 +3158,21 @@ static inline unsigned long btrfs_leaf_d
+ return offsetof(struct btrfs_leaf, items);
+ }
+
++/*
++ * The leaf data grows from end-to-front in the node.
++ * this returns the address of the start of the last item,
++ * which is the stop of the leaf data stack
++ */
++static inline unsigned int leaf_data_end(struct btrfs_root *root,
++ struct extent_buffer *leaf)
++{
++ u32 nr = btrfs_header_nritems(leaf);
++
++ if (nr == 0)
++ return BTRFS_LEAF_DATA_SIZE(root);
++ return btrfs_item_offset_nr(leaf, nr - 1);
++}
++
+ /* struct btrfs_file_extent_item */
+ BTRFS_SETGET_FUNCS(file_extent_type, struct btrfs_file_extent_item, type, 8);
+ BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_bytenr,
+--- a/fs/btrfs/extent_io.c
++++ b/fs/btrfs/extent_io.c
+@@ -3847,8 +3847,10 @@ static noinline_for_stack int write_one_
+ struct block_device *bdev = fs_info->fs_devices->latest_bdev;
+ struct extent_io_tree *tree = &BTRFS_I(fs_info->btree_inode)->io_tree;
+ u64 offset = eb->start;
++ u32 nritems;
+ unsigned long i, num_pages;
+ unsigned long bio_flags = 0;
++ unsigned long start, end;
+ int rw = (epd->sync_io ? WRITE_SYNC : WRITE) | REQ_META;
+ int ret = 0;
+
+@@ -3858,15 +3860,21 @@ static noinline_for_stack int write_one_
+ if (btrfs_header_owner(eb) == BTRFS_TREE_LOG_OBJECTID)
+ bio_flags = EXTENT_BIO_TREE_LOG;
+
+- /* set btree node beyond nritems with 0 to avoid stale content */
++ /* set btree blocks beyond nritems with 0 to avoid stale content. */
++ nritems = btrfs_header_nritems(eb);
+ if (btrfs_header_level(eb) > 0) {
+- u32 nritems;
+- unsigned long end;
+-
+- nritems = btrfs_header_nritems(eb);
+ end = btrfs_node_key_ptr_offset(nritems);
+
+ memset_extent_buffer(eb, 0, end, eb->len - end);
++ } else {
++ /*
++ * leaf:
++ * header 0 1 2 .. N ... data_N .. data_2 data_1 data_0
++ */
++ start = btrfs_item_nr_offset(nritems);
++ end = btrfs_leaf_data(eb) +
++ leaf_data_end(fs_info->tree_root, eb);
++ memset_extent_buffer(eb, 0, start, end - start);
+ }
+
+ for (i = 0; i < num_pages; i++) {
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Liu Bo <bo.li.liu@oracle.com>
+Date: Wed, 14 Sep 2016 17:22:57 -0700
+Subject: Btrfs: memset to avoid stale content in btree node block
+
+From: Liu Bo <bo.li.liu@oracle.com>
+
+commit 3eb548ee3a8042d95ad81be254e67a5222c24e03 upstream.
+
+During updating btree, we could push items between sibling
+nodes/leaves, for leaves data sections starts reversely from
+the end of the block while for nodes we only have key pairs
+which are stored one by one from the start of the block.
+
+So we could do try to push key pairs from one node to the next
+node right in the tree, and after that, we update the node's
+nritems to reflect the correct end while leaving the stale
+content in the node. One may intentionally corrupt the fs
+image and access the stale content by bumping the nritems and
+causes various crashes.
+
+This takes the in-memory @nritems as the correct one and
+gets to memset the unused part of a btree node.
+
+Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/extent_io.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+--- a/fs/btrfs/extent_io.c
++++ b/fs/btrfs/extent_io.c
+@@ -3858,6 +3858,17 @@ static noinline_for_stack int write_one_
+ if (btrfs_header_owner(eb) == BTRFS_TREE_LOG_OBJECTID)
+ bio_flags = EXTENT_BIO_TREE_LOG;
+
++ /* set btree node beyond nritems with 0 to avoid stale content */
++ if (btrfs_header_level(eb) > 0) {
++ u32 nritems;
++ unsigned long end;
++
++ nritems = btrfs_header_nritems(eb);
++ end = btrfs_node_key_ptr_offset(nritems);
++
++ memset_extent_buffer(eb, 0, end, eb->len - end);
++ }
++
+ for (i = 0; i < num_pages; i++) {
+ struct page *p = eb->pages[i];
+
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Qu Wenruo <quwenruo.btrfs@gmx.com>
+Date: Mon, 9 Oct 2017 01:51:02 +0000
+Subject: btrfs: Move leaf and node validation checker to tree-checker.c
+
+From: Qu Wenruo <quwenruo.btrfs@gmx.com>
+
+commit 557ea5dd003d371536f6b4e8f7c8209a2b6fd4e3 upstream.
+
+It's no doubt the comprehensive tree block checker will become larger,
+so moving them into their own files is quite reasonable.
+
+Signed-off-by: Qu Wenruo <quwenruo.btrfs@gmx.com>
+[ wording adjustments ]
+Signed-off-by: David Sterba <dsterba@suse.com>
+[bwh: Backported to 4.4:
+ - The moved code is slightly different
+ - Adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/Makefile | 2
+ fs/btrfs/disk-io.c | 284 --------------------------------------------
+ fs/btrfs/tree-checker.c | 309 ++++++++++++++++++++++++++++++++++++++++++++++++
+ fs/btrfs/tree-checker.h | 26 ++++
+ 4 files changed, 340 insertions(+), 281 deletions(-)
+ create mode 100644 fs/btrfs/tree-checker.c
+ create mode 100644 fs/btrfs/tree-checker.h
+
+--- a/fs/btrfs/Makefile
++++ b/fs/btrfs/Makefile
+@@ -9,7 +9,7 @@ btrfs-y += super.o ctree.o extent-tree.o
+ export.o tree-log.o free-space-cache.o zlib.o lzo.o \
+ compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
+ reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \
+- uuid-tree.o props.o hash.o
++ uuid-tree.o props.o hash.o tree-checker.o
+
+ btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
+ btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -49,6 +49,7 @@
+ #include "raid56.h"
+ #include "sysfs.h"
+ #include "qgroup.h"
++#include "tree-checker.h"
+
+ #ifdef CONFIG_X86
+ #include <asm/cpufeature.h>
+@@ -522,283 +523,6 @@ static int check_tree_block_fsid(struct
+ return ret;
+ }
+
+-#define CORRUPT(reason, eb, root, slot) \
+- btrfs_crit(root->fs_info, "corrupt %s, %s: block=%llu," \
+- " root=%llu, slot=%d", \
+- btrfs_header_level(eb) == 0 ? "leaf" : "node",\
+- reason, btrfs_header_bytenr(eb), root->objectid, slot)
+-
+-static int check_extent_data_item(struct btrfs_root *root,
+- struct extent_buffer *leaf,
+- struct btrfs_key *key, int slot)
+-{
+- struct btrfs_file_extent_item *fi;
+- u32 sectorsize = root->sectorsize;
+- u32 item_size = btrfs_item_size_nr(leaf, slot);
+-
+- if (!IS_ALIGNED(key->offset, sectorsize)) {
+- CORRUPT("unaligned key offset for file extent",
+- leaf, root, slot);
+- return -EUCLEAN;
+- }
+-
+- fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
+-
+- if (btrfs_file_extent_type(leaf, fi) > BTRFS_FILE_EXTENT_TYPES) {
+- CORRUPT("invalid file extent type", leaf, root, slot);
+- return -EUCLEAN;
+- }
+-
+- /*
+- * Support for new compression/encrption must introduce incompat flag,
+- * and must be caught in open_ctree().
+- */
+- if (btrfs_file_extent_compression(leaf, fi) > BTRFS_COMPRESS_TYPES) {
+- CORRUPT("invalid file extent compression", leaf, root, slot);
+- return -EUCLEAN;
+- }
+- if (btrfs_file_extent_encryption(leaf, fi)) {
+- CORRUPT("invalid file extent encryption", leaf, root, slot);
+- return -EUCLEAN;
+- }
+- if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
+- /* Inline extent must have 0 as key offset */
+- if (key->offset) {
+- CORRUPT("inline extent has non-zero key offset",
+- leaf, root, slot);
+- return -EUCLEAN;
+- }
+-
+- /* Compressed inline extent has no on-disk size, skip it */
+- if (btrfs_file_extent_compression(leaf, fi) !=
+- BTRFS_COMPRESS_NONE)
+- return 0;
+-
+- /* Uncompressed inline extent size must match item size */
+- if (item_size != BTRFS_FILE_EXTENT_INLINE_DATA_START +
+- btrfs_file_extent_ram_bytes(leaf, fi)) {
+- CORRUPT("plaintext inline extent has invalid size",
+- leaf, root, slot);
+- return -EUCLEAN;
+- }
+- return 0;
+- }
+-
+- /* Regular or preallocated extent has fixed item size */
+- if (item_size != sizeof(*fi)) {
+- CORRUPT(
+- "regluar or preallocated extent data item size is invalid",
+- leaf, root, slot);
+- return -EUCLEAN;
+- }
+- if (!IS_ALIGNED(btrfs_file_extent_ram_bytes(leaf, fi), sectorsize) ||
+- !IS_ALIGNED(btrfs_file_extent_disk_bytenr(leaf, fi), sectorsize) ||
+- !IS_ALIGNED(btrfs_file_extent_disk_num_bytes(leaf, fi), sectorsize) ||
+- !IS_ALIGNED(btrfs_file_extent_offset(leaf, fi), sectorsize) ||
+- !IS_ALIGNED(btrfs_file_extent_num_bytes(leaf, fi), sectorsize)) {
+- CORRUPT(
+- "regular or preallocated extent data item has unaligned value",
+- leaf, root, slot);
+- return -EUCLEAN;
+- }
+-
+- return 0;
+-}
+-
+-static int check_csum_item(struct btrfs_root *root, struct extent_buffer *leaf,
+- struct btrfs_key *key, int slot)
+-{
+- u32 sectorsize = root->sectorsize;
+- u32 csumsize = btrfs_super_csum_size(root->fs_info->super_copy);
+-
+- if (key->objectid != BTRFS_EXTENT_CSUM_OBJECTID) {
+- CORRUPT("invalid objectid for csum item", leaf, root, slot);
+- return -EUCLEAN;
+- }
+- if (!IS_ALIGNED(key->offset, sectorsize)) {
+- CORRUPT("unaligned key offset for csum item", leaf, root, slot);
+- return -EUCLEAN;
+- }
+- if (!IS_ALIGNED(btrfs_item_size_nr(leaf, slot), csumsize)) {
+- CORRUPT("unaligned csum item size", leaf, root, slot);
+- return -EUCLEAN;
+- }
+- return 0;
+-}
+-
+-/*
+- * Common point to switch the item-specific validation.
+- */
+-static int check_leaf_item(struct btrfs_root *root,
+- struct extent_buffer *leaf,
+- struct btrfs_key *key, int slot)
+-{
+- int ret = 0;
+-
+- switch (key->type) {
+- case BTRFS_EXTENT_DATA_KEY:
+- ret = check_extent_data_item(root, leaf, key, slot);
+- break;
+- case BTRFS_EXTENT_CSUM_KEY:
+- ret = check_csum_item(root, leaf, key, slot);
+- break;
+- }
+- return ret;
+-}
+-
+-static noinline int check_leaf(struct btrfs_root *root,
+- struct extent_buffer *leaf)
+-{
+- /* No valid key type is 0, so all key should be larger than this key */
+- struct btrfs_key prev_key = {0, 0, 0};
+- struct btrfs_key key;
+- u32 nritems = btrfs_header_nritems(leaf);
+- int slot;
+-
+- /*
+- * Extent buffers from a relocation tree have a owner field that
+- * corresponds to the subvolume tree they are based on. So just from an
+- * extent buffer alone we can not find out what is the id of the
+- * corresponding subvolume tree, so we can not figure out if the extent
+- * buffer corresponds to the root of the relocation tree or not. So skip
+- * this check for relocation trees.
+- */
+- if (nritems == 0 && !btrfs_header_flag(leaf, BTRFS_HEADER_FLAG_RELOC)) {
+- struct btrfs_root *check_root;
+-
+- key.objectid = btrfs_header_owner(leaf);
+- key.type = BTRFS_ROOT_ITEM_KEY;
+- key.offset = (u64)-1;
+-
+- check_root = btrfs_get_fs_root(root->fs_info, &key, false);
+- /*
+- * The only reason we also check NULL here is that during
+- * open_ctree() some roots has not yet been set up.
+- */
+- if (!IS_ERR_OR_NULL(check_root)) {
+- struct extent_buffer *eb;
+-
+- eb = btrfs_root_node(check_root);
+- /* if leaf is the root, then it's fine */
+- if (leaf != eb) {
+- CORRUPT("non-root leaf's nritems is 0",
+- leaf, check_root, 0);
+- free_extent_buffer(eb);
+- return -EUCLEAN;
+- }
+- free_extent_buffer(eb);
+- }
+- return 0;
+- }
+-
+- if (nritems == 0)
+- return 0;
+-
+- /*
+- * Check the following things to make sure this is a good leaf, and
+- * leaf users won't need to bother with similar sanity checks:
+- *
+- * 1) key order
+- * 2) item offset and size
+- * No overlap, no hole, all inside the leaf.
+- * 3) item content
+- * If possible, do comprehensive sanity check.
+- * NOTE: All checks must only rely on the item data itself.
+- */
+- for (slot = 0; slot < nritems; slot++) {
+- u32 item_end_expected;
+- int ret;
+-
+- btrfs_item_key_to_cpu(leaf, &key, slot);
+-
+- /* Make sure the keys are in the right order */
+- if (btrfs_comp_cpu_keys(&prev_key, &key) >= 0) {
+- CORRUPT("bad key order", leaf, root, slot);
+- return -EUCLEAN;
+- }
+-
+- /*
+- * Make sure the offset and ends are right, remember that the
+- * item data starts at the end of the leaf and grows towards the
+- * front.
+- */
+- if (slot == 0)
+- item_end_expected = BTRFS_LEAF_DATA_SIZE(root);
+- else
+- item_end_expected = btrfs_item_offset_nr(leaf,
+- slot - 1);
+- if (btrfs_item_end_nr(leaf, slot) != item_end_expected) {
+- CORRUPT("slot offset bad", leaf, root, slot);
+- return -EUCLEAN;
+- }
+-
+- /*
+- * Check to make sure that we don't point outside of the leaf,
+- * just incase all the items are consistent to eachother, but
+- * all point outside of the leaf.
+- */
+- if (btrfs_item_end_nr(leaf, slot) >
+- BTRFS_LEAF_DATA_SIZE(root)) {
+- CORRUPT("slot end outside of leaf", leaf, root, slot);
+- return -EUCLEAN;
+- }
+-
+- /* Also check if the item pointer overlaps with btrfs item. */
+- if (btrfs_item_nr_offset(slot) + sizeof(struct btrfs_item) >
+- btrfs_item_ptr_offset(leaf, slot)) {
+- CORRUPT("slot overlap with its data", leaf, root, slot);
+- return -EUCLEAN;
+- }
+-
+- /* Check if the item size and content meet other criteria */
+- ret = check_leaf_item(root, leaf, &key, slot);
+- if (ret < 0)
+- return ret;
+-
+- prev_key.objectid = key.objectid;
+- prev_key.type = key.type;
+- prev_key.offset = key.offset;
+- }
+-
+- return 0;
+-}
+-
+-static int check_node(struct btrfs_root *root, struct extent_buffer *node)
+-{
+- unsigned long nr = btrfs_header_nritems(node);
+- struct btrfs_key key, next_key;
+- int slot;
+- u64 bytenr;
+- int ret = 0;
+-
+- if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root)) {
+- btrfs_crit(root->fs_info,
+- "corrupt node: block %llu root %llu nritems %lu",
+- node->start, root->objectid, nr);
+- return -EIO;
+- }
+-
+- for (slot = 0; slot < nr - 1; slot++) {
+- bytenr = btrfs_node_blockptr(node, slot);
+- btrfs_node_key_to_cpu(node, &key, slot);
+- btrfs_node_key_to_cpu(node, &next_key, slot + 1);
+-
+- if (!bytenr) {
+- CORRUPT("invalid item slot", node, root, slot);
+- ret = -EIO;
+- goto out;
+- }
+-
+- if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) {
+- CORRUPT("bad key order", node, root, slot);
+- ret = -EIO;
+- goto out;
+- }
+- }
+-out:
+- return ret;
+-}
+-
+ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
+ u64 phy_offset, struct page *page,
+ u64 start, u64 end, int mirror)
+@@ -865,12 +589,12 @@ static int btree_readpage_end_io_hook(st
+ * that we don't try and read the other copies of this block, just
+ * return -EIO.
+ */
+- if (found_level == 0 && check_leaf(root, eb)) {
++ if (found_level == 0 && btrfs_check_leaf(root, eb)) {
+ set_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
+ ret = -EIO;
+ }
+
+- if (found_level > 0 && check_node(root, eb))
++ if (found_level > 0 && btrfs_check_node(root, eb))
+ ret = -EIO;
+
+ if (!ret)
+@@ -4172,7 +3896,7 @@ void btrfs_mark_buffer_dirty(struct exte
+ buf->len,
+ root->fs_info->dirty_metadata_batch);
+ #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
+- if (btrfs_header_level(buf) == 0 && check_leaf(root, buf)) {
++ if (btrfs_header_level(buf) == 0 && btrfs_check_leaf(root, buf)) {
+ btrfs_print_leaf(root, buf);
+ ASSERT(0);
+ }
+--- /dev/null
++++ b/fs/btrfs/tree-checker.c
+@@ -0,0 +1,309 @@
++/*
++ * Copyright (C) Qu Wenruo 2017. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public
++ * License v2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public
++ * License along with this program.
++ */
++
++/*
++ * The module is used to catch unexpected/corrupted tree block data.
++ * Such behavior can be caused either by a fuzzed image or bugs.
++ *
++ * The objective is to do leaf/node validation checks when tree block is read
++ * from disk, and check *every* possible member, so other code won't
++ * need to checking them again.
++ *
++ * Due to the potential and unwanted damage, every checker needs to be
++ * carefully reviewed otherwise so it does not prevent mount of valid images.
++ */
++
++#include "ctree.h"
++#include "tree-checker.h"
++#include "disk-io.h"
++#include "compression.h"
++
++#define CORRUPT(reason, eb, root, slot) \
++ btrfs_crit(root->fs_info, \
++ "corrupt %s, %s: block=%llu, root=%llu, slot=%d", \
++ btrfs_header_level(eb) == 0 ? "leaf" : "node", \
++ reason, btrfs_header_bytenr(eb), root->objectid, slot)
++
++static int check_extent_data_item(struct btrfs_root *root,
++ struct extent_buffer *leaf,
++ struct btrfs_key *key, int slot)
++{
++ struct btrfs_file_extent_item *fi;
++ u32 sectorsize = root->sectorsize;
++ u32 item_size = btrfs_item_size_nr(leaf, slot);
++
++ if (!IS_ALIGNED(key->offset, sectorsize)) {
++ CORRUPT("unaligned key offset for file extent",
++ leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
++
++ if (btrfs_file_extent_type(leaf, fi) > BTRFS_FILE_EXTENT_TYPES) {
++ CORRUPT("invalid file extent type", leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ /*
++ * Support for new compression/encrption must introduce incompat flag,
++ * and must be caught in open_ctree().
++ */
++ if (btrfs_file_extent_compression(leaf, fi) > BTRFS_COMPRESS_TYPES) {
++ CORRUPT("invalid file extent compression", leaf, root, slot);
++ return -EUCLEAN;
++ }
++ if (btrfs_file_extent_encryption(leaf, fi)) {
++ CORRUPT("invalid file extent encryption", leaf, root, slot);
++ return -EUCLEAN;
++ }
++ if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
++ /* Inline extent must have 0 as key offset */
++ if (key->offset) {
++ CORRUPT("inline extent has non-zero key offset",
++ leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ /* Compressed inline extent has no on-disk size, skip it */
++ if (btrfs_file_extent_compression(leaf, fi) !=
++ BTRFS_COMPRESS_NONE)
++ return 0;
++
++ /* Uncompressed inline extent size must match item size */
++ if (item_size != BTRFS_FILE_EXTENT_INLINE_DATA_START +
++ btrfs_file_extent_ram_bytes(leaf, fi)) {
++ CORRUPT("plaintext inline extent has invalid size",
++ leaf, root, slot);
++ return -EUCLEAN;
++ }
++ return 0;
++ }
++
++ /* Regular or preallocated extent has fixed item size */
++ if (item_size != sizeof(*fi)) {
++ CORRUPT(
++ "regluar or preallocated extent data item size is invalid",
++ leaf, root, slot);
++ return -EUCLEAN;
++ }
++ if (!IS_ALIGNED(btrfs_file_extent_ram_bytes(leaf, fi), sectorsize) ||
++ !IS_ALIGNED(btrfs_file_extent_disk_bytenr(leaf, fi), sectorsize) ||
++ !IS_ALIGNED(btrfs_file_extent_disk_num_bytes(leaf, fi), sectorsize) ||
++ !IS_ALIGNED(btrfs_file_extent_offset(leaf, fi), sectorsize) ||
++ !IS_ALIGNED(btrfs_file_extent_num_bytes(leaf, fi), sectorsize)) {
++ CORRUPT(
++ "regular or preallocated extent data item has unaligned value",
++ leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ return 0;
++}
++
++static int check_csum_item(struct btrfs_root *root, struct extent_buffer *leaf,
++ struct btrfs_key *key, int slot)
++{
++ u32 sectorsize = root->sectorsize;
++ u32 csumsize = btrfs_super_csum_size(root->fs_info->super_copy);
++
++ if (key->objectid != BTRFS_EXTENT_CSUM_OBJECTID) {
++ CORRUPT("invalid objectid for csum item", leaf, root, slot);
++ return -EUCLEAN;
++ }
++ if (!IS_ALIGNED(key->offset, sectorsize)) {
++ CORRUPT("unaligned key offset for csum item", leaf, root, slot);
++ return -EUCLEAN;
++ }
++ if (!IS_ALIGNED(btrfs_item_size_nr(leaf, slot), csumsize)) {
++ CORRUPT("unaligned csum item size", leaf, root, slot);
++ return -EUCLEAN;
++ }
++ return 0;
++}
++
++/*
++ * Common point to switch the item-specific validation.
++ */
++static int check_leaf_item(struct btrfs_root *root,
++ struct extent_buffer *leaf,
++ struct btrfs_key *key, int slot)
++{
++ int ret = 0;
++
++ switch (key->type) {
++ case BTRFS_EXTENT_DATA_KEY:
++ ret = check_extent_data_item(root, leaf, key, slot);
++ break;
++ case BTRFS_EXTENT_CSUM_KEY:
++ ret = check_csum_item(root, leaf, key, slot);
++ break;
++ }
++ return ret;
++}
++
++int btrfs_check_leaf(struct btrfs_root *root, struct extent_buffer *leaf)
++{
++ struct btrfs_fs_info *fs_info = root->fs_info;
++ /* No valid key type is 0, so all key should be larger than this key */
++ struct btrfs_key prev_key = {0, 0, 0};
++ struct btrfs_key key;
++ u32 nritems = btrfs_header_nritems(leaf);
++ int slot;
++
++ /*
++ * Extent buffers from a relocation tree have a owner field that
++ * corresponds to the subvolume tree they are based on. So just from an
++ * extent buffer alone we can not find out what is the id of the
++ * corresponding subvolume tree, so we can not figure out if the extent
++ * buffer corresponds to the root of the relocation tree or not. So
++ * skip this check for relocation trees.
++ */
++ if (nritems == 0 && !btrfs_header_flag(leaf, BTRFS_HEADER_FLAG_RELOC)) {
++ struct btrfs_root *check_root;
++
++ key.objectid = btrfs_header_owner(leaf);
++ key.type = BTRFS_ROOT_ITEM_KEY;
++ key.offset = (u64)-1;
++
++ check_root = btrfs_get_fs_root(fs_info, &key, false);
++ /*
++ * The only reason we also check NULL here is that during
++ * open_ctree() some roots has not yet been set up.
++ */
++ if (!IS_ERR_OR_NULL(check_root)) {
++ struct extent_buffer *eb;
++
++ eb = btrfs_root_node(check_root);
++ /* if leaf is the root, then it's fine */
++ if (leaf != eb) {
++ CORRUPT("non-root leaf's nritems is 0",
++ leaf, check_root, 0);
++ free_extent_buffer(eb);
++ return -EUCLEAN;
++ }
++ free_extent_buffer(eb);
++ }
++ return 0;
++ }
++
++ if (nritems == 0)
++ return 0;
++
++ /*
++ * Check the following things to make sure this is a good leaf, and
++ * leaf users won't need to bother with similar sanity checks:
++ *
++ * 1) key ordering
++ * 2) item offset and size
++ * No overlap, no hole, all inside the leaf.
++ * 3) item content
++ * If possible, do comprehensive sanity check.
++ * NOTE: All checks must only rely on the item data itself.
++ */
++ for (slot = 0; slot < nritems; slot++) {
++ u32 item_end_expected;
++ int ret;
++
++ btrfs_item_key_to_cpu(leaf, &key, slot);
++
++ /* Make sure the keys are in the right order */
++ if (btrfs_comp_cpu_keys(&prev_key, &key) >= 0) {
++ CORRUPT("bad key order", leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ /*
++ * Make sure the offset and ends are right, remember that the
++ * item data starts at the end of the leaf and grows towards the
++ * front.
++ */
++ if (slot == 0)
++ item_end_expected = BTRFS_LEAF_DATA_SIZE(root);
++ else
++ item_end_expected = btrfs_item_offset_nr(leaf,
++ slot - 1);
++ if (btrfs_item_end_nr(leaf, slot) != item_end_expected) {
++ CORRUPT("slot offset bad", leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ /*
++ * Check to make sure that we don't point outside of the leaf,
++ * just in case all the items are consistent to each other, but
++ * all point outside of the leaf.
++ */
++ if (btrfs_item_end_nr(leaf, slot) >
++ BTRFS_LEAF_DATA_SIZE(root)) {
++ CORRUPT("slot end outside of leaf", leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ /* Also check if the item pointer overlaps with btrfs item. */
++ if (btrfs_item_nr_offset(slot) + sizeof(struct btrfs_item) >
++ btrfs_item_ptr_offset(leaf, slot)) {
++ CORRUPT("slot overlap with its data", leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ /* Check if the item size and content meet other criteria */
++ ret = check_leaf_item(root, leaf, &key, slot);
++ if (ret < 0)
++ return ret;
++
++ prev_key.objectid = key.objectid;
++ prev_key.type = key.type;
++ prev_key.offset = key.offset;
++ }
++
++ return 0;
++}
++
++int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node)
++{
++ unsigned long nr = btrfs_header_nritems(node);
++ struct btrfs_key key, next_key;
++ int slot;
++ u64 bytenr;
++ int ret = 0;
++
++ if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root)) {
++ btrfs_crit(root->fs_info,
++ "corrupt node: block %llu root %llu nritems %lu",
++ node->start, root->objectid, nr);
++ return -EIO;
++ }
++
++ for (slot = 0; slot < nr - 1; slot++) {
++ bytenr = btrfs_node_blockptr(node, slot);
++ btrfs_node_key_to_cpu(node, &key, slot);
++ btrfs_node_key_to_cpu(node, &next_key, slot + 1);
++
++ if (!bytenr) {
++ CORRUPT("invalid item slot", node, root, slot);
++ ret = -EIO;
++ goto out;
++ }
++
++ if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) {
++ CORRUPT("bad key order", node, root, slot);
++ ret = -EIO;
++ goto out;
++ }
++ }
++out:
++ return ret;
++}
+--- /dev/null
++++ b/fs/btrfs/tree-checker.h
+@@ -0,0 +1,26 @@
++/*
++ * Copyright (C) Qu Wenruo 2017. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public
++ * License v2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public
++ * License along with this program.
++ */
++
++#ifndef __BTRFS_TREE_CHECKER__
++#define __BTRFS_TREE_CHECKER__
++
++#include "ctree.h"
++#include "extent_io.h"
++
++int btrfs_check_leaf(struct btrfs_root *root, struct extent_buffer *leaf);
++int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node);
++
++#endif
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Qu Wenruo <quwenruo.btrfs@gmx.com>
+Date: Wed, 23 Aug 2017 16:57:56 +0900
+Subject: btrfs: Refactor check_leaf function for later expansion
+
+From: Qu Wenruo <quwenruo.btrfs@gmx.com>
+
+commit c3267bbaa9cae09b62960eafe33ad19196803285 upstream.
+
+Current check_leaf() function does a good job checking key order and
+item offset/size.
+
+However it only checks from slot 0 to the last but one slot, this is
+good but makes later expansion hard.
+
+So this refactoring iterates from slot 0 to the last slot.
+For key comparison, it uses a key with all 0 as initial key, so all
+valid keys should be larger than that.
+
+And for item size/offset checks, it compares current item end with
+previous item offset.
+For slot 0, use leaf end as a special case.
+
+This makes later item/key offset checks and item size checks easier to
+be implemented.
+
+Also, makes check_leaf() to return -EUCLEAN other than -EIO to indicate
+error.
+
+Signed-off-by: Qu Wenruo <quwenruo.btrfs@gmx.com>
+Reviewed-by: Nikolay Borisov <nborisov@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+[bwh: Backported to 4.4:
+ - BTRFS_LEAF_DATA_SIZE() takes a root rather than an fs_info
+ - Adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/disk-io.c | 50 +++++++++++++++++++++++++++-----------------------
+ 1 file changed, 27 insertions(+), 23 deletions(-)
+
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -531,8 +531,9 @@ static int check_tree_block_fsid(struct
+ static noinline int check_leaf(struct btrfs_root *root,
+ struct extent_buffer *leaf)
+ {
++ /* No valid key type is 0, so all key should be larger than this key */
++ struct btrfs_key prev_key = {0, 0, 0};
+ struct btrfs_key key;
+- struct btrfs_key leaf_key;
+ u32 nritems = btrfs_header_nritems(leaf);
+ int slot;
+
+@@ -565,7 +566,7 @@ static noinline int check_leaf(struct bt
+ CORRUPT("non-root leaf's nritems is 0",
+ leaf, check_root, 0);
+ free_extent_buffer(eb);
+- return -EIO;
++ return -EUCLEAN;
+ }
+ free_extent_buffer(eb);
+ }
+@@ -575,28 +576,23 @@ static noinline int check_leaf(struct bt
+ if (nritems == 0)
+ return 0;
+
+- /* Check the 0 item */
+- if (btrfs_item_offset_nr(leaf, 0) + btrfs_item_size_nr(leaf, 0) !=
+- BTRFS_LEAF_DATA_SIZE(root)) {
+- CORRUPT("invalid item offset size pair", leaf, root, 0);
+- return -EIO;
+- }
+-
+ /*
+- * Check to make sure each items keys are in the correct order and their
+- * offsets make sense. We only have to loop through nritems-1 because
+- * we check the current slot against the next slot, which verifies the
+- * next slot's offset+size makes sense and that the current's slot
+- * offset is correct.
++ * Check the following things to make sure this is a good leaf, and
++ * leaf users won't need to bother with similar sanity checks:
++ *
++ * 1) key order
++ * 2) item offset and size
++ * No overlap, no hole, all inside the leaf.
+ */
+- for (slot = 0; slot < nritems - 1; slot++) {
+- btrfs_item_key_to_cpu(leaf, &leaf_key, slot);
+- btrfs_item_key_to_cpu(leaf, &key, slot + 1);
++ for (slot = 0; slot < nritems; slot++) {
++ u32 item_end_expected;
++
++ btrfs_item_key_to_cpu(leaf, &key, slot);
+
+ /* Make sure the keys are in the right order */
+- if (btrfs_comp_cpu_keys(&leaf_key, &key) >= 0) {
++ if (btrfs_comp_cpu_keys(&prev_key, &key) >= 0) {
+ CORRUPT("bad key order", leaf, root, slot);
+- return -EIO;
++ return -EUCLEAN;
+ }
+
+ /*
+@@ -604,10 +600,14 @@ static noinline int check_leaf(struct bt
+ * item data starts at the end of the leaf and grows towards the
+ * front.
+ */
+- if (btrfs_item_offset_nr(leaf, slot) !=
+- btrfs_item_end_nr(leaf, slot + 1)) {
++ if (slot == 0)
++ item_end_expected = BTRFS_LEAF_DATA_SIZE(root);
++ else
++ item_end_expected = btrfs_item_offset_nr(leaf,
++ slot - 1);
++ if (btrfs_item_end_nr(leaf, slot) != item_end_expected) {
+ CORRUPT("slot offset bad", leaf, root, slot);
+- return -EIO;
++ return -EUCLEAN;
+ }
+
+ /*
+@@ -618,8 +618,12 @@ static noinline int check_leaf(struct bt
+ if (btrfs_item_end_nr(leaf, slot) >
+ BTRFS_LEAF_DATA_SIZE(root)) {
+ CORRUPT("slot end outside of leaf", leaf, root, slot);
+- return -EIO;
++ return -EUCLEAN;
+ }
++
++ prev_key.objectid = key.objectid;
++ prev_key.type = key.type;
++ prev_key.offset = key.offset;
+ }
+
+ return 0;
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Jeff Mahoney <jeffm@suse.com>
+Date: Wed, 28 Jun 2017 21:56:53 -0600
+Subject: btrfs: struct-funcs, constify readers
+
+From: Jeff Mahoney <jeffm@suse.com>
+
+commit 1cbb1f454e5321e47fc1e6b233066c7ccc979d15 upstream.
+
+We have reader helpers for most of the on-disk structures that use
+an extent_buffer and pointer as offset into the buffer that are
+read-only. We should mark them as const and, in turn, allow consumers
+of these interfaces to mark the buffers const as well.
+
+No impact on code, but serves as documentation that a buffer is intended
+not to be modified.
+
+Signed-off-by: Jeff Mahoney <jeffm@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/ctree.h | 128 ++++++++++++++++++++++++------------------------
+ fs/btrfs/extent_io.c | 24 ++++-----
+ fs/btrfs/extent_io.h | 19 +++----
+ fs/btrfs/struct-funcs.c | 9 +--
+ 4 files changed, 91 insertions(+), 89 deletions(-)
+
+--- a/fs/btrfs/ctree.h
++++ b/fs/btrfs/ctree.h
+@@ -2283,7 +2283,7 @@ do {
+ #define BTRFS_INODE_ROOT_ITEM_INIT (1 << 31)
+
+ struct btrfs_map_token {
+- struct extent_buffer *eb;
++ const struct extent_buffer *eb;
+ char *kaddr;
+ unsigned long offset;
+ };
+@@ -2314,18 +2314,19 @@ static inline void btrfs_init_map_token
+ sizeof(((type *)0)->member)))
+
+ #define DECLARE_BTRFS_SETGET_BITS(bits) \
+-u##bits btrfs_get_token_##bits(struct extent_buffer *eb, void *ptr, \
+- unsigned long off, \
+- struct btrfs_map_token *token); \
+-void btrfs_set_token_##bits(struct extent_buffer *eb, void *ptr, \
++u##bits btrfs_get_token_##bits(const struct extent_buffer *eb, \
++ const void *ptr, unsigned long off, \
++ struct btrfs_map_token *token); \
++void btrfs_set_token_##bits(struct extent_buffer *eb, const void *ptr, \
+ unsigned long off, u##bits val, \
+ struct btrfs_map_token *token); \
+-static inline u##bits btrfs_get_##bits(struct extent_buffer *eb, void *ptr, \
++static inline u##bits btrfs_get_##bits(const struct extent_buffer *eb, \
++ const void *ptr, \
+ unsigned long off) \
+ { \
+ return btrfs_get_token_##bits(eb, ptr, off, NULL); \
+ } \
+-static inline void btrfs_set_##bits(struct extent_buffer *eb, void *ptr, \
++static inline void btrfs_set_##bits(struct extent_buffer *eb, void *ptr,\
+ unsigned long off, u##bits val) \
+ { \
+ btrfs_set_token_##bits(eb, ptr, off, val, NULL); \
+@@ -2337,7 +2338,8 @@ DECLARE_BTRFS_SETGET_BITS(32)
+ DECLARE_BTRFS_SETGET_BITS(64)
+
+ #define BTRFS_SETGET_FUNCS(name, type, member, bits) \
+-static inline u##bits btrfs_##name(struct extent_buffer *eb, type *s) \
++static inline u##bits btrfs_##name(const struct extent_buffer *eb, \
++ const type *s) \
+ { \
+ BUILD_BUG_ON(sizeof(u##bits) != sizeof(((type *)0))->member); \
+ return btrfs_get_##bits(eb, s, offsetof(type, member)); \
+@@ -2348,7 +2350,8 @@ static inline void btrfs_set_##name(stru
+ BUILD_BUG_ON(sizeof(u##bits) != sizeof(((type *)0))->member); \
+ btrfs_set_##bits(eb, s, offsetof(type, member), val); \
+ } \
+-static inline u##bits btrfs_token_##name(struct extent_buffer *eb, type *s, \
++static inline u##bits btrfs_token_##name(const struct extent_buffer *eb,\
++ const type *s, \
+ struct btrfs_map_token *token) \
+ { \
+ BUILD_BUG_ON(sizeof(u##bits) != sizeof(((type *)0))->member); \
+@@ -2363,9 +2366,9 @@ static inline void btrfs_set_token_##nam
+ }
+
+ #define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits) \
+-static inline u##bits btrfs_##name(struct extent_buffer *eb) \
++static inline u##bits btrfs_##name(const struct extent_buffer *eb) \
+ { \
+- type *p = page_address(eb->pages[0]); \
++ const type *p = page_address(eb->pages[0]); \
+ u##bits res = le##bits##_to_cpu(p->member); \
+ return res; \
+ } \
+@@ -2377,7 +2380,7 @@ static inline void btrfs_set_##name(stru
+ }
+
+ #define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits) \
+-static inline u##bits btrfs_##name(type *s) \
++static inline u##bits btrfs_##name(const type *s) \
+ { \
+ return le##bits##_to_cpu(s->member); \
+ } \
+@@ -2678,7 +2681,7 @@ static inline unsigned long btrfs_node_k
+ sizeof(struct btrfs_key_ptr) * nr;
+ }
+
+-void btrfs_node_key(struct extent_buffer *eb,
++void btrfs_node_key(const struct extent_buffer *eb,
+ struct btrfs_disk_key *disk_key, int nr);
+
+ static inline void btrfs_set_node_key(struct extent_buffer *eb,
+@@ -2707,28 +2710,28 @@ static inline struct btrfs_item *btrfs_i
+ return (struct btrfs_item *)btrfs_item_nr_offset(nr);
+ }
+
+-static inline u32 btrfs_item_end(struct extent_buffer *eb,
++static inline u32 btrfs_item_end(const struct extent_buffer *eb,
+ struct btrfs_item *item)
+ {
+ return btrfs_item_offset(eb, item) + btrfs_item_size(eb, item);
+ }
+
+-static inline u32 btrfs_item_end_nr(struct extent_buffer *eb, int nr)
++static inline u32 btrfs_item_end_nr(const struct extent_buffer *eb, int nr)
+ {
+ return btrfs_item_end(eb, btrfs_item_nr(nr));
+ }
+
+-static inline u32 btrfs_item_offset_nr(struct extent_buffer *eb, int nr)
++static inline u32 btrfs_item_offset_nr(const struct extent_buffer *eb, int nr)
+ {
+ return btrfs_item_offset(eb, btrfs_item_nr(nr));
+ }
+
+-static inline u32 btrfs_item_size_nr(struct extent_buffer *eb, int nr)
++static inline u32 btrfs_item_size_nr(const struct extent_buffer *eb, int nr)
+ {
+ return btrfs_item_size(eb, btrfs_item_nr(nr));
+ }
+
+-static inline void btrfs_item_key(struct extent_buffer *eb,
++static inline void btrfs_item_key(const struct extent_buffer *eb,
+ struct btrfs_disk_key *disk_key, int nr)
+ {
+ struct btrfs_item *item = btrfs_item_nr(nr);
+@@ -2764,8 +2767,8 @@ BTRFS_SETGET_STACK_FUNCS(stack_dir_name_
+ BTRFS_SETGET_STACK_FUNCS(stack_dir_transid, struct btrfs_dir_item,
+ transid, 64);
+
+-static inline void btrfs_dir_item_key(struct extent_buffer *eb,
+- struct btrfs_dir_item *item,
++static inline void btrfs_dir_item_key(const struct extent_buffer *eb,
++ const struct btrfs_dir_item *item,
+ struct btrfs_disk_key *key)
+ {
+ read_eb_member(eb, item, struct btrfs_dir_item, location, key);
+@@ -2773,7 +2776,7 @@ static inline void btrfs_dir_item_key(st
+
+ static inline void btrfs_set_dir_item_key(struct extent_buffer *eb,
+ struct btrfs_dir_item *item,
+- struct btrfs_disk_key *key)
++ const struct btrfs_disk_key *key)
+ {
+ write_eb_member(eb, item, struct btrfs_dir_item, location, key);
+ }
+@@ -2785,8 +2788,8 @@ BTRFS_SETGET_FUNCS(free_space_bitmaps, s
+ BTRFS_SETGET_FUNCS(free_space_generation, struct btrfs_free_space_header,
+ generation, 64);
+
+-static inline void btrfs_free_space_key(struct extent_buffer *eb,
+- struct btrfs_free_space_header *h,
++static inline void btrfs_free_space_key(const struct extent_buffer *eb,
++ const struct btrfs_free_space_header *h,
+ struct btrfs_disk_key *key)
+ {
+ read_eb_member(eb, h, struct btrfs_free_space_header, location, key);
+@@ -2794,7 +2797,7 @@ static inline void btrfs_free_space_key(
+
+ static inline void btrfs_set_free_space_key(struct extent_buffer *eb,
+ struct btrfs_free_space_header *h,
+- struct btrfs_disk_key *key)
++ const struct btrfs_disk_key *key)
+ {
+ write_eb_member(eb, h, struct btrfs_free_space_header, location, key);
+ }
+@@ -2821,25 +2824,25 @@ static inline void btrfs_cpu_key_to_disk
+ disk->objectid = cpu_to_le64(cpu->objectid);
+ }
+
+-static inline void btrfs_node_key_to_cpu(struct extent_buffer *eb,
+- struct btrfs_key *key, int nr)
++static inline void btrfs_node_key_to_cpu(const struct extent_buffer *eb,
++ struct btrfs_key *key, int nr)
+ {
+ struct btrfs_disk_key disk_key;
+ btrfs_node_key(eb, &disk_key, nr);
+ btrfs_disk_key_to_cpu(key, &disk_key);
+ }
+
+-static inline void btrfs_item_key_to_cpu(struct extent_buffer *eb,
+- struct btrfs_key *key, int nr)
++static inline void btrfs_item_key_to_cpu(const struct extent_buffer *eb,
++ struct btrfs_key *key, int nr)
+ {
+ struct btrfs_disk_key disk_key;
+ btrfs_item_key(eb, &disk_key, nr);
+ btrfs_disk_key_to_cpu(key, &disk_key);
+ }
+
+-static inline void btrfs_dir_item_key_to_cpu(struct extent_buffer *eb,
+- struct btrfs_dir_item *item,
+- struct btrfs_key *key)
++static inline void btrfs_dir_item_key_to_cpu(const struct extent_buffer *eb,
++ const struct btrfs_dir_item *item,
++ struct btrfs_key *key)
+ {
+ struct btrfs_disk_key disk_key;
+ btrfs_dir_item_key(eb, item, &disk_key);
+@@ -2872,7 +2875,7 @@ BTRFS_SETGET_STACK_FUNCS(stack_header_nr
+ nritems, 32);
+ BTRFS_SETGET_STACK_FUNCS(stack_header_bytenr, struct btrfs_header, bytenr, 64);
+
+-static inline int btrfs_header_flag(struct extent_buffer *eb, u64 flag)
++static inline int btrfs_header_flag(const struct extent_buffer *eb, u64 flag)
+ {
+ return (btrfs_header_flags(eb) & flag) == flag;
+ }
+@@ -2891,7 +2894,7 @@ static inline int btrfs_clear_header_fla
+ return (flags & flag) == flag;
+ }
+
+-static inline int btrfs_header_backref_rev(struct extent_buffer *eb)
++static inline int btrfs_header_backref_rev(const struct extent_buffer *eb)
+ {
+ u64 flags = btrfs_header_flags(eb);
+ return flags >> BTRFS_BACKREF_REV_SHIFT;
+@@ -2911,12 +2914,12 @@ static inline unsigned long btrfs_header
+ return offsetof(struct btrfs_header, fsid);
+ }
+
+-static inline unsigned long btrfs_header_chunk_tree_uuid(struct extent_buffer *eb)
++static inline unsigned long btrfs_header_chunk_tree_uuid(const struct extent_buffer *eb)
+ {
+ return offsetof(struct btrfs_header, chunk_tree_uuid);
+ }
+
+-static inline int btrfs_is_leaf(struct extent_buffer *eb)
++static inline int btrfs_is_leaf(const struct extent_buffer *eb)
+ {
+ return btrfs_header_level(eb) == 0;
+ }
+@@ -2950,12 +2953,12 @@ BTRFS_SETGET_STACK_FUNCS(root_stransid,
+ BTRFS_SETGET_STACK_FUNCS(root_rtransid, struct btrfs_root_item,
+ rtransid, 64);
+
+-static inline bool btrfs_root_readonly(struct btrfs_root *root)
++static inline bool btrfs_root_readonly(const struct btrfs_root *root)
+ {
+ return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_RDONLY)) != 0;
+ }
+
+-static inline bool btrfs_root_dead(struct btrfs_root *root)
++static inline bool btrfs_root_dead(const struct btrfs_root *root)
+ {
+ return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_DEAD)) != 0;
+ }
+@@ -3012,51 +3015,51 @@ BTRFS_SETGET_STACK_FUNCS(backup_num_devi
+ /* struct btrfs_balance_item */
+ BTRFS_SETGET_FUNCS(balance_flags, struct btrfs_balance_item, flags, 64);
+
+-static inline void btrfs_balance_data(struct extent_buffer *eb,
+- struct btrfs_balance_item *bi,
++static inline void btrfs_balance_data(const struct extent_buffer *eb,
++ const struct btrfs_balance_item *bi,
+ struct btrfs_disk_balance_args *ba)
+ {
+ read_eb_member(eb, bi, struct btrfs_balance_item, data, ba);
+ }
+
+ static inline void btrfs_set_balance_data(struct extent_buffer *eb,
+- struct btrfs_balance_item *bi,
+- struct btrfs_disk_balance_args *ba)
++ struct btrfs_balance_item *bi,
++ const struct btrfs_disk_balance_args *ba)
+ {
+ write_eb_member(eb, bi, struct btrfs_balance_item, data, ba);
+ }
+
+-static inline void btrfs_balance_meta(struct extent_buffer *eb,
+- struct btrfs_balance_item *bi,
++static inline void btrfs_balance_meta(const struct extent_buffer *eb,
++ const struct btrfs_balance_item *bi,
+ struct btrfs_disk_balance_args *ba)
+ {
+ read_eb_member(eb, bi, struct btrfs_balance_item, meta, ba);
+ }
+
+ static inline void btrfs_set_balance_meta(struct extent_buffer *eb,
+- struct btrfs_balance_item *bi,
+- struct btrfs_disk_balance_args *ba)
++ struct btrfs_balance_item *bi,
++ const struct btrfs_disk_balance_args *ba)
+ {
+ write_eb_member(eb, bi, struct btrfs_balance_item, meta, ba);
+ }
+
+-static inline void btrfs_balance_sys(struct extent_buffer *eb,
+- struct btrfs_balance_item *bi,
++static inline void btrfs_balance_sys(const struct extent_buffer *eb,
++ const struct btrfs_balance_item *bi,
+ struct btrfs_disk_balance_args *ba)
+ {
+ read_eb_member(eb, bi, struct btrfs_balance_item, sys, ba);
+ }
+
+ static inline void btrfs_set_balance_sys(struct extent_buffer *eb,
+- struct btrfs_balance_item *bi,
+- struct btrfs_disk_balance_args *ba)
++ struct btrfs_balance_item *bi,
++ const struct btrfs_disk_balance_args *ba)
+ {
+ write_eb_member(eb, bi, struct btrfs_balance_item, sys, ba);
+ }
+
+ static inline void
+ btrfs_disk_balance_args_to_cpu(struct btrfs_balance_args *cpu,
+- struct btrfs_disk_balance_args *disk)
++ const struct btrfs_disk_balance_args *disk)
+ {
+ memset(cpu, 0, sizeof(*cpu));
+
+@@ -3076,7 +3079,7 @@ btrfs_disk_balance_args_to_cpu(struct bt
+
+ static inline void
+ btrfs_cpu_balance_args_to_disk(struct btrfs_disk_balance_args *disk,
+- struct btrfs_balance_args *cpu)
++ const struct btrfs_balance_args *cpu)
+ {
+ memset(disk, 0, sizeof(*disk));
+
+@@ -3144,7 +3147,7 @@ BTRFS_SETGET_STACK_FUNCS(super_magic, st
+ BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,
+ uuid_tree_generation, 64);
+
+-static inline int btrfs_super_csum_size(struct btrfs_super_block *s)
++static inline int btrfs_super_csum_size(const struct btrfs_super_block *s)
+ {
+ u16 t = btrfs_super_csum_type(s);
+ /*
+@@ -3163,8 +3166,8 @@ static inline unsigned long btrfs_leaf_d
+ * this returns the address of the start of the last item,
+ * which is the stop of the leaf data stack
+ */
+-static inline unsigned int leaf_data_end(struct btrfs_root *root,
+- struct extent_buffer *leaf)
++static inline unsigned int leaf_data_end(const struct btrfs_root *root,
++ const struct extent_buffer *leaf)
+ {
+ u32 nr = btrfs_header_nritems(leaf);
+
+@@ -3189,7 +3192,7 @@ BTRFS_SETGET_STACK_FUNCS(stack_file_exte
+ struct btrfs_file_extent_item, compression, 8);
+
+ static inline unsigned long
+-btrfs_file_extent_inline_start(struct btrfs_file_extent_item *e)
++btrfs_file_extent_inline_start(const struct btrfs_file_extent_item *e)
+ {
+ return (unsigned long)e + BTRFS_FILE_EXTENT_INLINE_DATA_START;
+ }
+@@ -3223,8 +3226,9 @@ BTRFS_SETGET_FUNCS(file_extent_other_enc
+ * size of any extent headers. If a file is compressed on disk, this is
+ * the compressed size
+ */
+-static inline u32 btrfs_file_extent_inline_item_len(struct extent_buffer *eb,
+- struct btrfs_item *e)
++static inline u32 btrfs_file_extent_inline_item_len(
++ const struct extent_buffer *eb,
++ struct btrfs_item *e)
+ {
+ return btrfs_item_size(eb, e) - BTRFS_FILE_EXTENT_INLINE_DATA_START;
+ }
+@@ -3232,9 +3236,9 @@ static inline u32 btrfs_file_extent_inli
+ /* this returns the number of file bytes represented by the inline item.
+ * If an item is compressed, this is the uncompressed size
+ */
+-static inline u32 btrfs_file_extent_inline_len(struct extent_buffer *eb,
+- int slot,
+- struct btrfs_file_extent_item *fi)
++static inline u32 btrfs_file_extent_inline_len(const struct extent_buffer *eb,
++ int slot,
++ const struct btrfs_file_extent_item *fi)
+ {
+ struct btrfs_map_token token;
+
+@@ -3256,8 +3260,8 @@ static inline u32 btrfs_file_extent_inli
+
+
+ /* btrfs_dev_stats_item */
+-static inline u64 btrfs_dev_stats_value(struct extent_buffer *eb,
+- struct btrfs_dev_stats_item *ptr,
++static inline u64 btrfs_dev_stats_value(const struct extent_buffer *eb,
++ const struct btrfs_dev_stats_item *ptr,
+ int index)
+ {
+ u64 val;
+--- a/fs/btrfs/extent_io.c
++++ b/fs/btrfs/extent_io.c
+@@ -5381,9 +5381,8 @@ unlock_exit:
+ return ret;
+ }
+
+-void read_extent_buffer(struct extent_buffer *eb, void *dstv,
+- unsigned long start,
+- unsigned long len)
++void read_extent_buffer(const struct extent_buffer *eb, void *dstv,
++ unsigned long start, unsigned long len)
+ {
+ size_t cur;
+ size_t offset;
+@@ -5412,9 +5411,9 @@ void read_extent_buffer(struct extent_bu
+ }
+ }
+
+-int read_extent_buffer_to_user(struct extent_buffer *eb, void __user *dstv,
+- unsigned long start,
+- unsigned long len)
++int read_extent_buffer_to_user(const struct extent_buffer *eb,
++ void __user *dstv,
++ unsigned long start, unsigned long len)
+ {
+ size_t cur;
+ size_t offset;
+@@ -5449,10 +5448,10 @@ int read_extent_buffer_to_user(struct ex
+ return ret;
+ }
+
+-int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start,
+- unsigned long min_len, char **map,
+- unsigned long *map_start,
+- unsigned long *map_len)
++int map_private_extent_buffer(const struct extent_buffer *eb,
++ unsigned long start, unsigned long min_len,
++ char **map, unsigned long *map_start,
++ unsigned long *map_len)
+ {
+ size_t offset = start & (PAGE_CACHE_SIZE - 1);
+ char *kaddr;
+@@ -5487,9 +5486,8 @@ int map_private_extent_buffer(struct ext
+ return 0;
+ }
+
+-int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv,
+- unsigned long start,
+- unsigned long len)
++int memcmp_extent_buffer(const struct extent_buffer *eb, const void *ptrv,
++ unsigned long start, unsigned long len)
+ {
+ size_t cur;
+ size_t offset;
+--- a/fs/btrfs/extent_io.h
++++ b/fs/btrfs/extent_io.h
+@@ -308,14 +308,13 @@ static inline void extent_buffer_get(str
+ atomic_inc(&eb->refs);
+ }
+
+-int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv,
+- unsigned long start,
+- unsigned long len);
+-void read_extent_buffer(struct extent_buffer *eb, void *dst,
++int memcmp_extent_buffer(const struct extent_buffer *eb, const void *ptrv,
++ unsigned long start, unsigned long len);
++void read_extent_buffer(const struct extent_buffer *eb, void *dst,
+ unsigned long start,
+ unsigned long len);
+-int read_extent_buffer_to_user(struct extent_buffer *eb, void __user *dst,
+- unsigned long start,
++int read_extent_buffer_to_user(const struct extent_buffer *eb,
++ void __user *dst, unsigned long start,
+ unsigned long len);
+ void write_extent_buffer(struct extent_buffer *eb, const void *src,
+ unsigned long start, unsigned long len);
+@@ -334,10 +333,10 @@ int set_extent_buffer_uptodate(struct ex
+ int clear_extent_buffer_uptodate(struct extent_buffer *eb);
+ int extent_buffer_uptodate(struct extent_buffer *eb);
+ int extent_buffer_under_io(struct extent_buffer *eb);
+-int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset,
+- unsigned long min_len, char **map,
+- unsigned long *map_start,
+- unsigned long *map_len);
++int map_private_extent_buffer(const struct extent_buffer *eb,
++ unsigned long offset, unsigned long min_len,
++ char **map, unsigned long *map_start,
++ unsigned long *map_len);
+ int extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end);
+ int extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end);
+ int extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,
+--- a/fs/btrfs/struct-funcs.c
++++ b/fs/btrfs/struct-funcs.c
+@@ -50,8 +50,8 @@ static inline void put_unaligned_le8(u8
+ */
+
+ #define DEFINE_BTRFS_SETGET_BITS(bits) \
+-u##bits btrfs_get_token_##bits(struct extent_buffer *eb, void *ptr, \
+- unsigned long off, \
++u##bits btrfs_get_token_##bits(const struct extent_buffer *eb, \
++ const void *ptr, unsigned long off, \
+ struct btrfs_map_token *token) \
+ { \
+ unsigned long part_offset = (unsigned long)ptr; \
+@@ -90,7 +90,8 @@ u##bits btrfs_get_token_##bits(struct ex
+ return res; \
+ } \
+ void btrfs_set_token_##bits(struct extent_buffer *eb, \
+- void *ptr, unsigned long off, u##bits val, \
++ const void *ptr, unsigned long off, \
++ u##bits val, \
+ struct btrfs_map_token *token) \
+ { \
+ unsigned long part_offset = (unsigned long)ptr; \
+@@ -133,7 +134,7 @@ DEFINE_BTRFS_SETGET_BITS(16)
+ DEFINE_BTRFS_SETGET_BITS(32)
+ DEFINE_BTRFS_SETGET_BITS(64)
+
+-void btrfs_node_key(struct extent_buffer *eb,
++void btrfs_node_key(const struct extent_buffer *eb,
+ struct btrfs_disk_key *disk_key, int nr)
+ {
+ unsigned long ptr = btrfs_node_key_ptr_offset(nr);
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: David Sterba <dsterba@suse.com>
+Date: Wed, 10 Jan 2018 15:13:07 +0100
+Subject: btrfs: tree-check: reduce stack consumption in check_dir_item
+
+From: David Sterba <dsterba@suse.com>
+
+commit e2683fc9d219430f5b78889b50cde7f40efeba7b upstream.
+
+I've noticed that the updated item checker stack consumption increased
+dramatically in 542f5385e20cf97447 ("btrfs: tree-checker: Add checker
+for dir item")
+
+tree-checker.c:check_leaf +552 (176 -> 728)
+
+The array is 255 bytes long, dynamic allocation would slow down the
+sanity checks so it's more reasonable to keep it on-stack. Moving the
+variable to the scope of use reduces the stack usage again
+
+tree-checker.c:check_leaf -264 (728 -> 464)
+
+Reviewed-by: Josef Bacik <jbacik@fb.com>
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/tree-checker.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -212,7 +212,6 @@ static int check_dir_item(struct btrfs_r
+
+ di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
+ while (cur < item_size) {
+- char namebuf[max(BTRFS_NAME_LEN, XATTR_NAME_MAX)];
+ u32 name_len;
+ u32 data_len;
+ u32 max_name_len;
+@@ -295,6 +294,8 @@ static int check_dir_item(struct btrfs_r
+ */
+ if (key->type == BTRFS_DIR_ITEM_KEY ||
+ key->type == BTRFS_XATTR_ITEM_KEY) {
++ char namebuf[max(BTRFS_NAME_LEN, XATTR_NAME_MAX)];
++
+ read_extent_buffer(leaf, namebuf,
+ (unsigned long)(di + 1), name_len);
+ name_hash = btrfs_name_hash(namebuf, name_len);
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Qu Wenruo <wqu@suse.com>
+Date: Wed, 8 Nov 2017 08:54:25 +0800
+Subject: btrfs: tree-checker: Add checker for dir item
+
+From: Qu Wenruo <wqu@suse.com>
+
+commit ad7b0368f33cffe67fecd302028915926e50ef7e upstream.
+
+Add checker for dir item, for key types DIR_ITEM, DIR_INDEX and
+XATTR_ITEM.
+
+This checker does comprehensive checks for:
+
+1) dir_item header and its data size
+ Against item boundary and maximum name/xattr length.
+ This part is mostly the same as old verify_dir_item().
+
+2) dir_type
+ Against maximum file types, and against key type.
+ Since XATTR key should only have FT_XATTR dir item, and normal dir
+ item type should not have XATTR key.
+
+ The check between key->type and dir_type is newly introduced by this
+ patch.
+
+3) name hash
+ For XATTR and DIR_ITEM key, key->offset is name hash (crc32c).
+ Check the hash of the name against the key to ensure it's correct.
+
+ The name hash check is only found in btrfs-progs before this patch.
+
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: Nikolay Borisov <nborisov@suse.com>
+Reviewed-by: Su Yue <suy.fnst@cn.fujitsu.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+[bwh: Backported to 4.4: BTRFS_MAX_XATTR_SIZE() takes a root instead of an
+ fs_info, and yields a value of type size_t instead of unsigned int]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/tree-checker.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 141 insertions(+)
+
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -30,6 +30,7 @@
+ #include "tree-checker.h"
+ #include "disk-io.h"
+ #include "compression.h"
++#include "hash.h"
+
+ #define CORRUPT(reason, eb, root, slot) \
+ btrfs_crit(root->fs_info, \
+@@ -176,6 +177,141 @@ static int check_csum_item(struct btrfs_
+ }
+
+ /*
++ * Customized reported for dir_item, only important new info is key->objectid,
++ * which represents inode number
++ */
++__printf(4, 5)
++static void dir_item_err(const struct btrfs_root *root,
++ const struct extent_buffer *eb, int slot,
++ const char *fmt, ...)
++{
++ struct btrfs_key key;
++ struct va_format vaf;
++ va_list args;
++
++ btrfs_item_key_to_cpu(eb, &key, slot);
++ va_start(args, fmt);
++
++ vaf.fmt = fmt;
++ vaf.va = &args;
++
++ btrfs_crit(root->fs_info,
++ "corrupt %s: root=%llu block=%llu slot=%d ino=%llu, %pV",
++ btrfs_header_level(eb) == 0 ? "leaf" : "node", root->objectid,
++ btrfs_header_bytenr(eb), slot, key.objectid, &vaf);
++ va_end(args);
++}
++
++static int check_dir_item(struct btrfs_root *root,
++ struct extent_buffer *leaf,
++ struct btrfs_key *key, int slot)
++{
++ struct btrfs_dir_item *di;
++ u32 item_size = btrfs_item_size_nr(leaf, slot);
++ u32 cur = 0;
++
++ di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
++ while (cur < item_size) {
++ char namebuf[max(BTRFS_NAME_LEN, XATTR_NAME_MAX)];
++ u32 name_len;
++ u32 data_len;
++ u32 max_name_len;
++ u32 total_size;
++ u32 name_hash;
++ u8 dir_type;
++
++ /* header itself should not cross item boundary */
++ if (cur + sizeof(*di) > item_size) {
++ dir_item_err(root, leaf, slot,
++ "dir item header crosses item boundary, have %lu boundary %u",
++ cur + sizeof(*di), item_size);
++ return -EUCLEAN;
++ }
++
++ /* dir type check */
++ dir_type = btrfs_dir_type(leaf, di);
++ if (dir_type >= BTRFS_FT_MAX) {
++ dir_item_err(root, leaf, slot,
++ "invalid dir item type, have %u expect [0, %u)",
++ dir_type, BTRFS_FT_MAX);
++ return -EUCLEAN;
++ }
++
++ if (key->type == BTRFS_XATTR_ITEM_KEY &&
++ dir_type != BTRFS_FT_XATTR) {
++ dir_item_err(root, leaf, slot,
++ "invalid dir item type for XATTR key, have %u expect %u",
++ dir_type, BTRFS_FT_XATTR);
++ return -EUCLEAN;
++ }
++ if (dir_type == BTRFS_FT_XATTR &&
++ key->type != BTRFS_XATTR_ITEM_KEY) {
++ dir_item_err(root, leaf, slot,
++ "xattr dir type found for non-XATTR key");
++ return -EUCLEAN;
++ }
++ if (dir_type == BTRFS_FT_XATTR)
++ max_name_len = XATTR_NAME_MAX;
++ else
++ max_name_len = BTRFS_NAME_LEN;
++
++ /* Name/data length check */
++ name_len = btrfs_dir_name_len(leaf, di);
++ data_len = btrfs_dir_data_len(leaf, di);
++ if (name_len > max_name_len) {
++ dir_item_err(root, leaf, slot,
++ "dir item name len too long, have %u max %u",
++ name_len, max_name_len);
++ return -EUCLEAN;
++ }
++ if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(root)) {
++ dir_item_err(root, leaf, slot,
++ "dir item name and data len too long, have %u max %zu",
++ name_len + data_len,
++ BTRFS_MAX_XATTR_SIZE(root));
++ return -EUCLEAN;
++ }
++
++ if (data_len && dir_type != BTRFS_FT_XATTR) {
++ dir_item_err(root, leaf, slot,
++ "dir item with invalid data len, have %u expect 0",
++ data_len);
++ return -EUCLEAN;
++ }
++
++ total_size = sizeof(*di) + name_len + data_len;
++
++ /* header and name/data should not cross item boundary */
++ if (cur + total_size > item_size) {
++ dir_item_err(root, leaf, slot,
++ "dir item data crosses item boundary, have %u boundary %u",
++ cur + total_size, item_size);
++ return -EUCLEAN;
++ }
++
++ /*
++ * Special check for XATTR/DIR_ITEM, as key->offset is name
++ * hash, should match its name
++ */
++ if (key->type == BTRFS_DIR_ITEM_KEY ||
++ key->type == BTRFS_XATTR_ITEM_KEY) {
++ read_extent_buffer(leaf, namebuf,
++ (unsigned long)(di + 1), name_len);
++ name_hash = btrfs_name_hash(namebuf, name_len);
++ if (key->offset != name_hash) {
++ dir_item_err(root, leaf, slot,
++ "name hash mismatch with key, have 0x%016x expect 0x%016llx",
++ name_hash, key->offset);
++ return -EUCLEAN;
++ }
++ }
++ cur += total_size;
++ di = (struct btrfs_dir_item *)((void *)di + total_size);
++ }
++ return 0;
++}
++
++/*
+ * Common point to switch the item-specific validation.
+ */
+ static int check_leaf_item(struct btrfs_root *root,
+@@ -191,6 +327,11 @@ static int check_leaf_item(struct btrfs_
+ case BTRFS_EXTENT_CSUM_KEY:
+ ret = check_csum_item(root, leaf, key, slot);
+ break;
++ case BTRFS_DIR_ITEM_KEY:
++ case BTRFS_DIR_INDEX_KEY:
++ case BTRFS_XATTR_ITEM_KEY:
++ ret = check_dir_item(root, leaf, key, slot);
++ break;
+ }
+ return ret;
+ }
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Qu Wenruo <wqu@suse.com>
+Date: Fri, 28 Sep 2018 07:59:34 +0800
+Subject: btrfs: tree-checker: Check level for leaves and nodes
+
+From: Qu Wenruo <wqu@suse.com>
+
+commit f556faa46eb4e96d0d0772e74ecf66781e132f72 upstream.
+
+Although we have tree level check at tree read runtime, it's completely
+based on its parent level.
+We still need to do accurate level check to avoid invalid tree blocks
+sneak into kernel space.
+
+The check itself is simple, for leaf its level should always be 0.
+For nodes its level should be in range [1, BTRFS_MAX_LEVEL - 1].
+
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: Su Yue <suy.fnst@cn.fujitsu.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+[bwh: Backported to 4.4:
+ - Pass root instead of fs_info to generic_err()
+ - Adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/tree-checker.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -447,6 +447,13 @@ static int check_leaf(struct btrfs_root
+ u32 nritems = btrfs_header_nritems(leaf);
+ int slot;
+
++ if (btrfs_header_level(leaf) != 0) {
++ generic_err(root, leaf, 0,
++ "invalid level for leaf, have %d expect 0",
++ btrfs_header_level(leaf));
++ return -EUCLEAN;
++ }
++
+ /*
+ * Extent buffers from a relocation tree have a owner field that
+ * corresponds to the subvolume tree they are based on. So just from an
+@@ -589,9 +596,16 @@ int btrfs_check_node(struct btrfs_root *
+ unsigned long nr = btrfs_header_nritems(node);
+ struct btrfs_key key, next_key;
+ int slot;
++ int level = btrfs_header_level(node);
+ u64 bytenr;
+ int ret = 0;
+
++ if (level <= 0 || level >= BTRFS_MAX_LEVEL) {
++ generic_err(root, node, 0,
++ "invalid level for node, have %d expect [1, %d]",
++ level, BTRFS_MAX_LEVEL - 1);
++ return -EUCLEAN;
++ }
+ if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root)) {
+ btrfs_crit(root->fs_info,
+ "corrupt node: root=%llu block=%llu, nritems too %s, have %lu expect range [1,%zu]",
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Qu Wenruo <wqu@suse.com>
+Date: Tue, 3 Jul 2018 17:10:06 +0800
+Subject: btrfs: tree-checker: Detect invalid and empty essential trees
+
+From: Qu Wenruo <wqu@suse.com>
+
+commit ba480dd4db9f1798541eb2d1c423fc95feee8d36 upstream.
+
+A crafted image has empty root tree block, which will later cause NULL
+pointer dereference.
+
+The following trees should never be empty:
+1) Tree root
+ Must contain at least root items for extent tree, device tree and fs
+ tree
+
+2) Chunk tree
+ Or we can't even bootstrap as it contains the mapping.
+
+3) Fs tree
+ At least inode item for top level inode (.).
+
+4) Device tree
+ Dev extents for chunks
+
+5) Extent tree
+ Must have corresponding extent for each chunk.
+
+If any of them is empty, we are sure the fs is corrupted and no need to
+mount it.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=199847
+Reported-by: Xu Wen <wen.xu@gatech.edu>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Tested-by: Gu Jinxiang <gujx@cn.fujitsu.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+[bwh: Backported to 4.4: Pass root instead of fs_info to generic_err()]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/tree-checker.c | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -456,9 +456,22 @@ static int check_leaf(struct btrfs_root
+ * skip this check for relocation trees.
+ */
+ if (nritems == 0 && !btrfs_header_flag(leaf, BTRFS_HEADER_FLAG_RELOC)) {
++ u64 owner = btrfs_header_owner(leaf);
+ struct btrfs_root *check_root;
+
+- key.objectid = btrfs_header_owner(leaf);
++ /* These trees must never be empty */
++ if (owner == BTRFS_ROOT_TREE_OBJECTID ||
++ owner == BTRFS_CHUNK_TREE_OBJECTID ||
++ owner == BTRFS_EXTENT_TREE_OBJECTID ||
++ owner == BTRFS_DEV_TREE_OBJECTID ||
++ owner == BTRFS_FS_TREE_OBJECTID ||
++ owner == BTRFS_DATA_RELOC_TREE_OBJECTID) {
++ generic_err(root, leaf, 0,
++ "invalid root, root %llu must never be empty",
++ owner);
++ return -EUCLEAN;
++ }
++ key.objectid = owner;
+ key.type = BTRFS_ROOT_ITEM_KEY;
+ key.offset = (u64)-1;
+
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Qu Wenruo <quwenruo.btrfs@gmx.com>
+Date: Mon, 9 Oct 2017 01:51:03 +0000
+Subject: btrfs: tree-checker: Enhance btrfs_check_node output
+
+From: Qu Wenruo <quwenruo.btrfs@gmx.com>
+
+commit bba4f29896c986c4cec17bc0f19f2ce644fceae1 upstream.
+
+Use inline function to replace macro since we don't need
+stringification.
+(Macro still exists until all callers get updated)
+
+And add more info about the error, and replace EIO with EUCLEAN.
+
+For nr_items error, report if it's too large or too small, and output
+the valid value range.
+
+For node block pointer, added a new alignment checker.
+
+For key order, also output the next key to make the problem more
+obvious.
+
+Signed-off-by: Qu Wenruo <quwenruo.btrfs@gmx.com>
+[ wording adjustments, unindented long strings ]
+Signed-off-by: David Sterba <dsterba@suse.com>
+[bwh: Backported to 4.4:
+ - Use root->sectorsize instead of root->fs_info->sectorsize
+ - BTRFS_NODEPTRS_PER_BLOCK() takes a root instead of an fs_info, and yields
+ a value of type size_t instead of unsigned int]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/tree-checker.c | 68 +++++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 61 insertions(+), 7 deletions(-)
+
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -37,6 +37,46 @@
+ btrfs_header_level(eb) == 0 ? "leaf" : "node", \
+ reason, btrfs_header_bytenr(eb), root->objectid, slot)
+
++/*
++ * Error message should follow the following format:
++ * corrupt <type>: <identifier>, <reason>[, <bad_value>]
++ *
++ * @type: leaf or node
++ * @identifier: the necessary info to locate the leaf/node.
++ * It's recommened to decode key.objecitd/offset if it's
++ * meaningful.
++ * @reason: describe the error
++ * @bad_value: optional, it's recommened to output bad value and its
++ * expected value (range).
++ *
++ * Since comma is used to separate the components, only space is allowed
++ * inside each component.
++ */
++
++/*
++ * Append generic "corrupt leaf/node root=%llu block=%llu slot=%d: " to @fmt.
++ * Allows callers to customize the output.
++ */
++__printf(4, 5)
++static void generic_err(const struct btrfs_root *root,
++ const struct extent_buffer *eb, int slot,
++ const char *fmt, ...)
++{
++ struct va_format vaf;
++ va_list args;
++
++ va_start(args, fmt);
++
++ vaf.fmt = fmt;
++ vaf.va = &args;
++
++ btrfs_crit(root->fs_info,
++ "corrupt %s: root=%llu block=%llu slot=%d, %pV",
++ btrfs_header_level(eb) == 0 ? "leaf" : "node",
++ root->objectid, btrfs_header_bytenr(eb), slot, &vaf);
++ va_end(args);
++}
++
+ static int check_extent_data_item(struct btrfs_root *root,
+ struct extent_buffer *leaf,
+ struct btrfs_key *key, int slot)
+@@ -282,9 +322,11 @@ int btrfs_check_node(struct btrfs_root *
+
+ if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root)) {
+ btrfs_crit(root->fs_info,
+- "corrupt node: block %llu root %llu nritems %lu",
+- node->start, root->objectid, nr);
+- return -EIO;
++"corrupt node: root=%llu block=%llu, nritems too %s, have %lu expect range [1,%zu]",
++ root->objectid, node->start,
++ nr == 0 ? "small" : "large", nr,
++ BTRFS_NODEPTRS_PER_BLOCK(root));
++ return -EUCLEAN;
+ }
+
+ for (slot = 0; slot < nr - 1; slot++) {
+@@ -293,14 +335,26 @@ int btrfs_check_node(struct btrfs_root *
+ btrfs_node_key_to_cpu(node, &next_key, slot + 1);
+
+ if (!bytenr) {
+- CORRUPT("invalid item slot", node, root, slot);
+- ret = -EIO;
++ generic_err(root, node, slot,
++ "invalid NULL node pointer");
++ ret = -EUCLEAN;
++ goto out;
++ }
++ if (!IS_ALIGNED(bytenr, root->sectorsize)) {
++ generic_err(root, node, slot,
++ "unaligned pointer, have %llu should be aligned to %u",
++ bytenr, root->sectorsize);
++ ret = -EUCLEAN;
+ goto out;
+ }
+
+ if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) {
+- CORRUPT("bad key order", node, root, slot);
+- ret = -EIO;
++ generic_err(root, node, slot,
++ "bad key order, current (%llu %u %llu) next (%llu %u %llu)",
++ key.objectid, key.type, key.offset,
++ next_key.objectid, next_key.type,
++ next_key.offset);
++ ret = -EUCLEAN;
+ goto out;
+ }
+ }
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Qu Wenruo <wqu@suse.com>
+Date: Wed, 8 Nov 2017 08:54:24 +0800
+Subject: btrfs: tree-checker: Fix false panic for sanity test
+
+From: Qu Wenruo <wqu@suse.com>
+
+commit 69fc6cbbac542c349b3d350d10f6e394c253c81d upstream.
+
+[BUG]
+If we run btrfs with CONFIG_BTRFS_FS_RUN_SANITY_TESTS=y, it will
+instantly cause kernel panic like:
+
+------
+...
+assertion failed: 0, file: fs/btrfs/disk-io.c, line: 3853
+...
+Call Trace:
+ btrfs_mark_buffer_dirty+0x187/0x1f0 [btrfs]
+ setup_items_for_insert+0x385/0x650 [btrfs]
+ __btrfs_drop_extents+0x129a/0x1870 [btrfs]
+...
+-----
+
+[Cause]
+Btrfs will call btrfs_check_leaf() in btrfs_mark_buffer_dirty() to check
+if the leaf is valid with CONFIG_BTRFS_FS_RUN_SANITY_TESTS=y.
+
+However quite some btrfs_mark_buffer_dirty() callers(*) don't really
+initialize its item data but only initialize its item pointers, leaving
+item data uninitialized.
+
+This makes tree-checker catch uninitialized data as error, causing
+such panic.
+
+*: These callers include but not limited to
+setup_items_for_insert()
+btrfs_split_item()
+btrfs_expand_item()
+
+[Fix]
+Add a new parameter @check_item_data to btrfs_check_leaf().
+With @check_item_data set to false, item data check will be skipped and
+fallback to old btrfs_check_leaf() behavior.
+
+So we can still get early warning if we screw up item pointers, and
+avoid false panic.
+
+Cc: Filipe Manana <fdmanana@gmail.com>
+Reported-by: Lakshmipathi.G <lakshmipathi.g@gmail.com>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: Liu Bo <bo.li.liu@oracle.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+[bwh: Backported to 4.4: adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/disk-io.c | 10 ++++++++--
+ fs/btrfs/tree-checker.c | 27 ++++++++++++++++++++++-----
+ fs/btrfs/tree-checker.h | 14 +++++++++++++-
+ 3 files changed, 43 insertions(+), 8 deletions(-)
+
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -589,7 +589,7 @@ static int btree_readpage_end_io_hook(st
+ * that we don't try and read the other copies of this block, just
+ * return -EIO.
+ */
+- if (found_level == 0 && btrfs_check_leaf(root, eb)) {
++ if (found_level == 0 && btrfs_check_leaf_full(root, eb)) {
+ set_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
+ ret = -EIO;
+ }
+@@ -3896,7 +3896,13 @@ void btrfs_mark_buffer_dirty(struct exte
+ buf->len,
+ root->fs_info->dirty_metadata_batch);
+ #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
+- if (btrfs_header_level(buf) == 0 && btrfs_check_leaf(root, buf)) {
++ /*
++ * Since btrfs_mark_buffer_dirty() can be called with item pointer set
++ * but item data not updated.
++ * So here we should only check item pointers, not item data.
++ */
++ if (btrfs_header_level(buf) == 0 &&
++ btrfs_check_leaf_relaxed(root, buf)) {
+ btrfs_print_leaf(root, buf);
+ ASSERT(0);
+ }
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -195,7 +195,8 @@ static int check_leaf_item(struct btrfs_
+ return ret;
+ }
+
+-int btrfs_check_leaf(struct btrfs_root *root, struct extent_buffer *leaf)
++static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
++ bool check_item_data)
+ {
+ struct btrfs_fs_info *fs_info = root->fs_info;
+ /* No valid key type is 0, so all key should be larger than this key */
+@@ -299,10 +300,15 @@ int btrfs_check_leaf(struct btrfs_root *
+ return -EUCLEAN;
+ }
+
+- /* Check if the item size and content meet other criteria */
+- ret = check_leaf_item(root, leaf, &key, slot);
+- if (ret < 0)
+- return ret;
++ if (check_item_data) {
++ /*
++ * Check if the item size and content meet other
++ * criteria
++ */
++ ret = check_leaf_item(root, leaf, &key, slot);
++ if (ret < 0)
++ return ret;
++ }
+
+ prev_key.objectid = key.objectid;
+ prev_key.type = key.type;
+@@ -312,6 +318,17 @@ int btrfs_check_leaf(struct btrfs_root *
+ return 0;
+ }
+
++int btrfs_check_leaf_full(struct btrfs_root *root, struct extent_buffer *leaf)
++{
++ return check_leaf(root, leaf, true);
++}
++
++int btrfs_check_leaf_relaxed(struct btrfs_root *root,
++ struct extent_buffer *leaf)
++{
++ return check_leaf(root, leaf, false);
++}
++
+ int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node)
+ {
+ unsigned long nr = btrfs_header_nritems(node);
+--- a/fs/btrfs/tree-checker.h
++++ b/fs/btrfs/tree-checker.h
+@@ -20,7 +20,19 @@
+ #include "ctree.h"
+ #include "extent_io.h"
+
+-int btrfs_check_leaf(struct btrfs_root *root, struct extent_buffer *leaf);
++/*
++ * Comprehensive leaf checker.
++ * Will check not only the item pointers, but also every possible member
++ * in item data.
++ */
++int btrfs_check_leaf_full(struct btrfs_root *root, struct extent_buffer *leaf);
++
++/*
++ * Less strict leaf checker.
++ * Will only check item pointers, not reading item data.
++ */
++int btrfs_check_leaf_relaxed(struct btrfs_root *root,
++ struct extent_buffer *leaf);
+ int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node);
+
+ #endif
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Shaokun Zhang <zhangshaokun@hisilicon.com>
+Date: Mon, 5 Nov 2018 18:49:09 +0800
+Subject: btrfs: tree-checker: Fix misleading group system information
+
+From: Shaokun Zhang <zhangshaokun@hisilicon.com>
+
+commit 761333f2f50ccc887aa9957ae829300262c0d15b upstream.
+
+block_group_err shows the group system as a decimal value with a '0x'
+prefix, which is somewhat misleading.
+
+Fix it to print hexadecimal, as was intended.
+
+Fixes: fce466eab7ac6 ("btrfs: tree-checker: Verify block_group_item")
+Reviewed-by: Nikolay Borisov <nborisov@suse.com>
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/tree-checker.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -399,7 +399,7 @@ static int check_block_group_item(struct
+ type != (BTRFS_BLOCK_GROUP_METADATA |
+ BTRFS_BLOCK_GROUP_DATA)) {
+ block_group_err(fs_info, leaf, slot,
+-"invalid type, have 0x%llx (%lu bits set) expect either 0x%llx, 0x%llx, 0x%llu or 0x%llx",
++"invalid type, have 0x%llx (%lu bits set) expect either 0x%llx, 0x%llx, 0x%llx or 0x%llx",
+ type, hweight64(type),
+ BTRFS_BLOCK_GROUP_DATA, BTRFS_BLOCK_GROUP_METADATA,
+ BTRFS_BLOCK_GROUP_SYSTEM,
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Wed, 6 Dec 2017 15:18:14 +0100
+Subject: btrfs: tree-checker: use %zu format string for size_t
+
+From: Arnd Bergmann <arnd@arndb.de>
+
+commit 7cfad65297bfe0aa2996cd72d21c898aa84436d9 upstream.
+
+The return value of sizeof() is of type size_t, so we must print it
+using the %z format modifier rather than %l to avoid this warning
+on some architectures:
+
+fs/btrfs/tree-checker.c: In function 'check_dir_item':
+fs/btrfs/tree-checker.c:273:50: error: format '%lu' expects argument of type 'long unsigned int', but argument 5 has type 'u32' {aka 'unsigned int'} [-Werror=format=]
+
+Fixes: 005887f2e3e0 ("btrfs: tree-checker: Add checker for dir item")
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/tree-checker.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -223,7 +223,7 @@ static int check_dir_item(struct btrfs_r
+ /* header itself should not cross item boundary */
+ if (cur + sizeof(*di) > item_size) {
+ dir_item_err(root, leaf, slot,
+- "dir item header crosses item boundary, have %lu boundary %u",
++ "dir item header crosses item boundary, have %zu boundary %u",
+ cur + sizeof(*di), item_size);
+ return -EUCLEAN;
+ }
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Qu Wenruo <wqu@suse.com>
+Date: Tue, 3 Jul 2018 17:10:05 +0800
+Subject: btrfs: tree-checker: Verify block_group_item
+
+From: Qu Wenruo <wqu@suse.com>
+
+commit fce466eab7ac6baa9d2dcd88abcf945be3d4a089 upstream.
+
+A crafted image with invalid block group items could make free space cache
+code to cause panic.
+
+We could detect such invalid block group item by checking:
+1) Item size
+ Known fixed value.
+2) Block group size (key.offset)
+ We have an upper limit on block group item (10G)
+3) Chunk objectid
+ Known fixed value.
+4) Type
+ Only 4 valid type values, DATA, METADATA, SYSTEM and DATA|METADATA.
+ No more than 1 bit set for profile type.
+5) Used space
+ No more than the block group size.
+
+This should allow btrfs to detect and refuse to mount the crafted image.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=199849
+Reported-by: Xu Wen <wen.xu@gatech.edu>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: Gu Jinxiang <gujx@cn.fujitsu.com>
+Reviewed-by: Nikolay Borisov <nborisov@suse.com>
+Tested-by: Gu Jinxiang <gujx@cn.fujitsu.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+[bwh: Backported to 4.4:
+ - In check_leaf_item(), pass root->fs_info to check_block_group_item()
+ - Include <linux/sizes.h> (in ctree.h, to match upstream)
+ - Adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/ctree.h | 1
+ fs/btrfs/tree-checker.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++
+ fs/btrfs/volumes.c | 2
+ fs/btrfs/volumes.h | 2
+ 4 files changed, 104 insertions(+), 1 deletion(-)
+
+--- a/fs/btrfs/ctree.h
++++ b/fs/btrfs/ctree.h
+@@ -35,6 +35,7 @@
+ #include <linux/btrfs.h>
+ #include <linux/workqueue.h>
+ #include <linux/security.h>
++#include <linux/sizes.h>
+ #include "extent_io.h"
+ #include "extent_map.h"
+ #include "async-thread.h"
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -31,6 +31,7 @@
+ #include "disk-io.h"
+ #include "compression.h"
+ #include "hash.h"
++#include "volumes.h"
+
+ #define CORRUPT(reason, eb, root, slot) \
+ btrfs_crit(root->fs_info, \
+@@ -312,6 +313,102 @@ static int check_dir_item(struct btrfs_r
+ return 0;
+ }
+
++__printf(4, 5)
++__cold
++static void block_group_err(const struct btrfs_fs_info *fs_info,
++ const struct extent_buffer *eb, int slot,
++ const char *fmt, ...)
++{
++ struct btrfs_key key;
++ struct va_format vaf;
++ va_list args;
++
++ btrfs_item_key_to_cpu(eb, &key, slot);
++ va_start(args, fmt);
++
++ vaf.fmt = fmt;
++ vaf.va = &args;
++
++ btrfs_crit(fs_info,
++ "corrupt %s: root=%llu block=%llu slot=%d bg_start=%llu bg_len=%llu, %pV",
++ btrfs_header_level(eb) == 0 ? "leaf" : "node",
++ btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot,
++ key.objectid, key.offset, &vaf);
++ va_end(args);
++}
++
++static int check_block_group_item(struct btrfs_fs_info *fs_info,
++ struct extent_buffer *leaf,
++ struct btrfs_key *key, int slot)
++{
++ struct btrfs_block_group_item bgi;
++ u32 item_size = btrfs_item_size_nr(leaf, slot);
++ u64 flags;
++ u64 type;
++
++ /*
++ * Here we don't really care about alignment since extent allocator can
++ * handle it. We care more about the size, as if one block group is
++ * larger than maximum size, it's must be some obvious corruption.
++ */
++ if (key->offset > BTRFS_MAX_DATA_CHUNK_SIZE || key->offset == 0) {
++ block_group_err(fs_info, leaf, slot,
++ "invalid block group size, have %llu expect (0, %llu]",
++ key->offset, BTRFS_MAX_DATA_CHUNK_SIZE);
++ return -EUCLEAN;
++ }
++
++ if (item_size != sizeof(bgi)) {
++ block_group_err(fs_info, leaf, slot,
++ "invalid item size, have %u expect %zu",
++ item_size, sizeof(bgi));
++ return -EUCLEAN;
++ }
++
++ read_extent_buffer(leaf, &bgi, btrfs_item_ptr_offset(leaf, slot),
++ sizeof(bgi));
++ if (btrfs_block_group_chunk_objectid(&bgi) !=
++ BTRFS_FIRST_CHUNK_TREE_OBJECTID) {
++ block_group_err(fs_info, leaf, slot,
++ "invalid block group chunk objectid, have %llu expect %llu",
++ btrfs_block_group_chunk_objectid(&bgi),
++ BTRFS_FIRST_CHUNK_TREE_OBJECTID);
++ return -EUCLEAN;
++ }
++
++ if (btrfs_block_group_used(&bgi) > key->offset) {
++ block_group_err(fs_info, leaf, slot,
++ "invalid block group used, have %llu expect [0, %llu)",
++ btrfs_block_group_used(&bgi), key->offset);
++ return -EUCLEAN;
++ }
++
++ flags = btrfs_block_group_flags(&bgi);
++ if (hweight64(flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) > 1) {
++ block_group_err(fs_info, leaf, slot,
++"invalid profile flags, have 0x%llx (%lu bits set) expect no more than 1 bit set",
++ flags & BTRFS_BLOCK_GROUP_PROFILE_MASK,
++ hweight64(flags & BTRFS_BLOCK_GROUP_PROFILE_MASK));
++ return -EUCLEAN;
++ }
++
++ type = flags & BTRFS_BLOCK_GROUP_TYPE_MASK;
++ if (type != BTRFS_BLOCK_GROUP_DATA &&
++ type != BTRFS_BLOCK_GROUP_METADATA &&
++ type != BTRFS_BLOCK_GROUP_SYSTEM &&
++ type != (BTRFS_BLOCK_GROUP_METADATA |
++ BTRFS_BLOCK_GROUP_DATA)) {
++ block_group_err(fs_info, leaf, slot,
++"invalid type, have 0x%llx (%lu bits set) expect either 0x%llx, 0x%llx, 0x%llu or 0x%llx",
++ type, hweight64(type),
++ BTRFS_BLOCK_GROUP_DATA, BTRFS_BLOCK_GROUP_METADATA,
++ BTRFS_BLOCK_GROUP_SYSTEM,
++ BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA);
++ return -EUCLEAN;
++ }
++ return 0;
++}
++
+ /*
+ * Common point to switch the item-specific validation.
+ */
+@@ -333,6 +430,9 @@ static int check_leaf_item(struct btrfs_
+ case BTRFS_XATTR_ITEM_KEY:
+ ret = check_dir_item(root, leaf, key, slot);
+ break;
++ case BTRFS_BLOCK_GROUP_ITEM_KEY:
++ ret = check_block_group_item(root->fs_info, leaf, key, slot);
++ break;
+ }
+ return ret;
+ }
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -4540,7 +4540,7 @@ static int __btrfs_alloc_chunk(struct bt
+
+ if (type & BTRFS_BLOCK_GROUP_DATA) {
+ max_stripe_size = 1024 * 1024 * 1024;
+- max_chunk_size = 10 * max_stripe_size;
++ max_chunk_size = BTRFS_MAX_DATA_CHUNK_SIZE;
+ if (!devs_max)
+ devs_max = BTRFS_MAX_DEVS(info->chunk_root);
+ } else if (type & BTRFS_BLOCK_GROUP_METADATA) {
+--- a/fs/btrfs/volumes.h
++++ b/fs/btrfs/volumes.h
+@@ -24,6 +24,8 @@
+ #include <linux/btrfs.h>
+ #include "async-thread.h"
+
++#define BTRFS_MAX_DATA_CHUNK_SIZE (10ULL * SZ_1G)
++
+ extern struct mutex uuid_mutex;
+
+ #define BTRFS_STRIPE_LEN (64 * 1024)
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Gu Jinxiang <gujx@cn.fujitsu.com>
+Date: Wed, 4 Jul 2018 18:16:39 +0800
+Subject: btrfs: validate type when reading a chunk
+
+From: Gu Jinxiang <gujx@cn.fujitsu.com>
+
+commit 315409b0098fb2651d86553f0436b70502b29bb2 upstream.
+
+Reported in https://bugzilla.kernel.org/show_bug.cgi?id=199839, with an
+image that has an invalid chunk type but does not return an error.
+
+Add chunk type check in btrfs_check_chunk_valid, to detect the wrong
+type combinations.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=199839
+Reported-by: Xu Wen <wen.xu@gatech.edu>
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Gu Jinxiang <gujx@cn.fujitsu.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+[bwh: Backported to 4.4: Use root->fs_info instead of fs_info]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/volumes.c | 28 ++++++++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -6218,6 +6218,8 @@ static int btrfs_check_chunk_valid(struc
+ u16 num_stripes;
+ u16 sub_stripes;
+ u64 type;
++ u64 features;
++ bool mixed = false;
+
+ length = btrfs_chunk_length(leaf, chunk);
+ stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
+@@ -6258,6 +6260,32 @@ static int btrfs_check_chunk_valid(struc
+ btrfs_chunk_type(leaf, chunk));
+ return -EIO;
+ }
++
++ if ((type & BTRFS_BLOCK_GROUP_TYPE_MASK) == 0) {
++ btrfs_err(root->fs_info, "missing chunk type flag: 0x%llx", type);
++ return -EIO;
++ }
++
++ if ((type & BTRFS_BLOCK_GROUP_SYSTEM) &&
++ (type & (BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA))) {
++ btrfs_err(root->fs_info,
++ "system chunk with data or metadata type: 0x%llx", type);
++ return -EIO;
++ }
++
++ features = btrfs_super_incompat_flags(root->fs_info->super_copy);
++ if (features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS)
++ mixed = true;
++
++ if (!mixed) {
++ if ((type & BTRFS_BLOCK_GROUP_METADATA) &&
++ (type & BTRFS_BLOCK_GROUP_DATA)) {
++ btrfs_err(root->fs_info,
++ "mixed chunk type in non-mixed mode: 0x%llx", type);
++ return -EIO;
++ }
++ }
++
+ if ((type & BTRFS_BLOCK_GROUP_RAID10 && sub_stripes != 2) ||
+ (type & BTRFS_BLOCK_GROUP_RAID1 && num_stripes < 1) ||
+ (type & BTRFS_BLOCK_GROUP_RAID5 && num_stripes < 2) ||
--- /dev/null
+From foo@baz Mon Jan 14 14:39:22 CET 2019
+From: Qu Wenruo <wqu@suse.com>
+Date: Wed, 1 Aug 2018 10:37:17 +0800
+Subject: btrfs: Verify that every chunk has corresponding block group at mount time
+
+From: Qu Wenruo <wqu@suse.com>
+
+commit 7ef49515fa6727cb4b6f2f5b0ffbc5fc20a9f8c6 upstream.
+
+If a crafted image has missing block group items, it could cause
+unexpected behavior and breaks the assumption of 1:1 chunk<->block group
+mapping.
+
+Although we have the block group -> chunk mapping check, we still need
+chunk -> block group mapping check.
+
+This patch will do extra check to ensure each chunk has its
+corresponding block group.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=199847
+Reported-by: Xu Wen <wen.xu@gatech.edu>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: Gu Jinxiang <gujx@cn.fujitsu.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+[bwh: Backported to 4.4: adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/extent-tree.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 57 insertions(+), 1 deletion(-)
+
+--- a/fs/btrfs/extent-tree.c
++++ b/fs/btrfs/extent-tree.c
+@@ -9765,6 +9765,62 @@ btrfs_create_block_group_cache(struct bt
+ return cache;
+ }
+
++
++/*
++ * Iterate all chunks and verify that each of them has the corresponding block
++ * group
++ */
++static int check_chunk_block_group_mappings(struct btrfs_fs_info *fs_info)
++{
++ struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
++ struct extent_map *em;
++ struct btrfs_block_group_cache *bg;
++ u64 start = 0;
++ int ret = 0;
++
++ while (1) {
++ read_lock(&map_tree->map_tree.lock);
++ /*
++ * lookup_extent_mapping will return the first extent map
++ * intersecting the range, so setting @len to 1 is enough to
++ * get the first chunk.
++ */
++ em = lookup_extent_mapping(&map_tree->map_tree, start, 1);
++ read_unlock(&map_tree->map_tree.lock);
++ if (!em)
++ break;
++
++ bg = btrfs_lookup_block_group(fs_info, em->start);
++ if (!bg) {
++ btrfs_err(fs_info,
++ "chunk start=%llu len=%llu doesn't have corresponding block group",
++ em->start, em->len);
++ ret = -EUCLEAN;
++ free_extent_map(em);
++ break;
++ }
++ if (bg->key.objectid != em->start ||
++ bg->key.offset != em->len ||
++ (bg->flags & BTRFS_BLOCK_GROUP_TYPE_MASK) !=
++ (em->map_lookup->type & BTRFS_BLOCK_GROUP_TYPE_MASK)) {
++ btrfs_err(fs_info,
++"chunk start=%llu len=%llu flags=0x%llx doesn't match block group start=%llu len=%llu flags=0x%llx",
++ em->start, em->len,
++ em->map_lookup->type & BTRFS_BLOCK_GROUP_TYPE_MASK,
++ bg->key.objectid, bg->key.offset,
++ bg->flags & BTRFS_BLOCK_GROUP_TYPE_MASK);
++ ret = -EUCLEAN;
++ free_extent_map(em);
++ btrfs_put_block_group(bg);
++ break;
++ }
++ start = em->start + em->len;
++ free_extent_map(em);
++ btrfs_put_block_group(bg);
++ }
++ return ret;
++}
++
+ int btrfs_read_block_groups(struct btrfs_root *root)
+ {
+ struct btrfs_path *path;
+@@ -9951,7 +10007,7 @@ int btrfs_read_block_groups(struct btrfs
+ }
+
+ init_global_block_rsv(info);
+- ret = 0;
++ ret = check_chunk_block_group_mappings(info);
+ error:
+ btrfs_free_path(path);
+ return ret;
alsa-hda-realtek-disable-headset-mic-vref-for-headset-mode-of-alc225.patch
+btrfs-cleanup-stop-casting-for-extent_map-lookup-everywhere.patch
+btrfs-enhance-chunk-validation-check.patch
+btrfs-add-validadtion-checks-for-chunk-loading.patch
+btrfs-check-inconsistence-between-chunk-and-block-group.patch
+btrfs-fix-em-leak-in-find_first_block_group.patch
+btrfs-detect-corruption-when-non-root-leaf-has-zero-item.patch
+btrfs-check-btree-node-s-nritems.patch
+btrfs-fix-bug_on-in-btrfs_mark_buffer_dirty.patch
+btrfs-memset-to-avoid-stale-content-in-btree-node-block.patch
+btrfs-improve-check_node-to-avoid-reading-corrupted-nodes.patch
+btrfs-kill-bug_on-in-run_delayed_tree_ref.patch
+btrfs-memset-to-avoid-stale-content-in-btree-leaf.patch
+btrfs-fix-emptiness-check-for-dirtied-extent-buffers-at-check_leaf.patch
+btrfs-struct-funcs-constify-readers.patch
+btrfs-refactor-check_leaf-function-for-later-expansion.patch
+btrfs-check-if-item-pointer-overlaps-with-the-item-itself.patch
+btrfs-add-sanity-check-for-extent_data-when-reading-out-leaf.patch
+btrfs-add-checker-for-extent_csum.patch
+btrfs-move-leaf-and-node-validation-checker-to-tree-checker.c.patch
+btrfs-tree-checker-enhance-btrfs_check_node-output.patch
+btrfs-tree-checker-fix-false-panic-for-sanity-test.patch
+btrfs-tree-checker-add-checker-for-dir-item.patch
+btrfs-tree-checker-use-zu-format-string-for-size_t.patch
+btrfs-tree-check-reduce-stack-consumption-in-check_dir_item.patch
+btrfs-tree-checker-verify-block_group_item.patch
+btrfs-tree-checker-detect-invalid-and-empty-essential-trees.patch
+btrfs-validate-type-when-reading-a-chunk.patch
+btrfs-check-that-each-block-group-has-corresponding-chunk-at-mount-time.patch
+btrfs-verify-that-every-chunk-has-corresponding-block-group-at-mount-time.patch
+btrfs-tree-checker-check-level-for-leaves-and-nodes.patch
+btrfs-tree-checker-fix-misleading-group-system-information.patch