summaryrefslogtreecommitdiffstats
path: root/net/rds
diff options
context:
space:
mode:
authorSowmini Varadhan <sowmini.varadhan@oracle.com>2016-06-30 19:11:13 -0400
committerDavid S. Miller <davem@davemloft.net>2016-07-01 16:45:17 -0400
commitafb4164d91c7486a1d4ab098a1b88e27b5e25772 (patch)
tree9d1b76c3268d9c491fc9280237b62f7fb7a49892 /net/rds
parent02105b2ccdd6344146e0296172a9e0f17ff624ef (diff)
RDS: TCP: Refactor connection destruction to handle multiple paths
A single rds_connection may have multiple rds_conn_paths that have to be carefully and correctly destroyed, for both rmmod and netns-delete cases. For both cases, we extract a single rds_tcp_connection for each conn into a temporary list, and then invoke rds_conn_destroy() which iteratively dismantles every path in the rds_connection. For the netns deletion case, we additionally have to make sure that we do not leave a socket in TIME_WAIT state, as this will hold up the netns deletion. Thus we call rds_tcp_conn_paths_destroy() to reset state quickly. Acked-by: Santosh Shilimkar <santosh.shilimkar@oracle.com> Signed-off-by: Sowmini Varadhan <sowmini.varadhan@oracle.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/rds')
-rw-r--r--net/rds/tcp.c46
1 files changed, 39 insertions, 7 deletions
diff --git a/net/rds/tcp.c b/net/rds/tcp.c
index c6b47f670990..b32772759c9d 100644
--- a/net/rds/tcp.c
+++ b/net/rds/tcp.c
@@ -323,6 +323,17 @@ static void rds_tcp_conn_free(void *arg)
323 kmem_cache_free(rds_tcp_conn_slab, tc); 323 kmem_cache_free(rds_tcp_conn_slab, tc);
324} 324}
325 325
326static bool list_has_conn(struct list_head *list, struct rds_connection *conn)
327{
328 struct rds_tcp_connection *tc, *_tc;
329
330 list_for_each_entry_safe(tc, _tc, list, t_tcp_node) {
331 if (tc->t_cpath->cp_conn == conn)
332 return true;
333 }
334 return false;
335}
336
326static void rds_tcp_destroy_conns(void) 337static void rds_tcp_destroy_conns(void)
327{ 338{
328 struct rds_tcp_connection *tc, *_tc; 339 struct rds_tcp_connection *tc, *_tc;
@@ -330,8 +341,10 @@ static void rds_tcp_destroy_conns(void)
330 341
331 /* avoid calling conn_destroy with irqs off */ 342 /* avoid calling conn_destroy with irqs off */
332 spin_lock_irq(&rds_tcp_conn_lock); 343 spin_lock_irq(&rds_tcp_conn_lock);
333 list_splice(&rds_tcp_conn_list, &tmp_list); 344 list_for_each_entry_safe(tc, _tc, &rds_tcp_conn_list, t_tcp_node) {
334 INIT_LIST_HEAD(&rds_tcp_conn_list); 345 if (!list_has_conn(&tmp_list, tc->t_cpath->cp_conn))
346 list_move_tail(&tc->t_tcp_node, &tmp_list);
347 }
335 spin_unlock_irq(&rds_tcp_conn_lock); 348 spin_unlock_irq(&rds_tcp_conn_lock);
336 349
337 list_for_each_entry_safe(tc, _tc, &tmp_list, t_tcp_node) 350 list_for_each_entry_safe(tc, _tc, &tmp_list, t_tcp_node)
@@ -491,10 +504,30 @@ static struct pernet_operations rds_tcp_net_ops = {
491 .size = sizeof(struct rds_tcp_net), 504 .size = sizeof(struct rds_tcp_net),
492}; 505};
493 506
507/* explicitly send a RST on each socket, thereby releasing any socket refcnts
508 * that may otherwise hold up netns deletion.
509 */
510static void rds_tcp_conn_paths_destroy(struct rds_connection *conn)
511{
512 struct rds_conn_path *cp;
513 struct rds_tcp_connection *tc;
514 int i;
515 struct sock *sk;
516
517 for (i = 0; i < RDS_MPATH_WORKERS; i++) {
518 cp = &conn->c_path[i];
519 tc = cp->cp_transport_data;
520 if (!tc->t_sock)
521 continue;
522 sk = tc->t_sock->sk;
523 sk->sk_prot->disconnect(sk, 0);
524 tcp_done(sk);
525 }
526}
527
494static void rds_tcp_kill_sock(struct net *net) 528static void rds_tcp_kill_sock(struct net *net)
495{ 529{
496 struct rds_tcp_connection *tc, *_tc; 530 struct rds_tcp_connection *tc, *_tc;
497 struct sock *sk;
498 LIST_HEAD(tmp_list); 531 LIST_HEAD(tmp_list);
499 struct rds_tcp_net *rtn = net_generic(net, rds_tcp_netid); 532 struct rds_tcp_net *rtn = net_generic(net, rds_tcp_netid);
500 533
@@ -507,13 +540,12 @@ static void rds_tcp_kill_sock(struct net *net)
507 540
508 if (net != c_net || !tc->t_sock) 541 if (net != c_net || !tc->t_sock)
509 continue; 542 continue;
510 list_move_tail(&tc->t_tcp_node, &tmp_list); 543 if (!list_has_conn(&tmp_list, tc->t_cpath->cp_conn))
544 list_move_tail(&tc->t_tcp_node, &tmp_list);
511 } 545 }
512 spin_unlock_irq(&rds_tcp_conn_lock); 546 spin_unlock_irq(&rds_tcp_conn_lock);
513 list_for_each_entry_safe(tc, _tc, &tmp_list, t_tcp_node) { 547 list_for_each_entry_safe(tc, _tc, &tmp_list, t_tcp_node) {
514 sk = tc->t_sock->sk; 548 rds_tcp_conn_paths_destroy(tc->t_cpath->cp_conn);
515 sk->sk_prot->disconnect(sk, 0);
516 tcp_done(sk);
517 rds_conn_destroy(tc->t_cpath->cp_conn); 549 rds_conn_destroy(tc->t_cpath->cp_conn);
518 } 550 }
519} 551}