| From 4f6b4cc4602efba1f52655f739f07b3dc8877760 Mon Sep 17 00:00:00 2001 |
| From: Josef Bacik <josef@toxicpanda.com> |
| Date: Fri, 13 Mar 2020 17:17:07 -0400 |
| Subject: [PATCH] btrfs: restart relocate_tree_blocks properly |
| |
| commit 50dbbb71c79df89532ec41d118d59386e5a877e3 upstream. |
| |
| There are two bugs here, but fixing them independently would just result |
| in pain if you happened to bisect between the two patches. |
| |
| First is how we handle the -EAGAIN from relocate_tree_block(). We don't |
| set error, unless we happen to be the first node, which makes no sense, |
| I have no idea what the code was trying to accomplish here. |
| |
| We in fact _do_ want err set here so that we know we need to restart in |
| relocate_block_group(). Also we need finish_pending_nodes() to not |
| actually call link_to_upper(), because we didn't actually relocate the |
| block. |
| |
| And then if we do get -EAGAIN we do not want to set our backref cache |
| last_trans to the one before ours. This would force us to update our |
| backref cache if we didn't cross transaction ids, which would mean we'd |
| have some nodes updated to their new_bytenr, but still able to find |
| their old bytenr because we're searching the same commit root as the |
| last time we went through relocate_tree_blocks. |
| |
| Fixing these two things keeps us from panicing when we start breaking |
| out of relocate_tree_blocks() either for delayed ref flushing or enospc. |
| |
| Signed-off-by: Josef Bacik <josef@toxicpanda.com> |
| Signed-off-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c |
| index 16a9ee6f49b4..a91ae5320f02 100644 |
| --- a/fs/btrfs/relocation.c |
| +++ b/fs/btrfs/relocation.c |
| @@ -3133,9 +3133,8 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans, |
| ret = relocate_tree_block(trans, rc, node, &block->key, |
| path); |
| if (ret < 0) { |
| - if (ret != -EAGAIN || &block->rb_node == rb_first(blocks)) |
| - err = ret; |
| - goto out; |
| + err = ret; |
| + break; |
| } |
| } |
| out: |
| @@ -4111,12 +4110,6 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc) |
| if (!RB_EMPTY_ROOT(&blocks)) { |
| ret = relocate_tree_blocks(trans, rc, &blocks); |
| if (ret < 0) { |
| - /* |
| - * if we fail to relocate tree blocks, force to update |
| - * backref cache when committing transaction. |
| - */ |
| - rc->backref_cache.last_trans = trans->transid - 1; |
| - |
| if (ret != -EAGAIN) { |
| err = ret; |
| break; |
| -- |
| 2.7.4 |
| |