Messages in this thread | | | Subject | Re: [PATCH] locking/qrwlock: Fix ordering in queued_write_lock_slowpath | From | Steve Capper <> | Date | Thu, 15 Apr 2021 18:18:50 +0100 |
| |
Hiya,
On 15/04/2021 17:45, Will Deacon wrote: > On Thu, Apr 15, 2021 at 04:26:46PM +0000, Ali Saidi wrote: >> >> On Thu, 15 Apr 2021 16:02:29 +0100, Will Deacon wrote: >>> On Thu, Apr 15, 2021 at 02:25:52PM +0000, Ali Saidi wrote: >>>> While this code is executed with the wait_lock held, a reader can >>>> acquire the lock without holding wait_lock. The writer side loops >>>> checking the value with the atomic_cond_read_acquire(), but only truly >>>> acquires the lock when the compare-and-exchange is completed >>>> successfully which isn’t ordered. The other atomic operations from this >>>> point are release-ordered and thus reads after the lock acquisition can >>>> be completed before the lock is truly acquired which violates the >>>> guarantees the lock should be making. >>> >>> I think it would be worth spelling this out with an example. The issue >>> appears to be a concurrent reader in interrupt context taking and releasing >>> the lock in the window where the writer has returned from the >>> atomic_cond_read_acquire() but has not yet performed the cmpxchg(). Loads >>> can be speculated during this time, but the A-B-A of the lock word >>> from _QW_WAITING to (_QW_WAITING | _QR_BIAS) and back to _QW_WAITING allows >>> the atomic_cmpxchg_relaxed() to succeed. Is that right? >> >> You're right. What we're seeing is an A-B-A problem that can allow >> atomic_cond_read_acquire() to succeed and before the cmpxchg succeeds a reader >> performs an A-B-A on the lock which allows the core to observe a read that >> follows the cmpxchg ahead of the cmpxchg succeeding. >> >> We've seen a problem in epoll where the reader does a xchg while >> holding the read lock, but the writer can see a value change out from under it. >> >> Writer | Reader 2 >> -------------------------------------------------------------------------------- >> ep_scan_ready_list() | >> |- write_lock_irq() | >> |- queued_write_lock_slowpath() | >> |- atomic_cond_read_acquire() | >> | read_lock_irqsave(&ep->lock, flags); >> | chain_epi_lockless() >> | epi->next = xchg(&ep->ovflist, epi); >> | read_unlock_irqrestore(&ep->lock, flags); >> | >> atomic_cmpxchg_relaxed() | >> READ_ONCE(ep->ovflist); > > > Please stick this in the commit message, preferably annotated a bit like > Peter's example to show the READ_ONCE() being speculated. >
I can confirm that this patch fixes a problem observed in ep_scan_ready_list(.) whereby ovflist appeared to change when the write lock was held.
So please feel free to add: Tested-by: Steve Capper <steve.capper@arm.com>
Also, I have spent a decent chunk of time looking at the above issue and went through qrwlock, so FWIW, please feel free to add: Reviewed-by: Steve Capper <steve.capper@arm.com>
Cheers, -- Steve
| |