diff options
| author | Sage Weil <sage@inktank.com> | 2012-07-10 14:53:34 -0400 |
|---|---|---|
| committer | Sage Weil <sage@inktank.com> | 2012-07-17 22:35:59 -0400 |
| commit | 5bdca4e0768d3e0f4efa43d9a2cc8210aeb91ab9 (patch) | |
| tree | de2a46ca2bc95e84737f3fe65e715d602b3b9356 | |
| parent | a018540141a931f5299a866907b27886916b4374 (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 2521a95fa6d9..44c87e731e9d 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h | |||
| @@ -163,16 +163,8 @@ struct ceph_connection { | |||
| 163 | 163 | ||
| 164 | /* connection negotiation temps */ | 164 | /* connection negotiation temps */ |
| 165 | char in_banner[CEPH_BANNER_MAX_LEN]; | 165 | char in_banner[CEPH_BANNER_MAX_LEN]; |
| 166 | union { | 166 | struct ceph_msg_connect out_connect; |
| 167 | struct { /* outgoing connection */ | 167 | struct ceph_msg_connect_reply in_reply; |
| 168 | struct ceph_msg_connect out_connect; | ||
| 169 | struct ceph_msg_connect_reply in_reply; | ||
| 170 | }; | ||
| 171 | struct { /* incoming */ | ||
| 172 | struct ceph_msg_connect in_connect; | ||
| 173 | struct ceph_msg_connect_reply out_reply; | ||
| 174 | }; | ||
| 175 | }; | ||
| 176 | struct ceph_entity_addr actual_peer_addr; | 168 | struct ceph_entity_addr actual_peer_addr; |
| 177 | 169 | ||
| 178 | /* message out temps */ | 170 | /* message out temps */ |
diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index b332c3d76059..10255e81be79 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c | |||
| @@ -1423,7 +1423,7 @@ static int process_connect(struct ceph_connection *con) | |||
| 1423 | * dropped messages. | 1423 | * dropped messages. |
| 1424 | */ | 1424 | */ |
| 1425 | dout("process_connect got RESET peer seq %u\n", | 1425 | dout("process_connect got RESET peer seq %u\n", |
| 1426 | le32_to_cpu(con->in_connect.connect_seq)); | 1426 | le32_to_cpu(con->in_reply.connect_seq)); |
| 1427 | pr_err("%s%lld %s connection reset\n", | 1427 | pr_err("%s%lld %s connection reset\n", |
| 1428 | ENTITY_NAME(con->peer_name), | 1428 | ENTITY_NAME(con->peer_name), |
| 1429 | ceph_pr_addr(&con->peer_addr.in_addr)); | 1429 | ceph_pr_addr(&con->peer_addr.in_addr)); |
| @@ -1450,10 +1450,10 @@ static int process_connect(struct ceph_connection *con) | |||
| 1450 | * If we sent a smaller connect_seq than the peer has, try | 1450 | * If we sent a smaller connect_seq than the peer has, try |
| 1451 | * again with a larger value. | 1451 | * again with a larger value. |
| 1452 | */ | 1452 | */ |
| 1453 | dout("process_connect got RETRY my seq = %u, peer_seq = %u\n", | 1453 | dout("process_connect got RETRY_SESSION my seq %u, peer %u\n", |
| 1454 | le32_to_cpu(con->out_connect.connect_seq), | 1454 | le32_to_cpu(con->out_connect.connect_seq), |
| 1455 | le32_to_cpu(con->in_connect.connect_seq)); | 1455 | le32_to_cpu(con->in_reply.connect_seq)); |
| 1456 | con->connect_seq = le32_to_cpu(con->in_connect.connect_seq); | 1456 | con->connect_seq = le32_to_cpu(con->in_reply.connect_seq); |
| 1457 | ceph_con_out_kvec_reset(con); | 1457 | ceph_con_out_kvec_reset(con); |
| 1458 | ret = prepare_write_connect(con); | 1458 | ret = prepare_write_connect(con); |
| 1459 | if (ret < 0) | 1459 | if (ret < 0) |
| @@ -1468,9 +1468,9 @@ static int process_connect(struct ceph_connection *con) | |||
| 1468 | */ | 1468 | */ |
| 1469 | dout("process_connect got RETRY_GLOBAL my %u peer_gseq %u\n", | 1469 | dout("process_connect got RETRY_GLOBAL my %u peer_gseq %u\n", |
| 1470 | con->peer_global_seq, | 1470 | con->peer_global_seq, |
| 1471 | le32_to_cpu(con->in_connect.global_seq)); | 1471 | le32_to_cpu(con->in_reply.global_seq)); |
| 1472 | get_global_seq(con->msgr, | 1472 | get_global_seq(con->msgr, |
| 1473 | le32_to_cpu(con->in_connect.global_seq)); | 1473 | le32_to_cpu(con->in_reply.global_seq)); |
| 1474 | ceph_con_out_kvec_reset(con); | 1474 | ceph_con_out_kvec_reset(con); |
| 1475 | ret = prepare_write_connect(con); | 1475 | ret = prepare_write_connect(con); |
| 1476 | if (ret < 0) | 1476 | if (ret < 0) |
