io_uring-5.16-2021-11-27
-----BEGIN PGP SIGNATURE----- iQJEBAABCAAuFiEEwPw5LcreJtl1+l5K99NY+ylx4KYFAmGiPsAQHGF4Ym9lQGtl cm5lbC5kawAKCRD301j7KXHgpr6oD/9i1PrY0nhHbNdpEKC5ZB2TeX8inxvCQj5i HmAm421s9umLjUXrRZQH6VMsSOWAS6viaXA9MdeWkxXSA9950Stx4Tr5LpujN/iJ hZneHgX1V3kfGkIOWdstPE62QTKCoMDtBFx1Jk+XZfZ7N9ogWHlmvr3C7iD3QLId +RODIIZlOZXYP5cYIUon9hK4ydMRjAh5jGik73ckN6gG+vsEWlsVZPlKLgqQ+AyT CXkXHh5Ad5tQt1vqio+PH2Fk42Ce/+CeY0vhNS2ZUWDHwQEKSz8qIHz3kx+zaCCU Y3e5CVe8MW64MOZIQPayEeNyposT0YNxTDgOMZxRi2J3IMeYFluJTm57zMNnnH/N sgKZHZDItAfsgkptVkptoIEeg+2nus3GWmhAKVWu7zPaS8LfAVROt+OCx6+2CUvr DHJwuGbkG3XR4vwO69ugTbjgRh97P3VJJfg4t6QZZNE9JDSAviHUrZDu9X53xHN5 hAsxg98QRz5BqvqPq99KIB6lq2zQ8LBHLZnnjEXhF3q031LpxCAhpVNBNt+LgQo2 MiGyx4lgznAl6P7/2uXaq5VxCLhWWHI5BtLdlGvJH3v8Uckci/JQKYoO65RNL4D8 gzdGnLQwJ80mDVlHcoN/9vUIYirru4+E+BiW6ua1/5MGmTAQvt6zw4Lo88MZMa5i mKOxZxL30g== =h6A3 -----END PGP SIGNATURE----- Merge tag 'io_uring-5.16-2021-11-27' of git://git.kernel.dk/linux-block Pull more io_uring fixes from Jens Axboe: "The locking fixup that was applied earlier this rc has both a deadlock and IRQ safety issue, let's get that ironed out before -rc3. This contains: - Link traversal locking fix (Pavel) - Cancelation fix (Pavel) - Relocate cond_resched() for huge buffer chain freeing, avoiding a softlockup warning (Ye) - Fix timespec validation (Ye)" * tag 'io_uring-5.16-2021-11-27' of git://git.kernel.dk/linux-block: io_uring: Fix undefined-behaviour in io_issue_sqe io_uring: fix soft lockup when call __io_remove_buffers io_uring: fix link traversal locking io_uring: fail cancellation for EXITING tasks
This commit is contained in:
commit
86799cdfbc
@ -1278,6 +1278,7 @@ static void io_refs_resurrect(struct percpu_ref *ref, struct completion *compl)
|
||||
|
||||
static bool io_match_task(struct io_kiocb *head, struct task_struct *task,
|
||||
bool cancel_all)
|
||||
__must_hold(&req->ctx->timeout_lock)
|
||||
{
|
||||
struct io_kiocb *req;
|
||||
|
||||
@ -1293,6 +1294,44 @@ static bool io_match_task(struct io_kiocb *head, struct task_struct *task,
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool io_match_linked(struct io_kiocb *head)
|
||||
{
|
||||
struct io_kiocb *req;
|
||||
|
||||
io_for_each_link(req, head) {
|
||||
if (req->flags & REQ_F_INFLIGHT)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* As io_match_task() but protected against racing with linked timeouts.
|
||||
* User must not hold timeout_lock.
|
||||
*/
|
||||
static bool io_match_task_safe(struct io_kiocb *head, struct task_struct *task,
|
||||
bool cancel_all)
|
||||
{
|
||||
bool matched;
|
||||
|
||||
if (task && head->task != task)
|
||||
return false;
|
||||
if (cancel_all)
|
||||
return true;
|
||||
|
||||
if (head->flags & REQ_F_LINK_TIMEOUT) {
|
||||
struct io_ring_ctx *ctx = head->ctx;
|
||||
|
||||
/* protect against races with linked timeouts */
|
||||
spin_lock_irq(&ctx->timeout_lock);
|
||||
matched = io_match_linked(head);
|
||||
spin_unlock_irq(&ctx->timeout_lock);
|
||||
} else {
|
||||
matched = io_match_linked(head);
|
||||
}
|
||||
return matched;
|
||||
}
|
||||
|
||||
static inline bool req_has_async_data(struct io_kiocb *req)
|
||||
{
|
||||
return req->flags & REQ_F_ASYNC_DATA;
|
||||
@ -4327,6 +4366,7 @@ static int __io_remove_buffers(struct io_ring_ctx *ctx, struct io_buffer *buf,
|
||||
kfree(nxt);
|
||||
if (++i == nbufs)
|
||||
return i;
|
||||
cond_resched();
|
||||
}
|
||||
i++;
|
||||
kfree(buf);
|
||||
@ -5699,17 +5739,15 @@ static __cold bool io_poll_remove_all(struct io_ring_ctx *ctx,
|
||||
int posted = 0, i;
|
||||
|
||||
spin_lock(&ctx->completion_lock);
|
||||
spin_lock_irq(&ctx->timeout_lock);
|
||||
for (i = 0; i < (1U << ctx->cancel_hash_bits); i++) {
|
||||
struct hlist_head *list;
|
||||
|
||||
list = &ctx->cancel_hash[i];
|
||||
hlist_for_each_entry_safe(req, tmp, list, hash_node) {
|
||||
if (io_match_task(req, tsk, cancel_all))
|
||||
if (io_match_task_safe(req, tsk, cancel_all))
|
||||
posted += io_poll_remove_one(req);
|
||||
}
|
||||
}
|
||||
spin_unlock_irq(&ctx->timeout_lock);
|
||||
spin_unlock(&ctx->completion_lock);
|
||||
|
||||
if (posted)
|
||||
@ -6158,6 +6196,9 @@ static int io_timeout_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe,
|
||||
if (get_timespec64(&data->ts, u64_to_user_ptr(sqe->addr)))
|
||||
return -EFAULT;
|
||||
|
||||
if (data->ts.tv_sec < 0 || data->ts.tv_nsec < 0)
|
||||
return -EINVAL;
|
||||
|
||||
data->mode = io_translate_timeout_mode(flags);
|
||||
hrtimer_init(&data->timer, io_timeout_get_clock(data), data->mode);
|
||||
|
||||
@ -6882,10 +6923,11 @@ static inline struct file *io_file_get(struct io_ring_ctx *ctx,
|
||||
static void io_req_task_link_timeout(struct io_kiocb *req, bool *locked)
|
||||
{
|
||||
struct io_kiocb *prev = req->timeout.prev;
|
||||
int ret;
|
||||
int ret = -ENOENT;
|
||||
|
||||
if (prev) {
|
||||
ret = io_try_cancel_userdata(req, prev->user_data);
|
||||
if (!(req->task->flags & PF_EXITING))
|
||||
ret = io_try_cancel_userdata(req, prev->user_data);
|
||||
io_req_complete_post(req, ret ?: -ETIME, 0);
|
||||
io_put_req(prev);
|
||||
} else {
|
||||
@ -9257,10 +9299,8 @@ static void io_destroy_buffers(struct io_ring_ctx *ctx)
|
||||
struct io_buffer *buf;
|
||||
unsigned long index;
|
||||
|
||||
xa_for_each(&ctx->io_buffers, index, buf) {
|
||||
xa_for_each(&ctx->io_buffers, index, buf)
|
||||
__io_remove_buffers(ctx, buf, index, -1U);
|
||||
cond_resched();
|
||||
}
|
||||
}
|
||||
|
||||
static void io_req_caches_free(struct io_ring_ctx *ctx)
|
||||
@ -9564,19 +9604,8 @@ static bool io_cancel_task_cb(struct io_wq_work *work, void *data)
|
||||
{
|
||||
struct io_kiocb *req = container_of(work, struct io_kiocb, work);
|
||||
struct io_task_cancel *cancel = data;
|
||||
bool ret;
|
||||
|
||||
if (!cancel->all && (req->flags & REQ_F_LINK_TIMEOUT)) {
|
||||
struct io_ring_ctx *ctx = req->ctx;
|
||||
|
||||
/* protect against races with linked timeouts */
|
||||
spin_lock_irq(&ctx->timeout_lock);
|
||||
ret = io_match_task(req, cancel->task, cancel->all);
|
||||
spin_unlock_irq(&ctx->timeout_lock);
|
||||
} else {
|
||||
ret = io_match_task(req, cancel->task, cancel->all);
|
||||
}
|
||||
return ret;
|
||||
return io_match_task_safe(req, cancel->task, cancel->all);
|
||||
}
|
||||
|
||||
static __cold bool io_cancel_defer_files(struct io_ring_ctx *ctx,
|
||||
@ -9587,14 +9616,12 @@ static __cold bool io_cancel_defer_files(struct io_ring_ctx *ctx,
|
||||
LIST_HEAD(list);
|
||||
|
||||
spin_lock(&ctx->completion_lock);
|
||||
spin_lock_irq(&ctx->timeout_lock);
|
||||
list_for_each_entry_reverse(de, &ctx->defer_list, list) {
|
||||
if (io_match_task(de->req, task, cancel_all)) {
|
||||
if (io_match_task_safe(de->req, task, cancel_all)) {
|
||||
list_cut_position(&list, &ctx->defer_list, &de->list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irq(&ctx->timeout_lock);
|
||||
spin_unlock(&ctx->completion_lock);
|
||||
if (list_empty(&list))
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user