aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/locking/qspinlock.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/locking/qspinlock.c')
-rw-r--r--kernel/locking/qspinlock.c21
1 files changed, 15 insertions, 6 deletions
diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c
index 38ece035039e..d880296245c5 100644
--- a/kernel/locking/qspinlock.c
+++ b/kernel/locking/qspinlock.c
@@ -379,6 +379,14 @@ queue:
379 tail = encode_tail(smp_processor_id(), idx); 379 tail = encode_tail(smp_processor_id(), idx);
380 380
381 node += idx; 381 node += idx;
382
383 /*
384 * Ensure that we increment the head node->count before initialising
385 * the actual node. If the compiler is kind enough to reorder these
386 * stores, then an IRQ could overwrite our assignments.
387 */
388 barrier();
389
382 node->locked = 0; 390 node->locked = 0;
383 node->next = NULL; 391 node->next = NULL;
384 pv_init_node(node); 392 pv_init_node(node);
@@ -408,14 +416,15 @@ queue:
408 */ 416 */
409 if (old & _Q_TAIL_MASK) { 417 if (old & _Q_TAIL_MASK) {
410 prev = decode_tail(old); 418 prev = decode_tail(old);
419
411 /* 420 /*
412 * The above xchg_tail() is also a load of @lock which 421 * We must ensure that the stores to @node are observed before
413 * generates, through decode_tail(), a pointer. The address 422 * the write to prev->next. The address dependency from
414 * dependency matches the RELEASE of xchg_tail() such that 423 * xchg_tail is not sufficient to ensure this because the read
415 * the subsequent access to @prev happens after. 424 * component of xchg_tail is unordered with respect to the
425 * initialisation of @node.
416 */ 426 */
417 427 smp_store_release(&prev->next, node);
418 WRITE_ONCE(prev->next, node);
419 428
420 pv_wait_node(node, prev); 429 pv_wait_node(node, prev);
421 arch_mcs_spin_lock_contended(&node->locked); 430 arch_mcs_spin_lock_contended(&node->locked);