Currently btrfs_validate_super() only does a very basic check on the array chunk size (not too large than the available space, but not too small to contain no chunk). The more comprehensive checks (the regular chunk checks and size check inside the system chunk array) are all done inside btrfs_read_sys_array(). It's not a big deal, but it also means we do not do any validation on the system chunk array at super block writeback time either. Do the following modification to centralize the system chunk array checks into btrfs_validate_super(): - Make chunk_err() helper accept stack chunk pointer If @leaf parameter is NULL, then the @chunk pointer will be a pointer to the chunk item, other than the offset inside the leaf. And since @leaf can be NULL, add a new @fs_info parameter for that case. - Make btrfs_check_chunk_valid() handle stack chunk pointer The same as chunk_err(), a new @fs_info parameter, and if @leaf is NULL, then @chunk will be a pointer to a stack chunk. If @chunk is NULL, then all needed btrfs_chunk members will be read using the stack helper instead of the leaf helper. This means we need to read out all the needed member at the beginning of the function. Furthermore, at super block read time, fs_info->sectorsize is not yet initialized, we need one extra @sectorsize parameter to grab the correct sectorsize. - Introduce a helper validate_sys_chunk_array() * Validate the disk key. * Validate the size before we access the full chunk items. * Do the full chunk item validation. - Call validate_sys_chunk_array() at btrfs_validate_super() - Simplify the checks inside btrfs_read_sys_array() Now the checks will be converted to an ASSERT(). - Simplify the checks inside read_one_chunk() Now that all chunk items inside system chunk array and chunk tree are verified, there is no need to verify them again inside read_one_chunk(). This change has the following advantages: - More comprehensive checks at write time And unlike the sys_chunk_array read routine, this time we do not need to allocate a dummy extent buffer to do the check. All the checks done here require no new memory allocation. - Slightly improved readability when iterating the system chunk array Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
78 lines
2.1 KiB
C
78 lines
2.1 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (C) Qu Wenruo 2017. All rights reserved.
|
|
*/
|
|
|
|
#ifndef BTRFS_TREE_CHECKER_H
|
|
#define BTRFS_TREE_CHECKER_H
|
|
|
|
#include <linux/types.h>
|
|
#include <uapi/linux/btrfs_tree.h>
|
|
|
|
struct extent_buffer;
|
|
struct btrfs_fs_info;
|
|
struct btrfs_chunk;
|
|
struct btrfs_key;
|
|
|
|
/* All the extra info needed to verify the parentness of a tree block. */
|
|
struct btrfs_tree_parent_check {
|
|
/*
|
|
* The owner check against the tree block.
|
|
*
|
|
* Can be 0 to skip the owner check.
|
|
*/
|
|
u64 owner_root;
|
|
|
|
/*
|
|
* Expected transid, can be 0 to skip the check, but such skip
|
|
* should only be utilized for backref walk related code.
|
|
*/
|
|
u64 transid;
|
|
|
|
/*
|
|
* The expected first key.
|
|
*
|
|
* This check can be skipped if @has_first_key is false, such skip
|
|
* can happen for case where we don't have the parent node key,
|
|
* e.g. reading the tree root, doing backref walk.
|
|
*/
|
|
struct btrfs_key first_key;
|
|
bool has_first_key;
|
|
|
|
/* The expected level. Should always be set. */
|
|
u8 level;
|
|
};
|
|
|
|
enum btrfs_tree_block_status {
|
|
BTRFS_TREE_BLOCK_CLEAN,
|
|
BTRFS_TREE_BLOCK_INVALID_NRITEMS,
|
|
BTRFS_TREE_BLOCK_INVALID_PARENT_KEY,
|
|
BTRFS_TREE_BLOCK_BAD_KEY_ORDER,
|
|
BTRFS_TREE_BLOCK_INVALID_LEVEL,
|
|
BTRFS_TREE_BLOCK_INVALID_FREE_SPACE,
|
|
BTRFS_TREE_BLOCK_INVALID_OFFSETS,
|
|
BTRFS_TREE_BLOCK_INVALID_BLOCKPTR,
|
|
BTRFS_TREE_BLOCK_INVALID_ITEM,
|
|
BTRFS_TREE_BLOCK_INVALID_OWNER,
|
|
BTRFS_TREE_BLOCK_WRITTEN_NOT_SET,
|
|
};
|
|
|
|
/*
|
|
* Exported simply for btrfs-progs which wants to have the
|
|
* btrfs_tree_block_status return codes.
|
|
*/
|
|
enum btrfs_tree_block_status __btrfs_check_leaf(struct extent_buffer *leaf);
|
|
enum btrfs_tree_block_status __btrfs_check_node(struct extent_buffer *node);
|
|
|
|
int btrfs_check_leaf(struct extent_buffer *leaf);
|
|
int btrfs_check_node(struct extent_buffer *node);
|
|
|
|
int btrfs_check_chunk_valid(const struct btrfs_fs_info *fs_info,
|
|
const struct extent_buffer *leaf,
|
|
const struct btrfs_chunk *chunk, u64 logical,
|
|
u32 sectorsize);
|
|
int btrfs_check_eb_owner(const struct extent_buffer *eb, u64 root_owner);
|
|
int btrfs_verify_level_key(struct extent_buffer *eb,
|
|
const struct btrfs_tree_parent_check *check);
|
|
|
|
#endif
|