Cleanup waitqueue_active and barriers
David Sterba
maintainerv3 cover Cleanup waitqueue_active and barriers
Reduce number of standalone barriers before waitqueue_active calls.
Changes v3:
* fix wrong use of the _nomb variant in tree-log.c:btrfs_sync_log,
* update comments to be more specific about the waitqueue_active and barrier
Changes v2:
* add 2 barriers to btrfs_sync_log and do not assume they're implied, (pointed out by Nikolay)
git://github.com/kdave/btrfs-devel.git cleanup/cond-wake
David Sterba (3):
btrfs: introduce conditional wakeup helpers
btrfs: add barriers to btrfs_sync_log before log_commit_wait wakeups
btrfs: replace waitqueue_actvie with cond_wake_up
fs/btrfs/compression.c | 7 +------ fs/btrfs/ctree.h | 22 ++++++++++++++++++++++ fs/btrfs/delayed-inode.c | 9 +++------ fs/btrfs/dev-replace.c | 10 ++++------ fs/btrfs/extent-tree.c | 7 +------ fs/btrfs/inode.c | 9 +++------ fs/btrfs/locking.c | 34 +++++++++++----------------------- fs/btrfs/ordered-data.c | 14 ++++---------- fs/btrfs/transaction.c | 7 +------ fs/btrfs/tree-log.c | 28 ++++++++++++---------------- 10 files changed, 62 insertions(+), 85 deletions(-)
Signature · 1 line
2.16.2
David Sterba
maintainerPATCH v3 1/3 btrfs: introduce conditional wakeup helpers
Add convenience wrappers for the waitqueue management that involves memory barriers to prevent deadlocks. The helpers will let us remove barriers and the necessary comments in several places.
--- fs/btrfs/ctree.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
fs/btrfs/ctree.h +22 -0
@@ -3765,4 +3765,26 @@ static inline int btrfs_is_testing(struct btrfs_fs_info *fs_info) return 0; } +static inline void cond_wake_up (struct wait_queue_head *wq) +{ +/* +* This implies a full smp_mb barrier, see comments for +* waitqueue_active why. +*/ +if (wq_has_sleeper (wq)) +wake_up (wq); +} + +static inline void cond_wake_up_nomb (struct wait_queue_head *wq) +{ +/* +* Special case for conditional wakeup where the barrier required for +* waitqueue_active is implied by some of the preceding code. Eg. one +* of such atomic operations (atomic_dec_and_return, ...), or a +* unlock/lock sequence, etc. +*/ +if (waitqueue_active (wq)) +wake_up (wq); +} +#endif
Signature · 1 line
2.16.2
David Sterba
maintainerPATCH v3 2/3 btrfs: add barriers to btrfs_sync_log before log_commit_wait wakeups
In reply to David SterbaCurrently the code assumes that there's an implied barrier by the sequence of code preceding the wakeup, namely the mutex unlock.
As Nikolay pointed out:
I think this is wrong (not your code) but the original assumption that the RELEASE semantics provided by mutex_unlock is sufficient. According to memory-barriers.txt:
Section 'LOCK ACQUISITION FUNCTIONS' states:
(2) RELEASE operation implication:
Memory operations issued before the RELEASE will be completed before the RELEASE operation has completed.
Memory operations issued after the RELEASE *may* be completed before the RELEASE operation has completed.
(I've bolded the may portion)
The example given there:
As an example, consider the following:
*A = a;
*B = b;
ACQUIRE
*C = c;
*D = d;
RELEASE
*E = e;
*F = f;The following sequence of events is acceptable:
ACQUIRE, {*F,*A}, *E, {*C,*D}, *B, RELEASESo if we assume that *C is modifying the flag which the waitqueue is checking, and *E is the actual wakeup, then those accesses can be re-ordered...
IMHO this code should be considered broken...
---
To be on the safe side, add the barriers. The synchronization logic around log using the mutexes and several other threads does not make it easy to reason for/against the barrier.
--- fs/btrfs/tree-log.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
fs/btrfs/tree-log.c +8 -2
@@ -3116,8 +3116,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,mutex_unlock (&log_root_tree->log_mutex);/* -* The barrier before waitqueue_active is implied by mutex_unlock +* The barrier before waitqueue_active is needed so all the updates +* above are seen by the woken threads. It might not be necessary, but +* proving that seems to be hard. */ +smp_mb ();if (waitqueue_active (&log_root_tree->log_commit_wait[index2]))wake_up (&log_root_tree->log_commit_wait[index2]); out:
@@ -3128,8 +3131,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,mutex_unlock (&root->log_mutex);/* -* The barrier before waitqueue_active is implied by mutex_unlock +* The barrier before waitqueue_active is needed so all the updates +* above are seen by the woken threads. It might not be necessary, but +* proving that seems to be hard. */ +smp_mb ();if (waitqueue_active (&root->log_commit_wait[index1]))wake_up (&root->log_commit_wait[index1]);return ret;
Signature · 1 line
2.16.2
David Sterba
maintainerPATCH v3 3/3 btrfs: replace waitqueue_actvie with cond_wake_up
In reply to David SterbaUse the wrappers and reduce the amount of low-level details about the waitqueue management.
--- fs/btrfs/compression.c | 7 +------ fs/btrfs/delayed-inode.c | 9 +++------ fs/btrfs/dev-replace.c | 10 ++++------ fs/btrfs/extent-tree.c | 7 +------ fs/btrfs/inode.c | 9 +++------ fs/btrfs/locking.c | 34 +++++++++++----------------------- fs/btrfs/ordered-data.c | 14 ++++---------- fs/btrfs/transaction.c | 7 +------ fs/btrfs/tree-log.c | 34 ++++++++++++---------------------- 9 files changed, 40 insertions(+), 91 deletions(-)
fs/btrfs/compression.c +1 -6
@@ -990,12 +990,7 @@ static void __free_workspace(int type, struct list_head *workspace, btrfs_compress_op[idx]->free_workspace (workspace);atomic_dec (total_ws); wake: -/* -* Make sure counter is updated before we wake up waiters. -*/ -smp_mb (); -if (waitqueue_active (ws_wait)) -wake_up (ws_wait); +cond_wake_up (ws_wait); }static void free_workspace (int type,struct list_head *ws)
fs/btrfs/delayed-inode.c +3 -6
@@ -460,13 +460,10 @@ static void finish_one_item(struct btrfs_delayed_root *delayed_root) {int seq =atomic_inc_return (&delayed_root->items_seq); -/* -* atomic_dec_return implies a barrier for waitqueue_active -*/ +/* atomic_dec_return implies a barrier */ if ((atomic_dec_return (&delayed_root->items) < -BTRFS_DELAYED_BACKGROUND || seq %BTRFS_DELAYED_BATCH ==0 ) && -waitqueue_active (&delayed_root->wait)) -wake_up (&delayed_root->wait); +BTRFS_DELAYED_BACKGROUND || seq %BTRFS_DELAYED_BATCH ==0 )) +cond_wake_up_nomb (&delayed_root->wait); }static void __btrfs_remove_delayed_item (struct btrfs_delayed_item *delayed_item)
fs/btrfs/dev-replace.c +4 -6
@@ -916,9 +916,9 @@ void btrfs_dev_replace_clear_lock_blocking(ASSERT (atomic_read (&dev_replace->read_locks) >0 );ASSERT (atomic_read (&dev_replace->blocking_readers) >0 );read_lock (&dev_replace->lock); -if (atomic_dec_and_test (&dev_replace->blocking_readers) && -waitqueue_active (&dev_replace->read_lock_wq)) -wake_up (&dev_replace->read_lock_wq); +/* Barrier implied by atomic_dec_and_test */ +if (atomic_dec_and_test (&dev_replace->blocking_readers)) +cond_wake_up_nomb (&dev_replace->read_lock_wq); }void btrfs_bio_counter_inc_noblocked (struct btrfs_fs_info *fs_info)
@@ -929,9 +929,7 @@ void btrfs_bio_counter_inc_noblocked(struct btrfs_fs_info *fs_info)void btrfs_bio_counter_sub (struct btrfs_fs_info *fs_info,s64 amount) {percpu_counter_sub (&fs_info->bio_counter, amount); - -if (waitqueue_active (&fs_info->replace_wait)) -wake_up (&fs_info->replace_wait); +cond_wake_up_nomb (&fs_info->replace_wait); }void btrfs_bio_counter_inc_blocked (struct btrfs_fs_info *fs_info)
fs/btrfs/extent-tree.c +1 -6
@@ -11094,12 +11094,7 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)void btrfs_end_write_no_snapshotting (struct btrfs_root *root) {percpu_counter_dec (&root->subv_writers->counter); -/* -* Make sure counter is updated before we wake up waiters. -*/ -smp_mb (); -if (waitqueue_active (&root->subv_writers->wait)) -wake_up (&root->subv_writers->wait); +cond_wake_up (&root->subv_writers->wait); }int btrfs_start_write_no_snapshotting (struct btrfs_root *root)
fs/btrfs/inode.c +3 -6
@@ -1156,13 +1156,10 @@ static noinline void async_cow_submit(struct btrfs_work *work) nr_pages = (async_cow->end - async_cow->start +PAGE_SIZE ) >>PAGE_SHIFT ; -/* -* atomic_sub_return implies a barrier for waitqueue_active -*/ +/* atomic_sub_return implies a barrier */ if (atomic_sub_return (nr_pages, &fs_info->async_delalloc_pages) < -5 *SZ_1M && -waitqueue_active (&fs_info->async_submit_wait)) -wake_up (&fs_info->async_submit_wait); +5 *SZ_1M ) +cond_wake_up_nomb (&fs_info->async_submit_wait);if (async_cow->inode)submit_compressed_extents (async_cow->inode, async_cow);
fs/btrfs/locking.c +11 -23
@@ -66,22 +66,16 @@ void btrfs_clear_lock_blocking_rw(struct extent_buffer *eb, int rw)write_lock (&eb->lock);WARN_ON (atomic_read (&eb->spinning_writers));atomic_inc (&eb->spinning_writers); -/* -* atomic_dec_and_test implies a barrier for waitqueue_active -*/ -if (atomic_dec_and_test (&eb->blocking_writers) && -waitqueue_active (&eb->write_lock_wq)) -wake_up (&eb->write_lock_wq); +/* atomic_dec_and_test implies a barrier */ +if (atomic_dec_and_test (&eb->blocking_writers)) +cond_wake_up_nomb (&eb->write_lock_wq); }else if (rw ==BTRFS_READ_LOCK_BLOCKING ) {BUG_ON (atomic_read (&eb->blocking_readers) ==0 );read_lock (&eb->lock);atomic_inc (&eb->spinning_readers); -/* -* atomic_dec_and_test implies a barrier for waitqueue_active -*/ -if (atomic_dec_and_test (&eb->blocking_readers) && -waitqueue_active (&eb->read_lock_wq)) -wake_up (&eb->read_lock_wq); +/* atomic_dec_and_test implies a barrier */ +if (atomic_dec_and_test (&eb->blocking_readers)) +cond_wake_up_nomb (&eb->read_lock_wq); } }
@@ -221,12 +215,9 @@ void btrfs_tree_read_unlock_blocking(struct extent_buffer *eb) }btrfs_assert_tree_read_locked (eb);WARN_ON (atomic_read (&eb->blocking_readers) ==0 ); -/* -* atomic_dec_and_test implies a barrier for waitqueue_active -*/ -if (atomic_dec_and_test (&eb->blocking_readers) && -waitqueue_active (&eb->read_lock_wq)) -wake_up (&eb->read_lock_wq); +/* atomic_dec_and_test implies a barrier */ +if (atomic_dec_and_test (&eb->blocking_readers)) +cond_wake_up_nomb (&eb->read_lock_wq);atomic_dec (&eb->read_locks); }
@@ -275,12 +266,9 @@ void btrfs_tree_unlock(struct extent_buffer *eb)if (blockers) {WARN_ON (atomic_read (&eb->spinning_writers));atomic_dec (&eb->blocking_writers); -/* -* Make sure counter is updated before we wake up waiters. -*/ +/* Use the lighter barrier after atomic */ smp_mb__after_atomic (); -if (waitqueue_active (&eb->write_lock_wq)) -wake_up (&eb->write_lock_wq); +cond_wake_up_nomb (&eb->write_lock_wq); }else {WARN_ON (atomic_read (&eb->spinning_writers) !=1 );atomic_dec (&eb->spinning_writers);
fs/btrfs/ordered-data.c +4 -10
@@ -343,11 +343,8 @@ int btrfs_dec_test_first_ordered_pending(struct inode *inode,if (entry->bytes_left ==0 ) { ret =test_and_set_bit (BTRFS_ORDERED_IO_DONE , &entry->flags); -/* -* Implicit memory barrier after test_and_set_bit -*/ -if (waitqueue_active (&entry->wait)) -wake_up (&entry->wait); +/* test_and_set_bit implies a barrier */ +cond_wake_up_nomb (&entry->wait); }else { ret =1 ; }
@@ -410,11 +407,8 @@ int btrfs_dec_test_ordered_pending(struct inode *inode,if (entry->bytes_left ==0 ) { ret =test_and_set_bit (BTRFS_ORDERED_IO_DONE , &entry->flags); -/* -* Implicit memory barrier after test_and_set_bit -*/ -if (waitqueue_active (&entry->wait)) -wake_up (&entry->wait); +/* test_and_set_bit implies a barrier */ +cond_wake_up_nomb (&entry->wait); }else { ret =1 ; }
fs/btrfs/transaction.c +1 -6
@@ -877,12 +877,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,atomic_dec (&cur_trans->num_writers);extwriter_counter_dec (cur_trans, trans->type); -/* -* Make sure counter is updated before we wake up waiters. -*/ -smp_mb (); -if (waitqueue_active (&cur_trans->writer_wait)) -wake_up (&cur_trans->writer_wait); +cond_wake_up (&cur_trans->writer_wait);btrfs_put_transaction (cur_trans);if (current->journal_info == trans)
fs/btrfs/tree-log.c +12 -22
@@ -222,11 +222,8 @@ int btrfs_pin_log_trans(struct btrfs_root *root)void btrfs_end_log_trans (struct btrfs_root *root) {if (atomic_dec_and_test (&root->log_writers)) { -/* -* Implicit memory barrier after atomic_dec_and_test -*/ -if (waitqueue_active (&root->log_writer_wait)) -wake_up (&root->log_writer_wait); +/* atomic_dec_and_test implies a barrier */ +cond_wake_up_nomb (&root->log_writer_wait); } }
@@ -2988,11 +2985,8 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,mutex_lock (&log_root_tree->log_mutex);if (atomic_dec_and_test (&log_root_tree->log_writers)) { -/* -* Implicit memory barrier after atomic_dec_and_test -*/ -if (waitqueue_active (&log_root_tree->log_writer_wait)) -wake_up (&log_root_tree->log_writer_wait); +/* atomic_dec_and_test implies a barrier */ +cond_wake_up_nomb (&log_root_tree->log_writer_wait); }if (ret) {
@@ -3116,13 +3110,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,mutex_unlock (&log_root_tree->log_mutex);/* -* The barrier before waitqueue_active is needed so all the updates -* above are seen by the woken threads. It might not be necessary, but -* proving that seems to be hard. +* The barrier before waitqueue_active (in cond_wake_up) is needed so +* all the updates above are seen by the woken threads. It might not be +* necessary, but proving that seems to be hard. */ -smp_mb (); -if (waitqueue_active (&log_root_tree->log_commit_wait[index2])) -wake_up (&log_root_tree->log_commit_wait[index2]); +cond_wake_up (&log_root_tree->log_commit_wait[index2]); out:mutex_lock (&root->log_mutex);btrfs_remove_all_log_ctxs (root, index1, ret);
@@ -3131,13 +3123,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,mutex_unlock (&root->log_mutex);/* -* The barrier before waitqueue_active is needed so all the updates -* above are seen by the woken threads. It might not be necessary, but -* proving that seems to be hard. +* The barrier before waitqueue_active (in cond_wake_up) is needed so +* all the updates above are seen by the woken threads. It might not be +* necessary, but proving that seems to be hard. */ -smp_mb (); -if (waitqueue_active (&root->log_commit_wait[index1])) -wake_up (&root->log_commit_wait[index1]); +cond_wake_up (&root->log_commit_wait[index1]);return ret; }
Signature · 1 line
2.16.2
Re: [PATCH v3 2/3] btrfs: add barriers to btrfs_sync_log before log_commit_wait wakeups
In reply to David SterbaQuoted 44 lines · David Sterba
Currently the code assumes that there's an implied barrier by the sequence of code preceding the wakeup, namely the mutex unlock.
As Nikolay pointed out:
I think this is wrong (not your code) but the original assumption that the RELEASE semantics provided by
mutex_unlockis sufficient. According to memory-barriers.txt:Section 'LOCK ACQUISITION FUNCTIONS' states:
(2) RELEASE operation implication:
Memory operations issued before the RELEASE will be completed before the RELEASE operation has completed.
Memory operations issued after the RELEASE *may* be completed before the RELEASE operation has completed.
(I've bolded the may portion)
The example given there:
As an example, consider the following:
*A = a; *B = b; ACQUIRE *C = c; *D = d; RELEASE *E = e; *F = f;The following sequence of events is acceptable:
ACQUIRE, {*F,*A}, *E, {*C,*D}, *B, RELEASESo if we assume that *C is modifying the flag which the waitqueue is checking, and *E is the actual wakeup, then those accesses can be re-ordered...
IMHO this code should be considered broken...
---
Quoted 8 lines
To be on the safe side, add the barriers. The synchronization logic around log using the mutexes and several other threads does not make it easy to reason for/against the barrier.
CC Nikolay Borisov <[email protected]>Signed-off-by David Sterba <[email protected]>---
Apart from what I said initially which prompted introducing this patch I can't say anything else. I think the fsync code is in dire need of being rewritten/simplified.
But in so far as the newly introduced barriers are concerned:
Quoted 34 lines
fs/btrfs/tree-log.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)fs/btrfs/tree-log.c +8
-2@@ -3116,8 +3116,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,mutex_unlock (&log_root_tree->log_mutex);/* -* The barrier before waitqueue_active is implied by mutex_unlock +* The barrier before waitqueue_active is needed so all the updates +* above are seen by the woken threads. It might not be necessary, but +* proving that seems to be hard. */ +smp_mb ();if (waitqueue_active (&log_root_tree->log_commit_wait[index2]))wake_up (&log_root_tree->log_commit_wait[index2]); out:@@ -3128,8 +3131,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,mutex_unlock (&root->log_mutex);/* -* The barrier before waitqueue_active is implied by mutex_unlock +* The barrier before waitqueue_active is needed so all the updates +* above are seen by the woken threads. It might not be necessary, but +* proving that seems to be hard. */ +smp_mb ();if (waitqueue_active (&root->log_commit_wait[index1]))wake_up (&root->log_commit_wait[index1]);return ret;
Re: [PATCH v3 3/3] btrfs: replace waitqueue_actvie with cond_wake_up
In reply to David SterbaQuoted 4 lines · David Sterba
Use the wrappers and reduce the amount of low-level details about the waitqueue management.
Signed-off-by David Sterba <[email protected]>
Quoted 301 lines
--- fs/btrfs/compression.c | 7 +------ fs/btrfs/delayed-inode.c | 9 +++------ fs/btrfs/dev-replace.c | 10 ++++------ fs/btrfs/extent-tree.c | 7 +------ fs/btrfs/inode.c | 9 +++------ fs/btrfs/locking.c | 34 +++++++++++----------------------- fs/btrfs/ordered-data.c | 14 ++++---------- fs/btrfs/transaction.c | 7 +------ fs/btrfs/tree-log.c | 34 ++++++++++++---------------------- 9 files changed, 40 insertions(+), 91 deletions(-)fs/btrfs/compression.c +1
-6@@ -990,12 +990,7 @@ static void __free_workspace(int type, struct list_head *workspace, btrfs_compress_op[idx]->free_workspace (workspace);atomic_dec (total_ws); wake: -/* -* Make sure counter is updated before we wake up waiters. -*/ -smp_mb (); -if (waitqueue_active (ws_wait)) -wake_up (ws_wait); +cond_wake_up (ws_wait); }static void free_workspace (int type,struct list_head *ws)fs/btrfs/delayed-inode.c +3
-6@@ -460,13 +460,10 @@ static void finish_one_item(struct btrfs_delayed_root *delayed_root) {int seq =atomic_inc_return (&delayed_root->items_seq); -/* -* atomic_dec_return implies a barrier for waitqueue_active -*/ +/* atomic_dec_return implies a barrier */ if ((atomic_dec_return (&delayed_root->items) < -BTRFS_DELAYED_BACKGROUND || seq %BTRFS_DELAYED_BATCH ==0 ) && -waitqueue_active (&delayed_root->wait)) -wake_up (&delayed_root->wait); +BTRFS_DELAYED_BACKGROUND || seq %BTRFS_DELAYED_BATCH ==0 )) +cond_wake_up_nomb (&delayed_root->wait); }static void __btrfs_remove_delayed_item (struct btrfs_delayed_item *delayed_item)fs/btrfs/dev-replace.c +4
-6@@ -916,9 +916,9 @@ void btrfs_dev_replace_clear_lock_blocking(ASSERT (atomic_read (&dev_replace->read_locks) >0 );ASSERT (atomic_read (&dev_replace->blocking_readers) >0 );read_lock (&dev_replace->lock); -if (atomic_dec_and_test (&dev_replace->blocking_readers) && -waitqueue_active (&dev_replace->read_lock_wq)) -wake_up (&dev_replace->read_lock_wq); +/* Barrier implied by atomic_dec_and_test */ +if (atomic_dec_and_test (&dev_replace->blocking_readers)) +cond_wake_up_nomb (&dev_replace->read_lock_wq); }void btrfs_bio_counter_inc_noblocked (struct btrfs_fs_info *fs_info)@@ -929,9 +929,7 @@ void btrfs_bio_counter_inc_noblocked(struct btrfs_fs_info *fs_info)void btrfs_bio_counter_sub (struct btrfs_fs_info *fs_info,s64 amount) {percpu_counter_sub (&fs_info->bio_counter, amount); - -if (waitqueue_active (&fs_info->replace_wait)) -wake_up (&fs_info->replace_wait); +cond_wake_up_nomb (&fs_info->replace_wait); }void btrfs_bio_counter_inc_blocked (struct btrfs_fs_info *fs_info)fs/btrfs/extent-tree.c +1
-6@@ -11094,12 +11094,7 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)void btrfs_end_write_no_snapshotting (struct btrfs_root *root) {percpu_counter_dec (&root->subv_writers->counter); -/* -* Make sure counter is updated before we wake up waiters. -*/ -smp_mb (); -if (waitqueue_active (&root->subv_writers->wait)) -wake_up (&root->subv_writers->wait); +cond_wake_up (&root->subv_writers->wait); }int btrfs_start_write_no_snapshotting (struct btrfs_root *root)fs/btrfs/inode.c +3
-6@@ -1156,13 +1156,10 @@ static noinline void async_cow_submit(struct btrfs_work *work) nr_pages = (async_cow->end - async_cow->start +PAGE_SIZE ) >>PAGE_SHIFT ; -/* -* atomic_sub_return implies a barrier for waitqueue_active -*/ +/* atomic_sub_return implies a barrier */ if (atomic_sub_return (nr_pages, &fs_info->async_delalloc_pages) < -5 *SZ_1M && -waitqueue_active (&fs_info->async_submit_wait)) -wake_up (&fs_info->async_submit_wait); +5 *SZ_1M ) +cond_wake_up_nomb (&fs_info->async_submit_wait);if (async_cow->inode)submit_compressed_extents (async_cow->inode, async_cow);fs/btrfs/locking.c +11
-23@@ -66,22 +66,16 @@ void btrfs_clear_lock_blocking_rw(struct extent_buffer *eb, int rw)write_lock (&eb->lock);WARN_ON (atomic_read (&eb->spinning_writers));atomic_inc (&eb->spinning_writers); -/* -* atomic_dec_and_test implies a barrier for waitqueue_active -*/ -if (atomic_dec_and_test (&eb->blocking_writers) && -waitqueue_active (&eb->write_lock_wq)) -wake_up (&eb->write_lock_wq); +/* atomic_dec_and_test implies a barrier */ +if (atomic_dec_and_test (&eb->blocking_writers)) +cond_wake_up_nomb (&eb->write_lock_wq); }else if (rw ==BTRFS_READ_LOCK_BLOCKING ) {BUG_ON (atomic_read (&eb->blocking_readers) ==0 );read_lock (&eb->lock);atomic_inc (&eb->spinning_readers); -/* -* atomic_dec_and_test implies a barrier for waitqueue_active -*/ -if (atomic_dec_and_test (&eb->blocking_readers) && -waitqueue_active (&eb->read_lock_wq)) -wake_up (&eb->read_lock_wq); +/* atomic_dec_and_test implies a barrier */ +if (atomic_dec_and_test (&eb->blocking_readers)) +cond_wake_up_nomb (&eb->read_lock_wq); } }@@ -221,12 +215,9 @@ void btrfs_tree_read_unlock_blocking(struct extent_buffer *eb) }btrfs_assert_tree_read_locked (eb);WARN_ON (atomic_read (&eb->blocking_readers) ==0 ); -/* -* atomic_dec_and_test implies a barrier for waitqueue_active -*/ -if (atomic_dec_and_test (&eb->blocking_readers) && -waitqueue_active (&eb->read_lock_wq)) -wake_up (&eb->read_lock_wq); +/* atomic_dec_and_test implies a barrier */ +if (atomic_dec_and_test (&eb->blocking_readers)) +cond_wake_up_nomb (&eb->read_lock_wq);atomic_dec (&eb->read_locks); }@@ -275,12 +266,9 @@ void btrfs_tree_unlock(struct extent_buffer *eb)if (blockers) {WARN_ON (atomic_read (&eb->spinning_writers));atomic_dec (&eb->blocking_writers); -/* -* Make sure counter is updated before we wake up waiters. -*/ +/* Use the lighter barrier after atomic */ smp_mb__after_atomic (); -if (waitqueue_active (&eb->write_lock_wq)) -wake_up (&eb->write_lock_wq); +cond_wake_up_nomb (&eb->write_lock_wq); }else {WARN_ON (atomic_read (&eb->spinning_writers) !=1 );atomic_dec (&eb->spinning_writers);fs/btrfs/ordered-data.c +4
-10@@ -343,11 +343,8 @@ int btrfs_dec_test_first_ordered_pending(struct inode *inode,if (entry->bytes_left ==0 ) { ret =test_and_set_bit (BTRFS_ORDERED_IO_DONE , &entry->flags); -/* -* Implicit memory barrier after test_and_set_bit -*/ -if (waitqueue_active (&entry->wait)) -wake_up (&entry->wait); +/* test_and_set_bit implies a barrier */ +cond_wake_up_nomb (&entry->wait); }else { ret =1 ; }@@ -410,11 +407,8 @@ int btrfs_dec_test_ordered_pending(struct inode *inode,if (entry->bytes_left ==0 ) { ret =test_and_set_bit (BTRFS_ORDERED_IO_DONE , &entry->flags); -/* -* Implicit memory barrier after test_and_set_bit -*/ -if (waitqueue_active (&entry->wait)) -wake_up (&entry->wait); +/* test_and_set_bit implies a barrier */ +cond_wake_up_nomb (&entry->wait); }else { ret =1 ; }fs/btrfs/transaction.c +1
-6@@ -877,12 +877,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,atomic_dec (&cur_trans->num_writers);extwriter_counter_dec (cur_trans, trans->type); -/* -* Make sure counter is updated before we wake up waiters. -*/ -smp_mb (); -if (waitqueue_active (&cur_trans->writer_wait)) -wake_up (&cur_trans->writer_wait); +cond_wake_up (&cur_trans->writer_wait);btrfs_put_transaction (cur_trans);if (current->journal_info == trans)fs/btrfs/tree-log.c +12
-22@@ -222,11 +222,8 @@ int btrfs_pin_log_trans(struct btrfs_root *root)void btrfs_end_log_trans (struct btrfs_root *root) {if (atomic_dec_and_test (&root->log_writers)) { -/* -* Implicit memory barrier after atomic_dec_and_test -*/ -if (waitqueue_active (&root->log_writer_wait)) -wake_up (&root->log_writer_wait); +/* atomic_dec_and_test implies a barrier */ +cond_wake_up_nomb (&root->log_writer_wait); } }@@ -2988,11 +2985,8 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,mutex_lock (&log_root_tree->log_mutex);if (atomic_dec_and_test (&log_root_tree->log_writers)) { -/* -* Implicit memory barrier after atomic_dec_and_test -*/ -if (waitqueue_active (&log_root_tree->log_writer_wait)) -wake_up (&log_root_tree->log_writer_wait); +/* atomic_dec_and_test implies a barrier */ +cond_wake_up_nomb (&log_root_tree->log_writer_wait); }if (ret) {@@ -3116,13 +3110,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,mutex_unlock (&log_root_tree->log_mutex);/* -* The barrier before waitqueue_active is needed so all the updates -* above are seen by the woken threads. It might not be necessary, but -* proving that seems to be hard. +* The barrier before waitqueue_active (in cond_wake_up) is needed so +* all the updates above are seen by the woken threads. It might not be +* necessary, but proving that seems to be hard. */ -smp_mb (); -if (waitqueue_active (&log_root_tree->log_commit_wait[index2])) -wake_up (&log_root_tree->log_commit_wait[index2]); +cond_wake_up (&log_root_tree->log_commit_wait[index2]); out:mutex_lock (&root->log_mutex);btrfs_remove_all_log_ctxs (root, index1, ret);@@ -3131,13 +3123,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,mutex_unlock (&root->log_mutex);/* -* The barrier before waitqueue_active is needed so all the updates -* above are seen by the woken threads. It might not be necessary, but -* proving that seems to be hard. +* The barrier before waitqueue_active (in cond_wake_up) is needed so +* all the updates above are seen by the woken threads. It might not be +* necessary, but proving that seems to be hard. */ -smp_mb (); -if (waitqueue_active (&root->log_commit_wait[index1])) -wake_up (&root->log_commit_wait[index1]); +cond_wake_up (&root->log_commit_wait[index1]);return ret; }