io_uring: add support for recvmsg()
authorJens Axboe <axboe@kernel.dk>
Fri, 19 Apr 2019 19:38:09 +0000 (13:38 -0600)
committerJens Axboe <axboe@kernel.dk>
Tue, 9 Jul 2019 20:32:14 +0000 (14:32 -0600)
This is done through IORING_OP_RECVMSG. This opcode uses the same
sqe->msg_flags that IORING_OP_SENDMSG added, and we pass in the
msghdr struct in the sqe->addr field as well.

We use MSG_DONTWAIT to force an inline fast path if recvmsg() doesn't
block, and punt to async execution if it would have.

Acked-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
fs/io_uring.c
include/linux/socket.h
include/uapi/linux/io_uring.h
net/socket.c

index 5d4cd8c4132dcf16e48d44ba5cfe7ea82561facb..8d86e31b0762da2d5189483fe13b1c20fd7eae1d 100644 (file)
@@ -1390,10 +1390,12 @@ static int io_sync_file_range(struct io_kiocb *req,
        return 0;
 }
 
-static int io_sendmsg(struct io_kiocb *req, const struct io_uring_sqe *sqe,
-                     bool force_nonblock)
-{
 #if defined(CONFIG_NET)
+static int io_send_recvmsg(struct io_kiocb *req, const struct io_uring_sqe *sqe,
+                          bool force_nonblock,
+                  long (*fn)(struct socket *, struct user_msghdr __user *,
+                               unsigned int))
+{
        struct socket *sock;
        int ret;
 
@@ -1414,7 +1416,7 @@ static int io_sendmsg(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                msg = (struct user_msghdr __user *) (unsigned long)
                        READ_ONCE(sqe->addr);
 
-               ret = __sys_sendmsg_sock(sock, msg, flags);
+               ret = fn(sock, msg, flags);
                if (force_nonblock && ret == -EAGAIN)
                        return ret;
        }
@@ -1422,6 +1424,24 @@ static int io_sendmsg(struct io_kiocb *req, const struct io_uring_sqe *sqe,
        io_cqring_add_event(req->ctx, sqe->user_data, ret);
        io_put_req(req);
        return 0;
+}
+#endif
+
+static int io_sendmsg(struct io_kiocb *req, const struct io_uring_sqe *sqe,
+                     bool force_nonblock)
+{
+#if defined(CONFIG_NET)
+       return io_send_recvmsg(req, sqe, force_nonblock, __sys_sendmsg_sock);
+#else
+       return -EOPNOTSUPP;
+#endif
+}
+
+static int io_recvmsg(struct io_kiocb *req, const struct io_uring_sqe *sqe,
+                     bool force_nonblock)
+{
+#if defined(CONFIG_NET)
+       return io_send_recvmsg(req, sqe, force_nonblock, __sys_recvmsg_sock);
 #else
        return -EOPNOTSUPP;
 #endif
@@ -1715,6 +1735,9 @@ static int __io_submit_sqe(struct io_ring_ctx *ctx, struct io_kiocb *req,
        case IORING_OP_SENDMSG:
                ret = io_sendmsg(req, s->sqe, force_nonblock);
                break;
+       case IORING_OP_RECVMSG:
+               ret = io_recvmsg(req, s->sqe, force_nonblock);
+               break;
        default:
                ret = -EINVAL;
                break;
index 9d770ef3ced5aad529d7e6d4ba886da0d3781e96..97523818cb14e0676cdc22c6b748f5b643ddc9ec 100644 (file)
@@ -378,6 +378,9 @@ extern int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg,
 extern long __sys_sendmsg_sock(struct socket *sock,
                               struct user_msghdr __user *msg,
                               unsigned int flags);
+extern long __sys_recvmsg_sock(struct socket *sock,
+                              struct user_msghdr __user *msg,
+                              unsigned int flags);
 
 /* helpers which do the actual work for syscalls */
 extern int __sys_recvfrom(int fd, void __user *ubuf, size_t size,
index d74742d6269f3a7dc62b8f89d08e00c65bccd8e7..1e1652f25cc19d8c7b6f1090fc5633011ba6f624 100644 (file)
@@ -60,6 +60,7 @@ struct io_uring_sqe {
 #define IORING_OP_POLL_REMOVE  7
 #define IORING_OP_SYNC_FILE_RANGE      8
 #define IORING_OP_SENDMSG      9
+#define IORING_OP_RECVMSG      10
 
 /*
  * sqe->fsync_flags
index b9536940255e48c12c432eba4b8bbac4903cc0e3..98354cc18840de1b15cffd8b0c597422375ba257 100644 (file)
@@ -2494,6 +2494,14 @@ out_freeiov:
  *     BSD recvmsg interface
  */
 
+long __sys_recvmsg_sock(struct socket *sock, struct user_msghdr __user *msg,
+                       unsigned int flags)
+{
+       struct msghdr msg_sys;
+
+       return ___sys_recvmsg(sock, msg, &msg_sys, flags, 0);
+}
+
 long __sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned int flags,
                   bool forbid_cmsg_compat)
 {