cifs: find and use the dentry for cached non-root directories also
[linux-2.6-microblaze.git] / io_uring / rw.c
index 76ebcfe..a25cd44 100644 (file)
@@ -33,6 +33,46 @@ static inline bool io_file_supports_nowait(struct io_kiocb *req)
        return req->flags & REQ_F_SUPPORT_NOWAIT;
 }
 
+#ifdef CONFIG_COMPAT
+static int io_iov_compat_buffer_select_prep(struct io_rw *rw)
+{
+       struct compat_iovec __user *uiov;
+       compat_ssize_t clen;
+
+       uiov = u64_to_user_ptr(rw->addr);
+       if (!access_ok(uiov, sizeof(*uiov)))
+               return -EFAULT;
+       if (__get_user(clen, &uiov->iov_len))
+               return -EFAULT;
+       if (clen < 0)
+               return -EINVAL;
+
+       rw->len = clen;
+       return 0;
+}
+#endif
+
+static int io_iov_buffer_select_prep(struct io_kiocb *req)
+{
+       struct iovec __user *uiov;
+       struct iovec iov;
+       struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
+
+       if (rw->len != 1)
+               return -EINVAL;
+
+#ifdef CONFIG_COMPAT
+       if (req->ctx->compat)
+               return io_iov_compat_buffer_select_prep(rw);
+#endif
+
+       uiov = u64_to_user_ptr(rw->addr);
+       if (copy_from_user(&iov, uiov, sizeof(*uiov)))
+               return -EFAULT;
+       rw->len = iov.iov_len;
+       return 0;
+}
+
 int io_prep_rw(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 {
        struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
@@ -69,6 +109,16 @@ int io_prep_rw(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        rw->addr = READ_ONCE(sqe->addr);
        rw->len = READ_ONCE(sqe->len);
        rw->flags = READ_ONCE(sqe->rw_flags);
+
+       /* Have to do this validation here, as this is in io_read() rw->len might
+        * have chanaged due to buffer selection
+        */
+       if (req->opcode == IORING_OP_READV && req->flags & REQ_F_BUFFER_SELECT) {
+               ret = io_iov_buffer_select_prep(req);
+               if (ret)
+                       return ret;
+       }
+
        return 0;
 }
 
@@ -186,14 +236,6 @@ static void kiocb_end_write(struct io_kiocb *req)
 
 static bool __io_complete_rw_common(struct io_kiocb *req, long res)
 {
-       struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
-
-       if (rw->kiocb.ki_flags & IOCB_WRITE) {
-               kiocb_end_write(req);
-               fsnotify_modify(req->file);
-       } else {
-               fsnotify_access(req->file);
-       }
        if (unlikely(res != req->cqe.res)) {
                if ((res == -EAGAIN || res == -EOPNOTSUPP) &&
                    io_rw_should_reissue(req)) {
@@ -220,6 +262,20 @@ static inline int io_fixup_rw_res(struct io_kiocb *req, long res)
        return res;
 }
 
+static void io_req_rw_complete(struct io_kiocb *req, bool *locked)
+{
+       struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
+
+       if (rw->kiocb.ki_flags & IOCB_WRITE) {
+               kiocb_end_write(req);
+               fsnotify_modify(req->file);
+       } else {
+               fsnotify_access(req->file);
+       }
+
+       io_req_task_complete(req, locked);
+}
+
 static void io_complete_rw(struct kiocb *kiocb, long res)
 {
        struct io_rw *rw = container_of(kiocb, struct io_rw, kiocb);
@@ -228,7 +284,7 @@ static void io_complete_rw(struct kiocb *kiocb, long res)
        if (__io_complete_rw_common(req, res))
                return;
        io_req_set_res(req, io_fixup_rw_res(req, res), 0);
-       req->io_task_work.func = io_req_task_complete;
+       req->io_task_work.func = io_req_rw_complete;
        io_req_task_work_add(req);
 }
 
@@ -279,79 +335,6 @@ static int kiocb_done(struct io_kiocb *req, ssize_t ret,
        return IOU_ISSUE_SKIP_COMPLETE;
 }
 
-#ifdef CONFIG_COMPAT
-static ssize_t io_compat_import(struct io_kiocb *req, struct iovec *iov,
-                               unsigned int issue_flags)
-{
-       struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
-       struct compat_iovec __user *uiov;
-       compat_ssize_t clen;
-       void __user *buf;
-       size_t len;
-
-       uiov = u64_to_user_ptr(rw->addr);
-       if (!access_ok(uiov, sizeof(*uiov)))
-               return -EFAULT;
-       if (__get_user(clen, &uiov->iov_len))
-               return -EFAULT;
-       if (clen < 0)
-               return -EINVAL;
-
-       len = clen;
-       buf = io_buffer_select(req, &len, issue_flags);
-       if (!buf)
-               return -ENOBUFS;
-       rw->addr = (unsigned long) buf;
-       iov[0].iov_base = buf;
-       rw->len = iov[0].iov_len = (compat_size_t) len;
-       return 0;
-}
-#endif
-
-static ssize_t __io_iov_buffer_select(struct io_kiocb *req, struct iovec *iov,
-                                     unsigned int issue_flags)
-{
-       struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
-       struct iovec __user *uiov = u64_to_user_ptr(rw->addr);
-       void __user *buf;
-       ssize_t len;
-
-       if (copy_from_user(iov, uiov, sizeof(*uiov)))
-               return -EFAULT;
-
-       len = iov[0].iov_len;
-       if (len < 0)
-               return -EINVAL;
-       buf = io_buffer_select(req, &len, issue_flags);
-       if (!buf)
-               return -ENOBUFS;
-       rw->addr = (unsigned long) buf;
-       iov[0].iov_base = buf;
-       rw->len = iov[0].iov_len = len;
-       return 0;
-}
-
-static ssize_t io_iov_buffer_select(struct io_kiocb *req, struct iovec *iov,
-                                   unsigned int issue_flags)
-{
-       struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
-
-       if (req->flags & (REQ_F_BUFFER_SELECTED|REQ_F_BUFFER_RING)) {
-               iov[0].iov_base = u64_to_user_ptr(rw->addr);
-               iov[0].iov_len = rw->len;
-               return 0;
-       }
-       if (rw->len != 1)
-               return -EINVAL;
-
-#ifdef CONFIG_COMPAT
-       if (req->ctx->compat)
-               return io_compat_import(req, iov, issue_flags);
-#endif
-
-       return __io_iov_buffer_select(req, iov, issue_flags);
-}
-
 static struct iovec *__io_import_iovec(int ddir, struct io_kiocb *req,
                                       struct io_rw_state *s,
                                       unsigned int issue_flags)
@@ -374,7 +357,8 @@ static struct iovec *__io_import_iovec(int ddir, struct io_kiocb *req,
        buf = u64_to_user_ptr(rw->addr);
        sqe_len = rw->len;
 
-       if (opcode == IORING_OP_READ || opcode == IORING_OP_WRITE) {
+       if (opcode == IORING_OP_READ || opcode == IORING_OP_WRITE ||
+           (req->flags & REQ_F_BUFFER_SELECT)) {
                if (io_do_buffer_select(req)) {
                        buf = io_buffer_select(req, &sqe_len, issue_flags);
                        if (!buf)
@@ -390,14 +374,6 @@ static struct iovec *__io_import_iovec(int ddir, struct io_kiocb *req,
        }
 
        iovec = s->fast_iov;
-       if (req->flags & REQ_F_BUFFER_SELECT) {
-               ret = io_iov_buffer_select(req, iovec, issue_flags);
-               if (ret)
-                       return ERR_PTR(ret);
-               iov_iter_init(iter, ddir, iovec, 1, iovec->iov_len);
-               return NULL;
-       }
-
        ret = __import_iovec(ddir, buf, sqe_len, UIO_FASTIOV, &iovec, iter,
                              req->ctx->compat);
        if (unlikely(ret < 0))
@@ -794,10 +770,12 @@ int io_read(struct io_kiocb *req, unsigned int issue_flags)
        iov_iter_restore(&s->iter, &s->iter_state);
 
        ret2 = io_setup_async_rw(req, iovec, s, true);
-       if (ret2)
-               return ret2;
-
        iovec = NULL;
+       if (ret2) {
+               ret = ret > 0 ? ret : ret2;
+               goto done;
+       }
+
        io = req->async_data;
        s = &io->s;
        /*
@@ -823,6 +801,7 @@ int io_read(struct io_kiocb *req, unsigned int issue_flags)
                        return -EAGAIN;
                }
 
+               req->cqe.res = iov_iter_count(&s->iter);
                /*
                 * Now retry read with the IOCB_WAITQ parts set in the iocb. If
                 * we get -EIOCBQUEUED, then we'll get a notification when the
@@ -984,6 +963,14 @@ static void io_cqring_ev_posted_iopoll(struct io_ring_ctx *ctx)
                io_cqring_wake(ctx);
 }
 
+void io_rw_fail(struct io_kiocb *req)
+{
+       int res;
+
+       res = io_fixup_rw_res(req, req->cqe.res);
+       io_req_set_res(req, res, req->cqe.flags);
+}
+
 int io_do_iopoll(struct io_ring_ctx *ctx, bool force_nonspin)
 {
        struct io_wq_work_node *pos, *start, *prev;
@@ -1000,7 +987,7 @@ int io_do_iopoll(struct io_ring_ctx *ctx, bool force_nonspin)
 
        wq_list_for_each(pos, start, &ctx->iopoll_list) {
                struct io_kiocb *req = container_of(pos, struct io_kiocb, comp_list);
-               struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
+               struct file *file = req->file;
                int ret;
 
                /*
@@ -1011,7 +998,17 @@ int io_do_iopoll(struct io_ring_ctx *ctx, bool force_nonspin)
                if (READ_ONCE(req->iopoll_completed))
                        break;
 
-               ret = rw->kiocb.ki_filp->f_op->iopoll(&rw->kiocb, &iob, poll_flags);
+               if (req->opcode == IORING_OP_URING_CMD) {
+                       struct io_uring_cmd *ioucmd;
+
+                       ioucmd = io_kiocb_to_cmd(req, struct io_uring_cmd);
+                       ret = file->f_op->uring_cmd_iopoll(ioucmd, &iob,
+                                                               poll_flags);
+               } else {
+                       struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
+
+                       ret = file->f_op->iopoll(&rw->kiocb, &iob, poll_flags);
+               }
                if (unlikely(ret < 0))
                        return ret;
                else if (ret)