From patchwork Tue Sep 26 12:45:13 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Filipe Manana X-Patchwork-Id: 13399220 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 6369AE7E62E for ; Tue, 26 Sep 2023 12:45:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234684AbjIZMpc (ORCPT ); Tue, 26 Sep 2023 08:45:32 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33822 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234679AbjIZMpb (ORCPT ); Tue, 26 Sep 2023 08:45:31 -0400 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 33C07101 for ; Tue, 26 Sep 2023 05:45:25 -0700 (PDT) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 58477C433C8 for ; Tue, 26 Sep 2023 12:45:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1695732324; bh=/GrZMCYL+RDHnAmPIiItaFAXkaBvT5Cc25MvsXQ861A=; h=From:To:Subject:Date:In-Reply-To:References:From; b=TAFOkE1ZTIWC2ZNeVcKO3B0r1p9HajiMoRX1UrPt5nXQ8LtoXKlrgTiy07KTAUawk qEnwBxWGg0lHiYBm4TKrlMW6xmC2kOVACw/rMOMjVVT7R24Ntu5kCNuKeQyMgLDeWX PTZnWWtFgdesEMDuceQfi8qsCBsEavUZAq1TZlRBNSf5Ivs5QmtZQPLGDcu+Krptn2 LTSWxQasQdxDHlo5xoPx7r1yKaZTEq3y2vE4t8FLgY1F6GBJH5v4v3FWi3802pyaq1 HRfu+kg8IbxWUHSW9VzJfwPggjBII7ljnUfFU1fr6nFM2K6nE2AMQ8z4MNoZTGSJVB jNd/dlBznLPxA== From: fdmanana@kernel.org To: linux-btrfs@vger.kernel.org Subject: [PATCH 1/8] btrfs: error out when COWing block using a stale transaction Date: Tue, 26 Sep 2023 13:45:13 +0100 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Filipe Manana At btrfs_cow_block() we have these checks to verify we are not using a stale transaction (a past transaction with an unblocked state or higher), and the only thing we do is to trigger a WARN with a message and a stack trace. This however is a critical problem, highly unexpected and if it happens it's most likely due to a bug, so we should error out and turn the fs into error state so that such issue is much more easily noticed if it's triggered. The problem is critical because using such stale transaction will lead to not persisting the extent buffer used for the COW operation, as allocating a tree block adds the range of the respective extent buffer to the ->dirty_pages iotree of the transaction, and a stale transaction, in the unlocked state or higher, will not flush dirty extent buffers anymore, therefore resulting in not persisting the tree block and resource leaks (not cleaning the dirty_pages iotree for example). So do the following changes: 1) Return -EUCLEAN if we find a stale transaction; 2) Turn the fs into error state, with error -EUCLEAN, so that no transaction can be committed, and generate a stack trace; 3) Combine both conditions into a single if statement, as both are related and have the same error message; 4) Mark the check as unlikely, since this is not expected to ever happen. Signed-off-by: Filipe Manana --- fs/btrfs/ctree.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 56d2360e597c..dff2e07ba437 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -686,14 +686,22 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans, btrfs_err(fs_info, "COW'ing blocks on a fs root that's being dropped"); - if (trans->transaction != fs_info->running_transaction) - WARN(1, KERN_CRIT "trans %llu running %llu\n", - trans->transid, - fs_info->running_transaction->transid); - - if (trans->transid != fs_info->generation) - WARN(1, KERN_CRIT "trans %llu running %llu\n", - trans->transid, fs_info->generation); + /* + * COWing must happen through a running transaction, which always + * matches the current fs generation (it's a transaction with a state + * less than TRANS_STATE_UNBLOCKED). If it doesn't, then turn the fs + * into error state to prevent the commit of any transaction. + */ + if (unlikely(trans->transaction != fs_info->running_transaction || + trans->transid != fs_info->generation)) { + btrfs_handle_fs_error(fs_info, -EUCLEAN, +"unexpected transaction when attempting to COW block %llu on root %llu, transaction %llu running transaction %llu fs generation %llu", + buf->start, btrfs_root_id(root), + trans->transid, + fs_info->running_transaction->transid, + fs_info->generation); + return -EUCLEAN; + } if (!should_cow_block(trans, root, buf)) { *cow_ret = buf; From patchwork Tue Sep 26 12:45:14 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Filipe Manana X-Patchwork-Id: 13399221 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 17048E7E62F for ; Tue, 26 Sep 2023 12:45:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234685AbjIZMpe (ORCPT ); Tue, 26 Sep 2023 08:45:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33822 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233754AbjIZMpd (ORCPT ); Tue, 26 Sep 2023 08:45:33 -0400 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2FA91101 for ; Tue, 26 Sep 2023 05:45:26 -0700 (PDT) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4B6EFC433C9 for ; Tue, 26 Sep 2023 12:45:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1695732325; bh=whffOXEe4jKO0DIqq0Up5LUMQ8nSfHosfHoB81Johtw=; h=From:To:Subject:Date:In-Reply-To:References:From; b=aQyajFsk5ZgEJ6Ppr9jX7XAGZjvXGOzQizGLq/nCSX/Ujkj0+1e62RSFBKO8gWf4+ gv4dSBVhvEf+m9zeBZytIcHjxIx6NI1Cmn6txJTi/G0EHWg8z/RKEXW/L4chNCPW4A UracjHA2TC/hCyLz7GBDgDekfR3tmbU+V1WOlom7thGVc/kC6OjuWKTvvQU699q6ua S7GHXdjK+ZoklUhYDYTCyWuhO3S2Vk0EYlg8PxyLttuy5xg8xjcaZPm0eHhStgh5IX tip71dBCCApN+1+iumGa18kiAgPh+0zUFCa/M0Uj9LSD7yJwrcyIzfBrma5u6Klxyi 9Dl/+oZJsXp6Q== From: fdmanana@kernel.org To: linux-btrfs@vger.kernel.org Subject: [PATCH 2/8] btrfs: error when COWing block from a root that is being deleted Date: Tue, 26 Sep 2023 13:45:14 +0100 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Filipe Manana At btrfs_cow_block() we check if the block being COWed belongs to a root that is being deleted and if so we log an error message. However this is an unexpected case and it indicates a bug somewhere, so we should return an error and abort the transaction. So change this in the following ways: 1) Move the check after the checks for a stale transaction, so that if those checks pass, we can abort the transaction; 2) Abort the transaction with -EUCLEAN, so that if the issue ever happens it can easily be noticed; 3) Change the logged message level from error to critical, and change the message itself to print the block's logical address and the ID of the root; 4) Return -EUCLEAN to the caller; 5) As this is an unexpected scenario, that should never happen, mark the check as unlikely, allowing the compiler to potentially generate better code. Signed-off-by: Filipe Manana --- fs/btrfs/ctree.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index dff2e07ba437..4eef1a7d1db6 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -682,10 +682,6 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans, u64 search_start; int ret; - if (test_bit(BTRFS_ROOT_DELETING, &root->state)) - btrfs_err(fs_info, - "COW'ing blocks on a fs root that's being dropped"); - /* * COWing must happen through a running transaction, which always * matches the current fs generation (it's a transaction with a state @@ -703,6 +699,14 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans, return -EUCLEAN; } + if (unlikely(test_bit(BTRFS_ROOT_DELETING, &root->state))) { + btrfs_abort_transaction(trans, -EUCLEAN); + btrfs_crit(fs_info, + "attempt to COW block %llu on root %llu that is being deleted", + buf->start, btrfs_root_id(root)); + return -EUCLEAN; + } + if (!should_cow_block(trans, root, buf)) { *cow_ret = buf; return 0; From patchwork Tue Sep 26 12:45:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Filipe Manana X-Patchwork-Id: 13399222 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 4A32DE7E630 for ; Tue, 26 Sep 2023 12:45:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234692AbjIZMpf (ORCPT ); Tue, 26 Sep 2023 08:45:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33950 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234690AbjIZMpe (ORCPT ); Tue, 26 Sep 2023 08:45:34 -0400 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1C337EB for ; Tue, 26 Sep 2023 05:45:27 -0700 (PDT) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3F6AEC433C8 for ; Tue, 26 Sep 2023 12:45:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1695732326; bh=pF+CXgmXfvaQDaasfUm0D4BdJew5V7IE40NHsaoZ4rU=; h=From:To:Subject:Date:In-Reply-To:References:From; b=r9/vp/lHmUUGhC7TENMW5ak5ggYZbJ+e6O6tYx8KnQdDt+k1kazJVuFkRTP8bnnOy GjObViutm97Doyfdjo++lj8RmCSlcJSHQ3R43R17r+Ttg9wjKNWeTw2MMN+VhZGIcT RdE4KNbAjtC6owjLjOXBGk0gwhqvk5GZKACWv3KpArCU1IxF9k1u8GT8zXhNg8MbD6 WMIpmzZIdUlEDJGY6qkYwXvSDqU78oJgxKySmFxEj7hHZD/VNbZ0yFxN49hNRBW+en aBrNqUFWubYNCzFGUbswp9JJTnKYqEd2Hg+5L3/vPihHp0335u++iRjrrrM+nKhjVd AsmQCZO//7xPg== From: fdmanana@kernel.org To: linux-btrfs@vger.kernel.org Subject: [PATCH 3/8] btrfs: error out when reallocating block for defrag using a stale transaction Date: Tue, 26 Sep 2023 13:45:15 +0100 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Filipe Manana At btrfs_realloc_node() we have these checks to verify we are not using a stale transaction (a past transaction with an unblocked state or higher), and the only thing we do is to trigger two WARN_ON(). This however is a critical problem, highly unexpected and if it happens it's most likely due to a bug, so we should error out and turn the fs into error state so that such issue is much more easily noticed if it's triggered. The problem is critical because in btrfs_realloc_node() we COW tree blocks, and using such stale transaction will lead to not persisting the extent buffers used for the COW operations, as allocating tree block adds the range of the respective extent buffers to the ->dirty_pages iotree of the transaction, and a stale transaction, in the unlocked state or higher, will not flush dirty extent buffers anymore, therefore resulting in not persisting the tree block and resource leaks (not cleaning the dirty_pages iotree for example). So do the following changes: 1) Return -EUCLEAN if we find a stale transaction; 2) Turn the fs into error state, with error -EUCLEAN, so that no transaction can be committed, and generate a stack trace; 3) Combine both conditions into a single if statement, as both are related and have the same error message; 4) Mark the check as unlikely, since this is not expected to ever happen. Signed-off-by: Filipe Manana --- fs/btrfs/ctree.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 4eef1a7d1db6..8619172bcba1 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -817,8 +817,22 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, int progress_passed = 0; struct btrfs_disk_key disk_key; - WARN_ON(trans->transaction != fs_info->running_transaction); - WARN_ON(trans->transid != fs_info->generation); + /* + * COWing must happen through a running transaction, which always + * matches the current fs generation (it's a transaction with a state + * less than TRANS_STATE_UNBLOCKED). If it doesn't, then turn the fs + * into error state to prevent the commit of any transaction. + */ + if (unlikely(trans->transaction != fs_info->running_transaction || + trans->transid != fs_info->generation)) { + btrfs_handle_fs_error(fs_info, -EUCLEAN, +"unexpected transaction when attempting to reallocate parent %llu for root %llu, transaction %llu running transaction %llu fs generation %llu", + parent->start, btrfs_root_id(root), + trans->transid, + fs_info->running_transaction->transid, + fs_info->generation); + return -EUCLEAN; + } parent_nritems = btrfs_header_nritems(parent); blocksize = fs_info->nodesize; From patchwork Tue Sep 26 12:45:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Filipe Manana X-Patchwork-Id: 13399223 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 6057FE7E62E for ; Tue, 26 Sep 2023 12:45:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234696AbjIZMpg (ORCPT ); Tue, 26 Sep 2023 08:45:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33962 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234691AbjIZMpe (ORCPT ); Tue, 26 Sep 2023 08:45:34 -0400 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D1622C9 for ; Tue, 26 Sep 2023 05:45:27 -0700 (PDT) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3223CC433C7 for ; Tue, 26 Sep 2023 12:45:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1695732327; bh=5hRu3KrrRJv3CpO5Cj3Ym9PfH7hIqgLUDM6h9wszXhQ=; h=From:To:Subject:Date:In-Reply-To:References:From; b=nfrVn8dRhL5NfKxYutQyBVtv6Fbm/OXBZQUFac9opY3oZ8r+7PCrKsGJ717VSzhic bq4hhbh3JRZ6dBG3vJz5r4uZjOVHcw769E6Sx5GzadReWMxuq3ZoXXlGr6vwQsuLK9 lXTUnm4NNLH70qtgWpuZgXbCgg+OwDsIFlfoCdVmhrTCoHeRuX4QTpmgrDxalSpjeA Dz9giGKV+qQ9z1rGkZMuusJsYZiZ34W5u9BQ9IZzZEnW0idqh8PDQw6vhdfJq4ro0Y 2o7vT22TMgeX9IvS1SV1xM7r/7kVPthxpkPJBvHcwnkK+6PV2js381r5fHal37XK8F OCke4ZcRmklHQ== From: fdmanana@kernel.org To: linux-btrfs@vger.kernel.org Subject: [PATCH 4/8] btrfs: remove noinline attribute from btrfs_cow_block() Date: Tue, 26 Sep 2023 13:45:16 +0100 Message-Id: <8ee8102f8cb59c53efbc93ae7bfd129a28c76b19.1695731843.git.fdmanana@suse.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Filipe Manana It's pointless to have the noiline attribute for btrfs_cow_block(), as the function is exported and widely used. So remove it. Signed-off-by: Filipe Manana --- fs/btrfs/ctree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 8619172bcba1..602da318ba11 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -672,7 +672,7 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans, * This version of it has extra checks so that a block isn't COWed more than * once per transaction, as long as it hasn't been written yet */ -noinline int btrfs_cow_block(struct btrfs_trans_handle *trans, +int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf, struct extent_buffer *parent, int parent_slot, struct extent_buffer **cow_ret, From patchwork Tue Sep 26 12:45:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Filipe Manana X-Patchwork-Id: 13399224 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 023A2E7E62F for ; Tue, 26 Sep 2023 12:45:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233754AbjIZMph (ORCPT ); Tue, 26 Sep 2023 08:45:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33910 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234694AbjIZMpf (ORCPT ); Tue, 26 Sep 2023 08:45:35 -0400 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0BBA310A for ; Tue, 26 Sep 2023 05:45:28 -0700 (PDT) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 25874C433CA for ; Tue, 26 Sep 2023 12:45:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1695732328; bh=E1HcVfdQdZW2Bmxub4BO1QP38sBF6ilOjbghlsV3yLE=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Fr+eUa82jaD3ETxawMg2S9wWZ1vq6LZ0J4pOxtw8WDbYQyscJ6KaxArg4lUs8PVj7 zW33vXByfz7EJbew5HS6lbc7SUay/HsXd6IPqMBMQDK/+wX04qFcH47/MNgagRj7UP EYCl7qY1NUCtkv+KvC65mW89I9CVzYfpdo6Knr6x3D85I2duvPk+gFhNeHoG4G+jY2 6F9HfvX+3YXHlvMG8aakAdw0/RpAJq+0kmJZF92q7SiG9rcKGHAxnynzHjJvM6Jytp kzJ2yj3p/QhU0BZqrJRLKOZzThGCjve8ZA9Tjv7gxQaNv0C7GyZEhTt3K0JbFCbjRJ Gv8f9vs2Q1GPQ== From: fdmanana@kernel.org To: linux-btrfs@vger.kernel.org Subject: [PATCH 5/8] btrfs: use round_down() to align block offset at btrfs_cow_block() Date: Tue, 26 Sep 2023 13:45:17 +0100 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Filipe Manana At btrfs_cow_block() we can use round_down() to align the extent buffer's logical offset to the start offset of a metadata block group, instead of the less easy to read set of bitwise operations (two plus one subtraction). So replace the bitwise operations with a round_down() call. Signed-off-by: Filipe Manana --- fs/btrfs/ctree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 602da318ba11..9849477c5e19 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -712,7 +712,7 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans, return 0; } - search_start = buf->start & ~((u64)SZ_1G - 1); + search_start = round_down(buf->start, SZ_1G); /* * Before CoWing this block for later modification, check if it's From patchwork Tue Sep 26 12:45:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Filipe Manana X-Patchwork-Id: 13399225 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 053BAE7E630 for ; Tue, 26 Sep 2023 12:45:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234695AbjIZMpi (ORCPT ); Tue, 26 Sep 2023 08:45:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34010 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234697AbjIZMpg (ORCPT ); Tue, 26 Sep 2023 08:45:36 -0400 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E70F111D for ; Tue, 26 Sep 2023 05:45:29 -0700 (PDT) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 17507C433C9 for ; Tue, 26 Sep 2023 12:45:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1695732329; bh=FfhIAnx3tsr3Ht7kssvG76rgsTTJ7qDn9yiCAe3PKAU=; h=From:To:Subject:Date:In-Reply-To:References:From; b=FVuATkicRZegHha+ewKq3kjNGj546xS5ouHNGA4Z+bgqbZAGu8tG+Yaf/WQ6yPr9K ulhrsUKVTX/OHannuYIFpyaemk09qAthVqwg+Lcboha25mT7k9LZw5vOBqIiYXUf82 N3Y9yGV82tPGuCpcnbOmynNkUqs/CqvHjFeL280NAizSEe3Aebht1cO8kojA7U3Stn cNmN8bzLDR/jVXOUiBkoteHEyd7k72KIJY448w/l2zCNUWM93ZnAf33tSHUYHiPpO6 kwmkQGjivKkFMLFwDjk/GAQjiegB75VEvaRATpNIVI0QoTA80a4XkzRklP1i+FZUzo emurFILNOu74Q== From: fdmanana@kernel.org To: linux-btrfs@vger.kernel.org Subject: [PATCH 6/8] btrfs: rename and export __btrfs_cow_block() Date: Tue, 26 Sep 2023 13:45:18 +0100 Message-Id: <88a692d84cc6a0a58dcb278a272efe5c72f7e821.1695731844.git.fdmanana@suse.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Filipe Manana Rename and export __btrfs_cow_block() as btrfs_force_cow_block(). This is to allow to move defrag specific code out of ctree.c and into defrag.c in one of the next patches. Signed-off-by: Filipe Manana --- fs/btrfs/ctree.c | 30 +++++++++++++++--------------- fs/btrfs/ctree.h | 7 +++++++ 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 9849477c5e19..fddf700cc1a7 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -507,13 +507,13 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, * bytes the allocator should try to find free next to the block it returns. * This is just a hint and may be ignored by the allocator. */ -static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct extent_buffer *buf, - struct extent_buffer *parent, int parent_slot, - struct extent_buffer **cow_ret, - u64 search_start, u64 empty_size, - enum btrfs_lock_nesting nest) +int btrfs_force_cow_block(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct extent_buffer *buf, + struct extent_buffer *parent, int parent_slot, + struct extent_buffer **cow_ret, + u64 search_start, u64 empty_size, + enum btrfs_lock_nesting nest) { struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_disk_key disk_key; @@ -668,7 +668,7 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans, } /* - * cows a single block, see __btrfs_cow_block for the real work. + * COWs a single block, see btrfs_force_cow_block() for the real work. * This version of it has extra checks so that a block isn't COWed more than * once per transaction, as long as it hasn't been written yet */ @@ -721,8 +721,8 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans, * Also We don't care about the error, as it's handled internally. */ btrfs_qgroup_trace_subtree_after_cow(trans, root, buf); - ret = __btrfs_cow_block(trans, root, buf, parent, - parent_slot, cow_ret, search_start, 0, nest); + ret = btrfs_force_cow_block(trans, root, buf, parent, parent_slot, + cow_ret, search_start, 0, nest); trace_btrfs_cow_block(root, buf, *cow_ret); @@ -873,11 +873,11 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, search_start = last_block; btrfs_tree_lock(cur); - err = __btrfs_cow_block(trans, root, cur, parent, i, - &cur, search_start, - min(16 * blocksize, - (end_slot - i) * blocksize), - BTRFS_NESTING_COW); + err = btrfs_force_cow_block(trans, root, cur, parent, i, + &cur, search_start, + min(16 * blocksize, + (end_slot - i) * blocksize), + BTRFS_NESTING_COW); if (err) { btrfs_tree_unlock(cur); free_extent_buffer(cur); diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 0c059f20533d..c685952a544c 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -484,6 +484,13 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans, struct extent_buffer *parent, int parent_slot, struct extent_buffer **cow_ret, enum btrfs_lock_nesting nest); +int btrfs_force_cow_block(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct extent_buffer *buf, + struct extent_buffer *parent, int parent_slot, + struct extent_buffer **cow_ret, + u64 search_start, u64 empty_size, + enum btrfs_lock_nesting nest); int btrfs_copy_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf, From patchwork Tue Sep 26 12:45:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Filipe Manana X-Patchwork-Id: 13399226 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 B5404E7E631 for ; Tue, 26 Sep 2023 12:45:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234690AbjIZMpj (ORCPT ); Tue, 26 Sep 2023 08:45:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34024 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234689AbjIZMph (ORCPT ); Tue, 26 Sep 2023 08:45:37 -0400 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DC182EB for ; Tue, 26 Sep 2023 05:45:30 -0700 (PDT) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0B5B3C433C8 for ; Tue, 26 Sep 2023 12:45:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1695732330; bh=iteBX5AamMjRxAi3oexLMgmW2wqiKIiyIEdIOBJPRqQ=; h=From:To:Subject:Date:In-Reply-To:References:From; b=GukQ4IgxCjV1e6HQSExkUJQfTq36cvO5J5VCkT+DAtYZ1d/icVN/JrTXmGcY5aSU1 9u30XNp0iecnG+1yqL3iESo7PdQYFa3CAJ9ujdz3Nb44kI4D/NVAJYNGFGQf4zNA1W a208JP3jG08zwS278WfGx+ZBM8yGivOa0lHHOOo1/jkeMVV3t5LC2GUNaIRhBnwfsy bcFkcJ3+mDyMehwVZRbwHT2BcO3G8ZHD81E/+xGvlFexTK0NNX+HWkQN+CVoT7wxlk RcY0pmXAqWdHG7AmbaW8yZtqD5FXFF0lccCistbptYypRjWjNNHVvABTVGW5iDkl6B 0sIRgbyhpcm/A== From: fdmanana@kernel.org To: linux-btrfs@vger.kernel.org Subject: [PATCH 7/8] btrfs: export comp_keys() from ctree.c as btrfs_comp_keys() Date: Tue, 26 Sep 2023 13:45:19 +0100 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Filipe Manana Export comp_keys() out of ctree.c, as btrfs_comp_keys(), so that in a later patch we can move out defrag specific code from ctree.c into defrag.c. Signed-off-by: Filipe Manana --- fs/btrfs/ctree.c | 44 +++++++------------------------------------- fs/btrfs/ctree.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index fddf700cc1a7..f584e79c29e9 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -743,36 +743,6 @@ static int close_blocks(u64 blocknr, u64 other, u32 blocksize) return 0; } -#ifdef __LITTLE_ENDIAN - -/* - * Compare two keys, on little-endian the disk order is same as CPU order and - * we can avoid the conversion. - */ -static int comp_keys(const struct btrfs_disk_key *disk_key, - const struct btrfs_key *k2) -{ - const struct btrfs_key *k1 = (const struct btrfs_key *)disk_key; - - return btrfs_comp_cpu_keys(k1, k2); -} - -#else - -/* - * compare two keys in a memcmp fashion - */ -static int comp_keys(const struct btrfs_disk_key *disk, - const struct btrfs_key *k2) -{ - struct btrfs_key k1; - - btrfs_disk_key_to_cpu(&k1, disk); - - return btrfs_comp_cpu_keys(&k1, k2); -} -#endif - /* * same as comp_keys only with two btrfs_key's */ @@ -845,7 +815,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, int close = 1; btrfs_node_key(parent, &disk_key, i); - if (!progress_passed && comp_keys(&disk_key, progress) < 0) + if (!progress_passed && btrfs_comp_keys(&disk_key, progress) < 0) continue; progress_passed = 1; @@ -958,7 +928,7 @@ int btrfs_bin_search(struct extent_buffer *eb, int first_slot, tmp = &unaligned; } - ret = comp_keys(tmp, key); + ret = btrfs_comp_keys(tmp, key); if (ret < 0) low = mid + 1; @@ -1995,7 +1965,7 @@ static int search_leaf(struct btrfs_trans_handle *trans, * the extent buffer's header and we have recently accessed * the header's level field. */ - ret = comp_keys(&first_key, key); + ret = btrfs_comp_keys(&first_key, key); if (ret < 0) { /* * The first key is smaller than the key we want @@ -2504,7 +2474,7 @@ static int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path) */ if (path->slots[0] < btrfs_header_nritems(path->nodes[0])) { btrfs_item_key(path->nodes[0], &found_key, path->slots[0]); - ret = comp_keys(&found_key, &orig_key); + ret = btrfs_comp_keys(&found_key, &orig_key); if (ret == 0) { if (path->slots[0] > 0) { path->slots[0]--; @@ -2519,7 +2489,7 @@ static int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path) } btrfs_item_key(path->nodes[0], &found_key, 0); - ret = comp_keys(&found_key, &key); + ret = btrfs_comp_keys(&found_key, &key); /* * We might have had an item with the previous key in the tree right * before we released our path. And after we released our path, that @@ -2710,7 +2680,7 @@ void btrfs_set_item_key_safe(struct btrfs_trans_handle *trans, slot = path->slots[0]; if (slot > 0) { btrfs_item_key(eb, &disk_key, slot - 1); - if (unlikely(comp_keys(&disk_key, new_key) >= 0)) { + if (unlikely(btrfs_comp_keys(&disk_key, new_key) >= 0)) { btrfs_print_leaf(eb); btrfs_crit(fs_info, "slot %u key (%llu %u %llu) new key (%llu %u %llu)", @@ -2724,7 +2694,7 @@ void btrfs_set_item_key_safe(struct btrfs_trans_handle *trans, } if (slot < btrfs_header_nritems(eb) - 1) { btrfs_item_key(eb, &disk_key, slot + 1); - if (unlikely(comp_keys(&disk_key, new_key) <= 0)) { + if (unlikely(btrfs_comp_keys(&disk_key, new_key) <= 0)) { btrfs_print_leaf(eb); btrfs_crit(fs_info, "slot %u key (%llu %u %llu) new key (%llu %u %llu)", diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index c685952a544c..e6d982c3ea11 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -461,6 +461,36 @@ int btrfs_bin_search(struct extent_buffer *eb, int first_slot, const struct btrfs_key *key, int *slot); int __pure btrfs_comp_cpu_keys(const struct btrfs_key *k1, const struct btrfs_key *k2); + +#ifdef __LITTLE_ENDIAN + +/* + * Compare two keys, on little-endian the disk order is same as CPU order and + * we can avoid the conversion. + */ +static inline int btrfs_comp_keys(const struct btrfs_disk_key *disk_key, + const struct btrfs_key *k2) +{ + const struct btrfs_key *k1 = (const struct btrfs_key *)disk_key; + + return btrfs_comp_cpu_keys(k1, k2); +} + +#else + +/* Compare two keys in a memcmp fashion. */ +static inline int btrfs_comp_keys(const struct btrfs_disk_key *disk, + const struct btrfs_key *k2) +{ + struct btrfs_key k1; + + btrfs_disk_key_to_cpu(&k1, disk); + + return btrfs_comp_cpu_keys(&k1, k2); +} + +#endif + int btrfs_previous_item(struct btrfs_root *root, struct btrfs_path *path, u64 min_objectid, int type); From patchwork Tue Sep 26 12:45:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Filipe Manana X-Patchwork-Id: 13399227 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 6D804E7E62E for ; Tue, 26 Sep 2023 12:45:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234363AbjIZMpk (ORCPT ); Tue, 26 Sep 2023 08:45:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34080 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234691AbjIZMpi (ORCPT ); Tue, 26 Sep 2023 08:45:38 -0400 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CA54A101 for ; Tue, 26 Sep 2023 05:45:31 -0700 (PDT) Received: by smtp.kernel.org (Postfix) with ESMTPSA id F4134C433CA for ; Tue, 26 Sep 2023 12:45:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1695732331; bh=hg6qDh3iNkiYUEYTi2dvs1eRUDVr4++7lKD2sLrT/to=; h=From:To:Subject:Date:In-Reply-To:References:From; b=r0g2R7jR911/1ur15PXNd9nl8kaIXSYV6UcjUHKrTxRv6e7qf5MJ3NB9/JMyYr+DU +a4zUcWeaBcJubkOUjhHWqYO0DB6XMgGiyK3PyaKX87llrwEbOgopAhQdH0dQ59QdZ UsZ55QV661WHmH714Vr4PAfJyF5BtO/DGKfu+6sZd4ThFxwPF3QwetuC1/oRwPCzJ5 YKYUBkbm7j1/Hh+4QweX6MNdbqQjApbgidtlE2ElGilOXjPLQ8+E8hhMlOdyy3dLBy 8WTo3UCFs3FycTiM6G9DnHOV0KgNPRV4Hd8Q+1vrWYMP82bcQEYDedEe6VczAIJ35f KRTV9gqKmk6BA== From: fdmanana@kernel.org To: linux-btrfs@vger.kernel.org Subject: [PATCH 8/8] btrfs: move btrfs_realloc_node() from ctree.c into defrag.h Date: Tue, 26 Sep 2023 13:45:20 +0100 Message-Id: <935d5f7d09c31b38be102d066957ad6bbe0b4b2f.1695731845.git.fdmanana@suse.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Filipe Manana btrfs_realloc_node() is only used by the defrag code. Nowadays we have a defrag.c file, so move it, and its helper close_blocks(), into defrag.c. During the move also do a few minor cosmetic changes: 1) Change the return value of close_blocks() from int to bool; 2) Use SZ_32K instead of 32768 at close_blocks(); 3) Make some variables const in btrfs_realloc_node(), 'blocksize' and 'end_slot'; 4) Get rid of 'parent_nritems' variable, in both places where it was used it could be replaced by calling btrfs_header_nritems(parent); 5) Change the type of a couple variables from int to bool; 6) Rename variable 'err' to 'ret', as that's the most common name we use to track the return value of a function; 7) Move some variables from the top scope to the scope of the for loop where they are used. Signed-off-by: Filipe Manana --- fs/btrfs/ctree.c | 112 ---------------------------------------------- fs/btrfs/ctree.h | 4 -- fs/btrfs/defrag.c | 106 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 116 deletions(-) diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index f584e79c29e9..6cbebe8c416d 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -730,19 +730,6 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans, } ALLOW_ERROR_INJECTION(btrfs_cow_block, ERRNO); -/* - * helper function for defrag to decide if two blocks pointed to by a - * node are actually close by - */ -static int close_blocks(u64 blocknr, u64 other, u32 blocksize) -{ - if (blocknr < other && other - (blocknr + blocksize) < 32768) - return 1; - if (blocknr > other && blocknr - (other + blocksize) < 32768) - return 1; - return 0; -} - /* * same as comp_keys only with two btrfs_key's */ @@ -763,105 +750,6 @@ int __pure btrfs_comp_cpu_keys(const struct btrfs_key *k1, const struct btrfs_ke return 0; } -/* - * this is used by the defrag code to go through all the - * leaves pointed to by a node and reallocate them so that - * disk order is close to key order - */ -int btrfs_realloc_node(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct extent_buffer *parent, - int start_slot, u64 *last_ret, - struct btrfs_key *progress) -{ - struct btrfs_fs_info *fs_info = root->fs_info; - struct extent_buffer *cur; - u64 blocknr; - u64 search_start = *last_ret; - u64 last_block = 0; - u64 other; - u32 parent_nritems; - int end_slot; - int i; - int err = 0; - u32 blocksize; - int progress_passed = 0; - struct btrfs_disk_key disk_key; - - /* - * COWing must happen through a running transaction, which always - * matches the current fs generation (it's a transaction with a state - * less than TRANS_STATE_UNBLOCKED). If it doesn't, then turn the fs - * into error state to prevent the commit of any transaction. - */ - if (unlikely(trans->transaction != fs_info->running_transaction || - trans->transid != fs_info->generation)) { - btrfs_handle_fs_error(fs_info, -EUCLEAN, -"unexpected transaction when attempting to reallocate parent %llu for root %llu, transaction %llu running transaction %llu fs generation %llu", - parent->start, btrfs_root_id(root), - trans->transid, - fs_info->running_transaction->transid, - fs_info->generation); - return -EUCLEAN; - } - - parent_nritems = btrfs_header_nritems(parent); - blocksize = fs_info->nodesize; - end_slot = parent_nritems - 1; - - if (parent_nritems <= 1) - return 0; - - for (i = start_slot; i <= end_slot; i++) { - int close = 1; - - btrfs_node_key(parent, &disk_key, i); - if (!progress_passed && btrfs_comp_keys(&disk_key, progress) < 0) - continue; - - progress_passed = 1; - blocknr = btrfs_node_blockptr(parent, i); - if (last_block == 0) - last_block = blocknr; - - if (i > 0) { - other = btrfs_node_blockptr(parent, i - 1); - close = close_blocks(blocknr, other, blocksize); - } - if (!close && i < end_slot) { - other = btrfs_node_blockptr(parent, i + 1); - close = close_blocks(blocknr, other, blocksize); - } - if (close) { - last_block = blocknr; - continue; - } - - cur = btrfs_read_node_slot(parent, i); - if (IS_ERR(cur)) - return PTR_ERR(cur); - if (search_start == 0) - search_start = last_block; - - btrfs_tree_lock(cur); - err = btrfs_force_cow_block(trans, root, cur, parent, i, - &cur, search_start, - min(16 * blocksize, - (end_slot - i) * blocksize), - BTRFS_NESTING_COW); - if (err) { - btrfs_tree_unlock(cur); - free_extent_buffer(cur); - break; - } - search_start = cur->start; - last_block = cur->start; - *last_ret = search_start; - btrfs_tree_unlock(cur); - free_extent_buffer(cur); - } - return err; -} - /* * Search for a key in the given extent_buffer. * diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index e6d982c3ea11..353ba4821f25 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -553,10 +553,6 @@ int btrfs_search_slot_for_read(struct btrfs_root *root, const struct btrfs_key *key, struct btrfs_path *p, int find_higher, int return_any); -int btrfs_realloc_node(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct extent_buffer *parent, - int start_slot, u64 *last_ret, - struct btrfs_key *progress); void btrfs_release_path(struct btrfs_path *p); struct btrfs_path *btrfs_alloc_path(void); void btrfs_free_path(struct btrfs_path *p); diff --git a/fs/btrfs/defrag.c b/fs/btrfs/defrag.c index 53544787c348..ad084c295378 100644 --- a/fs/btrfs/defrag.c +++ b/fs/btrfs/defrag.c @@ -337,6 +337,112 @@ int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info) return 0; } +/* + * Helper function for defrag to decide if two blocks pointed to by a node are + * actually close by. + */ +static bool close_blocks(u64 blocknr, u64 other, u32 blocksize) +{ + if (blocknr < other && other - (blocknr + blocksize) < SZ_32K) + return true; + if (blocknr > other && blocknr - (other + blocksize) < SZ_32K) + return true; + return false; +} + +/* + * This is used by the defrag code to go through all the leaves pointed to by a + * node and reallocate them so that disk order is close to key order. + */ +static int btrfs_realloc_node(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct extent_buffer *parent, + int start_slot, u64 *last_ret, + struct btrfs_key *progress) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + const u32 blocksize = fs_info->nodesize; + const int end_slot = btrfs_header_nritems(parent) - 1; + u64 search_start = *last_ret; + u64 last_block = 0; + int ret = 0; + bool progress_passed = false; + + /* + * COWing must happen through a running transaction, which always + * matches the current fs generation (it's a transaction with a state + * less than TRANS_STATE_UNBLOCKED). If it doesn't, then turn the fs + * into error state to prevent the commit of any transaction. + */ + if (unlikely(trans->transaction != fs_info->running_transaction || + trans->transid != fs_info->generation)) { + btrfs_handle_fs_error(fs_info, -EUCLEAN, +"unexpected transaction when attempting to reallocate parent %llu for root %llu, transaction %llu running transaction %llu fs generation %llu", + parent->start, btrfs_root_id(root), + trans->transid, + fs_info->running_transaction->transid, + fs_info->generation); + return -EUCLEAN; + } + + if (btrfs_header_nritems(parent) <= 1) + return 0; + + for (int i = start_slot; i <= end_slot; i++) { + struct extent_buffer *cur; + struct btrfs_disk_key disk_key; + u64 blocknr; + u64 other; + bool close = true; + + btrfs_node_key(parent, &disk_key, i); + if (!progress_passed && btrfs_comp_keys(&disk_key, progress) < 0) + continue; + + progress_passed = true; + blocknr = btrfs_node_blockptr(parent, i); + if (last_block == 0) + last_block = blocknr; + + if (i > 0) { + other = btrfs_node_blockptr(parent, i - 1); + close = close_blocks(blocknr, other, blocksize); + } + if (!close && i < end_slot) { + other = btrfs_node_blockptr(parent, i + 1); + close = close_blocks(blocknr, other, blocksize); + } + if (close) { + last_block = blocknr; + continue; + } + + cur = btrfs_read_node_slot(parent, i); + if (IS_ERR(cur)) + return PTR_ERR(cur); + if (search_start == 0) + search_start = last_block; + + btrfs_tree_lock(cur); + ret = btrfs_force_cow_block(trans, root, cur, parent, i, + &cur, search_start, + min(16 * blocksize, + (end_slot - i) * blocksize), + BTRFS_NESTING_COW); + if (ret) { + btrfs_tree_unlock(cur); + free_extent_buffer(cur); + break; + } + search_start = cur->start; + last_block = cur->start; + *last_ret = search_start; + btrfs_tree_unlock(cur); + free_extent_buffer(cur); + } + return ret; +} + /* * Defrag all the leaves in a given btree. * Read all the leaves and try to get key order to