We would queue a work for each req in defer and link list without
increasing async->cnt, so we shouldn't decrease it while exiting
from workqueue as well as shouldn't process the req in async list.

Signed-off-by: Zhengyuan Liu <liuzhengy...@kylinos.cn>
---
 fs/io_uring.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/fs/io_uring.c b/fs/io_uring.c
index 7e932c572f26..3e48fd7cd08f 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -333,7 +333,8 @@ struct io_kiocb {
 #define REQ_F_IO_DRAIN         16      /* drain existing IO first */
 #define REQ_F_IO_DRAINED       32      /* drain done */
 #define REQ_F_LINK             64      /* linked sqes */
-#define REQ_F_FAIL_LINK                128     /* fail rest of links */
+#define REQ_F_LINKED           128     /* linked sqes done */
+#define REQ_F_FAIL_LINK                256     /* fail rest of links */
        u64                     user_data;
        u32                     result;
        u32                     sequence;
@@ -630,6 +631,7 @@ static void io_req_link_next(struct io_kiocb *req)
                        nxt->flags |= REQ_F_LINK;
                }
 
+               nxt->flags |= REQ_F_LINKED;
                INIT_WORK(&nxt->work, io_sq_wq_submit_work);
                queue_work(req->ctx->sqo_wq, &nxt->work);
        }
@@ -1845,6 +1847,10 @@ static void io_sq_wq_submit_work(struct work_struct 
*work)
                /* async context always use a copy of the sqe */
                kfree(sqe);
 
+               /* req from defer and link list needn't dec async_list->cnt */
+               if (req->flags & (REQ_F_IO_DRAINED | REQ_F_LINKED))
+                       goto out;
+
                if (!async_list)
                        break;
                if (!list_empty(&req_list)) {
@@ -1892,6 +1898,7 @@ static void io_sq_wq_submit_work(struct work_struct *work)
                }
        }
 
+out:
        if (cur_mm) {
                set_fs(old_fs);
                unuse_mm(cur_mm);
-- 
2.19.1



Reply via email to