]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
io_uring: Fix missing smp_mb() in io_cancel_async_work()
authorMuchun Song <songmuchun@bytedance.com>
Wed, 7 Oct 2020 03:16:33 +0000 (11:16 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 14 Oct 2020 08:32:57 +0000 (10:32 +0200)
The store to req->flags and load req->work_task should not be
reordering in io_cancel_async_work(). We should make sure that
either we store REQ_F_CANCE flag to req->flags or we see the
req->work_task setted in io_sq_wq_submit_work().

Fixes: 1c4404efcf2c ("io_uring: make sure async workqueue is canceled on exit")
Signed-off-by: Muchun Song <songmuchun@bytedance.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/io_uring.c

index 33bd3ebdd3ef0f8b81b48a7731b472a9b1ebba8d..27770af20d240f4b5751e6ca2c1d5839b34e9573 100644 (file)
@@ -2247,6 +2247,12 @@ restart:
 
                if (!ret) {
                        req->work_task = current;
+
+                       /*
+                        * Pairs with the smp_store_mb() (B) in
+                        * io_cancel_async_work().
+                        */
+                       smp_mb(); /* A */
                        if (req->flags & REQ_F_CANCEL) {
                                ret = -ECANCELED;
                                goto end_req;
@@ -3725,7 +3731,15 @@ static void io_cancel_async_work(struct io_ring_ctx *ctx,
 
                req = list_first_entry(&ctx->task_list, struct io_kiocb, task_list);
                list_del_init(&req->task_list);
-               req->flags |= REQ_F_CANCEL;
+
+               /*
+                * The below executes an smp_mb(), which matches with the
+                * smp_mb() (A) in io_sq_wq_submit_work() such that either
+                * we store REQ_F_CANCEL flag to req->flags or we see the
+                * req->work_task setted in io_sq_wq_submit_work().
+                */
+               smp_store_mb(req->flags, req->flags | REQ_F_CANCEL); /* B */
+
                if (req->work_task && (!files || req->files == files))
                        send_sig(SIGINT, req->work_task, 1);
        }