Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 23 additions & 14 deletions net/vmw_vsock/af_vsock.c
Original file line number Diff line number Diff line change
Expand Up @@ -479,20 +479,9 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk)
goto err;
}

if (vsk->transport) {
if (vsk->transport == new_transport) {
ret = 0;
goto err;
}

/* transport->release() must be called with sock lock acquired.
* This path can only be taken during vsock_connect(), where we
* have already held the sock lock. In the other cases, this
* function is called on a new socket which is not assigned to
* any transport.
*/
vsk->transport->release(vsk);
vsock_deassign_transport(vsk);
if (vsk->transport && vsk->transport == new_transport) {
ret = 0;
goto err;
}

/* We increase the module refcnt to prevent the transport unloading
Expand All @@ -509,6 +498,26 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk)
*/
mutex_unlock(&vsock_register_mutex);

if (vsk->transport) {
/* transport->release() must be called with sock lock acquired.
* This path can only be taken during vsock_connect(), where we
* have already held the sock lock. In the other cases, this
* function is called on a new socket which is not assigned to
* any transport.
*/
vsk->transport->release(vsk);
vsock_deassign_transport(vsk);

/* transport's release() and destruct() can touch some socket
* state, since we are reassigning the socket to a new transport
* during vsock_connect(), let's reset these fields to have a
* clean state.
*/
sock_reset_flag(sk, SOCK_DONE);
sk->sk_state = TCP_CLOSE;
vsk->peer_shutdown = 0;
}

if (sk->sk_type == SOCK_SEQPACKET) {
if (!new_transport->seqpacket_allow ||
!new_transport->seqpacket_allow(remote_cid)) {
Expand Down