diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-07-02 14:56:22 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-07-02 14:56:22 -0700 |
commit | c93493b7cd40c20708e3373a7cc8e8049460d7ce (patch) | |
tree | 72e472420baacf2168d484bbeaf521423115c049 /kernel/signal.c | |
parent | cd77006e01b3198c75fb7819b3d0ff89709539bb (diff) | |
parent | ce593a6c480a22acba08795be313c0c6d49dd35d (diff) | |
download | lwn-c93493b7cd40c20708e3373a7cc8e8049460d7ce.tar.gz lwn-c93493b7cd40c20708e3373a7cc8e8049460d7ce.zip |
Merge tag 'io_uring-5.8-2020-07-01' of git://git.kernel.dk/linux-block
Pull io_uring fixes from Jens Axboe:
"One fix in here, for a regression in 5.7 where a task is waiting in
the kernel for a condition, but that condition won't become true until
task_work is run. And the task_work can't be run exactly because the
task is waiting in the kernel, so we'll never make any progress.
One example of that is registering an eventfd and queueing io_uring
work, and then the task goes and waits in eventfd read with the
expectation that it'll get woken (and read an event) when the io_uring
request completes. The io_uring request is finished through task_work,
which won't get run while the task is looping in eventfd read"
* tag 'io_uring-5.8-2020-07-01' of git://git.kernel.dk/linux-block:
io_uring: use signal based task_work running
task_work: teach task_work_add() to do signal_wake_up()
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index 5ca48cc5da76..ee22ec78fd6d 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2529,9 +2529,6 @@ bool get_signal(struct ksignal *ksig) struct signal_struct *signal = current->signal; int signr; - if (unlikely(current->task_works)) - task_work_run(); - if (unlikely(uprobe_deny_signal())) return false; @@ -2544,6 +2541,13 @@ bool get_signal(struct ksignal *ksig) relock: spin_lock_irq(&sighand->siglock); + current->jobctl &= ~JOBCTL_TASK_WORK; + if (unlikely(current->task_works)) { + spin_unlock_irq(&sighand->siglock); + task_work_run(); + goto relock; + } + /* * Every stopped thread goes here after wakeup. Check to see if * we should notify the parent, prepare_signal(SIGCONT) encodes |