io_uring-5.8-2020-07-01
-----BEGIN PGP SIGNATURE----- iQJEBAABCAAuFiEEwPw5LcreJtl1+l5K99NY+ylx4KYFAl79YU0QHGF4Ym9lQGtl cm5lbC5kawAKCRD301j7KXHgplHKD/9rgv0c1I7dCh6MgQKxT+2z/eZcaPO3PekW sbn8yC8RiSIL85Av1zEfC1wAp+Mp21QlFKXFiZ6BJj5bdDbbshLk0WdbnxvuM+9I gyngTI/+em5D/WCcetAkPjnMTDq0m4l0UXd91fyNAeErmYZbvhL5dXihZsBJ3T9c Bprn4RzWwrUsUwGn8qIEZhx2UovMrzXJHGFxWXh/81YHkh7Y4mjvATKxtECIliW/ +QQJDU7Tf3gZw+ETPIDOEB9Hl9c9W+9fcWWzmrXzViUyy54IMbF4qyJpWcGaRh6c sO3apymwu7wwAUbQcE8IWr3ZLZDtw68AgUdZ5b/T0c2fEwqsI/UDMhBbELiuqcT0 MAoQdUSNNqZTti0PX5vg5CQlCFzjnl2uIwHF6LVSbrqgyqxiC3Qrus/FYSaf3x9h bAmNgWC9DeKp/wtEKMuBXaOm7RjrEutD5hjJYfVK/AkvKTZyZDx3vZ9FRH8WtrII 7KhUI3DPSZCeWlcpDtK+0fEqtqTw6OtCQ8U5vKSnJjoRSXLUtuk6IYbp/tqNxwe/ 0d+U6R+w513jVlXARUP48mV7tzpESp2MLP6Nd2Is/OD5tePWzQEZinpKzsFP4djH d2PT5FFGPCw9yBk03sI1Je/CFqVYwCGqav6h8dKKVBanMjoEdL4U1PMhI48Zua+9 M8pqRHoeDA== =4lvI -----END PGP SIGNATURE----- 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()
This commit is contained in:
commit
c93493b7cd
@ -4072,6 +4072,21 @@ struct io_poll_table {
|
|||||||
int error;
|
int error;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int io_req_task_work_add(struct io_kiocb *req, struct callback_head *cb,
|
||||||
|
int notify)
|
||||||
|
{
|
||||||
|
struct task_struct *tsk = req->task;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (req->ctx->flags & IORING_SETUP_SQPOLL)
|
||||||
|
notify = 0;
|
||||||
|
|
||||||
|
ret = task_work_add(tsk, cb, notify);
|
||||||
|
if (!ret)
|
||||||
|
wake_up_process(tsk);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int __io_async_wake(struct io_kiocb *req, struct io_poll_iocb *poll,
|
static int __io_async_wake(struct io_kiocb *req, struct io_poll_iocb *poll,
|
||||||
__poll_t mask, task_work_func_t func)
|
__poll_t mask, task_work_func_t func)
|
||||||
{
|
{
|
||||||
@ -4095,13 +4110,13 @@ static int __io_async_wake(struct io_kiocb *req, struct io_poll_iocb *poll,
|
|||||||
* of executing it. We can't safely execute it anyway, as we may not
|
* of executing it. We can't safely execute it anyway, as we may not
|
||||||
* have the needed state needed for it anyway.
|
* have the needed state needed for it anyway.
|
||||||
*/
|
*/
|
||||||
ret = task_work_add(tsk, &req->task_work, true);
|
ret = io_req_task_work_add(req, &req->task_work, TWA_SIGNAL);
|
||||||
if (unlikely(ret)) {
|
if (unlikely(ret)) {
|
||||||
WRITE_ONCE(poll->canceled, true);
|
WRITE_ONCE(poll->canceled, true);
|
||||||
tsk = io_wq_get_task(req->ctx->io_wq);
|
tsk = io_wq_get_task(req->ctx->io_wq);
|
||||||
task_work_add(tsk, &req->task_work, true);
|
task_work_add(tsk, &req->task_work, 0);
|
||||||
|
wake_up_process(tsk);
|
||||||
}
|
}
|
||||||
wake_up_process(tsk);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6182,19 +6197,20 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
|
|||||||
do {
|
do {
|
||||||
prepare_to_wait_exclusive(&ctx->wait, &iowq.wq,
|
prepare_to_wait_exclusive(&ctx->wait, &iowq.wq,
|
||||||
TASK_INTERRUPTIBLE);
|
TASK_INTERRUPTIBLE);
|
||||||
|
/* make sure we run task_work before checking for signals */
|
||||||
if (current->task_works)
|
if (current->task_works)
|
||||||
task_work_run();
|
task_work_run();
|
||||||
|
if (signal_pending(current)) {
|
||||||
|
ret = -ERESTARTSYS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (io_should_wake(&iowq, false))
|
if (io_should_wake(&iowq, false))
|
||||||
break;
|
break;
|
||||||
schedule();
|
schedule();
|
||||||
if (signal_pending(current)) {
|
|
||||||
ret = -EINTR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (1);
|
} while (1);
|
||||||
finish_wait(&ctx->wait, &iowq.wq);
|
finish_wait(&ctx->wait, &iowq.wq);
|
||||||
|
|
||||||
restore_saved_sigmask_unless(ret == -EINTR);
|
restore_saved_sigmask_unless(ret == -ERESTARTSYS);
|
||||||
|
|
||||||
return READ_ONCE(rings->cq.head) == READ_ONCE(rings->cq.tail) ? ret : 0;
|
return READ_ONCE(rings->cq.head) == READ_ONCE(rings->cq.tail) ? ret : 0;
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ struct task_struct;
|
|||||||
#define JOBCTL_TRAPPING_BIT 21 /* switching to TRACED */
|
#define JOBCTL_TRAPPING_BIT 21 /* switching to TRACED */
|
||||||
#define JOBCTL_LISTENING_BIT 22 /* ptracer is listening for events */
|
#define JOBCTL_LISTENING_BIT 22 /* ptracer is listening for events */
|
||||||
#define JOBCTL_TRAP_FREEZE_BIT 23 /* trap for cgroup freezer */
|
#define JOBCTL_TRAP_FREEZE_BIT 23 /* trap for cgroup freezer */
|
||||||
|
#define JOBCTL_TASK_WORK_BIT 24 /* set by TWA_SIGNAL */
|
||||||
|
|
||||||
#define JOBCTL_STOP_DEQUEUED (1UL << JOBCTL_STOP_DEQUEUED_BIT)
|
#define JOBCTL_STOP_DEQUEUED (1UL << JOBCTL_STOP_DEQUEUED_BIT)
|
||||||
#define JOBCTL_STOP_PENDING (1UL << JOBCTL_STOP_PENDING_BIT)
|
#define JOBCTL_STOP_PENDING (1UL << JOBCTL_STOP_PENDING_BIT)
|
||||||
@ -28,9 +29,10 @@ struct task_struct;
|
|||||||
#define JOBCTL_TRAPPING (1UL << JOBCTL_TRAPPING_BIT)
|
#define JOBCTL_TRAPPING (1UL << JOBCTL_TRAPPING_BIT)
|
||||||
#define JOBCTL_LISTENING (1UL << JOBCTL_LISTENING_BIT)
|
#define JOBCTL_LISTENING (1UL << JOBCTL_LISTENING_BIT)
|
||||||
#define JOBCTL_TRAP_FREEZE (1UL << JOBCTL_TRAP_FREEZE_BIT)
|
#define JOBCTL_TRAP_FREEZE (1UL << JOBCTL_TRAP_FREEZE_BIT)
|
||||||
|
#define JOBCTL_TASK_WORK (1UL << JOBCTL_TASK_WORK_BIT)
|
||||||
|
|
||||||
#define JOBCTL_TRAP_MASK (JOBCTL_TRAP_STOP | JOBCTL_TRAP_NOTIFY)
|
#define JOBCTL_TRAP_MASK (JOBCTL_TRAP_STOP | JOBCTL_TRAP_NOTIFY)
|
||||||
#define JOBCTL_PENDING_MASK (JOBCTL_STOP_PENDING | JOBCTL_TRAP_MASK)
|
#define JOBCTL_PENDING_MASK (JOBCTL_STOP_PENDING | JOBCTL_TRAP_MASK | JOBCTL_TASK_WORK)
|
||||||
|
|
||||||
extern bool task_set_jobctl_pending(struct task_struct *task, unsigned long mask);
|
extern bool task_set_jobctl_pending(struct task_struct *task, unsigned long mask);
|
||||||
extern void task_clear_jobctl_trapping(struct task_struct *task);
|
extern void task_clear_jobctl_trapping(struct task_struct *task);
|
||||||
|
@ -13,7 +13,10 @@ init_task_work(struct callback_head *twork, task_work_func_t func)
|
|||||||
twork->func = func;
|
twork->func = func;
|
||||||
}
|
}
|
||||||
|
|
||||||
int task_work_add(struct task_struct *task, struct callback_head *twork, bool);
|
#define TWA_RESUME 1
|
||||||
|
#define TWA_SIGNAL 2
|
||||||
|
int task_work_add(struct task_struct *task, struct callback_head *twork, int);
|
||||||
|
|
||||||
struct callback_head *task_work_cancel(struct task_struct *, task_work_func_t);
|
struct callback_head *task_work_cancel(struct task_struct *, task_work_func_t);
|
||||||
void task_work_run(void);
|
void task_work_run(void);
|
||||||
|
|
||||||
|
@ -2529,9 +2529,6 @@ bool get_signal(struct ksignal *ksig)
|
|||||||
struct signal_struct *signal = current->signal;
|
struct signal_struct *signal = current->signal;
|
||||||
int signr;
|
int signr;
|
||||||
|
|
||||||
if (unlikely(current->task_works))
|
|
||||||
task_work_run();
|
|
||||||
|
|
||||||
if (unlikely(uprobe_deny_signal()))
|
if (unlikely(uprobe_deny_signal()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -2544,6 +2541,13 @@ bool get_signal(struct ksignal *ksig)
|
|||||||
|
|
||||||
relock:
|
relock:
|
||||||
spin_lock_irq(&sighand->siglock);
|
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
|
* Every stopped thread goes here after wakeup. Check to see if
|
||||||
* we should notify the parent, prepare_signal(SIGCONT) encodes
|
* we should notify the parent, prepare_signal(SIGCONT) encodes
|
||||||
|
@ -25,9 +25,10 @@ static struct callback_head work_exited; /* all we need is ->next == NULL */
|
|||||||
* 0 if succeeds or -ESRCH.
|
* 0 if succeeds or -ESRCH.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
task_work_add(struct task_struct *task, struct callback_head *work, bool notify)
|
task_work_add(struct task_struct *task, struct callback_head *work, int notify)
|
||||||
{
|
{
|
||||||
struct callback_head *head;
|
struct callback_head *head;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
head = READ_ONCE(task->task_works);
|
head = READ_ONCE(task->task_works);
|
||||||
@ -36,8 +37,19 @@ task_work_add(struct task_struct *task, struct callback_head *work, bool notify)
|
|||||||
work->next = head;
|
work->next = head;
|
||||||
} while (cmpxchg(&task->task_works, head, work) != head);
|
} while (cmpxchg(&task->task_works, head, work) != head);
|
||||||
|
|
||||||
if (notify)
|
switch (notify) {
|
||||||
|
case TWA_RESUME:
|
||||||
set_notify_resume(task);
|
set_notify_resume(task);
|
||||||
|
break;
|
||||||
|
case TWA_SIGNAL:
|
||||||
|
if (lock_task_sighand(task, &flags)) {
|
||||||
|
task->jobctl |= JOBCTL_TASK_WORK;
|
||||||
|
signal_wake_up(task, 0);
|
||||||
|
unlock_task_sighand(task, &flags);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user