mirror of
https://github.com/kdave/btrfs-progs
synced 2025-03-03 09:18:11 +00:00
btrfs-progs: sync tree-checker.[ch] from kernel
This syncs tree-checker.c from the kernel. The main modification was to add a open ctree flag to skip the deeper leaf checks, and plumbing this through tree-checker.c. We need this for things like fsck or btrfs-image that need to work with slightly corrupted file systems, and these checks simply make us unable to look at the corrupted blocks. Signed-off-by: Josef Bacik <josef@toxicpanda.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
180bd5edd1
commit
e150c843ea
1
Makefile
1
Makefile
@ -187,6 +187,7 @@ objects = \
|
||||
kernel-shared/print-tree.o \
|
||||
kernel-shared/root-tree.o \
|
||||
kernel-shared/transaction.o \
|
||||
kernel-shared/tree-checker.o \
|
||||
kernel-shared/ulist.o \
|
||||
kernel-shared/uuid-tree.o \
|
||||
kernel-shared/volumes.o \
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "kernel-shared/backref.h"
|
||||
#include "kernel-shared/ulist.h"
|
||||
#include "kernel-shared/file-item.h"
|
||||
#include "kernel-shared/tree-checker.h"
|
||||
#include "common/defs.h"
|
||||
#include "common/extent-cache.h"
|
||||
#include "common/internal.h"
|
||||
@ -9999,7 +10000,8 @@ static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
|
||||
int qgroups_repaired = 0;
|
||||
int qgroup_verify_ret;
|
||||
unsigned ctree_flags = OPEN_CTREE_EXCLUSIVE |
|
||||
OPEN_CTREE_ALLOW_TRANSID_MISMATCH;
|
||||
OPEN_CTREE_ALLOW_TRANSID_MISMATCH |
|
||||
OPEN_CTREE_SKIP_LEAF_ITEM_CHECKS;
|
||||
int force = 0;
|
||||
|
||||
while(1) {
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "kernel-shared/compression.h"
|
||||
#include "kernel-shared/volumes.h"
|
||||
#include "kernel-shared/file-item.h"
|
||||
#include "kernel-shared/tree-checker.h"
|
||||
#include "common/messages.h"
|
||||
#include "common/internal.h"
|
||||
#include "common/utils.h"
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "kernel-shared/transaction.h"
|
||||
#include "kernel-shared/extent_io.h"
|
||||
#include "kernel-shared/disk-io.h"
|
||||
#include "kernel-shared/tree-checker.h"
|
||||
#include "common/extent-cache.h"
|
||||
#include "check/repair.h"
|
||||
|
||||
|
14
image/main.c
14
image/main.c
@ -1025,7 +1025,8 @@ static int create_metadump(const char *input, FILE *out, int num_threads,
|
||||
int ret;
|
||||
int err = 0;
|
||||
|
||||
root = open_ctree(input, 0, OPEN_CTREE_ALLOW_TRANSID_MISMATCH);
|
||||
root = open_ctree(input, 0, OPEN_CTREE_ALLOW_TRANSID_MISMATCH |
|
||||
OPEN_CTREE_SKIP_LEAF_ITEM_CHECKS);
|
||||
if (!root) {
|
||||
error("open ctree failed");
|
||||
return -EIO;
|
||||
@ -2798,7 +2799,7 @@ static int restore_metadump(const char *input, FILE *out, int old_restore,
|
||||
|
||||
ocf.filename = target;
|
||||
ocf.flags = OPEN_CTREE_WRITES | OPEN_CTREE_RESTORE |
|
||||
OPEN_CTREE_PARTIAL;
|
||||
OPEN_CTREE_PARTIAL | OPEN_CTREE_SKIP_LEAF_ITEM_CHECKS;
|
||||
info = open_ctree_fs_info(&ocf);
|
||||
if (!info) {
|
||||
error("open ctree failed");
|
||||
@ -2864,7 +2865,8 @@ static int restore_metadump(const char *input, FILE *out, int old_restore,
|
||||
OPEN_CTREE_PARTIAL |
|
||||
OPEN_CTREE_WRITES |
|
||||
OPEN_CTREE_NO_DEVICES |
|
||||
OPEN_CTREE_ALLOW_TRANSID_MISMATCH);
|
||||
OPEN_CTREE_ALLOW_TRANSID_MISMATCH |
|
||||
OPEN_CTREE_SKIP_LEAF_ITEM_CHECKS);
|
||||
if (!root) {
|
||||
error("open ctree failed in %s", target);
|
||||
ret = -EIO;
|
||||
@ -2883,7 +2885,8 @@ static int restore_metadump(const char *input, FILE *out, int old_restore,
|
||||
|
||||
if (!info) {
|
||||
root = open_ctree_fd(fileno(out), target, 0,
|
||||
OPEN_CTREE_ALLOW_TRANSID_MISMATCH);
|
||||
OPEN_CTREE_ALLOW_TRANSID_MISMATCH |
|
||||
OPEN_CTREE_SKIP_LEAF_ITEM_CHECKS);
|
||||
if (!root) {
|
||||
error("open ctree failed in %s", target);
|
||||
ret = -EIO;
|
||||
@ -3226,7 +3229,8 @@ int BOX_MAIN(image)(int argc, char *argv[])
|
||||
int i;
|
||||
|
||||
ocf.filename = target;
|
||||
ocf.flags = OPEN_CTREE_PARTIAL | OPEN_CTREE_RESTORE;
|
||||
ocf.flags = OPEN_CTREE_PARTIAL | OPEN_CTREE_RESTORE |
|
||||
OPEN_CTREE_SKIP_LEAF_ITEM_CHECKS;
|
||||
info = open_ctree_fs_info(&ocf);
|
||||
if (!info) {
|
||||
error("open ctree failed at %s", target);
|
||||
|
@ -85,6 +85,7 @@
|
||||
#define _RET_IP_ 0
|
||||
#define TASK_UNINTERRUPTIBLE 0
|
||||
#define SLAB_MEM_SPREAD 0
|
||||
#define ALLOW_ERROR_INJECTION(a, b)
|
||||
|
||||
#ifndef ULONG_MAX
|
||||
#define ULONG_MAX (~0UL)
|
||||
@ -417,6 +418,15 @@ do { \
|
||||
__ret_warn_on; \
|
||||
})
|
||||
|
||||
#define WARN(c, msg...) ({ \
|
||||
int __ret_warn_on = !!(c); \
|
||||
if (__ret_warn_on) \
|
||||
printf(msg); \
|
||||
__ret_warn_on; \
|
||||
})
|
||||
|
||||
#define IS_ENABLED(c) 0
|
||||
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||
(type *)( (char *)__mptr - offsetof(type,member) );})
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef _PERF_LINUX_BITOPS_H_
|
||||
#define _PERF_LINUX_BITOPS_H_
|
||||
|
||||
#include "kerncompat.h"
|
||||
#include <endian.h>
|
||||
#include "common/internal.h"
|
||||
|
||||
|
@ -22,6 +22,8 @@
|
||||
#ifndef __BTRFS_PROGS_RAID56_H__
|
||||
#define __BTRFS_PROGS_RAID56_H__
|
||||
|
||||
#include "kerncompat.h"
|
||||
|
||||
void raid6_gen_syndrome(int disks, size_t bytes, void **ptrs);
|
||||
int raid5_gen_result(int nr_devs, size_t stripe_len, int dest, void **data);
|
||||
|
||||
|
@ -16,17 +16,18 @@
|
||||
* Boston, MA 021110-1307, USA.
|
||||
*/
|
||||
|
||||
#include "kernel-lib/bitops.h"
|
||||
#include "kernel-lib/sizes.h"
|
||||
#include "kernel-shared/ctree.h"
|
||||
#include "kernel-shared/disk-io.h"
|
||||
#include "kernel-shared/transaction.h"
|
||||
#include "kernel-shared/print-tree.h"
|
||||
#include "kernel-lib/bitops.h"
|
||||
#include "kernel-shared/tree-checker.h"
|
||||
#include "kernel-shared/volumes.h"
|
||||
#include "crypto/crc32c.h"
|
||||
#include "common/internal.h"
|
||||
#include "common/messages.h"
|
||||
#include "common/utils.h"
|
||||
#include "kernel-lib/sizes.h"
|
||||
#include "kernel-shared/volumes.h"
|
||||
#include "check/repair.h"
|
||||
|
||||
static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
@ -602,185 +603,6 @@ static inline unsigned int leaf_data_end(const struct extent_buffer *leaf)
|
||||
return btrfs_item_offset(leaf, nr - 1);
|
||||
}
|
||||
|
||||
static void generic_err(const struct extent_buffer *buf, int slot,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
fprintf(stderr, "corrupt %s: root=%lld block=%llu slot=%d, ",
|
||||
btrfs_header_level(buf) == 0 ? "leaf": "node",
|
||||
btrfs_header_owner(buf), btrfs_header_bytenr(buf), slot);
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
enum btrfs_tree_block_status __btrfs_check_node(struct extent_buffer *node)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = node->fs_info;
|
||||
unsigned long nr = btrfs_header_nritems(node);
|
||||
struct btrfs_key key, next_key;
|
||||
int slot;
|
||||
int level = btrfs_header_level(node);
|
||||
u64 bytenr;
|
||||
enum btrfs_tree_block_status ret = BTRFS_TREE_BLOCK_INVALID_NRITEMS;
|
||||
|
||||
if (level <= 0 || level >= BTRFS_MAX_LEVEL) {
|
||||
generic_err(node, 0,
|
||||
"invalid level for node, have %d expect [1, %d]",
|
||||
level, BTRFS_MAX_LEVEL - 1);
|
||||
ret = BTRFS_TREE_BLOCK_INVALID_LEVEL;
|
||||
goto fail;
|
||||
}
|
||||
if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(fs_info)) {
|
||||
generic_err(node, 0,
|
||||
"corrupt node: root=%llu block=%llu, nritems too %s, have %lu expect range [1,%u]",
|
||||
btrfs_header_owner(node), node->start,
|
||||
nr == 0 ? "small" : "large", nr,
|
||||
BTRFS_NODEPTRS_PER_BLOCK(fs_info));
|
||||
ret = BTRFS_TREE_BLOCK_INVALID_NRITEMS;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
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) {
|
||||
generic_err(node, slot,
|
||||
"invalid NULL node pointer");
|
||||
ret = BTRFS_TREE_BLOCK_INVALID_BLOCKPTR;
|
||||
goto fail;
|
||||
}
|
||||
if (!IS_ALIGNED(bytenr, fs_info->sectorsize)) {
|
||||
generic_err(node, slot,
|
||||
"unaligned pointer, have %llu should be aligned to %u",
|
||||
bytenr, fs_info->sectorsize);
|
||||
ret = BTRFS_TREE_BLOCK_INVALID_BLOCKPTR;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) {
|
||||
generic_err(node, slot,
|
||||
"bad key order, current (%llu %u %llu) next (%llu %u %llu)",
|
||||
key.objectid, key.type, key.offset,
|
||||
next_key.objectid, next_key.type,
|
||||
next_key.offset);
|
||||
ret = BTRFS_TREE_BLOCK_BAD_KEY_ORDER;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
ret = BTRFS_TREE_BLOCK_CLEAN;
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum btrfs_tree_block_status __btrfs_check_leaf(struct extent_buffer *leaf)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = leaf->fs_info;
|
||||
/* No valid key type is 0, so all key should be larger than this key */
|
||||
struct btrfs_key prev_key = {0, 0, 0};
|
||||
struct btrfs_key key;
|
||||
u32 nritems = btrfs_header_nritems(leaf);
|
||||
int slot;
|
||||
int ret;
|
||||
|
||||
if (btrfs_header_level(leaf) != 0) {
|
||||
generic_err(leaf, 0,
|
||||
"invalid level for leaf, have %d expect 0",
|
||||
btrfs_header_level(leaf));
|
||||
ret = BTRFS_TREE_BLOCK_INVALID_LEVEL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
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;
|
||||
u64 item_data_end;
|
||||
|
||||
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) {
|
||||
generic_err(leaf, slot,
|
||||
"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);
|
||||
ret = BTRFS_TREE_BLOCK_BAD_KEY_ORDER;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
item_data_end = (u64)btrfs_item_offset(leaf, slot) +
|
||||
btrfs_item_size(leaf, slot);
|
||||
/*
|
||||
* 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(leaf,
|
||||
slot - 1);
|
||||
if (item_data_end != item_end_expected) {
|
||||
generic_err(leaf, slot,
|
||||
"unexpected item end, have %llu expect %u",
|
||||
item_data_end, item_end_expected);
|
||||
ret = BTRFS_TREE_BLOCK_INVALID_OFFSETS;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 (item_data_end > BTRFS_LEAF_DATA_SIZE(fs_info)) {
|
||||
generic_err(leaf, slot,
|
||||
"slot end outside of leaf, have %llu expect range [0, %u]",
|
||||
item_data_end, BTRFS_LEAF_DATA_SIZE(fs_info));
|
||||
ret = BTRFS_TREE_BLOCK_INVALID_OFFSETS;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Also check if the item pointer overlaps with btrfs item. */
|
||||
if (btrfs_item_ptr_offset(leaf, slot) <
|
||||
btrfs_item_nr_offset(leaf, slot) + sizeof(struct btrfs_item)) {
|
||||
generic_err(leaf, slot,
|
||||
"slot overlaps with its data, item end %lu data start %lu",
|
||||
btrfs_item_nr_offset(leaf, slot) +
|
||||
sizeof(struct btrfs_item),
|
||||
btrfs_item_ptr_offset(leaf, slot));
|
||||
ret = BTRFS_TREE_BLOCK_INVALID_OFFSETS;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
prev_key.objectid = key.objectid;
|
||||
prev_key.type = key.type;
|
||||
prev_key.offset = key.offset;
|
||||
}
|
||||
|
||||
ret = BTRFS_TREE_BLOCK_CLEAN;
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int noinline check_block(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_path *path, int level)
|
||||
{
|
||||
|
@ -185,17 +185,6 @@ struct btrfs_path {
|
||||
sizeof(struct btrfs_item))
|
||||
#define BTRFS_MAX_EXTENT_SIZE 128UL * 1024 * 1024
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
/*
|
||||
* We don't want to overwrite 1M at the beginning of device, even though
|
||||
* there is our 1st superblock at 64k. Some possible reasons:
|
||||
@ -373,6 +362,7 @@ struct btrfs_fs_info {
|
||||
unsigned int finalize_on_close:1;
|
||||
unsigned int hide_names:1;
|
||||
unsigned int allow_transid_mismatch:1;
|
||||
unsigned int skip_leaf_item_checks:1;
|
||||
|
||||
int transaction_aborted;
|
||||
int force_csum_type;
|
||||
@ -958,8 +948,6 @@ int btrfs_convert_one_bg(struct btrfs_trans_handle *trans, u64 bytenr);
|
||||
int btrfs_comp_cpu_keys(const struct btrfs_key *k1, const struct btrfs_key *k2);
|
||||
int btrfs_del_ptr(struct btrfs_root *root, struct btrfs_path *path,
|
||||
int level, int slot);
|
||||
enum btrfs_tree_block_status __btrfs_check_node(struct extent_buffer *buf);
|
||||
enum btrfs_tree_block_status __btrfs_check_leaf(struct extent_buffer *buf);
|
||||
struct extent_buffer *read_node_slot(struct btrfs_fs_info *fs_info,
|
||||
struct extent_buffer *parent, int slot);
|
||||
int btrfs_previous_item(struct btrfs_root *root,
|
||||
|
@ -24,19 +24,20 @@
|
||||
#include <unistd.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include "kerncompat.h"
|
||||
#include "kernel-lib/bitops.h"
|
||||
#include "kernel-shared/ctree.h"
|
||||
#include "kernel-shared/disk-io.h"
|
||||
#include "kernel-shared/volumes.h"
|
||||
#include "kernel-shared/transaction.h"
|
||||
#include "zoned.h"
|
||||
#include "kernel-shared/tree-checker.h"
|
||||
#include "kernel-shared/zoned.h"
|
||||
#include "kernel-shared/print-tree.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "crypto/crc32c.h"
|
||||
#include "common/utils.h"
|
||||
#include "kernel-shared/print-tree.h"
|
||||
#include "kernel-lib/bitops.h"
|
||||
#include "common/rbtree-utils.h"
|
||||
#include "common/device-scan.h"
|
||||
#include "common/device-utils.h"
|
||||
#include "crypto/hash.h"
|
||||
|
||||
/* specified errno for check_tree_block */
|
||||
#define BTRFS_BAD_BYTENR (-1)
|
||||
@ -1503,6 +1504,8 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, struct open_ctree_flags *oc
|
||||
fs_info->hide_names = 1;
|
||||
if (flags & OPEN_CTREE_ALLOW_TRANSID_MISMATCH)
|
||||
fs_info->allow_transid_mismatch = 1;
|
||||
if (flags & OPEN_CTREE_SKIP_LEAF_ITEM_CHECKS)
|
||||
fs_info->skip_leaf_item_checks = 1;
|
||||
|
||||
if ((flags & OPEN_CTREE_RECOVER_SUPER)
|
||||
&& (flags & OPEN_CTREE_TEMPORARY_SUPER)) {
|
||||
|
@ -98,6 +98,12 @@ enum btrfs_open_ctree_flags {
|
||||
* stored in the csum tree during conversion.
|
||||
*/
|
||||
OPEN_CTREE_SKIP_CSUM_CHECK = (1U << 16),
|
||||
|
||||
/*
|
||||
* Allow certain commands like check/restore to ignore more structure
|
||||
* specific checks and only do the superficial checks.
|
||||
*/
|
||||
OPEN_CTREE_SKIP_LEAF_ITEM_CHECKS = (1U << 17),
|
||||
};
|
||||
|
||||
/*
|
||||
|
2064
kernel-shared/tree-checker.c
Normal file
2064
kernel-shared/tree-checker.c
Normal file
File diff suppressed because it is too large
Load Diff
73
kernel-shared/tree-checker.h
Normal file
73
kernel-shared/tree-checker.h
Normal file
@ -0,0 +1,73 @@
|
||||
/* 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 "kerncompat.h"
|
||||
#include "uapi/btrfs_tree.h"
|
||||
|
||||
struct extent_buffer;
|
||||
struct btrfs_chunk;
|
||||
|
||||
/* 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 utlized 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,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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(struct extent_buffer *leaf,
|
||||
struct btrfs_chunk *chunk, u64 logical);
|
||||
int btrfs_check_eb_owner(const struct extent_buffer *eb, u64 root_owner);
|
||||
int btrfs_verify_level_key(struct extent_buffer *eb, int level,
|
||||
struct btrfs_key *first_key, u64 parent_transid);
|
||||
|
||||
#endif
|
@ -23,15 +23,16 @@
|
||||
#include <uuid/uuid.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include "kernel-lib/raid56.h"
|
||||
#include "kernel-shared/ctree.h"
|
||||
#include "kernel-shared/disk-io.h"
|
||||
#include "kernel-shared/transaction.h"
|
||||
#include "kernel-shared/print-tree.h"
|
||||
#include "kernel-shared/volumes.h"
|
||||
#include "zoned.h"
|
||||
#include "kernel-shared/tree-checker.h"
|
||||
#include "kernel-shared/zoned.h"
|
||||
#include "common/utils.h"
|
||||
#include "common/device-utils.h"
|
||||
#include "kernel-lib/raid56.h"
|
||||
|
||||
const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES] = {
|
||||
[BTRFS_RAID_RAID10] = {
|
||||
@ -2086,101 +2087,6 @@ static struct btrfs_device *fill_missing_device(u64 devid)
|
||||
return device;
|
||||
}
|
||||
|
||||
/*
|
||||
* slot == -1: SYSTEM chunk
|
||||
* return -EIO on error, otherwise return 0
|
||||
*/
|
||||
int btrfs_check_chunk_valid(struct extent_buffer *leaf,
|
||||
struct btrfs_chunk *chunk, u64 logical)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = leaf->fs_info;
|
||||
u64 length;
|
||||
u64 stripe_len;
|
||||
u16 num_stripes;
|
||||
u16 sub_stripes;
|
||||
u64 type;
|
||||
u32 sectorsize = fs_info->sectorsize;
|
||||
int min_devs;
|
||||
int table_sub_stripes;
|
||||
|
||||
length = btrfs_chunk_length(leaf, chunk);
|
||||
stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
|
||||
num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
|
||||
sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk);
|
||||
type = btrfs_chunk_type(leaf, chunk);
|
||||
|
||||
if (num_stripes == 0) {
|
||||
error("invalid num_stripes, have %u expect non-zero",
|
||||
num_stripes);
|
||||
return -EUCLEAN;
|
||||
}
|
||||
|
||||
/*
|
||||
* These valid checks may be insufficient to cover every corner cases.
|
||||
*/
|
||||
if (!IS_ALIGNED(logical, sectorsize)) {
|
||||
error("invalid chunk logical %llu", logical);
|
||||
return -EIO;
|
||||
}
|
||||
if (btrfs_chunk_sector_size(leaf, chunk) != sectorsize) {
|
||||
error("invalid chunk sectorsize %llu",
|
||||
(unsigned long long)btrfs_chunk_sector_size(leaf, chunk));
|
||||
return -EIO;
|
||||
}
|
||||
if (!length || !IS_ALIGNED(length, sectorsize)) {
|
||||
error("invalid chunk length %llu", length);
|
||||
return -EIO;
|
||||
}
|
||||
if (stripe_len != BTRFS_STRIPE_LEN) {
|
||||
error("invalid chunk stripe length: %llu", stripe_len);
|
||||
return -EIO;
|
||||
}
|
||||
if (type & ~(BTRFS_BLOCK_GROUP_TYPE_MASK |
|
||||
BTRFS_BLOCK_GROUP_PROFILE_MASK)) {
|
||||
error("unrecognized chunk type: %llu",
|
||||
~(BTRFS_BLOCK_GROUP_TYPE_MASK |
|
||||
BTRFS_BLOCK_GROUP_PROFILE_MASK) & type);
|
||||
return -EIO;
|
||||
}
|
||||
if (!(type & BTRFS_BLOCK_GROUP_TYPE_MASK)) {
|
||||
error("missing chunk type flag: %llu", type);
|
||||
return -EIO;
|
||||
}
|
||||
if (!(is_power_of_2(type & BTRFS_BLOCK_GROUP_PROFILE_MASK) ||
|
||||
(type & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0)) {
|
||||
error("conflicting chunk type detected: %llu", type);
|
||||
return -EIO;
|
||||
}
|
||||
if ((type & BTRFS_BLOCK_GROUP_PROFILE_MASK) &&
|
||||
!is_power_of_2(type & BTRFS_BLOCK_GROUP_PROFILE_MASK)) {
|
||||
error("conflicting chunk profile detected: %llu", type);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Device number check against profile
|
||||
*/
|
||||
min_devs = btrfs_bg_type_to_devs_min(type);
|
||||
table_sub_stripes = btrfs_bg_type_to_sub_stripes(type);
|
||||
if ((type & BTRFS_BLOCK_GROUP_RAID10 && (sub_stripes != table_sub_stripes ||
|
||||
!IS_ALIGNED(num_stripes, sub_stripes))) ||
|
||||
(type & BTRFS_BLOCK_GROUP_RAID1 && num_stripes < min_devs) ||
|
||||
(type & BTRFS_BLOCK_GROUP_RAID1C3 && num_stripes < min_devs) ||
|
||||
(type & BTRFS_BLOCK_GROUP_RAID1C4 && num_stripes < min_devs) ||
|
||||
(type & BTRFS_BLOCK_GROUP_RAID5 && num_stripes < min_devs) ||
|
||||
(type & BTRFS_BLOCK_GROUP_RAID6 && num_stripes < min_devs) ||
|
||||
(type & BTRFS_BLOCK_GROUP_DUP && num_stripes > 2) ||
|
||||
((type & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0 &&
|
||||
num_stripes != 1)) {
|
||||
error("Invalid num_stripes:sub_stripes %u:%u for profile %llu",
|
||||
num_stripes, sub_stripes,
|
||||
type & BTRFS_BLOCK_GROUP_PROFILE_MASK);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Slot is used to verify the chunk item is valid
|
||||
*
|
||||
|
@ -294,8 +294,6 @@ int write_raid56_with_parity(struct btrfs_fs_info *info,
|
||||
struct extent_buffer *eb,
|
||||
struct btrfs_multi_bio *multi,
|
||||
u64 stripe_len, u64 *raid_map);
|
||||
int btrfs_check_chunk_valid(struct extent_buffer *leaf,
|
||||
struct btrfs_chunk *chunk, u64 logical);
|
||||
u64 btrfs_stripe_length(struct btrfs_fs_info *fs_info,
|
||||
struct extent_buffer *leaf,
|
||||
struct btrfs_chunk *chunk);
|
||||
|
Loading…
Reference in New Issue
Block a user