diff options
author | Mike Christie <michaelc@cs.wisc.edu> | 2013-06-14 05:56:12 -0400 |
---|---|---|
committer | David Teigland <teigland@redhat.com> | 2013-06-14 14:07:11 -0400 |
commit | 98e1b60ecc441625c91013e88f14cbd1b3c1fa08 (patch) | |
tree | 4505bd8d9f6156ea7bfbc556da40db2afb59ccad /fs/dlm | |
parent | b390ca38d27bd3d2f409e64a6f13d6ff67eb4825 (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')
-rw-r--r-- | fs/dlm/lowcomms.c | 61 |
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 | ||
312 | static int nodeid_to_addr(int nodeid, struct sockaddr_storage *sas_out, | 314 | static 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 | } |
381 | unlock: | ||
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 | ||
562 | static void sctp_init_failed_foreach(struct connection *con) | 575 | static 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; |