diff mbox series

[v2,6/7] btrfs-progs: tune: add the ability to migrate the temporary csum items to regular csum items

Message ID cddd8882d22cffd8f9ff326252a043ac0c8be743.1684375729.git.wqu@suse.com (mailing list archive)
State New, archived
Headers show
Series btrfs-progs: csum-change: add the initial support for offline csum type change | expand

Commit Message

Qu Wenruo May 18, 2023, 2:10 a.m. UTC
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>
---
 tune/change-csum.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)
diff mbox series

Patch

diff --git a/tune/change-csum.c b/tune/change-csum.c
index 61368ddf34b9..167760536336 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.