Skip to content

Commit c93493b

Browse files
committed
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()
2 parents cd77006 + ce593a6 commit c93493b

File tree

5 files changed

+52
-15
lines changed

5 files changed

+52
-15
lines changed

fs/io_uring.c

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4072,6 +4072,21 @@ struct io_poll_table {
40724072
int error;
40734073
};
40744074

4075+
static int io_req_task_work_add(struct io_kiocb *req, struct callback_head *cb,
4076+
int notify)
4077+
{
4078+
struct task_struct *tsk = req->task;
4079+
int ret;
4080+
4081+
if (req->ctx->flags & IORING_SETUP_SQPOLL)
4082+
notify = 0;
4083+
4084+
ret = task_work_add(tsk, cb, notify);
4085+
if (!ret)
4086+
wake_up_process(tsk);
4087+
return ret;
4088+
}
4089+
40754090
static int __io_async_wake(struct io_kiocb *req, struct io_poll_iocb *poll,
40764091
__poll_t mask, task_work_func_t func)
40774092
{
@@ -4095,13 +4110,13 @@ static int __io_async_wake(struct io_kiocb *req, struct io_poll_iocb *poll,
40954110
* of executing it. We can't safely execute it anyway, as we may not
40964111
* have the needed state needed for it anyway.
40974112
*/
4098-
ret = task_work_add(tsk, &req->task_work, true);
4113+
ret = io_req_task_work_add(req, &req->task_work, TWA_SIGNAL);
40994114
if (unlikely(ret)) {
41004115
WRITE_ONCE(poll->canceled, true);
41014116
tsk = io_wq_get_task(req->ctx->io_wq);
4102-
task_work_add(tsk, &req->task_work, true);
4117+
task_work_add(tsk, &req->task_work, 0);
4118+
wake_up_process(tsk);
41034119
}
4104-
wake_up_process(tsk);
41054120
return 1;
41064121
}
41074122

@@ -6182,19 +6197,20 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
61826197
do {
61836198
prepare_to_wait_exclusive(&ctx->wait, &iowq.wq,
61846199
TASK_INTERRUPTIBLE);
6200+
/* make sure we run task_work before checking for signals */
61856201
if (current->task_works)
61866202
task_work_run();
6187-
if (io_should_wake(&iowq, false))
6188-
break;
6189-
schedule();
61906203
if (signal_pending(current)) {
6191-
ret = -EINTR;
6204+
ret = -ERESTARTSYS;
61926205
break;
61936206
}
6207+
if (io_should_wake(&iowq, false))
6208+
break;
6209+
schedule();
61946210
} while (1);
61956211
finish_wait(&ctx->wait, &iowq.wq);
61966212

6197-
restore_saved_sigmask_unless(ret == -EINTR);
6213+
restore_saved_sigmask_unless(ret == -ERESTARTSYS);
61986214

61996215
return READ_ONCE(rings->cq.head) == READ_ONCE(rings->cq.tail) ? ret : 0;
62006216
}

include/linux/sched/jobctl.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ struct task_struct;
1919
#define JOBCTL_TRAPPING_BIT 21 /* switching to TRACED */
2020
#define JOBCTL_LISTENING_BIT 22 /* ptracer is listening for events */
2121
#define JOBCTL_TRAP_FREEZE_BIT 23 /* trap for cgroup freezer */
22+
#define JOBCTL_TASK_WORK_BIT 24 /* set by TWA_SIGNAL */
2223

2324
#define JOBCTL_STOP_DEQUEUED (1UL << JOBCTL_STOP_DEQUEUED_BIT)
2425
#define JOBCTL_STOP_PENDING (1UL << JOBCTL_STOP_PENDING_BIT)
@@ -28,9 +29,10 @@ struct task_struct;
2829
#define JOBCTL_TRAPPING (1UL << JOBCTL_TRAPPING_BIT)
2930
#define JOBCTL_LISTENING (1UL << JOBCTL_LISTENING_BIT)
3031
#define JOBCTL_TRAP_FREEZE (1UL << JOBCTL_TRAP_FREEZE_BIT)
32+
#define JOBCTL_TASK_WORK (1UL << JOBCTL_TASK_WORK_BIT)
3133

3234
#define JOBCTL_TRAP_MASK (JOBCTL_TRAP_STOP | JOBCTL_TRAP_NOTIFY)
33-
#define JOBCTL_PENDING_MASK (JOBCTL_STOP_PENDING | JOBCTL_TRAP_MASK)
35+
#define JOBCTL_PENDING_MASK (JOBCTL_STOP_PENDING | JOBCTL_TRAP_MASK | JOBCTL_TASK_WORK)
3436

3537
extern bool task_set_jobctl_pending(struct task_struct *task, unsigned long mask);
3638
extern void task_clear_jobctl_trapping(struct task_struct *task);

include/linux/task_work.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ init_task_work(struct callback_head *twork, task_work_func_t func)
1313
twork->func = func;
1414
}
1515

16-
int task_work_add(struct task_struct *task, struct callback_head *twork, bool);
16+
#define TWA_RESUME 1
17+
#define TWA_SIGNAL 2
18+
int task_work_add(struct task_struct *task, struct callback_head *twork, int);
19+
1720
struct callback_head *task_work_cancel(struct task_struct *, task_work_func_t);
1821
void task_work_run(void);
1922

kernel/signal.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2529,9 +2529,6 @@ bool get_signal(struct ksignal *ksig)
25292529
struct signal_struct *signal = current->signal;
25302530
int signr;
25312531

2532-
if (unlikely(current->task_works))
2533-
task_work_run();
2534-
25352532
if (unlikely(uprobe_deny_signal()))
25362533
return false;
25372534

@@ -2544,6 +2541,13 @@ bool get_signal(struct ksignal *ksig)
25442541

25452542
relock:
25462543
spin_lock_irq(&sighand->siglock);
2544+
current->jobctl &= ~JOBCTL_TASK_WORK;
2545+
if (unlikely(current->task_works)) {
2546+
spin_unlock_irq(&sighand->siglock);
2547+
task_work_run();
2548+
goto relock;
2549+
}
2550+
25472551
/*
25482552
* Every stopped thread goes here after wakeup. Check to see if
25492553
* we should notify the parent, prepare_signal(SIGCONT) encodes

kernel/task_work.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@ static struct callback_head work_exited; /* all we need is ->next == NULL */
2525
* 0 if succeeds or -ESRCH.
2626
*/
2727
int
28-
task_work_add(struct task_struct *task, struct callback_head *work, bool notify)
28+
task_work_add(struct task_struct *task, struct callback_head *work, int notify)
2929
{
3030
struct callback_head *head;
31+
unsigned long flags;
3132

3233
do {
3334
head = READ_ONCE(task->task_works);
@@ -36,8 +37,19 @@ task_work_add(struct task_struct *task, struct callback_head *work, bool notify)
3637
work->next = head;
3738
} while (cmpxchg(&task->task_works, head, work) != head);
3839

39-
if (notify)
40+
switch (notify) {
41+
case TWA_RESUME:
4042
set_notify_resume(task);
43+
break;
44+
case TWA_SIGNAL:
45+
if (lock_task_sighand(task, &flags)) {
46+
task->jobctl |= JOBCTL_TASK_WORK;
47+
signal_wake_up(task, 0);
48+
unlock_task_sighand(task, &flags);
49+
}
50+
break;
51+
}
52+
4153
return 0;
4254
}
4355

0 commit comments

Comments
 (0)