aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Axboe <[email protected]>2020-01-09 07:52:28 -0700
committerJens Axboe <[email protected]>2020-01-20 17:04:06 -0700
commit10fef4bebf979bb705feed087611293d5864adfe (patch)
treeca1295794fd2ddf0d8be6fdd83d5950bbfcf6b3c
parent354420f705ccd0aa2d41249f3bb55b4afbed1873 (diff)
io_uring: account fixed file references correctly in batch
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 <[email protected]> Reported-by: Pavel Begunkov <[email protected]> Tested-by: Dmitrii Dolgov <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
-rw-r--r--fs/io_uring.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/fs/io_uring.c b/fs/io_uring.c
index 50233efd9445..8a645a37b4c7 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -1207,21 +1207,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)
@@ -1231,7 +1234,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;
@@ -1244,8 +1247,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;
}