diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/rxrpc/call_event.c | 10 | ||||
-rw-r--r-- | net/rxrpc/call_object.c | 26 | ||||
-rw-r--r-- | net/rxrpc/conn_object.c | 8 |
3 files changed, 22 insertions, 22 deletions
diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c index 0ba8429..638d66d 100644 --- a/net/rxrpc/call_event.c +++ b/net/rxrpc/call_event.c @@ -858,11 +858,6 @@ void rxrpc_process_call(struct work_struct *work) iov[0].iov_len = sizeof(whdr); /* deal with events of a final nature */ - if (test_bit(RXRPC_CALL_EV_RELEASE, &call->events)) { - rxrpc_release_call(call); - clear_bit(RXRPC_CALL_EV_RELEASE, &call->events); - } - if (test_bit(RXRPC_CALL_EV_RCVD_ERROR, &call->events)) { enum rxrpc_skb_mark mark; int error; @@ -1144,6 +1139,11 @@ void rxrpc_process_call(struct work_struct *work) goto maybe_reschedule; } + if (test_bit(RXRPC_CALL_EV_RELEASE, &call->events)) { + rxrpc_release_call(call); + clear_bit(RXRPC_CALL_EV_RELEASE, &call->events); + } + /* other events may have been raised since we started checking */ goto maybe_reschedule; diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c index 6223a7e..b43d89c 100644 --- a/net/rxrpc/call_object.c +++ b/net/rxrpc/call_object.c @@ -628,6 +628,10 @@ void rxrpc_release_call(struct rxrpc_call *call) */ _debug("RELEASE CALL %p (%d CONN %p)", call, call->debug_id, conn); + spin_lock(&conn->params.peer->lock); + hlist_del_init(&call->error_link); + spin_unlock(&conn->params.peer->lock); + write_lock_bh(&rx->call_lock); if (!list_empty(&call->accept_link)) { _debug("unlinking once-pending call %p { e=%lx f=%lx }", @@ -643,25 +647,22 @@ void rxrpc_release_call(struct rxrpc_call *call) write_unlock_bh(&rx->call_lock); /* free up the channel for reuse */ - spin_lock(&conn->channel_lock); write_lock_bh(&conn->lock); write_lock(&call->state_lock); - rxrpc_disconnect_call(call); - - spin_unlock(&conn->channel_lock); - if (call->state < RXRPC_CALL_COMPLETE && call->state != RXRPC_CALL_CLIENT_FINAL_ACK) { _debug("+++ ABORTING STATE %d +++\n", call->state); call->state = RXRPC_CALL_LOCALLY_ABORTED; call->local_abort = RX_CALL_DEAD; - set_bit(RXRPC_CALL_EV_ABORT, &call->events); - rxrpc_queue_call(call); } write_unlock(&call->state_lock); + + rb_erase(&call->conn_node, &conn->calls); write_unlock_bh(&conn->lock); + rxrpc_disconnect_call(call); + /* clean up the Rx queue */ if (!skb_queue_empty(&call->rx_queue) || !skb_queue_empty(&call->rx_oos_queue)) { @@ -817,16 +818,7 @@ static void rxrpc_cleanup_call(struct rxrpc_call *call) return; } - if (call->conn) { - spin_lock(&call->conn->params.peer->lock); - hlist_del_init(&call->error_link); - spin_unlock(&call->conn->params.peer->lock); - - write_lock_bh(&call->conn->lock); - rb_erase(&call->conn_node, &call->conn->calls); - write_unlock_bh(&call->conn->lock); - rxrpc_put_connection(call->conn); - } + ASSERTCMP(call->conn, ==, NULL); /* Remove the call from the hash */ rxrpc_call_hash_del(call); diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c index 0e022df..99d1810 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(""); } /* |