diff mbox series

[v3,16/54] btrfs: do proper error handling in record_reloc_root_in_trans

Message ID cf1b90302fa68b6ea40aa86d37153294bd4717f9.1606938211.git.josef@toxicpanda.com (mailing list archive)
State New, archived
Headers show
Series Cleanup error handling in relocation | expand

Commit Message

Josef Bacik Dec. 2, 2020, 7:50 p.m. UTC
Generally speaking this shouldn't ever fail, the corresponding fs root
for the reloc root will already be in memory, so we won't get -ENOMEM
here.

However if there is no corresponding root for the reloc root then we
could get -ENOMEM when we try to allocate it or we could get -ENOENT
when we look it up and see that it doesn't exist.

Convert these BUG_ON()'s into ASSERT()'s + proper error handling for the
case of corruption.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 fs/btrfs/relocation.c | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

Comments

Qu Wenruo Dec. 3, 2020, 2:39 a.m. UTC | #1
On 2020/12/3 上午3:50, Josef Bacik wrote:
> Generally speaking this shouldn't ever fail, the corresponding fs root
> for the reloc root will already be in memory, so we won't get -ENOMEM
> here.
> 
> However if there is no corresponding root for the reloc root then we
> could get -ENOMEM when we try to allocate it or we could get -ENOENT
> when we look it up and see that it doesn't exist.
> 
> Convert these BUG_ON()'s into ASSERT()'s + proper error handling for the
> case of corruption.
> 
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> ---
>  fs/btrfs/relocation.c | 26 ++++++++++++++++++++++++--
>  1 file changed, 24 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
> index d663d8fc085d..5a4b44857522 100644
> --- a/fs/btrfs/relocation.c
> +++ b/fs/btrfs/relocation.c
> @@ -1973,8 +1973,30 @@ static int record_reloc_root_in_trans(struct btrfs_trans_handle *trans,
>  		return 0;
>  
>  	root = btrfs_get_fs_root(fs_info, reloc_root->root_key.offset, false);
> -	BUG_ON(IS_ERR(root));
> -	BUG_ON(root->reloc_root != reloc_root);
> +
> +	/*
> +	 * This should succeed, since we can't have a reloc root without having
> +	 * already looked up the actual root and created the reloc root for this
> +	 * root.
> +	 *
> +	 * However if there's some sort of corruption where we have a ref to a
> +	 * reloc root without a corresponding root this could return -ENOENT.
> +	 *
> +	 * The ASSERT()'s are to catch this case in testing, because it could
> +	 * indicate a bug, but for non-developers it indicates corruption and we
> +	 * should error out.

The same mention of ASSERT() now looks really overkilled.
> +	 */
> +	ASSERT(!IS_ERR(root));
> +	ASSERT(root->reloc_root == reloc_root);
> +	if (IS_ERR(root))
> +		return PTR_ERR(root);
> +	if (root->reloc_root != reloc_root) {

ASSERT(0) would be easier to read here IMHO.

Despite that looks good to me.

Thanks,
Qu
> +		btrfs_err(fs_info,
> +			  "root %llu has two reloc roots associated with it",
> +			  reloc_root->root_key.offset);
> +		btrfs_put_root(root);
> +		return -EUCLEAN;
> +	}
>  	ret = btrfs_record_root_in_trans(trans, root);
>  	btrfs_put_root(root);
>  
>
diff mbox series

Patch

diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index d663d8fc085d..5a4b44857522 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -1973,8 +1973,30 @@  static int record_reloc_root_in_trans(struct btrfs_trans_handle *trans,
 		return 0;
 
 	root = btrfs_get_fs_root(fs_info, reloc_root->root_key.offset, false);
-	BUG_ON(IS_ERR(root));
-	BUG_ON(root->reloc_root != reloc_root);
+
+	/*
+	 * This should succeed, since we can't have a reloc root without having
+	 * already looked up the actual root and created the reloc root for this
+	 * root.
+	 *
+	 * However if there's some sort of corruption where we have a ref to a
+	 * reloc root without a corresponding root this could return -ENOENT.
+	 *
+	 * The ASSERT()'s are to catch this case in testing, because it could
+	 * indicate a bug, but for non-developers it indicates corruption and we
+	 * should error out.
+	 */
+	ASSERT(!IS_ERR(root));
+	ASSERT(root->reloc_root == reloc_root);
+	if (IS_ERR(root))
+		return PTR_ERR(root);
+	if (root->reloc_root != reloc_root) {
+		btrfs_err(fs_info,
+			  "root %llu has two reloc roots associated with it",
+			  reloc_root->root_key.offset);
+		btrfs_put_root(root);
+		return -EUCLEAN;
+	}
 	ret = btrfs_record_root_in_trans(trans, root);
 	btrfs_put_root(root);