diff options
author | David Sterba <dsterba@suse.com> | 2018-04-24 08:53:56 -0400 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2018-05-28 12:23:06 -0400 |
commit | 3d3a2e610ea5e7c6d4f9481ecce5d8e2d8317843 (patch) | |
tree | 1aeb76ba83d5a47cd0f580267d6b97966d531ce0 /fs/btrfs/tree-log.c | |
parent | 110a21feedd78d398598d91be57db60e19b76fe0 (diff) |
btrfs: add barriers to btrfs_sync_log before log_commit_wait wakeups
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_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, RELEASE
So 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.
CC: Nikolay Borisov <nborisov@suse.com>
Link: https://lkml.kernel.org/r/6ee068d8-1a69-3728-00d1-d86293d43c9f@suse.com
Reviewed-by: Nikolay Borisov <nborisov@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r-- | fs/btrfs/tree-log.c | 10 |
1 files changed, 8 insertions, 2 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 8f23a94dab77..2009cea65d89 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -3116,8 +3116,11 @@ out_wake_log_root: | |||
3116 | mutex_unlock(&log_root_tree->log_mutex); | 3116 | mutex_unlock(&log_root_tree->log_mutex); |
3117 | 3117 | ||
3118 | /* | 3118 | /* |
3119 | * The barrier before waitqueue_active is implied by mutex_unlock | 3119 | * The barrier before waitqueue_active is needed so all the updates |
3120 | * above are seen by the woken threads. It might not be necessary, but | ||
3121 | * proving that seems to be hard. | ||
3120 | */ | 3122 | */ |
3123 | smp_mb(); | ||
3121 | if (waitqueue_active(&log_root_tree->log_commit_wait[index2])) | 3124 | if (waitqueue_active(&log_root_tree->log_commit_wait[index2])) |
3122 | wake_up(&log_root_tree->log_commit_wait[index2]); | 3125 | wake_up(&log_root_tree->log_commit_wait[index2]); |
3123 | out: | 3126 | out: |
@@ -3128,8 +3131,11 @@ out: | |||
3128 | mutex_unlock(&root->log_mutex); | 3131 | mutex_unlock(&root->log_mutex); |
3129 | 3132 | ||
3130 | /* | 3133 | /* |
3131 | * The barrier before waitqueue_active is implied by mutex_unlock | 3134 | * The barrier before waitqueue_active is needed so all the updates |
3135 | * above are seen by the woken threads. It might not be necessary, but | ||
3136 | * proving that seems to be hard. | ||
3132 | */ | 3137 | */ |
3138 | smp_mb(); | ||
3133 | if (waitqueue_active(&root->log_commit_wait[index1])) | 3139 | if (waitqueue_active(&root->log_commit_wait[index1])) |
3134 | wake_up(&root->log_commit_wait[index1]); | 3140 | wake_up(&root->log_commit_wait[index1]); |
3135 | return ret; | 3141 | return ret; |