diff --git a/net/rxrpc/call_accept.c b/net/rxrpc/call_accept.c index 5fd9d2c89b7f..26c293ef98eb 100644 --- a/net/rxrpc/call_accept.c +++ b/net/rxrpc/call_accept.c @@ -221,6 +221,7 @@ void rxrpc_discard_prealloc(struct rxrpc_sock *rx) if (rx->discard_new_call) { _debug("discard %lx", call->user_call_ID); rx->discard_new_call(call, call->user_call_ID); + rxrpc_put_call(call, rxrpc_call_put_kernel); } rxrpc_call_completed(call); rxrpc_release_call(rx, call); @@ -402,6 +403,13 @@ found_service: if (call->state == RXRPC_CALL_SERVER_ACCEPTING) rxrpc_notify_socket(call); + /* We have to discard the prealloc queue's ref here and rely on a + * combination of the RCU read lock and refs held either by the socket + * (recvmsg queue, to-be-accepted queue or user ID tree) or the kernel + * service to prevent the call from being deallocated too early. + */ + rxrpc_put_call(call, rxrpc_call_put); + _leave(" = %p{%d}", call, call->debug_id); out: spin_unlock(&rx->incoming_lock); @@ -469,7 +477,6 @@ struct rxrpc_call *rxrpc_accept_call(struct rxrpc_sock *rx, } /* formalise the acceptance */ - rxrpc_get_call(call, rxrpc_call_got); call->notify_rx = notify_rx; call->user_call_ID = user_call_ID; rxrpc_get_call(call, rxrpc_call_got_userid); diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c index 3f9476508204..9aa1c4b53563 100644 --- a/net/rxrpc/call_object.c +++ b/net/rxrpc/call_object.c @@ -464,9 +464,6 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call) call->rxtx_buffer[i] = NULL; } - /* We have to release the prealloc backlog ref */ - if (rxrpc_is_service_call(call)) - rxrpc_put_call(call, rxrpc_call_put); _leave(""); } diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c index 16ff56f69256..a284205b8ecf 100644 --- a/net/rxrpc/recvmsg.c +++ b/net/rxrpc/recvmsg.c @@ -118,6 +118,7 @@ static int rxrpc_recvmsg_new_call(struct rxrpc_sock *rx, list_del_init(&call->recvmsg_link); write_unlock_bh(&rx->recvmsg_lock); + rxrpc_get_call(call, rxrpc_call_got); write_lock(&rx->call_lock); list_add_tail(&call->accept_link, &rx->to_be_accepted); write_unlock(&rx->call_lock);