From: Qu Wenruo <wqu@suse.com>
To: linux-btrfs@vger.kernel.org
Cc: "S ." <sb56637@gmail.com>
Subject: [PATCH] btrfs-progs: rescue: introduce clear-uuid-tree
Date: Thu, 11 Nov 2021 10:41:38 +0800 [thread overview]
Message-ID: <20211111024138.41687-1-wqu@suse.com> (raw)
[BUG]
There is a bug report that a corrupted key type (expected
UUID_KEY_SUBVOL, has EXTENT_ITEM) causing newer kernel to reject a
mount.
Although the root cause is not determined yet, with roll out of v5.11
kernel to various distros, such problem should be prevented by
tree-checker, no matter if it's hardware problem or not.
And older kernel with "-o uuid_rescan" mount option won't help, as
uuid_rescan will only delete items with
UUID_KEY_SUBVOL/UUID_KEY_RECEIVED_SUBVOL key types, not deleting such
corrupted key.
[FIX]
To fix such problem we have to rely on offline tool, thus there we
introduce a new rescue tool, clear-uuid-tree, to empty and then remove
uuid tree.
Kernel will re-generate the correct uuid tree at next mount.
Reported-by: S. <sb56637@gmail.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
cmds/rescue.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 104 insertions(+)
diff --git a/cmds/rescue.c b/cmds/rescue.c
index a98b255ad328..8b5b619da4f6 100644
--- a/cmds/rescue.c
+++ b/cmds/rescue.c
@@ -296,6 +296,109 @@ static int cmd_rescue_create_control_device(const struct cmd_struct *cmd,
}
static DEFINE_SIMPLE_COMMAND(rescue_create_control_device, "create-control-device");
+static int clear_uuid_tree(struct btrfs_fs_info *fs_info)
+{
+ struct btrfs_root *uuid_root = fs_info->uuid_root;
+ struct btrfs_trans_handle *trans;
+ struct btrfs_path path = {};
+ struct btrfs_key key = {};
+ int ret;
+
+ if (!uuid_root)
+ return 0;
+
+ fs_info->uuid_root = NULL;
+ trans = btrfs_start_transaction(fs_info->tree_root, 0);
+ if (IS_ERR(trans))
+ return PTR_ERR(trans);
+
+ while (1) {
+ int nr;
+
+ ret = btrfs_search_slot(trans, uuid_root, &key, &path, -1, 1);
+ if (ret < 0)
+ goto out;
+ ASSERT(ret > 0);
+ ASSERT(path.slots[0] == 0);
+
+ nr = btrfs_header_nritems(path.nodes[0]);
+ if (nr == 0) {
+ btrfs_release_path(&path);
+ break;
+ }
+
+ ret = btrfs_del_items(trans, uuid_root, &path, 0, nr);
+ btrfs_release_path(&path);
+ if (ret < 0)
+ goto out;
+ }
+ ret = btrfs_del_root(trans, fs_info->tree_root, &uuid_root->root_key);
+ if (ret < 0)
+ goto out;
+ list_del(&uuid_root->dirty_list);
+ ret = clean_tree_block(uuid_root->node);
+ if (ret < 0)
+ goto out;
+ ret = btrfs_free_tree_block(trans, uuid_root, uuid_root->node, 0, 1);
+ if (ret < 0)
+ goto out;
+ free_extent_buffer(uuid_root->node);
+ free_extent_buffer(uuid_root->commit_root);
+ kfree(uuid_root);
+out:
+ if (ret < 0)
+ btrfs_abort_transaction(trans, ret);
+ else
+ ret = btrfs_commit_transaction(trans, fs_info->tree_root);
+ return ret;
+}
+
+static const char * const cmd_rescue_clear_uuid_tree_usage[] = {
+ "btrfs rescue clear-uuid-tree",
+ "Delete uuid tree so that kernel can rebuild it at mount time",
+ NULL,
+};
+
+static int cmd_rescue_clear_uuid_tree(const struct cmd_struct *cmd,
+ int argc, char **argv)
+{
+ struct btrfs_fs_info *fs_info;
+ struct open_ctree_flags ocf = {};
+ char *devname;
+ int ret;
+
+ clean_args_no_options(cmd, argc, argv);
+ if (check_argc_exact(argc, 2))
+ return -EINVAL;
+
+ devname = argv[optind];
+ ret = check_mounted(devname);
+ if (ret < 0) {
+ errno = -ret;
+ error("could not check mount status: %m");
+ goto out;
+ } else if (ret) {
+ error("%s is currently mounted", devname);
+ ret = -EBUSY;
+ goto out;
+ }
+ ocf.filename = devname;
+ ocf.flags = OPEN_CTREE_WRITES | OPEN_CTREE_PARTIAL;
+ fs_info = open_ctree_fs_info(&ocf);
+ if (!fs_info) {
+ error("could not open btrfs");
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = clear_uuid_tree(fs_info);
+ close_ctree(fs_info->tree_root);
+out:
+ return !!ret;
+}
+
+static DEFINE_SIMPLE_COMMAND(rescue_clear_uuid_tree, "clear-uuid-tree");
+
static const char rescue_cmd_group_info[] =
"toolbox for specific rescue operations";
@@ -306,6 +409,7 @@ static const struct cmd_group rescue_cmd_group = {
&cmd_struct_rescue_zero_log,
&cmd_struct_rescue_fix_device_size,
&cmd_struct_rescue_create_control_device,
+ &cmd_struct_rescue_clear_uuid_tree,
NULL
}
};
--
2.33.1
next reply other threads:[~2021-11-11 2:42 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-11-11 2:41 Qu Wenruo [this message]
2021-11-11 2:55 ` [PATCH] btrfs-progs: rescue: introduce clear-uuid-tree Qu Wenruo
2021-11-11 6:37 ` Nikolay Borisov
2021-11-11 6:53 ` Qu Wenruo
2021-11-15 16:33 ` 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=20211111024138.41687-1-wqu@suse.com \
--to=wqu@suse.com \
--cc=linux-btrfs@vger.kernel.org \
--cc=sb56637@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox