|
@@ -30,7 +30,7 @@ unsigned int rxrpc_max_call_lifetime = 60 * HZ;
|
|
unsigned int rxrpc_dead_call_expiry = 2 * HZ;
|
|
unsigned int rxrpc_dead_call_expiry = 2 * HZ;
|
|
|
|
|
|
const char *const rxrpc_call_states[NR__RXRPC_CALL_STATES] = {
|
|
const char *const rxrpc_call_states[NR__RXRPC_CALL_STATES] = {
|
|
- [RXRPC_CALL_UNINITIALISED] = "Uninit",
|
|
|
|
|
|
+ [RXRPC_CALL_UNINITIALISED] = "Uninit ",
|
|
[RXRPC_CALL_CLIENT_AWAIT_CONN] = "ClWtConn",
|
|
[RXRPC_CALL_CLIENT_AWAIT_CONN] = "ClWtConn",
|
|
[RXRPC_CALL_CLIENT_SEND_REQUEST] = "ClSndReq",
|
|
[RXRPC_CALL_CLIENT_SEND_REQUEST] = "ClSndReq",
|
|
[RXRPC_CALL_CLIENT_AWAIT_REPLY] = "ClAwtRpl",
|
|
[RXRPC_CALL_CLIENT_AWAIT_REPLY] = "ClAwtRpl",
|
|
@@ -43,11 +43,16 @@ const char *const rxrpc_call_states[NR__RXRPC_CALL_STATES] = {
|
|
[RXRPC_CALL_SERVER_SEND_REPLY] = "SvSndRpl",
|
|
[RXRPC_CALL_SERVER_SEND_REPLY] = "SvSndRpl",
|
|
[RXRPC_CALL_SERVER_AWAIT_ACK] = "SvAwtACK",
|
|
[RXRPC_CALL_SERVER_AWAIT_ACK] = "SvAwtACK",
|
|
[RXRPC_CALL_COMPLETE] = "Complete",
|
|
[RXRPC_CALL_COMPLETE] = "Complete",
|
|
|
|
+ [RXRPC_CALL_DEAD] = "Dead ",
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const char *const rxrpc_call_completions[NR__RXRPC_CALL_COMPLETIONS] = {
|
|
|
|
+ [RXRPC_CALL_SUCCEEDED] = "Complete",
|
|
[RXRPC_CALL_SERVER_BUSY] = "SvBusy ",
|
|
[RXRPC_CALL_SERVER_BUSY] = "SvBusy ",
|
|
[RXRPC_CALL_REMOTELY_ABORTED] = "RmtAbort",
|
|
[RXRPC_CALL_REMOTELY_ABORTED] = "RmtAbort",
|
|
[RXRPC_CALL_LOCALLY_ABORTED] = "LocAbort",
|
|
[RXRPC_CALL_LOCALLY_ABORTED] = "LocAbort",
|
|
|
|
+ [RXRPC_CALL_LOCAL_ERROR] = "LocError",
|
|
[RXRPC_CALL_NETWORK_ERROR] = "NetError",
|
|
[RXRPC_CALL_NETWORK_ERROR] = "NetError",
|
|
- [RXRPC_CALL_DEAD] = "Dead ",
|
|
|
|
};
|
|
};
|
|
|
|
|
|
struct kmem_cache *rxrpc_call_jar;
|
|
struct kmem_cache *rxrpc_call_jar;
|
|
@@ -214,6 +219,7 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
|
|
{
|
|
{
|
|
struct rxrpc_call *call, *xcall;
|
|
struct rxrpc_call *call, *xcall;
|
|
struct rb_node *parent, **pp;
|
|
struct rb_node *parent, **pp;
|
|
|
|
+ const void *here = __builtin_return_address(0);
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
_enter("%p,%lx", rx, user_call_ID);
|
|
_enter("%p,%lx", rx, user_call_ID);
|
|
@@ -224,6 +230,9 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
|
|
return call;
|
|
return call;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ trace_rxrpc_call(call, 0, atomic_read(&call->usage), 0, here,
|
|
|
|
+ (const void *)user_call_ID);
|
|
|
|
+
|
|
/* Publish the call, even though it is incompletely set up as yet */
|
|
/* Publish the call, even though it is incompletely set up as yet */
|
|
call->user_call_ID = user_call_ID;
|
|
call->user_call_ID = user_call_ID;
|
|
__set_bit(RXRPC_CALL_HAS_USERID, &call->flags);
|
|
__set_bit(RXRPC_CALL_HAS_USERID, &call->flags);
|
|
@@ -303,6 +312,7 @@ struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *rx,
|
|
{
|
|
{
|
|
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
|
|
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
|
|
struct rxrpc_call *call, *candidate;
|
|
struct rxrpc_call *call, *candidate;
|
|
|
|
+ const void *here = __builtin_return_address(0);
|
|
u32 call_id, chan;
|
|
u32 call_id, chan;
|
|
|
|
|
|
_enter(",%d", conn->debug_id);
|
|
_enter(",%d", conn->debug_id);
|
|
@@ -313,6 +323,9 @@ struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *rx,
|
|
if (!candidate)
|
|
if (!candidate)
|
|
return ERR_PTR(-EBUSY);
|
|
return ERR_PTR(-EBUSY);
|
|
|
|
|
|
|
|
+ trace_rxrpc_call(candidate, 1, atomic_read(&candidate->usage),
|
|
|
|
+ 0, here, NULL);
|
|
|
|
+
|
|
chan = sp->hdr.cid & RXRPC_CHANNELMASK;
|
|
chan = sp->hdr.cid & RXRPC_CHANNELMASK;
|
|
candidate->socket = rx;
|
|
candidate->socket = rx;
|
|
candidate->conn = conn;
|
|
candidate->conn = conn;
|
|
@@ -358,7 +371,7 @@ struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *rx,
|
|
_debug("CALL: %u { %s }",
|
|
_debug("CALL: %u { %s }",
|
|
call->debug_id, rxrpc_call_states[call->state]);
|
|
call->debug_id, rxrpc_call_states[call->state]);
|
|
|
|
|
|
- if (call->state >= RXRPC_CALL_COMPLETE) {
|
|
|
|
|
|
+ if (call->state == RXRPC_CALL_COMPLETE) {
|
|
__rxrpc_disconnect_call(conn, call);
|
|
__rxrpc_disconnect_call(conn, call);
|
|
} else {
|
|
} else {
|
|
spin_unlock(&conn->channel_lock);
|
|
spin_unlock(&conn->channel_lock);
|
|
@@ -425,6 +438,44 @@ old_call:
|
|
return ERR_PTR(-ECONNRESET);
|
|
return ERR_PTR(-ECONNRESET);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Note the re-emergence of a call.
|
|
|
|
+ */
|
|
|
|
+void rxrpc_see_call(struct rxrpc_call *call)
|
|
|
|
+{
|
|
|
|
+ const void *here = __builtin_return_address(0);
|
|
|
|
+ if (call) {
|
|
|
|
+ int n = atomic_read(&call->usage);
|
|
|
|
+ int m = atomic_read(&call->skb_count);
|
|
|
|
+
|
|
|
|
+ trace_rxrpc_call(call, 2, n, m, here, 0);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Note the addition of a ref on a call.
|
|
|
|
+ */
|
|
|
|
+void rxrpc_get_call(struct rxrpc_call *call)
|
|
|
|
+{
|
|
|
|
+ const void *here = __builtin_return_address(0);
|
|
|
|
+ int n = atomic_inc_return(&call->usage);
|
|
|
|
+ int m = atomic_read(&call->skb_count);
|
|
|
|
+
|
|
|
|
+ trace_rxrpc_call(call, 3, n, m, here, 0);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Note the addition of a ref on a call for a socket buffer.
|
|
|
|
+ */
|
|
|
|
+void rxrpc_get_call_for_skb(struct rxrpc_call *call, struct sk_buff *skb)
|
|
|
|
+{
|
|
|
|
+ const void *here = __builtin_return_address(0);
|
|
|
|
+ int n = atomic_inc_return(&call->usage);
|
|
|
|
+ int m = atomic_inc_return(&call->skb_count);
|
|
|
|
+
|
|
|
|
+ trace_rxrpc_call(call, 4, n, m, here, skb);
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* detach a call from a socket and set up for release
|
|
* detach a call from a socket and set up for release
|
|
*/
|
|
*/
|
|
@@ -438,6 +489,8 @@ void rxrpc_release_call(struct rxrpc_call *call)
|
|
atomic_read(&call->ackr_not_idle),
|
|
atomic_read(&call->ackr_not_idle),
|
|
call->rx_first_oos);
|
|
call->rx_first_oos);
|
|
|
|
|
|
|
|
+ rxrpc_see_call(call);
|
|
|
|
+
|
|
spin_lock_bh(&call->lock);
|
|
spin_lock_bh(&call->lock);
|
|
if (test_and_set_bit(RXRPC_CALL_RELEASED, &call->flags))
|
|
if (test_and_set_bit(RXRPC_CALL_RELEASED, &call->flags))
|
|
BUG();
|
|
BUG();
|
|
@@ -472,8 +525,7 @@ void rxrpc_release_call(struct rxrpc_call *call)
|
|
if (call->state < RXRPC_CALL_COMPLETE &&
|
|
if (call->state < RXRPC_CALL_COMPLETE &&
|
|
call->state != RXRPC_CALL_CLIENT_FINAL_ACK) {
|
|
call->state != RXRPC_CALL_CLIENT_FINAL_ACK) {
|
|
_debug("+++ ABORTING STATE %d +++\n", call->state);
|
|
_debug("+++ ABORTING STATE %d +++\n", call->state);
|
|
- call->state = RXRPC_CALL_LOCALLY_ABORTED;
|
|
|
|
- call->local_abort = RX_CALL_DEAD;
|
|
|
|
|
|
+ __rxrpc_abort_call(call, RX_CALL_DEAD, ECONNRESET);
|
|
}
|
|
}
|
|
write_unlock_bh(&call->state_lock);
|
|
write_unlock_bh(&call->state_lock);
|
|
|
|
|
|
@@ -522,6 +574,7 @@ static void rxrpc_dead_call_expired(unsigned long _call)
|
|
|
|
|
|
_enter("{%d}", call->debug_id);
|
|
_enter("{%d}", call->debug_id);
|
|
|
|
|
|
|
|
+ rxrpc_see_call(call);
|
|
write_lock_bh(&call->state_lock);
|
|
write_lock_bh(&call->state_lock);
|
|
call->state = RXRPC_CALL_DEAD;
|
|
call->state = RXRPC_CALL_DEAD;
|
|
write_unlock_bh(&call->state_lock);
|
|
write_unlock_bh(&call->state_lock);
|
|
@@ -536,22 +589,16 @@ static void rxrpc_mark_call_released(struct rxrpc_call *call)
|
|
{
|
|
{
|
|
bool sched;
|
|
bool sched;
|
|
|
|
|
|
|
|
+ rxrpc_see_call(call);
|
|
write_lock(&call->state_lock);
|
|
write_lock(&call->state_lock);
|
|
if (call->state < RXRPC_CALL_DEAD) {
|
|
if (call->state < RXRPC_CALL_DEAD) {
|
|
- sched = false;
|
|
|
|
- if (call->state < RXRPC_CALL_COMPLETE) {
|
|
|
|
- _debug("abort call %p", call);
|
|
|
|
- call->state = RXRPC_CALL_LOCALLY_ABORTED;
|
|
|
|
- call->local_abort = RX_CALL_DEAD;
|
|
|
|
- if (!test_and_set_bit(RXRPC_CALL_EV_ABORT, &call->events))
|
|
|
|
- sched = true;
|
|
|
|
- }
|
|
|
|
|
|
+ sched = __rxrpc_abort_call(call, RX_CALL_DEAD, ECONNRESET);
|
|
if (!test_and_set_bit(RXRPC_CALL_EV_RELEASE, &call->events))
|
|
if (!test_and_set_bit(RXRPC_CALL_EV_RELEASE, &call->events))
|
|
sched = true;
|
|
sched = true;
|
|
- if (sched)
|
|
|
|
- rxrpc_queue_call(call);
|
|
|
|
}
|
|
}
|
|
write_unlock(&call->state_lock);
|
|
write_unlock(&call->state_lock);
|
|
|
|
+ if (sched)
|
|
|
|
+ rxrpc_queue_call(call);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -588,21 +635,43 @@ void rxrpc_release_calls_on_socket(struct rxrpc_sock *rx)
|
|
/*
|
|
/*
|
|
* release a call
|
|
* release a call
|
|
*/
|
|
*/
|
|
-void __rxrpc_put_call(struct rxrpc_call *call)
|
|
|
|
|
|
+void rxrpc_put_call(struct rxrpc_call *call)
|
|
{
|
|
{
|
|
- ASSERT(call != NULL);
|
|
|
|
|
|
+ const void *here = __builtin_return_address(0);
|
|
|
|
+ int n, m;
|
|
|
|
|
|
- _enter("%p{u=%d}", call, atomic_read(&call->usage));
|
|
|
|
|
|
+ ASSERT(call != NULL);
|
|
|
|
|
|
- ASSERTCMP(atomic_read(&call->usage), >, 0);
|
|
|
|
|
|
+ n = atomic_dec_return(&call->usage);
|
|
|
|
+ m = atomic_read(&call->skb_count);
|
|
|
|
+ trace_rxrpc_call(call, 5, n, m, here, NULL);
|
|
|
|
+ ASSERTCMP(n, >=, 0);
|
|
|
|
+ if (n == 0) {
|
|
|
|
+ _debug("call %d dead", call->debug_id);
|
|
|
|
+ WARN_ON(m != 0);
|
|
|
|
+ ASSERTCMP(call->state, ==, RXRPC_CALL_DEAD);
|
|
|
|
+ rxrpc_queue_work(&call->destroyer);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
- if (atomic_dec_and_test(&call->usage)) {
|
|
|
|
|
|
+/*
|
|
|
|
+ * Release a call ref held by a socket buffer.
|
|
|
|
+ */
|
|
|
|
+void rxrpc_put_call_for_skb(struct rxrpc_call *call, struct sk_buff *skb)
|
|
|
|
+{
|
|
|
|
+ const void *here = __builtin_return_address(0);
|
|
|
|
+ int n, m;
|
|
|
|
+
|
|
|
|
+ n = atomic_dec_return(&call->usage);
|
|
|
|
+ m = atomic_dec_return(&call->skb_count);
|
|
|
|
+ trace_rxrpc_call(call, 6, n, m, here, skb);
|
|
|
|
+ ASSERTCMP(n, >=, 0);
|
|
|
|
+ if (n == 0) {
|
|
_debug("call %d dead", call->debug_id);
|
|
_debug("call %d dead", call->debug_id);
|
|
- WARN_ON(atomic_read(&call->skb_count) != 0);
|
|
|
|
|
|
+ WARN_ON(m != 0);
|
|
ASSERTCMP(call->state, ==, RXRPC_CALL_DEAD);
|
|
ASSERTCMP(call->state, ==, RXRPC_CALL_DEAD);
|
|
rxrpc_queue_work(&call->destroyer);
|
|
rxrpc_queue_work(&call->destroyer);
|
|
}
|
|
}
|
|
- _leave("");
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -708,6 +777,7 @@ void __exit rxrpc_destroy_all_calls(void)
|
|
call = list_entry(rxrpc_calls.next, struct rxrpc_call, link);
|
|
call = list_entry(rxrpc_calls.next, struct rxrpc_call, link);
|
|
_debug("Zapping call %p", call);
|
|
_debug("Zapping call %p", call);
|
|
|
|
|
|
|
|
+ rxrpc_see_call(call);
|
|
list_del_init(&call->link);
|
|
list_del_init(&call->link);
|
|
|
|
|
|
switch (atomic_read(&call->usage)) {
|
|
switch (atomic_read(&call->usage)) {
|
|
@@ -749,16 +819,14 @@ static void rxrpc_call_life_expired(unsigned long _call)
|
|
{
|
|
{
|
|
struct rxrpc_call *call = (struct rxrpc_call *) _call;
|
|
struct rxrpc_call *call = (struct rxrpc_call *) _call;
|
|
|
|
|
|
|
|
+ _enter("{%d}", call->debug_id);
|
|
|
|
+
|
|
|
|
+ rxrpc_see_call(call);
|
|
if (call->state >= RXRPC_CALL_COMPLETE)
|
|
if (call->state >= RXRPC_CALL_COMPLETE)
|
|
return;
|
|
return;
|
|
|
|
|
|
- _enter("{%d}", call->debug_id);
|
|
|
|
- read_lock_bh(&call->state_lock);
|
|
|
|
- if (call->state < RXRPC_CALL_COMPLETE) {
|
|
|
|
- set_bit(RXRPC_CALL_EV_LIFE_TIMER, &call->events);
|
|
|
|
- rxrpc_queue_call(call);
|
|
|
|
- }
|
|
|
|
- read_unlock_bh(&call->state_lock);
|
|
|
|
|
|
+ set_bit(RXRPC_CALL_EV_LIFE_TIMER, &call->events);
|
|
|
|
+ rxrpc_queue_call(call);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -771,6 +839,7 @@ static void rxrpc_resend_time_expired(unsigned long _call)
|
|
|
|
|
|
_enter("{%d}", call->debug_id);
|
|
_enter("{%d}", call->debug_id);
|
|
|
|
|
|
|
|
+ rxrpc_see_call(call);
|
|
if (call->state >= RXRPC_CALL_COMPLETE)
|
|
if (call->state >= RXRPC_CALL_COMPLETE)
|
|
return;
|
|
return;
|
|
|
|
|
|
@@ -788,12 +857,10 @@ static void rxrpc_ack_time_expired(unsigned long _call)
|
|
|
|
|
|
_enter("{%d}", call->debug_id);
|
|
_enter("{%d}", call->debug_id);
|
|
|
|
|
|
|
|
+ rxrpc_see_call(call);
|
|
if (call->state >= RXRPC_CALL_COMPLETE)
|
|
if (call->state >= RXRPC_CALL_COMPLETE)
|
|
return;
|
|
return;
|
|
|
|
|
|
- read_lock_bh(&call->state_lock);
|
|
|
|
- if (call->state < RXRPC_CALL_COMPLETE &&
|
|
|
|
- !test_and_set_bit(RXRPC_CALL_EV_ACK, &call->events))
|
|
|
|
|
|
+ if (!test_and_set_bit(RXRPC_CALL_EV_ACK, &call->events))
|
|
rxrpc_queue_call(call);
|
|
rxrpc_queue_call(call);
|
|
- read_unlock_bh(&call->state_lock);
|
|
|
|
}
|
|
}
|