public inbox for [email protected]
 help / color / mirror / Atom feed
* Support for shutdown
@ 2020-09-05 17:03 Norman Maurer
  2020-09-05 17:11 ` Jens Axboe
  0 siblings, 1 reply; 4+ messages in thread
From: Norman Maurer @ 2020-09-05 17:03 UTC (permalink / raw)
  To: io-uring

Hi there,

As you may have noticed from previous emails we are currently writing a new transport for netty that will use io_uring under the hood for max performance. One thing that is missing at the moment is the support for “shutdown”. Shutdown is quite useful in TCP land when you only want to close either input or output of the connection.

Is this something you think that can be added in the future ? This would be a perfect addition to the already existing close support.

Thanks
Norman 


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Support for shutdown
  2020-09-05 17:03 Support for shutdown Norman Maurer
@ 2020-09-05 17:11 ` Jens Axboe
  2020-09-05 17:12   ` Norman Maurer
  0 siblings, 1 reply; 4+ messages in thread
From: Jens Axboe @ 2020-09-05 17:11 UTC (permalink / raw)
  To: Norman Maurer, io-uring

On 9/5/20 11:03 AM, Norman Maurer wrote:
> Hi there,
> 
> As you may have noticed from previous emails we are currently writing
> a new transport for netty that will use io_uring under the hood for
> max performance. One thing that is missing at the moment is the
> support for “shutdown”. Shutdown is quite useful in TCP land when you
> only want to close either input or output of the connection.
> 
> Is this something you think that can be added in the future ? This
> would be a perfect addition to the already existing close support.

Something like this should do it, should just be split into having the
net part as a prep patch. I can add this to the 5.8 branch if that's
easier for you to test?

diff --git a/fs/io_uring.c b/fs/io_uring.c
index a9a625ceea5f..67714078e85d 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -529,6 +529,11 @@ struct io_statx {
 	struct statx __user		*buffer;
 };
 
+struct io_shutdown {
+	struct file			*file;
+	int				how;
+};
+
 struct io_completion {
 	struct file			*file;
 	struct list_head		list;
@@ -666,6 +671,7 @@ struct io_kiocb {
 		struct io_splice	splice;
 		struct io_provide_buf	pbuf;
 		struct io_statx		statx;
+		struct io_shutdown	shutdown;
 		/* use only after cleaning per-op data, see io_clean_op() */
 		struct io_completion	compl;
 	};
@@ -922,6 +928,9 @@ static const struct io_op_def io_op_defs[] __read_mostly = {
 		.hash_reg_file		= 1,
 		.unbound_nonreg_file	= 1,
 	},
+	[IORING_OP_SHUTDOWN] = {
+		.needs_file		= 1,
+	},
 };
 
 enum io_mem_account {
@@ -3367,6 +3376,44 @@ static int io_write(struct io_kiocb *req, bool force_nonblock,
 	return ret;
 }
 
+static int io_shutdown_prep(struct io_kiocb *req,
+			    const struct io_uring_sqe *sqe)
+{
+#if defined(CONFIG_NET)
+	if (unlikely(req->ctx->flags & (IORING_SETUP_IOPOLL|IORING_SETUP_SQPOLL)))
+		return -EINVAL;
+	if (sqe->ioprio || sqe->off || sqe->addr || sqe->len ||
+	    sqe->rw_flags || sqe->buf_index)
+		return -EINVAL;
+
+	req->shutdown.how = READ_ONCE(sqe->len);
+	return 0;
+#else
+	return -EOPNOTSUPP;
+#endif
+}
+
+static int io_shutdown(struct io_kiocb *req, bool force_nonblock)
+{
+#if defined(CONFIG_NET)
+	struct socket *sock;
+	int ret;
+
+	if (force_nonblock)
+		return -EAGAIN;
+
+	sock = sock_from_file(req->file, &ret);
+	if (unlikely(!sock))
+		return ret;
+
+	ret = __sys_shutdown_sock(sock, req->shutdown.how);
+	io_req_complete(req, ret);
+	return 0;
+#else
+	return -EOPNOTSUPP;
+#endif
+}
+
 static int __io_splice_prep(struct io_kiocb *req,
 			    const struct io_uring_sqe *sqe)
 {
@@ -5588,6 +5635,9 @@ static int io_req_defer_prep(struct io_kiocb *req,
 	case IORING_OP_TEE:
 		ret = io_tee_prep(req, sqe);
 		break;
+	case IORING_OP_SHUTDOWN:
+		ret = io_shutdown_prep(req, sqe);
+		break;
 	default:
 		printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n",
 				req->opcode);
@@ -5942,6 +5992,14 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
 		}
 		ret = io_tee(req, force_nonblock);
 		break;
+	case IORING_OP_SHUTDOWN:
+		if (req) {
+			ret = io_shutdown_prep(req, sqe);
+			if (ret < 0)
+				break;
+		}
+		ret = io_shutdown(req, force_nonblock);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/include/linux/socket.h b/include/linux/socket.h
index e9cb30d8cbfb..385894b4a8bb 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -436,6 +436,7 @@ extern int __sys_getpeername(int fd, struct sockaddr __user *usockaddr,
 			     int __user *usockaddr_len);
 extern int __sys_socketpair(int family, int type, int protocol,
 			    int __user *usockvec);
+extern int __sys_shutdown_sock(struct socket *sock, int how);
 extern int __sys_shutdown(int fd, int how);
 
 extern struct ns_common *get_net_ns(struct ns_common *ns);
diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
index 7539d912690b..2301c37e86cb 100644
--- a/include/uapi/linux/io_uring.h
+++ b/include/uapi/linux/io_uring.h
@@ -132,6 +132,7 @@ enum {
 	IORING_OP_PROVIDE_BUFFERS,
 	IORING_OP_REMOVE_BUFFERS,
 	IORING_OP_TEE,
+	IORING_OP_SHUTDOWN,
 
 	/* this goes last, obviously */
 	IORING_OP_LAST,
diff --git a/net/socket.c b/net/socket.c
index 0c0144604f81..8616962c27bc 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -2192,6 +2192,17 @@ SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname,
  *	Shutdown a socket.
  */
 
+int __sys_shutdown_sock(struct socket *sock, int how)
+{
+	int err;
+
+	err = security_socket_shutdown(sock, how);
+	if (!err)
+		err = sock->ops->shutdown(sock, how);
+
+	return err;
+}
+
 int __sys_shutdown(int fd, int how)
 {
 	int err, fput_needed;
@@ -2199,9 +2210,7 @@ int __sys_shutdown(int fd, int how)
 
 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
 	if (sock != NULL) {
-		err = security_socket_shutdown(sock, how);
-		if (!err)
-			err = sock->ops->shutdown(sock, how);
+		err = __sys_shutdown_sock(sock, how);
 		fput_light(sock->file, fput_needed);
 	}
 	return err;

-- 
Jens Axboe


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: Support for shutdown
  2020-09-05 17:11 ` Jens Axboe
@ 2020-09-05 17:12   ` Norman Maurer
  2020-09-05 17:13     ` Jens Axboe
  0 siblings, 1 reply; 4+ messages in thread
From: Norman Maurer @ 2020-09-05 17:12 UTC (permalink / raw)
  To: Jens Axboe; +Cc: io-uring

Yes in 5.8 branch would be the easiest...

You rock!

Bye
Norman

> Am 05.09.2020 um 19:11 schrieb Jens Axboe <[email protected]>:
> 
> On 9/5/20 11:03 AM, Norman Maurer wrote:
>> Hi there,
>> 
>> As you may have noticed from previous emails we are currently writing
>> a new transport for netty that will use io_uring under the hood for
>> max performance. One thing that is missing at the moment is the
>> support for “shutdown”. Shutdown is quite useful in TCP land when you
>> only want to close either input or output of the connection.
>> 
>> Is this something you think that can be added in the future ? This
>> would be a perfect addition to the already existing close support.
> 
> Something like this should do it, should just be split into having the
> net part as a prep patch. I can add this to the 5.8 branch if that's
> easier for you to test?
> 
> diff --git a/fs/io_uring.c b/fs/io_uring.c
> index a9a625ceea5f..67714078e85d 100644
> --- a/fs/io_uring.c
> +++ b/fs/io_uring.c
> @@ -529,6 +529,11 @@ struct io_statx {
>    struct statx __user        *buffer;
> };
> 
> +struct io_shutdown {
> +    struct file            *file;
> +    int                how;
> +};
> +
> struct io_completion {
>    struct file            *file;
>    struct list_head        list;
> @@ -666,6 +671,7 @@ struct io_kiocb {
>        struct io_splice    splice;
>        struct io_provide_buf    pbuf;
>        struct io_statx        statx;
> +        struct io_shutdown    shutdown;
>        /* use only after cleaning per-op data, see io_clean_op() */
>        struct io_completion    compl;
>    };
> @@ -922,6 +928,9 @@ static const struct io_op_def io_op_defs[] __read_mostly = {
>        .hash_reg_file        = 1,
>        .unbound_nonreg_file    = 1,
>    },
> +    [IORING_OP_SHUTDOWN] = {
> +        .needs_file        = 1,
> +    },
> };
> 
> enum io_mem_account {
> @@ -3367,6 +3376,44 @@ static int io_write(struct io_kiocb *req, bool force_nonblock,
>    return ret;
> }
> 
> +static int io_shutdown_prep(struct io_kiocb *req,
> +                const struct io_uring_sqe *sqe)
> +{
> +#if defined(CONFIG_NET)
> +    if (unlikely(req->ctx->flags & (IORING_SETUP_IOPOLL|IORING_SETUP_SQPOLL)))
> +        return -EINVAL;
> +    if (sqe->ioprio || sqe->off || sqe->addr || sqe->len ||
> +        sqe->rw_flags || sqe->buf_index)
> +        return -EINVAL;
> +
> +    req->shutdown.how = READ_ONCE(sqe->len);
> +    return 0;
> +#else
> +    return -EOPNOTSUPP;
> +#endif
> +}
> +
> +static int io_shutdown(struct io_kiocb *req, bool force_nonblock)
> +{
> +#if defined(CONFIG_NET)
> +    struct socket *sock;
> +    int ret;
> +
> +    if (force_nonblock)
> +        return -EAGAIN;
> +
> +    sock = sock_from_file(req->file, &ret);
> +    if (unlikely(!sock))
> +        return ret;
> +
> +    ret = __sys_shutdown_sock(sock, req->shutdown.how);
> +    io_req_complete(req, ret);
> +    return 0;
> +#else
> +    return -EOPNOTSUPP;
> +#endif
> +}
> +
> static int __io_splice_prep(struct io_kiocb *req,
>                const struct io_uring_sqe *sqe)
> {
> @@ -5588,6 +5635,9 @@ static int io_req_defer_prep(struct io_kiocb *req,
>    case IORING_OP_TEE:
>        ret = io_tee_prep(req, sqe);
>        break;
> +    case IORING_OP_SHUTDOWN:
> +        ret = io_shutdown_prep(req, sqe);
> +        break;
>    default:
>        printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n",
>                req->opcode);
> @@ -5942,6 +5992,14 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
>        }
>        ret = io_tee(req, force_nonblock);
>        break;
> +    case IORING_OP_SHUTDOWN:
> +        if (req) {
> +            ret = io_shutdown_prep(req, sqe);
> +            if (ret < 0)
> +                break;
> +        }
> +        ret = io_shutdown(req, force_nonblock);
> +        break;
>    default:
>        ret = -EINVAL;
>        break;
> diff --git a/include/linux/socket.h b/include/linux/socket.h
> index e9cb30d8cbfb..385894b4a8bb 100644
> --- a/include/linux/socket.h
> +++ b/include/linux/socket.h
> @@ -436,6 +436,7 @@ extern int __sys_getpeername(int fd, struct sockaddr __user *usockaddr,
>                 int __user *usockaddr_len);
> extern int __sys_socketpair(int family, int type, int protocol,
>                int __user *usockvec);
> +extern int __sys_shutdown_sock(struct socket *sock, int how);
> extern int __sys_shutdown(int fd, int how);
> 
> extern struct ns_common *get_net_ns(struct ns_common *ns);
> diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
> index 7539d912690b..2301c37e86cb 100644
> --- a/include/uapi/linux/io_uring.h
> +++ b/include/uapi/linux/io_uring.h
> @@ -132,6 +132,7 @@ enum {
>    IORING_OP_PROVIDE_BUFFERS,
>    IORING_OP_REMOVE_BUFFERS,
>    IORING_OP_TEE,
> +    IORING_OP_SHUTDOWN,
> 
>    /* this goes last, obviously */
>    IORING_OP_LAST,
> diff --git a/net/socket.c b/net/socket.c
> index 0c0144604f81..8616962c27bc 100644
> --- a/net/socket.c
> +++ b/net/socket.c
> @@ -2192,6 +2192,17 @@ SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname,
>  *    Shutdown a socket.
>  */
> 
> +int __sys_shutdown_sock(struct socket *sock, int how)
> +{
> +    int err;
> +
> +    err = security_socket_shutdown(sock, how);
> +    if (!err)
> +        err = sock->ops->shutdown(sock, how);
> +
> +    return err;
> +}
> +
> int __sys_shutdown(int fd, int how)
> {
>    int err, fput_needed;
> @@ -2199,9 +2210,7 @@ int __sys_shutdown(int fd, int how)
> 
>    sock = sockfd_lookup_light(fd, &err, &fput_needed);
>    if (sock != NULL) {
> -        err = security_socket_shutdown(sock, how);
> -        if (!err)
> -            err = sock->ops->shutdown(sock, how);
> +        err = __sys_shutdown_sock(sock, how);
>        fput_light(sock->file, fput_needed);
>    }
>    return err;
> 
> -- 
> Jens Axboe
> 

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Support for shutdown
  2020-09-05 17:12   ` Norman Maurer
@ 2020-09-05 17:13     ` Jens Axboe
  0 siblings, 0 replies; 4+ messages in thread
From: Jens Axboe @ 2020-09-05 17:13 UTC (permalink / raw)
  To: Norman Maurer; +Cc: io-uring

On 9/5/20 11:12 AM, Norman Maurer wrote:
> Yes in 5.8 branch would be the easiest...

Alright, let me do that.

> You rock!

Aim to please :-)

-- 
Jens Axboe


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2020-09-05 17:13 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-09-05 17:03 Support for shutdown Norman Maurer
2020-09-05 17:11 ` Jens Axboe
2020-09-05 17:12   ` Norman Maurer
2020-09-05 17:13     ` Jens Axboe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox