xref: /openbmc/linux/fs/btrfs/tree-checker.c (revision c1d7c514f745628eb096c5cbb10737855879ae25)
1*c1d7c514SDavid 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 
18557ea5ddSQu Wenruo #include "ctree.h"
19557ea5ddSQu Wenruo #include "tree-checker.h"
20557ea5ddSQu Wenruo #include "disk-io.h"
21557ea5ddSQu Wenruo #include "compression.h"
22557ea5ddSQu Wenruo 
23bba4f298SQu Wenruo /*
24bba4f298SQu Wenruo  * Error message should follow the following format:
25bba4f298SQu Wenruo  * corrupt <type>: <identifier>, <reason>[, <bad_value>]
26bba4f298SQu Wenruo  *
27bba4f298SQu Wenruo  * @type:	leaf or node
28bba4f298SQu Wenruo  * @identifier:	the necessary info to locate the leaf/node.
29bba4f298SQu Wenruo  * 		It's recommened to decode key.objecitd/offset if it's
30bba4f298SQu Wenruo  * 		meaningful.
31bba4f298SQu Wenruo  * @reason:	describe the error
32bba4f298SQu Wenruo  * @bad_value:	optional, it's recommened to output bad value and its
33bba4f298SQu Wenruo  *		expected value (range).
34bba4f298SQu Wenruo  *
35bba4f298SQu Wenruo  * Since comma is used to separate the components, only space is allowed
36bba4f298SQu Wenruo  * inside each component.
37bba4f298SQu Wenruo  */
38bba4f298SQu Wenruo 
39bba4f298SQu Wenruo /*
40bba4f298SQu Wenruo  * Append generic "corrupt leaf/node root=%llu block=%llu slot=%d: " to @fmt.
41bba4f298SQu Wenruo  * Allows callers to customize the output.
42bba4f298SQu Wenruo  */
43bba4f298SQu Wenruo __printf(4, 5)
44e67c718bSDavid Sterba __cold
452f659546SQu Wenruo static void generic_err(const struct btrfs_fs_info *fs_info,
46bba4f298SQu Wenruo 			const struct extent_buffer *eb, int slot,
47bba4f298SQu Wenruo 			const char *fmt, ...)
48bba4f298SQu Wenruo {
49bba4f298SQu Wenruo 	struct va_format vaf;
50bba4f298SQu Wenruo 	va_list args;
51bba4f298SQu Wenruo 
52bba4f298SQu Wenruo 	va_start(args, fmt);
53bba4f298SQu Wenruo 
54bba4f298SQu Wenruo 	vaf.fmt = fmt;
55bba4f298SQu Wenruo 	vaf.va = &args;
56bba4f298SQu Wenruo 
572f659546SQu Wenruo 	btrfs_crit(fs_info,
58bba4f298SQu Wenruo 		"corrupt %s: root=%llu block=%llu slot=%d, %pV",
59bba4f298SQu Wenruo 		btrfs_header_level(eb) == 0 ? "leaf" : "node",
602f659546SQu Wenruo 		btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot, &vaf);
61bba4f298SQu Wenruo 	va_end(args);
62bba4f298SQu Wenruo }
63bba4f298SQu Wenruo 
648806d718SQu Wenruo /*
658806d718SQu Wenruo  * Customized reporter for extent data item, since its key objectid and
668806d718SQu Wenruo  * offset has its own meaning.
678806d718SQu Wenruo  */
688806d718SQu Wenruo __printf(4, 5)
69e67c718bSDavid Sterba __cold
702f659546SQu Wenruo static void file_extent_err(const struct btrfs_fs_info *fs_info,
718806d718SQu Wenruo 			    const struct extent_buffer *eb, int slot,
728806d718SQu Wenruo 			    const char *fmt, ...)
738806d718SQu Wenruo {
748806d718SQu Wenruo 	struct btrfs_key key;
758806d718SQu Wenruo 	struct va_format vaf;
768806d718SQu Wenruo 	va_list args;
778806d718SQu Wenruo 
788806d718SQu Wenruo 	btrfs_item_key_to_cpu(eb, &key, slot);
798806d718SQu Wenruo 	va_start(args, fmt);
808806d718SQu Wenruo 
818806d718SQu Wenruo 	vaf.fmt = fmt;
828806d718SQu Wenruo 	vaf.va = &args;
838806d718SQu Wenruo 
842f659546SQu Wenruo 	btrfs_crit(fs_info,
858806d718SQu Wenruo 	"corrupt %s: root=%llu block=%llu slot=%d ino=%llu file_offset=%llu, %pV",
862f659546SQu Wenruo 		btrfs_header_level(eb) == 0 ? "leaf" : "node",
872f659546SQu Wenruo 		btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot,
882f659546SQu Wenruo 		key.objectid, key.offset, &vaf);
898806d718SQu Wenruo 	va_end(args);
908806d718SQu Wenruo }
918806d718SQu Wenruo 
928806d718SQu Wenruo /*
938806d718SQu Wenruo  * Return 0 if the btrfs_file_extent_##name is aligned to @alignment
948806d718SQu Wenruo  * Else return 1
958806d718SQu Wenruo  */
962f659546SQu Wenruo #define CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, name, alignment)	      \
978806d718SQu Wenruo ({									      \
988806d718SQu Wenruo 	if (!IS_ALIGNED(btrfs_file_extent_##name((leaf), (fi)), (alignment))) \
992f659546SQu Wenruo 		file_extent_err((fs_info), (leaf), (slot),		      \
1008806d718SQu Wenruo 	"invalid %s for file extent, have %llu, should be aligned to %u",     \
1018806d718SQu Wenruo 			(#name), btrfs_file_extent_##name((leaf), (fi)),      \
1028806d718SQu Wenruo 			(alignment));					      \
1038806d718SQu Wenruo 	(!IS_ALIGNED(btrfs_file_extent_##name((leaf), (fi)), (alignment)));   \
1048806d718SQu Wenruo })
1058806d718SQu Wenruo 
1062f659546SQu Wenruo static int check_extent_data_item(struct btrfs_fs_info *fs_info,
107557ea5ddSQu Wenruo 				  struct extent_buffer *leaf,
108557ea5ddSQu Wenruo 				  struct btrfs_key *key, int slot)
109557ea5ddSQu Wenruo {
110557ea5ddSQu Wenruo 	struct btrfs_file_extent_item *fi;
1112f659546SQu Wenruo 	u32 sectorsize = fs_info->sectorsize;
112557ea5ddSQu Wenruo 	u32 item_size = btrfs_item_size_nr(leaf, slot);
113557ea5ddSQu Wenruo 
114557ea5ddSQu Wenruo 	if (!IS_ALIGNED(key->offset, sectorsize)) {
1152f659546SQu Wenruo 		file_extent_err(fs_info, leaf, slot,
1168806d718SQu Wenruo "unaligned file_offset for file extent, have %llu should be aligned to %u",
1178806d718SQu Wenruo 			key->offset, sectorsize);
118557ea5ddSQu Wenruo 		return -EUCLEAN;
119557ea5ddSQu Wenruo 	}
120557ea5ddSQu Wenruo 
121557ea5ddSQu Wenruo 	fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
122557ea5ddSQu Wenruo 
123557ea5ddSQu Wenruo 	if (btrfs_file_extent_type(leaf, fi) > BTRFS_FILE_EXTENT_TYPES) {
1242f659546SQu Wenruo 		file_extent_err(fs_info, leaf, slot,
1258806d718SQu Wenruo 		"invalid type for file extent, have %u expect range [0, %u]",
1268806d718SQu Wenruo 			btrfs_file_extent_type(leaf, fi),
1278806d718SQu Wenruo 			BTRFS_FILE_EXTENT_TYPES);
128557ea5ddSQu Wenruo 		return -EUCLEAN;
129557ea5ddSQu Wenruo 	}
130557ea5ddSQu Wenruo 
131557ea5ddSQu Wenruo 	/*
132557ea5ddSQu Wenruo 	 * Support for new compression/encrption must introduce incompat flag,
133557ea5ddSQu Wenruo 	 * and must be caught in open_ctree().
134557ea5ddSQu Wenruo 	 */
135557ea5ddSQu Wenruo 	if (btrfs_file_extent_compression(leaf, fi) > BTRFS_COMPRESS_TYPES) {
1362f659546SQu Wenruo 		file_extent_err(fs_info, leaf, slot,
1378806d718SQu Wenruo 	"invalid compression for file extent, have %u expect range [0, %u]",
1388806d718SQu Wenruo 			btrfs_file_extent_compression(leaf, fi),
1398806d718SQu Wenruo 			BTRFS_COMPRESS_TYPES);
140557ea5ddSQu Wenruo 		return -EUCLEAN;
141557ea5ddSQu Wenruo 	}
142557ea5ddSQu Wenruo 	if (btrfs_file_extent_encryption(leaf, fi)) {
1432f659546SQu Wenruo 		file_extent_err(fs_info, leaf, slot,
1448806d718SQu Wenruo 			"invalid encryption for file extent, have %u expect 0",
1458806d718SQu Wenruo 			btrfs_file_extent_encryption(leaf, fi));
146557ea5ddSQu Wenruo 		return -EUCLEAN;
147557ea5ddSQu Wenruo 	}
148557ea5ddSQu Wenruo 	if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
149557ea5ddSQu Wenruo 		/* Inline extent must have 0 as key offset */
150557ea5ddSQu Wenruo 		if (key->offset) {
1512f659546SQu Wenruo 			file_extent_err(fs_info, leaf, slot,
1528806d718SQu Wenruo 		"invalid file_offset for inline file extent, have %llu expect 0",
1538806d718SQu Wenruo 				key->offset);
154557ea5ddSQu Wenruo 			return -EUCLEAN;
155557ea5ddSQu Wenruo 		}
156557ea5ddSQu Wenruo 
157557ea5ddSQu Wenruo 		/* Compressed inline extent has no on-disk size, skip it */
158557ea5ddSQu Wenruo 		if (btrfs_file_extent_compression(leaf, fi) !=
159557ea5ddSQu Wenruo 		    BTRFS_COMPRESS_NONE)
160557ea5ddSQu Wenruo 			return 0;
161557ea5ddSQu Wenruo 
162557ea5ddSQu Wenruo 		/* Uncompressed inline extent size must match item size */
163557ea5ddSQu Wenruo 		if (item_size != BTRFS_FILE_EXTENT_INLINE_DATA_START +
164557ea5ddSQu Wenruo 		    btrfs_file_extent_ram_bytes(leaf, fi)) {
1652f659546SQu Wenruo 			file_extent_err(fs_info, leaf, slot,
1668806d718SQu Wenruo 	"invalid ram_bytes for uncompressed inline extent, have %u expect %llu",
1678806d718SQu Wenruo 				item_size, BTRFS_FILE_EXTENT_INLINE_DATA_START +
1688806d718SQu Wenruo 				btrfs_file_extent_ram_bytes(leaf, fi));
169557ea5ddSQu Wenruo 			return -EUCLEAN;
170557ea5ddSQu Wenruo 		}
171557ea5ddSQu Wenruo 		return 0;
172557ea5ddSQu Wenruo 	}
173557ea5ddSQu Wenruo 
174557ea5ddSQu Wenruo 	/* Regular or preallocated extent has fixed item size */
175557ea5ddSQu Wenruo 	if (item_size != sizeof(*fi)) {
1762f659546SQu Wenruo 		file_extent_err(fs_info, leaf, slot,
177709a95c3SArnd Bergmann 	"invalid item size for reg/prealloc file extent, have %u expect %zu",
1788806d718SQu Wenruo 			item_size, sizeof(*fi));
179557ea5ddSQu Wenruo 		return -EUCLEAN;
180557ea5ddSQu Wenruo 	}
1812f659546SQu Wenruo 	if (CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, ram_bytes, sectorsize) ||
1822f659546SQu Wenruo 	    CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, disk_bytenr, sectorsize) ||
1832f659546SQu Wenruo 	    CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, disk_num_bytes, sectorsize) ||
1842f659546SQu Wenruo 	    CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, offset, sectorsize) ||
1852f659546SQu Wenruo 	    CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, num_bytes, sectorsize))
186557ea5ddSQu Wenruo 		return -EUCLEAN;
187557ea5ddSQu Wenruo 	return 0;
188557ea5ddSQu Wenruo }
189557ea5ddSQu Wenruo 
1902f659546SQu Wenruo static int check_csum_item(struct btrfs_fs_info *fs_info,
1912f659546SQu Wenruo 			   struct extent_buffer *leaf, struct btrfs_key *key,
1922f659546SQu Wenruo 			   int slot)
193557ea5ddSQu Wenruo {
1942f659546SQu Wenruo 	u32 sectorsize = fs_info->sectorsize;
1952f659546SQu Wenruo 	u32 csumsize = btrfs_super_csum_size(fs_info->super_copy);
196557ea5ddSQu Wenruo 
197557ea5ddSQu Wenruo 	if (key->objectid != BTRFS_EXTENT_CSUM_OBJECTID) {
1982f659546SQu Wenruo 		generic_err(fs_info, leaf, slot,
199d508c5f0SQu Wenruo 		"invalid key objectid for csum item, have %llu expect %llu",
200d508c5f0SQu Wenruo 			key->objectid, BTRFS_EXTENT_CSUM_OBJECTID);
201557ea5ddSQu Wenruo 		return -EUCLEAN;
202557ea5ddSQu Wenruo 	}
203557ea5ddSQu Wenruo 	if (!IS_ALIGNED(key->offset, sectorsize)) {
2042f659546SQu Wenruo 		generic_err(fs_info, leaf, slot,
205d508c5f0SQu Wenruo 	"unaligned key offset for csum item, have %llu should be aligned to %u",
206d508c5f0SQu Wenruo 			key->offset, sectorsize);
207557ea5ddSQu Wenruo 		return -EUCLEAN;
208557ea5ddSQu Wenruo 	}
209557ea5ddSQu Wenruo 	if (!IS_ALIGNED(btrfs_item_size_nr(leaf, slot), csumsize)) {
2102f659546SQu Wenruo 		generic_err(fs_info, leaf, slot,
211d508c5f0SQu Wenruo 	"unaligned item size for csum item, have %u should be aligned to %u",
212d508c5f0SQu Wenruo 			btrfs_item_size_nr(leaf, slot), csumsize);
213557ea5ddSQu Wenruo 		return -EUCLEAN;
214557ea5ddSQu Wenruo 	}
215557ea5ddSQu Wenruo 	return 0;
216557ea5ddSQu Wenruo }
217557ea5ddSQu Wenruo 
218557ea5ddSQu Wenruo /*
219ad7b0368SQu Wenruo  * Customized reported for dir_item, only important new info is key->objectid,
220ad7b0368SQu Wenruo  * which represents inode number
221ad7b0368SQu Wenruo  */
222ad7b0368SQu Wenruo __printf(4, 5)
223e67c718bSDavid Sterba __cold
2242f659546SQu Wenruo static void dir_item_err(const struct btrfs_fs_info *fs_info,
225ad7b0368SQu Wenruo 			 const struct extent_buffer *eb, int slot,
226ad7b0368SQu Wenruo 			 const char *fmt, ...)
227ad7b0368SQu Wenruo {
228ad7b0368SQu Wenruo 	struct btrfs_key key;
229ad7b0368SQu Wenruo 	struct va_format vaf;
230ad7b0368SQu Wenruo 	va_list args;
231ad7b0368SQu Wenruo 
232ad7b0368SQu Wenruo 	btrfs_item_key_to_cpu(eb, &key, slot);
233ad7b0368SQu Wenruo 	va_start(args, fmt);
234ad7b0368SQu Wenruo 
235ad7b0368SQu Wenruo 	vaf.fmt = fmt;
236ad7b0368SQu Wenruo 	vaf.va = &args;
237ad7b0368SQu Wenruo 
2382f659546SQu Wenruo 	btrfs_crit(fs_info,
239ad7b0368SQu Wenruo 	"corrupt %s: root=%llu block=%llu slot=%d ino=%llu, %pV",
2402f659546SQu Wenruo 		btrfs_header_level(eb) == 0 ? "leaf" : "node",
2412f659546SQu Wenruo 		btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot,
2422f659546SQu Wenruo 		key.objectid, &vaf);
243ad7b0368SQu Wenruo 	va_end(args);
244ad7b0368SQu Wenruo }
245ad7b0368SQu Wenruo 
2462f659546SQu Wenruo static int check_dir_item(struct btrfs_fs_info *fs_info,
247ad7b0368SQu Wenruo 			  struct extent_buffer *leaf,
248ad7b0368SQu Wenruo 			  struct btrfs_key *key, int slot)
249ad7b0368SQu Wenruo {
250ad7b0368SQu Wenruo 	struct btrfs_dir_item *di;
251ad7b0368SQu Wenruo 	u32 item_size = btrfs_item_size_nr(leaf, slot);
252ad7b0368SQu Wenruo 	u32 cur = 0;
253ad7b0368SQu Wenruo 
254ad7b0368SQu Wenruo 	di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
255ad7b0368SQu Wenruo 	while (cur < item_size) {
256ad7b0368SQu Wenruo 		u32 name_len;
257ad7b0368SQu Wenruo 		u32 data_len;
258ad7b0368SQu Wenruo 		u32 max_name_len;
259ad7b0368SQu Wenruo 		u32 total_size;
260ad7b0368SQu Wenruo 		u32 name_hash;
261ad7b0368SQu Wenruo 		u8 dir_type;
262ad7b0368SQu Wenruo 
263ad7b0368SQu Wenruo 		/* header itself should not cross item boundary */
264ad7b0368SQu Wenruo 		if (cur + sizeof(*di) > item_size) {
2652f659546SQu Wenruo 			dir_item_err(fs_info, leaf, slot,
2667cfad652SArnd Bergmann 		"dir item header crosses item boundary, have %zu boundary %u",
267ad7b0368SQu Wenruo 				cur + sizeof(*di), item_size);
268ad7b0368SQu Wenruo 			return -EUCLEAN;
269ad7b0368SQu Wenruo 		}
270ad7b0368SQu Wenruo 
271ad7b0368SQu Wenruo 		/* dir type check */
272ad7b0368SQu Wenruo 		dir_type = btrfs_dir_type(leaf, di);
273ad7b0368SQu Wenruo 		if (dir_type >= BTRFS_FT_MAX) {
2742f659546SQu Wenruo 			dir_item_err(fs_info, leaf, slot,
275ad7b0368SQu Wenruo 			"invalid dir item type, have %u expect [0, %u)",
276ad7b0368SQu Wenruo 				dir_type, BTRFS_FT_MAX);
277ad7b0368SQu Wenruo 			return -EUCLEAN;
278ad7b0368SQu Wenruo 		}
279ad7b0368SQu Wenruo 
280ad7b0368SQu Wenruo 		if (key->type == BTRFS_XATTR_ITEM_KEY &&
281ad7b0368SQu Wenruo 		    dir_type != BTRFS_FT_XATTR) {
2822f659546SQu Wenruo 			dir_item_err(fs_info, leaf, slot,
283ad7b0368SQu Wenruo 		"invalid dir item type for XATTR key, have %u expect %u",
284ad7b0368SQu Wenruo 				dir_type, BTRFS_FT_XATTR);
285ad7b0368SQu Wenruo 			return -EUCLEAN;
286ad7b0368SQu Wenruo 		}
287ad7b0368SQu Wenruo 		if (dir_type == BTRFS_FT_XATTR &&
288ad7b0368SQu Wenruo 		    key->type != BTRFS_XATTR_ITEM_KEY) {
2892f659546SQu Wenruo 			dir_item_err(fs_info, leaf, slot,
290ad7b0368SQu Wenruo 			"xattr dir type found for non-XATTR key");
291ad7b0368SQu Wenruo 			return -EUCLEAN;
292ad7b0368SQu Wenruo 		}
293ad7b0368SQu Wenruo 		if (dir_type == BTRFS_FT_XATTR)
294ad7b0368SQu Wenruo 			max_name_len = XATTR_NAME_MAX;
295ad7b0368SQu Wenruo 		else
296ad7b0368SQu Wenruo 			max_name_len = BTRFS_NAME_LEN;
297ad7b0368SQu Wenruo 
298ad7b0368SQu Wenruo 		/* Name/data length check */
299ad7b0368SQu Wenruo 		name_len = btrfs_dir_name_len(leaf, di);
300ad7b0368SQu Wenruo 		data_len = btrfs_dir_data_len(leaf, di);
301ad7b0368SQu Wenruo 		if (name_len > max_name_len) {
3022f659546SQu Wenruo 			dir_item_err(fs_info, leaf, slot,
303ad7b0368SQu Wenruo 			"dir item name len too long, have %u max %u",
304ad7b0368SQu Wenruo 				name_len, max_name_len);
305ad7b0368SQu Wenruo 			return -EUCLEAN;
306ad7b0368SQu Wenruo 		}
3072f659546SQu Wenruo 		if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(fs_info)) {
3082f659546SQu Wenruo 			dir_item_err(fs_info, leaf, slot,
309ad7b0368SQu Wenruo 			"dir item name and data len too long, have %u max %u",
310ad7b0368SQu Wenruo 				name_len + data_len,
3112f659546SQu Wenruo 				BTRFS_MAX_XATTR_SIZE(fs_info));
312ad7b0368SQu Wenruo 			return -EUCLEAN;
313ad7b0368SQu Wenruo 		}
314ad7b0368SQu Wenruo 
315ad7b0368SQu Wenruo 		if (data_len && dir_type != BTRFS_FT_XATTR) {
3162f659546SQu Wenruo 			dir_item_err(fs_info, leaf, slot,
317ad7b0368SQu Wenruo 			"dir item with invalid data len, have %u expect 0",
318ad7b0368SQu Wenruo 				data_len);
319ad7b0368SQu Wenruo 			return -EUCLEAN;
320ad7b0368SQu Wenruo 		}
321ad7b0368SQu Wenruo 
322ad7b0368SQu Wenruo 		total_size = sizeof(*di) + name_len + data_len;
323ad7b0368SQu Wenruo 
324ad7b0368SQu Wenruo 		/* header and name/data should not cross item boundary */
325ad7b0368SQu Wenruo 		if (cur + total_size > item_size) {
3262f659546SQu Wenruo 			dir_item_err(fs_info, leaf, slot,
327ad7b0368SQu Wenruo 		"dir item data crosses item boundary, have %u boundary %u",
328ad7b0368SQu Wenruo 				cur + total_size, item_size);
329ad7b0368SQu Wenruo 			return -EUCLEAN;
330ad7b0368SQu Wenruo 		}
331ad7b0368SQu Wenruo 
332ad7b0368SQu Wenruo 		/*
333ad7b0368SQu Wenruo 		 * Special check for XATTR/DIR_ITEM, as key->offset is name
334ad7b0368SQu Wenruo 		 * hash, should match its name
335ad7b0368SQu Wenruo 		 */
336ad7b0368SQu Wenruo 		if (key->type == BTRFS_DIR_ITEM_KEY ||
337ad7b0368SQu Wenruo 		    key->type == BTRFS_XATTR_ITEM_KEY) {
338e2683fc9SDavid Sterba 			char namebuf[max(BTRFS_NAME_LEN, XATTR_NAME_MAX)];
339e2683fc9SDavid Sterba 
340ad7b0368SQu Wenruo 			read_extent_buffer(leaf, namebuf,
341ad7b0368SQu Wenruo 					(unsigned long)(di + 1), name_len);
342ad7b0368SQu Wenruo 			name_hash = btrfs_name_hash(namebuf, name_len);
343ad7b0368SQu Wenruo 			if (key->offset != name_hash) {
3442f659546SQu Wenruo 				dir_item_err(fs_info, leaf, slot,
345ad7b0368SQu Wenruo 		"name hash mismatch with key, have 0x%016x expect 0x%016llx",
346ad7b0368SQu Wenruo 					name_hash, key->offset);
347ad7b0368SQu Wenruo 				return -EUCLEAN;
348ad7b0368SQu Wenruo 			}
349ad7b0368SQu Wenruo 		}
350ad7b0368SQu Wenruo 		cur += total_size;
351ad7b0368SQu Wenruo 		di = (struct btrfs_dir_item *)((void *)di + total_size);
352ad7b0368SQu Wenruo 	}
353ad7b0368SQu Wenruo 	return 0;
354ad7b0368SQu Wenruo }
355ad7b0368SQu Wenruo 
356ad7b0368SQu Wenruo /*
357557ea5ddSQu Wenruo  * Common point to switch the item-specific validation.
358557ea5ddSQu Wenruo  */
3592f659546SQu Wenruo static int check_leaf_item(struct btrfs_fs_info *fs_info,
360557ea5ddSQu Wenruo 			   struct extent_buffer *leaf,
361557ea5ddSQu Wenruo 			   struct btrfs_key *key, int slot)
362557ea5ddSQu Wenruo {
363557ea5ddSQu Wenruo 	int ret = 0;
364557ea5ddSQu Wenruo 
365557ea5ddSQu Wenruo 	switch (key->type) {
366557ea5ddSQu Wenruo 	case BTRFS_EXTENT_DATA_KEY:
3672f659546SQu Wenruo 		ret = check_extent_data_item(fs_info, leaf, key, slot);
368557ea5ddSQu Wenruo 		break;
369557ea5ddSQu Wenruo 	case BTRFS_EXTENT_CSUM_KEY:
3702f659546SQu Wenruo 		ret = check_csum_item(fs_info, leaf, key, slot);
371557ea5ddSQu Wenruo 		break;
372ad7b0368SQu Wenruo 	case BTRFS_DIR_ITEM_KEY:
373ad7b0368SQu Wenruo 	case BTRFS_DIR_INDEX_KEY:
374ad7b0368SQu Wenruo 	case BTRFS_XATTR_ITEM_KEY:
3752f659546SQu Wenruo 		ret = check_dir_item(fs_info, leaf, key, slot);
376ad7b0368SQu Wenruo 		break;
377557ea5ddSQu Wenruo 	}
378557ea5ddSQu Wenruo 	return ret;
379557ea5ddSQu Wenruo }
380557ea5ddSQu Wenruo 
3812f659546SQu Wenruo static int check_leaf(struct btrfs_fs_info *fs_info, struct extent_buffer *leaf,
38269fc6cbbSQu Wenruo 		      bool check_item_data)
383557ea5ddSQu Wenruo {
384557ea5ddSQu Wenruo 	/* No valid key type is 0, so all key should be larger than this key */
385557ea5ddSQu Wenruo 	struct btrfs_key prev_key = {0, 0, 0};
386557ea5ddSQu Wenruo 	struct btrfs_key key;
387557ea5ddSQu Wenruo 	u32 nritems = btrfs_header_nritems(leaf);
388557ea5ddSQu Wenruo 	int slot;
389557ea5ddSQu Wenruo 
390557ea5ddSQu Wenruo 	/*
391557ea5ddSQu Wenruo 	 * Extent buffers from a relocation tree have a owner field that
392557ea5ddSQu Wenruo 	 * corresponds to the subvolume tree they are based on. So just from an
393557ea5ddSQu Wenruo 	 * extent buffer alone we can not find out what is the id of the
394557ea5ddSQu Wenruo 	 * corresponding subvolume tree, so we can not figure out if the extent
395557ea5ddSQu Wenruo 	 * buffer corresponds to the root of the relocation tree or not. So
396557ea5ddSQu Wenruo 	 * skip this check for relocation trees.
397557ea5ddSQu Wenruo 	 */
398557ea5ddSQu Wenruo 	if (nritems == 0 && !btrfs_header_flag(leaf, BTRFS_HEADER_FLAG_RELOC)) {
399557ea5ddSQu Wenruo 		struct btrfs_root *check_root;
400557ea5ddSQu Wenruo 
401557ea5ddSQu Wenruo 		key.objectid = btrfs_header_owner(leaf);
402557ea5ddSQu Wenruo 		key.type = BTRFS_ROOT_ITEM_KEY;
403557ea5ddSQu Wenruo 		key.offset = (u64)-1;
404557ea5ddSQu Wenruo 
405557ea5ddSQu Wenruo 		check_root = btrfs_get_fs_root(fs_info, &key, false);
406557ea5ddSQu Wenruo 		/*
407557ea5ddSQu Wenruo 		 * The only reason we also check NULL here is that during
408557ea5ddSQu Wenruo 		 * open_ctree() some roots has not yet been set up.
409557ea5ddSQu Wenruo 		 */
410557ea5ddSQu Wenruo 		if (!IS_ERR_OR_NULL(check_root)) {
411557ea5ddSQu Wenruo 			struct extent_buffer *eb;
412557ea5ddSQu Wenruo 
413557ea5ddSQu Wenruo 			eb = btrfs_root_node(check_root);
414557ea5ddSQu Wenruo 			/* if leaf is the root, then it's fine */
415557ea5ddSQu Wenruo 			if (leaf != eb) {
4162f659546SQu Wenruo 				generic_err(fs_info, leaf, 0,
417478d01b3SQu Wenruo 		"invalid nritems, have %u should not be 0 for non-root leaf",
418478d01b3SQu Wenruo 					nritems);
419557ea5ddSQu Wenruo 				free_extent_buffer(eb);
420557ea5ddSQu Wenruo 				return -EUCLEAN;
421557ea5ddSQu Wenruo 			}
422557ea5ddSQu Wenruo 			free_extent_buffer(eb);
423557ea5ddSQu Wenruo 		}
424557ea5ddSQu Wenruo 		return 0;
425557ea5ddSQu Wenruo 	}
426557ea5ddSQu Wenruo 
427557ea5ddSQu Wenruo 	if (nritems == 0)
428557ea5ddSQu Wenruo 		return 0;
429557ea5ddSQu Wenruo 
430557ea5ddSQu Wenruo 	/*
431557ea5ddSQu Wenruo 	 * Check the following things to make sure this is a good leaf, and
432557ea5ddSQu Wenruo 	 * leaf users won't need to bother with similar sanity checks:
433557ea5ddSQu Wenruo 	 *
434557ea5ddSQu Wenruo 	 * 1) key ordering
435557ea5ddSQu Wenruo 	 * 2) item offset and size
436557ea5ddSQu Wenruo 	 *    No overlap, no hole, all inside the leaf.
437557ea5ddSQu Wenruo 	 * 3) item content
438557ea5ddSQu Wenruo 	 *    If possible, do comprehensive sanity check.
439557ea5ddSQu Wenruo 	 *    NOTE: All checks must only rely on the item data itself.
440557ea5ddSQu Wenruo 	 */
441557ea5ddSQu Wenruo 	for (slot = 0; slot < nritems; slot++) {
442557ea5ddSQu Wenruo 		u32 item_end_expected;
443557ea5ddSQu Wenruo 		int ret;
444557ea5ddSQu Wenruo 
445557ea5ddSQu Wenruo 		btrfs_item_key_to_cpu(leaf, &key, slot);
446557ea5ddSQu Wenruo 
447557ea5ddSQu Wenruo 		/* Make sure the keys are in the right order */
448557ea5ddSQu Wenruo 		if (btrfs_comp_cpu_keys(&prev_key, &key) >= 0) {
4492f659546SQu Wenruo 			generic_err(fs_info, leaf, slot,
450478d01b3SQu Wenruo 	"bad key order, prev (%llu %u %llu) current (%llu %u %llu)",
451478d01b3SQu Wenruo 				prev_key.objectid, prev_key.type,
452478d01b3SQu Wenruo 				prev_key.offset, key.objectid, key.type,
453478d01b3SQu Wenruo 				key.offset);
454557ea5ddSQu Wenruo 			return -EUCLEAN;
455557ea5ddSQu Wenruo 		}
456557ea5ddSQu Wenruo 
457557ea5ddSQu Wenruo 		/*
458557ea5ddSQu Wenruo 		 * Make sure the offset and ends are right, remember that the
459557ea5ddSQu Wenruo 		 * item data starts at the end of the leaf and grows towards the
460557ea5ddSQu Wenruo 		 * front.
461557ea5ddSQu Wenruo 		 */
462557ea5ddSQu Wenruo 		if (slot == 0)
463557ea5ddSQu Wenruo 			item_end_expected = BTRFS_LEAF_DATA_SIZE(fs_info);
464557ea5ddSQu Wenruo 		else
465557ea5ddSQu Wenruo 			item_end_expected = btrfs_item_offset_nr(leaf,
466557ea5ddSQu Wenruo 								 slot - 1);
467557ea5ddSQu Wenruo 		if (btrfs_item_end_nr(leaf, slot) != item_end_expected) {
4682f659546SQu Wenruo 			generic_err(fs_info, leaf, slot,
469478d01b3SQu Wenruo 				"unexpected item end, have %u expect %u",
470478d01b3SQu Wenruo 				btrfs_item_end_nr(leaf, slot),
471478d01b3SQu Wenruo 				item_end_expected);
472557ea5ddSQu Wenruo 			return -EUCLEAN;
473557ea5ddSQu Wenruo 		}
474557ea5ddSQu Wenruo 
475557ea5ddSQu Wenruo 		/*
476557ea5ddSQu Wenruo 		 * Check to make sure that we don't point outside of the leaf,
477557ea5ddSQu Wenruo 		 * just in case all the items are consistent to each other, but
478557ea5ddSQu Wenruo 		 * all point outside of the leaf.
479557ea5ddSQu Wenruo 		 */
480557ea5ddSQu Wenruo 		if (btrfs_item_end_nr(leaf, slot) >
481557ea5ddSQu Wenruo 		    BTRFS_LEAF_DATA_SIZE(fs_info)) {
4822f659546SQu Wenruo 			generic_err(fs_info, leaf, slot,
483478d01b3SQu Wenruo 			"slot end outside of leaf, have %u expect range [0, %u]",
484478d01b3SQu Wenruo 				btrfs_item_end_nr(leaf, slot),
485478d01b3SQu Wenruo 				BTRFS_LEAF_DATA_SIZE(fs_info));
486557ea5ddSQu Wenruo 			return -EUCLEAN;
487557ea5ddSQu Wenruo 		}
488557ea5ddSQu Wenruo 
489557ea5ddSQu Wenruo 		/* Also check if the item pointer overlaps with btrfs item. */
490557ea5ddSQu Wenruo 		if (btrfs_item_nr_offset(slot) + sizeof(struct btrfs_item) >
491557ea5ddSQu Wenruo 		    btrfs_item_ptr_offset(leaf, slot)) {
4922f659546SQu Wenruo 			generic_err(fs_info, leaf, slot,
493478d01b3SQu Wenruo 		"slot overlaps with its data, item end %lu data start %lu",
494478d01b3SQu Wenruo 				btrfs_item_nr_offset(slot) +
495478d01b3SQu Wenruo 				sizeof(struct btrfs_item),
496478d01b3SQu Wenruo 				btrfs_item_ptr_offset(leaf, slot));
497557ea5ddSQu Wenruo 			return -EUCLEAN;
498557ea5ddSQu Wenruo 		}
499557ea5ddSQu Wenruo 
50069fc6cbbSQu Wenruo 		if (check_item_data) {
50169fc6cbbSQu Wenruo 			/*
50269fc6cbbSQu Wenruo 			 * Check if the item size and content meet other
50369fc6cbbSQu Wenruo 			 * criteria
50469fc6cbbSQu Wenruo 			 */
5052f659546SQu Wenruo 			ret = check_leaf_item(fs_info, leaf, &key, slot);
506557ea5ddSQu Wenruo 			if (ret < 0)
507557ea5ddSQu Wenruo 				return ret;
50869fc6cbbSQu Wenruo 		}
509557ea5ddSQu Wenruo 
510557ea5ddSQu Wenruo 		prev_key.objectid = key.objectid;
511557ea5ddSQu Wenruo 		prev_key.type = key.type;
512557ea5ddSQu Wenruo 		prev_key.offset = key.offset;
513557ea5ddSQu Wenruo 	}
514557ea5ddSQu Wenruo 
515557ea5ddSQu Wenruo 	return 0;
516557ea5ddSQu Wenruo }
517557ea5ddSQu Wenruo 
5182f659546SQu Wenruo int btrfs_check_leaf_full(struct btrfs_fs_info *fs_info,
51969fc6cbbSQu Wenruo 			  struct extent_buffer *leaf)
52069fc6cbbSQu Wenruo {
5212f659546SQu Wenruo 	return check_leaf(fs_info, leaf, true);
52269fc6cbbSQu Wenruo }
52369fc6cbbSQu Wenruo 
5242f659546SQu Wenruo int btrfs_check_leaf_relaxed(struct btrfs_fs_info *fs_info,
5252f659546SQu Wenruo 			     struct extent_buffer *leaf)
5262f659546SQu Wenruo {
5272f659546SQu Wenruo 	return check_leaf(fs_info, leaf, false);
5282f659546SQu Wenruo }
5292f659546SQu Wenruo 
5302f659546SQu Wenruo int btrfs_check_node(struct btrfs_fs_info *fs_info, struct extent_buffer *node)
531557ea5ddSQu Wenruo {
532557ea5ddSQu Wenruo 	unsigned long nr = btrfs_header_nritems(node);
533557ea5ddSQu Wenruo 	struct btrfs_key key, next_key;
534557ea5ddSQu Wenruo 	int slot;
535557ea5ddSQu Wenruo 	u64 bytenr;
536557ea5ddSQu Wenruo 	int ret = 0;
537557ea5ddSQu Wenruo 
5382f659546SQu Wenruo 	if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(fs_info)) {
5392f659546SQu Wenruo 		btrfs_crit(fs_info,
540bba4f298SQu Wenruo "corrupt node: root=%llu block=%llu, nritems too %s, have %lu expect range [1,%u]",
5412f659546SQu Wenruo 			   btrfs_header_owner(node), node->start,
542bba4f298SQu Wenruo 			   nr == 0 ? "small" : "large", nr,
5432f659546SQu Wenruo 			   BTRFS_NODEPTRS_PER_BLOCK(fs_info));
544bba4f298SQu Wenruo 		return -EUCLEAN;
545557ea5ddSQu Wenruo 	}
546557ea5ddSQu Wenruo 
547557ea5ddSQu Wenruo 	for (slot = 0; slot < nr - 1; slot++) {
548557ea5ddSQu Wenruo 		bytenr = btrfs_node_blockptr(node, slot);
549557ea5ddSQu Wenruo 		btrfs_node_key_to_cpu(node, &key, slot);
550557ea5ddSQu Wenruo 		btrfs_node_key_to_cpu(node, &next_key, slot + 1);
551557ea5ddSQu Wenruo 
552557ea5ddSQu Wenruo 		if (!bytenr) {
5532f659546SQu Wenruo 			generic_err(fs_info, node, slot,
554bba4f298SQu Wenruo 				"invalid NULL node pointer");
555bba4f298SQu Wenruo 			ret = -EUCLEAN;
556bba4f298SQu Wenruo 			goto out;
557bba4f298SQu Wenruo 		}
5582f659546SQu Wenruo 		if (!IS_ALIGNED(bytenr, fs_info->sectorsize)) {
5592f659546SQu Wenruo 			generic_err(fs_info, node, slot,
560bba4f298SQu Wenruo 			"unaligned pointer, have %llu should be aligned to %u",
5612f659546SQu Wenruo 				bytenr, fs_info->sectorsize);
562bba4f298SQu Wenruo 			ret = -EUCLEAN;
563557ea5ddSQu Wenruo 			goto out;
564557ea5ddSQu Wenruo 		}
565557ea5ddSQu Wenruo 
566557ea5ddSQu Wenruo 		if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) {
5672f659546SQu Wenruo 			generic_err(fs_info, node, slot,
568bba4f298SQu Wenruo 	"bad key order, current (%llu %u %llu) next (%llu %u %llu)",
569bba4f298SQu Wenruo 				key.objectid, key.type, key.offset,
570bba4f298SQu Wenruo 				next_key.objectid, next_key.type,
571bba4f298SQu Wenruo 				next_key.offset);
572bba4f298SQu Wenruo 			ret = -EUCLEAN;
573557ea5ddSQu Wenruo 			goto out;
574557ea5ddSQu Wenruo 		}
575557ea5ddSQu Wenruo 	}
576557ea5ddSQu Wenruo out:
577557ea5ddSQu Wenruo 	return ret;
578557ea5ddSQu Wenruo }
579