diff options
author | David Howells <dhowells@redhat.com> | 2016-08-23 10:27:24 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2016-08-23 11:02:35 -0400 |
commit | f51b4480021c470d1f5e8066ccc7c10513bd4e37 (patch) | |
tree | 63b43923ac921fe8e3509d5b06f0efafe062a038 | |
parent | df844fd46b98c2efde8f4ac2d50d59bc90c4c679 (diff) |
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: David Howells <dhowells@redhat.com>
-rw-r--r-- | net/rxrpc/ar-internal.h | 11 | ||||
-rw-r--r-- | net/rxrpc/conn_object.c | 42 |
2 files changed, 26 insertions, 27 deletions
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 8cb517fbbd23..66c917077880 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h | |||
@@ -313,7 +313,7 @@ struct rxrpc_connection { | |||
313 | struct rxrpc_crypt csum_iv; /* packet checksum base */ | 313 | struct rxrpc_crypt csum_iv; /* packet checksum base */ |
314 | unsigned long flags; | 314 | unsigned long flags; |
315 | unsigned long events; | 315 | unsigned long events; |
316 | unsigned long put_time; /* Time at which last put */ | 316 | unsigned long idle_timestamp; /* Time at which last became idle */ |
317 | spinlock_t state_lock; /* state-change lock */ | 317 | spinlock_t state_lock; /* state-change lock */ |
318 | atomic_t usage; | 318 | atomic_t usage; |
319 | enum rxrpc_conn_proto_state state : 8; /* current state of connection */ | 319 | 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 | struct sk_buff *); | 565 | struct sk_buff *); |
566 | void __rxrpc_disconnect_call(struct rxrpc_call *); | 566 | void __rxrpc_disconnect_call(struct rxrpc_call *); |
567 | void rxrpc_disconnect_call(struct rxrpc_call *); | 567 | void rxrpc_disconnect_call(struct rxrpc_call *); |
568 | void rxrpc_put_connection(struct rxrpc_connection *); | 568 | void __rxrpc_put_connection(struct rxrpc_connection *); |
569 | void __exit rxrpc_destroy_all_connections(void); | 569 | void __exit rxrpc_destroy_all_connections(void); |
570 | 570 | ||
571 | static inline bool rxrpc_conn_is_client(const struct rxrpc_connection *conn) | 571 | 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 | return atomic_inc_not_zero(&conn->usage) ? conn : NULL; | 589 | return atomic_inc_not_zero(&conn->usage) ? conn : NULL; |
590 | } | 590 | } |
591 | 591 | ||
592 | static inline void rxrpc_put_connection(struct rxrpc_connection *conn) | ||
593 | { | ||
594 | if (conn && atomic_dec_return(&conn->usage) == 1) | ||
595 | __rxrpc_put_connection(conn); | ||
596 | } | ||
597 | |||
598 | |||
592 | static inline bool rxrpc_queue_conn(struct rxrpc_connection *conn) | 599 | static inline bool rxrpc_queue_conn(struct rxrpc_connection *conn) |
593 | { | 600 | { |
594 | if (!rxrpc_get_connection_maybe(conn)) | 601 | if (!rxrpc_get_connection_maybe(conn)) |
diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c index 6a5a17efc538..743f0bb4aaa8 100644 --- a/net/rxrpc/conn_object.c +++ b/net/rxrpc/conn_object.c | |||
@@ -56,6 +56,7 @@ struct rxrpc_connection *rxrpc_alloc_connection(gfp_t gfp) | |||
56 | atomic_set(&conn->avail_chans, RXRPC_MAXCALLS); | 56 | atomic_set(&conn->avail_chans, RXRPC_MAXCALLS); |
57 | conn->size_align = 4; | 57 | conn->size_align = 4; |
58 | conn->header_size = sizeof(struct rxrpc_wire_header); | 58 | conn->header_size = sizeof(struct rxrpc_wire_header); |
59 | conn->idle_timestamp = jiffies; | ||
59 | } | 60 | } |
60 | 61 | ||
61 | _leave(" = %p{%d}", conn, conn ? conn->debug_id : 0); | 62 | _leave(" = %p{%d}", conn, conn ? conn->debug_id : 0); |
@@ -191,29 +192,16 @@ void rxrpc_disconnect_call(struct rxrpc_call *call) | |||
191 | spin_unlock(&conn->channel_lock); | 192 | spin_unlock(&conn->channel_lock); |
192 | 193 | ||
193 | call->conn = NULL; | 194 | call->conn = NULL; |
195 | conn->idle_timestamp = jiffies; | ||
194 | rxrpc_put_connection(conn); | 196 | rxrpc_put_connection(conn); |
195 | } | 197 | } |
196 | 198 | ||
197 | /* | 199 | /* |
198 | * release a virtual connection | 200 | * release a virtual connection |
199 | */ | 201 | */ |
200 | void rxrpc_put_connection(struct rxrpc_connection *conn) | 202 | void __rxrpc_put_connection(struct rxrpc_connection *conn) |
201 | { | 203 | { |
202 | if (!conn) | 204 | rxrpc_queue_delayed_work(&rxrpc_connection_reap, 0); |
203 | return; | ||
204 | |||
205 | _enter("%p{u=%d,d=%d}", | ||
206 | conn, atomic_read(&conn->usage), conn->debug_id); | ||
207 | |||
208 | ASSERTCMP(atomic_read(&conn->usage), >, 1); | ||
209 | |||
210 | conn->put_time = ktime_get_seconds(); | ||
211 | if (atomic_dec_return(&conn->usage) == 1) { | ||
212 | _debug("zombie"); | ||
213 | rxrpc_queue_delayed_work(&rxrpc_connection_reap, 0); | ||
214 | } | ||
215 | |||
216 | _leave(""); | ||
217 | } | 205 | } |
218 | 206 | ||
219 | /* | 207 | /* |
@@ -248,14 +236,14 @@ static void rxrpc_destroy_connection(struct rcu_head *rcu) | |||
248 | static void rxrpc_connection_reaper(struct work_struct *work) | 236 | static void rxrpc_connection_reaper(struct work_struct *work) |
249 | { | 237 | { |
250 | struct rxrpc_connection *conn, *_p; | 238 | struct rxrpc_connection *conn, *_p; |
251 | unsigned long reap_older_than, earliest, put_time, now; | 239 | unsigned long reap_older_than, earliest, idle_timestamp, now; |
252 | 240 | ||
253 | LIST_HEAD(graveyard); | 241 | LIST_HEAD(graveyard); |
254 | 242 | ||
255 | _enter(""); | 243 | _enter(""); |
256 | 244 | ||
257 | now = ktime_get_seconds(); | 245 | now = jiffies; |
258 | reap_older_than = now - rxrpc_connection_expiry; | 246 | reap_older_than = now - rxrpc_connection_expiry * HZ; |
259 | earliest = ULONG_MAX; | 247 | earliest = ULONG_MAX; |
260 | 248 | ||
261 | write_lock(&rxrpc_connection_lock); | 249 | write_lock(&rxrpc_connection_lock); |
@@ -264,10 +252,14 @@ static void rxrpc_connection_reaper(struct work_struct *work) | |||
264 | if (likely(atomic_read(&conn->usage) > 1)) | 252 | if (likely(atomic_read(&conn->usage) > 1)) |
265 | continue; | 253 | continue; |
266 | 254 | ||
267 | put_time = READ_ONCE(conn->put_time); | 255 | idle_timestamp = READ_ONCE(conn->idle_timestamp); |
268 | if (time_after(put_time, reap_older_than)) { | 256 | _debug("reap CONN %d { u=%d,t=%ld }", |
269 | if (time_before(put_time, earliest)) | 257 | conn->debug_id, atomic_read(&conn->usage), |
270 | earliest = put_time; | 258 | (long)reap_older_than - (long)idle_timestamp); |
259 | |||
260 | if (time_after(idle_timestamp, reap_older_than)) { | ||
261 | if (time_before(idle_timestamp, earliest)) | ||
262 | earliest = idle_timestamp; | ||
271 | continue; | 263 | continue; |
272 | } | 264 | } |
273 | 265 | ||
@@ -288,9 +280,9 @@ static void rxrpc_connection_reaper(struct work_struct *work) | |||
288 | 280 | ||
289 | if (earliest != ULONG_MAX) { | 281 | if (earliest != ULONG_MAX) { |
290 | _debug("reschedule reaper %ld", (long) earliest - now); | 282 | _debug("reschedule reaper %ld", (long) earliest - now); |
291 | ASSERTCMP(earliest, >, now); | 283 | ASSERT(time_after(earliest, now)); |
292 | rxrpc_queue_delayed_work(&rxrpc_connection_reap, | 284 | rxrpc_queue_delayed_work(&rxrpc_connection_reap, |
293 | (earliest - now) * HZ); | 285 | earliest - now); |
294 | } | 286 | } |
295 | 287 | ||
296 | while (!list_empty(&graveyard)) { | 288 | while (!list_empty(&graveyard)) { |