tree-checker.c 19.9 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * Copyright (C) Qu Wenruo 2017.  All rights reserved.
 */

/*
 * 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"
22
#include "volumes.h"
23

24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
/*
 * 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)
45
__cold
46
static void generic_err(const struct btrfs_fs_info *fs_info,
47 48 49 50 51 52 53 54 55 56 57
			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;

58
	btrfs_crit(fs_info,
59 60
		"corrupt %s: root=%llu block=%llu slot=%d, %pV",
		btrfs_header_level(eb) == 0 ? "leaf" : "node",
61
		btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot, &vaf);
62 63 64
	va_end(args);
}

65 66 67 68 69
/*
 * Customized reporter for extent data item, since its key objectid and
 * offset has its own meaning.
 */
__printf(4, 5)
70
__cold
71
static void file_extent_err(const struct btrfs_fs_info *fs_info,
72 73 74 75 76 77 78 79 80 81 82 83 84
			    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;

85
	btrfs_crit(fs_info,
86
	"corrupt %s: root=%llu block=%llu slot=%d ino=%llu file_offset=%llu, %pV",
87 88 89
		btrfs_header_level(eb) == 0 ? "leaf" : "node",
		btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot,
		key.objectid, key.offset, &vaf);
90 91 92 93 94 95 96
	va_end(args);
}

/*
 * Return 0 if the btrfs_file_extent_##name is aligned to @alignment
 * Else return 1
 */
97
#define CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, name, alignment)	      \
98 99
({									      \
	if (!IS_ALIGNED(btrfs_file_extent_##name((leaf), (fi)), (alignment))) \
100
		file_extent_err((fs_info), (leaf), (slot),		      \
101 102 103 104 105 106
	"invalid %s for file extent, have %llu, should be aligned to %u",     \
			(#name), btrfs_file_extent_##name((leaf), (fi)),      \
			(alignment));					      \
	(!IS_ALIGNED(btrfs_file_extent_##name((leaf), (fi)), (alignment)));   \
})

107
static int check_extent_data_item(struct btrfs_fs_info *fs_info,
108 109 110 111
				  struct extent_buffer *leaf,
				  struct btrfs_key *key, int slot)
{
	struct btrfs_file_extent_item *fi;
112
	u32 sectorsize = fs_info->sectorsize;
113 114 115
	u32 item_size = btrfs_item_size_nr(leaf, slot);

	if (!IS_ALIGNED(key->offset, sectorsize)) {
116
		file_extent_err(fs_info, leaf, slot,
117 118
"unaligned file_offset for file extent, have %llu should be aligned to %u",
			key->offset, sectorsize);
119 120 121 122 123 124
		return -EUCLEAN;
	}

	fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);

	if (btrfs_file_extent_type(leaf, fi) > BTRFS_FILE_EXTENT_TYPES) {
125
		file_extent_err(fs_info, leaf, slot,
126 127 128
		"invalid type for file extent, have %u expect range [0, %u]",
			btrfs_file_extent_type(leaf, fi),
			BTRFS_FILE_EXTENT_TYPES);
129 130 131 132 133 134 135 136
		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) {
137
		file_extent_err(fs_info, leaf, slot,
138 139 140
	"invalid compression for file extent, have %u expect range [0, %u]",
			btrfs_file_extent_compression(leaf, fi),
			BTRFS_COMPRESS_TYPES);
141 142 143
		return -EUCLEAN;
	}
	if (btrfs_file_extent_encryption(leaf, fi)) {
144
		file_extent_err(fs_info, leaf, slot,
145 146
			"invalid encryption for file extent, have %u expect 0",
			btrfs_file_extent_encryption(leaf, fi));
147 148 149 150 151
		return -EUCLEAN;
	}
	if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
		/* Inline extent must have 0 as key offset */
		if (key->offset) {
152
			file_extent_err(fs_info, leaf, slot,
153 154
		"invalid file_offset for inline file extent, have %llu expect 0",
				key->offset);
155 156 157 158 159 160 161 162 163 164 165
			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)) {
166
			file_extent_err(fs_info, leaf, slot,
167 168 169
	"invalid ram_bytes for uncompressed inline extent, have %u expect %llu",
				item_size, BTRFS_FILE_EXTENT_INLINE_DATA_START +
				btrfs_file_extent_ram_bytes(leaf, fi));
170 171 172 173 174 175 176
			return -EUCLEAN;
		}
		return 0;
	}

	/* Regular or preallocated extent has fixed item size */
	if (item_size != sizeof(*fi)) {
177
		file_extent_err(fs_info, leaf, slot,
178
	"invalid item size for reg/prealloc file extent, have %u expect %zu",
179
			item_size, sizeof(*fi));
180 181
		return -EUCLEAN;
	}
182 183 184 185 186
	if (CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, ram_bytes, sectorsize) ||
	    CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, disk_bytenr, sectorsize) ||
	    CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, disk_num_bytes, sectorsize) ||
	    CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, offset, sectorsize) ||
	    CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, num_bytes, sectorsize))
187 188 189 190
		return -EUCLEAN;
	return 0;
}

191 192 193
static int check_csum_item(struct btrfs_fs_info *fs_info,
			   struct extent_buffer *leaf, struct btrfs_key *key,
			   int slot)
194
{
195 196
	u32 sectorsize = fs_info->sectorsize;
	u32 csumsize = btrfs_super_csum_size(fs_info->super_copy);
197 198

	if (key->objectid != BTRFS_EXTENT_CSUM_OBJECTID) {
199
		generic_err(fs_info, leaf, slot,
200 201
		"invalid key objectid for csum item, have %llu expect %llu",
			key->objectid, BTRFS_EXTENT_CSUM_OBJECTID);
202 203 204
		return -EUCLEAN;
	}
	if (!IS_ALIGNED(key->offset, sectorsize)) {
205
		generic_err(fs_info, leaf, slot,
206 207
	"unaligned key offset for csum item, have %llu should be aligned to %u",
			key->offset, sectorsize);
208 209 210
		return -EUCLEAN;
	}
	if (!IS_ALIGNED(btrfs_item_size_nr(leaf, slot), csumsize)) {
211
		generic_err(fs_info, leaf, slot,
212 213
	"unaligned item size for csum item, have %u should be aligned to %u",
			btrfs_item_size_nr(leaf, slot), csumsize);
214 215 216 217 218
		return -EUCLEAN;
	}
	return 0;
}

219 220 221 222 223
/*
 * Customized reported for dir_item, only important new info is key->objectid,
 * which represents inode number
 */
__printf(4, 5)
224
__cold
225
static void dir_item_err(const struct btrfs_fs_info *fs_info,
226 227 228 229 230 231 232 233 234 235 236 237 238
			 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;

239
	btrfs_crit(fs_info,
240
	"corrupt %s: root=%llu block=%llu slot=%d ino=%llu, %pV",
241 242 243
		btrfs_header_level(eb) == 0 ? "leaf" : "node",
		btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot,
		key.objectid, &vaf);
244 245 246
	va_end(args);
}

247
static int check_dir_item(struct btrfs_fs_info *fs_info,
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
			  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) {
		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) {
266
			dir_item_err(fs_info, leaf, slot,
267
		"dir item header crosses item boundary, have %zu boundary %u",
268 269 270 271 272 273 274
				cur + sizeof(*di), item_size);
			return -EUCLEAN;
		}

		/* dir type check */
		dir_type = btrfs_dir_type(leaf, di);
		if (dir_type >= BTRFS_FT_MAX) {
275
			dir_item_err(fs_info, leaf, slot,
276 277 278 279 280 281 282
			"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) {
283
			dir_item_err(fs_info, leaf, slot,
284 285 286 287 288 289
		"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) {
290
			dir_item_err(fs_info, leaf, slot,
291 292 293 294 295 296 297 298 299 300 301 302
			"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) {
303
			dir_item_err(fs_info, leaf, slot,
304 305 306 307
			"dir item name len too long, have %u max %u",
				name_len, max_name_len);
			return -EUCLEAN;
		}
308 309
		if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(fs_info)) {
			dir_item_err(fs_info, leaf, slot,
310 311
			"dir item name and data len too long, have %u max %u",
				name_len + data_len,
312
				BTRFS_MAX_XATTR_SIZE(fs_info));
313 314 315 316
			return -EUCLEAN;
		}

		if (data_len && dir_type != BTRFS_FT_XATTR) {
317
			dir_item_err(fs_info, leaf, slot,
318 319 320 321 322 323 324 325 326
			"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) {
327
			dir_item_err(fs_info, leaf, slot,
328 329 330 331 332 333 334 335 336 337 338
		"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) {
339 340
			char namebuf[max(BTRFS_NAME_LEN, XATTR_NAME_MAX)];

341 342 343 344
			read_extent_buffer(leaf, namebuf,
					(unsigned long)(di + 1), name_len);
			name_hash = btrfs_name_hash(namebuf, name_len);
			if (key->offset != name_hash) {
345
				dir_item_err(fs_info, leaf, slot,
346 347 348 349 350 351 352 353 354 355 356
		"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;
}

357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
__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;
}

453 454 455
/*
 * Common point to switch the item-specific validation.
 */
456
static int check_leaf_item(struct btrfs_fs_info *fs_info,
457 458 459 460 461 462 463
			   struct extent_buffer *leaf,
			   struct btrfs_key *key, int slot)
{
	int ret = 0;

	switch (key->type) {
	case BTRFS_EXTENT_DATA_KEY:
464
		ret = check_extent_data_item(fs_info, leaf, key, slot);
465 466
		break;
	case BTRFS_EXTENT_CSUM_KEY:
467
		ret = check_csum_item(fs_info, leaf, key, slot);
468
		break;
469 470 471
	case BTRFS_DIR_ITEM_KEY:
	case BTRFS_DIR_INDEX_KEY:
	case BTRFS_XATTR_ITEM_KEY:
472
		ret = check_dir_item(fs_info, leaf, key, slot);
473
		break;
474 475 476
	case BTRFS_BLOCK_GROUP_ITEM_KEY:
		ret = check_block_group_item(fs_info, leaf, key, slot);
		break;
477 478 479 480
	}
	return ret;
}

481
static int check_leaf(struct btrfs_fs_info *fs_info, struct extent_buffer *leaf,
482
		      bool check_item_data)
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
{
	/* 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)) {
499
		u64 owner = btrfs_header_owner(leaf);
500 501
		struct btrfs_root *check_root;

502 503 504 505 506 507 508 509 510 511 512 513 514
		/* 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(fs_info, leaf, 0,
			"invalid root, root %llu must never be empty",
				    owner);
			return -EUCLEAN;
		}
		key.objectid = owner;
515 516 517 518 519 520 521 522 523 524 525 526 527 528
		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) {
529
				generic_err(fs_info, leaf, 0,
530 531
		"invalid nritems, have %u should not be 0 for non-root leaf",
					nritems);
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
				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) {
562
			generic_err(fs_info, leaf, slot,
563 564 565 566
	"bad key order, prev (%llu %u %llu) current (%llu %u %llu)",
				prev_key.objectid, prev_key.type,
				prev_key.offset, key.objectid, key.type,
				key.offset);
567 568 569 570 571 572 573 574 575 576 577 578 579 580
			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(fs_info);
		else
			item_end_expected = btrfs_item_offset_nr(leaf,
								 slot - 1);
		if (btrfs_item_end_nr(leaf, slot) != item_end_expected) {
581
			generic_err(fs_info, leaf, slot,
582 583 584
				"unexpected item end, have %u expect %u",
				btrfs_item_end_nr(leaf, slot),
				item_end_expected);
585 586 587 588 589 590 591 592 593 594
			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(fs_info)) {
595
			generic_err(fs_info, leaf, slot,
596 597 598
			"slot end outside of leaf, have %u expect range [0, %u]",
				btrfs_item_end_nr(leaf, slot),
				BTRFS_LEAF_DATA_SIZE(fs_info));
599 600 601 602 603 604
			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)) {
605
			generic_err(fs_info, leaf, slot,
606 607 608 609
		"slot overlaps with its data, item end %lu data start %lu",
				btrfs_item_nr_offset(slot) +
				sizeof(struct btrfs_item),
				btrfs_item_ptr_offset(leaf, slot));
610 611 612
			return -EUCLEAN;
		}

613 614 615 616 617
		if (check_item_data) {
			/*
			 * Check if the item size and content meet other
			 * criteria
			 */
618
			ret = check_leaf_item(fs_info, leaf, &key, slot);
619 620 621
			if (ret < 0)
				return ret;
		}
622 623 624 625 626 627 628 629 630

		prev_key.objectid = key.objectid;
		prev_key.type = key.type;
		prev_key.offset = key.offset;
	}

	return 0;
}

631 632
int btrfs_check_leaf_full(struct btrfs_fs_info *fs_info,
			  struct extent_buffer *leaf)
633
{
634
	return check_leaf(fs_info, leaf, true);
635 636
}

637
int btrfs_check_leaf_relaxed(struct btrfs_fs_info *fs_info,
638 639
			     struct extent_buffer *leaf)
{
640
	return check_leaf(fs_info, leaf, false);
641 642
}

643
int btrfs_check_node(struct btrfs_fs_info *fs_info, struct extent_buffer *node)
644 645 646 647 648 649 650
{
	unsigned long nr = btrfs_header_nritems(node);
	struct btrfs_key key, next_key;
	int slot;
	u64 bytenr;
	int ret = 0;

651 652
	if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(fs_info)) {
		btrfs_crit(fs_info,
653
"corrupt node: root=%llu block=%llu, nritems too %s, have %lu expect range [1,%u]",
654
			   btrfs_header_owner(node), node->start,
655
			   nr == 0 ? "small" : "large", nr,
656
			   BTRFS_NODEPTRS_PER_BLOCK(fs_info));
657
		return -EUCLEAN;
658 659 660 661 662 663 664 665
	}

	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) {
666
			generic_err(fs_info, node, slot,
667 668 669 670
				"invalid NULL node pointer");
			ret = -EUCLEAN;
			goto out;
		}
671 672
		if (!IS_ALIGNED(bytenr, fs_info->sectorsize)) {
			generic_err(fs_info, node, slot,
673
			"unaligned pointer, have %llu should be aligned to %u",
674
				bytenr, fs_info->sectorsize);
675
			ret = -EUCLEAN;
676 677 678 679
			goto out;
		}

		if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) {
680
			generic_err(fs_info, node, slot,
681 682 683 684 685
	"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;
686 687 688 689 690 691
			goto out;
		}
	}
out:
	return ret;
}