12f713615SIlya Dryomov // SPDX-License-Identifier: GPL-2.0 22f713615SIlya Dryomov #include <linux/ceph/ceph_debug.h> 32f713615SIlya Dryomov 42f713615SIlya Dryomov #include <linux/bvec.h> 52f713615SIlya Dryomov #include <linux/crc32c.h> 62f713615SIlya Dryomov #include <linux/net.h> 72f713615SIlya Dryomov #include <linux/socket.h> 82f713615SIlya Dryomov #include <net/sock.h> 92f713615SIlya Dryomov 102f713615SIlya Dryomov #include <linux/ceph/ceph_features.h> 112f713615SIlya Dryomov #include <linux/ceph/decode.h> 122f713615SIlya Dryomov #include <linux/ceph/libceph.h> 132f713615SIlya Dryomov #include <linux/ceph/messenger.h> 142f713615SIlya Dryomov 152f713615SIlya Dryomov /* static tag bytes (protocol control messages) */ 162f713615SIlya Dryomov static char tag_msg = CEPH_MSGR_TAG_MSG; 172f713615SIlya Dryomov static char tag_ack = CEPH_MSGR_TAG_ACK; 182f713615SIlya Dryomov static char tag_keepalive = CEPH_MSGR_TAG_KEEPALIVE; 192f713615SIlya Dryomov static char tag_keepalive2 = CEPH_MSGR_TAG_KEEPALIVE2; 202f713615SIlya Dryomov 212f713615SIlya Dryomov /* 222f713615SIlya Dryomov * If @buf is NULL, discard up to @len bytes. 232f713615SIlya Dryomov */ 242f713615SIlya Dryomov static int ceph_tcp_recvmsg(struct socket *sock, void *buf, size_t len) 252f713615SIlya Dryomov { 262f713615SIlya Dryomov struct kvec iov = {buf, len}; 272f713615SIlya Dryomov struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL }; 282f713615SIlya Dryomov int r; 292f713615SIlya Dryomov 302f713615SIlya Dryomov if (!buf) 312f713615SIlya Dryomov msg.msg_flags |= MSG_TRUNC; 322f713615SIlya Dryomov 33de4eda9dSAl Viro iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, len); 342f713615SIlya Dryomov r = sock_recvmsg(sock, &msg, msg.msg_flags); 352f713615SIlya Dryomov if (r == -EAGAIN) 362f713615SIlya Dryomov r = 0; 372f713615SIlya Dryomov return r; 382f713615SIlya Dryomov } 392f713615SIlya Dryomov 402f713615SIlya Dryomov static int ceph_tcp_recvpage(struct socket *sock, struct page *page, 412f713615SIlya Dryomov int page_offset, size_t length) 422f713615SIlya Dryomov { 43*1eb9cd15SChristoph Hellwig struct bio_vec bvec; 442f713615SIlya Dryomov struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL }; 452f713615SIlya Dryomov int r; 462f713615SIlya Dryomov 472f713615SIlya Dryomov BUG_ON(page_offset + length > PAGE_SIZE); 48*1eb9cd15SChristoph Hellwig bvec_set_page(&bvec, page, length, page_offset); 49de4eda9dSAl Viro iov_iter_bvec(&msg.msg_iter, ITER_DEST, &bvec, 1, length); 502f713615SIlya Dryomov r = sock_recvmsg(sock, &msg, msg.msg_flags); 512f713615SIlya Dryomov if (r == -EAGAIN) 522f713615SIlya Dryomov r = 0; 532f713615SIlya Dryomov return r; 542f713615SIlya Dryomov } 552f713615SIlya Dryomov 562f713615SIlya Dryomov /* 572f713615SIlya Dryomov * write something. @more is true if caller will be sending more data 582f713615SIlya Dryomov * shortly. 592f713615SIlya Dryomov */ 602f713615SIlya Dryomov static int ceph_tcp_sendmsg(struct socket *sock, struct kvec *iov, 612f713615SIlya Dryomov size_t kvlen, size_t len, bool more) 622f713615SIlya Dryomov { 632f713615SIlya Dryomov struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL }; 642f713615SIlya Dryomov int r; 652f713615SIlya Dryomov 662f713615SIlya Dryomov if (more) 672f713615SIlya Dryomov msg.msg_flags |= MSG_MORE; 682f713615SIlya Dryomov else 692f713615SIlya Dryomov msg.msg_flags |= MSG_EOR; /* superfluous, but what the hell */ 702f713615SIlya Dryomov 712f713615SIlya Dryomov r = kernel_sendmsg(sock, &msg, iov, kvlen, len); 722f713615SIlya Dryomov if (r == -EAGAIN) 732f713615SIlya Dryomov r = 0; 742f713615SIlya Dryomov return r; 752f713615SIlya Dryomov } 762f713615SIlya Dryomov 772f713615SIlya Dryomov /* 782f713615SIlya Dryomov * @more: either or both of MSG_MORE and MSG_SENDPAGE_NOTLAST 792f713615SIlya Dryomov */ 802f713615SIlya Dryomov static int ceph_tcp_sendpage(struct socket *sock, struct page *page, 812f713615SIlya Dryomov int offset, size_t size, int more) 822f713615SIlya Dryomov { 832f713615SIlya Dryomov ssize_t (*sendpage)(struct socket *sock, struct page *page, 842f713615SIlya Dryomov int offset, size_t size, int flags); 852f713615SIlya Dryomov int flags = MSG_DONTWAIT | MSG_NOSIGNAL | more; 862f713615SIlya Dryomov int ret; 872f713615SIlya Dryomov 882f713615SIlya Dryomov /* 892f713615SIlya Dryomov * sendpage cannot properly handle pages with page_count == 0, 902f713615SIlya Dryomov * we need to fall back to sendmsg if that's the case. 912f713615SIlya Dryomov * 922f713615SIlya Dryomov * Same goes for slab pages: skb_can_coalesce() allows 932f713615SIlya Dryomov * coalescing neighboring slab objects into a single frag which 942f713615SIlya Dryomov * triggers one of hardened usercopy checks. 952f713615SIlya Dryomov */ 962f713615SIlya Dryomov if (sendpage_ok(page)) 972f713615SIlya Dryomov sendpage = sock->ops->sendpage; 982f713615SIlya Dryomov else 992f713615SIlya Dryomov sendpage = sock_no_sendpage; 1002f713615SIlya Dryomov 1012f713615SIlya Dryomov ret = sendpage(sock, page, offset, size, flags); 1022f713615SIlya Dryomov if (ret == -EAGAIN) 1032f713615SIlya Dryomov ret = 0; 1042f713615SIlya Dryomov 1052f713615SIlya Dryomov return ret; 1062f713615SIlya Dryomov } 1072f713615SIlya Dryomov 1082f713615SIlya Dryomov static void con_out_kvec_reset(struct ceph_connection *con) 1092f713615SIlya Dryomov { 110a56dd9bfSIlya Dryomov BUG_ON(con->v1.out_skip); 1112f713615SIlya Dryomov 112a56dd9bfSIlya Dryomov con->v1.out_kvec_left = 0; 113a56dd9bfSIlya Dryomov con->v1.out_kvec_bytes = 0; 114a56dd9bfSIlya Dryomov con->v1.out_kvec_cur = &con->v1.out_kvec[0]; 1152f713615SIlya Dryomov } 1162f713615SIlya Dryomov 1172f713615SIlya Dryomov static void con_out_kvec_add(struct ceph_connection *con, 1182f713615SIlya Dryomov size_t size, void *data) 1192f713615SIlya Dryomov { 120a56dd9bfSIlya Dryomov int index = con->v1.out_kvec_left; 1212f713615SIlya Dryomov 122a56dd9bfSIlya Dryomov BUG_ON(con->v1.out_skip); 123a56dd9bfSIlya Dryomov BUG_ON(index >= ARRAY_SIZE(con->v1.out_kvec)); 1242f713615SIlya Dryomov 125a56dd9bfSIlya Dryomov con->v1.out_kvec[index].iov_len = size; 126a56dd9bfSIlya Dryomov con->v1.out_kvec[index].iov_base = data; 127a56dd9bfSIlya Dryomov con->v1.out_kvec_left++; 128a56dd9bfSIlya Dryomov con->v1.out_kvec_bytes += size; 1292f713615SIlya Dryomov } 1302f713615SIlya Dryomov 1312f713615SIlya Dryomov /* 1322f713615SIlya Dryomov * Chop off a kvec from the end. Return residual number of bytes for 1332f713615SIlya Dryomov * that kvec, i.e. how many bytes would have been written if the kvec 1342f713615SIlya Dryomov * hadn't been nuked. 1352f713615SIlya Dryomov */ 1362f713615SIlya Dryomov static int con_out_kvec_skip(struct ceph_connection *con) 1372f713615SIlya Dryomov { 1382f713615SIlya Dryomov int skip = 0; 1392f713615SIlya Dryomov 140a56dd9bfSIlya Dryomov if (con->v1.out_kvec_bytes > 0) { 141a56dd9bfSIlya Dryomov skip = con->v1.out_kvec_cur[con->v1.out_kvec_left - 1].iov_len; 142a56dd9bfSIlya Dryomov BUG_ON(con->v1.out_kvec_bytes < skip); 143a56dd9bfSIlya Dryomov BUG_ON(!con->v1.out_kvec_left); 144a56dd9bfSIlya Dryomov con->v1.out_kvec_bytes -= skip; 145a56dd9bfSIlya Dryomov con->v1.out_kvec_left--; 1462f713615SIlya Dryomov } 1472f713615SIlya Dryomov 1482f713615SIlya Dryomov return skip; 1492f713615SIlya Dryomov } 1502f713615SIlya Dryomov 1512f713615SIlya Dryomov static size_t sizeof_footer(struct ceph_connection *con) 1522f713615SIlya Dryomov { 1532f713615SIlya Dryomov return (con->peer_features & CEPH_FEATURE_MSG_AUTH) ? 1542f713615SIlya Dryomov sizeof(struct ceph_msg_footer) : 1552f713615SIlya Dryomov sizeof(struct ceph_msg_footer_old); 1562f713615SIlya Dryomov } 1572f713615SIlya Dryomov 1582f713615SIlya Dryomov static void prepare_message_data(struct ceph_msg *msg, u32 data_len) 1592f713615SIlya Dryomov { 1602f713615SIlya Dryomov /* Initialize data cursor */ 1612f713615SIlya Dryomov 1622f713615SIlya Dryomov ceph_msg_data_cursor_init(&msg->cursor, msg, data_len); 1632f713615SIlya Dryomov } 1642f713615SIlya Dryomov 1652f713615SIlya Dryomov /* 1662f713615SIlya Dryomov * Prepare footer for currently outgoing message, and finish things 1672f713615SIlya Dryomov * off. Assumes out_kvec* are already valid.. we just add on to the end. 1682f713615SIlya Dryomov */ 1692f713615SIlya Dryomov static void prepare_write_message_footer(struct ceph_connection *con) 1702f713615SIlya Dryomov { 1712f713615SIlya Dryomov struct ceph_msg *m = con->out_msg; 1722f713615SIlya Dryomov 1732f713615SIlya Dryomov m->footer.flags |= CEPH_MSG_FOOTER_COMPLETE; 1742f713615SIlya Dryomov 1752f713615SIlya Dryomov dout("prepare_write_message_footer %p\n", con); 1762f713615SIlya Dryomov con_out_kvec_add(con, sizeof_footer(con), &m->footer); 1772f713615SIlya Dryomov if (con->peer_features & CEPH_FEATURE_MSG_AUTH) { 1782f713615SIlya Dryomov if (con->ops->sign_message) 1792f713615SIlya Dryomov con->ops->sign_message(m); 1802f713615SIlya Dryomov else 1812f713615SIlya Dryomov m->footer.sig = 0; 1822f713615SIlya Dryomov } else { 1832f713615SIlya Dryomov m->old_footer.flags = m->footer.flags; 1842f713615SIlya Dryomov } 185a56dd9bfSIlya Dryomov con->v1.out_more = m->more_to_follow; 186a56dd9bfSIlya Dryomov con->v1.out_msg_done = true; 1872f713615SIlya Dryomov } 1882f713615SIlya Dryomov 1892f713615SIlya Dryomov /* 1902f713615SIlya Dryomov * Prepare headers for the next outgoing message. 1912f713615SIlya Dryomov */ 1922f713615SIlya Dryomov static void prepare_write_message(struct ceph_connection *con) 1932f713615SIlya Dryomov { 1942f713615SIlya Dryomov struct ceph_msg *m; 1952f713615SIlya Dryomov u32 crc; 1962f713615SIlya Dryomov 1972f713615SIlya Dryomov con_out_kvec_reset(con); 198a56dd9bfSIlya Dryomov con->v1.out_msg_done = false; 1992f713615SIlya Dryomov 2002f713615SIlya Dryomov /* Sneak an ack in there first? If we can get it into the same 2012f713615SIlya Dryomov * TCP packet that's a good thing. */ 2022f713615SIlya Dryomov if (con->in_seq > con->in_seq_acked) { 2032f713615SIlya Dryomov con->in_seq_acked = con->in_seq; 2042f713615SIlya Dryomov con_out_kvec_add(con, sizeof (tag_ack), &tag_ack); 205a56dd9bfSIlya Dryomov con->v1.out_temp_ack = cpu_to_le64(con->in_seq_acked); 206a56dd9bfSIlya Dryomov con_out_kvec_add(con, sizeof(con->v1.out_temp_ack), 207a56dd9bfSIlya Dryomov &con->v1.out_temp_ack); 2082f713615SIlya Dryomov } 2092f713615SIlya Dryomov 2102f713615SIlya Dryomov ceph_con_get_out_msg(con); 2112f713615SIlya Dryomov m = con->out_msg; 2122f713615SIlya Dryomov 2132f713615SIlya Dryomov dout("prepare_write_message %p seq %lld type %d len %d+%d+%zd\n", 2142f713615SIlya Dryomov m, con->out_seq, le16_to_cpu(m->hdr.type), 2152f713615SIlya Dryomov le32_to_cpu(m->hdr.front_len), le32_to_cpu(m->hdr.middle_len), 2162f713615SIlya Dryomov m->data_length); 2172f713615SIlya Dryomov WARN_ON(m->front.iov_len != le32_to_cpu(m->hdr.front_len)); 2182f713615SIlya Dryomov WARN_ON(m->data_length != le32_to_cpu(m->hdr.data_len)); 2192f713615SIlya Dryomov 2202f713615SIlya Dryomov /* tag + hdr + front + middle */ 2212f713615SIlya Dryomov con_out_kvec_add(con, sizeof (tag_msg), &tag_msg); 222a56dd9bfSIlya Dryomov con_out_kvec_add(con, sizeof(con->v1.out_hdr), &con->v1.out_hdr); 2232f713615SIlya Dryomov con_out_kvec_add(con, m->front.iov_len, m->front.iov_base); 2242f713615SIlya Dryomov 2252f713615SIlya Dryomov if (m->middle) 2262f713615SIlya Dryomov con_out_kvec_add(con, m->middle->vec.iov_len, 2272f713615SIlya Dryomov m->middle->vec.iov_base); 2282f713615SIlya Dryomov 2292f713615SIlya Dryomov /* fill in hdr crc and finalize hdr */ 2302f713615SIlya Dryomov crc = crc32c(0, &m->hdr, offsetof(struct ceph_msg_header, crc)); 2312f713615SIlya Dryomov con->out_msg->hdr.crc = cpu_to_le32(crc); 232a56dd9bfSIlya Dryomov memcpy(&con->v1.out_hdr, &con->out_msg->hdr, sizeof(con->v1.out_hdr)); 2332f713615SIlya Dryomov 2342f713615SIlya Dryomov /* fill in front and middle crc, footer */ 2352f713615SIlya Dryomov crc = crc32c(0, m->front.iov_base, m->front.iov_len); 2362f713615SIlya Dryomov con->out_msg->footer.front_crc = cpu_to_le32(crc); 2372f713615SIlya Dryomov if (m->middle) { 2382f713615SIlya Dryomov crc = crc32c(0, m->middle->vec.iov_base, 2392f713615SIlya Dryomov m->middle->vec.iov_len); 2402f713615SIlya Dryomov con->out_msg->footer.middle_crc = cpu_to_le32(crc); 2412f713615SIlya Dryomov } else 2422f713615SIlya Dryomov con->out_msg->footer.middle_crc = 0; 2432f713615SIlya Dryomov dout("%s front_crc %u middle_crc %u\n", __func__, 2442f713615SIlya Dryomov le32_to_cpu(con->out_msg->footer.front_crc), 2452f713615SIlya Dryomov le32_to_cpu(con->out_msg->footer.middle_crc)); 2462f713615SIlya Dryomov con->out_msg->footer.flags = 0; 2472f713615SIlya Dryomov 2482f713615SIlya Dryomov /* is there a data payload? */ 2492f713615SIlya Dryomov con->out_msg->footer.data_crc = 0; 2502f713615SIlya Dryomov if (m->data_length) { 2512f713615SIlya Dryomov prepare_message_data(con->out_msg, m->data_length); 252a56dd9bfSIlya Dryomov con->v1.out_more = 1; /* data + footer will follow */ 2532f713615SIlya Dryomov } else { 2542f713615SIlya Dryomov /* no, queue up footer too and be done */ 2552f713615SIlya Dryomov prepare_write_message_footer(con); 2562f713615SIlya Dryomov } 2572f713615SIlya Dryomov 2582f713615SIlya Dryomov ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING); 2592f713615SIlya Dryomov } 2602f713615SIlya Dryomov 2612f713615SIlya Dryomov /* 2622f713615SIlya Dryomov * Prepare an ack. 2632f713615SIlya Dryomov */ 2642f713615SIlya Dryomov static void prepare_write_ack(struct ceph_connection *con) 2652f713615SIlya Dryomov { 2662f713615SIlya Dryomov dout("prepare_write_ack %p %llu -> %llu\n", con, 2672f713615SIlya Dryomov con->in_seq_acked, con->in_seq); 2682f713615SIlya Dryomov con->in_seq_acked = con->in_seq; 2692f713615SIlya Dryomov 2702f713615SIlya Dryomov con_out_kvec_reset(con); 2712f713615SIlya Dryomov 2722f713615SIlya Dryomov con_out_kvec_add(con, sizeof (tag_ack), &tag_ack); 2732f713615SIlya Dryomov 274a56dd9bfSIlya Dryomov con->v1.out_temp_ack = cpu_to_le64(con->in_seq_acked); 275a56dd9bfSIlya Dryomov con_out_kvec_add(con, sizeof(con->v1.out_temp_ack), 276a56dd9bfSIlya Dryomov &con->v1.out_temp_ack); 2772f713615SIlya Dryomov 278a56dd9bfSIlya Dryomov con->v1.out_more = 1; /* more will follow.. eventually.. */ 2792f713615SIlya Dryomov ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING); 2802f713615SIlya Dryomov } 2812f713615SIlya Dryomov 2822f713615SIlya Dryomov /* 2832f713615SIlya Dryomov * Prepare to share the seq during handshake 2842f713615SIlya Dryomov */ 2852f713615SIlya Dryomov static void prepare_write_seq(struct ceph_connection *con) 2862f713615SIlya Dryomov { 2872f713615SIlya Dryomov dout("prepare_write_seq %p %llu -> %llu\n", con, 2882f713615SIlya Dryomov con->in_seq_acked, con->in_seq); 2892f713615SIlya Dryomov con->in_seq_acked = con->in_seq; 2902f713615SIlya Dryomov 2912f713615SIlya Dryomov con_out_kvec_reset(con); 2922f713615SIlya Dryomov 293a56dd9bfSIlya Dryomov con->v1.out_temp_ack = cpu_to_le64(con->in_seq_acked); 294a56dd9bfSIlya Dryomov con_out_kvec_add(con, sizeof(con->v1.out_temp_ack), 295a56dd9bfSIlya Dryomov &con->v1.out_temp_ack); 2962f713615SIlya Dryomov 2972f713615SIlya Dryomov ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING); 2982f713615SIlya Dryomov } 2992f713615SIlya Dryomov 3002f713615SIlya Dryomov /* 3012f713615SIlya Dryomov * Prepare to write keepalive byte. 3022f713615SIlya Dryomov */ 3032f713615SIlya Dryomov static void prepare_write_keepalive(struct ceph_connection *con) 3042f713615SIlya Dryomov { 3052f713615SIlya Dryomov dout("prepare_write_keepalive %p\n", con); 3062f713615SIlya Dryomov con_out_kvec_reset(con); 3072f713615SIlya Dryomov if (con->peer_features & CEPH_FEATURE_MSGR_KEEPALIVE2) { 3082f713615SIlya Dryomov struct timespec64 now; 3092f713615SIlya Dryomov 3102f713615SIlya Dryomov ktime_get_real_ts64(&now); 3112f713615SIlya Dryomov con_out_kvec_add(con, sizeof(tag_keepalive2), &tag_keepalive2); 312a56dd9bfSIlya Dryomov ceph_encode_timespec64(&con->v1.out_temp_keepalive2, &now); 313a56dd9bfSIlya Dryomov con_out_kvec_add(con, sizeof(con->v1.out_temp_keepalive2), 314a56dd9bfSIlya Dryomov &con->v1.out_temp_keepalive2); 3152f713615SIlya Dryomov } else { 3162f713615SIlya Dryomov con_out_kvec_add(con, sizeof(tag_keepalive), &tag_keepalive); 3172f713615SIlya Dryomov } 3182f713615SIlya Dryomov ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING); 3192f713615SIlya Dryomov } 3202f713615SIlya Dryomov 3212f713615SIlya Dryomov /* 3222f713615SIlya Dryomov * Connection negotiation. 3232f713615SIlya Dryomov */ 3242f713615SIlya Dryomov 3252f713615SIlya Dryomov static int get_connect_authorizer(struct ceph_connection *con) 3262f713615SIlya Dryomov { 3272f713615SIlya Dryomov struct ceph_auth_handshake *auth; 3282f713615SIlya Dryomov int auth_proto; 3292f713615SIlya Dryomov 3302f713615SIlya Dryomov if (!con->ops->get_authorizer) { 331a56dd9bfSIlya Dryomov con->v1.auth = NULL; 332a56dd9bfSIlya Dryomov con->v1.out_connect.authorizer_protocol = CEPH_AUTH_UNKNOWN; 333a56dd9bfSIlya Dryomov con->v1.out_connect.authorizer_len = 0; 3342f713615SIlya Dryomov return 0; 3352f713615SIlya Dryomov } 3362f713615SIlya Dryomov 337a56dd9bfSIlya Dryomov auth = con->ops->get_authorizer(con, &auth_proto, con->v1.auth_retry); 3382f713615SIlya Dryomov if (IS_ERR(auth)) 3392f713615SIlya Dryomov return PTR_ERR(auth); 3402f713615SIlya Dryomov 341a56dd9bfSIlya Dryomov con->v1.auth = auth; 342a56dd9bfSIlya Dryomov con->v1.out_connect.authorizer_protocol = cpu_to_le32(auth_proto); 343a56dd9bfSIlya Dryomov con->v1.out_connect.authorizer_len = 344a56dd9bfSIlya Dryomov cpu_to_le32(auth->authorizer_buf_len); 3452f713615SIlya Dryomov return 0; 3462f713615SIlya Dryomov } 3472f713615SIlya Dryomov 3482f713615SIlya Dryomov /* 3492f713615SIlya Dryomov * We connected to a peer and are saying hello. 3502f713615SIlya Dryomov */ 3512f713615SIlya Dryomov static void prepare_write_banner(struct ceph_connection *con) 3522f713615SIlya Dryomov { 3532f713615SIlya Dryomov con_out_kvec_add(con, strlen(CEPH_BANNER), CEPH_BANNER); 3542f713615SIlya Dryomov con_out_kvec_add(con, sizeof (con->msgr->my_enc_addr), 3552f713615SIlya Dryomov &con->msgr->my_enc_addr); 3562f713615SIlya Dryomov 357a56dd9bfSIlya Dryomov con->v1.out_more = 0; 3582f713615SIlya Dryomov ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING); 3592f713615SIlya Dryomov } 3602f713615SIlya Dryomov 3612f713615SIlya Dryomov static void __prepare_write_connect(struct ceph_connection *con) 3622f713615SIlya Dryomov { 363a56dd9bfSIlya Dryomov con_out_kvec_add(con, sizeof(con->v1.out_connect), 364a56dd9bfSIlya Dryomov &con->v1.out_connect); 365a56dd9bfSIlya Dryomov if (con->v1.auth) 366a56dd9bfSIlya Dryomov con_out_kvec_add(con, con->v1.auth->authorizer_buf_len, 367a56dd9bfSIlya Dryomov con->v1.auth->authorizer_buf); 3682f713615SIlya Dryomov 369a56dd9bfSIlya Dryomov con->v1.out_more = 0; 3702f713615SIlya Dryomov ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING); 3712f713615SIlya Dryomov } 3722f713615SIlya Dryomov 3732f713615SIlya Dryomov static int prepare_write_connect(struct ceph_connection *con) 3742f713615SIlya Dryomov { 3752f713615SIlya Dryomov unsigned int global_seq = ceph_get_global_seq(con->msgr, 0); 3762f713615SIlya Dryomov int proto; 3772f713615SIlya Dryomov int ret; 3782f713615SIlya Dryomov 3792f713615SIlya Dryomov switch (con->peer_name.type) { 3802f713615SIlya Dryomov case CEPH_ENTITY_TYPE_MON: 3812f713615SIlya Dryomov proto = CEPH_MONC_PROTOCOL; 3822f713615SIlya Dryomov break; 3832f713615SIlya Dryomov case CEPH_ENTITY_TYPE_OSD: 3842f713615SIlya Dryomov proto = CEPH_OSDC_PROTOCOL; 3852f713615SIlya Dryomov break; 3862f713615SIlya Dryomov case CEPH_ENTITY_TYPE_MDS: 3872f713615SIlya Dryomov proto = CEPH_MDSC_PROTOCOL; 3882f713615SIlya Dryomov break; 3892f713615SIlya Dryomov default: 3902f713615SIlya Dryomov BUG(); 3912f713615SIlya Dryomov } 3922f713615SIlya Dryomov 3932f713615SIlya Dryomov dout("prepare_write_connect %p cseq=%d gseq=%d proto=%d\n", con, 394a56dd9bfSIlya Dryomov con->v1.connect_seq, global_seq, proto); 3952f713615SIlya Dryomov 396a56dd9bfSIlya Dryomov con->v1.out_connect.features = 3972f713615SIlya Dryomov cpu_to_le64(from_msgr(con->msgr)->supported_features); 398a56dd9bfSIlya Dryomov con->v1.out_connect.host_type = cpu_to_le32(CEPH_ENTITY_TYPE_CLIENT); 399a56dd9bfSIlya Dryomov con->v1.out_connect.connect_seq = cpu_to_le32(con->v1.connect_seq); 400a56dd9bfSIlya Dryomov con->v1.out_connect.global_seq = cpu_to_le32(global_seq); 401a56dd9bfSIlya Dryomov con->v1.out_connect.protocol_version = cpu_to_le32(proto); 402a56dd9bfSIlya Dryomov con->v1.out_connect.flags = 0; 4032f713615SIlya Dryomov 4042f713615SIlya Dryomov ret = get_connect_authorizer(con); 4052f713615SIlya Dryomov if (ret) 4062f713615SIlya Dryomov return ret; 4072f713615SIlya Dryomov 4082f713615SIlya Dryomov __prepare_write_connect(con); 4092f713615SIlya Dryomov return 0; 4102f713615SIlya Dryomov } 4112f713615SIlya Dryomov 4122f713615SIlya Dryomov /* 4132f713615SIlya Dryomov * write as much of pending kvecs to the socket as we can. 4142f713615SIlya Dryomov * 1 -> done 4152f713615SIlya Dryomov * 0 -> socket full, but more to do 4162f713615SIlya Dryomov * <0 -> error 4172f713615SIlya Dryomov */ 4182f713615SIlya Dryomov static int write_partial_kvec(struct ceph_connection *con) 4192f713615SIlya Dryomov { 4202f713615SIlya Dryomov int ret; 4212f713615SIlya Dryomov 422a56dd9bfSIlya Dryomov dout("write_partial_kvec %p %d left\n", con, con->v1.out_kvec_bytes); 423a56dd9bfSIlya Dryomov while (con->v1.out_kvec_bytes > 0) { 424a56dd9bfSIlya Dryomov ret = ceph_tcp_sendmsg(con->sock, con->v1.out_kvec_cur, 425a56dd9bfSIlya Dryomov con->v1.out_kvec_left, 426a56dd9bfSIlya Dryomov con->v1.out_kvec_bytes, 427a56dd9bfSIlya Dryomov con->v1.out_more); 4282f713615SIlya Dryomov if (ret <= 0) 4292f713615SIlya Dryomov goto out; 430a56dd9bfSIlya Dryomov con->v1.out_kvec_bytes -= ret; 431a56dd9bfSIlya Dryomov if (!con->v1.out_kvec_bytes) 4322f713615SIlya Dryomov break; /* done */ 4332f713615SIlya Dryomov 4342f713615SIlya Dryomov /* account for full iov entries consumed */ 435a56dd9bfSIlya Dryomov while (ret >= con->v1.out_kvec_cur->iov_len) { 436a56dd9bfSIlya Dryomov BUG_ON(!con->v1.out_kvec_left); 437a56dd9bfSIlya Dryomov ret -= con->v1.out_kvec_cur->iov_len; 438a56dd9bfSIlya Dryomov con->v1.out_kvec_cur++; 439a56dd9bfSIlya Dryomov con->v1.out_kvec_left--; 4402f713615SIlya Dryomov } 4412f713615SIlya Dryomov /* and for a partially-consumed entry */ 4422f713615SIlya Dryomov if (ret) { 443a56dd9bfSIlya Dryomov con->v1.out_kvec_cur->iov_len -= ret; 444a56dd9bfSIlya Dryomov con->v1.out_kvec_cur->iov_base += ret; 4452f713615SIlya Dryomov } 4462f713615SIlya Dryomov } 447a56dd9bfSIlya Dryomov con->v1.out_kvec_left = 0; 4482f713615SIlya Dryomov ret = 1; 4492f713615SIlya Dryomov out: 4502f713615SIlya Dryomov dout("write_partial_kvec %p %d left in %d kvecs ret = %d\n", con, 451a56dd9bfSIlya Dryomov con->v1.out_kvec_bytes, con->v1.out_kvec_left, ret); 4522f713615SIlya Dryomov return ret; /* done! */ 4532f713615SIlya Dryomov } 4542f713615SIlya Dryomov 4552f713615SIlya Dryomov /* 4562f713615SIlya Dryomov * Write as much message data payload as we can. If we finish, queue 4572f713615SIlya Dryomov * up the footer. 4582f713615SIlya Dryomov * 1 -> done, footer is now queued in out_kvec[]. 4592f713615SIlya Dryomov * 0 -> socket full, but more to do 4602f713615SIlya Dryomov * <0 -> error 4612f713615SIlya Dryomov */ 4622f713615SIlya Dryomov static int write_partial_message_data(struct ceph_connection *con) 4632f713615SIlya Dryomov { 4642f713615SIlya Dryomov struct ceph_msg *msg = con->out_msg; 4652f713615SIlya Dryomov struct ceph_msg_data_cursor *cursor = &msg->cursor; 4662f713615SIlya Dryomov bool do_datacrc = !ceph_test_opt(from_msgr(con->msgr), NOCRC); 4672f713615SIlya Dryomov int more = MSG_MORE | MSG_SENDPAGE_NOTLAST; 4682f713615SIlya Dryomov u32 crc; 4692f713615SIlya Dryomov 4702f713615SIlya Dryomov dout("%s %p msg %p\n", __func__, con, msg); 4712f713615SIlya Dryomov 4722f713615SIlya Dryomov if (!msg->num_data_items) 4732f713615SIlya Dryomov return -EINVAL; 4742f713615SIlya Dryomov 4752f713615SIlya Dryomov /* 4762f713615SIlya Dryomov * Iterate through each page that contains data to be 4772f713615SIlya Dryomov * written, and send as much as possible for each. 4782f713615SIlya Dryomov * 4792f713615SIlya Dryomov * If we are calculating the data crc (the default), we will 4802f713615SIlya Dryomov * need to map the page. If we have no pages, they have 4812f713615SIlya Dryomov * been revoked, so use the zero page. 4822f713615SIlya Dryomov */ 4832f713615SIlya Dryomov crc = do_datacrc ? le32_to_cpu(msg->footer.data_crc) : 0; 4842f713615SIlya Dryomov while (cursor->total_resid) { 4852f713615SIlya Dryomov struct page *page; 4862f713615SIlya Dryomov size_t page_offset; 4872f713615SIlya Dryomov size_t length; 4882f713615SIlya Dryomov int ret; 4892f713615SIlya Dryomov 4902f713615SIlya Dryomov if (!cursor->resid) { 4912f713615SIlya Dryomov ceph_msg_data_advance(cursor, 0); 4922f713615SIlya Dryomov continue; 4932f713615SIlya Dryomov } 4942f713615SIlya Dryomov 495da4ab869SJeff Layton page = ceph_msg_data_next(cursor, &page_offset, &length); 4962f713615SIlya Dryomov if (length == cursor->total_resid) 4972f713615SIlya Dryomov more = MSG_MORE; 4982f713615SIlya Dryomov ret = ceph_tcp_sendpage(con->sock, page, page_offset, length, 4992f713615SIlya Dryomov more); 5002f713615SIlya Dryomov if (ret <= 0) { 5012f713615SIlya Dryomov if (do_datacrc) 5022f713615SIlya Dryomov msg->footer.data_crc = cpu_to_le32(crc); 5032f713615SIlya Dryomov 5042f713615SIlya Dryomov return ret; 5052f713615SIlya Dryomov } 5062f713615SIlya Dryomov if (do_datacrc && cursor->need_crc) 5072f713615SIlya Dryomov crc = ceph_crc32c_page(crc, page, page_offset, length); 5082f713615SIlya Dryomov ceph_msg_data_advance(cursor, (size_t)ret); 5092f713615SIlya Dryomov } 5102f713615SIlya Dryomov 5112f713615SIlya Dryomov dout("%s %p msg %p done\n", __func__, con, msg); 5122f713615SIlya Dryomov 5132f713615SIlya Dryomov /* prepare and queue up footer, too */ 5142f713615SIlya Dryomov if (do_datacrc) 5152f713615SIlya Dryomov msg->footer.data_crc = cpu_to_le32(crc); 5162f713615SIlya Dryomov else 5172f713615SIlya Dryomov msg->footer.flags |= CEPH_MSG_FOOTER_NOCRC; 5182f713615SIlya Dryomov con_out_kvec_reset(con); 5192f713615SIlya Dryomov prepare_write_message_footer(con); 5202f713615SIlya Dryomov 5212f713615SIlya Dryomov return 1; /* must return > 0 to indicate success */ 5222f713615SIlya Dryomov } 5232f713615SIlya Dryomov 5242f713615SIlya Dryomov /* 5252f713615SIlya Dryomov * write some zeros 5262f713615SIlya Dryomov */ 5272f713615SIlya Dryomov static int write_partial_skip(struct ceph_connection *con) 5282f713615SIlya Dryomov { 5292f713615SIlya Dryomov int more = MSG_MORE | MSG_SENDPAGE_NOTLAST; 5302f713615SIlya Dryomov int ret; 5312f713615SIlya Dryomov 532a56dd9bfSIlya Dryomov dout("%s %p %d left\n", __func__, con, con->v1.out_skip); 533a56dd9bfSIlya Dryomov while (con->v1.out_skip > 0) { 534a56dd9bfSIlya Dryomov size_t size = min(con->v1.out_skip, (int)PAGE_SIZE); 5352f713615SIlya Dryomov 536a56dd9bfSIlya Dryomov if (size == con->v1.out_skip) 5372f713615SIlya Dryomov more = MSG_MORE; 5382f713615SIlya Dryomov ret = ceph_tcp_sendpage(con->sock, ceph_zero_page, 0, size, 5392f713615SIlya Dryomov more); 5402f713615SIlya Dryomov if (ret <= 0) 5412f713615SIlya Dryomov goto out; 542a56dd9bfSIlya Dryomov con->v1.out_skip -= ret; 5432f713615SIlya Dryomov } 5442f713615SIlya Dryomov ret = 1; 5452f713615SIlya Dryomov out: 5462f713615SIlya Dryomov return ret; 5472f713615SIlya Dryomov } 5482f713615SIlya Dryomov 5492f713615SIlya Dryomov /* 5502f713615SIlya Dryomov * Prepare to read connection handshake, or an ack. 5512f713615SIlya Dryomov */ 5522f713615SIlya Dryomov static void prepare_read_banner(struct ceph_connection *con) 5532f713615SIlya Dryomov { 5542f713615SIlya Dryomov dout("prepare_read_banner %p\n", con); 555a56dd9bfSIlya Dryomov con->v1.in_base_pos = 0; 5562f713615SIlya Dryomov } 5572f713615SIlya Dryomov 5582f713615SIlya Dryomov static void prepare_read_connect(struct ceph_connection *con) 5592f713615SIlya Dryomov { 5602f713615SIlya Dryomov dout("prepare_read_connect %p\n", con); 561a56dd9bfSIlya Dryomov con->v1.in_base_pos = 0; 5622f713615SIlya Dryomov } 5632f713615SIlya Dryomov 5642f713615SIlya Dryomov static void prepare_read_ack(struct ceph_connection *con) 5652f713615SIlya Dryomov { 5662f713615SIlya Dryomov dout("prepare_read_ack %p\n", con); 567a56dd9bfSIlya Dryomov con->v1.in_base_pos = 0; 5682f713615SIlya Dryomov } 5692f713615SIlya Dryomov 5702f713615SIlya Dryomov static void prepare_read_seq(struct ceph_connection *con) 5712f713615SIlya Dryomov { 5722f713615SIlya Dryomov dout("prepare_read_seq %p\n", con); 573a56dd9bfSIlya Dryomov con->v1.in_base_pos = 0; 574a56dd9bfSIlya Dryomov con->v1.in_tag = CEPH_MSGR_TAG_SEQ; 5752f713615SIlya Dryomov } 5762f713615SIlya Dryomov 5772f713615SIlya Dryomov static void prepare_read_tag(struct ceph_connection *con) 5782f713615SIlya Dryomov { 5792f713615SIlya Dryomov dout("prepare_read_tag %p\n", con); 580a56dd9bfSIlya Dryomov con->v1.in_base_pos = 0; 581a56dd9bfSIlya Dryomov con->v1.in_tag = CEPH_MSGR_TAG_READY; 5822f713615SIlya Dryomov } 5832f713615SIlya Dryomov 5842f713615SIlya Dryomov static void prepare_read_keepalive_ack(struct ceph_connection *con) 5852f713615SIlya Dryomov { 5862f713615SIlya Dryomov dout("prepare_read_keepalive_ack %p\n", con); 587a56dd9bfSIlya Dryomov con->v1.in_base_pos = 0; 5882f713615SIlya Dryomov } 5892f713615SIlya Dryomov 5902f713615SIlya Dryomov /* 5912f713615SIlya Dryomov * Prepare to read a message. 5922f713615SIlya Dryomov */ 5932f713615SIlya Dryomov static int prepare_read_message(struct ceph_connection *con) 5942f713615SIlya Dryomov { 5952f713615SIlya Dryomov dout("prepare_read_message %p\n", con); 5962f713615SIlya Dryomov BUG_ON(con->in_msg != NULL); 597a56dd9bfSIlya Dryomov con->v1.in_base_pos = 0; 5982f713615SIlya Dryomov con->in_front_crc = con->in_middle_crc = con->in_data_crc = 0; 5992f713615SIlya Dryomov return 0; 6002f713615SIlya Dryomov } 6012f713615SIlya Dryomov 6022f713615SIlya Dryomov static int read_partial(struct ceph_connection *con, 6032f713615SIlya Dryomov int end, int size, void *object) 6042f713615SIlya Dryomov { 605a56dd9bfSIlya Dryomov while (con->v1.in_base_pos < end) { 606a56dd9bfSIlya Dryomov int left = end - con->v1.in_base_pos; 6072f713615SIlya Dryomov int have = size - left; 6082f713615SIlya Dryomov int ret = ceph_tcp_recvmsg(con->sock, object + have, left); 6092f713615SIlya Dryomov if (ret <= 0) 6102f713615SIlya Dryomov return ret; 611a56dd9bfSIlya Dryomov con->v1.in_base_pos += ret; 6122f713615SIlya Dryomov } 6132f713615SIlya Dryomov return 1; 6142f713615SIlya Dryomov } 6152f713615SIlya Dryomov 6162f713615SIlya Dryomov /* 6172f713615SIlya Dryomov * Read all or part of the connect-side handshake on a new connection 6182f713615SIlya Dryomov */ 6192f713615SIlya Dryomov static int read_partial_banner(struct ceph_connection *con) 6202f713615SIlya Dryomov { 6212f713615SIlya Dryomov int size; 6222f713615SIlya Dryomov int end; 6232f713615SIlya Dryomov int ret; 6242f713615SIlya Dryomov 625a56dd9bfSIlya Dryomov dout("read_partial_banner %p at %d\n", con, con->v1.in_base_pos); 6262f713615SIlya Dryomov 6272f713615SIlya Dryomov /* peer's banner */ 6282f713615SIlya Dryomov size = strlen(CEPH_BANNER); 6292f713615SIlya Dryomov end = size; 630a56dd9bfSIlya Dryomov ret = read_partial(con, end, size, con->v1.in_banner); 6312f713615SIlya Dryomov if (ret <= 0) 6322f713615SIlya Dryomov goto out; 6332f713615SIlya Dryomov 634a56dd9bfSIlya Dryomov size = sizeof(con->v1.actual_peer_addr); 6352f713615SIlya Dryomov end += size; 636a56dd9bfSIlya Dryomov ret = read_partial(con, end, size, &con->v1.actual_peer_addr); 6372f713615SIlya Dryomov if (ret <= 0) 6382f713615SIlya Dryomov goto out; 639a56dd9bfSIlya Dryomov ceph_decode_banner_addr(&con->v1.actual_peer_addr); 6402f713615SIlya Dryomov 641a56dd9bfSIlya Dryomov size = sizeof(con->v1.peer_addr_for_me); 6422f713615SIlya Dryomov end += size; 643a56dd9bfSIlya Dryomov ret = read_partial(con, end, size, &con->v1.peer_addr_for_me); 6442f713615SIlya Dryomov if (ret <= 0) 6452f713615SIlya Dryomov goto out; 646a56dd9bfSIlya Dryomov ceph_decode_banner_addr(&con->v1.peer_addr_for_me); 6472f713615SIlya Dryomov 6482f713615SIlya Dryomov out: 6492f713615SIlya Dryomov return ret; 6502f713615SIlya Dryomov } 6512f713615SIlya Dryomov 6522f713615SIlya Dryomov static int read_partial_connect(struct ceph_connection *con) 6532f713615SIlya Dryomov { 6542f713615SIlya Dryomov int size; 6552f713615SIlya Dryomov int end; 6562f713615SIlya Dryomov int ret; 6572f713615SIlya Dryomov 658a56dd9bfSIlya Dryomov dout("read_partial_connect %p at %d\n", con, con->v1.in_base_pos); 6592f713615SIlya Dryomov 660a56dd9bfSIlya Dryomov size = sizeof(con->v1.in_reply); 6612f713615SIlya Dryomov end = size; 662a56dd9bfSIlya Dryomov ret = read_partial(con, end, size, &con->v1.in_reply); 6632f713615SIlya Dryomov if (ret <= 0) 6642f713615SIlya Dryomov goto out; 6652f713615SIlya Dryomov 666a56dd9bfSIlya Dryomov if (con->v1.auth) { 667a56dd9bfSIlya Dryomov size = le32_to_cpu(con->v1.in_reply.authorizer_len); 668a56dd9bfSIlya Dryomov if (size > con->v1.auth->authorizer_reply_buf_len) { 6692f713615SIlya Dryomov pr_err("authorizer reply too big: %d > %zu\n", size, 670a56dd9bfSIlya Dryomov con->v1.auth->authorizer_reply_buf_len); 6712f713615SIlya Dryomov ret = -EINVAL; 6722f713615SIlya Dryomov goto out; 6732f713615SIlya Dryomov } 6742f713615SIlya Dryomov 6752f713615SIlya Dryomov end += size; 6762f713615SIlya Dryomov ret = read_partial(con, end, size, 677a56dd9bfSIlya Dryomov con->v1.auth->authorizer_reply_buf); 6782f713615SIlya Dryomov if (ret <= 0) 6792f713615SIlya Dryomov goto out; 6802f713615SIlya Dryomov } 6812f713615SIlya Dryomov 6822f713615SIlya Dryomov dout("read_partial_connect %p tag %d, con_seq = %u, g_seq = %u\n", 683a56dd9bfSIlya Dryomov con, con->v1.in_reply.tag, 684a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.in_reply.connect_seq), 685a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.in_reply.global_seq)); 6862f713615SIlya Dryomov out: 6872f713615SIlya Dryomov return ret; 6882f713615SIlya Dryomov } 6892f713615SIlya Dryomov 6902f713615SIlya Dryomov /* 6912f713615SIlya Dryomov * Verify the hello banner looks okay. 6922f713615SIlya Dryomov */ 6932f713615SIlya Dryomov static int verify_hello(struct ceph_connection *con) 6942f713615SIlya Dryomov { 695a56dd9bfSIlya Dryomov if (memcmp(con->v1.in_banner, CEPH_BANNER, strlen(CEPH_BANNER))) { 6962f713615SIlya Dryomov pr_err("connect to %s got bad banner\n", 6972f713615SIlya Dryomov ceph_pr_addr(&con->peer_addr)); 6982f713615SIlya Dryomov con->error_msg = "protocol error, bad banner"; 6992f713615SIlya Dryomov return -1; 7002f713615SIlya Dryomov } 7012f713615SIlya Dryomov return 0; 7022f713615SIlya Dryomov } 7032f713615SIlya Dryomov 7042f713615SIlya Dryomov static int process_banner(struct ceph_connection *con) 7052f713615SIlya Dryomov { 7062f713615SIlya Dryomov struct ceph_entity_addr *my_addr = &con->msgr->inst.addr; 7072f713615SIlya Dryomov 7082f713615SIlya Dryomov dout("process_banner on %p\n", con); 7092f713615SIlya Dryomov 7102f713615SIlya Dryomov if (verify_hello(con) < 0) 7112f713615SIlya Dryomov return -1; 7122f713615SIlya Dryomov 7132f713615SIlya Dryomov /* 7142f713615SIlya Dryomov * Make sure the other end is who we wanted. note that the other 7152f713615SIlya Dryomov * end may not yet know their ip address, so if it's 0.0.0.0, give 7162f713615SIlya Dryomov * them the benefit of the doubt. 7172f713615SIlya Dryomov */ 718a56dd9bfSIlya Dryomov if (memcmp(&con->peer_addr, &con->v1.actual_peer_addr, 7192f713615SIlya Dryomov sizeof(con->peer_addr)) != 0 && 720a56dd9bfSIlya Dryomov !(ceph_addr_is_blank(&con->v1.actual_peer_addr) && 721a56dd9bfSIlya Dryomov con->v1.actual_peer_addr.nonce == con->peer_addr.nonce)) { 7222f713615SIlya Dryomov pr_warn("wrong peer, want %s/%u, got %s/%u\n", 7232f713615SIlya Dryomov ceph_pr_addr(&con->peer_addr), 7242f713615SIlya Dryomov le32_to_cpu(con->peer_addr.nonce), 725a56dd9bfSIlya Dryomov ceph_pr_addr(&con->v1.actual_peer_addr), 726a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.actual_peer_addr.nonce)); 7272f713615SIlya Dryomov con->error_msg = "wrong peer at address"; 7282f713615SIlya Dryomov return -1; 7292f713615SIlya Dryomov } 7302f713615SIlya Dryomov 7312f713615SIlya Dryomov /* 7322f713615SIlya Dryomov * did we learn our address? 7332f713615SIlya Dryomov */ 7342f713615SIlya Dryomov if (ceph_addr_is_blank(my_addr)) { 7352f713615SIlya Dryomov memcpy(&my_addr->in_addr, 736a56dd9bfSIlya Dryomov &con->v1.peer_addr_for_me.in_addr, 737a56dd9bfSIlya Dryomov sizeof(con->v1.peer_addr_for_me.in_addr)); 7382f713615SIlya Dryomov ceph_addr_set_port(my_addr, 0); 7392f713615SIlya Dryomov ceph_encode_my_addr(con->msgr); 7402f713615SIlya Dryomov dout("process_banner learned my addr is %s\n", 7412f713615SIlya Dryomov ceph_pr_addr(my_addr)); 7422f713615SIlya Dryomov } 7432f713615SIlya Dryomov 7442f713615SIlya Dryomov return 0; 7452f713615SIlya Dryomov } 7462f713615SIlya Dryomov 7472f713615SIlya Dryomov static int process_connect(struct ceph_connection *con) 7482f713615SIlya Dryomov { 7492f713615SIlya Dryomov u64 sup_feat = from_msgr(con->msgr)->supported_features; 7502f713615SIlya Dryomov u64 req_feat = from_msgr(con->msgr)->required_features; 751a56dd9bfSIlya Dryomov u64 server_feat = le64_to_cpu(con->v1.in_reply.features); 7522f713615SIlya Dryomov int ret; 7532f713615SIlya Dryomov 754a56dd9bfSIlya Dryomov dout("process_connect on %p tag %d\n", con, con->v1.in_tag); 7552f713615SIlya Dryomov 756a56dd9bfSIlya Dryomov if (con->v1.auth) { 757a56dd9bfSIlya Dryomov int len = le32_to_cpu(con->v1.in_reply.authorizer_len); 7582f713615SIlya Dryomov 7592f713615SIlya Dryomov /* 7602f713615SIlya Dryomov * Any connection that defines ->get_authorizer() 7612f713615SIlya Dryomov * should also define ->add_authorizer_challenge() and 7622f713615SIlya Dryomov * ->verify_authorizer_reply(). 7632f713615SIlya Dryomov * 7642f713615SIlya Dryomov * See get_connect_authorizer(). 7652f713615SIlya Dryomov */ 766a56dd9bfSIlya Dryomov if (con->v1.in_reply.tag == 767a56dd9bfSIlya Dryomov CEPH_MSGR_TAG_CHALLENGE_AUTHORIZER) { 7682f713615SIlya Dryomov ret = con->ops->add_authorizer_challenge( 769a56dd9bfSIlya Dryomov con, con->v1.auth->authorizer_reply_buf, len); 7702f713615SIlya Dryomov if (ret < 0) 7712f713615SIlya Dryomov return ret; 7722f713615SIlya Dryomov 7732f713615SIlya Dryomov con_out_kvec_reset(con); 7742f713615SIlya Dryomov __prepare_write_connect(con); 7752f713615SIlya Dryomov prepare_read_connect(con); 7762f713615SIlya Dryomov return 0; 7772f713615SIlya Dryomov } 7782f713615SIlya Dryomov 7792f713615SIlya Dryomov if (len) { 7802f713615SIlya Dryomov ret = con->ops->verify_authorizer_reply(con); 7812f713615SIlya Dryomov if (ret < 0) { 7822f713615SIlya Dryomov con->error_msg = "bad authorize reply"; 7832f713615SIlya Dryomov return ret; 7842f713615SIlya Dryomov } 7852f713615SIlya Dryomov } 7862f713615SIlya Dryomov } 7872f713615SIlya Dryomov 788a56dd9bfSIlya Dryomov switch (con->v1.in_reply.tag) { 7892f713615SIlya Dryomov case CEPH_MSGR_TAG_FEATURES: 7902f713615SIlya Dryomov pr_err("%s%lld %s feature set mismatch," 7912f713615SIlya Dryomov " my %llx < server's %llx, missing %llx\n", 7922f713615SIlya Dryomov ENTITY_NAME(con->peer_name), 7932f713615SIlya Dryomov ceph_pr_addr(&con->peer_addr), 7942f713615SIlya Dryomov sup_feat, server_feat, server_feat & ~sup_feat); 7952f713615SIlya Dryomov con->error_msg = "missing required protocol features"; 7962f713615SIlya Dryomov return -1; 7972f713615SIlya Dryomov 7982f713615SIlya Dryomov case CEPH_MSGR_TAG_BADPROTOVER: 7992f713615SIlya Dryomov pr_err("%s%lld %s protocol version mismatch," 8002f713615SIlya Dryomov " my %d != server's %d\n", 8012f713615SIlya Dryomov ENTITY_NAME(con->peer_name), 8022f713615SIlya Dryomov ceph_pr_addr(&con->peer_addr), 803a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.out_connect.protocol_version), 804a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.in_reply.protocol_version)); 8052f713615SIlya Dryomov con->error_msg = "protocol version mismatch"; 8062f713615SIlya Dryomov return -1; 8072f713615SIlya Dryomov 8082f713615SIlya Dryomov case CEPH_MSGR_TAG_BADAUTHORIZER: 809a56dd9bfSIlya Dryomov con->v1.auth_retry++; 8102f713615SIlya Dryomov dout("process_connect %p got BADAUTHORIZER attempt %d\n", con, 811a56dd9bfSIlya Dryomov con->v1.auth_retry); 812a56dd9bfSIlya Dryomov if (con->v1.auth_retry == 2) { 8132f713615SIlya Dryomov con->error_msg = "connect authorization failure"; 8142f713615SIlya Dryomov return -1; 8152f713615SIlya Dryomov } 8162f713615SIlya Dryomov con_out_kvec_reset(con); 8172f713615SIlya Dryomov ret = prepare_write_connect(con); 8182f713615SIlya Dryomov if (ret < 0) 8192f713615SIlya Dryomov return ret; 8202f713615SIlya Dryomov prepare_read_connect(con); 8212f713615SIlya Dryomov break; 8222f713615SIlya Dryomov 8232f713615SIlya Dryomov case CEPH_MSGR_TAG_RESETSESSION: 8242f713615SIlya Dryomov /* 8252f713615SIlya Dryomov * If we connected with a large connect_seq but the peer 8262f713615SIlya Dryomov * has no record of a session with us (no connection, or 8272f713615SIlya Dryomov * connect_seq == 0), they will send RESETSESION to indicate 8282f713615SIlya Dryomov * that they must have reset their session, and may have 8292f713615SIlya Dryomov * dropped messages. 8302f713615SIlya Dryomov */ 8312f713615SIlya Dryomov dout("process_connect got RESET peer seq %u\n", 832a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.in_reply.connect_seq)); 8332f713615SIlya Dryomov pr_info("%s%lld %s session reset\n", 8342f713615SIlya Dryomov ENTITY_NAME(con->peer_name), 8352f713615SIlya Dryomov ceph_pr_addr(&con->peer_addr)); 8362f713615SIlya Dryomov ceph_con_reset_session(con); 8372f713615SIlya Dryomov con_out_kvec_reset(con); 8382f713615SIlya Dryomov ret = prepare_write_connect(con); 8392f713615SIlya Dryomov if (ret < 0) 8402f713615SIlya Dryomov return ret; 8412f713615SIlya Dryomov prepare_read_connect(con); 8422f713615SIlya Dryomov 8432f713615SIlya Dryomov /* Tell ceph about it. */ 8442f713615SIlya Dryomov mutex_unlock(&con->mutex); 8452f713615SIlya Dryomov if (con->ops->peer_reset) 8462f713615SIlya Dryomov con->ops->peer_reset(con); 8472f713615SIlya Dryomov mutex_lock(&con->mutex); 8482f713615SIlya Dryomov if (con->state != CEPH_CON_S_V1_CONNECT_MSG) 8492f713615SIlya Dryomov return -EAGAIN; 8502f713615SIlya Dryomov break; 8512f713615SIlya Dryomov 8522f713615SIlya Dryomov case CEPH_MSGR_TAG_RETRY_SESSION: 8532f713615SIlya Dryomov /* 8542f713615SIlya Dryomov * If we sent a smaller connect_seq than the peer has, try 8552f713615SIlya Dryomov * again with a larger value. 8562f713615SIlya Dryomov */ 8572f713615SIlya Dryomov dout("process_connect got RETRY_SESSION my seq %u, peer %u\n", 858a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.out_connect.connect_seq), 859a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.in_reply.connect_seq)); 860a56dd9bfSIlya Dryomov con->v1.connect_seq = le32_to_cpu(con->v1.in_reply.connect_seq); 8612f713615SIlya Dryomov con_out_kvec_reset(con); 8622f713615SIlya Dryomov ret = prepare_write_connect(con); 8632f713615SIlya Dryomov if (ret < 0) 8642f713615SIlya Dryomov return ret; 8652f713615SIlya Dryomov prepare_read_connect(con); 8662f713615SIlya Dryomov break; 8672f713615SIlya Dryomov 8682f713615SIlya Dryomov case CEPH_MSGR_TAG_RETRY_GLOBAL: 8692f713615SIlya Dryomov /* 8702f713615SIlya Dryomov * If we sent a smaller global_seq than the peer has, try 8712f713615SIlya Dryomov * again with a larger value. 8722f713615SIlya Dryomov */ 8732f713615SIlya Dryomov dout("process_connect got RETRY_GLOBAL my %u peer_gseq %u\n", 874a56dd9bfSIlya Dryomov con->v1.peer_global_seq, 875a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.in_reply.global_seq)); 8762f713615SIlya Dryomov ceph_get_global_seq(con->msgr, 877a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.in_reply.global_seq)); 8782f713615SIlya Dryomov con_out_kvec_reset(con); 8792f713615SIlya Dryomov ret = prepare_write_connect(con); 8802f713615SIlya Dryomov if (ret < 0) 8812f713615SIlya Dryomov return ret; 8822f713615SIlya Dryomov prepare_read_connect(con); 8832f713615SIlya Dryomov break; 8842f713615SIlya Dryomov 8852f713615SIlya Dryomov case CEPH_MSGR_TAG_SEQ: 8862f713615SIlya Dryomov case CEPH_MSGR_TAG_READY: 8872f713615SIlya Dryomov if (req_feat & ~server_feat) { 8882f713615SIlya Dryomov pr_err("%s%lld %s protocol feature mismatch," 8892f713615SIlya Dryomov " my required %llx > server's %llx, need %llx\n", 8902f713615SIlya Dryomov ENTITY_NAME(con->peer_name), 8912f713615SIlya Dryomov ceph_pr_addr(&con->peer_addr), 8922f713615SIlya Dryomov req_feat, server_feat, req_feat & ~server_feat); 8932f713615SIlya Dryomov con->error_msg = "missing required protocol features"; 8942f713615SIlya Dryomov return -1; 8952f713615SIlya Dryomov } 8962f713615SIlya Dryomov 8972f713615SIlya Dryomov WARN_ON(con->state != CEPH_CON_S_V1_CONNECT_MSG); 8982f713615SIlya Dryomov con->state = CEPH_CON_S_OPEN; 899a56dd9bfSIlya Dryomov con->v1.auth_retry = 0; /* we authenticated; clear flag */ 900a56dd9bfSIlya Dryomov con->v1.peer_global_seq = 901a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.in_reply.global_seq); 902a56dd9bfSIlya Dryomov con->v1.connect_seq++; 9032f713615SIlya Dryomov con->peer_features = server_feat; 9042f713615SIlya Dryomov dout("process_connect got READY gseq %d cseq %d (%d)\n", 905a56dd9bfSIlya Dryomov con->v1.peer_global_seq, 906a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.in_reply.connect_seq), 907a56dd9bfSIlya Dryomov con->v1.connect_seq); 908a56dd9bfSIlya Dryomov WARN_ON(con->v1.connect_seq != 909a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.in_reply.connect_seq)); 9102f713615SIlya Dryomov 911a56dd9bfSIlya Dryomov if (con->v1.in_reply.flags & CEPH_MSG_CONNECT_LOSSY) 9122f713615SIlya Dryomov ceph_con_flag_set(con, CEPH_CON_F_LOSSYTX); 9132f713615SIlya Dryomov 9142f713615SIlya Dryomov con->delay = 0; /* reset backoff memory */ 9152f713615SIlya Dryomov 916a56dd9bfSIlya Dryomov if (con->v1.in_reply.tag == CEPH_MSGR_TAG_SEQ) { 9172f713615SIlya Dryomov prepare_write_seq(con); 9182f713615SIlya Dryomov prepare_read_seq(con); 9192f713615SIlya Dryomov } else { 9202f713615SIlya Dryomov prepare_read_tag(con); 9212f713615SIlya Dryomov } 9222f713615SIlya Dryomov break; 9232f713615SIlya Dryomov 9242f713615SIlya Dryomov case CEPH_MSGR_TAG_WAIT: 9252f713615SIlya Dryomov /* 9262f713615SIlya Dryomov * If there is a connection race (we are opening 9272f713615SIlya Dryomov * connections to each other), one of us may just have 9282f713615SIlya Dryomov * to WAIT. This shouldn't happen if we are the 9292f713615SIlya Dryomov * client. 9302f713615SIlya Dryomov */ 9312f713615SIlya Dryomov con->error_msg = "protocol error, got WAIT as client"; 9322f713615SIlya Dryomov return -1; 9332f713615SIlya Dryomov 9342f713615SIlya Dryomov default: 9352f713615SIlya Dryomov con->error_msg = "protocol error, garbage tag during connect"; 9362f713615SIlya Dryomov return -1; 9372f713615SIlya Dryomov } 9382f713615SIlya Dryomov return 0; 9392f713615SIlya Dryomov } 9402f713615SIlya Dryomov 9412f713615SIlya Dryomov /* 9422f713615SIlya Dryomov * read (part of) an ack 9432f713615SIlya Dryomov */ 9442f713615SIlya Dryomov static int read_partial_ack(struct ceph_connection *con) 9452f713615SIlya Dryomov { 946a56dd9bfSIlya Dryomov int size = sizeof(con->v1.in_temp_ack); 9472f713615SIlya Dryomov int end = size; 9482f713615SIlya Dryomov 949a56dd9bfSIlya Dryomov return read_partial(con, end, size, &con->v1.in_temp_ack); 9502f713615SIlya Dryomov } 9512f713615SIlya Dryomov 9522f713615SIlya Dryomov /* 9532f713615SIlya Dryomov * We can finally discard anything that's been acked. 9542f713615SIlya Dryomov */ 9552f713615SIlya Dryomov static void process_ack(struct ceph_connection *con) 9562f713615SIlya Dryomov { 957a56dd9bfSIlya Dryomov u64 ack = le64_to_cpu(con->v1.in_temp_ack); 9582f713615SIlya Dryomov 959a56dd9bfSIlya Dryomov if (con->v1.in_tag == CEPH_MSGR_TAG_ACK) 9602f713615SIlya Dryomov ceph_con_discard_sent(con, ack); 9612f713615SIlya Dryomov else 9622f713615SIlya Dryomov ceph_con_discard_requeued(con, ack); 9632f713615SIlya Dryomov 9642f713615SIlya Dryomov prepare_read_tag(con); 9652f713615SIlya Dryomov } 9662f713615SIlya Dryomov 9672f713615SIlya Dryomov static int read_partial_message_section(struct ceph_connection *con, 9682f713615SIlya Dryomov struct kvec *section, 9692f713615SIlya Dryomov unsigned int sec_len, u32 *crc) 9702f713615SIlya Dryomov { 9712f713615SIlya Dryomov int ret, left; 9722f713615SIlya Dryomov 9732f713615SIlya Dryomov BUG_ON(!section); 9742f713615SIlya Dryomov 9752f713615SIlya Dryomov while (section->iov_len < sec_len) { 9762f713615SIlya Dryomov BUG_ON(section->iov_base == NULL); 9772f713615SIlya Dryomov left = sec_len - section->iov_len; 9782f713615SIlya Dryomov ret = ceph_tcp_recvmsg(con->sock, (char *)section->iov_base + 9792f713615SIlya Dryomov section->iov_len, left); 9802f713615SIlya Dryomov if (ret <= 0) 9812f713615SIlya Dryomov return ret; 9822f713615SIlya Dryomov section->iov_len += ret; 9832f713615SIlya Dryomov } 9842f713615SIlya Dryomov if (section->iov_len == sec_len) 9852f713615SIlya Dryomov *crc = crc32c(0, section->iov_base, section->iov_len); 9862f713615SIlya Dryomov 9872f713615SIlya Dryomov return 1; 9882f713615SIlya Dryomov } 9892f713615SIlya Dryomov 9902f713615SIlya Dryomov static int read_partial_msg_data(struct ceph_connection *con) 9912f713615SIlya Dryomov { 992038b8d1dSIlya Dryomov struct ceph_msg_data_cursor *cursor = &con->in_msg->cursor; 9932f713615SIlya Dryomov bool do_datacrc = !ceph_test_opt(from_msgr(con->msgr), NOCRC); 9942f713615SIlya Dryomov struct page *page; 9952f713615SIlya Dryomov size_t page_offset; 9962f713615SIlya Dryomov size_t length; 9972f713615SIlya Dryomov u32 crc = 0; 9982f713615SIlya Dryomov int ret; 9992f713615SIlya Dryomov 10002f713615SIlya Dryomov if (do_datacrc) 10012f713615SIlya Dryomov crc = con->in_data_crc; 10022f713615SIlya Dryomov while (cursor->total_resid) { 10032f713615SIlya Dryomov if (!cursor->resid) { 10042f713615SIlya Dryomov ceph_msg_data_advance(cursor, 0); 10052f713615SIlya Dryomov continue; 10062f713615SIlya Dryomov } 10072f713615SIlya Dryomov 1008da4ab869SJeff Layton page = ceph_msg_data_next(cursor, &page_offset, &length); 10092f713615SIlya Dryomov ret = ceph_tcp_recvpage(con->sock, page, page_offset, length); 10102f713615SIlya Dryomov if (ret <= 0) { 10112f713615SIlya Dryomov if (do_datacrc) 10122f713615SIlya Dryomov con->in_data_crc = crc; 10132f713615SIlya Dryomov 10142f713615SIlya Dryomov return ret; 10152f713615SIlya Dryomov } 10162f713615SIlya Dryomov 10172f713615SIlya Dryomov if (do_datacrc) 10182f713615SIlya Dryomov crc = ceph_crc32c_page(crc, page, page_offset, ret); 10192f713615SIlya Dryomov ceph_msg_data_advance(cursor, (size_t)ret); 10202f713615SIlya Dryomov } 10212f713615SIlya Dryomov if (do_datacrc) 10222f713615SIlya Dryomov con->in_data_crc = crc; 10232f713615SIlya Dryomov 10242f713615SIlya Dryomov return 1; /* must return > 0 to indicate success */ 10252f713615SIlya Dryomov } 10262f713615SIlya Dryomov 1027038b8d1dSIlya Dryomov static int read_partial_msg_data_bounce(struct ceph_connection *con) 1028038b8d1dSIlya Dryomov { 1029038b8d1dSIlya Dryomov struct ceph_msg_data_cursor *cursor = &con->in_msg->cursor; 1030038b8d1dSIlya Dryomov struct page *page; 1031038b8d1dSIlya Dryomov size_t off, len; 1032038b8d1dSIlya Dryomov u32 crc; 1033038b8d1dSIlya Dryomov int ret; 1034038b8d1dSIlya Dryomov 1035038b8d1dSIlya Dryomov if (unlikely(!con->bounce_page)) { 1036038b8d1dSIlya Dryomov con->bounce_page = alloc_page(GFP_NOIO); 1037038b8d1dSIlya Dryomov if (!con->bounce_page) { 1038038b8d1dSIlya Dryomov pr_err("failed to allocate bounce page\n"); 1039038b8d1dSIlya Dryomov return -ENOMEM; 1040038b8d1dSIlya Dryomov } 1041038b8d1dSIlya Dryomov } 1042038b8d1dSIlya Dryomov 1043038b8d1dSIlya Dryomov crc = con->in_data_crc; 1044038b8d1dSIlya Dryomov while (cursor->total_resid) { 1045038b8d1dSIlya Dryomov if (!cursor->resid) { 1046038b8d1dSIlya Dryomov ceph_msg_data_advance(cursor, 0); 1047038b8d1dSIlya Dryomov continue; 1048038b8d1dSIlya Dryomov } 1049038b8d1dSIlya Dryomov 1050da4ab869SJeff Layton page = ceph_msg_data_next(cursor, &off, &len); 1051038b8d1dSIlya Dryomov ret = ceph_tcp_recvpage(con->sock, con->bounce_page, 0, len); 1052038b8d1dSIlya Dryomov if (ret <= 0) { 1053038b8d1dSIlya Dryomov con->in_data_crc = crc; 1054038b8d1dSIlya Dryomov return ret; 1055038b8d1dSIlya Dryomov } 1056038b8d1dSIlya Dryomov 1057038b8d1dSIlya Dryomov crc = crc32c(crc, page_address(con->bounce_page), ret); 1058038b8d1dSIlya Dryomov memcpy_to_page(page, off, page_address(con->bounce_page), ret); 1059038b8d1dSIlya Dryomov 1060038b8d1dSIlya Dryomov ceph_msg_data_advance(cursor, ret); 1061038b8d1dSIlya Dryomov } 1062038b8d1dSIlya Dryomov con->in_data_crc = crc; 1063038b8d1dSIlya Dryomov 1064038b8d1dSIlya Dryomov return 1; /* must return > 0 to indicate success */ 1065038b8d1dSIlya Dryomov } 1066038b8d1dSIlya Dryomov 10672f713615SIlya Dryomov /* 10682f713615SIlya Dryomov * read (part of) a message. 10692f713615SIlya Dryomov */ 10702f713615SIlya Dryomov static int read_partial_message(struct ceph_connection *con) 10712f713615SIlya Dryomov { 10722f713615SIlya Dryomov struct ceph_msg *m = con->in_msg; 10732f713615SIlya Dryomov int size; 10742f713615SIlya Dryomov int end; 10752f713615SIlya Dryomov int ret; 10762f713615SIlya Dryomov unsigned int front_len, middle_len, data_len; 10772f713615SIlya Dryomov bool do_datacrc = !ceph_test_opt(from_msgr(con->msgr), NOCRC); 10782f713615SIlya Dryomov bool need_sign = (con->peer_features & CEPH_FEATURE_MSG_AUTH); 10792f713615SIlya Dryomov u64 seq; 10802f713615SIlya Dryomov u32 crc; 10812f713615SIlya Dryomov 10822f713615SIlya Dryomov dout("read_partial_message con %p msg %p\n", con, m); 10832f713615SIlya Dryomov 10842f713615SIlya Dryomov /* header */ 1085a56dd9bfSIlya Dryomov size = sizeof(con->v1.in_hdr); 10862f713615SIlya Dryomov end = size; 1087a56dd9bfSIlya Dryomov ret = read_partial(con, end, size, &con->v1.in_hdr); 10882f713615SIlya Dryomov if (ret <= 0) 10892f713615SIlya Dryomov return ret; 10902f713615SIlya Dryomov 1091a56dd9bfSIlya Dryomov crc = crc32c(0, &con->v1.in_hdr, offsetof(struct ceph_msg_header, crc)); 1092a56dd9bfSIlya Dryomov if (cpu_to_le32(crc) != con->v1.in_hdr.crc) { 10932f713615SIlya Dryomov pr_err("read_partial_message bad hdr crc %u != expected %u\n", 1094a56dd9bfSIlya Dryomov crc, con->v1.in_hdr.crc); 10952f713615SIlya Dryomov return -EBADMSG; 10962f713615SIlya Dryomov } 10972f713615SIlya Dryomov 1098a56dd9bfSIlya Dryomov front_len = le32_to_cpu(con->v1.in_hdr.front_len); 10992f713615SIlya Dryomov if (front_len > CEPH_MSG_MAX_FRONT_LEN) 11002f713615SIlya Dryomov return -EIO; 1101a56dd9bfSIlya Dryomov middle_len = le32_to_cpu(con->v1.in_hdr.middle_len); 11022f713615SIlya Dryomov if (middle_len > CEPH_MSG_MAX_MIDDLE_LEN) 11032f713615SIlya Dryomov return -EIO; 1104a56dd9bfSIlya Dryomov data_len = le32_to_cpu(con->v1.in_hdr.data_len); 11052f713615SIlya Dryomov if (data_len > CEPH_MSG_MAX_DATA_LEN) 11062f713615SIlya Dryomov return -EIO; 11072f713615SIlya Dryomov 11082f713615SIlya Dryomov /* verify seq# */ 1109a56dd9bfSIlya Dryomov seq = le64_to_cpu(con->v1.in_hdr.seq); 11102f713615SIlya Dryomov if ((s64)seq - (s64)con->in_seq < 1) { 11112f713615SIlya Dryomov pr_info("skipping %s%lld %s seq %lld expected %lld\n", 11122f713615SIlya Dryomov ENTITY_NAME(con->peer_name), 11132f713615SIlya Dryomov ceph_pr_addr(&con->peer_addr), 11142f713615SIlya Dryomov seq, con->in_seq + 1); 1115a56dd9bfSIlya Dryomov con->v1.in_base_pos = -front_len - middle_len - data_len - 11162f713615SIlya Dryomov sizeof_footer(con); 1117a56dd9bfSIlya Dryomov con->v1.in_tag = CEPH_MSGR_TAG_READY; 11182f713615SIlya Dryomov return 1; 11192f713615SIlya Dryomov } else if ((s64)seq - (s64)con->in_seq > 1) { 11202f713615SIlya Dryomov pr_err("read_partial_message bad seq %lld expected %lld\n", 11212f713615SIlya Dryomov seq, con->in_seq + 1); 11222f713615SIlya Dryomov con->error_msg = "bad message sequence # for incoming message"; 11232f713615SIlya Dryomov return -EBADE; 11242f713615SIlya Dryomov } 11252f713615SIlya Dryomov 11262f713615SIlya Dryomov /* allocate message? */ 11272f713615SIlya Dryomov if (!con->in_msg) { 11282f713615SIlya Dryomov int skip = 0; 11292f713615SIlya Dryomov 1130a56dd9bfSIlya Dryomov dout("got hdr type %d front %d data %d\n", con->v1.in_hdr.type, 11312f713615SIlya Dryomov front_len, data_len); 1132a56dd9bfSIlya Dryomov ret = ceph_con_in_msg_alloc(con, &con->v1.in_hdr, &skip); 11332f713615SIlya Dryomov if (ret < 0) 11342f713615SIlya Dryomov return ret; 11352f713615SIlya Dryomov 11369d5ae6f3SIlya Dryomov BUG_ON((!con->in_msg) ^ skip); 11372f713615SIlya Dryomov if (skip) { 11382f713615SIlya Dryomov /* skip this message */ 11392f713615SIlya Dryomov dout("alloc_msg said skip message\n"); 1140a56dd9bfSIlya Dryomov con->v1.in_base_pos = -front_len - middle_len - 1141a56dd9bfSIlya Dryomov data_len - sizeof_footer(con); 1142a56dd9bfSIlya Dryomov con->v1.in_tag = CEPH_MSGR_TAG_READY; 11432f713615SIlya Dryomov con->in_seq++; 11442f713615SIlya Dryomov return 1; 11452f713615SIlya Dryomov } 11462f713615SIlya Dryomov 11472f713615SIlya Dryomov BUG_ON(!con->in_msg); 11482f713615SIlya Dryomov BUG_ON(con->in_msg->con != con); 11492f713615SIlya Dryomov m = con->in_msg; 11502f713615SIlya Dryomov m->front.iov_len = 0; /* haven't read it yet */ 11512f713615SIlya Dryomov if (m->middle) 11522f713615SIlya Dryomov m->middle->vec.iov_len = 0; 11532f713615SIlya Dryomov 11542f713615SIlya Dryomov /* prepare for data payload, if any */ 11552f713615SIlya Dryomov 11562f713615SIlya Dryomov if (data_len) 11572f713615SIlya Dryomov prepare_message_data(con->in_msg, data_len); 11582f713615SIlya Dryomov } 11592f713615SIlya Dryomov 11602f713615SIlya Dryomov /* front */ 11612f713615SIlya Dryomov ret = read_partial_message_section(con, &m->front, front_len, 11622f713615SIlya Dryomov &con->in_front_crc); 11632f713615SIlya Dryomov if (ret <= 0) 11642f713615SIlya Dryomov return ret; 11652f713615SIlya Dryomov 11662f713615SIlya Dryomov /* middle */ 11672f713615SIlya Dryomov if (m->middle) { 11682f713615SIlya Dryomov ret = read_partial_message_section(con, &m->middle->vec, 11692f713615SIlya Dryomov middle_len, 11702f713615SIlya Dryomov &con->in_middle_crc); 11712f713615SIlya Dryomov if (ret <= 0) 11722f713615SIlya Dryomov return ret; 11732f713615SIlya Dryomov } 11742f713615SIlya Dryomov 11752f713615SIlya Dryomov /* (page) data */ 11762f713615SIlya Dryomov if (data_len) { 1177038b8d1dSIlya Dryomov if (!m->num_data_items) 1178038b8d1dSIlya Dryomov return -EIO; 1179038b8d1dSIlya Dryomov 1180038b8d1dSIlya Dryomov if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE)) 1181038b8d1dSIlya Dryomov ret = read_partial_msg_data_bounce(con); 1182038b8d1dSIlya Dryomov else 11832f713615SIlya Dryomov ret = read_partial_msg_data(con); 11842f713615SIlya Dryomov if (ret <= 0) 11852f713615SIlya Dryomov return ret; 11862f713615SIlya Dryomov } 11872f713615SIlya Dryomov 11882f713615SIlya Dryomov /* footer */ 11892f713615SIlya Dryomov size = sizeof_footer(con); 11902f713615SIlya Dryomov end += size; 11912f713615SIlya Dryomov ret = read_partial(con, end, size, &m->footer); 11922f713615SIlya Dryomov if (ret <= 0) 11932f713615SIlya Dryomov return ret; 11942f713615SIlya Dryomov 11952f713615SIlya Dryomov if (!need_sign) { 11962f713615SIlya Dryomov m->footer.flags = m->old_footer.flags; 11972f713615SIlya Dryomov m->footer.sig = 0; 11982f713615SIlya Dryomov } 11992f713615SIlya Dryomov 12002f713615SIlya Dryomov dout("read_partial_message got msg %p %d (%u) + %d (%u) + %d (%u)\n", 12012f713615SIlya Dryomov m, front_len, m->footer.front_crc, middle_len, 12022f713615SIlya Dryomov m->footer.middle_crc, data_len, m->footer.data_crc); 12032f713615SIlya Dryomov 12042f713615SIlya Dryomov /* crc ok? */ 12052f713615SIlya Dryomov if (con->in_front_crc != le32_to_cpu(m->footer.front_crc)) { 12062f713615SIlya Dryomov pr_err("read_partial_message %p front crc %u != exp. %u\n", 12072f713615SIlya Dryomov m, con->in_front_crc, m->footer.front_crc); 12082f713615SIlya Dryomov return -EBADMSG; 12092f713615SIlya Dryomov } 12102f713615SIlya Dryomov if (con->in_middle_crc != le32_to_cpu(m->footer.middle_crc)) { 12112f713615SIlya Dryomov pr_err("read_partial_message %p middle crc %u != exp %u\n", 12122f713615SIlya Dryomov m, con->in_middle_crc, m->footer.middle_crc); 12132f713615SIlya Dryomov return -EBADMSG; 12142f713615SIlya Dryomov } 12152f713615SIlya Dryomov if (do_datacrc && 12162f713615SIlya Dryomov (m->footer.flags & CEPH_MSG_FOOTER_NOCRC) == 0 && 12172f713615SIlya Dryomov con->in_data_crc != le32_to_cpu(m->footer.data_crc)) { 12182f713615SIlya Dryomov pr_err("read_partial_message %p data crc %u != exp. %u\n", m, 12192f713615SIlya Dryomov con->in_data_crc, le32_to_cpu(m->footer.data_crc)); 12202f713615SIlya Dryomov return -EBADMSG; 12212f713615SIlya Dryomov } 12222f713615SIlya Dryomov 12232f713615SIlya Dryomov if (need_sign && con->ops->check_message_signature && 12242f713615SIlya Dryomov con->ops->check_message_signature(m)) { 12252f713615SIlya Dryomov pr_err("read_partial_message %p signature check failed\n", m); 12262f713615SIlya Dryomov return -EBADMSG; 12272f713615SIlya Dryomov } 12282f713615SIlya Dryomov 12292f713615SIlya Dryomov return 1; /* done! */ 12302f713615SIlya Dryomov } 12312f713615SIlya Dryomov 12322f713615SIlya Dryomov static int read_keepalive_ack(struct ceph_connection *con) 12332f713615SIlya Dryomov { 12342f713615SIlya Dryomov struct ceph_timespec ceph_ts; 12352f713615SIlya Dryomov size_t size = sizeof(ceph_ts); 12362f713615SIlya Dryomov int ret = read_partial(con, size, size, &ceph_ts); 12372f713615SIlya Dryomov if (ret <= 0) 12382f713615SIlya Dryomov return ret; 12392f713615SIlya Dryomov ceph_decode_timespec64(&con->last_keepalive_ack, &ceph_ts); 12402f713615SIlya Dryomov prepare_read_tag(con); 12412f713615SIlya Dryomov return 1; 12422f713615SIlya Dryomov } 12432f713615SIlya Dryomov 12442f713615SIlya Dryomov /* 12452f713615SIlya Dryomov * Read what we can from the socket. 12462f713615SIlya Dryomov */ 12472f713615SIlya Dryomov int ceph_con_v1_try_read(struct ceph_connection *con) 12482f713615SIlya Dryomov { 12492f713615SIlya Dryomov int ret = -1; 12502f713615SIlya Dryomov 12512f713615SIlya Dryomov more: 12522f713615SIlya Dryomov dout("try_read start %p state %d\n", con, con->state); 12532f713615SIlya Dryomov if (con->state != CEPH_CON_S_V1_BANNER && 12542f713615SIlya Dryomov con->state != CEPH_CON_S_V1_CONNECT_MSG && 12552f713615SIlya Dryomov con->state != CEPH_CON_S_OPEN) 12562f713615SIlya Dryomov return 0; 12572f713615SIlya Dryomov 12582f713615SIlya Dryomov BUG_ON(!con->sock); 12592f713615SIlya Dryomov 1260a56dd9bfSIlya Dryomov dout("try_read tag %d in_base_pos %d\n", con->v1.in_tag, 1261a56dd9bfSIlya Dryomov con->v1.in_base_pos); 12622f713615SIlya Dryomov 12632f713615SIlya Dryomov if (con->state == CEPH_CON_S_V1_BANNER) { 12642f713615SIlya Dryomov ret = read_partial_banner(con); 12652f713615SIlya Dryomov if (ret <= 0) 12662f713615SIlya Dryomov goto out; 12672f713615SIlya Dryomov ret = process_banner(con); 12682f713615SIlya Dryomov if (ret < 0) 12692f713615SIlya Dryomov goto out; 12702f713615SIlya Dryomov 12712f713615SIlya Dryomov con->state = CEPH_CON_S_V1_CONNECT_MSG; 12722f713615SIlya Dryomov 12732f713615SIlya Dryomov /* 12742f713615SIlya Dryomov * Received banner is good, exchange connection info. 12752f713615SIlya Dryomov * Do not reset out_kvec, as sending our banner raced 12762f713615SIlya Dryomov * with receiving peer banner after connect completed. 12772f713615SIlya Dryomov */ 12782f713615SIlya Dryomov ret = prepare_write_connect(con); 12792f713615SIlya Dryomov if (ret < 0) 12802f713615SIlya Dryomov goto out; 12812f713615SIlya Dryomov prepare_read_connect(con); 12822f713615SIlya Dryomov 12832f713615SIlya Dryomov /* Send connection info before awaiting response */ 12842f713615SIlya Dryomov goto out; 12852f713615SIlya Dryomov } 12862f713615SIlya Dryomov 12872f713615SIlya Dryomov if (con->state == CEPH_CON_S_V1_CONNECT_MSG) { 12882f713615SIlya Dryomov ret = read_partial_connect(con); 12892f713615SIlya Dryomov if (ret <= 0) 12902f713615SIlya Dryomov goto out; 12912f713615SIlya Dryomov ret = process_connect(con); 12922f713615SIlya Dryomov if (ret < 0) 12932f713615SIlya Dryomov goto out; 12942f713615SIlya Dryomov goto more; 12952f713615SIlya Dryomov } 12962f713615SIlya Dryomov 12972f713615SIlya Dryomov WARN_ON(con->state != CEPH_CON_S_OPEN); 12982f713615SIlya Dryomov 1299a56dd9bfSIlya Dryomov if (con->v1.in_base_pos < 0) { 13002f713615SIlya Dryomov /* 13012f713615SIlya Dryomov * skipping + discarding content. 13022f713615SIlya Dryomov */ 1303a56dd9bfSIlya Dryomov ret = ceph_tcp_recvmsg(con->sock, NULL, -con->v1.in_base_pos); 13042f713615SIlya Dryomov if (ret <= 0) 13052f713615SIlya Dryomov goto out; 1306a56dd9bfSIlya Dryomov dout("skipped %d / %d bytes\n", ret, -con->v1.in_base_pos); 1307a56dd9bfSIlya Dryomov con->v1.in_base_pos += ret; 1308a56dd9bfSIlya Dryomov if (con->v1.in_base_pos) 13092f713615SIlya Dryomov goto more; 13102f713615SIlya Dryomov } 1311a56dd9bfSIlya Dryomov if (con->v1.in_tag == CEPH_MSGR_TAG_READY) { 13122f713615SIlya Dryomov /* 13132f713615SIlya Dryomov * what's next? 13142f713615SIlya Dryomov */ 1315a56dd9bfSIlya Dryomov ret = ceph_tcp_recvmsg(con->sock, &con->v1.in_tag, 1); 13162f713615SIlya Dryomov if (ret <= 0) 13172f713615SIlya Dryomov goto out; 1318a56dd9bfSIlya Dryomov dout("try_read got tag %d\n", con->v1.in_tag); 1319a56dd9bfSIlya Dryomov switch (con->v1.in_tag) { 13202f713615SIlya Dryomov case CEPH_MSGR_TAG_MSG: 13212f713615SIlya Dryomov prepare_read_message(con); 13222f713615SIlya Dryomov break; 13232f713615SIlya Dryomov case CEPH_MSGR_TAG_ACK: 13242f713615SIlya Dryomov prepare_read_ack(con); 13252f713615SIlya Dryomov break; 13262f713615SIlya Dryomov case CEPH_MSGR_TAG_KEEPALIVE2_ACK: 13272f713615SIlya Dryomov prepare_read_keepalive_ack(con); 13282f713615SIlya Dryomov break; 13292f713615SIlya Dryomov case CEPH_MSGR_TAG_CLOSE: 13302f713615SIlya Dryomov ceph_con_close_socket(con); 13312f713615SIlya Dryomov con->state = CEPH_CON_S_CLOSED; 13322f713615SIlya Dryomov goto out; 13332f713615SIlya Dryomov default: 13342f713615SIlya Dryomov goto bad_tag; 13352f713615SIlya Dryomov } 13362f713615SIlya Dryomov } 1337a56dd9bfSIlya Dryomov if (con->v1.in_tag == CEPH_MSGR_TAG_MSG) { 13382f713615SIlya Dryomov ret = read_partial_message(con); 13392f713615SIlya Dryomov if (ret <= 0) { 13402f713615SIlya Dryomov switch (ret) { 13412f713615SIlya Dryomov case -EBADMSG: 13422f713615SIlya Dryomov con->error_msg = "bad crc/signature"; 13432f713615SIlya Dryomov fallthrough; 13442f713615SIlya Dryomov case -EBADE: 13452f713615SIlya Dryomov ret = -EIO; 13462f713615SIlya Dryomov break; 13472f713615SIlya Dryomov case -EIO: 13482f713615SIlya Dryomov con->error_msg = "io error"; 13492f713615SIlya Dryomov break; 13502f713615SIlya Dryomov } 13512f713615SIlya Dryomov goto out; 13522f713615SIlya Dryomov } 1353a56dd9bfSIlya Dryomov if (con->v1.in_tag == CEPH_MSGR_TAG_READY) 13542f713615SIlya Dryomov goto more; 13552f713615SIlya Dryomov ceph_con_process_message(con); 13562f713615SIlya Dryomov if (con->state == CEPH_CON_S_OPEN) 13572f713615SIlya Dryomov prepare_read_tag(con); 13582f713615SIlya Dryomov goto more; 13592f713615SIlya Dryomov } 1360a56dd9bfSIlya Dryomov if (con->v1.in_tag == CEPH_MSGR_TAG_ACK || 1361a56dd9bfSIlya Dryomov con->v1.in_tag == CEPH_MSGR_TAG_SEQ) { 13622f713615SIlya Dryomov /* 13632f713615SIlya Dryomov * the final handshake seq exchange is semantically 13642f713615SIlya Dryomov * equivalent to an ACK 13652f713615SIlya Dryomov */ 13662f713615SIlya Dryomov ret = read_partial_ack(con); 13672f713615SIlya Dryomov if (ret <= 0) 13682f713615SIlya Dryomov goto out; 13692f713615SIlya Dryomov process_ack(con); 13702f713615SIlya Dryomov goto more; 13712f713615SIlya Dryomov } 1372a56dd9bfSIlya Dryomov if (con->v1.in_tag == CEPH_MSGR_TAG_KEEPALIVE2_ACK) { 13732f713615SIlya Dryomov ret = read_keepalive_ack(con); 13742f713615SIlya Dryomov if (ret <= 0) 13752f713615SIlya Dryomov goto out; 13762f713615SIlya Dryomov goto more; 13772f713615SIlya Dryomov } 13782f713615SIlya Dryomov 13792f713615SIlya Dryomov out: 13802f713615SIlya Dryomov dout("try_read done on %p ret %d\n", con, ret); 13812f713615SIlya Dryomov return ret; 13822f713615SIlya Dryomov 13832f713615SIlya Dryomov bad_tag: 1384a56dd9bfSIlya Dryomov pr_err("try_read bad tag %d\n", con->v1.in_tag); 13852f713615SIlya Dryomov con->error_msg = "protocol error, garbage tag"; 13862f713615SIlya Dryomov ret = -1; 13872f713615SIlya Dryomov goto out; 13882f713615SIlya Dryomov } 13892f713615SIlya Dryomov 13902f713615SIlya Dryomov /* 13912f713615SIlya Dryomov * Write something to the socket. Called in a worker thread when the 13922f713615SIlya Dryomov * socket appears to be writeable and we have something ready to send. 13932f713615SIlya Dryomov */ 13942f713615SIlya Dryomov int ceph_con_v1_try_write(struct ceph_connection *con) 13952f713615SIlya Dryomov { 13962f713615SIlya Dryomov int ret = 1; 13972f713615SIlya Dryomov 13982f713615SIlya Dryomov dout("try_write start %p state %d\n", con, con->state); 13992f713615SIlya Dryomov if (con->state != CEPH_CON_S_PREOPEN && 14002f713615SIlya Dryomov con->state != CEPH_CON_S_V1_BANNER && 14012f713615SIlya Dryomov con->state != CEPH_CON_S_V1_CONNECT_MSG && 14022f713615SIlya Dryomov con->state != CEPH_CON_S_OPEN) 14032f713615SIlya Dryomov return 0; 14042f713615SIlya Dryomov 14052f713615SIlya Dryomov /* open the socket first? */ 14062f713615SIlya Dryomov if (con->state == CEPH_CON_S_PREOPEN) { 14072f713615SIlya Dryomov BUG_ON(con->sock); 14082f713615SIlya Dryomov con->state = CEPH_CON_S_V1_BANNER; 14092f713615SIlya Dryomov 14102f713615SIlya Dryomov con_out_kvec_reset(con); 14112f713615SIlya Dryomov prepare_write_banner(con); 14122f713615SIlya Dryomov prepare_read_banner(con); 14132f713615SIlya Dryomov 14142f713615SIlya Dryomov BUG_ON(con->in_msg); 1415a56dd9bfSIlya Dryomov con->v1.in_tag = CEPH_MSGR_TAG_READY; 14162f713615SIlya Dryomov dout("try_write initiating connect on %p new state %d\n", 14172f713615SIlya Dryomov con, con->state); 14182f713615SIlya Dryomov ret = ceph_tcp_connect(con); 14192f713615SIlya Dryomov if (ret < 0) { 14202f713615SIlya Dryomov con->error_msg = "connect error"; 14212f713615SIlya Dryomov goto out; 14222f713615SIlya Dryomov } 14232f713615SIlya Dryomov } 14242f713615SIlya Dryomov 14252f713615SIlya Dryomov more: 1426a56dd9bfSIlya Dryomov dout("try_write out_kvec_bytes %d\n", con->v1.out_kvec_bytes); 14272f713615SIlya Dryomov BUG_ON(!con->sock); 14282f713615SIlya Dryomov 14292f713615SIlya Dryomov /* kvec data queued? */ 1430a56dd9bfSIlya Dryomov if (con->v1.out_kvec_left) { 14312f713615SIlya Dryomov ret = write_partial_kvec(con); 14322f713615SIlya Dryomov if (ret <= 0) 14332f713615SIlya Dryomov goto out; 14342f713615SIlya Dryomov } 1435a56dd9bfSIlya Dryomov if (con->v1.out_skip) { 14362f713615SIlya Dryomov ret = write_partial_skip(con); 14372f713615SIlya Dryomov if (ret <= 0) 14382f713615SIlya Dryomov goto out; 14392f713615SIlya Dryomov } 14402f713615SIlya Dryomov 14412f713615SIlya Dryomov /* msg pages? */ 14422f713615SIlya Dryomov if (con->out_msg) { 1443a56dd9bfSIlya Dryomov if (con->v1.out_msg_done) { 14442f713615SIlya Dryomov ceph_msg_put(con->out_msg); 14452f713615SIlya Dryomov con->out_msg = NULL; /* we're done with this one */ 14462f713615SIlya Dryomov goto do_next; 14472f713615SIlya Dryomov } 14482f713615SIlya Dryomov 14492f713615SIlya Dryomov ret = write_partial_message_data(con); 14502f713615SIlya Dryomov if (ret == 1) 14512f713615SIlya Dryomov goto more; /* we need to send the footer, too! */ 14522f713615SIlya Dryomov if (ret == 0) 14532f713615SIlya Dryomov goto out; 14542f713615SIlya Dryomov if (ret < 0) { 14552f713615SIlya Dryomov dout("try_write write_partial_message_data err %d\n", 14562f713615SIlya Dryomov ret); 14572f713615SIlya Dryomov goto out; 14582f713615SIlya Dryomov } 14592f713615SIlya Dryomov } 14602f713615SIlya Dryomov 14612f713615SIlya Dryomov do_next: 14622f713615SIlya Dryomov if (con->state == CEPH_CON_S_OPEN) { 14632f713615SIlya Dryomov if (ceph_con_flag_test_and_clear(con, 14642f713615SIlya Dryomov CEPH_CON_F_KEEPALIVE_PENDING)) { 14652f713615SIlya Dryomov prepare_write_keepalive(con); 14662f713615SIlya Dryomov goto more; 14672f713615SIlya Dryomov } 14682f713615SIlya Dryomov /* is anything else pending? */ 14692f713615SIlya Dryomov if (!list_empty(&con->out_queue)) { 14702f713615SIlya Dryomov prepare_write_message(con); 14712f713615SIlya Dryomov goto more; 14722f713615SIlya Dryomov } 14732f713615SIlya Dryomov if (con->in_seq > con->in_seq_acked) { 14742f713615SIlya Dryomov prepare_write_ack(con); 14752f713615SIlya Dryomov goto more; 14762f713615SIlya Dryomov } 14772f713615SIlya Dryomov } 14782f713615SIlya Dryomov 14792f713615SIlya Dryomov /* Nothing to do! */ 14802f713615SIlya Dryomov ceph_con_flag_clear(con, CEPH_CON_F_WRITE_PENDING); 14812f713615SIlya Dryomov dout("try_write nothing else to write.\n"); 14822f713615SIlya Dryomov ret = 0; 14832f713615SIlya Dryomov out: 14842f713615SIlya Dryomov dout("try_write done on %p ret %d\n", con, ret); 14852f713615SIlya Dryomov return ret; 14862f713615SIlya Dryomov } 14872f713615SIlya Dryomov 14882f713615SIlya Dryomov void ceph_con_v1_revoke(struct ceph_connection *con) 14892f713615SIlya Dryomov { 14902f713615SIlya Dryomov struct ceph_msg *msg = con->out_msg; 14912f713615SIlya Dryomov 1492a56dd9bfSIlya Dryomov WARN_ON(con->v1.out_skip); 14932f713615SIlya Dryomov /* footer */ 1494a56dd9bfSIlya Dryomov if (con->v1.out_msg_done) { 1495a56dd9bfSIlya Dryomov con->v1.out_skip += con_out_kvec_skip(con); 14962f713615SIlya Dryomov } else { 14972f713615SIlya Dryomov WARN_ON(!msg->data_length); 1498a56dd9bfSIlya Dryomov con->v1.out_skip += sizeof_footer(con); 14992f713615SIlya Dryomov } 15002f713615SIlya Dryomov /* data, middle, front */ 15012f713615SIlya Dryomov if (msg->data_length) 1502a56dd9bfSIlya Dryomov con->v1.out_skip += msg->cursor.total_resid; 15032f713615SIlya Dryomov if (msg->middle) 1504a56dd9bfSIlya Dryomov con->v1.out_skip += con_out_kvec_skip(con); 1505a56dd9bfSIlya Dryomov con->v1.out_skip += con_out_kvec_skip(con); 15062f713615SIlya Dryomov 15072f713615SIlya Dryomov dout("%s con %p out_kvec_bytes %d out_skip %d\n", __func__, con, 1508a56dd9bfSIlya Dryomov con->v1.out_kvec_bytes, con->v1.out_skip); 15092f713615SIlya Dryomov } 15102f713615SIlya Dryomov 15112f713615SIlya Dryomov void ceph_con_v1_revoke_incoming(struct ceph_connection *con) 15122f713615SIlya Dryomov { 1513a56dd9bfSIlya Dryomov unsigned int front_len = le32_to_cpu(con->v1.in_hdr.front_len); 1514a56dd9bfSIlya Dryomov unsigned int middle_len = le32_to_cpu(con->v1.in_hdr.middle_len); 1515a56dd9bfSIlya Dryomov unsigned int data_len = le32_to_cpu(con->v1.in_hdr.data_len); 15162f713615SIlya Dryomov 15172f713615SIlya Dryomov /* skip rest of message */ 1518a56dd9bfSIlya Dryomov con->v1.in_base_pos = con->v1.in_base_pos - 15192f713615SIlya Dryomov sizeof(struct ceph_msg_header) - 15202f713615SIlya Dryomov front_len - 15212f713615SIlya Dryomov middle_len - 15222f713615SIlya Dryomov data_len - 15232f713615SIlya Dryomov sizeof(struct ceph_msg_footer); 15242f713615SIlya Dryomov 1525a56dd9bfSIlya Dryomov con->v1.in_tag = CEPH_MSGR_TAG_READY; 15262f713615SIlya Dryomov con->in_seq++; 15272f713615SIlya Dryomov 1528a56dd9bfSIlya Dryomov dout("%s con %p in_base_pos %d\n", __func__, con, con->v1.in_base_pos); 15292f713615SIlya Dryomov } 15302f713615SIlya Dryomov 15312f713615SIlya Dryomov bool ceph_con_v1_opened(struct ceph_connection *con) 15322f713615SIlya Dryomov { 1533a56dd9bfSIlya Dryomov return con->v1.connect_seq; 15342f713615SIlya Dryomov } 15352f713615SIlya Dryomov 15362f713615SIlya Dryomov void ceph_con_v1_reset_session(struct ceph_connection *con) 15372f713615SIlya Dryomov { 1538a56dd9bfSIlya Dryomov con->v1.connect_seq = 0; 1539a56dd9bfSIlya Dryomov con->v1.peer_global_seq = 0; 15402f713615SIlya Dryomov } 15412f713615SIlya Dryomov 15422f713615SIlya Dryomov void ceph_con_v1_reset_protocol(struct ceph_connection *con) 15432f713615SIlya Dryomov { 1544a56dd9bfSIlya Dryomov con->v1.out_skip = 0; 15452f713615SIlya Dryomov } 1546