summaryrefslogtreecommitdiff
path: root/net/rxrpc/conn_object.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2016-04-04 16:00:38 +0300
committerDavid Howells <dhowells@redhat.com>2016-07-06 12:43:51 +0300
commite653cfe49cec540529217933e07caf6c0f25ac93 (patch)
tree455d3e42c41388b7ebed523ed9b701db1ee0aeb9 /net/rxrpc/conn_object.c
parentd1e858c5a392a50c16ce36624203032bdeb3595b (diff)
downloadlinux-e653cfe49cec540529217933e07caf6c0f25ac93.tar.xz
rxrpc: Release a call's connection ref on call disconnection
When a call is disconnected, clear the call's pointer to the connection and release the associated ref on that connection. This means that the call no longer pins the connection and the connection can be discarded even before the call is. As the code currently stands, the call struct is effectively pinned by userspace until userspace has enacted a recvmsg() to retrieve the final call state as sk_buffs on the receive queue pin the call to which they're related because: (1) The rxrpc_call struct contains the userspace ID that recvmsg() has to include in the control message buffer to indicate which call is being referred to. This ID must remain valid until the terminal packet is completely read and must be invalidated immediately at that point as userspace is entitled to immediately reuse it. (2) The final ACK to the reply to a client call isn't sent until the last data packet is entirely read (it's probably worth altering this in future to be send the ACK as soon as all the data has been received). This change requires a bit of rearrangement to make sure that the call isn't going to try and access the connection again after protocol completion: (1) Delete the error link earlier when we're releasing the call. Possibly network errors should be distributed via connections at the cost of adding in an access to the rxrpc_connection struct. (2) Remove the call from the connection's call tree before disconnecting the call. The call tree needs to be removed anyway and incoming packets delivered by channel pointer instead. (3) The release call event should be considered last after all other events have been processed so that we don't need access to the connection again. (4) Move the channel_lock taking from rxrpc_release_call() to rxrpc_disconnect_call() where it will be required in future. Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'net/rxrpc/conn_object.c')
-rw-r--r--net/rxrpc/conn_object.c8
1 files changed, 8 insertions, 0 deletions
diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c
index 0e022dfab034..99d18107421f 100644
--- a/net/rxrpc/conn_object.c
+++ b/net/rxrpc/conn_object.c
@@ -540,11 +540,19 @@ void rxrpc_disconnect_call(struct rxrpc_call *call)
_enter("%d,%d", conn->debug_id, call->channel);
+ spin_lock(&conn->channel_lock);
+
if (conn->channels[chan] == call) {
rcu_assign_pointer(conn->channels[chan], NULL);
atomic_inc(&conn->avail_chans);
wake_up(&conn->channel_wq);
}
+
+ spin_unlock(&conn->channel_lock);
+
+ call->conn = NULL;
+ rxrpc_put_connection(conn);
+ _leave("");
}
/*