From patchwork Wed May 17 07:35:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qu Wenruo X-Patchwork-Id: 13244319 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0216EC7EE2A for ; Wed, 17 May 2023 07:37:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230017AbjEQHhC (ORCPT ); Wed, 17 May 2023 03:37:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59188 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229887AbjEQHg1 (ORCPT ); Wed, 17 May 2023 03:36:27 -0400 Received: from smtp-out1.suse.de (smtp-out1.suse.de [IPv6:2001:67c:2178:6::1c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 39DAF4C2D for ; Wed, 17 May 2023 00:36:11 -0700 (PDT) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id ECE9E228CC for ; Wed, 17 May 2023 07:36:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1684308969; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=5NITmkOFquxmjy/UFc1LE/m3Hlpv+Mnkk6ileNvcmuU=; b=YIB5XbBKSaTEHwAich1IM+58TcwBixgGt9S9dI3s3O+MPUJROPB4K0drKJ9pEaO6Ko6awQ ziVmnf/pCrD/2o/qY9imshQ9+dzbgOTswhQlpgMRd2NWaEMD3g8SoyC5ZUKofu7mnOpWXm gygbYOaIPJCjMNiiaRRNsuRIARu5SD8= Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 35CF213358 for ; Wed, 17 May 2023 07:36:08 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id QAA1OuiDZGQkEQAAMHmgww (envelope-from ) for ; Wed, 17 May 2023 07:36:08 +0000 From: Qu Wenruo To: linux-btrfs@vger.kernel.org Subject: [PATCH 7/7] btrfs-progs: tune: add the ability to change metadata csums Date: Wed, 17 May 2023 15:35:42 +0800 Message-Id: X-Mailer: git-send-email 2.40.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org The csum change for metadata is like uuid-change, we go with in-place csum update without any COW. During the rewrite, we will manually check the csum (both old and new) for each tree block. And only rewrite the csum if the tree block matches its old csum. (For tree block matches its new csum, we need to do nothing). And when everything is done, just update the superblock to reflect the csum type change. Signed-off-by: Qu Wenruo --- tune/change-csum.c | 143 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 142 insertions(+), 1 deletion(-) diff --git a/tune/change-csum.c b/tune/change-csum.c index 167760536336..c8809300a143 100644 --- a/tune/change-csum.c +++ b/tune/change-csum.c @@ -471,8 +471,144 @@ out: return ret; } +static int rewrite_tree_block_csum(struct btrfs_fs_info *fs_info, u64 logical, + u16 new_csum_type) +{ + struct extent_buffer *eb; + u8 result_old[BTRFS_CSUM_SIZE]; + u8 result_new[BTRFS_CSUM_SIZE]; + int ret; + + eb = alloc_dummy_extent_buffer(fs_info, logical, fs_info->nodesize); + if (!eb) + return -ENOMEM; + + ret = btrfs_read_extent_buffer(eb, 0, 0, NULL); + if (ret < 0) { + errno = -ret; + error("failed to read tree block at logical %llu: %m", logical); + goto out; + } + + /* Verify the csum first. */ + btrfs_csum_data(fs_info, fs_info->csum_type, (u8 *)eb->data + BTRFS_CSUM_SIZE, + result_old, fs_info->nodesize - BTRFS_CSUM_SIZE); + btrfs_csum_data(fs_info, new_csum_type, (u8 *)eb->data + BTRFS_CSUM_SIZE, + result_new, fs_info->nodesize - BTRFS_CSUM_SIZE); + + /* Matches old csum, rewrite. */ + if (memcmp_extent_buffer(eb, result_old, 0, fs_info->csum_size) == 0) { + write_extent_buffer(eb, result_new, 0, + btrfs_csum_type_size(new_csum_type)); + ret = write_data_to_disk(fs_info, eb->data, eb->start, + fs_info->nodesize); + if (ret < 0) { + errno = -ret; + error("failed to write tree block at logical %llu: %m", + logical); + } + goto out; + } + + /* Already new csum. */ + if (memcmp_extent_buffer(eb, result_new, 0, fs_info->csum_size) == 0) + goto out; + + /* Csum doesn't match either old or new csum type, bad tree block. */ + ret = -EIO; + error("tree block csum mismatch at logical %llu", logical); +out: + free_extent_buffer(eb); + return ret; +} + +static int change_meta_csums(struct btrfs_fs_info *fs_info, u32 new_csum_type) +{ + struct btrfs_root *extent_root = btrfs_extent_root(fs_info, 0); + struct btrfs_path path = { 0 }; + struct btrfs_key key; + int ret; + + /* + * Disable metadata csum checks first, as we may hit tree blocks with + * either old or new csums. + * We will manually check the meta csums here. + */ + fs_info->skip_csum_check = true; + + key.objectid = 0; + key.type = 0; + key.offset = 0; + + ret = btrfs_search_slot(NULL, extent_root, &key, &path, 0, 0); + if (ret < 0) { + errno = -ret; + error("failed to get the first tree block of extent tree: %m"); + return ret; + } + assert(ret > 0); + while (true) { + btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]); + if (key.type != BTRFS_EXTENT_ITEM_KEY && + key.type != BTRFS_METADATA_ITEM_KEY) + goto next; + + if (key.type == BTRFS_EXTENT_ITEM_KEY) { + struct btrfs_extent_item *ei; + ei = btrfs_item_ptr(path.nodes[0], path.slots[0], + struct btrfs_extent_item); + if (btrfs_extent_flags(path.nodes[0], ei) & + BTRFS_EXTENT_FLAG_DATA) + goto next; + } + ret = rewrite_tree_block_csum(fs_info, key.objectid, new_csum_type); + if (ret < 0) { + errno = -ret; + error("failed to rewrite csum for tree block %llu: %m", + key.offset); + goto out; + } +next: + ret = btrfs_next_extent_item(extent_root, &path, U64_MAX); + if (ret < 0) { + errno = -ret; + error("failed to get next extent item: %m"); + } + if (ret > 0) { + ret = 0; + goto out; + } + } +out: + btrfs_release_path(&path); + + /* + * Finish the change by clearing the csum change flag and update the superblock + * csum type. + */ + if (ret == 0) { + u64 super_flags = btrfs_super_flags(fs_info->super_copy); + + btrfs_set_super_csum_type(fs_info->super_copy, new_csum_type); + super_flags &= ~(BTRFS_SUPER_FLAG_CHANGING_DATA_CSUM | + BTRFS_SUPER_FLAG_CHANGING_META_CSUM); + btrfs_set_super_flags(fs_info->super_copy, super_flags); + + fs_info->csum_type = new_csum_type; + fs_info->csum_size = btrfs_csum_type_size(new_csum_type); + + ret = write_all_supers(fs_info); + if (ret < 0) { + errno = -ret; + error("failed to write super blocks: %m"); + } + } + return ret; +} + int btrfs_change_csum_type(struct btrfs_fs_info *fs_info, u16 new_csum_type) { + u16 old_csum_type = fs_info->csum_type; int ret; /* Phase 0, check conflicting features. */ @@ -511,5 +647,10 @@ int btrfs_change_csum_type(struct btrfs_fs_info *fs_info, u16 new_csum_type) * like relocation in progs. * Thus we have to support reading a tree block with either csum. */ - return -EOPNOTSUPP; + ret = change_meta_csums(fs_info, new_csum_type); + if (ret == 0) + printf("converted csum type from %s (%u) to %s (%u)\n", + btrfs_super_csum_name(old_csum_type), old_csum_type, + btrfs_super_csum_name(new_csum_type), new_csum_type); + return ret; }