FAILED: patch "[PATCH] io_uring: enable lookup of links holding inflight files" failed to apply to 5.7-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.7-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From f254ac04c8744cf7bfed012717eac34eacc65dfb Mon Sep 17 00:00:00 2001
From: Jens Axboe <[email protected]>
Date: Wed, 12 Aug 2020 17:33:30 -0600
Subject: [PATCH] io_uring: enable lookup of links holding inflight files
When a process exits, we cancel whatever requests it has pending that are referencing the file table. However, if a link is holding a reference, then we cannot find it by simply looking at the inflight list.
Enable checking of the poll and timeout list to find the link, and cancel it appropriately.
fs/io_uring.c +87 -10
@@ -4937,6 +4937,7 @@ static bool io_poll_remove_one(struct io_kiocb *req)io_cqring_fill_event (req, -ECANCELED );io_commit_cqring (req->ctx); req->flags |=REQ_F_COMP_LOCKED ; +req_set_fail_links (req);io_put_req (req); }
@@ -5109,6 +5110,23 @@ static enum hrtimer_restart io_timeout_fn(struct hrtimer *timer)return HRTIMER_NORESTART ; } +static int __io_timeout_cancel (struct io_kiocb *req) +{ +int ret; + +list_del_init (&req->timeout.list); + + ret =hrtimer_try_to_cancel (&req->io->timeout.timer); +if (ret ==-1 ) +return -EALREADY ; + +req_set_fail_links (req); + req->flags |=REQ_F_COMP_LOCKED ; +io_cqring_fill_event (req, -ECANCELED ); +io_put_req (req); +return 0 ; +} +static int io_timeout_cancel (struct io_ring_ctx *ctx,__u64 user_data) {struct io_kiocb *req;
@@ -5116,7 +5134,6 @@ static int io_timeout_cancel(struct io_ring_ctx *ctx, __u64 user_data)list_for_each_entry (req, &ctx->timeout_list, timeout.list) {if (user_data == req->user_data) { -list_del_init (&req->timeout.list); ret =0 ;break ; }
@@ -5125,15 +5142,7 @@ static int io_timeout_cancel(struct io_ring_ctx *ctx, __u64 user_data)if (ret == -ENOENT )return ret; - ret =hrtimer_try_to_cancel (&req->io->timeout.timer); -if (ret ==-1 ) -return -EALREADY ; - -req_set_fail_links (req); - req->flags |=REQ_F_COMP_LOCKED ; -io_cqring_fill_event (req, -ECANCELED ); -io_put_req (req); -return 0 ; +return __io_timeout_cancel (req); } static int io_timeout_remove_prep(struct io_kiocb *req,
@@ -7935,6 +7944,71 @@ static bool io_wq_files_match(struct io_wq_work *work, void *data)return work->files == files; } +/* +* Returns true if 'preq' is the link parent of 'req' +*/ +static bool io_match_link (struct io_kiocb *preq,struct io_kiocb *req) +{ +struct io_kiocb *link; + +if (!(preq->flags &REQ_F_LINK_HEAD )) +return false; + +list_for_each_entry (link, &preq->link_list, link_list) { +if (link == req) +return true; + } + +return false; +} + +/* +* We're looking to cancel 'req' because it's holding on to our files, but +* 'req' could be a link to another request. See if it is, and cancel that +* parent request if so. +*/ +static bool io_poll_remove_link (struct io_ring_ctx *ctx,struct io_kiocb *req) +{ +struct hlist_node *tmp; +struct io_kiocb *preq; +bool found = false; +int i; + +spin_lock_irq (&ctx->completion_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 (preq, tmp, list, hash_node) { + found =io_match_link (preq, req); +if (found) { +io_poll_remove_one (preq); +break ; + } + } + } +spin_unlock_irq (&ctx->completion_lock); +return found; +} + +static bool io_timeout_remove_link (struct io_ring_ctx *ctx, +struct io_kiocb *req) +{ +struct io_kiocb *preq; +bool found = false; + +spin_lock_irq (&ctx->completion_lock); +list_for_each_entry (preq, &ctx->timeout_list, timeout.list) { + found =io_match_link (preq, req); +if (found) { +__io_timeout_cancel (preq); +break ; + } + } +spin_unlock_irq (&ctx->completion_lock); +return found; +} +static void io_uring_cancel_files (struct io_ring_ctx *ctx,struct files_struct *files) {
@@ -7989,6 +8063,9 @@ static void io_uring_cancel_files(struct io_ring_ctx *ctx, } }else {io_wq_cancel_work (ctx->io_wq, &cancel_req->work); +/* could be a link, check and remove if it is */ +if (!io_poll_remove_link (ctx, cancel_req)) +io_timeout_remove_link (ctx, cancel_req);io_put_req (cancel_req); }
Quoted 5 lines · On 8/17/20 3:43 AM, [email protected] wrote:
The patch below does not apply to the 5.7-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
Same as 5.8, needs the prep patch first. Attached the two patches.
Signature · 1 line
Jens Axboe
From 4acdfdda9d161327ed7dd1b5d7a84ed1d4dca24a Mon Sep 17 00:00:00 2001
From: Jens Axboe <[email protected]>
Date: Wed, 12 Aug 2020 17:33:30 -0600
Subject: [PATCH 2/2] io_uring: enable lookup of links holding inflight files
When a process exits, we cancel whatever requests it has pending that are referencing the file table. However, if a link is holding a reference, then we cannot find it by simply looking at the inflight list.
Enable checking of the poll and timeout list to find the link, and cancel it appropriately.
--- fs/io_uring.c | 97 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 87 insertions(+), 10 deletions(-)
fs/io_uring.c +87 -10
@@ -4627,6 +4627,7 @@ static bool io_poll_remove_one(struct io_kiocb *req)io_cqring_fill_event (req, -ECANCELED );io_commit_cqring (req->ctx); req->flags |=REQ_F_COMP_LOCKED ; +req_set_fail_links (req);io_put_req (req); }
@@ -4809,6 +4810,23 @@ static enum hrtimer_restart io_timeout_fn(struct hrtimer *timer)return HRTIMER_NORESTART ; } +static int __io_timeout_cancel (struct io_kiocb *req) +{ +int ret; + +list_del_init (&req->list); + + ret =hrtimer_try_to_cancel (&req->io->timeout.timer); +if (ret ==-1 ) +return -EALREADY ; + +req_set_fail_links (req); + req->flags |=REQ_F_COMP_LOCKED ; +io_cqring_fill_event (req, -ECANCELED ); +io_put_req (req); +return 0 ; +} +static int io_timeout_cancel (struct io_ring_ctx *ctx,__u64 user_data) {struct io_kiocb *req;
@@ -4816,7 +4834,6 @@ static int io_timeout_cancel(struct io_ring_ctx *ctx, __u64 user_data)list_for_each_entry (req, &ctx->timeout_list, list) {if (user_data == req->user_data) { -list_del_init (&req->list); ret =0 ;break ; }
@@ -4825,15 +4842,7 @@ static int io_timeout_cancel(struct io_ring_ctx *ctx, __u64 user_data)if (ret == -ENOENT )return ret; - ret =hrtimer_try_to_cancel (&req->io->timeout.timer); -if (ret ==-1 ) -return -EALREADY ; - -req_set_fail_links (req); - req->flags |=REQ_F_COMP_LOCKED ; -io_cqring_fill_event (req, -ECANCELED ); -io_put_req (req); -return 0 ; +return __io_timeout_cancel (req); } static int io_timeout_remove_prep(struct io_kiocb *req,
@@ -7572,6 +7581,71 @@ static int io_uring_release(struct inode *inode, struct file *file)return 0 ; } +/* +* Returns true if 'preq' is the link parent of 'req' +*/ +static bool io_match_link (struct io_kiocb *preq,struct io_kiocb *req) +{ +struct io_kiocb *link; + +if (!(preq->flags &REQ_F_LINK_HEAD )) +return false; + +list_for_each_entry (link, &preq->link_list, link_list) { +if (link == req) +return true; + } + +return false; +} + +/* +* We're looking to cancel 'req' because it's holding on to our files, but +* 'req' could be a link to another request. See if it is, and cancel that +* parent request if so. +*/ +static bool io_poll_remove_link (struct io_ring_ctx *ctx,struct io_kiocb *req) +{ +struct hlist_node *tmp; +struct io_kiocb *preq; +bool found = false; +int i; + +spin_lock_irq (&ctx->completion_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 (preq, tmp, list, hash_node) { + found =io_match_link (preq, req); +if (found) { +io_poll_remove_one (preq); +break ; + } + } + } +spin_unlock_irq (&ctx->completion_lock); +return found; +} + +static bool io_timeout_remove_link (struct io_ring_ctx *ctx, +struct io_kiocb *req) +{ +struct io_kiocb *preq; +bool found = false; + +spin_lock_irq (&ctx->completion_lock); +list_for_each_entry (preq, &ctx->timeout_list, list) { + found =io_match_link (preq, req); +if (found) { +__io_timeout_cancel (preq); +break ; + } + } +spin_unlock_irq (&ctx->completion_lock); +return found; +} +static void io_uring_cancel_files (struct io_ring_ctx *ctx,struct files_struct *files) {
@@ -7622,6 +7696,9 @@ static void io_uring_cancel_files(struct io_ring_ctx *ctx, } }else {io_wq_cancel_work (ctx->io_wq, &cancel_req->work); +/* could be a link, check and remove if it is */ +if (!io_poll_remove_link (ctx, cancel_req)) +io_timeout_remove_link (ctx, cancel_req);io_put_req (cancel_req); }
Signature · 1 line
2.28.0
From 4f65a22da4159dae4f6ad27a22cf13f5bd06ecf9 Mon Sep 17 00:00:00 2001
From: Jens Axboe <[email protected]>
Date: Mon, 17 Aug 2020 06:02:02 -0700
Subject: [PATCH 1/2] io_uring: add missing REQ_F_COMP_LOCKED for nested
requests
When we traverse into failing links or timeouts, we need to ensure we propagate the REQ_F_COMP_LOCKED flag to ensure that we correctly signal to the completion side that we already hold the completion lock.
--- fs/io_uring.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-)
fs/io_uring.c +19 -5
@@ -1484,12 +1484,9 @@ static void io_req_link_next(struct io_kiocb *req, struct io_kiocb **nxtptr)/* * Called if REQ_F_LINK_HEAD is set, and we fail the head request */ -static void io_fail_links (struct io_kiocb *req) +static void __io_fail_links (struct io_kiocb *req) {struct io_ring_ctx *ctx = req->ctx; -unsigned long flags; - -spin_lock_irqsave (&ctx->completion_lock, flags);while (!list_empty (&req->link_list)) { struct io_kiocb *link = list_first_entry(&req->link_list,
@@ -1503,13 +1500,29 @@ static void io_fail_links(struct io_kiocb *req)io_link_cancel_timeout (link); }else {io_cqring_fill_event (link, -ECANCELED ); + link->flags |=REQ_F_COMP_LOCKED ;__io_double_put_req (link); } req->flags &= ~REQ_F_LINK_TIMEOUT ; }io_commit_cqring (ctx); -spin_unlock_irqrestore (&ctx->completion_lock, flags); +} + +static void io_fail_links (struct io_kiocb *req) +{ +struct io_ring_ctx *ctx = req->ctx; + +if (!(req->flags &REQ_F_COMP_LOCKED )) { +unsigned long flags; + +spin_lock_irqsave (&ctx->completion_lock, flags); +__io_fail_links (req); +spin_unlock_irqrestore (&ctx->completion_lock, flags); + }else { +__io_fail_links (req); + } +io_cqring_ev_posted (ctx); }
@@ -4817,6 +4830,7 @@ static int io_timeout_cancel(struct io_ring_ctx *ctx, __u64 user_data)return -EALREADY ;req_set_fail_links (req); + req->flags |=REQ_F_COMP_LOCKED ;io_cqring_fill_event (req, -ECANCELED );io_put_req (req);return 0 ;
Signature · 1 line
2.28.0
Greg KH
maintainerQuoted 8 lines · Jens Axboe
Quoted 5 lines · On 8/17/20 3:43 AM, [email protected] wrote:
The patch below does not apply to the 5.7-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.Same as 5.8, needs the prep patch first. Attached the two patches.
Both now queued up, thanks.
greg k-h