aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dlm/lowcomms.c
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2013-06-14 05:56:12 -0400
committerDavid Teigland <teigland@redhat.com>2013-06-14 14:07:11 -0400
commit98e1b60ecc441625c91013e88f14cbd1b3c1fa08 (patch)
tree4505bd8d9f6156ea7bfbc556da40db2afb59ccad /fs/dlm/lowcomms.c
parentb390ca38d27bd3d2f409e64a6f13d6ff67eb4825 (diff)
dlm: try other IPs when sctp init assoc fails
Currently, if we cannot create a association to the first IP addr that is added to DLM, the SCTP init assoc code will just retry the same IP. This patch adds a simple failover schemes where we will try one of the addresses that was passed into DLM. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: David Teigland <teigland@redhat.com>
Diffstat (limited to 'fs/dlm/lowcomms.c')
-rw-r--r--fs/dlm/lowcomms.c61
1 files changed, 50 insertions, 11 deletions
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index 87e68dd01479..56015c9e8d00 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -126,6 +126,7 @@ struct connection {
126 struct connection *othercon; 126 struct connection *othercon;
127 struct work_struct rwork; /* Receive workqueue */ 127 struct work_struct rwork; /* Receive workqueue */
128 struct work_struct swork; /* Send workqueue */ 128 struct work_struct swork; /* Send workqueue */
129 bool try_new_addr;
129}; 130};
130#define sock2con(x) ((struct connection *)(x)->sk_user_data) 131#define sock2con(x) ((struct connection *)(x)->sk_user_data)
131 132
@@ -144,6 +145,7 @@ struct dlm_node_addr {
144 struct list_head list; 145 struct list_head list;
145 int nodeid; 146 int nodeid;
146 int addr_count; 147 int addr_count;
148 int curr_addr_index;
147 struct sockaddr_storage *addr[DLM_MAX_ADDR_COUNT]; 149 struct sockaddr_storage *addr[DLM_MAX_ADDR_COUNT];
148}; 150};
149 151
@@ -310,7 +312,7 @@ static int addr_compare(struct sockaddr_storage *x, struct sockaddr_storage *y)
310} 312}
311 313
312static int nodeid_to_addr(int nodeid, struct sockaddr_storage *sas_out, 314static int nodeid_to_addr(int nodeid, struct sockaddr_storage *sas_out,
313 struct sockaddr *sa_out) 315 struct sockaddr *sa_out, bool try_new_addr)
314{ 316{
315 struct sockaddr_storage sas; 317 struct sockaddr_storage sas;
316 struct dlm_node_addr *na; 318 struct dlm_node_addr *na;
@@ -320,8 +322,16 @@ static int nodeid_to_addr(int nodeid, struct sockaddr_storage *sas_out,
320 322
321 spin_lock(&dlm_node_addrs_spin); 323 spin_lock(&dlm_node_addrs_spin);
322 na = find_node_addr(nodeid); 324 na = find_node_addr(nodeid);
323 if (na && na->addr_count) 325 if (na && na->addr_count) {
324 memcpy(&sas, na->addr[0], sizeof(struct sockaddr_storage)); 326 if (try_new_addr) {
327 na->curr_addr_index++;
328 if (na->curr_addr_index == na->addr_count)
329 na->curr_addr_index = 0;
330 }
331
332 memcpy(&sas, na->addr[na->curr_addr_index ],
333 sizeof(struct sockaddr_storage));
334 }
325 spin_unlock(&dlm_node_addrs_spin); 335 spin_unlock(&dlm_node_addrs_spin);
326 336
327 if (!na) 337 if (!na)
@@ -353,19 +363,22 @@ static int addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid)
353{ 363{
354 struct dlm_node_addr *na; 364 struct dlm_node_addr *na;
355 int rv = -EEXIST; 365 int rv = -EEXIST;
366 int addr_i;
356 367
357 spin_lock(&dlm_node_addrs_spin); 368 spin_lock(&dlm_node_addrs_spin);
358 list_for_each_entry(na, &dlm_node_addrs, list) { 369 list_for_each_entry(na, &dlm_node_addrs, list) {
359 if (!na->addr_count) 370 if (!na->addr_count)
360 continue; 371 continue;
361 372
362 if (!addr_compare(na->addr[0], addr)) 373 for (addr_i = 0; addr_i < na->addr_count; addr_i++) {
363 continue; 374 if (addr_compare(na->addr[addr_i], addr)) {
364 375 *nodeid = na->nodeid;
365 *nodeid = na->nodeid; 376 rv = 0;
366 rv = 0; 377 goto unlock;
367 break; 378 }
379 }
368 } 380 }
381unlock:
369 spin_unlock(&dlm_node_addrs_spin); 382 spin_unlock(&dlm_node_addrs_spin);
370 return rv; 383 return rv;
371} 384}
@@ -561,6 +574,21 @@ static void sctp_send_shutdown(sctp_assoc_t associd)
561 574
562static void sctp_init_failed_foreach(struct connection *con) 575static void sctp_init_failed_foreach(struct connection *con)
563{ 576{
577
578 /*
579 * Don't try to recover base con and handle race where the
580 * other node's assoc init creates a assoc and we get that
581 * notification, then we get a notification that our attempt
582 * failed due. This happens when we are still trying the primary
583 * address, but the other node has already tried secondary addrs
584 * and found one that worked.
585 */
586 if (!con->nodeid || con->sctp_assoc)
587 return;
588
589 log_print("Retrying SCTP association init for node %d\n", con->nodeid);
590
591 con->try_new_addr = true;
564 con->sctp_assoc = 0; 592 con->sctp_assoc = 0;
565 if (test_and_clear_bit(CF_INIT_PENDING, &con->flags)) { 593 if (test_and_clear_bit(CF_INIT_PENDING, &con->flags)) {
566 if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags)) 594 if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags))
@@ -663,6 +691,7 @@ static void process_sctp_notification(struct connection *con,
663 nodeid, (int)sn->sn_assoc_change.sac_assoc_id); 691 nodeid, (int)sn->sn_assoc_change.sac_assoc_id);
664 692
665 new_con->sctp_assoc = sn->sn_assoc_change.sac_assoc_id; 693 new_con->sctp_assoc = sn->sn_assoc_change.sac_assoc_id;
694 new_con->try_new_addr = false;
666 /* Send any pending writes */ 695 /* Send any pending writes */
667 clear_bit(CF_CONNECT_PENDING, &new_con->flags); 696 clear_bit(CF_CONNECT_PENDING, &new_con->flags);
668 clear_bit(CF_INIT_PENDING, &new_con->flags); 697 clear_bit(CF_INIT_PENDING, &new_con->flags);
@@ -984,7 +1013,8 @@ static void sctp_init_assoc(struct connection *con)
984 if (con->retries++ > MAX_CONNECT_RETRIES) 1013 if (con->retries++ > MAX_CONNECT_RETRIES)
985 return; 1014 return;
986 1015
987 if (nodeid_to_addr(con->nodeid, NULL, (struct sockaddr *)&rem_addr)) { 1016 if (nodeid_to_addr(con->nodeid, NULL, (struct sockaddr *)&rem_addr,
1017 con->try_new_addr)) {
988 log_print("no address for nodeid %d", con->nodeid); 1018 log_print("no address for nodeid %d", con->nodeid);
989 return; 1019 return;
990 } 1020 }
@@ -1016,6 +1046,14 @@ static void sctp_init_assoc(struct connection *con)
1016 iov[0].iov_base = page_address(e->page)+offset; 1046 iov[0].iov_base = page_address(e->page)+offset;
1017 iov[0].iov_len = len; 1047 iov[0].iov_len = len;
1018 1048
1049 if (rem_addr.ss_family == AF_INET) {
1050 struct sockaddr_in *sin = (struct sockaddr_in *)&rem_addr;
1051 log_print("Trying to connect to %pI4", &sin->sin_addr.s_addr);
1052 } else {
1053 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&rem_addr;
1054 log_print("Trying to connect to %pI6", &sin6->sin6_addr);
1055 }
1056
1019 cmsg = CMSG_FIRSTHDR(&outmessage); 1057 cmsg = CMSG_FIRSTHDR(&outmessage);
1020 cmsg->cmsg_level = IPPROTO_SCTP; 1058 cmsg->cmsg_level = IPPROTO_SCTP;
1021 cmsg->cmsg_type = SCTP_SNDRCV; 1059 cmsg->cmsg_type = SCTP_SNDRCV;
@@ -1024,6 +1062,7 @@ static void sctp_init_assoc(struct connection *con)
1024 memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo)); 1062 memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
1025 sinfo->sinfo_ppid = cpu_to_le32(dlm_our_nodeid()); 1063 sinfo->sinfo_ppid = cpu_to_le32(dlm_our_nodeid());
1026 outmessage.msg_controllen = cmsg->cmsg_len; 1064 outmessage.msg_controllen = cmsg->cmsg_len;
1065 sinfo->sinfo_flags |= SCTP_ADDR_OVER;
1027 1066
1028 ret = kernel_sendmsg(base_con->sock, &outmessage, iov, 1, len); 1067 ret = kernel_sendmsg(base_con->sock, &outmessage, iov, 1, len);
1029 if (ret < 0) { 1068 if (ret < 0) {
@@ -1076,7 +1115,7 @@ static void tcp_connect_to_sock(struct connection *con)
1076 goto out_err; 1115 goto out_err;
1077 1116
1078 memset(&saddr, 0, sizeof(saddr)); 1117 memset(&saddr, 0, sizeof(saddr));
1079 result = nodeid_to_addr(con->nodeid, &saddr, NULL); 1118 result = nodeid_to_addr(con->nodeid, &saddr, NULL, false);
1080 if (result < 0) { 1119 if (result < 0) {
1081 log_print("no address for nodeid %d", con->nodeid); 1120 log_print("no address for nodeid %d", con->nodeid);
1082 goto out_err; 1121 goto out_err;