diff options
author | Sage Weil <sage@inktank.com> | 2012-07-10 14:53:34 -0400 |
---|---|---|
committer | Sage Weil <sage@inktank.com> | 2012-07-30 12:29:52 -0400 |
commit | a16cb1f70799c851410d9dca0a24122e258df06c (patch) | |
tree | 0290805d3594d770da3937da7fa68841c1e294ac | |
parent | cd43045c2de60f40a0aea49bfb252a2eafe58f8c (diff) |
libceph: fix messenger retry
In ancient times, the messenger could both initiate and accept connections.
An artifact if that was data structures to store/process an incoming
ceph_msg_connect request and send an outgoing ceph_msg_connect_reply.
Sadly, the negotiation code was referencing those structures and ignoring
important information (like the peer's connect_seq) from the correct ones.
Among other things, this fixes tight reconnect loops where the server sends
RETRY_SESSION and we (the client) retries with the same connect_seq as last
time. This bug pretty easily triggered by injecting socket failures on the
MDS and running some fs workload like workunits/direct_io/test_sync_io.
Signed-off-by: Sage Weil <sage@inktank.com>
-rw-r--r-- | include/linux/ceph/messenger.h | 12 | ||||
-rw-r--r-- | net/ceph/messenger.c | 12 |
2 files changed, 8 insertions, 16 deletions
diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 478f814f2100..cfb1bbdac624 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h | |||
@@ -172,16 +172,8 @@ struct ceph_connection { | |||
172 | 172 | ||
173 | /* connection negotiation temps */ | 173 | /* connection negotiation temps */ |
174 | char in_banner[CEPH_BANNER_MAX_LEN]; | 174 | char in_banner[CEPH_BANNER_MAX_LEN]; |
175 | union { | 175 | struct ceph_msg_connect out_connect; |
176 | struct { /* outgoing connection */ | 176 | struct ceph_msg_connect_reply in_reply; |
177 | struct ceph_msg_connect out_connect; | ||
178 | struct ceph_msg_connect_reply in_reply; | ||
179 | }; | ||
180 | struct { /* incoming */ | ||
181 | struct ceph_msg_connect in_connect; | ||
182 | struct ceph_msg_connect_reply out_reply; | ||
183 | }; | ||
184 | }; | ||
185 | struct ceph_entity_addr actual_peer_addr; | 177 | struct ceph_entity_addr actual_peer_addr; |
186 | 178 | ||
187 | /* message out temps */ | 179 | /* message out temps */ |
diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 09ada7924874..16814d1f4774 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c | |||
@@ -1540,7 +1540,7 @@ static int process_connect(struct ceph_connection *con) | |||
1540 | * dropped messages. | 1540 | * dropped messages. |
1541 | */ | 1541 | */ |
1542 | dout("process_connect got RESET peer seq %u\n", | 1542 | dout("process_connect got RESET peer seq %u\n", |
1543 | le32_to_cpu(con->in_connect.connect_seq)); | 1543 | le32_to_cpu(con->in_reply.connect_seq)); |
1544 | pr_err("%s%lld %s connection reset\n", | 1544 | pr_err("%s%lld %s connection reset\n", |
1545 | ENTITY_NAME(con->peer_name), | 1545 | ENTITY_NAME(con->peer_name), |
1546 | ceph_pr_addr(&con->peer_addr.in_addr)); | 1546 | ceph_pr_addr(&con->peer_addr.in_addr)); |
@@ -1566,10 +1566,10 @@ static int process_connect(struct ceph_connection *con) | |||
1566 | * If we sent a smaller connect_seq than the peer has, try | 1566 | * If we sent a smaller connect_seq than the peer has, try |
1567 | * again with a larger value. | 1567 | * again with a larger value. |
1568 | */ | 1568 | */ |
1569 | dout("process_connect got RETRY my seq = %u, peer_seq = %u\n", | 1569 | dout("process_connect got RETRY_SESSION my seq %u, peer %u\n", |
1570 | le32_to_cpu(con->out_connect.connect_seq), | 1570 | le32_to_cpu(con->out_connect.connect_seq), |
1571 | le32_to_cpu(con->in_connect.connect_seq)); | 1571 | le32_to_cpu(con->in_reply.connect_seq)); |
1572 | con->connect_seq = le32_to_cpu(con->in_connect.connect_seq); | 1572 | con->connect_seq = le32_to_cpu(con->in_reply.connect_seq); |
1573 | ret = prepare_write_connect(con); | 1573 | ret = prepare_write_connect(con); |
1574 | if (ret < 0) | 1574 | if (ret < 0) |
1575 | return ret; | 1575 | return ret; |
@@ -1583,9 +1583,9 @@ static int process_connect(struct ceph_connection *con) | |||
1583 | */ | 1583 | */ |
1584 | dout("process_connect got RETRY_GLOBAL my %u peer_gseq %u\n", | 1584 | dout("process_connect got RETRY_GLOBAL my %u peer_gseq %u\n", |
1585 | con->peer_global_seq, | 1585 | con->peer_global_seq, |
1586 | le32_to_cpu(con->in_connect.global_seq)); | 1586 | le32_to_cpu(con->in_reply.global_seq)); |
1587 | get_global_seq(con->msgr, | 1587 | get_global_seq(con->msgr, |
1588 | le32_to_cpu(con->in_connect.global_seq)); | 1588 | le32_to_cpu(con->in_reply.global_seq)); |
1589 | ret = prepare_write_connect(con); | 1589 | ret = prepare_write_connect(con); |
1590 | if (ret < 0) | 1590 | if (ret < 0) |
1591 | return ret; | 1591 | return ret; |