Commit f51b4480 authored by David Howells's avatar David Howells

rxrpc: Set connection expiry on idle, not put

Set the connection expiry time when a connection becomes idle rather than
doing this in rxrpc_put_connection().  This makes the put path more
efficient (it is likely to be called occasionally whilst a connection has
outstanding calls because active workqueue items needs to be given a ref).

The time is also preset in the connection allocator in case the connection
never gets used.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent df844fd4
...@@ -313,7 +313,7 @@ struct rxrpc_connection { ...@@ -313,7 +313,7 @@ struct rxrpc_connection {
struct rxrpc_crypt csum_iv; /* packet checksum base */ struct rxrpc_crypt csum_iv; /* packet checksum base */
unsigned long flags; unsigned long flags;
unsigned long events; unsigned long events;
unsigned long put_time; /* Time at which last put */ unsigned long idle_timestamp; /* Time at which last became idle */
spinlock_t state_lock; /* state-change lock */ spinlock_t state_lock; /* state-change lock */
atomic_t usage; atomic_t usage;
enum rxrpc_conn_proto_state state : 8; /* current state of connection */ enum rxrpc_conn_proto_state state : 8; /* current state of connection */
...@@ -565,7 +565,7 @@ struct rxrpc_connection *rxrpc_find_connection_rcu(struct rxrpc_local *, ...@@ -565,7 +565,7 @@ struct rxrpc_connection *rxrpc_find_connection_rcu(struct rxrpc_local *,
struct sk_buff *); struct sk_buff *);
void __rxrpc_disconnect_call(struct rxrpc_call *); void __rxrpc_disconnect_call(struct rxrpc_call *);
void rxrpc_disconnect_call(struct rxrpc_call *); void rxrpc_disconnect_call(struct rxrpc_call *);
void rxrpc_put_connection(struct rxrpc_connection *); void __rxrpc_put_connection(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)
...@@ -589,6 +589,13 @@ struct rxrpc_connection *rxrpc_get_connection_maybe(struct rxrpc_connection *con ...@@ -589,6 +589,13 @@ struct rxrpc_connection *rxrpc_get_connection_maybe(struct rxrpc_connection *con
return atomic_inc_not_zero(&conn->usage) ? conn : NULL; return atomic_inc_not_zero(&conn->usage) ? conn : NULL;
} }
static inline void rxrpc_put_connection(struct rxrpc_connection *conn)
{
if (conn && atomic_dec_return(&conn->usage) == 1)
__rxrpc_put_connection(conn);
}
static inline bool rxrpc_queue_conn(struct rxrpc_connection *conn) static inline bool rxrpc_queue_conn(struct rxrpc_connection *conn)
{ {
if (!rxrpc_get_connection_maybe(conn)) if (!rxrpc_get_connection_maybe(conn))
......
...@@ -56,6 +56,7 @@ struct rxrpc_connection *rxrpc_alloc_connection(gfp_t gfp) ...@@ -56,6 +56,7 @@ struct rxrpc_connection *rxrpc_alloc_connection(gfp_t gfp)
atomic_set(&conn->avail_chans, RXRPC_MAXCALLS); atomic_set(&conn->avail_chans, RXRPC_MAXCALLS);
conn->size_align = 4; conn->size_align = 4;
conn->header_size = sizeof(struct rxrpc_wire_header); conn->header_size = sizeof(struct rxrpc_wire_header);
conn->idle_timestamp = jiffies;
} }
_leave(" = %p{%d}", conn, conn ? conn->debug_id : 0); _leave(" = %p{%d}", conn, conn ? conn->debug_id : 0);
...@@ -191,29 +192,16 @@ void rxrpc_disconnect_call(struct rxrpc_call *call) ...@@ -191,29 +192,16 @@ void rxrpc_disconnect_call(struct rxrpc_call *call)
spin_unlock(&conn->channel_lock); spin_unlock(&conn->channel_lock);
call->conn = NULL; call->conn = NULL;
conn->idle_timestamp = jiffies;
rxrpc_put_connection(conn); rxrpc_put_connection(conn);
} }
/* /*
* release a virtual connection * release a virtual connection
*/ */
void rxrpc_put_connection(struct rxrpc_connection *conn) void __rxrpc_put_connection(struct rxrpc_connection *conn)
{ {
if (!conn) rxrpc_queue_delayed_work(&rxrpc_connection_reap, 0);
return;
_enter("%p{u=%d,d=%d}",
conn, atomic_read(&conn->usage), conn->debug_id);
ASSERTCMP(atomic_read(&conn->usage), >, 1);
conn->put_time = ktime_get_seconds();
if (atomic_dec_return(&conn->usage) == 1) {
_debug("zombie");
rxrpc_queue_delayed_work(&rxrpc_connection_reap, 0);
}
_leave("");
} }
/* /*
...@@ -248,14 +236,14 @@ static void rxrpc_destroy_connection(struct rcu_head *rcu) ...@@ -248,14 +236,14 @@ static void rxrpc_destroy_connection(struct rcu_head *rcu)
static void rxrpc_connection_reaper(struct work_struct *work) static void rxrpc_connection_reaper(struct work_struct *work)
{ {
struct rxrpc_connection *conn, *_p; struct rxrpc_connection *conn, *_p;
unsigned long reap_older_than, earliest, put_time, now; unsigned long reap_older_than, earliest, idle_timestamp, now;
LIST_HEAD(graveyard); LIST_HEAD(graveyard);
_enter(""); _enter("");
now = ktime_get_seconds(); now = jiffies;
reap_older_than = now - rxrpc_connection_expiry; reap_older_than = now - rxrpc_connection_expiry * HZ;
earliest = ULONG_MAX; earliest = ULONG_MAX;
write_lock(&rxrpc_connection_lock); write_lock(&rxrpc_connection_lock);
...@@ -264,10 +252,14 @@ static void rxrpc_connection_reaper(struct work_struct *work) ...@@ -264,10 +252,14 @@ static void rxrpc_connection_reaper(struct work_struct *work)
if (likely(atomic_read(&conn->usage) > 1)) if (likely(atomic_read(&conn->usage) > 1))
continue; continue;
put_time = READ_ONCE(conn->put_time); idle_timestamp = READ_ONCE(conn->idle_timestamp);
if (time_after(put_time, reap_older_than)) { _debug("reap CONN %d { u=%d,t=%ld }",
if (time_before(put_time, earliest)) conn->debug_id, atomic_read(&conn->usage),
earliest = put_time; (long)reap_older_than - (long)idle_timestamp);
if (time_after(idle_timestamp, reap_older_than)) {
if (time_before(idle_timestamp, earliest))
earliest = idle_timestamp;
continue; continue;
} }
...@@ -288,9 +280,9 @@ static void rxrpc_connection_reaper(struct work_struct *work) ...@@ -288,9 +280,9 @@ static void rxrpc_connection_reaper(struct work_struct *work)
if (earliest != ULONG_MAX) { if (earliest != ULONG_MAX) {
_debug("reschedule reaper %ld", (long) earliest - now); _debug("reschedule reaper %ld", (long) earliest - now);
ASSERTCMP(earliest, >, now); ASSERT(time_after(earliest, now));
rxrpc_queue_delayed_work(&rxrpc_connection_reap, rxrpc_queue_delayed_work(&rxrpc_connection_reap,
(earliest - now) * HZ); earliest - now);
} }
while (!list_empty(&graveyard)) { while (!list_empty(&graveyard)) {
......
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