Commit 363deeab authored by David Howells's avatar David Howells

rxrpc: Add connection tracepoint and client conn state tracepoint

Add a pair of tracepoints, one to track rxrpc_connection struct ref
counting and the other to track the client connection cache state.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent a84a46d7
...@@ -16,6 +16,66 @@ ...@@ -16,6 +16,66 @@
#include <linux/tracepoint.h> #include <linux/tracepoint.h>
TRACE_EVENT(rxrpc_conn,
TP_PROTO(struct rxrpc_connection *conn, enum rxrpc_conn_trace op,
int usage, const void *where),
TP_ARGS(conn, op, usage, where),
TP_STRUCT__entry(
__field(struct rxrpc_connection *, conn )
__field(int, op )
__field(int, usage )
__field(const void *, where )
),
TP_fast_assign(
__entry->conn = conn;
__entry->op = op;
__entry->usage = usage;
__entry->where = where;
),
TP_printk("C=%p %s u=%d sp=%pSR",
__entry->conn,
rxrpc_conn_traces[__entry->op],
__entry->usage,
__entry->where)
);
TRACE_EVENT(rxrpc_client,
TP_PROTO(struct rxrpc_connection *conn, int channel,
enum rxrpc_client_trace op),
TP_ARGS(conn, channel, op),
TP_STRUCT__entry(
__field(struct rxrpc_connection *, conn )
__field(u32, cid )
__field(int, channel )
__field(int, usage )
__field(enum rxrpc_client_trace, op )
__field(enum rxrpc_conn_cache_state, cs )
),
TP_fast_assign(
__entry->conn = conn;
__entry->channel = channel;
__entry->usage = atomic_read(&conn->usage);
__entry->op = op;
__entry->cid = conn->proto.cid;
__entry->cs = conn->cache_state;
),
TP_printk("C=%p h=%2d %s %s i=%08x u=%d",
__entry->conn,
__entry->channel,
rxrpc_client_traces[__entry->op],
rxrpc_conn_cache_states[__entry->cs],
__entry->cid,
__entry->usage)
);
TRACE_EVENT(rxrpc_call, TRACE_EVENT(rxrpc_call,
TP_PROTO(struct rxrpc_call *call, enum rxrpc_call_trace op, TP_PROTO(struct rxrpc_call *call, enum rxrpc_call_trace op,
int usage, const void *where, const void *aux), int usage, const void *where, const void *aux),
......
...@@ -314,6 +314,7 @@ enum rxrpc_conn_cache_state { ...@@ -314,6 +314,7 @@ enum rxrpc_conn_cache_state {
RXRPC_CONN_CLIENT_ACTIVE, /* Conn is on active list, doing calls */ RXRPC_CONN_CLIENT_ACTIVE, /* Conn is on active list, doing calls */
RXRPC_CONN_CLIENT_CULLED, /* Conn is culled and delisted, doing calls */ RXRPC_CONN_CLIENT_CULLED, /* Conn is culled and delisted, doing calls */
RXRPC_CONN_CLIENT_IDLE, /* Conn is on idle list, doing mostly nothing */ RXRPC_CONN_CLIENT_IDLE, /* Conn is on idle list, doing mostly nothing */
RXRPC_CONN__NR_CACHE_STATES
}; };
/* /*
...@@ -533,6 +534,44 @@ struct rxrpc_call { ...@@ -533,6 +534,44 @@ struct rxrpc_call {
rxrpc_serial_t acks_latest; /* serial number of latest ACK received */ rxrpc_serial_t acks_latest; /* serial number of latest ACK received */
}; };
enum rxrpc_conn_trace {
rxrpc_conn_new_client,
rxrpc_conn_new_service,
rxrpc_conn_queued,
rxrpc_conn_seen,
rxrpc_conn_got,
rxrpc_conn_put_client,
rxrpc_conn_put_service,
rxrpc_conn__nr_trace
};
extern const char rxrpc_conn_traces[rxrpc_conn__nr_trace][4];
enum rxrpc_client_trace {
rxrpc_client_activate_chans,
rxrpc_client_alloc,
rxrpc_client_chan_activate,
rxrpc_client_chan_disconnect,
rxrpc_client_chan_pass,
rxrpc_client_chan_unstarted,
rxrpc_client_cleanup,
rxrpc_client_count,
rxrpc_client_discard,
rxrpc_client_duplicate,
rxrpc_client_exposed,
rxrpc_client_replace,
rxrpc_client_to_active,
rxrpc_client_to_culled,
rxrpc_client_to_idle,
rxrpc_client_to_inactive,
rxrpc_client_to_waiting,
rxrpc_client_uncount,
rxrpc_client__nr_trace
};
extern const char rxrpc_client_traces[rxrpc_client__nr_trace][7];
extern const char rxrpc_conn_cache_states[RXRPC_CONN__NR_CACHE_STATES][5];
enum rxrpc_call_trace { enum rxrpc_call_trace {
rxrpc_call_new_client, rxrpc_call_new_client,
rxrpc_call_new_service, rxrpc_call_new_service,
...@@ -734,7 +773,11 @@ struct rxrpc_connection *rxrpc_find_connection_rcu(struct rxrpc_local *, ...@@ -734,7 +773,11 @@ struct rxrpc_connection *rxrpc_find_connection_rcu(struct rxrpc_local *,
void __rxrpc_disconnect_call(struct rxrpc_connection *, struct rxrpc_call *); void __rxrpc_disconnect_call(struct rxrpc_connection *, struct rxrpc_call *);
void rxrpc_disconnect_call(struct rxrpc_call *); void rxrpc_disconnect_call(struct rxrpc_call *);
void rxrpc_kill_connection(struct rxrpc_connection *); void rxrpc_kill_connection(struct rxrpc_connection *);
void __rxrpc_put_connection(struct rxrpc_connection *); bool rxrpc_queue_conn(struct rxrpc_connection *);
void rxrpc_see_connection(struct rxrpc_connection *);
void rxrpc_get_connection(struct rxrpc_connection *);
struct rxrpc_connection *rxrpc_get_connection_maybe(struct rxrpc_connection *);
void rxrpc_put_service_conn(struct rxrpc_connection *);
void __exit rxrpc_destroy_all_connections(void); void __exit rxrpc_destroy_all_connections(void);
static inline bool rxrpc_conn_is_client(const struct rxrpc_connection *conn) static inline bool rxrpc_conn_is_client(const struct rxrpc_connection *conn)
...@@ -747,38 +790,15 @@ static inline bool rxrpc_conn_is_service(const struct rxrpc_connection *conn) ...@@ -747,38 +790,15 @@ static inline bool rxrpc_conn_is_service(const struct rxrpc_connection *conn)
return !rxrpc_conn_is_client(conn); return !rxrpc_conn_is_client(conn);
} }
static inline void rxrpc_get_connection(struct rxrpc_connection *conn)
{
atomic_inc(&conn->usage);
}
static inline
struct rxrpc_connection *rxrpc_get_connection_maybe(struct rxrpc_connection *conn)
{
return atomic_inc_not_zero(&conn->usage) ? conn : NULL;
}
static inline void rxrpc_put_connection(struct rxrpc_connection *conn) static inline void rxrpc_put_connection(struct rxrpc_connection *conn)
{ {
if (!conn) if (!conn)
return; return;
if (rxrpc_conn_is_client(conn)) { if (rxrpc_conn_is_client(conn))
if (atomic_dec_and_test(&conn->usage)) rxrpc_put_client_conn(conn);
rxrpc_put_client_conn(conn); else
} else { rxrpc_put_service_conn(conn);
if (atomic_dec_return(&conn->usage) == 1)
__rxrpc_put_connection(conn);
}
}
static inline bool rxrpc_queue_conn(struct rxrpc_connection *conn)
{
if (!rxrpc_get_connection_maybe(conn))
return false;
if (!rxrpc_queue_work(&conn->processor))
rxrpc_put_connection(conn);
return true;
} }
/* /*
......
...@@ -85,6 +85,9 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx, ...@@ -85,6 +85,9 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
b->conn_backlog[head] = conn; b->conn_backlog[head] = conn;
smp_store_release(&b->conn_backlog_head, smp_store_release(&b->conn_backlog_head,
(head + 1) & (size - 1)); (head + 1) & (size - 1));
trace_rxrpc_conn(conn, rxrpc_conn_new_service,
atomic_read(&conn->usage), here);
} }
/* Now it gets complicated, because calls get registered with the /* Now it gets complicated, because calls get registered with the
...@@ -290,6 +293,7 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx, ...@@ -290,6 +293,7 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx,
rxrpc_get_local(local); rxrpc_get_local(local);
conn->params.local = local; conn->params.local = local;
conn->params.peer = peer; conn->params.peer = peer;
rxrpc_see_connection(conn);
rxrpc_new_incoming_connection(conn, skb); rxrpc_new_incoming_connection(conn, skb);
} else { } else {
rxrpc_get_connection(conn); rxrpc_get_connection(conn);
......
...@@ -479,8 +479,6 @@ void rxrpc_release_calls_on_socket(struct rxrpc_sock *rx) ...@@ -479,8 +479,6 @@ void rxrpc_release_calls_on_socket(struct rxrpc_sock *rx)
struct rxrpc_call, accept_link); struct rxrpc_call, accept_link);
list_del(&call->accept_link); list_del(&call->accept_link);
rxrpc_abort_call("SKR", call, 0, RX_CALL_DEAD, ECONNRESET); rxrpc_abort_call("SKR", call, 0, RX_CALL_DEAD, ECONNRESET);
rxrpc_send_call_packet(call, RXRPC_PACKET_TYPE_ABORT);
rxrpc_release_call(rx, call);
rxrpc_put_call(call, rxrpc_call_put); rxrpc_put_call(call, rxrpc_call_put);
} }
......
...@@ -105,6 +105,14 @@ static void rxrpc_discard_expired_client_conns(struct work_struct *); ...@@ -105,6 +105,14 @@ static void rxrpc_discard_expired_client_conns(struct work_struct *);
static DECLARE_DELAYED_WORK(rxrpc_client_conn_reap, static DECLARE_DELAYED_WORK(rxrpc_client_conn_reap,
rxrpc_discard_expired_client_conns); rxrpc_discard_expired_client_conns);
const char rxrpc_conn_cache_states[RXRPC_CONN__NR_CACHE_STATES][5] = {
[RXRPC_CONN_CLIENT_INACTIVE] = "Inac",
[RXRPC_CONN_CLIENT_WAITING] = "Wait",
[RXRPC_CONN_CLIENT_ACTIVE] = "Actv",
[RXRPC_CONN_CLIENT_CULLED] = "Cull",
[RXRPC_CONN_CLIENT_IDLE] = "Idle",
};
/* /*
* Get a connection ID and epoch for a client connection from the global pool. * Get a connection ID and epoch for a client connection from the global pool.
* The connection struct pointer is then recorded in the idr radix tree. The * The connection struct pointer is then recorded in the idr radix tree. The
...@@ -220,6 +228,9 @@ rxrpc_alloc_client_connection(struct rxrpc_conn_parameters *cp, gfp_t gfp) ...@@ -220,6 +228,9 @@ rxrpc_alloc_client_connection(struct rxrpc_conn_parameters *cp, gfp_t gfp)
rxrpc_get_local(conn->params.local); rxrpc_get_local(conn->params.local);
key_get(conn->params.key); key_get(conn->params.key);
trace_rxrpc_conn(conn, rxrpc_conn_new_client, atomic_read(&conn->usage),
__builtin_return_address(0));
trace_rxrpc_client(conn, -1, rxrpc_client_alloc);
_leave(" = %p", conn); _leave(" = %p", conn);
return conn; return conn;
...@@ -385,6 +396,7 @@ static int rxrpc_get_client_conn(struct rxrpc_call *call, ...@@ -385,6 +396,7 @@ static int rxrpc_get_client_conn(struct rxrpc_call *call,
rb_replace_node(&conn->client_node, rb_replace_node(&conn->client_node,
&candidate->client_node, &candidate->client_node,
&local->client_conns); &local->client_conns);
trace_rxrpc_client(conn, -1, rxrpc_client_replace);
goto candidate_published; goto candidate_published;
} }
} }
...@@ -409,8 +421,11 @@ static int rxrpc_get_client_conn(struct rxrpc_call *call, ...@@ -409,8 +421,11 @@ static int rxrpc_get_client_conn(struct rxrpc_call *call,
_debug("found conn"); _debug("found conn");
spin_unlock(&local->client_conns_lock); spin_unlock(&local->client_conns_lock);
rxrpc_put_connection(candidate); if (candidate) {
candidate = NULL; trace_rxrpc_client(candidate, -1, rxrpc_client_duplicate);
rxrpc_put_connection(candidate);
candidate = NULL;
}
spin_lock(&conn->channel_lock); spin_lock(&conn->channel_lock);
call->conn = conn; call->conn = conn;
...@@ -433,6 +448,7 @@ static int rxrpc_get_client_conn(struct rxrpc_call *call, ...@@ -433,6 +448,7 @@ static int rxrpc_get_client_conn(struct rxrpc_call *call,
*/ */
static void rxrpc_activate_conn(struct rxrpc_connection *conn) static void rxrpc_activate_conn(struct rxrpc_connection *conn)
{ {
trace_rxrpc_client(conn, -1, rxrpc_client_to_active);
conn->cache_state = RXRPC_CONN_CLIENT_ACTIVE; conn->cache_state = RXRPC_CONN_CLIENT_ACTIVE;
rxrpc_nr_active_client_conns++; rxrpc_nr_active_client_conns++;
list_move_tail(&conn->cache_link, &rxrpc_active_client_conns); list_move_tail(&conn->cache_link, &rxrpc_active_client_conns);
...@@ -462,8 +478,10 @@ static void rxrpc_animate_client_conn(struct rxrpc_connection *conn) ...@@ -462,8 +478,10 @@ static void rxrpc_animate_client_conn(struct rxrpc_connection *conn)
spin_lock(&rxrpc_client_conn_cache_lock); spin_lock(&rxrpc_client_conn_cache_lock);
nr_conns = rxrpc_nr_client_conns; nr_conns = rxrpc_nr_client_conns;
if (!test_and_set_bit(RXRPC_CONN_COUNTED, &conn->flags)) if (!test_and_set_bit(RXRPC_CONN_COUNTED, &conn->flags)) {
trace_rxrpc_client(conn, -1, rxrpc_client_count);
rxrpc_nr_client_conns = nr_conns + 1; rxrpc_nr_client_conns = nr_conns + 1;
}
switch (conn->cache_state) { switch (conn->cache_state) {
case RXRPC_CONN_CLIENT_ACTIVE: case RXRPC_CONN_CLIENT_ACTIVE:
...@@ -494,6 +512,7 @@ static void rxrpc_animate_client_conn(struct rxrpc_connection *conn) ...@@ -494,6 +512,7 @@ static void rxrpc_animate_client_conn(struct rxrpc_connection *conn)
wait_for_capacity: wait_for_capacity:
_debug("wait"); _debug("wait");
trace_rxrpc_client(conn, -1, rxrpc_client_to_waiting);
conn->cache_state = RXRPC_CONN_CLIENT_WAITING; conn->cache_state = RXRPC_CONN_CLIENT_WAITING;
list_move_tail(&conn->cache_link, &rxrpc_waiting_client_conns); list_move_tail(&conn->cache_link, &rxrpc_waiting_client_conns);
goto out_unlock; goto out_unlock;
...@@ -524,6 +543,8 @@ static void rxrpc_activate_one_channel(struct rxrpc_connection *conn, ...@@ -524,6 +543,8 @@ static void rxrpc_activate_one_channel(struct rxrpc_connection *conn,
struct rxrpc_call, chan_wait_link); struct rxrpc_call, chan_wait_link);
u32 call_id = chan->call_counter + 1; u32 call_id = chan->call_counter + 1;
trace_rxrpc_client(conn, channel, rxrpc_client_chan_activate);
write_lock_bh(&call->state_lock); write_lock_bh(&call->state_lock);
call->state = RXRPC_CALL_CLIENT_SEND_REQUEST; call->state = RXRPC_CALL_CLIENT_SEND_REQUEST;
write_unlock_bh(&call->state_lock); write_unlock_bh(&call->state_lock);
...@@ -563,6 +584,8 @@ static void rxrpc_activate_channels(struct rxrpc_connection *conn) ...@@ -563,6 +584,8 @@ static void rxrpc_activate_channels(struct rxrpc_connection *conn)
_enter("%d", conn->debug_id); _enter("%d", conn->debug_id);
trace_rxrpc_client(conn, -1, rxrpc_client_activate_chans);
if (conn->cache_state != RXRPC_CONN_CLIENT_ACTIVE || if (conn->cache_state != RXRPC_CONN_CLIENT_ACTIVE ||
conn->active_chans == RXRPC_ACTIVE_CHANS_MASK) conn->active_chans == RXRPC_ACTIVE_CHANS_MASK)
return; return;
...@@ -657,10 +680,13 @@ int rxrpc_connect_call(struct rxrpc_call *call, ...@@ -657,10 +680,13 @@ int rxrpc_connect_call(struct rxrpc_call *call,
* had a chance at re-use (the per-connection security negotiation is * had a chance at re-use (the per-connection security negotiation is
* expensive). * expensive).
*/ */
static void rxrpc_expose_client_conn(struct rxrpc_connection *conn) static void rxrpc_expose_client_conn(struct rxrpc_connection *conn,
unsigned int channel)
{ {
if (!test_and_set_bit(RXRPC_CONN_EXPOSED, &conn->flags)) if (!test_and_set_bit(RXRPC_CONN_EXPOSED, &conn->flags)) {
trace_rxrpc_client(conn, channel, rxrpc_client_exposed);
rxrpc_get_connection(conn); rxrpc_get_connection(conn);
}
} }
/* /*
...@@ -669,9 +695,9 @@ static void rxrpc_expose_client_conn(struct rxrpc_connection *conn) ...@@ -669,9 +695,9 @@ static void rxrpc_expose_client_conn(struct rxrpc_connection *conn)
*/ */
void rxrpc_expose_client_call(struct rxrpc_call *call) void rxrpc_expose_client_call(struct rxrpc_call *call)
{ {
unsigned int channel = call->cid & RXRPC_CHANNELMASK;
struct rxrpc_connection *conn = call->conn; struct rxrpc_connection *conn = call->conn;
struct rxrpc_channel *chan = struct rxrpc_channel *chan = &conn->channels[channel];
&conn->channels[call->cid & RXRPC_CHANNELMASK];
if (!test_and_set_bit(RXRPC_CALL_EXPOSED, &call->flags)) { if (!test_and_set_bit(RXRPC_CALL_EXPOSED, &call->flags)) {
/* Mark the call ID as being used. If the callNumber counter /* Mark the call ID as being used. If the callNumber counter
...@@ -682,7 +708,7 @@ void rxrpc_expose_client_call(struct rxrpc_call *call) ...@@ -682,7 +708,7 @@ void rxrpc_expose_client_call(struct rxrpc_call *call)
chan->call_counter++; chan->call_counter++;
if (chan->call_counter >= INT_MAX) if (chan->call_counter >= INT_MAX)
set_bit(RXRPC_CONN_DONT_REUSE, &conn->flags); set_bit(RXRPC_CONN_DONT_REUSE, &conn->flags);
rxrpc_expose_client_conn(conn); rxrpc_expose_client_conn(conn, channel);
} }
} }
...@@ -695,6 +721,7 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *call) ...@@ -695,6 +721,7 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *call)
struct rxrpc_connection *conn = call->conn; struct rxrpc_connection *conn = call->conn;
struct rxrpc_channel *chan = &conn->channels[channel]; struct rxrpc_channel *chan = &conn->channels[channel];
trace_rxrpc_client(conn, channel, rxrpc_client_chan_disconnect);
call->conn = NULL; call->conn = NULL;
spin_lock(&conn->channel_lock); spin_lock(&conn->channel_lock);
...@@ -709,6 +736,8 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *call) ...@@ -709,6 +736,8 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *call)
ASSERT(!test_bit(RXRPC_CALL_EXPOSED, &call->flags)); ASSERT(!test_bit(RXRPC_CALL_EXPOSED, &call->flags));
list_del_init(&call->chan_wait_link); list_del_init(&call->chan_wait_link);
trace_rxrpc_client(conn, channel, rxrpc_client_chan_unstarted);
/* We must deactivate or idle the connection if it's now /* We must deactivate or idle the connection if it's now
* waiting for nothing. * waiting for nothing.
*/ */
...@@ -739,7 +768,7 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *call) ...@@ -739,7 +768,7 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *call)
/* See if we can pass the channel directly to another call. */ /* See if we can pass the channel directly to another call. */
if (conn->cache_state == RXRPC_CONN_CLIENT_ACTIVE && if (conn->cache_state == RXRPC_CONN_CLIENT_ACTIVE &&
!list_empty(&conn->waiting_calls)) { !list_empty(&conn->waiting_calls)) {
_debug("pass chan"); trace_rxrpc_client(conn, channel, rxrpc_client_chan_pass);
rxrpc_activate_one_channel(conn, channel); rxrpc_activate_one_channel(conn, channel);
goto out_2; goto out_2;
} }
...@@ -762,7 +791,7 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *call) ...@@ -762,7 +791,7 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *call)
goto out; goto out;
} }
_debug("pass chan 2"); trace_rxrpc_client(conn, channel, rxrpc_client_chan_pass);
rxrpc_activate_one_channel(conn, channel); rxrpc_activate_one_channel(conn, channel);
goto out; goto out;
...@@ -794,7 +823,7 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *call) ...@@ -794,7 +823,7 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *call)
* immediately or moved to the idle list for a short while. * immediately or moved to the idle list for a short while.
*/ */
if (test_bit(RXRPC_CONN_EXPOSED, &conn->flags)) { if (test_bit(RXRPC_CONN_EXPOSED, &conn->flags)) {
_debug("make idle"); trace_rxrpc_client(conn, channel, rxrpc_client_to_idle);
conn->idle_timestamp = jiffies; conn->idle_timestamp = jiffies;
conn->cache_state = RXRPC_CONN_CLIENT_IDLE; conn->cache_state = RXRPC_CONN_CLIENT_IDLE;
list_move_tail(&conn->cache_link, &rxrpc_idle_client_conns); list_move_tail(&conn->cache_link, &rxrpc_idle_client_conns);
...@@ -804,7 +833,7 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *call) ...@@ -804,7 +833,7 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *call)
&rxrpc_client_conn_reap, &rxrpc_client_conn_reap,
rxrpc_conn_idle_client_expiry); rxrpc_conn_idle_client_expiry);
} else { } else {
_debug("make inactive"); trace_rxrpc_client(conn, channel, rxrpc_client_to_inactive);
conn->cache_state = RXRPC_CONN_CLIENT_INACTIVE; conn->cache_state = RXRPC_CONN_CLIENT_INACTIVE;
list_del_init(&conn->cache_link); list_del_init(&conn->cache_link);
} }
...@@ -821,6 +850,8 @@ rxrpc_put_one_client_conn(struct rxrpc_connection *conn) ...@@ -821,6 +850,8 @@ rxrpc_put_one_client_conn(struct rxrpc_connection *conn)
struct rxrpc_local *local = conn->params.local; struct rxrpc_local *local = conn->params.local;
unsigned int nr_conns; unsigned int nr_conns;
trace_rxrpc_client(conn, -1, rxrpc_client_cleanup);
if (test_bit(RXRPC_CONN_IN_CLIENT_CONNS, &conn->flags)) { if (test_bit(RXRPC_CONN_IN_CLIENT_CONNS, &conn->flags)) {
spin_lock(&local->client_conns_lock); spin_lock(&local->client_conns_lock);
if (test_and_clear_bit(RXRPC_CONN_IN_CLIENT_CONNS, if (test_and_clear_bit(RXRPC_CONN_IN_CLIENT_CONNS,
...@@ -834,6 +865,7 @@ rxrpc_put_one_client_conn(struct rxrpc_connection *conn) ...@@ -834,6 +865,7 @@ rxrpc_put_one_client_conn(struct rxrpc_connection *conn)
ASSERTCMP(conn->cache_state, ==, RXRPC_CONN_CLIENT_INACTIVE); ASSERTCMP(conn->cache_state, ==, RXRPC_CONN_CLIENT_INACTIVE);
if (test_bit(RXRPC_CONN_COUNTED, &conn->flags)) { if (test_bit(RXRPC_CONN_COUNTED, &conn->flags)) {
trace_rxrpc_client(conn, -1, rxrpc_client_uncount);
spin_lock(&rxrpc_client_conn_cache_lock); spin_lock(&rxrpc_client_conn_cache_lock);
nr_conns = --rxrpc_nr_client_conns; nr_conns = --rxrpc_nr_client_conns;
...@@ -863,20 +895,18 @@ rxrpc_put_one_client_conn(struct rxrpc_connection *conn) ...@@ -863,20 +895,18 @@ rxrpc_put_one_client_conn(struct rxrpc_connection *conn)
*/ */
void rxrpc_put_client_conn(struct rxrpc_connection *conn) void rxrpc_put_client_conn(struct rxrpc_connection *conn)
{ {
struct rxrpc_connection *next; const void *here = __builtin_return_address(0);
int n;
do { do {
_enter("%p{u=%d,d=%d}", n = atomic_dec_return(&conn->usage);
conn, atomic_read(&conn->usage), conn->debug_id); trace_rxrpc_conn(conn, rxrpc_conn_put_client, n, here);
if (n > 0)
next = rxrpc_put_one_client_conn(conn); return;
ASSERTCMP(n, >=, 0);
if (!next)
break; conn = rxrpc_put_one_client_conn(conn);
conn = next; } while (conn);
} while (atomic_dec_and_test(&conn->usage));
_leave("");
} }
/* /*
...@@ -907,9 +937,11 @@ static void rxrpc_cull_active_client_conns(void) ...@@ -907,9 +937,11 @@ static void rxrpc_cull_active_client_conns(void)
ASSERTCMP(conn->cache_state, ==, RXRPC_CONN_CLIENT_ACTIVE); ASSERTCMP(conn->cache_state, ==, RXRPC_CONN_CLIENT_ACTIVE);
if (list_empty(&conn->waiting_calls)) { if (list_empty(&conn->waiting_calls)) {
trace_rxrpc_client(conn, -1, rxrpc_client_to_culled);
conn->cache_state = RXRPC_CONN_CLIENT_CULLED; conn->cache_state = RXRPC_CONN_CLIENT_CULLED;
list_del_init(&conn->cache_link); list_del_init(&conn->cache_link);
} else { } else {
trace_rxrpc_client(conn, -1, rxrpc_client_to_waiting);
conn->cache_state = RXRPC_CONN_CLIENT_WAITING; conn->cache_state = RXRPC_CONN_CLIENT_WAITING;
list_move_tail(&conn->cache_link, list_move_tail(&conn->cache_link,
&rxrpc_waiting_client_conns); &rxrpc_waiting_client_conns);
...@@ -983,7 +1015,7 @@ static void rxrpc_discard_expired_client_conns(struct work_struct *work) ...@@ -983,7 +1015,7 @@ static void rxrpc_discard_expired_client_conns(struct work_struct *work)
goto not_yet_expired; goto not_yet_expired;
} }
_debug("discard conn %d", conn->debug_id); trace_rxrpc_client(conn, -1, rxrpc_client_discard);
if (!test_and_clear_bit(RXRPC_CONN_EXPOSED, &conn->flags)) if (!test_and_clear_bit(RXRPC_CONN_EXPOSED, &conn->flags))
BUG(); BUG();
conn->cache_state = RXRPC_CONN_CLIENT_INACTIVE; conn->cache_state = RXRPC_CONN_CLIENT_INACTIVE;
......
...@@ -377,7 +377,7 @@ void rxrpc_process_connection(struct work_struct *work) ...@@ -377,7 +377,7 @@ void rxrpc_process_connection(struct work_struct *work)
u32 abort_code = RX_PROTOCOL_ERROR; u32 abort_code = RX_PROTOCOL_ERROR;
int ret; int ret;
_enter("{%d}", conn->debug_id); rxrpc_see_connection(conn);
if (test_and_clear_bit(RXRPC_CONN_EV_CHALLENGE, &conn->events)) if (test_and_clear_bit(RXRPC_CONN_EV_CHALLENGE, &conn->events))
rxrpc_secure_connection(conn); rxrpc_secure_connection(conn);
......
...@@ -246,11 +246,77 @@ void rxrpc_kill_connection(struct rxrpc_connection *conn) ...@@ -246,11 +246,77 @@ void rxrpc_kill_connection(struct rxrpc_connection *conn)
} }
/* /*
* release a virtual connection * Queue a connection's work processor, getting a ref to pass to the work
* queue.
*/ */
void __rxrpc_put_connection(struct rxrpc_connection *conn) bool rxrpc_queue_conn(struct rxrpc_connection *conn)
{ {
rxrpc_queue_delayed_work(&rxrpc_connection_reap, 0); const void *here = __builtin_return_address(0);
int n = __atomic_add_unless(&conn->usage, 1, 0);
if (n == 0)
return false;
if (rxrpc_queue_work(&conn->processor))
trace_rxrpc_conn(conn, rxrpc_conn_queued, n + 1, here);
else
rxrpc_put_connection(conn);
return true;
}
/*
* Note the re-emergence of a connection.
*/
void rxrpc_see_connection(struct rxrpc_connection *conn)
{
const void *here = __builtin_return_address(0);
if (conn) {
int n = atomic_read(&conn->usage);
trace_rxrpc_conn(conn, rxrpc_conn_seen, n, here);
}
}
/*
* Get a ref on a connection.
*/
void rxrpc_get_connection(struct rxrpc_connection *conn)
{
const void *here = __builtin_return_address(0);
int n = atomic_inc_return(&conn->usage);
trace_rxrpc_conn(conn, rxrpc_conn_got, n, here);
}
/*
* Try to get a ref on a connection.
*/
struct rxrpc_connection *
rxrpc_get_connection_maybe(struct rxrpc_connection *conn)
{
const void *here = __builtin_return_address(0);
if (conn) {
int n = __atomic_add_unless(&conn->usage, 1, 0);
if (n > 0)
trace_rxrpc_conn(conn, rxrpc_conn_got, n + 1, here);
else
conn = NULL;
}
return conn;
}
/*
* Release a service connection
*/
void rxrpc_put_service_conn(struct rxrpc_connection *conn)
{
const void *here = __builtin_return_address(0);
int n;
n = atomic_dec_return(&conn->usage);
trace_rxrpc_conn(conn, rxrpc_conn_put_service, n, here);
ASSERTCMP(n, >=, 0);
if (n == 0)
rxrpc_queue_delayed_work(&rxrpc_connection_reap, 0);
} }
/* /*
......
...@@ -136,6 +136,10 @@ struct rxrpc_connection *rxrpc_prealloc_service_connection(gfp_t gfp) ...@@ -136,6 +136,10 @@ struct rxrpc_connection *rxrpc_prealloc_service_connection(gfp_t gfp)
list_add_tail(&conn->link, &rxrpc_connections); list_add_tail(&conn->link, &rxrpc_connections);
list_add_tail(&conn->proc_link, &rxrpc_connection_proc_list); list_add_tail(&conn->proc_link, &rxrpc_connection_proc_list);
write_unlock(&rxrpc_connection_lock); write_unlock(&rxrpc_connection_lock);
trace_rxrpc_conn(conn, rxrpc_conn_new_service,
atomic_read(&conn->usage),
__builtin_return_address(0));
} }
return conn; return conn;
......
...@@ -101,3 +101,34 @@ const char *rxrpc_acks(u8 reason) ...@@ -101,3 +101,34 @@ const char *rxrpc_acks(u8 reason)
reason = ARRAY_SIZE(str) - 1; reason = ARRAY_SIZE(str) - 1;
return str[reason]; return str[reason];
} }
const char rxrpc_conn_traces[rxrpc_conn__nr_trace][4] = {
[rxrpc_conn_new_client] = "NWc",
[rxrpc_conn_new_service] = "NWs",
[rxrpc_conn_queued] = "QUE",
[rxrpc_conn_seen] = "SEE",
[rxrpc_conn_got] = "GOT",
[rxrpc_conn_put_client] = "PTc",
[rxrpc_conn_put_service] = "PTs",
};
const char rxrpc_client_traces[rxrpc_client__nr_trace][7] = {
[rxrpc_client_activate_chans] = "Activa",
[rxrpc_client_alloc] = "Alloc ",
[rxrpc_client_chan_activate] = "ChActv",
[rxrpc_client_chan_disconnect] = "ChDisc",
[rxrpc_client_chan_pass] = "ChPass",
[rxrpc_client_chan_unstarted] = "ChUnst",
[rxrpc_client_cleanup] = "Clean ",
[rxrpc_client_count] = "Count ",
[rxrpc_client_discard] = "Discar",
[rxrpc_client_duplicate] = "Duplic",
[rxrpc_client_exposed] = "Expose",
[rxrpc_client_replace] = "Replac",
[rxrpc_client_to_active] = "->Actv",
[rxrpc_client_to_culled] = "->Cull",
[rxrpc_client_to_idle] = "->Idle",
[rxrpc_client_to_inactive] = "->Inac",
[rxrpc_client_to_waiting] = "->Wait",
[rxrpc_client_uncount] = "Uncoun",
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment