linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: John Ogness <john.ogness@linutronix.de>
To: Petr Mladek <pmladek@suse.com>
Cc: Andrea Parri <parri.andrea@gmail.com>,
	Sergey Senozhatsky <sergey.senozhatsky@gmail.com>,
	Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>,
	Steven Rostedt <rostedt@goodmis.org>,
	Brendan Higgins <brendanhiggins@google.com>,
	Peter Zijlstra <peterz@infradead.org>,
	Thomas Gleixner <tglx@linutronix.de>,
	Linus Torvalds <torvalds@linux-foundation.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	linux-kernel@vger.kernel.org
Subject: Re: numlist_push() barriers Re: [RFC PATCH v4 1/9] printk-rb: add a new printk ringbuffer implementation
Date: Tue, 27 Aug 2019 16:28:55 +0200	[thread overview]
Message-ID: <87mufuvg0o.fsf@linutronix.de> (raw)
In-Reply-To: 20190827074057.2qybpmvfueub3ztl@pathway.suse.cz

On 2019-08-27, Petr Mladek <pmladek@suse.com> wrote:
>> On 2019-08-23, Petr Mladek <pmladek@suse.com> wrote:
>>>> --- /dev/null
>>>> +++ b/kernel/printk/numlist.c
>>>> +void numlist_push(struct numlist *nl, struct nl_node *n, unsigned long id)
>>>> +{
> [...]
>>>> +
>>>> +	/* bB: #1 */
>>>> +	head_id = atomic_long_read(&nl->head_id);
>>>> +
>>>> +	for (;;) {
>>>> +		/* bC: */
>>>> +		while (!numlist_read(nl, head_id, &seq, NULL)) {
>>>> +			/*
>>>> +			 * @head_id is invalid. Try again with an
>>>> +			 * updated value.
>>>> +			 */
>>>> +
>>>> +			cpu_relax();
>>>
>>> I have got very confused by this. cpu_relax() suggests that this
>>> cycle is busy waiting until a particular node becomes valid.
>>> My first though was that it must cause deadlock in NMI when
>>> the interrupted code is supposed to make the node valid.
>>>
>>> But it is the other way. The head is always valid when it is
>>> added to the list. It might become invalid when another CPU
>>> moves the head and the old one gets reused.
>>>
>>> Anyway, I do not see any reason for cpu_relax() here.
>> 
>> You are correct. The cpu_relax() should not be there. But there is
>> still an issue that this could spin hard if the head was recycled and
>> this CPU does not yet see the new head value.
>
> I do not understand this. The head could get reused only after
> head_id was replaced with the following valid node.
> The next cycle is done with a new id that should be valid.
>
> Of course, the new ID might get reused as well. But then we just
> repeat the cycle. We have to be able to find a valid head after
> few cycles. The last valid ID could not get reused because nodes
> can be removed only if was not the last valid node.

Sorry, I was not very precise with my language. I will try again...

nl->head_id is read using a relaxed read. A second CPU may have added
new nodes and removed/recycled the node with the ID that the first CPU
read as the head.

As a result, the first CPU's numlist_read() will (correctly) fail. If
numlist_read() failed in the first node() callback within numlist_read()
(i.e. it sees that the node already has a new ID), there is no guarantee
that rereading the head ID will provide a new ID. At some point the
memory system would make the new head ID visible, but there could be
some heavy spinning until that happens.

Here is a litmus test showing the problem (using comments and verbose
variable names):

C numlist_push_loop

{
	int node1 = 1;
	int node2 = 2;
	int *numlist_head = &node1;
}

P0(int **numlist_head)
{
	int *head;
	int id;

	// read head ID
	head = READ_ONCE(*numlist_head);

	// read head node ID
	id = READ_ONCE(*head);

	// re-read head ID when node ID is unexpected
	head = READ_ONCE(*numlist_head);
}

P1(int **numlist_head, int *node1, int *node2)
{
	int *r0;

	// push node2
	r0 = cmpxchg_release(numlist_head, node1, node2);

	// pop node1, reassigning a new ID
	smp_store_release(node1, 3);
}

exists (0:head=node1 /\ 0:id=3)

$ herd7 -conf linux-kernel.cfg numlist_push_loop.litmus 
Test numlist_push_loop Allowed
States 5
0:head=node1; 0:id=1;
0:head=node1; 0:id=3;
0:head=node2; 0:id=1;
0:head=node2; 0:id=2;
0:head=node2; 0:id=3;
Ok
Witnesses
Positive: 1 Negative: 4
Condition exists (0:head=node1 /\ 0:id=3)
Observation numlist_push_loop Sometimes 1 4
Time numlist_push_loop 0.01
Hash=27b10efb171ab4cf390bd612a9e79bf0

The results show that P0 sees the head is node1 but also sees that
node1's ID has changed. (And if node1's ID changed, it means P1 had
previously replaced the head.) If P0 ran in a while-loop, at some point
it _would_ see that node2 is now the head. But that is wasteful spinning
and may possibly have negative influence on the memory system.

>> To handle that, and in preparation for my next version, I'm now using
>> a read_acquire() to load the ID in the node() callback (matching the
>> set_release() in assign_desc()). This ensures that if numlist_read()
>> fails, the new head will be visible.
>
> I do not understand this either. The above paragraph seems to
> describe a race. I do not see how it could cause an infinite loop.

It isn't an infinite loop. It is burning some/many CPU cycles.

By changing P0's ID read to:

    id = smp_load_acquire(head);

the results change to:

$ herd7 -conf linux-kernel.cfg numlist_push_loop.litmus 
Test numlist_push_loop Allowed
States 4
0:head=node1; 0:id=1;
0:head=node2; 0:id=1;
0:head=node2; 0:id=2;
0:head=node2; 0:id=3;
No
Witnesses
Positive: 0 Negative: 4
Condition exists (0:head=node1 /\ 0:id=3)
Observation numlist_push_loop Never 0 4
Time numlist_push_loop 0.01
Hash=3eb63ea3bec59f8941f61faddb5499da

Meaning that if a new ID is seen, a new head ID is also visible.

Loading the ID is what the node() callback does, and the ACQUIRE pairs
with the set_release() in assign_desc(). Both in ringbuffer.c.

John Ogness

  reply	other threads:[~2019-08-27 14:29 UTC|newest]

Thread overview: 131+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-08-07 22:26 [RFC PATCH v4 0/9] printk: new ringbuffer implementation John Ogness
2019-08-07 22:26 ` [RFC PATCH v4 1/9] printk-rb: add a new printk " John Ogness
2019-08-20  8:15   ` numlist_pop(): " Petr Mladek
2019-08-21  5:41     ` John Ogness
2019-09-04 12:19     ` Peter Zijlstra
2019-08-20  8:22   ` assign_desc() barriers: " Petr Mladek
2019-08-20 14:14     ` Petr Mladek
2019-08-21  5:52       ` John Ogness
2019-08-22 11:53         ` Petr Mladek
2019-08-25  2:06           ` John Ogness
2019-08-26  8:21             ` John Ogness
2019-08-20  8:55   ` comments style: " Petr Mladek
2019-08-20  9:27     ` Sergey Senozhatsky
2019-08-21  5:46       ` John Ogness
2019-08-22 13:50         ` Petr Mladek
2019-08-22 17:38           ` Andrea Parri
2019-08-23 10:47             ` Petr Mladek
2019-08-23 14:27               ` Andrea Parri
2019-08-23  9:49           ` Sergey Senozhatsky
2019-08-23  5:54         ` Sergey Senozhatsky
2019-08-23 10:29           ` Petr Mladek
2019-08-21  5:42     ` John Ogness
2019-08-22 12:44       ` Petr Mladek
2019-08-20 13:50   ` dataring_push() barriers " Petr Mladek
2019-08-25  2:42     ` John Ogness
2019-08-27 14:36       ` Petr Mladek
2019-08-28 13:43         ` John Ogness
2019-08-20 15:12   ` datablock reuse races " Petr Mladek
2019-08-23  9:21   ` numlist_push() barriers " Petr Mladek
2019-08-26  8:34     ` Andrea Parri
2019-08-26  8:43       ` Andrea Parri
2019-08-26 14:10       ` Petr Mladek
2019-08-26 16:01         ` Andrea Parri
2019-08-26 22:36     ` John Ogness
2019-08-27  7:40       ` Petr Mladek
2019-08-27 14:28         ` John Ogness [this message]
2019-08-27 15:07           ` Petr Mladek
2019-08-28 10:24             ` John Ogness
2019-08-23 17:18   ` numlist API " Petr Mladek
2019-08-26 23:57     ` John Ogness
2019-08-27 13:03       ` Petr Mladek
2019-08-28  7:13         ` John Ogness
2019-08-28  8:58           ` Petr Mladek
2019-08-28 14:03             ` John Ogness
2019-08-29 11:28               ` Petr Mladek
2019-09-03  7:58         ` Sergey Senozhatsky
2019-08-30 14:48   ` dataring " Petr Mladek
2019-08-07 22:26 ` [RFC PATCH v4 2/9] printk-rb: add test module John Ogness
2019-08-07 22:26 ` [RFC PATCH v4 3/9] printk-rb: fix missing includes/exports John Ogness
2019-08-07 22:26 ` [RFC PATCH v4 4/9] printk-rb: initialize new descriptors as invalid John Ogness
2019-08-20  9:23   ` Petr Mladek
2019-08-20 10:16     ` Sergey Senozhatsky
2019-08-21  5:56     ` John Ogness
2019-08-07 22:26 ` [RFC PATCH v4 5/9] printk-rb: remove extra data buffer size allocation John Ogness
2019-08-07 22:26 ` [RFC PATCH v4 6/9] printk-rb: adjust test module ringbuffer sizes John Ogness
2019-08-19 21:29   ` [PATCH] printk-rb: fix test module macro usage John Ogness
2019-08-07 22:26 ` [RFC PATCH v4 7/9] printk-rb: increase size of seq and size variables John Ogness
2019-08-07 22:26 ` [RFC PATCH v4 8/9] printk-rb: new functionality to support printk John Ogness
2019-08-20  9:59   ` Sergey Senozhatsky
2019-08-21  5:47     ` John Ogness
2019-08-07 22:26 ` [RFC PATCH v4 9/9] printk: use a new ringbuffer implementation John Ogness
2019-08-08 19:07   ` Linus Torvalds
2019-08-08 22:55     ` John Ogness
2019-08-08 23:33       ` Linus Torvalds
2019-08-08 23:45         ` Steven Rostedt
2019-08-09  0:21           ` Linus Torvalds
2019-08-09  0:48             ` Steven Rostedt
2019-08-09  1:15               ` Linus Torvalds
2019-08-09 11:15                 ` Thomas Gleixner
2019-08-09 16:00                   ` Linus Torvalds
2019-08-09 20:07                     ` Thomas Gleixner
2019-08-09 20:20                       ` Linus Torvalds
2019-08-09  6:14     ` Peter Zijlstra
2019-08-09  7:08       ` John Ogness
2019-08-09 15:57       ` Linus Torvalds
2019-08-10  5:53         ` Thomas Gleixner
2019-09-10  3:19           ` Sergey Senozhatsky
2019-08-12  9:54       ` Geert Uytterhoeven
2019-08-16  5:46   ` Dave Young
2019-08-16  5:54     ` Dave Young
2019-08-16  9:40     ` John Ogness
2019-09-04 12:35 ` [RFC PATCH v4 0/9] printk: " Peter Zijlstra
2019-09-05 13:05   ` Petr Mladek
2019-09-05 14:31     ` Peter Zijlstra
2019-09-05 15:38       ` Thomas Gleixner
2019-09-05 16:11         ` Steven Rostedt
2019-09-05 21:10           ` John Ogness
2019-09-06  9:39           ` Petr Mladek
2019-09-09 14:11           ` printk meeting at LPC Thomas Gleixner
2019-09-13 13:26             ` John Ogness
2019-09-13 14:48               ` Daniel Vetter
2019-09-15 13:47                 ` John Ogness
2019-09-16  8:44                   ` Daniel Vetter
2019-09-16  4:30               ` Tetsuo Handa
2019-09-16 10:46                 ` Petr Mladek
2019-09-16 13:43                   ` Steven Rostedt
2019-09-16 14:28                     ` John Ogness
2019-09-17  8:11                       ` Petr Mladek
2019-09-17  7:52                     ` Petr Mladek
2019-09-17 13:02                       ` Steven Rostedt
2019-09-17 13:12                         ` Greg Kroah-Hartman
2019-09-17 13:37                           ` Steven Rostedt
2019-09-17 14:08                             ` Tetsuo Handa
2019-09-17  7:51                   ` Sergey Senozhatsky
2019-09-18  1:25               ` Sergey Senozhatsky
2019-09-18  2:08                 ` Steven Rostedt
2019-09-18  2:36                   ` Sergey Senozhatsky
2019-09-18  5:19                     ` Sergey Senozhatsky
2019-09-18  7:42                       ` John Ogness
2019-09-18  8:10                         ` Sergey Senozhatsky
2019-09-18  9:05                           ` John Ogness
2019-09-18  9:11                             ` Sergey Senozhatsky
2019-09-18 16:41                             ` Petr Mladek
2019-09-18 16:48                               ` Steven Rostedt
2019-09-24 14:24                                 ` Petr Mladek
2019-09-19  8:06                         ` Daniel Vetter
2019-09-18  7:33                     ` John Ogness
2019-09-18  8:08                       ` Sergey Senozhatsky
2019-10-04 14:48               ` Tony Asleson
2019-10-07 12:01                 ` Petr Mladek
2019-09-06  9:06       ` [RFC PATCH v4 0/9] printk: new ringbuffer implementation Peter Zijlstra
2019-09-06 10:09         ` Sergey Senozhatsky
2019-09-06 10:49           ` Peter Zijlstra
2019-09-06 13:44             ` Sergey Senozhatsky
2019-09-06 12:42         ` Petr Mladek
2019-09-06 14:01           ` Peter Zijlstra
2019-09-06 14:22             ` Peter Zijlstra
2019-09-06 19:53             ` Sergey Senozhatsky
2019-09-06 22:47             ` John Ogness
2019-09-08 22:18             ` Peter Zijlstra
2019-09-10  3:22             ` Sergey Senozhatsky

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87mufuvg0o.fsf@linutronix.de \
    --to=john.ogness@linutronix.de \
    --cc=brendanhiggins@google.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=parri.andrea@gmail.com \
    --cc=peterz@infradead.org \
    --cc=pmladek@suse.com \
    --cc=rostedt@goodmis.org \
    --cc=sergey.senozhatsky.work@gmail.com \
    --cc=sergey.senozhatsky@gmail.com \
    --cc=tglx@linutronix.de \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).