From: Oleg Nesterov <oleg@redhat.com>
To: Peter Zijlstra <peterz@infradead.org>
Cc: "Jens Axboe" <axboe@kernel.dk>,
"Carter Li 李通洲" <carter.li@eoitek.com>,
"Pavel Begunkov" <asml.silence@gmail.com>,
io-uring <io-uring@vger.kernel.org>
Subject: Re: [PATCH] task_work_run: don't take ->pi_lock unconditionally
Date: Fri, 21 Feb 2020 15:52:56 +0100 [thread overview]
Message-ID: <20200221145256.GA16646@redhat.com> (raw)
In-Reply-To: <20200220174932.GB18400@hirez.programming.kicks-ass.net>
On 02/20, Peter Zijlstra wrote:
>
> On Thu, Feb 20, 2020 at 06:22:02PM +0100, Oleg Nesterov wrote:
> > @@ -68,10 +65,10 @@ task_work_cancel(struct task_struct *task, task_work_func_t func)
> > * we raced with task_work_run(), *pprev == NULL/exited.
> > */
> > raw_spin_lock_irqsave(&task->pi_lock, flags);
> > + for (work = READ_ONCE(*pprev); work; ) {
> > if (work->func != func)
> > pprev = &work->next;
>
> But didn't you loose the READ_ONCE() of *pprev in this branch?
Argh, yes ;)
> > @@ -97,16 +94,16 @@ void task_work_run(void)
> > * work->func() can do task_work_add(), do not set
> > * work_exited unless the list is empty.
> > */
> > + work = READ_ONCE(task->task_works);
> > do {
> > head = NULL;
> > if (!work) {
> > if (task->flags & PF_EXITING)
> > head = &work_exited;
> > else
> > break;
> > }
> > + } while (!try_cmpxchg(&task->task_works, &work, head));
> >
> > if (!work)
> > break;
>
> But given that, as you say, cancel() could have gone and stole our head,
> should we not try and install &work_exiting when PF_EXITING in that
> case?
cancel() can't do this, as long as we use cmpxchg/try_cmpxchg, not xchg().
This is what the comment before lock/unlock below tries to explain.
> That is; should we not do continue in that case, instead of break.
This is what we should do if we use xchg() like your previous version did.
Or I am totally confused. Hmm, and when I re-read my words it looks as if
I am trying to confuse you.
So lets "simplify" this code assuming that PF_EXITING is set:
work = READ_ONCE(task->task_works);
do {
head = NULL;
if (!work)
head = &work_exited;
} while (!try_cmpxchg(&task->task_works, &work, head));
if (!work)
break;
If work == NULL after try_cmpxchg() _succeeds_, then the new "head" must
be work_exited and we have nothing to do.
If it was nullified by try_cmpxchg(&work) because we raced with cancel_(),
then this try_cmpxchg() should have been failed.
Right?
> @@ -69,9 +68,12 @@ task_work_cancel(struct task_struct *tas
> */
> raw_spin_lock_irqsave(&task->pi_lock, flags);
> while ((work = READ_ONCE(*pprev))) {
> - if (work->func != func)
> + if (work->func != func) {
> pprev = &work->next;
> - else if (cmpxchg(pprev, work, work->next) == work)
> + continue;
> + }
> +
> + if (try_cmpxchg(pprev, &work, work->next))
> break;
perhaps I misread this code, but it looks a bit strange to me... it doesn't
differ from
while ((work = READ_ONCE(*pprev))) {
if (work->func != func)
pprev = &work->next;
else if (try_cmpxchg(pprev, &work, work->next))
break;
}
either way it is correct, the only problem is that we do not need (want)
another READ_ONCE() if try_cmpxchg() fails.
> void task_work_run(void)
> {
> struct task_struct *task = current;
> - struct callback_head *work, *head, *next;
> + struct callback_head *work, *next;
>
> for (;;) {
> - /*
> - * work->func() can do task_work_add(), do not set
> - * work_exited unless the list is empty.
> - */
> - do {
> - head = NULL;
> - work = READ_ONCE(task->task_works);
> - if (!work) {
> - if (task->flags & PF_EXITING)
> - head = &work_exited;
> - else
> - break;
> - }
> - } while (cmpxchg(&task->task_works, work, head) != work);
> + work = READ_ONCE(task->task_works);
> + if (!work) {
> + if (!(task->flags & PF_EXITING))
> + return;
> +
> + /*
> + * work->func() can do task_work_add(), do not set
> + * work_exited unless the list is empty.
> + */
> + if (try_cmpxchg(&task->task_works, &work, &work_exited))
> + return;
> + }
> +
> + work = xchg(&task->task_works, NULL);
> + if (!work)
> + continue;
looks correct...
Oleg.
next prev parent reply other threads:[~2020-02-21 14:53 UTC|newest]
Thread overview: 59+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-02-12 16:31 [ISSUE] The time cost of IOSQE_IO_LINK Carter Li 李通洲
2020-02-12 17:11 ` Jens Axboe
2020-02-12 17:22 ` Jens Axboe
2020-02-12 17:29 ` Jens Axboe
2020-02-13 0:33 ` Carter Li 李通洲
2020-02-13 15:08 ` Pavel Begunkov
2020-02-13 15:14 ` Jens Axboe
2020-02-13 15:51 ` Carter Li 李通洲
2020-02-14 1:25 ` Carter Li 李通洲
2020-02-14 2:45 ` Jens Axboe
2020-02-14 5:03 ` Jens Axboe
2020-02-14 15:32 ` Peter Zijlstra
2020-02-14 15:47 ` Jens Axboe
2020-02-14 16:18 ` Jens Axboe
2020-02-14 17:52 ` Jens Axboe
2020-02-14 20:44 ` Jens Axboe
2020-02-15 0:16 ` Carter Li 李通洲
2020-02-15 1:10 ` Jens Axboe
2020-02-15 1:25 ` Carter Li 李通洲
2020-02-15 1:27 ` Jens Axboe
2020-02-15 6:01 ` Jens Axboe
2020-02-15 6:32 ` Carter Li 李通洲
2020-02-15 15:11 ` Jens Axboe
2020-02-16 19:06 ` Pavel Begunkov
2020-02-16 22:23 ` Jens Axboe
2020-02-17 10:30 ` Pavel Begunkov
2020-02-17 19:30 ` Jens Axboe
2020-02-16 23:06 ` Jens Axboe
2020-02-16 23:07 ` Jens Axboe
2020-02-17 12:09 ` Peter Zijlstra
2020-02-17 16:12 ` Jens Axboe
2020-02-17 17:16 ` Jens Axboe
2020-02-17 17:46 ` Peter Zijlstra
2020-02-17 18:16 ` Jens Axboe
2020-02-18 13:13 ` Peter Zijlstra
2020-02-18 14:27 ` [PATCH] asm-generic/atomic: Add try_cmpxchg() fallbacks Peter Zijlstra
2020-02-18 14:40 ` Peter Zijlstra
2020-02-20 10:30 ` Will Deacon
2020-02-20 10:37 ` Peter Zijlstra
2020-02-20 10:39 ` Will Deacon
2020-02-18 14:56 ` [ISSUE] The time cost of IOSQE_IO_LINK Oleg Nesterov
2020-02-18 15:07 ` Oleg Nesterov
2020-02-18 15:38 ` Peter Zijlstra
2020-02-18 16:33 ` Jens Axboe
2020-02-18 15:07 ` Peter Zijlstra
2020-02-18 15:50 ` [PATCH] task_work_run: don't take ->pi_lock unconditionally Oleg Nesterov
2020-02-20 16:39 ` Peter Zijlstra
2020-02-20 17:22 ` Oleg Nesterov
2020-02-20 17:49 ` Peter Zijlstra
2020-02-21 14:52 ` Oleg Nesterov [this message]
2020-02-24 18:47 ` Jens Axboe
2020-02-28 19:17 ` Jens Axboe
2020-02-28 19:25 ` Peter Zijlstra
2020-02-28 19:28 ` Jens Axboe
2020-02-28 20:06 ` Peter Zijlstra
2020-02-28 20:15 ` Jens Axboe
2020-02-18 16:46 ` [ISSUE] The time cost of IOSQE_IO_LINK Jens Axboe
2020-02-18 16:52 ` Jens Axboe
2020-02-18 13:13 ` Peter Zijlstra
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=20200221145256.GA16646@redhat.com \
--to=oleg@redhat.com \
--cc=asml.silence@gmail.com \
--cc=axboe@kernel.dk \
--cc=carter.li@eoitek.com \
--cc=io-uring@vger.kernel.org \
--cc=peterz@infradead.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.