Yes in 5.8 branch would be the easiest... You rock! Bye Norman > Am 05.09.2020 um 19:11 schrieb Jens Axboe <axboe@xxxxxxxxx>: > > 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 >