net: add __sys_accept4_file() helper
This is identical to __sys_accept4(), except it takes a struct file instead of an fd, and it also allows passing in extra file->f_flags flags. The latter is done to support masking in O_NONBLOCK without manipulating the original file flags. No functional changes in this patch. Cc: netdev@vger.kernel.org Acked-by: David S. Miller <davem@davemloft.net> Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
Родитель
fcb323cc53
Коммит
de2ea4b64b
|
@ -392,6 +392,9 @@ extern int __sys_recvfrom(int fd, void __user *ubuf, size_t size,
|
|||
extern int __sys_sendto(int fd, void __user *buff, size_t len,
|
||||
unsigned int flags, struct sockaddr __user *addr,
|
||||
int addr_len);
|
||||
extern int __sys_accept4_file(struct file *file, unsigned file_flags,
|
||||
struct sockaddr __user *upeer_sockaddr,
|
||||
int __user *upeer_addrlen, int flags);
|
||||
extern int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
|
||||
int __user *upeer_addrlen, int flags);
|
||||
extern int __sys_socket(int family, int type, int protocol);
|
||||
|
|
65
net/socket.c
65
net/socket.c
|
@ -1690,24 +1690,13 @@ SYSCALL_DEFINE2(listen, int, fd, int, backlog)
|
|||
return __sys_listen(fd, backlog);
|
||||
}
|
||||
|
||||
/*
|
||||
* For accept, we attempt to create a new socket, set up the link
|
||||
* with the client, wake up the client, then return the new
|
||||
* connected fd. We collect the address of the connector in kernel
|
||||
* space and move it to user at the very end. This is unclean because
|
||||
* we open the socket then return an error.
|
||||
*
|
||||
* 1003.1g adds the ability to recvmsg() to query connection pending
|
||||
* status to recvmsg. We need to add that support in a way thats
|
||||
* clean when we restructure accept also.
|
||||
*/
|
||||
|
||||
int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
|
||||
int __user *upeer_addrlen, int flags)
|
||||
int __sys_accept4_file(struct file *file, unsigned file_flags,
|
||||
struct sockaddr __user *upeer_sockaddr,
|
||||
int __user *upeer_addrlen, int flags)
|
||||
{
|
||||
struct socket *sock, *newsock;
|
||||
struct file *newfile;
|
||||
int err, len, newfd, fput_needed;
|
||||
int err, len, newfd;
|
||||
struct sockaddr_storage address;
|
||||
|
||||
if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
|
||||
|
@ -1716,14 +1705,14 @@ int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
|
|||
if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
|
||||
flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
|
||||
|
||||
sock = sockfd_lookup_light(fd, &err, &fput_needed);
|
||||
sock = sock_from_file(file, &err);
|
||||
if (!sock)
|
||||
goto out;
|
||||
|
||||
err = -ENFILE;
|
||||
newsock = sock_alloc();
|
||||
if (!newsock)
|
||||
goto out_put;
|
||||
goto out;
|
||||
|
||||
newsock->type = sock->type;
|
||||
newsock->ops = sock->ops;
|
||||
|
@ -1738,20 +1727,21 @@ int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
|
|||
if (unlikely(newfd < 0)) {
|
||||
err = newfd;
|
||||
sock_release(newsock);
|
||||
goto out_put;
|
||||
goto out;
|
||||
}
|
||||
newfile = sock_alloc_file(newsock, flags, sock->sk->sk_prot_creator->name);
|
||||
if (IS_ERR(newfile)) {
|
||||
err = PTR_ERR(newfile);
|
||||
put_unused_fd(newfd);
|
||||
goto out_put;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = security_socket_accept(sock, newsock);
|
||||
if (err)
|
||||
goto out_fd;
|
||||
|
||||
err = sock->ops->accept(sock, newsock, sock->file->f_flags, false);
|
||||
err = sock->ops->accept(sock, newsock, sock->file->f_flags | file_flags,
|
||||
false);
|
||||
if (err < 0)
|
||||
goto out_fd;
|
||||
|
||||
|
@ -1772,15 +1762,42 @@ int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
|
|||
|
||||
fd_install(newfd, newfile);
|
||||
err = newfd;
|
||||
|
||||
out_put:
|
||||
fput_light(sock->file, fput_needed);
|
||||
out:
|
||||
return err;
|
||||
out_fd:
|
||||
fput(newfile);
|
||||
put_unused_fd(newfd);
|
||||
goto out_put;
|
||||
goto out;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* For accept, we attempt to create a new socket, set up the link
|
||||
* with the client, wake up the client, then return the new
|
||||
* connected fd. We collect the address of the connector in kernel
|
||||
* space and move it to user at the very end. This is unclean because
|
||||
* we open the socket then return an error.
|
||||
*
|
||||
* 1003.1g adds the ability to recvmsg() to query connection pending
|
||||
* status to recvmsg. We need to add that support in a way thats
|
||||
* clean when we restructure accept also.
|
||||
*/
|
||||
|
||||
int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
|
||||
int __user *upeer_addrlen, int flags)
|
||||
{
|
||||
int ret = -EBADF;
|
||||
struct fd f;
|
||||
|
||||
f = fdget(fd);
|
||||
if (f.file) {
|
||||
ret = __sys_accept4_file(f.file, 0, upeer_sockaddr,
|
||||
upeer_addrlen, flags);
|
||||
if (f.flags)
|
||||
fput(f.file);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
|
||||
|
|
Загрузка…
Ссылка в новой задаче