From: Jens Axboe axboe@kernel.dk
mainline inclusion from mainline-5.6-rc1 commit 10fef4bebf979bb705feed087611293d5864adfe category: feature bugzilla: https://bugzilla.openeuler.org/show_bug.cgi?id=27 CVE: NA ---------------------------
We can't assume that the whole batch has fixed files in it. If it's a mix, or none at all, then we can end up doing a ref put that either messes up accounting, or causes an oops if we have no fixed files at all.
Also ensure we free requests properly between inflight accounted and normal requests.
Fixes: 82c721577011 ("io_uring: extend batch freeing to cover more cases") Reported-by: Dmitrii Dolgov 9erthalion6@gmail.com Reported-by: Pavel Begunkov asml.silence@gmail.com Tested-by: Dmitrii Dolgov 9erthalion6@gmail.com Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: yangerkun yangerkun@huawei.com Reviewed-by: zhangyi (F) yi.zhang@huawei.com Signed-off-by: Cheng Jian cj.chengjian@huawei.com --- fs/io_uring.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/fs/io_uring.c b/fs/io_uring.c index 0a616a4d9125..68881cb7f7c0 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -1202,21 +1202,24 @@ struct req_batch {
static void io_free_req_many(struct io_ring_ctx *ctx, struct req_batch *rb) { + int fixed_refs = rb->to_free; + if (!rb->to_free) return; if (rb->need_iter) { int i, inflight = 0; unsigned long flags;
+ fixed_refs = 0; for (i = 0; i < rb->to_free; i++) { struct io_kiocb *req = rb->reqs[i];
- if (req->flags & REQ_F_FIXED_FILE) + if (req->flags & REQ_F_FIXED_FILE) { req->file = NULL; + fixed_refs++; + } if (req->flags & REQ_F_INFLIGHT) inflight++; - else - rb->reqs[i] = NULL; __io_req_aux_free(req); } if (!inflight) @@ -1226,7 +1229,7 @@ static void io_free_req_many(struct io_ring_ctx *ctx, struct req_batch *rb) for (i = 0; i < rb->to_free; i++) { struct io_kiocb *req = rb->reqs[i];
- if (req) { + if (req->flags & REQ_F_INFLIGHT) { list_del(&req->inflight_entry); if (!--inflight) break; @@ -1239,8 +1242,9 @@ static void io_free_req_many(struct io_ring_ctx *ctx, struct req_batch *rb) } do_free: kmem_cache_free_bulk(req_cachep, rb->to_free, rb->reqs); + if (fixed_refs) + percpu_ref_put_many(&ctx->file_data->refs, fixed_refs); percpu_ref_put_many(&ctx->refs, rb->to_free); - percpu_ref_put_many(&ctx->file_data->refs, rb->to_free); rb->to_free = rb->need_iter = 0; }