Skip to content

Commit c8593f6

Browse files
josefbacikkdave
authored andcommitted
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 <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent ad5c224 commit c8593f6

File tree

16 files changed

+2186
-304
lines changed

16 files changed

+2186
-304
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ objects = \
187187
kernel-shared/print-tree.o \
188188
kernel-shared/root-tree.o \
189189
kernel-shared/transaction.o \
190+
kernel-shared/tree-checker.o \
190191
kernel-shared/ulist.o \
191192
kernel-shared/uuid-tree.o \
192193
kernel-shared/volumes.o \

check/main.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "kernel-shared/backref.h"
4545
#include "kernel-shared/ulist.h"
4646
#include "kernel-shared/file-item.h"
47+
#include "kernel-shared/tree-checker.h"
4748
#include "common/defs.h"
4849
#include "common/extent-cache.h"
4950
#include "common/internal.h"
@@ -9999,7 +10000,8 @@ static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
999910000
int qgroups_repaired = 0;
1000010001
int qgroup_verify_ret;
1000110002
unsigned ctree_flags = OPEN_CTREE_EXCLUSIVE |
10002-
OPEN_CTREE_ALLOW_TRANSID_MISMATCH;
10003+
OPEN_CTREE_ALLOW_TRANSID_MISMATCH |
10004+
OPEN_CTREE_SKIP_LEAF_ITEM_CHECKS;
1000310005
int force = 0;
1000410006

1000510007
while(1) {

check/mode-lowmem.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "kernel-shared/compression.h"
3232
#include "kernel-shared/volumes.h"
3333
#include "kernel-shared/file-item.h"
34+
#include "kernel-shared/tree-checker.h"
3435
#include "common/messages.h"
3536
#include "common/internal.h"
3637
#include "common/utils.h"

check/repair.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "kernel-shared/transaction.h"
2828
#include "kernel-shared/extent_io.h"
2929
#include "kernel-shared/disk-io.h"
30+
#include "kernel-shared/tree-checker.h"
3031
#include "common/extent-cache.h"
3132
#include "check/repair.h"
3233

image/main.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,7 +1025,8 @@ static int create_metadump(const char *input, FILE *out, int num_threads,
10251025
int ret;
10261026
int err = 0;
10271027

1028-
root = open_ctree(input, 0, OPEN_CTREE_ALLOW_TRANSID_MISMATCH);
1028+
root = open_ctree(input, 0, OPEN_CTREE_ALLOW_TRANSID_MISMATCH |
1029+
OPEN_CTREE_SKIP_LEAF_ITEM_CHECKS);
10291030
if (!root) {
10301031
error("open ctree failed");
10311032
return -EIO;
@@ -2798,7 +2799,7 @@ static int restore_metadump(const char *input, FILE *out, int old_restore,
27982799

27992800
ocf.filename = target;
28002801
ocf.flags = OPEN_CTREE_WRITES | OPEN_CTREE_RESTORE |
2801-
OPEN_CTREE_PARTIAL;
2802+
OPEN_CTREE_PARTIAL | OPEN_CTREE_SKIP_LEAF_ITEM_CHECKS;
28022803
info = open_ctree_fs_info(&ocf);
28032804
if (!info) {
28042805
error("open ctree failed");
@@ -2864,7 +2865,8 @@ static int restore_metadump(const char *input, FILE *out, int old_restore,
28642865
OPEN_CTREE_PARTIAL |
28652866
OPEN_CTREE_WRITES |
28662867
OPEN_CTREE_NO_DEVICES |
2867-
OPEN_CTREE_ALLOW_TRANSID_MISMATCH);
2868+
OPEN_CTREE_ALLOW_TRANSID_MISMATCH |
2869+
OPEN_CTREE_SKIP_LEAF_ITEM_CHECKS);
28682870
if (!root) {
28692871
error("open ctree failed in %s", target);
28702872
ret = -EIO;
@@ -2883,7 +2885,8 @@ static int restore_metadump(const char *input, FILE *out, int old_restore,
28832885

28842886
if (!info) {
28852887
root = open_ctree_fd(fileno(out), target, 0,
2886-
OPEN_CTREE_ALLOW_TRANSID_MISMATCH);
2888+
OPEN_CTREE_ALLOW_TRANSID_MISMATCH |
2889+
OPEN_CTREE_SKIP_LEAF_ITEM_CHECKS);
28872890
if (!root) {
28882891
error("open ctree failed in %s", target);
28892892
ret = -EIO;
@@ -3226,7 +3229,8 @@ int BOX_MAIN(image)(int argc, char *argv[])
32263229
int i;
32273230

32283231
ocf.filename = target;
3229-
ocf.flags = OPEN_CTREE_PARTIAL | OPEN_CTREE_RESTORE;
3232+
ocf.flags = OPEN_CTREE_PARTIAL | OPEN_CTREE_RESTORE |
3233+
OPEN_CTREE_SKIP_LEAF_ITEM_CHECKS;
32303234
info = open_ctree_fs_info(&ocf);
32313235
if (!info) {
32323236
error("open ctree failed at %s", target);

include/kerncompat.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
#define _RET_IP_ 0
8686
#define TASK_UNINTERRUPTIBLE 0
8787
#define SLAB_MEM_SPREAD 0
88+
#define ALLOW_ERROR_INJECTION(a, b)
8889

8990
#ifndef ULONG_MAX
9091
#define ULONG_MAX (~0UL)
@@ -417,6 +418,15 @@ do { \
417418
__ret_warn_on; \
418419
})
419420

421+
#define WARN(c, msg...) ({ \
422+
int __ret_warn_on = !!(c); \
423+
if (__ret_warn_on) \
424+
printf(msg); \
425+
__ret_warn_on; \
426+
})
427+
428+
#define IS_ENABLED(c) 0
429+
420430
#define container_of(ptr, type, member) ({ \
421431
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
422432
(type *)( (char *)__mptr - offsetof(type,member) );})

kernel-lib/bitops.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef _PERF_LINUX_BITOPS_H_
22
#define _PERF_LINUX_BITOPS_H_
33

4+
#include "kerncompat.h"
45
#include <endian.h>
56
#include "common/internal.h"
67

kernel-lib/raid56.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#ifndef __BTRFS_PROGS_RAID56_H__
2323
#define __BTRFS_PROGS_RAID56_H__
2424

25+
#include "kerncompat.h"
26+
2527
void raid6_gen_syndrome(int disks, size_t bytes, void **ptrs);
2628
int raid5_gen_result(int nr_devs, size_t stripe_len, int dest, void **data);
2729

kernel-shared/ctree.c

Lines changed: 4 additions & 182 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,18 @@
1616
* Boston, MA 021110-1307, USA.
1717
*/
1818

19+
#include "kernel-lib/bitops.h"
20+
#include "kernel-lib/sizes.h"
1921
#include "kernel-shared/ctree.h"
2022
#include "kernel-shared/disk-io.h"
2123
#include "kernel-shared/transaction.h"
2224
#include "kernel-shared/print-tree.h"
23-
#include "kernel-lib/bitops.h"
25+
#include "kernel-shared/tree-checker.h"
26+
#include "kernel-shared/volumes.h"
2427
#include "crypto/crc32c.h"
2528
#include "common/internal.h"
2629
#include "common/messages.h"
2730
#include "common/utils.h"
28-
#include "kernel-lib/sizes.h"
29-
#include "kernel-shared/volumes.h"
3031
#include "check/repair.h"
3132

3233
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)
602603
return btrfs_item_offset(leaf, nr - 1);
603604
}
604605

605-
static void generic_err(const struct extent_buffer *buf, int slot,
606-
const char *fmt, ...)
607-
{
608-
va_list args;
609-
610-
fprintf(stderr, "corrupt %s: root=%lld block=%llu slot=%d, ",
611-
btrfs_header_level(buf) == 0 ? "leaf": "node",
612-
btrfs_header_owner(buf), btrfs_header_bytenr(buf), slot);
613-
va_start(args, fmt);
614-
vfprintf(stderr, fmt, args);
615-
va_end(args);
616-
fprintf(stderr, "\n");
617-
}
618-
619-
enum btrfs_tree_block_status __btrfs_check_node(struct extent_buffer *node)
620-
{
621-
struct btrfs_fs_info *fs_info = node->fs_info;
622-
unsigned long nr = btrfs_header_nritems(node);
623-
struct btrfs_key key, next_key;
624-
int slot;
625-
int level = btrfs_header_level(node);
626-
u64 bytenr;
627-
enum btrfs_tree_block_status ret = BTRFS_TREE_BLOCK_INVALID_NRITEMS;
628-
629-
if (level <= 0 || level >= BTRFS_MAX_LEVEL) {
630-
generic_err(node, 0,
631-
"invalid level for node, have %d expect [1, %d]",
632-
level, BTRFS_MAX_LEVEL - 1);
633-
ret = BTRFS_TREE_BLOCK_INVALID_LEVEL;
634-
goto fail;
635-
}
636-
if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(fs_info)) {
637-
generic_err(node, 0,
638-
"corrupt node: root=%llu block=%llu, nritems too %s, have %lu expect range [1,%u]",
639-
btrfs_header_owner(node), node->start,
640-
nr == 0 ? "small" : "large", nr,
641-
BTRFS_NODEPTRS_PER_BLOCK(fs_info));
642-
ret = BTRFS_TREE_BLOCK_INVALID_NRITEMS;
643-
goto fail;
644-
}
645-
646-
for (slot = 0; slot < nr - 1; slot++) {
647-
bytenr = btrfs_node_blockptr(node, slot);
648-
btrfs_node_key_to_cpu(node, &key, slot);
649-
btrfs_node_key_to_cpu(node, &next_key, slot + 1);
650-
651-
if (!bytenr) {
652-
generic_err(node, slot,
653-
"invalid NULL node pointer");
654-
ret = BTRFS_TREE_BLOCK_INVALID_BLOCKPTR;
655-
goto fail;
656-
}
657-
if (!IS_ALIGNED(bytenr, fs_info->sectorsize)) {
658-
generic_err(node, slot,
659-
"unaligned pointer, have %llu should be aligned to %u",
660-
bytenr, fs_info->sectorsize);
661-
ret = BTRFS_TREE_BLOCK_INVALID_BLOCKPTR;
662-
goto fail;
663-
}
664-
665-
if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) {
666-
generic_err(node, slot,
667-
"bad key order, current (%llu %u %llu) next (%llu %u %llu)",
668-
key.objectid, key.type, key.offset,
669-
next_key.objectid, next_key.type,
670-
next_key.offset);
671-
ret = BTRFS_TREE_BLOCK_BAD_KEY_ORDER;
672-
goto fail;
673-
}
674-
}
675-
ret = BTRFS_TREE_BLOCK_CLEAN;
676-
fail:
677-
return ret;
678-
}
679-
680-
enum btrfs_tree_block_status __btrfs_check_leaf(struct extent_buffer *leaf)
681-
{
682-
struct btrfs_fs_info *fs_info = leaf->fs_info;
683-
/* No valid key type is 0, so all key should be larger than this key */
684-
struct btrfs_key prev_key = {0, 0, 0};
685-
struct btrfs_key key;
686-
u32 nritems = btrfs_header_nritems(leaf);
687-
int slot;
688-
int ret;
689-
690-
if (btrfs_header_level(leaf) != 0) {
691-
generic_err(leaf, 0,
692-
"invalid level for leaf, have %d expect 0",
693-
btrfs_header_level(leaf));
694-
ret = BTRFS_TREE_BLOCK_INVALID_LEVEL;
695-
goto fail;
696-
}
697-
698-
if (nritems == 0)
699-
return 0;
700-
701-
/*
702-
* Check the following things to make sure this is a good leaf, and
703-
* leaf users won't need to bother with similar sanity checks:
704-
*
705-
* 1) key ordering
706-
* 2) item offset and size
707-
* No overlap, no hole, all inside the leaf.
708-
* 3) item content
709-
* If possible, do comprehensive sanity check.
710-
* NOTE: All checks must only rely on the item data itself.
711-
*/
712-
for (slot = 0; slot < nritems; slot++) {
713-
u32 item_end_expected;
714-
u64 item_data_end;
715-
716-
btrfs_item_key_to_cpu(leaf, &key, slot);
717-
718-
/* Make sure the keys are in the right order */
719-
if (btrfs_comp_cpu_keys(&prev_key, &key) >= 0) {
720-
generic_err(leaf, slot,
721-
"bad key order, prev (%llu %u %llu) current (%llu %u %llu)",
722-
prev_key.objectid, prev_key.type,
723-
prev_key.offset, key.objectid, key.type,
724-
key.offset);
725-
ret = BTRFS_TREE_BLOCK_BAD_KEY_ORDER;
726-
goto fail;
727-
}
728-
729-
item_data_end = (u64)btrfs_item_offset(leaf, slot) +
730-
btrfs_item_size(leaf, slot);
731-
/*
732-
* Make sure the offset and ends are right, remember that the
733-
* item data starts at the end of the leaf and grows towards the
734-
* front.
735-
*/
736-
if (slot == 0)
737-
item_end_expected = BTRFS_LEAF_DATA_SIZE(fs_info);
738-
else
739-
item_end_expected = btrfs_item_offset(leaf,
740-
slot - 1);
741-
if (item_data_end != item_end_expected) {
742-
generic_err(leaf, slot,
743-
"unexpected item end, have %llu expect %u",
744-
item_data_end, item_end_expected);
745-
ret = BTRFS_TREE_BLOCK_INVALID_OFFSETS;
746-
goto fail;
747-
}
748-
749-
/*
750-
* Check to make sure that we don't point outside of the leaf,
751-
* just in case all the items are consistent to each other, but
752-
* all point outside of the leaf.
753-
*/
754-
if (item_data_end > BTRFS_LEAF_DATA_SIZE(fs_info)) {
755-
generic_err(leaf, slot,
756-
"slot end outside of leaf, have %llu expect range [0, %u]",
757-
item_data_end, BTRFS_LEAF_DATA_SIZE(fs_info));
758-
ret = BTRFS_TREE_BLOCK_INVALID_OFFSETS;
759-
goto fail;
760-
}
761-
762-
/* Also check if the item pointer overlaps with btrfs item. */
763-
if (btrfs_item_ptr_offset(leaf, slot) <
764-
btrfs_item_nr_offset(leaf, slot) + sizeof(struct btrfs_item)) {
765-
generic_err(leaf, slot,
766-
"slot overlaps with its data, item end %lu data start %lu",
767-
btrfs_item_nr_offset(leaf, slot) +
768-
sizeof(struct btrfs_item),
769-
btrfs_item_ptr_offset(leaf, slot));
770-
ret = BTRFS_TREE_BLOCK_INVALID_OFFSETS;
771-
goto fail;
772-
}
773-
774-
prev_key.objectid = key.objectid;
775-
prev_key.type = key.type;
776-
prev_key.offset = key.offset;
777-
}
778-
779-
ret = BTRFS_TREE_BLOCK_CLEAN;
780-
fail:
781-
return ret;
782-
}
783-
784606
static int noinline check_block(struct btrfs_fs_info *fs_info,
785607
struct btrfs_path *path, int level)
786608
{

kernel-shared/ctree.h

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -185,17 +185,6 @@ struct btrfs_path {
185185
sizeof(struct btrfs_item))
186186
#define BTRFS_MAX_EXTENT_SIZE 128UL * 1024 * 1024
187187

188-
enum btrfs_tree_block_status {
189-
BTRFS_TREE_BLOCK_CLEAN,
190-
BTRFS_TREE_BLOCK_INVALID_NRITEMS,
191-
BTRFS_TREE_BLOCK_INVALID_PARENT_KEY,
192-
BTRFS_TREE_BLOCK_BAD_KEY_ORDER,
193-
BTRFS_TREE_BLOCK_INVALID_LEVEL,
194-
BTRFS_TREE_BLOCK_INVALID_FREE_SPACE,
195-
BTRFS_TREE_BLOCK_INVALID_OFFSETS,
196-
BTRFS_TREE_BLOCK_INVALID_BLOCKPTR,
197-
};
198-
199188
/*
200189
* We don't want to overwrite 1M at the beginning of device, even though
201190
* there is our 1st superblock at 64k. Some possible reasons:
@@ -373,6 +362,7 @@ struct btrfs_fs_info {
373362
unsigned int finalize_on_close:1;
374363
unsigned int hide_names:1;
375364
unsigned int allow_transid_mismatch:1;
365+
unsigned int skip_leaf_item_checks:1;
376366

377367
int transaction_aborted;
378368
int force_csum_type;
@@ -958,8 +948,6 @@ int btrfs_convert_one_bg(struct btrfs_trans_handle *trans, u64 bytenr);
958948
int btrfs_comp_cpu_keys(const struct btrfs_key *k1, const struct btrfs_key *k2);
959949
int btrfs_del_ptr(struct btrfs_root *root, struct btrfs_path *path,
960950
int level, int slot);
961-
enum btrfs_tree_block_status __btrfs_check_node(struct extent_buffer *buf);
962-
enum btrfs_tree_block_status __btrfs_check_leaf(struct extent_buffer *buf);
963951
struct extent_buffer *read_node_slot(struct btrfs_fs_info *fs_info,
964952
struct extent_buffer *parent, int slot);
965953
int btrfs_previous_item(struct btrfs_root *root,

0 commit comments

Comments
 (0)