| From foo@baz Sun May 27 17:52:22 CEST 2018 |
| From: Will Deacon <will.deacon@arm.com> |
| Date: Tue, 13 Feb 2018 13:22:57 +0000 |
| Subject: locking/qspinlock: Ensure node->count is updated before initialising node |
| |
| From: Will Deacon <will.deacon@arm.com> |
| |
| [ Upstream commit 11dc13224c975efcec96647a4768a6f1bb7a19a8 ] |
| |
| When queuing on the qspinlock, the count field for the current CPU's head |
| node is incremented. This needn't be atomic because locking in e.g. IRQ |
| context is balanced and so an IRQ will return with node->count as it |
| found it. |
| |
| However, the compiler could in theory reorder the initialisation of |
| node[idx] before the increment of the head node->count, causing an |
| IRQ to overwrite the initialised node and potentially corrupt the lock |
| state. |
| |
| Avoid the potential for this harmful compiler reordering by placing a |
| barrier() between the increment of the head node->count and the subsequent |
| node initialisation. |
| |
| Signed-off-by: Will Deacon <will.deacon@arm.com> |
| Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> |
| Cc: Linus Torvalds <torvalds@linux-foundation.org> |
| Cc: Thomas Gleixner <tglx@linutronix.de> |
| Link: http://lkml.kernel.org/r/1518528177-19169-3-git-send-email-will.deacon@arm.com |
| Signed-off-by: Ingo Molnar <mingo@kernel.org> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| kernel/locking/qspinlock.c | 8 ++++++++ |
| 1 file changed, 8 insertions(+) |
| |
| --- a/kernel/locking/qspinlock.c |
| +++ b/kernel/locking/qspinlock.c |
| @@ -423,6 +423,14 @@ queue: |
| tail = encode_tail(smp_processor_id(), idx); |
| |
| node += idx; |
| + |
| + /* |
| + * Ensure that we increment the head node->count before initialising |
| + * the actual node. If the compiler is kind enough to reorder these |
| + * stores, then an IRQ could overwrite our assignments. |
| + */ |
| + barrier(); |
| + |
| node->locked = 0; |
| node->next = NULL; |
| pv_init_node(node); |