Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fd708b81 authored by Josef Bacik's avatar Josef Bacik Committed by David Sterba
Browse files

Btrfs: add a extent ref verify tool



We were having corruption issues that were tied back to problems with
the extent tree.  In order to track them down I built this tool to try
and find the culprit, which was pretty successful.  If you compile with
this tool on it will live verify every ref update that the fs makes and
make sure it is consistent and valid.  I've run this through with
xfstests and haven't gotten any false positives.  Thanks,

Signed-off-by: default avatarJosef Bacik <jbacik@fb.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
[ update error messages, add fixup from Dan Carpenter to handle errors
  of read_tree_block ]
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 84f7d8e6
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -91,3 +91,14 @@ config BTRFS_ASSERT
	  any of the assertions trip.  This is meant for btrfs developers only.

	  If unsure, say N.

config BTRFS_FS_REF_VERIFY
	bool "Btrfs with the ref verify tool compiled in"
	depends on BTRFS_FS
	default n
	help
	  Enable run-time extent reference verification instrumentation.  This
	  is meant to be used by btrfs developers for tracking down extent
	  reference problems or verifying they didn't break something.

	  If unsure, say N.
+1 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \

btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
btrfs-$(CONFIG_BTRFS_FS_REF_VERIFY) += ref-verify.o

btrfs-$(CONFIG_BTRFS_FS_RUN_SANITY_TESTS) += tests/free-space-tests.o \
	tests/extent-buffer-tests.o tests/btrfs-tests.o \
+5 −0
Original line number Diff line number Diff line
@@ -1097,6 +1097,11 @@ struct btrfs_fs_info {
	u32 nodesize;
	u32 sectorsize;
	u32 stripesize;

#ifdef CONFIG_BTRFS_FS_REF_VERIFY
	spinlock_t ref_verify_lock;
	struct rb_root block_tree;
#endif
};

static inline struct btrfs_fs_info *btrfs_sb(struct super_block *sb)
+6 −0
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@
#include "qgroup.h"
#include "compression.h"
#include "tree-checker.h"
#include "ref-verify.h"

#ifdef CONFIG_X86
#include <asm/cpufeature.h>
@@ -2509,6 +2510,7 @@ int open_ctree(struct super_block *sb,
	/* readahead state */
	INIT_RADIX_TREE(&fs_info->reada_tree, GFP_NOFS & ~__GFP_DIRECT_RECLAIM);
	spin_lock_init(&fs_info->reada_lock);
	btrfs_init_ref_verify(fs_info);

	fs_info->thread_pool_size = min_t(unsigned long,
					  num_online_cpus() + 2, 8);
@@ -2920,6 +2922,9 @@ int open_ctree(struct super_block *sb,
	if (ret)
		goto fail_trans_kthread;

	if (btrfs_build_ref_tree(fs_info))
		btrfs_err(fs_info, "couldn't build ref tree");

	/* do not make disk changes in broken FS or nologreplay is given */
	if (btrfs_super_log_root(disk_super) != 0 &&
	    !btrfs_test_opt(fs_info, NOLOGREPLAY)) {
@@ -3785,6 +3790,7 @@ void close_ctree(struct btrfs_fs_info *fs_info)
	cleanup_srcu_struct(&fs_info->subvol_srcu);

	btrfs_free_stripe_hash_table(fs_info);
	btrfs_free_ref_cache(fs_info);

	__btrfs_free_block_rsv(root->orphan_block_rsv);
	root->orphan_block_rsv = NULL;
+22 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
#include "math.h"
#include "sysfs.h"
#include "qgroup.h"
#include "ref-verify.h"

#undef SCRAMBLE_DELAYED_REFS

@@ -2188,6 +2189,9 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
	BUG_ON(owner < BTRFS_FIRST_FREE_OBJECTID &&
	       root_objectid == BTRFS_TREE_LOG_OBJECTID);

	btrfs_ref_tree_mod(root, bytenr, num_bytes, parent, root_objectid,
			   owner, offset, BTRFS_ADD_DELAYED_REF);

	if (owner < BTRFS_FIRST_FREE_OBJECTID) {
		ret = btrfs_add_delayed_tree_ref(fs_info, trans, bytenr,
						 num_bytes, parent,
@@ -7280,6 +7284,10 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
	if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
		int old_ref_mod, new_ref_mod;

		btrfs_ref_tree_mod(root, buf->start, buf->len, parent,
				   root->root_key.objectid,
				   btrfs_header_level(buf), 0,
				   BTRFS_DROP_DELAYED_REF);
		ret = btrfs_add_delayed_tree_ref(fs_info, trans, buf->start,
						 buf->len, parent,
						 root->root_key.objectid,
@@ -7343,6 +7351,11 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans,
	if (btrfs_is_testing(fs_info))
		return 0;

	if (root_objectid != BTRFS_TREE_LOG_OBJECTID)
		btrfs_ref_tree_mod(root, bytenr, num_bytes, parent,
				   root_objectid, owner, offset,
				   BTRFS_DROP_DELAYED_REF);

	/*
	 * tree log blocks never actually go into the extent allocation
	 * tree, just update pinning info and exit early.
@@ -8318,6 +8331,10 @@ int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans,

	BUG_ON(root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID);

	btrfs_ref_tree_mod(root, ins->objectid, ins->offset, 0,
			   root->root_key.objectid, owner, offset,
			   BTRFS_ADD_DELAYED_EXTENT);

	ret = btrfs_add_delayed_data_ref(fs_info, trans, ins->objectid,
					 ins->offset, 0,
					 root->root_key.objectid, owner,
@@ -8542,6 +8559,9 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
		extent_op->is_data = false;
		extent_op->level = level;

		btrfs_ref_tree_mod(root, ins.objectid, ins.offset, parent,
				   root_objectid, level, 0,
				   BTRFS_ADD_DELAYED_EXTENT);
		ret = btrfs_add_delayed_tree_ref(fs_info, trans, ins.objectid,
						 ins.offset, parent,
						 root_objectid, level,
@@ -10391,6 +10411,8 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
	 * remove it.
	 */
	free_excluded_extents(fs_info, block_group);
	btrfs_free_ref_tree_range(fs_info, block_group->key.objectid,
				  block_group->key.offset);

	memcpy(&key, &block_group->key, sizeof(key));
	index = get_block_group_index(block_group);
Loading