Rely on the fd exit path machinery. Signed-off-by: Christian Brauner (Amutable) --- net/sctp/socket.c | 78 +++++++++++++++++++++---------------------------------- 1 file changed, 29 insertions(+), 49 deletions(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index c7b9e325ec1c..b75c50af8c16 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -5744,46 +5744,41 @@ static int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, } static int sctp_getsockopt_peeloff_common(struct sock *sk, sctp_peeloff_arg_t *peeloff, - struct file **newfile, unsigned flags) + unsigned flags) { struct socket *newsock; + struct file *newfile; + const struct fd_slot *fd; int retval; retval = sctp_do_peeloff(sk, peeloff->associd, &newsock); if (retval < 0) - goto out; + return retval; - /* Map the socket to an unused fd that can be returned to the user. */ - retval = get_unused_fd_flags(flags & SOCK_CLOEXEC); - if (retval < 0) { + /* Map the socket to a reserved fd that can be returned to the user. */ + fd = fd_prepare(flags & SOCK_CLOEXEC); + if (IS_ERR(fd)) { sock_release(newsock); - goto out; - } - - *newfile = sock_alloc_file(newsock, 0, NULL); - if (IS_ERR(*newfile)) { - put_unused_fd(retval); - retval = PTR_ERR(*newfile); - *newfile = NULL; - return retval; + return PTR_ERR(fd); } - pr_debug("%s: sk:%p, newsk:%p, sd:%d\n", __func__, sk, newsock->sk, - retval); - - peeloff->sd = retval; + newfile = sock_alloc_file(newsock, 0, NULL); + if (IS_ERR(newfile)) + return PTR_ERR(newfile); if (flags & SOCK_NONBLOCK) - (*newfile)->f_flags |= O_NONBLOCK; -out: - return retval; + newfile->f_flags |= O_NONBLOCK; + + peeloff->sd = fd_stage(fd, newfile); + pr_debug("%s: sk:%p, newsk:%p, sd:%d\n", __func__, sk, newsock->sk, + peeloff->sd); + return peeloff->sd; } static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval, int __user *optlen) { sctp_peeloff_arg_t peeloff; - struct file *newfile = NULL; - int retval = 0; + int retval; if (len < sizeof(sctp_peeloff_arg_t)) return -EINVAL; @@ -5791,24 +5786,17 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval if (copy_from_user(&peeloff, optval, len)) return -EFAULT; - retval = sctp_getsockopt_peeloff_common(sk, &peeloff, &newfile, 0); + retval = sctp_getsockopt_peeloff_common(sk, &peeloff, 0); if (retval < 0) - goto out; + return retval; /* Return the fd mapped to the new socket. */ - if (put_user(len, optlen)) { - fput(newfile); - put_unused_fd(retval); + if (put_user(len, optlen)) return -EFAULT; - } - if (copy_to_user(optval, &peeloff, len)) { - fput(newfile); - put_unused_fd(retval); + if (copy_to_user(optval, &peeloff, len)) return -EFAULT; - } - fd_install(retval, newfile); -out: + return retval; } @@ -5816,8 +5804,7 @@ static int sctp_getsockopt_peeloff_flags(struct sock *sk, int len, char __user *optval, int __user *optlen) { sctp_peeloff_flags_arg_t peeloff; - struct file *newfile = NULL; - int retval = 0; + int retval; if (len < sizeof(sctp_peeloff_flags_arg_t)) return -EINVAL; @@ -5826,24 +5813,17 @@ static int sctp_getsockopt_peeloff_flags(struct sock *sk, int len, return -EFAULT; retval = sctp_getsockopt_peeloff_common(sk, &peeloff.p_arg, - &newfile, peeloff.flags); + peeloff.flags); if (retval < 0) - goto out; + return retval; /* Return the fd mapped to the new socket. */ - if (put_user(len, optlen)) { - fput(newfile); - put_unused_fd(retval); + if (put_user(len, optlen)) return -EFAULT; - } - if (copy_to_user(optval, &peeloff, len)) { - fput(newfile); - put_unused_fd(retval); + if (copy_to_user(optval, &peeloff, len)) return -EFAULT; - } - fd_install(retval, newfile); -out: + return retval; } -- 2.53.0