* [PATCH 1/2] btrfs: Remove superflous lock acquisition in __del_reloc_root
@ 2020-02-21 13:11 Nikolay Borisov
2020-02-21 13:11 ` [PATCH 2/2] btrfs: Use list_for_each_entry_safe in free_reloc_roots Nikolay Borisov
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Nikolay Borisov @ 2020-02-21 13:11 UTC (permalink / raw)
To: linux-btrfs; +Cc: Nikolay Borisov
__del_reloc_root is called from:
a) Transaction commit via:
btrfs_transaction_commit
commit_fs_roots
btrfs_update_reloc_root
__del_reloc_root
b) From the relocation thread with the following call chains:
relocate_block_group
merge_reloc_roots
insert_dirty_subvol
btrfs_update_reloc_root
__del_reloc_root
c) merge_reloc_roots
free_reloc_roots
__del_reloc_roots
(The above call chain can called from btrfs_recover_relocation as well
but for the purpose of this fix this is irrelevant).
The commont data structure that needs protecting is
fs_info->reloc_ctl->reloc_list as reloc roots are anchored at this list.
Turns out it's no needed to hold the trans_lock in __del_reloc_root
since consistency is already guaranteed by call chain b) above holding
a transaction while calling insert_dirty_subvol, meaning we cannot have
a concurrent transaction commit. For call chain c) above a snapshot of
the fs_info->reloc_ctl->reloc_list is taken with reloc_mutex held and
free_reloc_roots is called on this local snapshot.
Those invariants are sufficient to prevent racing calls to
__del_reloc_root alongside other users of the list, as such it's fine
to drop the lock acquisition.
Signed-off-by: Nikolay Borisov <nborisov@suse.com>
---
fs/btrfs/relocation.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 8076c340749f..e5cb64409f7c 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -1381,9 +1381,7 @@ static void __del_reloc_root(struct btrfs_root *root)
BUG_ON((struct btrfs_root *)node->data != root);
}
- spin_lock(&fs_info->trans_lock);
list_del_init(&root->root_list);
- spin_unlock(&fs_info->trans_lock);
kfree(node);
}
--
2.17.1
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 2/2] btrfs: Use list_for_each_entry_safe in free_reloc_roots 2020-02-21 13:11 [PATCH 1/2] btrfs: Remove superflous lock acquisition in __del_reloc_root Nikolay Borisov @ 2020-02-21 13:11 ` Nikolay Borisov 2020-02-21 13:17 ` [PATCH v2 " Nikolay Borisov ` (2 more replies) 2020-02-21 13:22 ` [PATCH 1/2] btrfs: Remove superflous lock acquisition in __del_reloc_root Qu Wenruo 2020-04-10 16:29 ` David Sterba 2 siblings, 3 replies; 7+ messages in thread From: Nikolay Borisov @ 2020-02-21 13:11 UTC (permalink / raw) To: linux-btrfs; +Cc: Nikolay Borisov The function always works on a local copy of the reloc root list, which cannot be modified outside of it so using list_for_each_entry is fine. Additionally the macro handles empty lists so drop list_empty checks of callers. No semantic changes. Signed-off-by: Nikolay Borisov <nborisov@suse.com> --- fs/btrfs/relocation.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index e5cb64409f7c..f13b79adf6b0 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -2523,13 +2523,10 @@ int prepare_to_merge(struct reloc_control *rc, int err) static noinline_for_stack void free_reloc_roots(struct list_head *list) { - struct btrfs_root *reloc_root; + struct btrfs_root *reloc_root, *tmp; - while (!list_empty(list)) { - reloc_root = list_entry(list->next, struct btrfs_root, - root_list); + list_for_each_entry_safe(reloc_root, tmp, list, root_list) __del_reloc_root(reloc_root); - } } static noinline_for_stack @@ -2588,15 +2585,13 @@ void merge_reloc_roots(struct reloc_control *rc) out: if (ret) { btrfs_handle_fs_error(fs_info, ret, NULL); - if (!list_empty(&reloc_roots)) - free_reloc_roots(&reloc_roots); + free_reloc_roots(&reloc_roots); /* new reloc root may be added */ mutex_lock(&fs_info->reloc_mutex); list_splice_init(&rc->reloc_roots, &reloc_roots); mutex_unlock(&fs_info->reloc_mutex); - if (!list_empty(&reloc_roots)) - free_reloc_roots(&reloc_roots); + free_reloc_roots(&reloc_roots); } BUG_ON(!RB_EMPTY_ROOT(&rc->reloc_root_tree.rb_root)); @@ -4689,8 +4684,7 @@ int btrfs_recover_relocation(struct btrfs_root *root) out_free: kfree(rc); out: - if (!list_empty(&reloc_roots)) - free_reloc_roots(&reloc_roots); + free_reloc_roots(&reloc_roots); btrfs_free_path(path); -- 2.17.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 2/2] btrfs: Use list_for_each_entry_safe in free_reloc_roots 2020-02-21 13:11 ` [PATCH 2/2] btrfs: Use list_for_each_entry_safe in free_reloc_roots Nikolay Borisov @ 2020-02-21 13:17 ` Nikolay Borisov 2020-02-21 13:23 ` [PATCH " Qu Wenruo 2020-04-10 16:33 ` David Sterba 2 siblings, 0 replies; 7+ messages in thread From: Nikolay Borisov @ 2020-02-21 13:17 UTC (permalink / raw) To: linux-btrfs; +Cc: Nikolay Borisov The function always works on a local copy of the reloc root list, which cannot be modified outside of it so using list_for_each_entry is fine. Additionally the macro handles empty lists so drop list_empty checks of callers. No semantic changes. --- V2: Base the patch on current misc-next rather than on a branch with Josef's subvol cleanups part 2. fs/btrfs/relocation.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 4b8c80de925b..a8898894f443 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -2523,11 +2523,9 @@ int prepare_to_merge(struct reloc_control *rc, int err) static noinline_for_stack void free_reloc_roots(struct list_head *list) { - struct btrfs_root *reloc_root; + struct btrfs_root *reloc_root, *tmp; - while (!list_empty(list)) { - reloc_root = list_entry(list->next, struct btrfs_root, - root_list); + list_for_each_entry_safe(reloc_root, tmp, list, root_list) { __del_reloc_root(reloc_root); free_extent_buffer(reloc_root->node); free_extent_buffer(reloc_root->commit_root); @@ -2592,15 +2590,13 @@ void merge_reloc_roots(struct reloc_control *rc) out: if (ret) { btrfs_handle_fs_error(fs_info, ret, NULL); - if (!list_empty(&reloc_roots)) - free_reloc_roots(&reloc_roots); + free_reloc_roots(&reloc_roots); /* new reloc root may be added */ mutex_lock(&fs_info->reloc_mutex); list_splice_init(&rc->reloc_roots, &reloc_roots); mutex_unlock(&fs_info->reloc_mutex); - if (!list_empty(&reloc_roots)) - free_reloc_roots(&reloc_roots); + free_reloc_roots(&reloc_roots); } BUG_ON(!RB_EMPTY_ROOT(&rc->reloc_root_tree.rb_root)); @@ -4693,8 +4689,7 @@ int btrfs_recover_relocation(struct btrfs_root *root) out_free: kfree(rc); out: - if (!list_empty(&reloc_roots)) - free_reloc_roots(&reloc_roots); + free_reloc_roots(&reloc_roots); btrfs_free_path(path); -- 2.17.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] btrfs: Use list_for_each_entry_safe in free_reloc_roots 2020-02-21 13:11 ` [PATCH 2/2] btrfs: Use list_for_each_entry_safe in free_reloc_roots Nikolay Borisov 2020-02-21 13:17 ` [PATCH v2 " Nikolay Borisov @ 2020-02-21 13:23 ` Qu Wenruo 2020-04-10 16:33 ` David Sterba 2 siblings, 0 replies; 7+ messages in thread From: Qu Wenruo @ 2020-02-21 13:23 UTC (permalink / raw) To: Nikolay Borisov, linux-btrfs On 2020/2/21 下午9:11, Nikolay Borisov wrote: > The function always works on a local copy of the reloc root list, which > cannot be modified outside of it so using list_for_each_entry is fine. > Additionally the macro handles empty lists so drop list_empty checks of > callers. No semantic changes. > > Signed-off-by: Nikolay Borisov <nborisov@suse.com> Reviewed-by: Qu Wenruo <wqu@suse.com> Thanks, Qu > --- > fs/btrfs/relocation.c | 16 +++++----------- > 1 file changed, 5 insertions(+), 11 deletions(-) > > diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c > index e5cb64409f7c..f13b79adf6b0 100644 > --- a/fs/btrfs/relocation.c > +++ b/fs/btrfs/relocation.c > @@ -2523,13 +2523,10 @@ int prepare_to_merge(struct reloc_control *rc, int err) > static noinline_for_stack > void free_reloc_roots(struct list_head *list) > { > - struct btrfs_root *reloc_root; > + struct btrfs_root *reloc_root, *tmp; > > - while (!list_empty(list)) { > - reloc_root = list_entry(list->next, struct btrfs_root, > - root_list); > + list_for_each_entry_safe(reloc_root, tmp, list, root_list) > __del_reloc_root(reloc_root); > - } > } > > static noinline_for_stack > @@ -2588,15 +2585,13 @@ void merge_reloc_roots(struct reloc_control *rc) > out: > if (ret) { > btrfs_handle_fs_error(fs_info, ret, NULL); > - if (!list_empty(&reloc_roots)) > - free_reloc_roots(&reloc_roots); > + free_reloc_roots(&reloc_roots); > > /* new reloc root may be added */ > mutex_lock(&fs_info->reloc_mutex); > list_splice_init(&rc->reloc_roots, &reloc_roots); > mutex_unlock(&fs_info->reloc_mutex); > - if (!list_empty(&reloc_roots)) > - free_reloc_roots(&reloc_roots); > + free_reloc_roots(&reloc_roots); > } > > BUG_ON(!RB_EMPTY_ROOT(&rc->reloc_root_tree.rb_root)); > @@ -4689,8 +4684,7 @@ int btrfs_recover_relocation(struct btrfs_root *root) > out_free: > kfree(rc); > out: > - if (!list_empty(&reloc_roots)) > - free_reloc_roots(&reloc_roots); > + free_reloc_roots(&reloc_roots); > > btrfs_free_path(path); > > ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] btrfs: Use list_for_each_entry_safe in free_reloc_roots 2020-02-21 13:11 ` [PATCH 2/2] btrfs: Use list_for_each_entry_safe in free_reloc_roots Nikolay Borisov 2020-02-21 13:17 ` [PATCH v2 " Nikolay Borisov 2020-02-21 13:23 ` [PATCH " Qu Wenruo @ 2020-04-10 16:33 ` David Sterba 2 siblings, 0 replies; 7+ messages in thread From: David Sterba @ 2020-04-10 16:33 UTC (permalink / raw) To: Nikolay Borisov; +Cc: linux-btrfs On Fri, Feb 21, 2020 at 03:11:24PM +0200, Nikolay Borisov wrote: > The function always works on a local copy of the reloc root list, which > cannot be modified outside of it so using list_for_each_entry is fine. > Additionally the macro handles empty lists so drop list_empty checks of > callers. No semantic changes. > > Signed-off-by: Nikolay Borisov <nborisov@suse.com> This is still relevant for misc-next, so I'm applying it to misc-next. ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] btrfs: Remove superflous lock acquisition in __del_reloc_root 2020-02-21 13:11 [PATCH 1/2] btrfs: Remove superflous lock acquisition in __del_reloc_root Nikolay Borisov 2020-02-21 13:11 ` [PATCH 2/2] btrfs: Use list_for_each_entry_safe in free_reloc_roots Nikolay Borisov @ 2020-02-21 13:22 ` Qu Wenruo 2020-04-10 16:29 ` David Sterba 2 siblings, 0 replies; 7+ messages in thread From: Qu Wenruo @ 2020-02-21 13:22 UTC (permalink / raw) To: Nikolay Borisov, linux-btrfs On 2020/2/21 下午9:11, Nikolay Borisov wrote: > __del_reloc_root is called from: > > a) Transaction commit via: > btrfs_transaction_commit > commit_fs_roots > btrfs_update_reloc_root > __del_reloc_root > > b) From the relocation thread with the following call chains: > > relocate_block_group > merge_reloc_roots > insert_dirty_subvol > btrfs_update_reloc_root > __del_reloc_root > > c) merge_reloc_roots > free_reloc_roots > __del_reloc_roots > > (The above call chain can called from btrfs_recover_relocation as well > but for the purpose of this fix this is irrelevant). > > The commont data structure that needs protecting is > fs_info->reloc_ctl->reloc_list as reloc roots are anchored at this list. > Turns out it's no needed to hold the trans_lock in __del_reloc_root > since consistency is already guaranteed by call chain b) above holding > a transaction while calling insert_dirty_subvol, meaning we cannot have > a concurrent transaction commit. For call chain c) above a snapshot of > the fs_info->reloc_ctl->reloc_list is taken with reloc_mutex held and > free_reloc_roots is called on this local snapshot. > > Those invariants are sufficient to prevent racing calls to > __del_reloc_root alongside other users of the list, as such it's fine > to drop the lock acquisition. > > Signed-off-by: Nikolay Borisov <nborisov@suse.com> Reviewed-by: Qu Wenruo <wqu@suse.com> Thanks, Qu > --- > fs/btrfs/relocation.c | 2 -- > 1 file changed, 2 deletions(-) > > diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c > index 8076c340749f..e5cb64409f7c 100644 > --- a/fs/btrfs/relocation.c > +++ b/fs/btrfs/relocation.c > @@ -1381,9 +1381,7 @@ static void __del_reloc_root(struct btrfs_root *root) > BUG_ON((struct btrfs_root *)node->data != root); > } > > - spin_lock(&fs_info->trans_lock); > list_del_init(&root->root_list); > - spin_unlock(&fs_info->trans_lock); > kfree(node); > } > > ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] btrfs: Remove superflous lock acquisition in __del_reloc_root 2020-02-21 13:11 [PATCH 1/2] btrfs: Remove superflous lock acquisition in __del_reloc_root Nikolay Borisov 2020-02-21 13:11 ` [PATCH 2/2] btrfs: Use list_for_each_entry_safe in free_reloc_roots Nikolay Borisov 2020-02-21 13:22 ` [PATCH 1/2] btrfs: Remove superflous lock acquisition in __del_reloc_root Qu Wenruo @ 2020-04-10 16:29 ` David Sterba 2 siblings, 0 replies; 7+ messages in thread From: David Sterba @ 2020-04-10 16:29 UTC (permalink / raw) To: Nikolay Borisov; +Cc: linux-btrfs On Fri, Feb 21, 2020 at 03:11:23PM +0200, Nikolay Borisov wrote: > __del_reloc_root is called from: > > a) Transaction commit via: > btrfs_transaction_commit > commit_fs_roots > btrfs_update_reloc_root > __del_reloc_root > > b) From the relocation thread with the following call chains: > > relocate_block_group > merge_reloc_roots > insert_dirty_subvol > btrfs_update_reloc_root > __del_reloc_root > > c) merge_reloc_roots > free_reloc_roots > __del_reloc_roots > > (The above call chain can called from btrfs_recover_relocation as well > but for the purpose of this fix this is irrelevant). > > The commont data structure that needs protecting is > fs_info->reloc_ctl->reloc_list as reloc roots are anchored at this list. > Turns out it's no needed to hold the trans_lock in __del_reloc_root > since consistency is already guaranteed by call chain b) above holding > a transaction while calling insert_dirty_subvol, meaning we cannot have > a concurrent transaction commit. For call chain c) above a snapshot of > the fs_info->reloc_ctl->reloc_list is taken with reloc_mutex held and > free_reloc_roots is called on this local snapshot. > > Those invariants are sufficient to prevent racing calls to > __del_reloc_root alongside other users of the list, as such it's fine > to drop the lock acquisition. > > Signed-off-by: Nikolay Borisov <nborisov@suse.com> > --- > fs/btrfs/relocation.c | 2 -- > 1 file changed, 2 deletions(-) > > diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c > index 8076c340749f..e5cb64409f7c 100644 > --- a/fs/btrfs/relocation.c > +++ b/fs/btrfs/relocation.c > @@ -1381,9 +1381,7 @@ static void __del_reloc_root(struct btrfs_root *root) > BUG_ON((struct btrfs_root *)node->data != root); > } > > - spin_lock(&fs_info->trans_lock); > list_del_init(&root->root_list); > - spin_unlock(&fs_info->trans_lock); This has been obsoleted by patch f44deb7442edf42abee6 ("btrfs: hold a ref on the root->reloc_root"), I think the locks are still needed but you may want take a look. ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2020-04-10 16:33 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2020-02-21 13:11 [PATCH 1/2] btrfs: Remove superflous lock acquisition in __del_reloc_root Nikolay Borisov 2020-02-21 13:11 ` [PATCH 2/2] btrfs: Use list_for_each_entry_safe in free_reloc_roots Nikolay Borisov 2020-02-21 13:17 ` [PATCH v2 " Nikolay Borisov 2020-02-21 13:23 ` [PATCH " Qu Wenruo 2020-04-10 16:33 ` David Sterba 2020-02-21 13:22 ` [PATCH 1/2] btrfs: Remove superflous lock acquisition in __del_reloc_root Qu Wenruo 2020-04-10 16:29 ` David Sterba
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox