* [PATCH] bcachefs: Fix lost wake up
@ 2024-08-27 15:14 Alan Huang
2024-09-01 1:09 ` Kent Overstreet
0 siblings, 1 reply; 5+ messages in thread
From: Alan Huang @ 2024-08-27 15:14 UTC (permalink / raw)
To: kent.overstreet; +Cc: linux-bcachefs, Alan Huang
If the reader acquires the read lock and then the writer enters the slow
path, while the reader proceeds to the unlock path, the following scenario
can occur without the change:
writer: pcpu_read_count(lock) return 1 (so __do_six_trylock will return 0)
reader: this_cpu_dec(*lock->readers)
reader: smp_mb()
reader: state = atomic_read(&lock->state) (there is no waiting flag set)
writer: six_set_bitmask()
then the writer will sleep forever.
Signed-off-by: Alan Huang <mmpgouride@gmail.com>
---
fs/bcachefs/six.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/fs/bcachefs/six.c b/fs/bcachefs/six.c
index 3a494c5d1247..b3583c50ef04 100644
--- a/fs/bcachefs/six.c
+++ b/fs/bcachefs/six.c
@@ -169,11 +169,17 @@ static int __do_six_trylock(struct six_lock *lock, enum six_lock_type type,
ret = -1 - SIX_LOCK_write;
}
} else if (type == SIX_LOCK_write && lock->readers) {
- if (try) {
+ if (try)
atomic_add(SIX_LOCK_HELD_write, &lock->state);
- smp_mb__after_atomic();
- }
+ /*
+ * Make sure atomic_add happens before pcpu_read_count and
+ * six_set_bitmask in slow path happens before pcpu_read_count.
+ *
+ * Paired with the smp_mb() in read lock fast path (per-cpu mode)
+ * and the one before atomic_read in read unlock path.
+ */
+ smp_mb();
ret = !pcpu_read_count(lock);
if (try && !ret) {
--
2.45.2
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH] bcachefs: Fix lost wake up
2024-08-27 15:14 [PATCH] bcachefs: Fix lost wake up Alan Huang
@ 2024-09-01 1:09 ` Kent Overstreet
2024-09-01 2:50 ` Alan Huang
0 siblings, 1 reply; 5+ messages in thread
From: Kent Overstreet @ 2024-09-01 1:09 UTC (permalink / raw)
To: Alan Huang; +Cc: linux-bcachefs
On Tue, Aug 27, 2024 at 11:14:48PM GMT, Alan Huang wrote:
> If the reader acquires the read lock and then the writer enters the slow
> path, while the reader proceeds to the unlock path, the following scenario
> can occur without the change:
>
> writer: pcpu_read_count(lock) return 1 (so __do_six_trylock will return 0)
> reader: this_cpu_dec(*lock->readers)
> reader: smp_mb()
> reader: state = atomic_read(&lock->state) (there is no waiting flag set)
> writer: six_set_bitmask()
>
> then the writer will sleep forever.
>
> Signed-off-by: Alan Huang <mmpgouride@gmail.com>
> ---
> fs/bcachefs/six.c | 12 +++++++++---
> 1 file changed, 9 insertions(+), 3 deletions(-)
>
> diff --git a/fs/bcachefs/six.c b/fs/bcachefs/six.c
> index 3a494c5d1247..b3583c50ef04 100644
> --- a/fs/bcachefs/six.c
> +++ b/fs/bcachefs/six.c
> @@ -169,11 +169,17 @@ static int __do_six_trylock(struct six_lock *lock, enum six_lock_type type,
> ret = -1 - SIX_LOCK_write;
> }
> } else if (type == SIX_LOCK_write && lock->readers) {
> - if (try) {
> + if (try)
> atomic_add(SIX_LOCK_HELD_write, &lock->state);
> - smp_mb__after_atomic();
> - }
>
> + /*
> + * Make sure atomic_add happens before pcpu_read_count and
> + * six_set_bitmask in slow path happens before pcpu_read_count.
> + *
> + * Paired with the smp_mb() in read lock fast path (per-cpu mode)
> + * and the one before atomic_read in read unlock path.
> + */
> + smp_mb();
What is this barrier ordering?
This is only a change in the !try case, and we didn't do anything before
checking pcpu_read_count() - except way back in six_lock_slowpath()
where we set SIX_LOCK_HELD_write, but that does have a barrier.
> ret = !pcpu_read_count(lock);
>
> if (try && !ret) {
> --
> 2.45.2
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] bcachefs: Fix lost wake up
2024-09-01 1:09 ` Kent Overstreet
@ 2024-09-01 2:50 ` Alan Huang
2024-09-01 3:10 ` Kent Overstreet
0 siblings, 1 reply; 5+ messages in thread
From: Alan Huang @ 2024-09-01 2:50 UTC (permalink / raw)
To: Kent Overstreet; +Cc: linux-bcachefs
> 2024年9月1日 09:09,Kent Overstreet <kent.overstreet@linux.dev> wrote:
>
> On Tue, Aug 27, 2024 at 11:14:48PM GMT, Alan Huang wrote:
>> If the reader acquires the read lock and then the writer enters the slow
>> path, while the reader proceeds to the unlock path, the following scenario
>> can occur without the change:
>>
>> writer: pcpu_read_count(lock) return 1 (so __do_six_trylock will return 0)
>> reader: this_cpu_dec(*lock->readers)
>> reader: smp_mb()
>> reader: state = atomic_read(&lock->state) (there is no waiting flag set)
>> writer: six_set_bitmask()
>>
>> then the writer will sleep forever.
>>
>> Signed-off-by: Alan Huang <mmpgouride@gmail.com>
>> ---
>> fs/bcachefs/six.c | 12 +++++++++---
>> 1 file changed, 9 insertions(+), 3 deletions(-)
>>
>> diff --git a/fs/bcachefs/six.c b/fs/bcachefs/six.c
>> index 3a494c5d1247..b3583c50ef04 100644
>> --- a/fs/bcachefs/six.c
>> +++ b/fs/bcachefs/six.c
>> @@ -169,11 +169,17 @@ static int __do_six_trylock(struct six_lock *lock, enum six_lock_type type,
>> ret = -1 - SIX_LOCK_write;
>> }
>> } else if (type == SIX_LOCK_write && lock->readers) {
>> - if (try) {
>> + if (try)
>> atomic_add(SIX_LOCK_HELD_write, &lock->state);
>> - smp_mb__after_atomic();
>> - }
>>
>> + /*
>> + * Make sure atomic_add happens before pcpu_read_count and
>> + * six_set_bitmask in slow path happens before pcpu_read_count.
>> + *
>> + * Paired with the smp_mb() in read lock fast path (per-cpu mode)
>> + * and the one before atomic_read in read unlock path.
>> + */
>> + smp_mb();
>
> What is this barrier ordering?
>
> This is only a change in the !try case, and we didn't do anything before
> checking pcpu_read_count() - except way back in six_lock_slowpath()
> where we set SIX_LOCK_HELD_write, but that does have a barrier.
Make sure six_set_bitmask(lock, SIX_LOCK_WAITING_read << type)
happens before pcpu_read_count()
>
>> ret = !pcpu_read_count(lock);
>>
>> if (try && !ret) {
>> --
>> 2.45.2
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] bcachefs: Fix lost wake up
2024-09-01 2:50 ` Alan Huang
@ 2024-09-01 3:10 ` Kent Overstreet
2024-09-01 3:27 ` Alan Huang
0 siblings, 1 reply; 5+ messages in thread
From: Kent Overstreet @ 2024-09-01 3:10 UTC (permalink / raw)
To: Alan Huang; +Cc: linux-bcachefs
On Sun, Sep 01, 2024 at 10:50:37AM GMT, Alan Huang wrote:
> > 2024年9月1日 09:09,Kent Overstreet <kent.overstreet@linux.dev> wrote:
> >
> > On Tue, Aug 27, 2024 at 11:14:48PM GMT, Alan Huang wrote:
> >> If the reader acquires the read lock and then the writer enters the slow
> >> path, while the reader proceeds to the unlock path, the following scenario
> >> can occur without the change:
> >>
> >> writer: pcpu_read_count(lock) return 1 (so __do_six_trylock will return 0)
> >> reader: this_cpu_dec(*lock->readers)
> >> reader: smp_mb()
> >> reader: state = atomic_read(&lock->state) (there is no waiting flag set)
> >> writer: six_set_bitmask()
> >>
> >> then the writer will sleep forever.
> >>
> >> Signed-off-by: Alan Huang <mmpgouride@gmail.com>
> >> ---
> >> fs/bcachefs/six.c | 12 +++++++++---
> >> 1 file changed, 9 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/fs/bcachefs/six.c b/fs/bcachefs/six.c
> >> index 3a494c5d1247..b3583c50ef04 100644
> >> --- a/fs/bcachefs/six.c
> >> +++ b/fs/bcachefs/six.c
> >> @@ -169,11 +169,17 @@ static int __do_six_trylock(struct six_lock *lock, enum six_lock_type type,
> >> ret = -1 - SIX_LOCK_write;
> >> }
> >> } else if (type == SIX_LOCK_write && lock->readers) {
> >> - if (try) {
> >> + if (try)
> >> atomic_add(SIX_LOCK_HELD_write, &lock->state);
> >> - smp_mb__after_atomic();
> >> - }
> >>
> >> + /*
> >> + * Make sure atomic_add happens before pcpu_read_count and
> >> + * six_set_bitmask in slow path happens before pcpu_read_count.
> >> + *
> >> + * Paired with the smp_mb() in read lock fast path (per-cpu mode)
> >> + * and the one before atomic_read in read unlock path.
> >> + */
> >> + smp_mb();
> >
> > What is this barrier ordering?
> >
> > This is only a change in the !try case, and we didn't do anything before
> > checking pcpu_read_count() - except way back in six_lock_slowpath()
> > where we set SIX_LOCK_HELD_write, but that does have a barrier.
>
> Make sure six_set_bitmask(lock, SIX_LOCK_WAITING_read << type)
>
> happens before pcpu_read_count()
that's in another thread, a memory barrier orders things in the same
thread
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] bcachefs: Fix lost wake up
2024-09-01 3:10 ` Kent Overstreet
@ 2024-09-01 3:27 ` Alan Huang
0 siblings, 0 replies; 5+ messages in thread
From: Alan Huang @ 2024-09-01 3:27 UTC (permalink / raw)
To: Kent Overstreet; +Cc: linux-bcachefs
2024年9月1日 11:10,Kent Overstreet <kent.overstreet@linux.dev> wrote:
>
> On Sun, Sep 01, 2024 at 10:50:37AM GMT, Alan Huang wrote:
>>> 2024年9月1日 09:09,Kent Overstreet <kent.overstreet@linux.dev> wrote:
>>>
>>> On Tue, Aug 27, 2024 at 11:14:48PM GMT, Alan Huang wrote:
>>>> If the reader acquires the read lock and then the writer enters the slow
>>>> path, while the reader proceeds to the unlock path, the following scenario
>>>> can occur without the change:
>>>>
>>>> writer: pcpu_read_count(lock) return 1 (so __do_six_trylock will return 0)
>>>> reader: this_cpu_dec(*lock->readers)
>>>> reader: smp_mb()
>>>> reader: state = atomic_read(&lock->state) (there is no waiting flag set)
>>>> writer: six_set_bitmask()
>>>>
>>>> then the writer will sleep forever.
>>>>
>>>> Signed-off-by: Alan Huang <mmpgouride@gmail.com>
>>>> ---
>>>> fs/bcachefs/six.c | 12 +++++++++---
>>>> 1 file changed, 9 insertions(+), 3 deletions(-)
>>>>
>>>> diff --git a/fs/bcachefs/six.c b/fs/bcachefs/six.c
>>>> index 3a494c5d1247..b3583c50ef04 100644
>>>> --- a/fs/bcachefs/six.c
>>>> +++ b/fs/bcachefs/six.c
>>>> @@ -169,11 +169,17 @@ static int __do_six_trylock(struct six_lock *lock, enum six_lock_type type,
>>>> ret = -1 - SIX_LOCK_write;
>>>> }
>>>> } else if (type == SIX_LOCK_write && lock->readers) {
>>>> - if (try) {
>>>> + if (try)
>>>> atomic_add(SIX_LOCK_HELD_write, &lock->state);
>>>> - smp_mb__after_atomic();
>>>> - }
>>>>
>>>> + /*
>>>> + * Make sure atomic_add happens before pcpu_read_count and
>>>> + * six_set_bitmask in slow path happens before pcpu_read_count.
>>>> + *
>>>> + * Paired with the smp_mb() in read lock fast path (per-cpu mode)
>>>> + * and the one before atomic_read in read unlock path.
>>>> + */
>>>> + smp_mb();
>>>
>>> What is this barrier ordering?
>>>
>>> This is only a change in the !try case, and we didn't do anything before
>>> checking pcpu_read_count() - except way back in six_lock_slowpath()
>>> where we set SIX_LOCK_HELD_write, but that does have a barrier.
>>
>> Make sure six_set_bitmask(lock, SIX_LOCK_WAITING_read << type)
>>
>> happens before pcpu_read_count()
>
> that's in another thread, a memory barrier orders things in the same
> thread
six_set_bitmask(lock, SIX_LOCK_WAITING_read << type) is called before __do_six_trylock()
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2024-09-01 3:28 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-27 15:14 [PATCH] bcachefs: Fix lost wake up Alan Huang
2024-09-01 1:09 ` Kent Overstreet
2024-09-01 2:50 ` Alan Huang
2024-09-01 3:10 ` Kent Overstreet
2024-09-01 3:27 ` Alan Huang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox