aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSage Weil <sage@inktank.com>2012-07-10 14:53:34 -0400
committerSage Weil <sage@inktank.com>2012-07-17 22:35:59 -0400
commit5bdca4e0768d3e0f4efa43d9a2cc8210aeb91ab9 (patch)
treede2a46ca2bc95e84737f3fe65e715d602b3b9356
parenta018540141a931f5299a866907b27886916b4374 (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.h12
-rw-r--r--net/ceph/messenger.c12
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)