1c1d7c514SDavid Sterba // SPDX-License-Identifier: GPL-2.0 2557ea5ddSQu Wenruo /* 3557ea5ddSQu Wenruo * Copyright (C) Qu Wenruo 2017. All rights reserved. 4557ea5ddSQu Wenruo */ 5557ea5ddSQu Wenruo 6557ea5ddSQu Wenruo /* 7557ea5ddSQu Wenruo * The module is used to catch unexpected/corrupted tree block data. 8557ea5ddSQu Wenruo * Such behavior can be caused either by a fuzzed image or bugs. 9557ea5ddSQu Wenruo * 10557ea5ddSQu Wenruo * The objective is to do leaf/node validation checks when tree block is read 11557ea5ddSQu Wenruo * from disk, and check *every* possible member, so other code won't 12557ea5ddSQu Wenruo * need to checking them again. 13557ea5ddSQu Wenruo * 14557ea5ddSQu Wenruo * Due to the potential and unwanted damage, every checker needs to be 15557ea5ddSQu Wenruo * carefully reviewed otherwise so it does not prevent mount of valid images. 16557ea5ddSQu Wenruo */ 17557ea5ddSQu Wenruo 1802529d7aSQu Wenruo #include <linux/types.h> 1902529d7aSQu Wenruo #include <linux/stddef.h> 2002529d7aSQu Wenruo #include <linux/error-injection.h> 21557ea5ddSQu Wenruo #include "ctree.h" 22557ea5ddSQu Wenruo #include "tree-checker.h" 23557ea5ddSQu Wenruo #include "disk-io.h" 24557ea5ddSQu Wenruo #include "compression.h" 25fce466eaSQu Wenruo #include "volumes.h" 26557ea5ddSQu Wenruo 27bba4f298SQu Wenruo /* 28bba4f298SQu Wenruo * Error message should follow the following format: 29bba4f298SQu Wenruo * corrupt <type>: <identifier>, <reason>[, <bad_value>] 30bba4f298SQu Wenruo * 31bba4f298SQu Wenruo * @type: leaf or node 32bba4f298SQu Wenruo * @identifier: the necessary info to locate the leaf/node. 3352042d8eSAndrea Gelmini * It's recommended to decode key.objecitd/offset if it's 34bba4f298SQu Wenruo * meaningful. 35bba4f298SQu Wenruo * @reason: describe the error 3652042d8eSAndrea Gelmini * @bad_value: optional, it's recommended to output bad value and its 37bba4f298SQu Wenruo * expected value (range). 38bba4f298SQu Wenruo * 39bba4f298SQu Wenruo * Since comma is used to separate the components, only space is allowed 40bba4f298SQu Wenruo * inside each component. 41bba4f298SQu Wenruo */ 42bba4f298SQu Wenruo 43bba4f298SQu Wenruo /* 44bba4f298SQu Wenruo * Append generic "corrupt leaf/node root=%llu block=%llu slot=%d: " to @fmt. 45bba4f298SQu Wenruo * Allows callers to customize the output. 46bba4f298SQu Wenruo */ 4786a6be3aSDavid Sterba __printf(3, 4) 48e67c718bSDavid Sterba __cold 4986a6be3aSDavid Sterba static void generic_err(const struct extent_buffer *eb, int slot, 50bba4f298SQu Wenruo const char *fmt, ...) 51bba4f298SQu Wenruo { 5286a6be3aSDavid Sterba const struct btrfs_fs_info *fs_info = eb->fs_info; 53bba4f298SQu Wenruo struct va_format vaf; 54bba4f298SQu Wenruo va_list args; 55bba4f298SQu Wenruo 56bba4f298SQu Wenruo va_start(args, fmt); 57bba4f298SQu Wenruo 58bba4f298SQu Wenruo vaf.fmt = fmt; 59bba4f298SQu Wenruo vaf.va = &args; 60bba4f298SQu Wenruo 612f659546SQu Wenruo btrfs_crit(fs_info, 62bba4f298SQu Wenruo "corrupt %s: root=%llu block=%llu slot=%d, %pV", 63bba4f298SQu Wenruo btrfs_header_level(eb) == 0 ? "leaf" : "node", 642f659546SQu Wenruo btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot, &vaf); 65bba4f298SQu Wenruo va_end(args); 66bba4f298SQu Wenruo } 67bba4f298SQu Wenruo 688806d718SQu Wenruo /* 698806d718SQu Wenruo * Customized reporter for extent data item, since its key objectid and 708806d718SQu Wenruo * offset has its own meaning. 718806d718SQu Wenruo */ 721fd715ffSDavid Sterba __printf(3, 4) 73e67c718bSDavid Sterba __cold 741fd715ffSDavid Sterba static void file_extent_err(const struct extent_buffer *eb, int slot, 758806d718SQu Wenruo const char *fmt, ...) 768806d718SQu Wenruo { 771fd715ffSDavid Sterba const struct btrfs_fs_info *fs_info = eb->fs_info; 788806d718SQu Wenruo struct btrfs_key key; 798806d718SQu Wenruo struct va_format vaf; 808806d718SQu Wenruo va_list args; 818806d718SQu Wenruo 828806d718SQu Wenruo btrfs_item_key_to_cpu(eb, &key, slot); 838806d718SQu Wenruo va_start(args, fmt); 848806d718SQu Wenruo 858806d718SQu Wenruo vaf.fmt = fmt; 868806d718SQu Wenruo vaf.va = &args; 878806d718SQu Wenruo 882f659546SQu Wenruo btrfs_crit(fs_info, 898806d718SQu Wenruo "corrupt %s: root=%llu block=%llu slot=%d ino=%llu file_offset=%llu, %pV", 902f659546SQu Wenruo btrfs_header_level(eb) == 0 ? "leaf" : "node", 912f659546SQu Wenruo btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot, 922f659546SQu Wenruo key.objectid, key.offset, &vaf); 938806d718SQu Wenruo va_end(args); 948806d718SQu Wenruo } 958806d718SQu Wenruo 968806d718SQu Wenruo /* 978806d718SQu Wenruo * Return 0 if the btrfs_file_extent_##name is aligned to @alignment 988806d718SQu Wenruo * Else return 1 998806d718SQu Wenruo */ 100033774dcSDavid Sterba #define CHECK_FE_ALIGNED(leaf, slot, fi, name, alignment) \ 1018806d718SQu Wenruo ({ \ 1028806d718SQu Wenruo if (!IS_ALIGNED(btrfs_file_extent_##name((leaf), (fi)), (alignment))) \ 1031fd715ffSDavid Sterba file_extent_err((leaf), (slot), \ 1048806d718SQu Wenruo "invalid %s for file extent, have %llu, should be aligned to %u", \ 1058806d718SQu Wenruo (#name), btrfs_file_extent_##name((leaf), (fi)), \ 1068806d718SQu Wenruo (alignment)); \ 1078806d718SQu Wenruo (!IS_ALIGNED(btrfs_file_extent_##name((leaf), (fi)), (alignment))); \ 1088806d718SQu Wenruo }) 1098806d718SQu Wenruo 1104e9845efSFilipe Manana static u64 file_extent_end(struct extent_buffer *leaf, 1114e9845efSFilipe Manana struct btrfs_key *key, 1124e9845efSFilipe Manana struct btrfs_file_extent_item *extent) 1134e9845efSFilipe Manana { 1144e9845efSFilipe Manana u64 end; 1154e9845efSFilipe Manana u64 len; 1164e9845efSFilipe Manana 1174e9845efSFilipe Manana if (btrfs_file_extent_type(leaf, extent) == BTRFS_FILE_EXTENT_INLINE) { 1184e9845efSFilipe Manana len = btrfs_file_extent_ram_bytes(leaf, extent); 1194e9845efSFilipe Manana end = ALIGN(key->offset + len, leaf->fs_info->sectorsize); 1204e9845efSFilipe Manana } else { 1214e9845efSFilipe Manana len = btrfs_file_extent_num_bytes(leaf, extent); 1224e9845efSFilipe Manana end = key->offset + len; 1234e9845efSFilipe Manana } 1244e9845efSFilipe Manana return end; 1254e9845efSFilipe Manana } 1264e9845efSFilipe Manana 127ae2a19d8SDavid Sterba static int check_extent_data_item(struct extent_buffer *leaf, 1284e9845efSFilipe Manana struct btrfs_key *key, int slot, 1294e9845efSFilipe Manana struct btrfs_key *prev_key) 130557ea5ddSQu Wenruo { 131ae2a19d8SDavid Sterba struct btrfs_fs_info *fs_info = leaf->fs_info; 132557ea5ddSQu Wenruo struct btrfs_file_extent_item *fi; 1332f659546SQu Wenruo u32 sectorsize = fs_info->sectorsize; 134557ea5ddSQu Wenruo u32 item_size = btrfs_item_size_nr(leaf, slot); 1354c094c33SQu Wenruo u64 extent_end; 136557ea5ddSQu Wenruo 137557ea5ddSQu Wenruo if (!IS_ALIGNED(key->offset, sectorsize)) { 1381fd715ffSDavid Sterba file_extent_err(leaf, slot, 1398806d718SQu Wenruo "unaligned file_offset for file extent, have %llu should be aligned to %u", 1408806d718SQu Wenruo key->offset, sectorsize); 141557ea5ddSQu Wenruo return -EUCLEAN; 142557ea5ddSQu Wenruo } 143557ea5ddSQu Wenruo 144557ea5ddSQu Wenruo fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); 145557ea5ddSQu Wenruo 146557ea5ddSQu Wenruo if (btrfs_file_extent_type(leaf, fi) > BTRFS_FILE_EXTENT_TYPES) { 1471fd715ffSDavid Sterba file_extent_err(leaf, slot, 1488806d718SQu Wenruo "invalid type for file extent, have %u expect range [0, %u]", 1498806d718SQu Wenruo btrfs_file_extent_type(leaf, fi), 1508806d718SQu Wenruo BTRFS_FILE_EXTENT_TYPES); 151557ea5ddSQu Wenruo return -EUCLEAN; 152557ea5ddSQu Wenruo } 153557ea5ddSQu Wenruo 154557ea5ddSQu Wenruo /* 15552042d8eSAndrea Gelmini * Support for new compression/encryption must introduce incompat flag, 156557ea5ddSQu Wenruo * and must be caught in open_ctree(). 157557ea5ddSQu Wenruo */ 158557ea5ddSQu Wenruo if (btrfs_file_extent_compression(leaf, fi) > BTRFS_COMPRESS_TYPES) { 1591fd715ffSDavid Sterba file_extent_err(leaf, slot, 1608806d718SQu Wenruo "invalid compression for file extent, have %u expect range [0, %u]", 1618806d718SQu Wenruo btrfs_file_extent_compression(leaf, fi), 1628806d718SQu Wenruo BTRFS_COMPRESS_TYPES); 163557ea5ddSQu Wenruo return -EUCLEAN; 164557ea5ddSQu Wenruo } 165557ea5ddSQu Wenruo if (btrfs_file_extent_encryption(leaf, fi)) { 1661fd715ffSDavid Sterba file_extent_err(leaf, slot, 1678806d718SQu Wenruo "invalid encryption for file extent, have %u expect 0", 1688806d718SQu Wenruo btrfs_file_extent_encryption(leaf, fi)); 169557ea5ddSQu Wenruo return -EUCLEAN; 170557ea5ddSQu Wenruo } 171557ea5ddSQu Wenruo if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) { 172557ea5ddSQu Wenruo /* Inline extent must have 0 as key offset */ 173557ea5ddSQu Wenruo if (key->offset) { 1741fd715ffSDavid Sterba file_extent_err(leaf, slot, 1758806d718SQu Wenruo "invalid file_offset for inline file extent, have %llu expect 0", 1768806d718SQu Wenruo key->offset); 177557ea5ddSQu Wenruo return -EUCLEAN; 178557ea5ddSQu Wenruo } 179557ea5ddSQu Wenruo 180557ea5ddSQu Wenruo /* Compressed inline extent has no on-disk size, skip it */ 181557ea5ddSQu Wenruo if (btrfs_file_extent_compression(leaf, fi) != 182557ea5ddSQu Wenruo BTRFS_COMPRESS_NONE) 183557ea5ddSQu Wenruo return 0; 184557ea5ddSQu Wenruo 185557ea5ddSQu Wenruo /* Uncompressed inline extent size must match item size */ 186557ea5ddSQu Wenruo if (item_size != BTRFS_FILE_EXTENT_INLINE_DATA_START + 187557ea5ddSQu Wenruo btrfs_file_extent_ram_bytes(leaf, fi)) { 1881fd715ffSDavid Sterba file_extent_err(leaf, slot, 1898806d718SQu Wenruo "invalid ram_bytes for uncompressed inline extent, have %u expect %llu", 1908806d718SQu Wenruo item_size, BTRFS_FILE_EXTENT_INLINE_DATA_START + 1918806d718SQu Wenruo btrfs_file_extent_ram_bytes(leaf, fi)); 192557ea5ddSQu Wenruo return -EUCLEAN; 193557ea5ddSQu Wenruo } 194557ea5ddSQu Wenruo return 0; 195557ea5ddSQu Wenruo } 196557ea5ddSQu Wenruo 197557ea5ddSQu Wenruo /* Regular or preallocated extent has fixed item size */ 198557ea5ddSQu Wenruo if (item_size != sizeof(*fi)) { 1991fd715ffSDavid Sterba file_extent_err(leaf, slot, 200709a95c3SArnd Bergmann "invalid item size for reg/prealloc file extent, have %u expect %zu", 2018806d718SQu Wenruo item_size, sizeof(*fi)); 202557ea5ddSQu Wenruo return -EUCLEAN; 203557ea5ddSQu Wenruo } 204033774dcSDavid Sterba if (CHECK_FE_ALIGNED(leaf, slot, fi, ram_bytes, sectorsize) || 205033774dcSDavid Sterba CHECK_FE_ALIGNED(leaf, slot, fi, disk_bytenr, sectorsize) || 206033774dcSDavid Sterba CHECK_FE_ALIGNED(leaf, slot, fi, disk_num_bytes, sectorsize) || 207033774dcSDavid Sterba CHECK_FE_ALIGNED(leaf, slot, fi, offset, sectorsize) || 208033774dcSDavid Sterba CHECK_FE_ALIGNED(leaf, slot, fi, num_bytes, sectorsize)) 209557ea5ddSQu Wenruo return -EUCLEAN; 2104e9845efSFilipe Manana 2114c094c33SQu Wenruo /* Catch extent end overflow */ 2124c094c33SQu Wenruo if (check_add_overflow(btrfs_file_extent_num_bytes(leaf, fi), 2134c094c33SQu Wenruo key->offset, &extent_end)) { 2144c094c33SQu Wenruo file_extent_err(leaf, slot, 2154c094c33SQu Wenruo "extent end overflow, have file offset %llu extent num bytes %llu", 2164c094c33SQu Wenruo key->offset, 2174c094c33SQu Wenruo btrfs_file_extent_num_bytes(leaf, fi)); 2184c094c33SQu Wenruo return -EUCLEAN; 2194c094c33SQu Wenruo } 2204c094c33SQu Wenruo 2214e9845efSFilipe Manana /* 2224e9845efSFilipe Manana * Check that no two consecutive file extent items, in the same leaf, 2234e9845efSFilipe Manana * present ranges that overlap each other. 2244e9845efSFilipe Manana */ 2254e9845efSFilipe Manana if (slot > 0 && 2264e9845efSFilipe Manana prev_key->objectid == key->objectid && 2274e9845efSFilipe Manana prev_key->type == BTRFS_EXTENT_DATA_KEY) { 2284e9845efSFilipe Manana struct btrfs_file_extent_item *prev_fi; 2294e9845efSFilipe Manana u64 prev_end; 2304e9845efSFilipe Manana 2314e9845efSFilipe Manana prev_fi = btrfs_item_ptr(leaf, slot - 1, 2324e9845efSFilipe Manana struct btrfs_file_extent_item); 2334e9845efSFilipe Manana prev_end = file_extent_end(leaf, prev_key, prev_fi); 2344e9845efSFilipe Manana if (prev_end > key->offset) { 2354e9845efSFilipe Manana file_extent_err(leaf, slot - 1, 2364e9845efSFilipe Manana "file extent end range (%llu) goes beyond start offset (%llu) of the next file extent", 2374e9845efSFilipe Manana prev_end, key->offset); 2384e9845efSFilipe Manana return -EUCLEAN; 2394e9845efSFilipe Manana } 2404e9845efSFilipe Manana } 2414e9845efSFilipe Manana 242557ea5ddSQu Wenruo return 0; 243557ea5ddSQu Wenruo } 244557ea5ddSQu Wenruo 24568128ce7SDavid Sterba static int check_csum_item(struct extent_buffer *leaf, struct btrfs_key *key, 2462f659546SQu Wenruo int slot) 247557ea5ddSQu Wenruo { 24868128ce7SDavid Sterba struct btrfs_fs_info *fs_info = leaf->fs_info; 2492f659546SQu Wenruo u32 sectorsize = fs_info->sectorsize; 2502f659546SQu Wenruo u32 csumsize = btrfs_super_csum_size(fs_info->super_copy); 251557ea5ddSQu Wenruo 252557ea5ddSQu Wenruo if (key->objectid != BTRFS_EXTENT_CSUM_OBJECTID) { 25386a6be3aSDavid Sterba generic_err(leaf, slot, 254d508c5f0SQu Wenruo "invalid key objectid for csum item, have %llu expect %llu", 255d508c5f0SQu Wenruo key->objectid, BTRFS_EXTENT_CSUM_OBJECTID); 256557ea5ddSQu Wenruo return -EUCLEAN; 257557ea5ddSQu Wenruo } 258557ea5ddSQu Wenruo if (!IS_ALIGNED(key->offset, sectorsize)) { 25986a6be3aSDavid Sterba generic_err(leaf, slot, 260d508c5f0SQu Wenruo "unaligned key offset for csum item, have %llu should be aligned to %u", 261d508c5f0SQu Wenruo key->offset, sectorsize); 262557ea5ddSQu Wenruo return -EUCLEAN; 263557ea5ddSQu Wenruo } 264557ea5ddSQu Wenruo if (!IS_ALIGNED(btrfs_item_size_nr(leaf, slot), csumsize)) { 26586a6be3aSDavid Sterba generic_err(leaf, slot, 266d508c5f0SQu Wenruo "unaligned item size for csum item, have %u should be aligned to %u", 267d508c5f0SQu Wenruo btrfs_item_size_nr(leaf, slot), csumsize); 268557ea5ddSQu Wenruo return -EUCLEAN; 269557ea5ddSQu Wenruo } 270557ea5ddSQu Wenruo return 0; 271557ea5ddSQu Wenruo } 272557ea5ddSQu Wenruo 273557ea5ddSQu Wenruo /* 274ad7b0368SQu Wenruo * Customized reported for dir_item, only important new info is key->objectid, 275ad7b0368SQu Wenruo * which represents inode number 276ad7b0368SQu Wenruo */ 277d98ced68SDavid Sterba __printf(3, 4) 278e67c718bSDavid Sterba __cold 279d98ced68SDavid Sterba static void dir_item_err(const struct extent_buffer *eb, int slot, 280ad7b0368SQu Wenruo const char *fmt, ...) 281ad7b0368SQu Wenruo { 282d98ced68SDavid Sterba const struct btrfs_fs_info *fs_info = eb->fs_info; 283ad7b0368SQu Wenruo struct btrfs_key key; 284ad7b0368SQu Wenruo struct va_format vaf; 285ad7b0368SQu Wenruo va_list args; 286ad7b0368SQu Wenruo 287ad7b0368SQu Wenruo btrfs_item_key_to_cpu(eb, &key, slot); 288ad7b0368SQu Wenruo va_start(args, fmt); 289ad7b0368SQu Wenruo 290ad7b0368SQu Wenruo vaf.fmt = fmt; 291ad7b0368SQu Wenruo vaf.va = &args; 292ad7b0368SQu Wenruo 2932f659546SQu Wenruo btrfs_crit(fs_info, 294ad7b0368SQu Wenruo "corrupt %s: root=%llu block=%llu slot=%d ino=%llu, %pV", 2952f659546SQu Wenruo btrfs_header_level(eb) == 0 ? "leaf" : "node", 2962f659546SQu Wenruo btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot, 2972f659546SQu Wenruo key.objectid, &vaf); 298ad7b0368SQu Wenruo va_end(args); 299ad7b0368SQu Wenruo } 300ad7b0368SQu Wenruo 301ce4252c0SDavid Sterba static int check_dir_item(struct extent_buffer *leaf, 302ad7b0368SQu Wenruo struct btrfs_key *key, int slot) 303ad7b0368SQu Wenruo { 304ce4252c0SDavid Sterba struct btrfs_fs_info *fs_info = leaf->fs_info; 305ad7b0368SQu Wenruo struct btrfs_dir_item *di; 306ad7b0368SQu Wenruo u32 item_size = btrfs_item_size_nr(leaf, slot); 307ad7b0368SQu Wenruo u32 cur = 0; 308ad7b0368SQu Wenruo 309ad7b0368SQu Wenruo di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item); 310ad7b0368SQu Wenruo while (cur < item_size) { 311ad7b0368SQu Wenruo u32 name_len; 312ad7b0368SQu Wenruo u32 data_len; 313ad7b0368SQu Wenruo u32 max_name_len; 314ad7b0368SQu Wenruo u32 total_size; 315ad7b0368SQu Wenruo u32 name_hash; 316ad7b0368SQu Wenruo u8 dir_type; 317ad7b0368SQu Wenruo 318ad7b0368SQu Wenruo /* header itself should not cross item boundary */ 319ad7b0368SQu Wenruo if (cur + sizeof(*di) > item_size) { 320d98ced68SDavid Sterba dir_item_err(leaf, slot, 3217cfad652SArnd Bergmann "dir item header crosses item boundary, have %zu boundary %u", 322ad7b0368SQu Wenruo cur + sizeof(*di), item_size); 323ad7b0368SQu Wenruo return -EUCLEAN; 324ad7b0368SQu Wenruo } 325ad7b0368SQu Wenruo 326ad7b0368SQu Wenruo /* dir type check */ 327ad7b0368SQu Wenruo dir_type = btrfs_dir_type(leaf, di); 328ad7b0368SQu Wenruo if (dir_type >= BTRFS_FT_MAX) { 329d98ced68SDavid Sterba dir_item_err(leaf, slot, 330ad7b0368SQu Wenruo "invalid dir item type, have %u expect [0, %u)", 331ad7b0368SQu Wenruo dir_type, BTRFS_FT_MAX); 332ad7b0368SQu Wenruo return -EUCLEAN; 333ad7b0368SQu Wenruo } 334ad7b0368SQu Wenruo 335ad7b0368SQu Wenruo if (key->type == BTRFS_XATTR_ITEM_KEY && 336ad7b0368SQu Wenruo dir_type != BTRFS_FT_XATTR) { 337d98ced68SDavid Sterba dir_item_err(leaf, slot, 338ad7b0368SQu Wenruo "invalid dir item type for XATTR key, have %u expect %u", 339ad7b0368SQu Wenruo dir_type, BTRFS_FT_XATTR); 340ad7b0368SQu Wenruo return -EUCLEAN; 341ad7b0368SQu Wenruo } 342ad7b0368SQu Wenruo if (dir_type == BTRFS_FT_XATTR && 343ad7b0368SQu Wenruo key->type != BTRFS_XATTR_ITEM_KEY) { 344d98ced68SDavid Sterba dir_item_err(leaf, slot, 345ad7b0368SQu Wenruo "xattr dir type found for non-XATTR key"); 346ad7b0368SQu Wenruo return -EUCLEAN; 347ad7b0368SQu Wenruo } 348ad7b0368SQu Wenruo if (dir_type == BTRFS_FT_XATTR) 349ad7b0368SQu Wenruo max_name_len = XATTR_NAME_MAX; 350ad7b0368SQu Wenruo else 351ad7b0368SQu Wenruo max_name_len = BTRFS_NAME_LEN; 352ad7b0368SQu Wenruo 353ad7b0368SQu Wenruo /* Name/data length check */ 354ad7b0368SQu Wenruo name_len = btrfs_dir_name_len(leaf, di); 355ad7b0368SQu Wenruo data_len = btrfs_dir_data_len(leaf, di); 356ad7b0368SQu Wenruo if (name_len > max_name_len) { 357d98ced68SDavid Sterba dir_item_err(leaf, slot, 358ad7b0368SQu Wenruo "dir item name len too long, have %u max %u", 359ad7b0368SQu Wenruo name_len, max_name_len); 360ad7b0368SQu Wenruo return -EUCLEAN; 361ad7b0368SQu Wenruo } 3622f659546SQu Wenruo if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(fs_info)) { 363d98ced68SDavid Sterba dir_item_err(leaf, slot, 364ad7b0368SQu Wenruo "dir item name and data len too long, have %u max %u", 365ad7b0368SQu Wenruo name_len + data_len, 3662f659546SQu Wenruo BTRFS_MAX_XATTR_SIZE(fs_info)); 367ad7b0368SQu Wenruo return -EUCLEAN; 368ad7b0368SQu Wenruo } 369ad7b0368SQu Wenruo 370ad7b0368SQu Wenruo if (data_len && dir_type != BTRFS_FT_XATTR) { 371d98ced68SDavid Sterba dir_item_err(leaf, slot, 372ad7b0368SQu Wenruo "dir item with invalid data len, have %u expect 0", 373ad7b0368SQu Wenruo data_len); 374ad7b0368SQu Wenruo return -EUCLEAN; 375ad7b0368SQu Wenruo } 376ad7b0368SQu Wenruo 377ad7b0368SQu Wenruo total_size = sizeof(*di) + name_len + data_len; 378ad7b0368SQu Wenruo 379ad7b0368SQu Wenruo /* header and name/data should not cross item boundary */ 380ad7b0368SQu Wenruo if (cur + total_size > item_size) { 381d98ced68SDavid Sterba dir_item_err(leaf, slot, 382ad7b0368SQu Wenruo "dir item data crosses item boundary, have %u boundary %u", 383ad7b0368SQu Wenruo cur + total_size, item_size); 384ad7b0368SQu Wenruo return -EUCLEAN; 385ad7b0368SQu Wenruo } 386ad7b0368SQu Wenruo 387ad7b0368SQu Wenruo /* 388ad7b0368SQu Wenruo * Special check for XATTR/DIR_ITEM, as key->offset is name 389ad7b0368SQu Wenruo * hash, should match its name 390ad7b0368SQu Wenruo */ 391ad7b0368SQu Wenruo if (key->type == BTRFS_DIR_ITEM_KEY || 392ad7b0368SQu Wenruo key->type == BTRFS_XATTR_ITEM_KEY) { 393e2683fc9SDavid Sterba char namebuf[max(BTRFS_NAME_LEN, XATTR_NAME_MAX)]; 394e2683fc9SDavid Sterba 395ad7b0368SQu Wenruo read_extent_buffer(leaf, namebuf, 396ad7b0368SQu Wenruo (unsigned long)(di + 1), name_len); 397ad7b0368SQu Wenruo name_hash = btrfs_name_hash(namebuf, name_len); 398ad7b0368SQu Wenruo if (key->offset != name_hash) { 399d98ced68SDavid Sterba dir_item_err(leaf, slot, 400ad7b0368SQu Wenruo "name hash mismatch with key, have 0x%016x expect 0x%016llx", 401ad7b0368SQu Wenruo name_hash, key->offset); 402ad7b0368SQu Wenruo return -EUCLEAN; 403ad7b0368SQu Wenruo } 404ad7b0368SQu Wenruo } 405ad7b0368SQu Wenruo cur += total_size; 406ad7b0368SQu Wenruo di = (struct btrfs_dir_item *)((void *)di + total_size); 407ad7b0368SQu Wenruo } 408ad7b0368SQu Wenruo return 0; 409ad7b0368SQu Wenruo } 410ad7b0368SQu Wenruo 4114806bd88SDavid Sterba __printf(3, 4) 412fce466eaSQu Wenruo __cold 4134806bd88SDavid Sterba static void block_group_err(const struct extent_buffer *eb, int slot, 414fce466eaSQu Wenruo const char *fmt, ...) 415fce466eaSQu Wenruo { 4164806bd88SDavid Sterba const struct btrfs_fs_info *fs_info = eb->fs_info; 417fce466eaSQu Wenruo struct btrfs_key key; 418fce466eaSQu Wenruo struct va_format vaf; 419fce466eaSQu Wenruo va_list args; 420fce466eaSQu Wenruo 421fce466eaSQu Wenruo btrfs_item_key_to_cpu(eb, &key, slot); 422fce466eaSQu Wenruo va_start(args, fmt); 423fce466eaSQu Wenruo 424fce466eaSQu Wenruo vaf.fmt = fmt; 425fce466eaSQu Wenruo vaf.va = &args; 426fce466eaSQu Wenruo 427fce466eaSQu Wenruo btrfs_crit(fs_info, 428fce466eaSQu Wenruo "corrupt %s: root=%llu block=%llu slot=%d bg_start=%llu bg_len=%llu, %pV", 429fce466eaSQu Wenruo btrfs_header_level(eb) == 0 ? "leaf" : "node", 430fce466eaSQu Wenruo btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot, 431fce466eaSQu Wenruo key.objectid, key.offset, &vaf); 432fce466eaSQu Wenruo va_end(args); 433fce466eaSQu Wenruo } 434fce466eaSQu Wenruo 435af60ce2bSDavid Sterba static int check_block_group_item(struct extent_buffer *leaf, 436fce466eaSQu Wenruo struct btrfs_key *key, int slot) 437fce466eaSQu Wenruo { 438fce466eaSQu Wenruo struct btrfs_block_group_item bgi; 439fce466eaSQu Wenruo u32 item_size = btrfs_item_size_nr(leaf, slot); 440fce466eaSQu Wenruo u64 flags; 441fce466eaSQu Wenruo u64 type; 442fce466eaSQu Wenruo 443fce466eaSQu Wenruo /* 444fce466eaSQu Wenruo * Here we don't really care about alignment since extent allocator can 44510950929SQu Wenruo * handle it. We care more about the size. 446fce466eaSQu Wenruo */ 44710950929SQu Wenruo if (key->offset == 0) { 4484806bd88SDavid Sterba block_group_err(leaf, slot, 44910950929SQu Wenruo "invalid block group size 0"); 450fce466eaSQu Wenruo return -EUCLEAN; 451fce466eaSQu Wenruo } 452fce466eaSQu Wenruo 453fce466eaSQu Wenruo if (item_size != sizeof(bgi)) { 4544806bd88SDavid Sterba block_group_err(leaf, slot, 455fce466eaSQu Wenruo "invalid item size, have %u expect %zu", 456fce466eaSQu Wenruo item_size, sizeof(bgi)); 457fce466eaSQu Wenruo return -EUCLEAN; 458fce466eaSQu Wenruo } 459fce466eaSQu Wenruo 460fce466eaSQu Wenruo read_extent_buffer(leaf, &bgi, btrfs_item_ptr_offset(leaf, slot), 461fce466eaSQu Wenruo sizeof(bgi)); 462fce466eaSQu Wenruo if (btrfs_block_group_chunk_objectid(&bgi) != 463fce466eaSQu Wenruo BTRFS_FIRST_CHUNK_TREE_OBJECTID) { 4644806bd88SDavid Sterba block_group_err(leaf, slot, 465fce466eaSQu Wenruo "invalid block group chunk objectid, have %llu expect %llu", 466fce466eaSQu Wenruo btrfs_block_group_chunk_objectid(&bgi), 467fce466eaSQu Wenruo BTRFS_FIRST_CHUNK_TREE_OBJECTID); 468fce466eaSQu Wenruo return -EUCLEAN; 469fce466eaSQu Wenruo } 470fce466eaSQu Wenruo 471fce466eaSQu Wenruo if (btrfs_block_group_used(&bgi) > key->offset) { 4724806bd88SDavid Sterba block_group_err(leaf, slot, 473fce466eaSQu Wenruo "invalid block group used, have %llu expect [0, %llu)", 474fce466eaSQu Wenruo btrfs_block_group_used(&bgi), key->offset); 475fce466eaSQu Wenruo return -EUCLEAN; 476fce466eaSQu Wenruo } 477fce466eaSQu Wenruo 478fce466eaSQu Wenruo flags = btrfs_block_group_flags(&bgi); 479fce466eaSQu Wenruo if (hweight64(flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) > 1) { 4804806bd88SDavid Sterba block_group_err(leaf, slot, 481fce466eaSQu Wenruo "invalid profile flags, have 0x%llx (%lu bits set) expect no more than 1 bit set", 482fce466eaSQu Wenruo flags & BTRFS_BLOCK_GROUP_PROFILE_MASK, 483fce466eaSQu Wenruo hweight64(flags & BTRFS_BLOCK_GROUP_PROFILE_MASK)); 484fce466eaSQu Wenruo return -EUCLEAN; 485fce466eaSQu Wenruo } 486fce466eaSQu Wenruo 487fce466eaSQu Wenruo type = flags & BTRFS_BLOCK_GROUP_TYPE_MASK; 488fce466eaSQu Wenruo if (type != BTRFS_BLOCK_GROUP_DATA && 489fce466eaSQu Wenruo type != BTRFS_BLOCK_GROUP_METADATA && 490fce466eaSQu Wenruo type != BTRFS_BLOCK_GROUP_SYSTEM && 491fce466eaSQu Wenruo type != (BTRFS_BLOCK_GROUP_METADATA | 492fce466eaSQu Wenruo BTRFS_BLOCK_GROUP_DATA)) { 4934806bd88SDavid Sterba block_group_err(leaf, slot, 494761333f2SShaokun Zhang "invalid type, have 0x%llx (%lu bits set) expect either 0x%llx, 0x%llx, 0x%llx or 0x%llx", 495fce466eaSQu Wenruo type, hweight64(type), 496fce466eaSQu Wenruo BTRFS_BLOCK_GROUP_DATA, BTRFS_BLOCK_GROUP_METADATA, 497fce466eaSQu Wenruo BTRFS_BLOCK_GROUP_SYSTEM, 498fce466eaSQu Wenruo BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA); 499fce466eaSQu Wenruo return -EUCLEAN; 500fce466eaSQu Wenruo } 501fce466eaSQu Wenruo return 0; 502fce466eaSQu Wenruo } 503fce466eaSQu Wenruo 504d001e4a3SDavid Sterba __printf(4, 5) 505f1140243SQu Wenruo __cold 506d001e4a3SDavid Sterba static void chunk_err(const struct extent_buffer *leaf, 507f1140243SQu Wenruo const struct btrfs_chunk *chunk, u64 logical, 508f1140243SQu Wenruo const char *fmt, ...) 509f1140243SQu Wenruo { 510d001e4a3SDavid Sterba const struct btrfs_fs_info *fs_info = leaf->fs_info; 511f1140243SQu Wenruo bool is_sb; 512f1140243SQu Wenruo struct va_format vaf; 513f1140243SQu Wenruo va_list args; 514f1140243SQu Wenruo int i; 515f1140243SQu Wenruo int slot = -1; 516f1140243SQu Wenruo 517f1140243SQu Wenruo /* Only superblock eb is able to have such small offset */ 518f1140243SQu Wenruo is_sb = (leaf->start == BTRFS_SUPER_INFO_OFFSET); 519f1140243SQu Wenruo 520f1140243SQu Wenruo if (!is_sb) { 521f1140243SQu Wenruo /* 522f1140243SQu Wenruo * Get the slot number by iterating through all slots, this 523f1140243SQu Wenruo * would provide better readability. 524f1140243SQu Wenruo */ 525f1140243SQu Wenruo for (i = 0; i < btrfs_header_nritems(leaf); i++) { 526f1140243SQu Wenruo if (btrfs_item_ptr_offset(leaf, i) == 527f1140243SQu Wenruo (unsigned long)chunk) { 528f1140243SQu Wenruo slot = i; 529f1140243SQu Wenruo break; 530f1140243SQu Wenruo } 531f1140243SQu Wenruo } 532f1140243SQu Wenruo } 533f1140243SQu Wenruo va_start(args, fmt); 534f1140243SQu Wenruo vaf.fmt = fmt; 535f1140243SQu Wenruo vaf.va = &args; 536f1140243SQu Wenruo 537f1140243SQu Wenruo if (is_sb) 538f1140243SQu Wenruo btrfs_crit(fs_info, 539f1140243SQu Wenruo "corrupt superblock syschunk array: chunk_start=%llu, %pV", 540f1140243SQu Wenruo logical, &vaf); 541f1140243SQu Wenruo else 542f1140243SQu Wenruo btrfs_crit(fs_info, 543f1140243SQu Wenruo "corrupt leaf: root=%llu block=%llu slot=%d chunk_start=%llu, %pV", 544f1140243SQu Wenruo BTRFS_CHUNK_TREE_OBJECTID, leaf->start, slot, 545f1140243SQu Wenruo logical, &vaf); 546f1140243SQu Wenruo va_end(args); 547f1140243SQu Wenruo } 548f1140243SQu Wenruo 549ad7b0368SQu Wenruo /* 55082fc28fbSQu Wenruo * The common chunk check which could also work on super block sys chunk array. 55182fc28fbSQu Wenruo * 552bf871c3bSQu Wenruo * Return -EUCLEAN if anything is corrupted. 55382fc28fbSQu Wenruo * Return 0 if everything is OK. 55482fc28fbSQu Wenruo */ 555ddaf1d5aSDavid Sterba int btrfs_check_chunk_valid(struct extent_buffer *leaf, 55682fc28fbSQu Wenruo struct btrfs_chunk *chunk, u64 logical) 55782fc28fbSQu Wenruo { 558ddaf1d5aSDavid Sterba struct btrfs_fs_info *fs_info = leaf->fs_info; 55982fc28fbSQu Wenruo u64 length; 56082fc28fbSQu Wenruo u64 stripe_len; 56182fc28fbSQu Wenruo u16 num_stripes; 56282fc28fbSQu Wenruo u16 sub_stripes; 56382fc28fbSQu Wenruo u64 type; 56482fc28fbSQu Wenruo u64 features; 56582fc28fbSQu Wenruo bool mixed = false; 56682fc28fbSQu Wenruo 56782fc28fbSQu Wenruo length = btrfs_chunk_length(leaf, chunk); 56882fc28fbSQu Wenruo stripe_len = btrfs_chunk_stripe_len(leaf, chunk); 56982fc28fbSQu Wenruo num_stripes = btrfs_chunk_num_stripes(leaf, chunk); 57082fc28fbSQu Wenruo sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk); 57182fc28fbSQu Wenruo type = btrfs_chunk_type(leaf, chunk); 57282fc28fbSQu Wenruo 57382fc28fbSQu Wenruo if (!num_stripes) { 574d001e4a3SDavid Sterba chunk_err(leaf, chunk, logical, 575f1140243SQu Wenruo "invalid chunk num_stripes, have %u", num_stripes); 576bf871c3bSQu Wenruo return -EUCLEAN; 57782fc28fbSQu Wenruo } 57882fc28fbSQu Wenruo if (!IS_ALIGNED(logical, fs_info->sectorsize)) { 579d001e4a3SDavid Sterba chunk_err(leaf, chunk, logical, 580f1140243SQu Wenruo "invalid chunk logical, have %llu should aligned to %u", 581f1140243SQu Wenruo logical, fs_info->sectorsize); 582bf871c3bSQu Wenruo return -EUCLEAN; 58382fc28fbSQu Wenruo } 58482fc28fbSQu Wenruo if (btrfs_chunk_sector_size(leaf, chunk) != fs_info->sectorsize) { 585d001e4a3SDavid Sterba chunk_err(leaf, chunk, logical, 586f1140243SQu Wenruo "invalid chunk sectorsize, have %u expect %u", 587f1140243SQu Wenruo btrfs_chunk_sector_size(leaf, chunk), 588f1140243SQu Wenruo fs_info->sectorsize); 589bf871c3bSQu Wenruo return -EUCLEAN; 59082fc28fbSQu Wenruo } 59182fc28fbSQu Wenruo if (!length || !IS_ALIGNED(length, fs_info->sectorsize)) { 592d001e4a3SDavid Sterba chunk_err(leaf, chunk, logical, 593f1140243SQu Wenruo "invalid chunk length, have %llu", length); 594bf871c3bSQu Wenruo return -EUCLEAN; 59582fc28fbSQu Wenruo } 59682fc28fbSQu Wenruo if (!is_power_of_2(stripe_len) || stripe_len != BTRFS_STRIPE_LEN) { 597d001e4a3SDavid Sterba chunk_err(leaf, chunk, logical, 598f1140243SQu Wenruo "invalid chunk stripe length: %llu", 59982fc28fbSQu Wenruo stripe_len); 600bf871c3bSQu Wenruo return -EUCLEAN; 60182fc28fbSQu Wenruo } 60282fc28fbSQu Wenruo if (~(BTRFS_BLOCK_GROUP_TYPE_MASK | BTRFS_BLOCK_GROUP_PROFILE_MASK) & 60382fc28fbSQu Wenruo type) { 604d001e4a3SDavid Sterba chunk_err(leaf, chunk, logical, 605f1140243SQu Wenruo "unrecognized chunk type: 0x%llx", 60682fc28fbSQu Wenruo ~(BTRFS_BLOCK_GROUP_TYPE_MASK | 60782fc28fbSQu Wenruo BTRFS_BLOCK_GROUP_PROFILE_MASK) & 60882fc28fbSQu Wenruo btrfs_chunk_type(leaf, chunk)); 609bf871c3bSQu Wenruo return -EUCLEAN; 61082fc28fbSQu Wenruo } 61182fc28fbSQu Wenruo 61280e46cf2SQu Wenruo if (!is_power_of_2(type & BTRFS_BLOCK_GROUP_PROFILE_MASK) && 61380e46cf2SQu Wenruo (type & BTRFS_BLOCK_GROUP_PROFILE_MASK) != 0) { 614d001e4a3SDavid Sterba chunk_err(leaf, chunk, logical, 61580e46cf2SQu Wenruo "invalid chunk profile flag: 0x%llx, expect 0 or 1 bit set", 61680e46cf2SQu Wenruo type & BTRFS_BLOCK_GROUP_PROFILE_MASK); 61780e46cf2SQu Wenruo return -EUCLEAN; 61880e46cf2SQu Wenruo } 61982fc28fbSQu Wenruo if ((type & BTRFS_BLOCK_GROUP_TYPE_MASK) == 0) { 620d001e4a3SDavid Sterba chunk_err(leaf, chunk, logical, 621f1140243SQu Wenruo "missing chunk type flag, have 0x%llx one bit must be set in 0x%llx", 622f1140243SQu Wenruo type, BTRFS_BLOCK_GROUP_TYPE_MASK); 623bf871c3bSQu Wenruo return -EUCLEAN; 62482fc28fbSQu Wenruo } 62582fc28fbSQu Wenruo 62682fc28fbSQu Wenruo if ((type & BTRFS_BLOCK_GROUP_SYSTEM) && 62782fc28fbSQu Wenruo (type & (BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA))) { 628d001e4a3SDavid Sterba chunk_err(leaf, chunk, logical, 629f1140243SQu Wenruo "system chunk with data or metadata type: 0x%llx", 630f1140243SQu Wenruo type); 631bf871c3bSQu Wenruo return -EUCLEAN; 63282fc28fbSQu Wenruo } 63382fc28fbSQu Wenruo 63482fc28fbSQu Wenruo features = btrfs_super_incompat_flags(fs_info->super_copy); 63582fc28fbSQu Wenruo if (features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) 63682fc28fbSQu Wenruo mixed = true; 63782fc28fbSQu Wenruo 63882fc28fbSQu Wenruo if (!mixed) { 63982fc28fbSQu Wenruo if ((type & BTRFS_BLOCK_GROUP_METADATA) && 64082fc28fbSQu Wenruo (type & BTRFS_BLOCK_GROUP_DATA)) { 641d001e4a3SDavid Sterba chunk_err(leaf, chunk, logical, 64282fc28fbSQu Wenruo "mixed chunk type in non-mixed mode: 0x%llx", type); 643bf871c3bSQu Wenruo return -EUCLEAN; 64482fc28fbSQu Wenruo } 64582fc28fbSQu Wenruo } 64682fc28fbSQu Wenruo 64782fc28fbSQu Wenruo if ((type & BTRFS_BLOCK_GROUP_RAID10 && sub_stripes != 2) || 64882fc28fbSQu Wenruo (type & BTRFS_BLOCK_GROUP_RAID1 && num_stripes != 2) || 64982fc28fbSQu Wenruo (type & BTRFS_BLOCK_GROUP_RAID5 && num_stripes < 2) || 65082fc28fbSQu Wenruo (type & BTRFS_BLOCK_GROUP_RAID6 && num_stripes < 3) || 65182fc28fbSQu Wenruo (type & BTRFS_BLOCK_GROUP_DUP && num_stripes != 2) || 65282fc28fbSQu Wenruo ((type & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0 && num_stripes != 1)) { 653d001e4a3SDavid Sterba chunk_err(leaf, chunk, logical, 65482fc28fbSQu Wenruo "invalid num_stripes:sub_stripes %u:%u for profile %llu", 65582fc28fbSQu Wenruo num_stripes, sub_stripes, 65682fc28fbSQu Wenruo type & BTRFS_BLOCK_GROUP_PROFILE_MASK); 657bf871c3bSQu Wenruo return -EUCLEAN; 65882fc28fbSQu Wenruo } 65982fc28fbSQu Wenruo 66082fc28fbSQu Wenruo return 0; 66182fc28fbSQu Wenruo } 66282fc28fbSQu Wenruo 6635617ed80SDavid Sterba __printf(3, 4) 664ab4ba2e1SQu Wenruo __cold 6655617ed80SDavid Sterba static void dev_item_err(const struct extent_buffer *eb, int slot, 666ab4ba2e1SQu Wenruo const char *fmt, ...) 667ab4ba2e1SQu Wenruo { 668ab4ba2e1SQu Wenruo struct btrfs_key key; 669ab4ba2e1SQu Wenruo struct va_format vaf; 670ab4ba2e1SQu Wenruo va_list args; 671ab4ba2e1SQu Wenruo 672ab4ba2e1SQu Wenruo btrfs_item_key_to_cpu(eb, &key, slot); 673ab4ba2e1SQu Wenruo va_start(args, fmt); 674ab4ba2e1SQu Wenruo 675ab4ba2e1SQu Wenruo vaf.fmt = fmt; 676ab4ba2e1SQu Wenruo vaf.va = &args; 677ab4ba2e1SQu Wenruo 6785617ed80SDavid Sterba btrfs_crit(eb->fs_info, 679ab4ba2e1SQu Wenruo "corrupt %s: root=%llu block=%llu slot=%d devid=%llu %pV", 680ab4ba2e1SQu Wenruo btrfs_header_level(eb) == 0 ? "leaf" : "node", 681ab4ba2e1SQu Wenruo btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot, 682ab4ba2e1SQu Wenruo key.objectid, &vaf); 683ab4ba2e1SQu Wenruo va_end(args); 684ab4ba2e1SQu Wenruo } 685ab4ba2e1SQu Wenruo 686412a2312SDavid Sterba static int check_dev_item(struct extent_buffer *leaf, 687ab4ba2e1SQu Wenruo struct btrfs_key *key, int slot) 688ab4ba2e1SQu Wenruo { 689412a2312SDavid Sterba struct btrfs_fs_info *fs_info = leaf->fs_info; 690ab4ba2e1SQu Wenruo struct btrfs_dev_item *ditem; 691ab4ba2e1SQu Wenruo u64 max_devid = max(BTRFS_MAX_DEVS(fs_info), BTRFS_MAX_DEVS_SYS_CHUNK); 692ab4ba2e1SQu Wenruo 693ab4ba2e1SQu Wenruo if (key->objectid != BTRFS_DEV_ITEMS_OBJECTID) { 6945617ed80SDavid Sterba dev_item_err(leaf, slot, 695ab4ba2e1SQu Wenruo "invalid objectid: has=%llu expect=%llu", 696ab4ba2e1SQu Wenruo key->objectid, BTRFS_DEV_ITEMS_OBJECTID); 697ab4ba2e1SQu Wenruo return -EUCLEAN; 698ab4ba2e1SQu Wenruo } 699ab4ba2e1SQu Wenruo if (key->offset > max_devid) { 7005617ed80SDavid Sterba dev_item_err(leaf, slot, 701ab4ba2e1SQu Wenruo "invalid devid: has=%llu expect=[0, %llu]", 702ab4ba2e1SQu Wenruo key->offset, max_devid); 703ab4ba2e1SQu Wenruo return -EUCLEAN; 704ab4ba2e1SQu Wenruo } 705ab4ba2e1SQu Wenruo ditem = btrfs_item_ptr(leaf, slot, struct btrfs_dev_item); 706ab4ba2e1SQu Wenruo if (btrfs_device_id(leaf, ditem) != key->offset) { 7075617ed80SDavid Sterba dev_item_err(leaf, slot, 708ab4ba2e1SQu Wenruo "devid mismatch: key has=%llu item has=%llu", 709ab4ba2e1SQu Wenruo key->offset, btrfs_device_id(leaf, ditem)); 710ab4ba2e1SQu Wenruo return -EUCLEAN; 711ab4ba2e1SQu Wenruo } 712ab4ba2e1SQu Wenruo 713ab4ba2e1SQu Wenruo /* 714ab4ba2e1SQu Wenruo * For device total_bytes, we don't have reliable way to check it, as 715ab4ba2e1SQu Wenruo * it can be 0 for device removal. Device size check can only be done 716ab4ba2e1SQu Wenruo * by dev extents check. 717ab4ba2e1SQu Wenruo */ 718ab4ba2e1SQu Wenruo if (btrfs_device_bytes_used(leaf, ditem) > 719ab4ba2e1SQu Wenruo btrfs_device_total_bytes(leaf, ditem)) { 7205617ed80SDavid Sterba dev_item_err(leaf, slot, 721ab4ba2e1SQu Wenruo "invalid bytes used: have %llu expect [0, %llu]", 722ab4ba2e1SQu Wenruo btrfs_device_bytes_used(leaf, ditem), 723ab4ba2e1SQu Wenruo btrfs_device_total_bytes(leaf, ditem)); 724ab4ba2e1SQu Wenruo return -EUCLEAN; 725ab4ba2e1SQu Wenruo } 726ab4ba2e1SQu Wenruo /* 727ab4ba2e1SQu Wenruo * Remaining members like io_align/type/gen/dev_group aren't really 728ab4ba2e1SQu Wenruo * utilized. Skip them to make later usage of them easier. 729ab4ba2e1SQu Wenruo */ 730ab4ba2e1SQu Wenruo return 0; 731ab4ba2e1SQu Wenruo } 732ab4ba2e1SQu Wenruo 733496245caSQu Wenruo /* Inode item error output has the same format as dir_item_err() */ 734496245caSQu Wenruo #define inode_item_err(fs_info, eb, slot, fmt, ...) \ 735d98ced68SDavid Sterba dir_item_err(eb, slot, fmt, __VA_ARGS__) 736496245caSQu Wenruo 73739e57f49SDavid Sterba static int check_inode_item(struct extent_buffer *leaf, 738496245caSQu Wenruo struct btrfs_key *key, int slot) 739496245caSQu Wenruo { 74039e57f49SDavid Sterba struct btrfs_fs_info *fs_info = leaf->fs_info; 741496245caSQu Wenruo struct btrfs_inode_item *iitem; 742496245caSQu Wenruo u64 super_gen = btrfs_super_generation(fs_info->super_copy); 743496245caSQu Wenruo u32 valid_mask = (S_IFMT | S_ISUID | S_ISGID | S_ISVTX | 0777); 744496245caSQu Wenruo u32 mode; 745496245caSQu Wenruo 746496245caSQu Wenruo if ((key->objectid < BTRFS_FIRST_FREE_OBJECTID || 747496245caSQu Wenruo key->objectid > BTRFS_LAST_FREE_OBJECTID) && 748496245caSQu Wenruo key->objectid != BTRFS_ROOT_TREE_DIR_OBJECTID && 749496245caSQu Wenruo key->objectid != BTRFS_FREE_INO_OBJECTID) { 75086a6be3aSDavid Sterba generic_err(leaf, slot, 751496245caSQu Wenruo "invalid key objectid: has %llu expect %llu or [%llu, %llu] or %llu", 752496245caSQu Wenruo key->objectid, BTRFS_ROOT_TREE_DIR_OBJECTID, 753496245caSQu Wenruo BTRFS_FIRST_FREE_OBJECTID, 754496245caSQu Wenruo BTRFS_LAST_FREE_OBJECTID, 755496245caSQu Wenruo BTRFS_FREE_INO_OBJECTID); 756496245caSQu Wenruo return -EUCLEAN; 757496245caSQu Wenruo } 758496245caSQu Wenruo if (key->offset != 0) { 759496245caSQu Wenruo inode_item_err(fs_info, leaf, slot, 760496245caSQu Wenruo "invalid key offset: has %llu expect 0", 761496245caSQu Wenruo key->offset); 762496245caSQu Wenruo return -EUCLEAN; 763496245caSQu Wenruo } 764496245caSQu Wenruo iitem = btrfs_item_ptr(leaf, slot, struct btrfs_inode_item); 765496245caSQu Wenruo 766496245caSQu Wenruo /* Here we use super block generation + 1 to handle log tree */ 767496245caSQu Wenruo if (btrfs_inode_generation(leaf, iitem) > super_gen + 1) { 768496245caSQu Wenruo inode_item_err(fs_info, leaf, slot, 769496245caSQu Wenruo "invalid inode generation: has %llu expect (0, %llu]", 770496245caSQu Wenruo btrfs_inode_generation(leaf, iitem), 771496245caSQu Wenruo super_gen + 1); 772496245caSQu Wenruo return -EUCLEAN; 773496245caSQu Wenruo } 774496245caSQu Wenruo /* Note for ROOT_TREE_DIR_ITEM, mkfs could set its transid 0 */ 775496245caSQu Wenruo if (btrfs_inode_transid(leaf, iitem) > super_gen + 1) { 776496245caSQu Wenruo inode_item_err(fs_info, leaf, slot, 777496245caSQu Wenruo "invalid inode generation: has %llu expect [0, %llu]", 778496245caSQu Wenruo btrfs_inode_transid(leaf, iitem), super_gen + 1); 779496245caSQu Wenruo return -EUCLEAN; 780496245caSQu Wenruo } 781496245caSQu Wenruo 782496245caSQu Wenruo /* 783496245caSQu Wenruo * For size and nbytes it's better not to be too strict, as for dir 784496245caSQu Wenruo * item its size/nbytes can easily get wrong, but doesn't affect 785496245caSQu Wenruo * anything in the fs. So here we skip the check. 786496245caSQu Wenruo */ 787496245caSQu Wenruo mode = btrfs_inode_mode(leaf, iitem); 788496245caSQu Wenruo if (mode & ~valid_mask) { 789496245caSQu Wenruo inode_item_err(fs_info, leaf, slot, 790496245caSQu Wenruo "unknown mode bit detected: 0x%x", 791496245caSQu Wenruo mode & ~valid_mask); 792496245caSQu Wenruo return -EUCLEAN; 793496245caSQu Wenruo } 794496245caSQu Wenruo 795496245caSQu Wenruo /* 796496245caSQu Wenruo * S_IFMT is not bit mapped so we can't completely rely on is_power_of_2, 797496245caSQu Wenruo * but is_power_of_2() can save us from checking FIFO/CHR/DIR/REG. 798496245caSQu Wenruo * Only needs to check BLK, LNK and SOCKS 799496245caSQu Wenruo */ 800496245caSQu Wenruo if (!is_power_of_2(mode & S_IFMT)) { 801496245caSQu Wenruo if (!S_ISLNK(mode) && !S_ISBLK(mode) && !S_ISSOCK(mode)) { 802496245caSQu Wenruo inode_item_err(fs_info, leaf, slot, 803496245caSQu Wenruo "invalid mode: has 0%o expect valid S_IF* bit(s)", 804496245caSQu Wenruo mode & S_IFMT); 805496245caSQu Wenruo return -EUCLEAN; 806496245caSQu Wenruo } 807496245caSQu Wenruo } 808496245caSQu Wenruo if (S_ISDIR(mode) && btrfs_inode_nlink(leaf, iitem) > 1) { 809496245caSQu Wenruo inode_item_err(fs_info, leaf, slot, 810496245caSQu Wenruo "invalid nlink: has %u expect no more than 1 for dir", 811496245caSQu Wenruo btrfs_inode_nlink(leaf, iitem)); 812496245caSQu Wenruo return -EUCLEAN; 813496245caSQu Wenruo } 814496245caSQu Wenruo if (btrfs_inode_flags(leaf, iitem) & ~BTRFS_INODE_FLAG_MASK) { 815496245caSQu Wenruo inode_item_err(fs_info, leaf, slot, 816496245caSQu Wenruo "unknown flags detected: 0x%llx", 817496245caSQu Wenruo btrfs_inode_flags(leaf, iitem) & 818496245caSQu Wenruo ~BTRFS_INODE_FLAG_MASK); 819496245caSQu Wenruo return -EUCLEAN; 820496245caSQu Wenruo } 821496245caSQu Wenruo return 0; 822496245caSQu Wenruo } 823496245caSQu Wenruo 824*259ee775SQu Wenruo static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key, 825*259ee775SQu Wenruo int slot) 826*259ee775SQu Wenruo { 827*259ee775SQu Wenruo struct btrfs_fs_info *fs_info = leaf->fs_info; 828*259ee775SQu Wenruo struct btrfs_root_item ri; 829*259ee775SQu Wenruo const u64 valid_root_flags = BTRFS_ROOT_SUBVOL_RDONLY | 830*259ee775SQu Wenruo BTRFS_ROOT_SUBVOL_DEAD; 831*259ee775SQu Wenruo 832*259ee775SQu Wenruo /* No such tree id */ 833*259ee775SQu Wenruo if (key->objectid == 0) { 834*259ee775SQu Wenruo generic_err(leaf, slot, "invalid root id 0"); 835*259ee775SQu Wenruo return -EUCLEAN; 836*259ee775SQu Wenruo } 837*259ee775SQu Wenruo 838*259ee775SQu Wenruo /* 839*259ee775SQu Wenruo * Some older kernel may create ROOT_ITEM with non-zero offset, so here 840*259ee775SQu Wenruo * we only check offset for reloc tree whose key->offset must be a 841*259ee775SQu Wenruo * valid tree. 842*259ee775SQu Wenruo */ 843*259ee775SQu Wenruo if (key->objectid == BTRFS_TREE_RELOC_OBJECTID && key->offset == 0) { 844*259ee775SQu Wenruo generic_err(leaf, slot, "invalid root id 0 for reloc tree"); 845*259ee775SQu Wenruo return -EUCLEAN; 846*259ee775SQu Wenruo } 847*259ee775SQu Wenruo 848*259ee775SQu Wenruo if (btrfs_item_size_nr(leaf, slot) != sizeof(ri)) { 849*259ee775SQu Wenruo generic_err(leaf, slot, 850*259ee775SQu Wenruo "invalid root item size, have %u expect %zu", 851*259ee775SQu Wenruo btrfs_item_size_nr(leaf, slot), sizeof(ri)); 852*259ee775SQu Wenruo } 853*259ee775SQu Wenruo 854*259ee775SQu Wenruo read_extent_buffer(leaf, &ri, btrfs_item_ptr_offset(leaf, slot), 855*259ee775SQu Wenruo sizeof(ri)); 856*259ee775SQu Wenruo 857*259ee775SQu Wenruo /* Generation related */ 858*259ee775SQu Wenruo if (btrfs_root_generation(&ri) > 859*259ee775SQu Wenruo btrfs_super_generation(fs_info->super_copy) + 1) { 860*259ee775SQu Wenruo generic_err(leaf, slot, 861*259ee775SQu Wenruo "invalid root generation, have %llu expect (0, %llu]", 862*259ee775SQu Wenruo btrfs_root_generation(&ri), 863*259ee775SQu Wenruo btrfs_super_generation(fs_info->super_copy) + 1); 864*259ee775SQu Wenruo return -EUCLEAN; 865*259ee775SQu Wenruo } 866*259ee775SQu Wenruo if (btrfs_root_generation_v2(&ri) > 867*259ee775SQu Wenruo btrfs_super_generation(fs_info->super_copy) + 1) { 868*259ee775SQu Wenruo generic_err(leaf, slot, 869*259ee775SQu Wenruo "invalid root v2 generation, have %llu expect (0, %llu]", 870*259ee775SQu Wenruo btrfs_root_generation_v2(&ri), 871*259ee775SQu Wenruo btrfs_super_generation(fs_info->super_copy) + 1); 872*259ee775SQu Wenruo return -EUCLEAN; 873*259ee775SQu Wenruo } 874*259ee775SQu Wenruo if (btrfs_root_last_snapshot(&ri) > 875*259ee775SQu Wenruo btrfs_super_generation(fs_info->super_copy) + 1) { 876*259ee775SQu Wenruo generic_err(leaf, slot, 877*259ee775SQu Wenruo "invalid root last_snapshot, have %llu expect (0, %llu]", 878*259ee775SQu Wenruo btrfs_root_last_snapshot(&ri), 879*259ee775SQu Wenruo btrfs_super_generation(fs_info->super_copy) + 1); 880*259ee775SQu Wenruo return -EUCLEAN; 881*259ee775SQu Wenruo } 882*259ee775SQu Wenruo 883*259ee775SQu Wenruo /* Alignment and level check */ 884*259ee775SQu Wenruo if (!IS_ALIGNED(btrfs_root_bytenr(&ri), fs_info->sectorsize)) { 885*259ee775SQu Wenruo generic_err(leaf, slot, 886*259ee775SQu Wenruo "invalid root bytenr, have %llu expect to be aligned to %u", 887*259ee775SQu Wenruo btrfs_root_bytenr(&ri), fs_info->sectorsize); 888*259ee775SQu Wenruo return -EUCLEAN; 889*259ee775SQu Wenruo } 890*259ee775SQu Wenruo if (btrfs_root_level(&ri) >= BTRFS_MAX_LEVEL) { 891*259ee775SQu Wenruo generic_err(leaf, slot, 892*259ee775SQu Wenruo "invalid root level, have %u expect [0, %u]", 893*259ee775SQu Wenruo btrfs_root_level(&ri), BTRFS_MAX_LEVEL - 1); 894*259ee775SQu Wenruo return -EUCLEAN; 895*259ee775SQu Wenruo } 896*259ee775SQu Wenruo if (ri.drop_level >= BTRFS_MAX_LEVEL) { 897*259ee775SQu Wenruo generic_err(leaf, slot, 898*259ee775SQu Wenruo "invalid root level, have %u expect [0, %u]", 899*259ee775SQu Wenruo ri.drop_level, BTRFS_MAX_LEVEL - 1); 900*259ee775SQu Wenruo return -EUCLEAN; 901*259ee775SQu Wenruo } 902*259ee775SQu Wenruo 903*259ee775SQu Wenruo /* Flags check */ 904*259ee775SQu Wenruo if (btrfs_root_flags(&ri) & ~valid_root_flags) { 905*259ee775SQu Wenruo generic_err(leaf, slot, 906*259ee775SQu Wenruo "invalid root flags, have 0x%llx expect mask 0x%llx", 907*259ee775SQu Wenruo btrfs_root_flags(&ri), valid_root_flags); 908*259ee775SQu Wenruo return -EUCLEAN; 909*259ee775SQu Wenruo } 910*259ee775SQu Wenruo return 0; 911*259ee775SQu Wenruo } 912*259ee775SQu Wenruo 91382fc28fbSQu Wenruo /* 914557ea5ddSQu Wenruo * Common point to switch the item-specific validation. 915557ea5ddSQu Wenruo */ 9160076bc89SDavid Sterba static int check_leaf_item(struct extent_buffer *leaf, 9174e9845efSFilipe Manana struct btrfs_key *key, int slot, 9184e9845efSFilipe Manana struct btrfs_key *prev_key) 919557ea5ddSQu Wenruo { 920557ea5ddSQu Wenruo int ret = 0; 921075cb3c7SQu Wenruo struct btrfs_chunk *chunk; 922557ea5ddSQu Wenruo 923557ea5ddSQu Wenruo switch (key->type) { 924557ea5ddSQu Wenruo case BTRFS_EXTENT_DATA_KEY: 9254e9845efSFilipe Manana ret = check_extent_data_item(leaf, key, slot, prev_key); 926557ea5ddSQu Wenruo break; 927557ea5ddSQu Wenruo case BTRFS_EXTENT_CSUM_KEY: 92868128ce7SDavid Sterba ret = check_csum_item(leaf, key, slot); 929557ea5ddSQu Wenruo break; 930ad7b0368SQu Wenruo case BTRFS_DIR_ITEM_KEY: 931ad7b0368SQu Wenruo case BTRFS_DIR_INDEX_KEY: 932ad7b0368SQu Wenruo case BTRFS_XATTR_ITEM_KEY: 933ce4252c0SDavid Sterba ret = check_dir_item(leaf, key, slot); 934ad7b0368SQu Wenruo break; 935fce466eaSQu Wenruo case BTRFS_BLOCK_GROUP_ITEM_KEY: 936af60ce2bSDavid Sterba ret = check_block_group_item(leaf, key, slot); 937fce466eaSQu Wenruo break; 938075cb3c7SQu Wenruo case BTRFS_CHUNK_ITEM_KEY: 939075cb3c7SQu Wenruo chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk); 940ddaf1d5aSDavid Sterba ret = btrfs_check_chunk_valid(leaf, chunk, key->offset); 941075cb3c7SQu Wenruo break; 942ab4ba2e1SQu Wenruo case BTRFS_DEV_ITEM_KEY: 943412a2312SDavid Sterba ret = check_dev_item(leaf, key, slot); 944ab4ba2e1SQu Wenruo break; 945496245caSQu Wenruo case BTRFS_INODE_ITEM_KEY: 94639e57f49SDavid Sterba ret = check_inode_item(leaf, key, slot); 947496245caSQu Wenruo break; 948*259ee775SQu Wenruo case BTRFS_ROOT_ITEM_KEY: 949*259ee775SQu Wenruo ret = check_root_item(leaf, key, slot); 950*259ee775SQu Wenruo break; 951557ea5ddSQu Wenruo } 952557ea5ddSQu Wenruo return ret; 953557ea5ddSQu Wenruo } 954557ea5ddSQu Wenruo 955e2ccd361SDavid Sterba static int check_leaf(struct extent_buffer *leaf, bool check_item_data) 956557ea5ddSQu Wenruo { 957e2ccd361SDavid Sterba struct btrfs_fs_info *fs_info = leaf->fs_info; 958557ea5ddSQu Wenruo /* No valid key type is 0, so all key should be larger than this key */ 959557ea5ddSQu Wenruo struct btrfs_key prev_key = {0, 0, 0}; 960557ea5ddSQu Wenruo struct btrfs_key key; 961557ea5ddSQu Wenruo u32 nritems = btrfs_header_nritems(leaf); 962557ea5ddSQu Wenruo int slot; 963557ea5ddSQu Wenruo 964f556faa4SQu Wenruo if (btrfs_header_level(leaf) != 0) { 96586a6be3aSDavid Sterba generic_err(leaf, 0, 966f556faa4SQu Wenruo "invalid level for leaf, have %d expect 0", 967f556faa4SQu Wenruo btrfs_header_level(leaf)); 968f556faa4SQu Wenruo return -EUCLEAN; 969f556faa4SQu Wenruo } 970f556faa4SQu Wenruo 971557ea5ddSQu Wenruo /* 972557ea5ddSQu Wenruo * Extent buffers from a relocation tree have a owner field that 973557ea5ddSQu Wenruo * corresponds to the subvolume tree they are based on. So just from an 974557ea5ddSQu Wenruo * extent buffer alone we can not find out what is the id of the 975557ea5ddSQu Wenruo * corresponding subvolume tree, so we can not figure out if the extent 976557ea5ddSQu Wenruo * buffer corresponds to the root of the relocation tree or not. So 977557ea5ddSQu Wenruo * skip this check for relocation trees. 978557ea5ddSQu Wenruo */ 979557ea5ddSQu Wenruo if (nritems == 0 && !btrfs_header_flag(leaf, BTRFS_HEADER_FLAG_RELOC)) { 980ba480dd4SQu Wenruo u64 owner = btrfs_header_owner(leaf); 981557ea5ddSQu Wenruo 982ba480dd4SQu Wenruo /* These trees must never be empty */ 983ba480dd4SQu Wenruo if (owner == BTRFS_ROOT_TREE_OBJECTID || 984ba480dd4SQu Wenruo owner == BTRFS_CHUNK_TREE_OBJECTID || 985ba480dd4SQu Wenruo owner == BTRFS_EXTENT_TREE_OBJECTID || 986ba480dd4SQu Wenruo owner == BTRFS_DEV_TREE_OBJECTID || 987ba480dd4SQu Wenruo owner == BTRFS_FS_TREE_OBJECTID || 988ba480dd4SQu Wenruo owner == BTRFS_DATA_RELOC_TREE_OBJECTID) { 98986a6be3aSDavid Sterba generic_err(leaf, 0, 990ba480dd4SQu Wenruo "invalid root, root %llu must never be empty", 991ba480dd4SQu Wenruo owner); 992ba480dd4SQu Wenruo return -EUCLEAN; 993ba480dd4SQu Wenruo } 994557ea5ddSQu Wenruo return 0; 995557ea5ddSQu Wenruo } 996557ea5ddSQu Wenruo 997557ea5ddSQu Wenruo if (nritems == 0) 998557ea5ddSQu Wenruo return 0; 999557ea5ddSQu Wenruo 1000557ea5ddSQu Wenruo /* 1001557ea5ddSQu Wenruo * Check the following things to make sure this is a good leaf, and 1002557ea5ddSQu Wenruo * leaf users won't need to bother with similar sanity checks: 1003557ea5ddSQu Wenruo * 1004557ea5ddSQu Wenruo * 1) key ordering 1005557ea5ddSQu Wenruo * 2) item offset and size 1006557ea5ddSQu Wenruo * No overlap, no hole, all inside the leaf. 1007557ea5ddSQu Wenruo * 3) item content 1008557ea5ddSQu Wenruo * If possible, do comprehensive sanity check. 1009557ea5ddSQu Wenruo * NOTE: All checks must only rely on the item data itself. 1010557ea5ddSQu Wenruo */ 1011557ea5ddSQu Wenruo for (slot = 0; slot < nritems; slot++) { 1012557ea5ddSQu Wenruo u32 item_end_expected; 1013557ea5ddSQu Wenruo int ret; 1014557ea5ddSQu Wenruo 1015557ea5ddSQu Wenruo btrfs_item_key_to_cpu(leaf, &key, slot); 1016557ea5ddSQu Wenruo 1017557ea5ddSQu Wenruo /* Make sure the keys are in the right order */ 1018557ea5ddSQu Wenruo if (btrfs_comp_cpu_keys(&prev_key, &key) >= 0) { 101986a6be3aSDavid Sterba generic_err(leaf, slot, 1020478d01b3SQu Wenruo "bad key order, prev (%llu %u %llu) current (%llu %u %llu)", 1021478d01b3SQu Wenruo prev_key.objectid, prev_key.type, 1022478d01b3SQu Wenruo prev_key.offset, key.objectid, key.type, 1023478d01b3SQu Wenruo key.offset); 1024557ea5ddSQu Wenruo return -EUCLEAN; 1025557ea5ddSQu Wenruo } 1026557ea5ddSQu Wenruo 1027557ea5ddSQu Wenruo /* 1028557ea5ddSQu Wenruo * Make sure the offset and ends are right, remember that the 1029557ea5ddSQu Wenruo * item data starts at the end of the leaf and grows towards the 1030557ea5ddSQu Wenruo * front. 1031557ea5ddSQu Wenruo */ 1032557ea5ddSQu Wenruo if (slot == 0) 1033557ea5ddSQu Wenruo item_end_expected = BTRFS_LEAF_DATA_SIZE(fs_info); 1034557ea5ddSQu Wenruo else 1035557ea5ddSQu Wenruo item_end_expected = btrfs_item_offset_nr(leaf, 1036557ea5ddSQu Wenruo slot - 1); 1037557ea5ddSQu Wenruo if (btrfs_item_end_nr(leaf, slot) != item_end_expected) { 103886a6be3aSDavid Sterba generic_err(leaf, slot, 1039478d01b3SQu Wenruo "unexpected item end, have %u expect %u", 1040478d01b3SQu Wenruo btrfs_item_end_nr(leaf, slot), 1041478d01b3SQu Wenruo item_end_expected); 1042557ea5ddSQu Wenruo return -EUCLEAN; 1043557ea5ddSQu Wenruo } 1044557ea5ddSQu Wenruo 1045557ea5ddSQu Wenruo /* 1046557ea5ddSQu Wenruo * Check to make sure that we don't point outside of the leaf, 1047557ea5ddSQu Wenruo * just in case all the items are consistent to each other, but 1048557ea5ddSQu Wenruo * all point outside of the leaf. 1049557ea5ddSQu Wenruo */ 1050557ea5ddSQu Wenruo if (btrfs_item_end_nr(leaf, slot) > 1051557ea5ddSQu Wenruo BTRFS_LEAF_DATA_SIZE(fs_info)) { 105286a6be3aSDavid Sterba generic_err(leaf, slot, 1053478d01b3SQu Wenruo "slot end outside of leaf, have %u expect range [0, %u]", 1054478d01b3SQu Wenruo btrfs_item_end_nr(leaf, slot), 1055478d01b3SQu Wenruo BTRFS_LEAF_DATA_SIZE(fs_info)); 1056557ea5ddSQu Wenruo return -EUCLEAN; 1057557ea5ddSQu Wenruo } 1058557ea5ddSQu Wenruo 1059557ea5ddSQu Wenruo /* Also check if the item pointer overlaps with btrfs item. */ 1060557ea5ddSQu Wenruo if (btrfs_item_nr_offset(slot) + sizeof(struct btrfs_item) > 1061557ea5ddSQu Wenruo btrfs_item_ptr_offset(leaf, slot)) { 106286a6be3aSDavid Sterba generic_err(leaf, slot, 1063478d01b3SQu Wenruo "slot overlaps with its data, item end %lu data start %lu", 1064478d01b3SQu Wenruo btrfs_item_nr_offset(slot) + 1065478d01b3SQu Wenruo sizeof(struct btrfs_item), 1066478d01b3SQu Wenruo btrfs_item_ptr_offset(leaf, slot)); 1067557ea5ddSQu Wenruo return -EUCLEAN; 1068557ea5ddSQu Wenruo } 1069557ea5ddSQu Wenruo 107069fc6cbbSQu Wenruo if (check_item_data) { 107169fc6cbbSQu Wenruo /* 107269fc6cbbSQu Wenruo * Check if the item size and content meet other 107369fc6cbbSQu Wenruo * criteria 107469fc6cbbSQu Wenruo */ 10754e9845efSFilipe Manana ret = check_leaf_item(leaf, &key, slot, &prev_key); 1076557ea5ddSQu Wenruo if (ret < 0) 1077557ea5ddSQu Wenruo return ret; 107869fc6cbbSQu Wenruo } 1079557ea5ddSQu Wenruo 1080557ea5ddSQu Wenruo prev_key.objectid = key.objectid; 1081557ea5ddSQu Wenruo prev_key.type = key.type; 1082557ea5ddSQu Wenruo prev_key.offset = key.offset; 1083557ea5ddSQu Wenruo } 1084557ea5ddSQu Wenruo 1085557ea5ddSQu Wenruo return 0; 1086557ea5ddSQu Wenruo } 1087557ea5ddSQu Wenruo 10881c4360eeSDavid Sterba int btrfs_check_leaf_full(struct extent_buffer *leaf) 108969fc6cbbSQu Wenruo { 1090e2ccd361SDavid Sterba return check_leaf(leaf, true); 109169fc6cbbSQu Wenruo } 109202529d7aSQu Wenruo ALLOW_ERROR_INJECTION(btrfs_check_leaf_full, ERRNO); 109369fc6cbbSQu Wenruo 1094cfdaad5eSDavid Sterba int btrfs_check_leaf_relaxed(struct extent_buffer *leaf) 10952f659546SQu Wenruo { 1096e2ccd361SDavid Sterba return check_leaf(leaf, false); 10972f659546SQu Wenruo } 10982f659546SQu Wenruo 1099813fd1dcSDavid Sterba int btrfs_check_node(struct extent_buffer *node) 1100557ea5ddSQu Wenruo { 1101813fd1dcSDavid Sterba struct btrfs_fs_info *fs_info = node->fs_info; 1102557ea5ddSQu Wenruo unsigned long nr = btrfs_header_nritems(node); 1103557ea5ddSQu Wenruo struct btrfs_key key, next_key; 1104557ea5ddSQu Wenruo int slot; 1105f556faa4SQu Wenruo int level = btrfs_header_level(node); 1106557ea5ddSQu Wenruo u64 bytenr; 1107557ea5ddSQu Wenruo int ret = 0; 1108557ea5ddSQu Wenruo 1109f556faa4SQu Wenruo if (level <= 0 || level >= BTRFS_MAX_LEVEL) { 111086a6be3aSDavid Sterba generic_err(node, 0, 1111f556faa4SQu Wenruo "invalid level for node, have %d expect [1, %d]", 1112f556faa4SQu Wenruo level, BTRFS_MAX_LEVEL - 1); 1113f556faa4SQu Wenruo return -EUCLEAN; 1114f556faa4SQu Wenruo } 11152f659546SQu Wenruo if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(fs_info)) { 11162f659546SQu Wenruo btrfs_crit(fs_info, 1117bba4f298SQu Wenruo "corrupt node: root=%llu block=%llu, nritems too %s, have %lu expect range [1,%u]", 11182f659546SQu Wenruo btrfs_header_owner(node), node->start, 1119bba4f298SQu Wenruo nr == 0 ? "small" : "large", nr, 11202f659546SQu Wenruo BTRFS_NODEPTRS_PER_BLOCK(fs_info)); 1121bba4f298SQu Wenruo return -EUCLEAN; 1122557ea5ddSQu Wenruo } 1123557ea5ddSQu Wenruo 1124557ea5ddSQu Wenruo for (slot = 0; slot < nr - 1; slot++) { 1125557ea5ddSQu Wenruo bytenr = btrfs_node_blockptr(node, slot); 1126557ea5ddSQu Wenruo btrfs_node_key_to_cpu(node, &key, slot); 1127557ea5ddSQu Wenruo btrfs_node_key_to_cpu(node, &next_key, slot + 1); 1128557ea5ddSQu Wenruo 1129557ea5ddSQu Wenruo if (!bytenr) { 113086a6be3aSDavid Sterba generic_err(node, slot, 1131bba4f298SQu Wenruo "invalid NULL node pointer"); 1132bba4f298SQu Wenruo ret = -EUCLEAN; 1133bba4f298SQu Wenruo goto out; 1134bba4f298SQu Wenruo } 11352f659546SQu Wenruo if (!IS_ALIGNED(bytenr, fs_info->sectorsize)) { 113686a6be3aSDavid Sterba generic_err(node, slot, 1137bba4f298SQu Wenruo "unaligned pointer, have %llu should be aligned to %u", 11382f659546SQu Wenruo bytenr, fs_info->sectorsize); 1139bba4f298SQu Wenruo ret = -EUCLEAN; 1140557ea5ddSQu Wenruo goto out; 1141557ea5ddSQu Wenruo } 1142557ea5ddSQu Wenruo 1143557ea5ddSQu Wenruo if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) { 114486a6be3aSDavid Sterba generic_err(node, slot, 1145bba4f298SQu Wenruo "bad key order, current (%llu %u %llu) next (%llu %u %llu)", 1146bba4f298SQu Wenruo key.objectid, key.type, key.offset, 1147bba4f298SQu Wenruo next_key.objectid, next_key.type, 1148bba4f298SQu Wenruo next_key.offset); 1149bba4f298SQu Wenruo ret = -EUCLEAN; 1150557ea5ddSQu Wenruo goto out; 1151557ea5ddSQu Wenruo } 1152557ea5ddSQu Wenruo } 1153557ea5ddSQu Wenruo out: 1154557ea5ddSQu Wenruo return ret; 1155557ea5ddSQu Wenruo } 115602529d7aSQu Wenruo ALLOW_ERROR_INJECTION(btrfs_check_node, ERRNO); 1157