diff options
-rw-r--r-- | net/vmw_vsock/af_vsock.c | 116 |
1 files changed, 67 insertions, 49 deletions
diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index 4269e80b02cd..c4f6bfa1e381 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -1896,65 +1896,22 @@ static int vsock_wait_data(struct sock *sk, struct wait_queue_entry *wait, return data; } -static int -vsock_connectible_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, - int flags) +static int __vsock_stream_recvmsg(struct sock *sk, struct msghdr *msg, + size_t len, int flags) { - struct sock *sk; - struct vsock_sock *vsk; + struct vsock_transport_recv_notify_data recv_data; const struct vsock_transport *transport; - int err; - size_t target; + struct vsock_sock *vsk; ssize_t copied; + size_t target; long timeout; - struct vsock_transport_recv_notify_data recv_data; + int err; DEFINE_WAIT(wait); - sk = sock->sk; vsk = vsock_sk(sk); - err = 0; - - lock_sock(sk); - transport = vsk->transport; - if (!transport || sk->sk_state != TCP_ESTABLISHED) { - /* Recvmsg is supposed to return 0 if a peer performs an - * orderly shutdown. Differentiate between that case and when a - * peer has not connected or a local shutdown occurred with the - * SOCK_DONE flag. - */ - if (sock_flag(sk, SOCK_DONE)) - err = 0; - else - err = -ENOTCONN; - - goto out; - } - - if (flags & MSG_OOB) { - err = -EOPNOTSUPP; - goto out; - } - - /* We don't check peer_shutdown flag here since peer may actually shut - * down, but there can be data in the queue that a local socket can - * receive. - */ - if (sk->sk_shutdown & RCV_SHUTDOWN) { - err = 0; - goto out; - } - - /* It is valid on Linux to pass in a zero-length receive buffer. This - * is not an error. We may as well bail out now. - */ - if (!len) { - err = 0; - goto out; - } - /* We must not copy less than target bytes into the user's buffer * before returning successfully, so we wait for the consume queue to * have that much data to consume before dequeueing. Note that this @@ -2014,6 +1971,67 @@ vsock_connectible_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, err = copied; out: + return err; +} + +static int +vsock_connectible_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, + int flags) +{ + struct sock *sk; + struct vsock_sock *vsk; + const struct vsock_transport *transport; + int err; + + DEFINE_WAIT(wait); + + sk = sock->sk; + vsk = vsock_sk(sk); + err = 0; + + lock_sock(sk); + + transport = vsk->transport; + + if (!transport || sk->sk_state != TCP_ESTABLISHED) { + /* Recvmsg is supposed to return 0 if a peer performs an + * orderly shutdown. Differentiate between that case and when a + * peer has not connected or a local shutdown occurred with the + * SOCK_DONE flag. + */ + if (sock_flag(sk, SOCK_DONE)) + err = 0; + else + err = -ENOTCONN; + + goto out; + } + + if (flags & MSG_OOB) { + err = -EOPNOTSUPP; + goto out; + } + + /* We don't check peer_shutdown flag here since peer may actually shut + * down, but there can be data in the queue that a local socket can + * receive. + */ + if (sk->sk_shutdown & RCV_SHUTDOWN) { + err = 0; + goto out; + } + + /* It is valid on Linux to pass in a zero-length receive buffer. This + * is not an error. We may as well bail out now. + */ + if (!len) { + err = 0; + goto out; + } + + err = __vsock_stream_recvmsg(sk, msg, len, flags); + +out: release_sock(sk); return err; } |