From patchwork Mon Feb 28 16:29:28 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Filipe Manana X-Patchwork-Id: 12763542 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 C2817C433F5 for ; Mon, 28 Feb 2022 16:29:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237910AbiB1QaR (ORCPT ); Mon, 28 Feb 2022 11:30:17 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51746 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229809AbiB1QaQ (ORCPT ); Mon, 28 Feb 2022 11:30:16 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E1359517F5 for ; Mon, 28 Feb 2022 08:29:36 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 90669B80FEA for ; Mon, 28 Feb 2022 16:29:35 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id B6A78C340F0 for ; Mon, 28 Feb 2022 16:29:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1646065774; bh=NWPA5wPrzJI938aO+LuHb8tPBLqBzNL60w/FsSE2tUE=; h=From:To:Subject:Date:In-Reply-To:References:From; b=cfUe7X8K5AxHiV6aBCPT1MkYdz4jorPGbBcWDKgJqGd7EZQyHPbI1Y+ePXieUne++ gXW/TQtV2wi0AOwTOBpQVVYIdqwNrfYLmPobrFDbhRX/nQ8uOchNQI5XiXXSrzqDAS dh/stQkB6M1+JjLdocO3t4ZoIQr5TZsvlqSA55newcLyARv1bOm8QozmDUabbfpthI 9S8gvpZzo8P4lqOg+KE31kRS2Y/Jx0kErJl3+ZPMJjpptk4TATyIByHTajJkA37ugz echO1zT3NgsI/3JPNZp9kc0qDjt3nKbYuV0AMEE64ULNFjg4XYhSytz7GJTktcB7pd zaejICZKuwfVg== From: fdmanana@kernel.org To: linux-btrfs@vger.kernel.org Subject: [PATCH 1/2] btrfs: add missing run of delayed items after unlink during log replay Date: Mon, 28 Feb 2022 16:29:28 +0000 Message-Id: <168fc1cc179d960ed47173cf47e8274e37611f96.1646064823.git.fdmanana@suse.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Filipe Manana During log replay, whenever we need to check if a name (dentry) exists in a directory we do searches on the subvolume tree for inode references or or directory entries (BTRFS_DIR_INDEX_KEY keys, and BTRFS_DIR_ITEM_KEY keys as well, before kernel 5.17). However when during log replay we unlink a name, through btrfs_unlink_inode(), we may not delete inode references and dir index keys from a subvolume tree and instead just add the deletions to the delayed inode's delayed items, which will only be run when we commit the transaction used for log replay. This means that after an unlink operation during log replay, if we attempt to search for the same name during log replay, we will not see that the name was already deleted, since the deletion is recorded only on the delayed items. We run delayed items after every unlink operation during log replay, except at unlink_old_inode_refs() and at add_inode_ref(). This was due to an overlook, as delayed items should be run after evert unlink, for the reasons stated above. So fix those two cases. Fixes: 0d836392cadd5 ("Btrfs: fix mount failure after fsync due to hard link recreation") Fixes: 1f250e929a9c9 ("Btrfs: fix log replay failure after unlink and link combination") CC: stable@vger.kernel.org # 4.19+ Signed-off-by: Filipe Manana --- fs/btrfs/tree-log.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 73ecc4f67a23..ad2da46bca0d 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -1344,6 +1344,15 @@ static int unlink_old_inode_refs(struct btrfs_trans_handle *trans, inode, name, namelen); kfree(name); iput(dir); + /* + * Whenever we need to check if a name exists or not, we + * check the subvolume tree. So after an unlink we must + * run delayed items, so that future checks for a name + * during log replay see that the name does not exists + * anymore. + */ + if (!ret) + ret = btrfs_run_delayed_items(trans); if (ret) goto out; goto again; @@ -1596,6 +1605,15 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, */ if (!ret && inode->i_nlink == 0) inc_nlink(inode); + /* + * Whenever we need to check if a name exists or + * not, we check the subvolume tree. So after an + * unlink we must run delayed items, so that future + * checks for a name during log replay see that the + * name does not exists anymore. + */ + if (!ret) + ret = btrfs_run_delayed_items(trans); } if (ret < 0) goto out; From patchwork Mon Feb 28 16:29:29 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Filipe Manana X-Patchwork-Id: 12763543 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 7CEB9C433FE for ; Mon, 28 Feb 2022 16:29:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237915AbiB1QaR (ORCPT ); Mon, 28 Feb 2022 11:30:17 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51782 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237892AbiB1QaQ (ORCPT ); Mon, 28 Feb 2022 11:30:16 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C225851E74 for ; Mon, 28 Feb 2022 08:29:37 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 82ED9B81235 for ; Mon, 28 Feb 2022 16:29:36 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id A8907C340F1 for ; Mon, 28 Feb 2022 16:29:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1646065775; bh=APvogQT+HIkqncHPc/b8+cUb1pqQT43srsModO+wvZw=; h=From:To:Subject:Date:In-Reply-To:References:From; b=T1pZxWmcsJkK7O5n2Wkce0WwFQWbFzKqY8JfB1onv5R9uG8azG3KYs8tQ6fWvha/a MNnAzbmJ8YVdiu4xk+rcugOx7p/MiyNHL848yfpbhWGCNvKcmxXdsrqqYaiuGMSXdW cjwZZLAu2DqJB2OOcqZR93JG6PakC+ICysckBgcICHWvZHeooscSN7gezLFApR0lDo kwDcm2zD6LW0zeqmeYDqvxK5wv/LT8WK3aRhc/xQTE2a5uOU++QvjrEY1okfzyKU+i SW3PxVcb1gSxs8oRZ+5neMrba/5yfL2j6xRNKmyh2TyvcN+/6DNHoeltqby4+WzxHt 9XIM0RsGYNW/Q== From: fdmanana@kernel.org To: linux-btrfs@vger.kernel.org Subject: [PATCH 2/2] btrfs: add and use helper for unlinking inode during log replay Date: Mon, 28 Feb 2022 16:29:29 +0000 Message-Id: <1e47a4aa8af20f71057631874de0e91c9b0c0f45.1646064823.git.fdmanana@suse.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Filipe Manana During log replay there is this pattern of running delayed items after every inode unlink. To avoid repeating this several times, move the logic into an helper function and use it instead of calling btrfs_unlink_inode() followed by btrfs_run_delayed_items(). Signed-off-by: Filipe Manana --- fs/btrfs/tree-log.c | 78 +++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 48 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index ad2da46bca0d..6081bc98c4a7 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -899,6 +899,26 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, return ret; } +static int unlink_inode_for_log_replay(struct btrfs_trans_handle *trans, + struct btrfs_inode *dir, + struct btrfs_inode *inode, + const char *name, + int name_len) +{ + int ret; + + ret = btrfs_unlink_inode(trans, dir, inode, name, name_len); + if (ret) + return ret; + /* + * Whenever we need to check if a name exists or not, we check the + * fs/subvolume tree. So after an unlink we must run delayed items, so + * that future checks for a name during log replay see that the name + * does not exists anymore. + */ + return btrfs_run_delayed_items(trans); +} + /* * when cleaning up conflicts between the directory names in the * subvolume, directory names in the log and directory names in the @@ -941,12 +961,8 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans, if (ret) goto out; - ret = btrfs_unlink_inode(trans, dir, BTRFS_I(inode), name, + ret = unlink_inode_for_log_replay(trans, dir, BTRFS_I(inode), name, name_len); - if (ret) - goto out; - else - ret = btrfs_run_delayed_items(trans); out: kfree(name); iput(inode); @@ -1106,12 +1122,9 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans, inc_nlink(&inode->vfs_inode); btrfs_release_path(path); - ret = btrfs_unlink_inode(trans, dir, inode, + ret = unlink_inode_for_log_replay(trans, dir, inode, victim_name, victim_name_len); kfree(victim_name); - if (ret) - return ret; - ret = btrfs_run_delayed_items(trans); if (ret) return ret; *search_done = 1; @@ -1178,14 +1191,11 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans, inc_nlink(&inode->vfs_inode); btrfs_release_path(path); - ret = btrfs_unlink_inode(trans, + ret = unlink_inode_for_log_replay(trans, BTRFS_I(victim_parent), inode, victim_name, victim_name_len); - if (!ret) - ret = btrfs_run_delayed_items( - trans); } iput(victim_parent); kfree(victim_name); @@ -1340,19 +1350,10 @@ static int unlink_old_inode_refs(struct btrfs_trans_handle *trans, kfree(name); goto out; } - ret = btrfs_unlink_inode(trans, BTRFS_I(dir), + ret = unlink_inode_for_log_replay(trans, BTRFS_I(dir), inode, name, namelen); kfree(name); iput(dir); - /* - * Whenever we need to check if a name exists or not, we - * check the subvolume tree. So after an unlink we must - * run delayed items, so that future checks for a name - * during log replay see that the name does not exists - * anymore. - */ - if (!ret) - ret = btrfs_run_delayed_items(trans); if (ret) goto out; goto again; @@ -1448,8 +1449,9 @@ static int add_link(struct btrfs_trans_handle *trans, ret = -ENOENT; goto out; } - ret = btrfs_unlink_inode(trans, BTRFS_I(dir), BTRFS_I(other_inode), - name, namelen); + ret = unlink_inode_for_log_replay(trans, BTRFS_I(dir), + BTRFS_I(other_inode), + name, namelen); if (ret) goto out; /* @@ -1458,10 +1460,6 @@ static int add_link(struct btrfs_trans_handle *trans, */ if (other_inode->i_nlink == 0) inc_nlink(other_inode); - - ret = btrfs_run_delayed_items(trans); - if (ret) - goto out; add_link: ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode), name, namelen, 0, ref_index); @@ -1594,7 +1592,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, ret = btrfs_inode_ref_exists(inode, dir, key->type, name, namelen); if (ret > 0) { - ret = btrfs_unlink_inode(trans, + ret = unlink_inode_for_log_replay(trans, BTRFS_I(dir), BTRFS_I(inode), name, namelen); @@ -1605,15 +1603,6 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, */ if (!ret && inode->i_nlink == 0) inc_nlink(inode); - /* - * Whenever we need to check if a name exists or - * not, we check the subvolume tree. So after an - * unlink we must run delayed items, so that future - * checks for a name during log replay see that the - * name does not exists anymore. - */ - if (!ret) - ret = btrfs_run_delayed_items(trans); } if (ret < 0) goto out; @@ -2350,15 +2339,8 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans, goto out; inc_nlink(inode); - ret = btrfs_unlink_inode(trans, BTRFS_I(dir), BTRFS_I(inode), name, - name_len); - if (ret) - goto out; - - ret = btrfs_run_delayed_items(trans); - if (ret) - goto out; - + ret = unlink_inode_for_log_replay(trans, BTRFS_I(dir), BTRFS_I(inode), + name, name_len); /* * Unlike dir item keys, dir index keys can only have one name (entry) in * them, as there are no key collisions since each key has a unique offset