* [PATCH 1/2] task_work: make FIFO task_work list @ 2013-03-14 7:57 liguang 2013-03-14 7:57 ` [PATCH 2/2] task_work: check callback if it's NULL liguang 2013-03-14 14:40 ` [PATCH 1/2] task_work: make FIFO task_work list Oleg Nesterov 0 siblings, 2 replies; 11+ messages in thread From: liguang @ 2013-03-14 7:57 UTC (permalink / raw) To: viro, oleg, edumazet, linux-kernel; +Cc: liguang Signed-off-by: liguang <lig.fnst@cn.fujitsu.com> --- kernel/task_work.c | 15 +++------------ 1 files changed, 3 insertions(+), 12 deletions(-) diff --git a/kernel/task_work.c b/kernel/task_work.c index 65bd3c9..0bf4258 100644 --- a/kernel/task_work.c +++ b/kernel/task_work.c @@ -13,11 +13,12 @@ task_work_add(struct task_struct *task, struct callback_head *work, bool notify) head = ACCESS_ONCE(task->task_works); if (unlikely(head == &work_exited)) return -ESRCH; - work->next = head; - } while (cmpxchg(&task->task_works, head, work) != head); + head = head->next; + } while (cmpxchg(&head, NULL, work) == head); if (notify) set_notify_resume(task); + return 0; } @@ -72,16 +73,6 @@ void task_work_run(void) raw_spin_unlock_wait(&task->pi_lock); smp_mb(); - /* Reverse the list to run the works in fifo order */ - head = NULL; - do { - next = work->next; - work->next = head; - head = work; - work = next; - } while (work); - - work = head; do { next = work->next; work->func(work); -- 1.7.2.5 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/2] task_work: check callback if it's NULL 2013-03-14 7:57 [PATCH 1/2] task_work: make FIFO task_work list liguang @ 2013-03-14 7:57 ` liguang 2013-03-14 14:43 ` Oleg Nesterov 2013-03-14 14:40 ` [PATCH 1/2] task_work: make FIFO task_work list Oleg Nesterov 1 sibling, 1 reply; 11+ messages in thread From: liguang @ 2013-03-14 7:57 UTC (permalink / raw) To: viro, oleg, edumazet, linux-kernel; +Cc: liguang Signed-off-by: liguang <lig.fnst@cn.fujitsu.com> --- kernel/task_work.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/kernel/task_work.c b/kernel/task_work.c index 0bf4258..f458b08 100644 --- a/kernel/task_work.c +++ b/kernel/task_work.c @@ -75,7 +75,8 @@ void task_work_run(void) do { next = work->next; - work->func(work); + if (unlikely(work->func)) + work->func(work); work = next; cond_resched(); } while (work); -- 1.7.2.5 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] task_work: check callback if it's NULL 2013-03-14 7:57 ` [PATCH 2/2] task_work: check callback if it's NULL liguang @ 2013-03-14 14:43 ` Oleg Nesterov 2013-03-15 0:20 ` li guang 0 siblings, 1 reply; 11+ messages in thread From: Oleg Nesterov @ 2013-03-14 14:43 UTC (permalink / raw) To: liguang; +Cc: viro, edumazet, linux-kernel On 03/14, liguang wrote: > > Signed-off-by: liguang <lig.fnst@cn.fujitsu.com> > --- > kernel/task_work.c | 3 ++- > 1 files changed, 2 insertions(+), 1 deletions(-) > > diff --git a/kernel/task_work.c b/kernel/task_work.c > index 0bf4258..f458b08 100644 > --- a/kernel/task_work.c > +++ b/kernel/task_work.c > @@ -75,7 +75,8 @@ void task_work_run(void) > > do { > next = work->next; > - work->func(work); > + if (unlikely(work->func)) > + work->func(work); Why? Oleg. ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] task_work: check callback if it's NULL 2013-03-14 14:43 ` Oleg Nesterov @ 2013-03-15 0:20 ` li guang 2013-03-15 1:01 ` Li Zefan 0 siblings, 1 reply; 11+ messages in thread From: li guang @ 2013-03-15 0:20 UTC (permalink / raw) To: Oleg Nesterov; +Cc: viro, edumazet, linux-kernel 在 2013-03-14四的 15:43 +0100,Oleg Nesterov写道: > On 03/14, liguang wrote: > > > > Signed-off-by: liguang <lig.fnst@cn.fujitsu.com> > > --- > > kernel/task_work.c | 3 ++- > > 1 files changed, 2 insertions(+), 1 deletions(-) > > > > diff --git a/kernel/task_work.c b/kernel/task_work.c > > index 0bf4258..f458b08 100644 > > --- a/kernel/task_work.c > > +++ b/kernel/task_work.c > > @@ -75,7 +75,8 @@ void task_work_run(void) > > > > do { > > next = work->next; > > - work->func(work); > > + if (unlikely(work->func)) > > + work->func(work); > > Why? > > Oleg. > can we believe a callback always be call-able? can it happened to be 0? e.g. wrong initialized. of course, we can complain the caller, be why don't we easily make it more safer? ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] task_work: check callback if it's NULL 2013-03-15 0:20 ` li guang @ 2013-03-15 1:01 ` Li Zefan 2013-03-15 1:26 ` li guang 0 siblings, 1 reply; 11+ messages in thread From: Li Zefan @ 2013-03-15 1:01 UTC (permalink / raw) To: li guang; +Cc: Oleg Nesterov, viro, edumazet, linux-kernel On 2013/3/15 8:20, li guang wrote: > 在 2013-03-14四的 15:43 +0100,Oleg Nesterov写道: >> On 03/14, liguang wrote: >>> >>> Signed-off-by: liguang <lig.fnst@cn.fujitsu.com> >>> --- >>> kernel/task_work.c | 3 ++- >>> 1 files changed, 2 insertions(+), 1 deletions(-) >>> >>> diff --git a/kernel/task_work.c b/kernel/task_work.c >>> index 0bf4258..f458b08 100644 >>> --- a/kernel/task_work.c >>> +++ b/kernel/task_work.c >>> @@ -75,7 +75,8 @@ void task_work_run(void) >>> >>> do { >>> next = work->next; >>> - work->func(work); >>> + if (unlikely(work->func)) >>> + work->func(work); >> >> Why? >> >> Oleg. >> > > can we believe a callback always be call-able? > can it happened to be 0? e.g. wrong initialized. > of course, we can complain the caller, be why don't > we easily make it more safer? > Because you're not making things safer, but your're trying to cover up bugs... ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] task_work: check callback if it's NULL 2013-03-15 1:01 ` Li Zefan @ 2013-03-15 1:26 ` li guang 2013-03-15 1:43 ` Li Zefan 0 siblings, 1 reply; 11+ messages in thread From: li guang @ 2013-03-15 1:26 UTC (permalink / raw) To: Li Zefan; +Cc: Oleg Nesterov, viro, edumazet, linux-kernel 在 2013-03-15五的 09:01 +0800,Li Zefan写道: > On 2013/3/15 8:20, li guang wrote: > > 在 2013-03-14四的 15:43 +0100,Oleg Nesterov写道: > >> On 03/14, liguang wrote: > >>> > >>> Signed-off-by: liguang <lig.fnst@cn.fujitsu.com> > >>> --- > >>> kernel/task_work.c | 3 ++- > >>> 1 files changed, 2 insertions(+), 1 deletions(-) > >>> > >>> diff --git a/kernel/task_work.c b/kernel/task_work.c > >>> index 0bf4258..f458b08 100644 > >>> --- a/kernel/task_work.c > >>> +++ b/kernel/task_work.c > >>> @@ -75,7 +75,8 @@ void task_work_run(void) > >>> > >>> do { > >>> next = work->next; > >>> - work->func(work); > >>> + if (unlikely(work->func)) > >>> + work->func(work); > >> > >> Why? > >> > >> Oleg. > >> > > > > can we believe a callback always be call-able? > > can it happened to be 0? e.g. wrong initialized. > > of course, we can complain the caller, be why don't > > we easily make it more safer? > > > > Because you're not making things safer, but your're trying > to cover up bugs... > Oh, that's a little harsh to a normal programmer like me :-) for it seems you are asking me to be coding without any bug. are you? or it is the theory of kernel coding? ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] task_work: check callback if it's NULL 2013-03-15 1:26 ` li guang @ 2013-03-15 1:43 ` Li Zefan 2013-03-15 2:29 ` li guang 0 siblings, 1 reply; 11+ messages in thread From: Li Zefan @ 2013-03-15 1:43 UTC (permalink / raw) To: li guang; +Cc: Oleg Nesterov, viro, edumazet, linux-kernel On 2013/3/15 9:26, li guang wrote: > 在 2013-03-15五的 09:01 +0800,Li Zefan写道: >> On 2013/3/15 8:20, li guang wrote: >>> 在 2013-03-14四的 15:43 +0100,Oleg Nesterov写道: >>>> On 03/14, liguang wrote: >>>>> >>>>> Signed-off-by: liguang <lig.fnst@cn.fujitsu.com> >>>>> --- >>>>> kernel/task_work.c | 3 ++- >>>>> 1 files changed, 2 insertions(+), 1 deletions(-) >>>>> >>>>> diff --git a/kernel/task_work.c b/kernel/task_work.c >>>>> index 0bf4258..f458b08 100644 >>>>> --- a/kernel/task_work.c >>>>> +++ b/kernel/task_work.c >>>>> @@ -75,7 +75,8 @@ void task_work_run(void) >>>>> >>>>> do { >>>>> next = work->next; >>>>> - work->func(work); >>>>> + if (unlikely(work->func)) >>>>> + work->func(work); >>>> >>>> Why? >>>> >>>> Oleg. >>>> >>> >>> can we believe a callback always be call-able? >>> can it happened to be 0? e.g. wrong initialized. >>> of course, we can complain the caller, be why don't >>> we easily make it more safer? >>> >> >> Because you're not making things safer, but your're trying >> to cover up bugs... >> > > Oh, that's a little harsh to a normal programmer like me :-) > for it seems you are asking me to be coding without any bug. > are you? or it is the theory of kernel coding? > And you make a bug, and you want the kernel to cover up the bug instead of crash on a null pointer deref so you'll know you've made a bug? Why we check if a callback is NULL before calling it? Because it's allowed to be. Why we don't check if a callback is NULL? Because it's not supposed to be. ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] task_work: check callback if it's NULL 2013-03-15 1:43 ` Li Zefan @ 2013-03-15 2:29 ` li guang 0 siblings, 0 replies; 11+ messages in thread From: li guang @ 2013-03-15 2:29 UTC (permalink / raw) To: Li Zefan; +Cc: Oleg Nesterov, viro, edumazet, linux-kernel 在 2013-03-15五的 09:43 +0800,Li Zefan写道: > On 2013/3/15 9:26, li guang wrote: > > 在 2013-03-15五的 09:01 +0800,Li Zefan写道: > >> On 2013/3/15 8:20, li guang wrote: > >>> 在 2013-03-14四的 15:43 +0100,Oleg Nesterov写道: > >>>> On 03/14, liguang wrote: > >>>>> > >>>>> Signed-off-by: liguang <lig.fnst@cn.fujitsu.com> > >>>>> --- > >>>>> kernel/task_work.c | 3 ++- > >>>>> 1 files changed, 2 insertions(+), 1 deletions(-) > >>>>> > >>>>> diff --git a/kernel/task_work.c b/kernel/task_work.c > >>>>> index 0bf4258..f458b08 100644 > >>>>> --- a/kernel/task_work.c > >>>>> +++ b/kernel/task_work.c > >>>>> @@ -75,7 +75,8 @@ void task_work_run(void) > >>>>> > >>>>> do { > >>>>> next = work->next; > >>>>> - work->func(work); > >>>>> + if (unlikely(work->func)) > >>>>> + work->func(work); > >>>> > >>>> Why? > >>>> > >>>> Oleg. > >>>> > >>> > >>> can we believe a callback always be call-able? > >>> can it happened to be 0? e.g. wrong initialized. > >>> of course, we can complain the caller, be why don't > >>> we easily make it more safer? > >>> > >> > >> Because you're not making things safer, but your're trying > >> to cover up bugs... > >> > > > > Oh, that's a little harsh to a normal programmer like me :-) > > for it seems you are asking me to be coding without any bug. > > are you? or it is the theory of kernel coding? > > > > And you make a bug, and you want the kernel to cover up the bug > instead of crash on a null pointer deref so you'll know you've > made a bug? > > Why we check if a callback is NULL before calling it? Because > it's allowed to be. Why we don't check if a callback is NULL? > Because it's not supposed to be. > OK, Thanks for your reminder. ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] task_work: make FIFO task_work list 2013-03-14 7:57 [PATCH 1/2] task_work: make FIFO task_work list liguang 2013-03-14 7:57 ` [PATCH 2/2] task_work: check callback if it's NULL liguang @ 2013-03-14 14:40 ` Oleg Nesterov 2013-03-15 0:16 ` li guang 1 sibling, 1 reply; 11+ messages in thread From: Oleg Nesterov @ 2013-03-14 14:40 UTC (permalink / raw) To: liguang; +Cc: viro, edumazet, linux-kernel On 03/14, liguang wrote: > > Signed-off-by: liguang <lig.fnst@cn.fujitsu.com> Changelog please... > --- > kernel/task_work.c | 15 +++------------ > 1 files changed, 3 insertions(+), 12 deletions(-) > > diff --git a/kernel/task_work.c b/kernel/task_work.c > index 65bd3c9..0bf4258 100644 > --- a/kernel/task_work.c > +++ b/kernel/task_work.c > @@ -13,11 +13,12 @@ task_work_add(struct task_struct *task, struct callback_head *work, bool notify) > head = ACCESS_ONCE(task->task_works); > if (unlikely(head == &work_exited)) > return -ESRCH; > - work->next = head; > - } while (cmpxchg(&task->task_works, head, work) != head); > + head = head->next; > + } while (cmpxchg(&head, NULL, work) == head); I simply can't understand how this can work... The patch assumes that head->next == NULL after head = head->next, why? And then compares the result with head and succeeds if not equal. Could you please explain how it was supposed to work? If nothing else, Suppose we have task->task_works -> W1 -> W2 -> W3. How this code can add W4 after W3? And cmpxchg(&head) should be cmpxchg(&head->next).... Anyway, whatever I missed this is racy. head = head->next; nothing protects "head" after this. Say, it can be task_work_cancel'ed and freed. So, cmpxchg(&head, ...) can modify the freed and reused memory. Oleg. ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] task_work: make FIFO task_work list 2013-03-14 14:40 ` [PATCH 1/2] task_work: make FIFO task_work list Oleg Nesterov @ 2013-03-15 0:16 ` li guang 2013-03-15 14:34 ` Oleg Nesterov 0 siblings, 1 reply; 11+ messages in thread From: li guang @ 2013-03-15 0:16 UTC (permalink / raw) To: Oleg Nesterov; +Cc: viro, edumazet, linux-kernel 在 2013-03-14四的 15:40 +0100,Oleg Nesterov写道: > On 03/14, liguang wrote: > > > > Signed-off-by: liguang <lig.fnst@cn.fujitsu.com> > > Changelog please... > OK. > > --- > > kernel/task_work.c | 15 +++------------ > > 1 files changed, 3 insertions(+), 12 deletions(-) > > > > diff --git a/kernel/task_work.c b/kernel/task_work.c > > index 65bd3c9..0bf4258 100644 > > --- a/kernel/task_work.c > > +++ b/kernel/task_work.c > > @@ -13,11 +13,12 @@ task_work_add(struct task_struct *task, struct callback_head *work, bool notify) > > head = ACCESS_ONCE(task->task_works); > > if (unlikely(head == &work_exited)) > > return -ESRCH; > > - work->next = head; > > - } while (cmpxchg(&task->task_works, head, work) != head); > > + head = head->next; > > + } while (cmpxchg(&head, NULL, work) == head); > > I simply can't understand how this can work... The patch assumes > that head->next == NULL after head = head->next, why? And then > compares the result with head and succeeds if not equal. > then ->next filed was not initialized, so I think it will be 0'ed by compiler, is it unreliable?. > Could you please explain how it was supposed to work? If nothing > else, Suppose we have task->task_works -> W1 -> W2 -> W3. How this > code can add W4 after W3? > 1. head = task_works 2. head = head->next 3. if head == NULL /* it's next node of list tail (w3->next) */ head = work else goto 1 > And cmpxchg(&head) should be cmpxchg(&head->next).... > > > > Anyway, whatever I missed this is racy. > > head = head->next; > > nothing protects "head" after this. Say, it can be task_work_cancel'ed > and freed. So, > > cmpxchg(&head, ...) > > can modify the freed and reused memory. > > Oleg. > Thanks Oleg, Hmm, at first, I think even it was changed, it can't happened to be NULL, but ... maybe it need more deliberation. The motivation it make the list FIFO at task_work_add, so you don't need to reverse it at task_work_run, and it's a time-saver if the list doesn't have too many nodes I think. ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] task_work: make FIFO task_work list 2013-03-15 0:16 ` li guang @ 2013-03-15 14:34 ` Oleg Nesterov 0 siblings, 0 replies; 11+ messages in thread From: Oleg Nesterov @ 2013-03-15 14:34 UTC (permalink / raw) To: li guang; +Cc: viro, edumazet, linux-kernel On 03/15, li guang wrote: > > 在 2013-03-14四的 15:40 +0100,Oleg Nesterov写道: > > > --- a/kernel/task_work.c > > > +++ b/kernel/task_work.c > > > @@ -13,11 +13,12 @@ task_work_add(struct task_struct *task, struct callback_head *work, bool notify) > > > head = ACCESS_ONCE(task->task_works); > > > if (unlikely(head == &work_exited)) > > > return -ESRCH; > > > - work->next = head; > > > - } while (cmpxchg(&task->task_works, head, work) != head); > > > + head = head->next; > > > + } while (cmpxchg(&head, NULL, work) == head); > > > > I simply can't understand how this can work... The patch assumes > > that head->next == NULL after head = head->next, why? And then > > compares the result with head and succeeds if not equal. > > > > then ->next filed was not initialized, so I think it will > be 0'ed by compiler, is it unreliable?. work->next is not necessarily initialized, but this is not the main problem... > > Could you please explain how it was supposed to work? If nothing > > else, Suppose we have task->task_works -> W1 -> W2 -> W3. How this > > code can add W4 after W3? > > > > 1. head = task_works head == &W1 > 2. head = head->next head == &W2 > 3. if head == NULL > /* it's next node of list tail (w3->next) */ > head = work No, > else > goto 1 And? You restart from ->task_works again. > > Anyway, whatever I missed this is racy. > > > > head = head->next; > > > > nothing protects "head" after this. Say, it can be task_work_cancel'ed > > and freed. So, > > > > cmpxchg(&head, ...) > > > > can modify the freed and reused memory. > > > > Oleg. > > Thanks Oleg, > Hmm, at first, I think even it was changed, it can't happened to be > NULL, but ... maybe it need more deliberation. My point was, even if it is not NULL nothing protects this element. It can be freed/reused before you do cmpxchg(&head). > The motivation it make the list FIFO at task_work_add, so you don't > need to reverse it at task_work_run, I understand, but this is not easy and unlikely possible without the locking. > and it's a time-saver if the list Yes, but compared to the next loop which does do/while again _and_ calls the work->func() "Reverse the list" doesn't add too much. Oleg. ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2013-03-15 14:36 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-03-14 7:57 [PATCH 1/2] task_work: make FIFO task_work list liguang 2013-03-14 7:57 ` [PATCH 2/2] task_work: check callback if it's NULL liguang 2013-03-14 14:43 ` Oleg Nesterov 2013-03-15 0:20 ` li guang 2013-03-15 1:01 ` Li Zefan 2013-03-15 1:26 ` li guang 2013-03-15 1:43 ` Li Zefan 2013-03-15 2:29 ` li guang 2013-03-14 14:40 ` [PATCH 1/2] task_work: make FIFO task_work list Oleg Nesterov 2013-03-15 0:16 ` li guang 2013-03-15 14:34 ` Oleg Nesterov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox