|
@@ -52,11 +52,18 @@ again:
|
|
|
head = local_read(&rb->head);
|
|
head = local_read(&rb->head);
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
|
- * IRQ/NMI can happen here, which means we can miss a head update.
|
|
|
|
|
|
|
+ * IRQ/NMI can happen here and advance @rb->head, causing our
|
|
|
|
|
+ * load above to be stale.
|
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
- if (!local_dec_and_test(&rb->nest))
|
|
|
|
|
|
|
+ /*
|
|
|
|
|
+ * If this isn't the outermost nesting, we don't have to update
|
|
|
|
|
+ * @rb->user_page->data_head.
|
|
|
|
|
+ */
|
|
|
|
|
+ if (local_read(&rb->nest) > 1) {
|
|
|
|
|
+ local_dec(&rb->nest);
|
|
|
goto out;
|
|
goto out;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
|
* Since the mmap() consumer (userspace) can run on a different CPU:
|
|
* Since the mmap() consumer (userspace) can run on a different CPU:
|
|
@@ -88,9 +95,18 @@ again:
|
|
|
rb->user_page->data_head = head;
|
|
rb->user_page->data_head = head;
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
|
- * Now check if we missed an update -- rely on previous implied
|
|
|
|
|
- * compiler barriers to force a re-read.
|
|
|
|
|
|
|
+ * We must publish the head before decrementing the nest count,
|
|
|
|
|
+ * otherwise an IRQ/NMI can publish a more recent head value and our
|
|
|
|
|
+ * write will (temporarily) publish a stale value.
|
|
|
|
|
+ */
|
|
|
|
|
+ barrier();
|
|
|
|
|
+ local_set(&rb->nest, 0);
|
|
|
|
|
+
|
|
|
|
|
+ /*
|
|
|
|
|
+ * Ensure we decrement @rb->nest before we validate the @rb->head.
|
|
|
|
|
+ * Otherwise we cannot be sure we caught the 'last' nested update.
|
|
|
*/
|
|
*/
|
|
|
|
|
+ barrier();
|
|
|
if (unlikely(head != local_read(&rb->head))) {
|
|
if (unlikely(head != local_read(&rb->head))) {
|
|
|
local_inc(&rb->nest);
|
|
local_inc(&rb->nest);
|
|
|
goto again;
|
|
goto again;
|