aboutsummaryrefslogtreecommitdiffstats
path: root/tune
diff options
context:
space:
mode:
authorQu Wenruo <wqu@suse.com>2023-05-18 10:10:44 +0800
committerDavid Sterba <dsterba@suse.com>2023-05-26 18:02:32 +0200
commit87016bffbbe80fea6c2b9b1f535e196436531d14 (patch)
treea083f04f76cdaa718ad53dcbc2982497ef068807 /tune
parent4cf02fbc84a2d4750209ebba17899ce00dfc1c0e (diff)
downloadbtrfs-progs-87016bffbbe80fea6c2b9b1f535e196436531d14.tar.gz
btrfs-progs: tune: add the ability to migrate the temporary csum items to regular csum items
At this stage, the csum tree should only contain the temporary csum items (CSUM_CHANGE, EXTENT_CSUM, logical), and no more old csum items. Now we can convert those temporary csum items back to regular csum items by changing their key objectids back to EXTENT_CSUM. Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'tune')
-rw-r--r--tune/change-csum.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/tune/change-csum.c b/tune/change-csum.c
index 61368ddf..16776053 100644
--- a/tune/change-csum.c
+++ b/tune/change-csum.c
@@ -388,6 +388,89 @@ static int delete_old_data_csums(struct btrfs_fs_info *fs_info)
return ret;
}
+static int change_csum_objectids(struct btrfs_fs_info *fs_info)
+{
+ struct btrfs_root *csum_root = btrfs_csum_root(fs_info, 0);
+ struct btrfs_trans_handle *trans;
+ struct btrfs_path path = { 0 };
+ struct btrfs_key last_key;
+ u64 super_flags;
+ int ret = 0;
+
+ last_key.objectid = BTRFS_CSUM_CHANGE_OBJECTID;
+ last_key.type = BTRFS_EXTENT_CSUM_KEY;
+ last_key.offset = (u64)-1;
+
+ trans = btrfs_start_transaction(csum_root, 1);
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ errno = -ret;
+ error("failed to start transaction to change csum objectids: %m");
+ return ret;
+ }
+ while (true) {
+ struct btrfs_key found_key;
+ int nr;
+
+ ret = btrfs_search_slot(trans, csum_root, &last_key, &path, 0, 1);
+ if (ret < 0)
+ goto out;
+ assert(ret > 0);
+
+ nr = btrfs_header_nritems(path.nodes[0]);
+ /* No item left (empty csum tree), exit. */
+ if (!nr)
+ goto out;
+ /* No more temporary csum items, all converted, exit. */
+ if (path.slots[0] == 0)
+ goto out;
+
+ /* All csum items should be new csums. */
+ btrfs_item_key_to_cpu(path.nodes[0], &found_key, 0);
+ assert(found_key.objectid == BTRFS_CSUM_CHANGE_OBJECTID);
+
+ /*
+ * Start changing the objectids, since EXTENT_CSUM (-10) is
+ * larger than CSUM_CHANGE (-13), we always change from the tail.
+ */
+ for (int i = nr - 1; i >= 0; i--) {
+ btrfs_item_key_to_cpu(path.nodes[0], &found_key, i);
+ found_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
+ path.slots[0] = i;
+ ret = btrfs_set_item_key_safe(csum_root, &path, &found_key);
+ if (ret < 0) {
+ errno = -ret;
+ error("failed to set item key for data csum at logical %llu: %m",
+ found_key.offset);
+ goto out;
+ }
+ }
+ btrfs_release_path(&path);
+ }
+out:
+ btrfs_release_path(&path);
+ if (ret < 0) {
+ btrfs_abort_transaction(trans, ret);
+ return ret;
+ }
+
+ /*
+ * All data csum items has been changed to the new type, we can clear
+ * the superblock flag for data csum change, and go to the metadata csum
+ * change phase.
+ */
+ super_flags = btrfs_super_flags(fs_info->super_copy);
+ super_flags &= ~BTRFS_SUPER_FLAG_CHANGING_DATA_CSUM;
+ super_flags |= BTRFS_SUPER_FLAG_CHANGING_META_CSUM;
+ btrfs_set_super_flags(fs_info->super_copy, super_flags);
+ ret = btrfs_commit_transaction(trans, csum_root);
+ if (ret < 0) {
+ errno = -ret;
+ error("failed to commit transaction after changing data csum objectids: %m");
+ }
+ return ret;
+}
+
int btrfs_change_csum_type(struct btrfs_fs_info *fs_info, u16 new_csum_type)
{
int ret;
@@ -417,6 +500,9 @@ int btrfs_change_csum_type(struct btrfs_fs_info *fs_info, u16 new_csum_type)
return ret;
/* Phase 3, change the new csum key objectid */
+ ret = change_csum_objectids(fs_info);
+ if (ret < 0)
+ return ret;
/*
* Phase 4, change the csums for metadata.