return ret;
 }
 
-static void io_req_map_io(struct io_kiocb *req, ssize_t io_size,
+static void io_req_map_rw(struct io_kiocb *req, ssize_t io_size,
                          struct iovec *iovec, struct iovec *fast_iov,
                          struct iov_iter *iter)
 {
        }
 }
 
-static int io_setup_async_io(struct io_kiocb *req, ssize_t io_size,
-                            struct iovec *iovec, struct iovec *fast_iov,
-                            struct iov_iter *iter)
+static int io_alloc_async_ctx(struct io_kiocb *req)
 {
        req->io = kmalloc(sizeof(*req->io), GFP_KERNEL);
        if (req->io) {
-               io_req_map_io(req, io_size, iovec, fast_iov, iter);
                memcpy(&req->io->sqe, req->sqe, sizeof(req->io->sqe));
                req->sqe = &req->io->sqe;
                return 0;
        }
 
-       return -ENOMEM;
+       return 1;
+}
+
+static void io_rw_async(struct io_wq_work **workptr)
+{
+       struct io_kiocb *req = container_of(*workptr, struct io_kiocb, work);
+       struct iovec *iov = NULL;
+
+       if (req->io->rw.iov != req->io->rw.fast_iov)
+               iov = req->io->rw.iov;
+       io_wq_submit_work(workptr);
+       kfree(iov);
+}
+
+static int io_setup_async_rw(struct io_kiocb *req, ssize_t io_size,
+                            struct iovec *iovec, struct iovec *fast_iov,
+                            struct iov_iter *iter)
+{
+       if (!req->io && io_alloc_async_ctx(req))
+               return -ENOMEM;
+
+       io_req_map_rw(req, io_size, iovec, fast_iov, iter);
+       req->work.func = io_rw_async;
+       return 0;
 }
 
 static int io_read_prep(struct io_kiocb *req, struct iovec **iovec,
                        kiocb_done(kiocb, ret2, nxt, req->in_async);
                } else {
 copy_iov:
-                       ret = io_setup_async_io(req, io_size, iovec,
+                       ret = io_setup_async_rw(req, io_size, iovec,
                                                inline_vecs, &iter);
                        if (ret)
                                goto out_free;
                }
        }
 out_free:
-       kfree(iovec);
+       if (!io_wq_current_is_worker())
+               kfree(iovec);
        return ret;
 }
 
                        kiocb_done(kiocb, ret2, nxt, req->in_async);
                } else {
 copy_iov:
-                       ret = io_setup_async_io(req, io_size, iovec,
+                       ret = io_setup_async_rw(req, io_size, iovec,
                                                inline_vecs, &iter);
                        if (ret)
                                goto out_free;
                }
        }
 out_free:
-       kfree(iovec);
+       if (!io_wq_current_is_worker())
+               kfree(iovec);
        return ret;
 }
 
        return 0;
 }
 
+#if defined(CONFIG_NET)
+static void io_sendrecv_async(struct io_wq_work **workptr)
+{
+       struct io_kiocb *req = container_of(*workptr, struct io_kiocb, work);
+       struct iovec *iov = NULL;
+
+       if (req->io->rw.iov != req->io->rw.fast_iov)
+               iov = req->io->msg.iov;
+       io_wq_submit_work(workptr);
+       kfree(iov);
+}
+#endif
+
 static int io_sendmsg_prep(struct io_kiocb *req, struct io_async_ctx *io)
 {
 #if defined(CONFIG_NET)
 
        sock = sock_from_file(req->file, &ret);
        if (sock) {
-               struct io_async_ctx io, *copy;
+               struct io_async_ctx io;
                struct sockaddr_storage addr;
                unsigned flags;
 
 
                ret = __sys_sendmsg_sock(sock, &kmsg->msg, flags);
                if (force_nonblock && ret == -EAGAIN) {
-                       copy = kmalloc(sizeof(*copy), GFP_KERNEL);
-                       if (!copy) {
-                               ret = -ENOMEM;
-                               goto out;
-                       }
-                       memcpy(©->msg, &io.msg, sizeof(copy->msg));
-                       req->io = copy;
-                       memcpy(&req->io->sqe, req->sqe, sizeof(*req->sqe));
-                       req->sqe = &req->io->sqe;
+                       if (req->io)
+                               return -EAGAIN;
+                       if (io_alloc_async_ctx(req))
+                               return -ENOMEM;
+                       memcpy(&req->io->msg, &io.msg, sizeof(io.msg));
+                       req->work.func = io_sendrecv_async;
                        return -EAGAIN;
                }
                if (ret == -ERESTARTSYS)
        }
 
 out:
-       if (kmsg && kmsg->iov != kmsg->fast_iov)
+       if (!io_wq_current_is_worker() && kmsg && kmsg->iov != kmsg->fast_iov)
                kfree(kmsg->iov);
        io_cqring_add_event(req, ret);
        if (ret < 0)
        sock = sock_from_file(req->file, &ret);
        if (sock) {
                struct user_msghdr __user *msg;
-               struct io_async_ctx io, *copy;
+               struct io_async_ctx io;
                struct sockaddr_storage addr;
                unsigned flags;
 
 
                ret = __sys_recvmsg_sock(sock, &kmsg->msg, msg, kmsg->uaddr, flags);
                if (force_nonblock && ret == -EAGAIN) {
-                       copy = kmalloc(sizeof(*copy), GFP_KERNEL);
-                       if (!copy) {
-                               ret = -ENOMEM;
-                               goto out;
-                       }
-                       memcpy(copy, &io, sizeof(*copy));
-                       req->io = copy;
-                       memcpy(&req->io->sqe, req->sqe, sizeof(*req->sqe));
-                       req->sqe = &req->io->sqe;
+                       if (req->io)
+                               return -EAGAIN;
+                       if (io_alloc_async_ctx(req))
+                               return -ENOMEM;
+                       memcpy(&req->io->msg, &io.msg, sizeof(io.msg));
+                       req->work.func = io_sendrecv_async;
                        return -EAGAIN;
                }
                if (ret == -ERESTARTSYS)
        }
 
 out:
-       if (kmsg && kmsg->iov != kmsg->fast_iov)
+       if (!io_wq_current_is_worker() && kmsg && kmsg->iov != kmsg->fast_iov)
                kfree(kmsg->iov);
        io_cqring_add_event(req, ret);
        if (ret < 0)
        ret = __sys_connect_file(req->file, &io->connect.address, addr_len,
                                        file_flags);
        if ((ret == -EAGAIN || ret == -EINPROGRESS) && force_nonblock) {
-               io = kmalloc(sizeof(*io), GFP_KERNEL);
-               if (!io) {
+               if (req->io)
+                       return -EAGAIN;
+               if (io_alloc_async_ctx(req)) {
                        ret = -ENOMEM;
                        goto out;
                }
-               memcpy(&io->connect, &__io.connect, sizeof(io->connect));
-               req->io = io;
-               memcpy(&io->sqe, req->sqe, sizeof(*req->sqe));
-               req->sqe = &io->sqe;
+               memcpy(&req->io->connect, &__io.connect, sizeof(__io.connect));
                return -EAGAIN;
        }
        if (ret == -ERESTARTSYS)
        if (!poll->file)
                return -EBADF;
 
-       req->io = NULL;
        INIT_IO_WORK(&req->work, io_poll_complete_work);
        events = READ_ONCE(sqe->poll_events);
        poll->events = demangle_poll(events) | EPOLLERR | EPOLLHUP;
                data->mode = HRTIMER_MODE_REL;
 
        hrtimer_init(&data->timer, CLOCK_MONOTONIC, data->mode);
-       req->io = io;
        return 0;
 }
 
        unsigned count;
        struct io_ring_ctx *ctx = req->ctx;
        struct io_timeout_data *data;
-       struct io_async_ctx *io;
        struct list_head *entry;
        unsigned span = 0;
+       int ret;
 
-       io = req->io;
-       if (!io) {
-               int ret;
-
-               io = kmalloc(sizeof(*io), GFP_KERNEL);
-               if (!io)
+       if (!req->io) {
+               if (io_alloc_async_ctx(req))
                        return -ENOMEM;
-               ret = io_timeout_prep(req, io, false);
-               if (ret) {
-                       kfree(io);
+               ret = io_timeout_prep(req, req->io, false);
+               if (ret)
                        return ret;
-               }
        }
        data = &req->io->timeout;
 
        return 0;
 }
 
-static int io_req_defer_prep(struct io_kiocb *req, struct io_async_ctx *io)
+static int io_req_defer_prep(struct io_kiocb *req)
 {
        struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs;
+       struct io_async_ctx *io = req->io;
        struct iov_iter iter;
        ssize_t ret;
 
-       memcpy(&io->sqe, req->sqe, sizeof(io->sqe));
-       req->sqe = &io->sqe;
-
        switch (io->sqe.opcode) {
        case IORING_OP_READV:
        case IORING_OP_READ_FIXED:
+               /* ensure prep does right import */
+               req->io = NULL;
                ret = io_read_prep(req, &iovec, &iter, true);
+               req->io = io;
+               if (ret < 0)
+                       break;
+               io_req_map_rw(req, ret, iovec, inline_vecs, &iter);
+               ret = 0;
                break;
        case IORING_OP_WRITEV:
        case IORING_OP_WRITE_FIXED:
+               /* ensure prep does right import */
+               req->io = NULL;
                ret = io_write_prep(req, &iovec, &iter, true);
+               req->io = io;
+               if (ret < 0)
+                       break;
+               io_req_map_rw(req, ret, iovec, inline_vecs, &iter);
+               ret = 0;
                break;
        case IORING_OP_SENDMSG:
                ret = io_sendmsg_prep(req, io);
                ret = io_connect_prep(req, io);
                break;
        case IORING_OP_TIMEOUT:
-               return io_timeout_prep(req, io, false);
+               ret = io_timeout_prep(req, io, false);
+               break;
        case IORING_OP_LINK_TIMEOUT:
-               return io_timeout_prep(req, io, true);
+               ret = io_timeout_prep(req, io, true);
+               break;
        default:
-               req->io = io;
-               return 0;
+               ret = 0;
+               break;
        }
 
-       if (ret < 0)
-               return ret;
-
-       req->io = io;
-       io_req_map_io(req, ret, iovec, inline_vecs, &iter);
-       return 0;
+       return ret;
 }
 
 static int io_req_defer(struct io_kiocb *req)
 {
        struct io_ring_ctx *ctx = req->ctx;
-       struct io_async_ctx *io;
        int ret;
 
        /* Still need defer if there is pending req in defer list. */
        if (!req_need_defer(req) && list_empty(&ctx->defer_list))
                return 0;
 
-       io = kmalloc(sizeof(*io), GFP_KERNEL);
-       if (!io)
+       if (io_alloc_async_ctx(req))
                return -EAGAIN;
 
-       ret = io_req_defer_prep(req, io);
-       if (ret < 0) {
-               kfree(io);
+       ret = io_req_defer_prep(req);
+       if (ret < 0)
                return ret;
-       }
 
        spin_lock_irq(&ctx->completion_lock);
        if (!req_need_defer(req) && list_empty(&ctx->defer_list)) {
         */
        if (*link) {
                struct io_kiocb *prev = *link;
-               struct io_async_ctx *io;
 
                if (req->sqe->flags & IOSQE_IO_DRAIN)
                        (*link)->flags |= REQ_F_DRAIN_LINK | REQ_F_IO_DRAIN;
                if (req->sqe->flags & IOSQE_IO_HARDLINK)
                        req->flags |= REQ_F_HARDLINK;
 
-               io = kmalloc(sizeof(*io), GFP_KERNEL);
-               if (!io) {
+               if (io_alloc_async_ctx(req)) {
                        ret = -EAGAIN;
                        goto err_req;
                }
 
-               ret = io_req_defer_prep(req, io);
+               ret = io_req_defer_prep(req);
                if (ret) {
-                       kfree(io);
                        /* fail even hard links since we don't submit */
                        prev->flags |= REQ_F_FAIL_LINK;
                        goto err_req;