OSDN Git Service

io_uring: fix sporadic double CQE entry for close
authorJens Axboe <axboe@kernel.dk>
Sat, 1 Feb 2020 00:16:48 +0000 (17:16 -0700)
committerJens Axboe <axboe@kernel.dk>
Tue, 4 Feb 2020 00:27:47 +0000 (17:27 -0700)
We punt close to async for the final fput(), but we log the completion
even before that even in that case. We rely on the request not having
a files table assigned to detect what the final async close should do.
However, if we punt the async queue to __io_queue_sqe(), we'll get
->files assigned and this makes io_close_finish() think it should both
close the filp again (which does no harm) AND log a new CQE event for
this request. This causes duplicate CQEs.

Queue the request up for async manually so we don't grab files
needlessly and trigger this condition.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
fs/io_uring.c

index a3c75af..b9c9e04 100644 (file)
@@ -2843,16 +2843,13 @@ static void io_close_finish(struct io_wq_work **workptr)
                int ret;
 
                ret = filp_close(req->close.put_file, req->work.files);
-               if (ret < 0) {
+               if (ret < 0)
                        req_set_fail_links(req);
-               }
                io_cqring_add_event(req, ret);
        }
 
        fput(req->close.put_file);
 
-       /* we bypassed the re-issue, drop the submission reference */
-       io_put_req(req);
        io_put_req_find_next(req, &nxt);
        if (nxt)
                io_wq_assign_next(workptr, nxt);
@@ -2894,7 +2891,13 @@ static int io_close(struct io_kiocb *req, struct io_kiocb **nxt,
 
 eagain:
        req->work.func = io_close_finish;
-       return -EAGAIN;
+       /*
+        * Do manual async queue here to avoid grabbing files - we don't
+        * need the files, and it'll cause io_close_finish() to close
+        * the file again and cause a double CQE entry for this request
+        */
+       io_queue_async_work(req);
+       return 0;
 }
 
 static int io_prep_sfr(struct io_kiocb *req, const struct io_uring_sqe *sqe)