Skip to content

Commit 3432a75

Browse files
committed
rxrpc: Fix prealloc refcounting
The preallocated call buffer holds a ref on the calls within that buffer. The ref was being released in the wrong place - it worked okay for incoming calls to the AFS cache manager service, but doesn't work right for incoming calls to a userspace service. Instead of releasing an extra ref service calls in rxrpc_release_call(), the ref needs to be released during the acceptance/rejectance process. To this end: (1) The prealloc ref is now normally released during rxrpc_new_incoming_call(). (2) For preallocated kernel API calls, the kernel API's ref needs to be released when the call is discarded on socket close. (3) We shouldn't take a second ref in rxrpc_accept_call(). (4) rxrpc_recvmsg_new_call() needs to get a ref of its own when it adds the call to the to_be_accepted socket queue. In doing (4) above, we would prefer not to put the call's refcount down to 0 as that entails doing cleanup in softirq context, but it's unlikely as there are several refs held elsewhere, at least one of which must be put by someone in process context calling rxrpc_release_call(). However, it's not a problem if we do have to do that. Signed-off-by: David Howells <[email protected]>
1 parent cbd0089 commit 3432a75

File tree

3 files changed

+9
-4
lines changed

3 files changed

+9
-4
lines changed

net/rxrpc/call_accept.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ void rxrpc_discard_prealloc(struct rxrpc_sock *rx)
221221
if (rx->discard_new_call) {
222222
_debug("discard %lx", call->user_call_ID);
223223
rx->discard_new_call(call, call->user_call_ID);
224+
rxrpc_put_call(call, rxrpc_call_put_kernel);
224225
}
225226
rxrpc_call_completed(call);
226227
rxrpc_release_call(rx, call);
@@ -402,6 +403,13 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
402403
if (call->state == RXRPC_CALL_SERVER_ACCEPTING)
403404
rxrpc_notify_socket(call);
404405

406+
/* We have to discard the prealloc queue's ref here and rely on a
407+
* combination of the RCU read lock and refs held either by the socket
408+
* (recvmsg queue, to-be-accepted queue or user ID tree) or the kernel
409+
* service to prevent the call from being deallocated too early.
410+
*/
411+
rxrpc_put_call(call, rxrpc_call_put);
412+
405413
_leave(" = %p{%d}", call, call->debug_id);
406414
out:
407415
spin_unlock(&rx->incoming_lock);
@@ -469,7 +477,6 @@ struct rxrpc_call *rxrpc_accept_call(struct rxrpc_sock *rx,
469477
}
470478

471479
/* formalise the acceptance */
472-
rxrpc_get_call(call, rxrpc_call_got);
473480
call->notify_rx = notify_rx;
474481
call->user_call_ID = user_call_ID;
475482
rxrpc_get_call(call, rxrpc_call_got_userid);

net/rxrpc/call_object.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -464,9 +464,6 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)
464464
call->rxtx_buffer[i] = NULL;
465465
}
466466

467-
/* We have to release the prealloc backlog ref */
468-
if (rxrpc_is_service_call(call))
469-
rxrpc_put_call(call, rxrpc_call_put);
470467
_leave("");
471468
}
472469

net/rxrpc/recvmsg.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ static int rxrpc_recvmsg_new_call(struct rxrpc_sock *rx,
118118
list_del_init(&call->recvmsg_link);
119119
write_unlock_bh(&rx->recvmsg_lock);
120120

121+
rxrpc_get_call(call, rxrpc_call_got);
121122
write_lock(&rx->call_lock);
122123
list_add_tail(&call->accept_link, &rx->to_be_accepted);
123124
write_unlock(&rx->call_lock);

0 commit comments

Comments
 (0)