All of lore.kernel.org
 help / color / mirror / Atom feed
From: Qu Wenruo <wqu@suse.com>
To: linux-btrfs@vger.kernel.org
Cc: "Luca Béla Palkovics" <luca.bela.palkovics@gmail.com>
Subject: [PATCH 1/2] btrfs-progs: check: add check and repair ability for super num devs mismatch
Date: Mon, 28 Feb 2022 08:50:07 +0800	[thread overview]
Message-ID: <029df99dabfee5b8fc602bf284bb3ea364176418.1646009185.git.wqu@suse.com> (raw)
In-Reply-To: <cover.1646009185.git.wqu@suse.com>

[BUG]
There is a bug report of kernel rejecting fs which has a mismatch in
super num devices and num devices found in chunk tree.

But btrfs-check reports no problem about the fs.

[CAUSE]
We just didn't verify super num devices against the result found in
chunk tree.

[FIX]
Add such check and repair ability for btrfs-check.

The ability is mode independent.

Reported-by: Luca Béla Palkovics <luca.bela.palkovics@gmail.com>
Link: https://lore.kernel.org/linux-btrfs/CA+8xDSpvdm_U0QLBAnrH=zqDq_cWCOH5TiV46CKmp3igr44okQ@mail.gmail.com/
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 check/main.c        |  1 +
 check/mode-common.c | 88 +++++++++++++++++++++++++++++++++++++++++++++
 check/mode-common.h |  2 ++
 3 files changed, 91 insertions(+)

diff --git a/check/main.c b/check/main.c
index 8ccba4478de8..b29f6266b974 100644
--- a/check/main.c
+++ b/check/main.c
@@ -9140,6 +9140,7 @@ static int do_check_chunks_and_extents(void)
 		if (ret > 0)
 			ret = 0;
 	}
+	ret = check_and_repair_super_num_devs(gfs_info);
 	return ret;
 }
 
diff --git a/check/mode-common.c b/check/mode-common.c
index c3d8bb45c6b6..a2c6c7732f4e 100644
--- a/check/mode-common.c
+++ b/check/mode-common.c
@@ -1583,3 +1583,91 @@ int fill_csum_tree(struct btrfs_trans_handle *trans, bool search_fs_tree)
 	}
 	return ret;
 }
+
+static int get_num_devs_in_chunk_tree(struct btrfs_fs_info *fs_info)
+{
+	struct btrfs_root *chunk_root = fs_info->chunk_root;
+	struct btrfs_path path = {0};
+	struct btrfs_key key = {0};
+	int found_devs = 0;
+	int ret;
+
+	ret = btrfs_search_slot(NULL, chunk_root, &key, &path, 0, 0);
+	if (ret < 0)
+		return ret;
+
+	/* We should be the first slot, and chunk tree should not be empty*/
+	ASSERT(path.slots[0] == 0 && btrfs_header_nritems(path.nodes[0]));
+
+	btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
+
+	while (key.objectid == BTRFS_DEV_ITEMS_OBJECTID &&
+	       key.type == BTRFS_DEV_ITEM_KEY) {
+		found_devs++;
+
+		ret = btrfs_next_item(chunk_root, &path);
+		if (ret < 0)
+			break;
+
+		/*
+		 * This should not happen, as we should have CHUNK items after
+		 * dev items, but since we're only to get the num devices,
+		 * no need to bother the problem.
+		 */
+		if (ret > 0) {
+			ret = 0;
+			break;
+		}
+		btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
+	}
+	btrfs_release_path(&path);
+	if (ret < 0)
+		return ret;
+	return found_devs;
+}
+
+int check_and_repair_super_num_devs(struct btrfs_fs_info *fs_info)
+{
+	struct btrfs_trans_handle *trans;
+	int found_devs;
+	int ret;
+
+	ret = get_num_devs_in_chunk_tree(fs_info);
+	if (ret < 0)
+		return ret;
+
+	found_devs = ret;
+
+	if (found_devs == btrfs_super_num_devices(fs_info->super_copy))
+		return 0;
+
+	/* Now the found devs in chunk tree mismatch with super block*/
+	error("super num devices mismatch, have %llu expect %u",
+	      btrfs_super_num_devices(fs_info->super_copy),
+	      found_devs);
+
+	if (!repair)
+		return -EUCLEAN;
+
+	/*
+	 * Repair is pretty simple, just reset the super block value and
+	 * commit a new transaction.
+	 */
+	trans = btrfs_start_transaction(fs_info->tree_root, 0);
+	if (IS_ERR(trans)) {
+		ret = PTR_ERR(trans);
+		errno = -ret;
+		error("failed to start trans: %m");
+		return ret;
+	}
+	btrfs_set_super_num_devices(fs_info->super_copy, found_devs);
+	ret = btrfs_commit_transaction(trans, fs_info->tree_root);
+	if (ret < 0) {
+		errno = -ret;
+		error("failed to commit trans: %m");
+		btrfs_abort_transaction(trans, ret);
+		return ret;
+	}
+	printf("Successfully reset super num devices to %u\n", found_devs);
+	return 0;
+}
diff --git a/check/mode-common.h b/check/mode-common.h
index b5e6b727fe73..d5bab85a4f5e 100644
--- a/check/mode-common.h
+++ b/check/mode-common.h
@@ -201,4 +201,6 @@ int repair_dev_item_bytes_used(struct btrfs_fs_info *fs_info,
 
 int fill_csum_tree(struct btrfs_trans_handle *trans, bool search_fs_tree);
 
+int check_and_repair_super_num_devs(struct btrfs_fs_info *fs_info);
+
 #endif
-- 
2.35.1


  reply	other threads:[~2022-02-28  0:50 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-02-28  0:50 [PATCH 0/2] btrfs-progs: add check and repair ability for super num devices mismatch Qu Wenruo
2022-02-28  0:50 ` Qu Wenruo [this message]
2022-03-23 17:43   ` [PATCH 1/2] btrfs-progs: check: add check and repair ability for super num devs mismatch David Sterba
2022-03-23 23:15     ` Qu Wenruo
2022-03-23 23:38       ` Qu Wenruo
2022-02-28  0:50 ` [PATCH 2/2] btrfs-progs: tests/fsck: add test case " Qu Wenruo
2022-03-23 17:12 ` [PATCH 0/2] btrfs-progs: add check and repair ability for super num devices mismatch David Sterba
2022-03-23 17:17 ` David Sterba
2022-03-23 23:30   ` Qu Wenruo
2022-03-24 15:12     ` David Sterba

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=029df99dabfee5b8fc602bf284bb3ea364176418.1646009185.git.wqu@suse.com \
    --to=wqu@suse.com \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=luca.bela.palkovics@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.