162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/ceph/ceph_debug.h> 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/bvec.h> 562306a36Sopenharmony_ci#include <linux/crc32c.h> 662306a36Sopenharmony_ci#include <linux/net.h> 762306a36Sopenharmony_ci#include <linux/socket.h> 862306a36Sopenharmony_ci#include <net/sock.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/ceph/ceph_features.h> 1162306a36Sopenharmony_ci#include <linux/ceph/decode.h> 1262306a36Sopenharmony_ci#include <linux/ceph/libceph.h> 1362306a36Sopenharmony_ci#include <linux/ceph/messenger.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* static tag bytes (protocol control messages) */ 1662306a36Sopenharmony_cistatic char tag_msg = CEPH_MSGR_TAG_MSG; 1762306a36Sopenharmony_cistatic char tag_ack = CEPH_MSGR_TAG_ACK; 1862306a36Sopenharmony_cistatic char tag_keepalive = CEPH_MSGR_TAG_KEEPALIVE; 1962306a36Sopenharmony_cistatic char tag_keepalive2 = CEPH_MSGR_TAG_KEEPALIVE2; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* 2262306a36Sopenharmony_ci * If @buf is NULL, discard up to @len bytes. 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_cistatic int ceph_tcp_recvmsg(struct socket *sock, void *buf, size_t len) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci struct kvec iov = {buf, len}; 2762306a36Sopenharmony_ci struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL }; 2862306a36Sopenharmony_ci int r; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci if (!buf) 3162306a36Sopenharmony_ci msg.msg_flags |= MSG_TRUNC; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, len); 3462306a36Sopenharmony_ci r = sock_recvmsg(sock, &msg, msg.msg_flags); 3562306a36Sopenharmony_ci if (r == -EAGAIN) 3662306a36Sopenharmony_ci r = 0; 3762306a36Sopenharmony_ci return r; 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic int ceph_tcp_recvpage(struct socket *sock, struct page *page, 4162306a36Sopenharmony_ci int page_offset, size_t length) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci struct bio_vec bvec; 4462306a36Sopenharmony_ci struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL }; 4562306a36Sopenharmony_ci int r; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci BUG_ON(page_offset + length > PAGE_SIZE); 4862306a36Sopenharmony_ci bvec_set_page(&bvec, page, length, page_offset); 4962306a36Sopenharmony_ci iov_iter_bvec(&msg.msg_iter, ITER_DEST, &bvec, 1, length); 5062306a36Sopenharmony_ci r = sock_recvmsg(sock, &msg, msg.msg_flags); 5162306a36Sopenharmony_ci if (r == -EAGAIN) 5262306a36Sopenharmony_ci r = 0; 5362306a36Sopenharmony_ci return r; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* 5762306a36Sopenharmony_ci * write something. @more is true if caller will be sending more data 5862306a36Sopenharmony_ci * shortly. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_cistatic int ceph_tcp_sendmsg(struct socket *sock, struct kvec *iov, 6162306a36Sopenharmony_ci size_t kvlen, size_t len, bool more) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL }; 6462306a36Sopenharmony_ci int r; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (more) 6762306a36Sopenharmony_ci msg.msg_flags |= MSG_MORE; 6862306a36Sopenharmony_ci else 6962306a36Sopenharmony_ci msg.msg_flags |= MSG_EOR; /* superfluous, but what the hell */ 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci r = kernel_sendmsg(sock, &msg, iov, kvlen, len); 7262306a36Sopenharmony_ci if (r == -EAGAIN) 7362306a36Sopenharmony_ci r = 0; 7462306a36Sopenharmony_ci return r; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* 7862306a36Sopenharmony_ci * @more: MSG_MORE or 0. 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_cistatic int ceph_tcp_sendpage(struct socket *sock, struct page *page, 8162306a36Sopenharmony_ci int offset, size_t size, int more) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci struct msghdr msg = { 8462306a36Sopenharmony_ci .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL | more, 8562306a36Sopenharmony_ci }; 8662306a36Sopenharmony_ci struct bio_vec bvec; 8762306a36Sopenharmony_ci int ret; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* 9062306a36Sopenharmony_ci * MSG_SPLICE_PAGES cannot properly handle pages with page_count == 0, 9162306a36Sopenharmony_ci * we need to fall back to sendmsg if that's the case. 9262306a36Sopenharmony_ci * 9362306a36Sopenharmony_ci * Same goes for slab pages: skb_can_coalesce() allows 9462306a36Sopenharmony_ci * coalescing neighboring slab objects into a single frag which 9562306a36Sopenharmony_ci * triggers one of hardened usercopy checks. 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_ci if (sendpage_ok(page)) 9862306a36Sopenharmony_ci msg.msg_flags |= MSG_SPLICE_PAGES; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci bvec_set_page(&bvec, page, size, offset); 10162306a36Sopenharmony_ci iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci ret = sock_sendmsg(sock, &msg); 10462306a36Sopenharmony_ci if (ret == -EAGAIN) 10562306a36Sopenharmony_ci ret = 0; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci return ret; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic void con_out_kvec_reset(struct ceph_connection *con) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci BUG_ON(con->v1.out_skip); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci con->v1.out_kvec_left = 0; 11562306a36Sopenharmony_ci con->v1.out_kvec_bytes = 0; 11662306a36Sopenharmony_ci con->v1.out_kvec_cur = &con->v1.out_kvec[0]; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic void con_out_kvec_add(struct ceph_connection *con, 12062306a36Sopenharmony_ci size_t size, void *data) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci int index = con->v1.out_kvec_left; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci BUG_ON(con->v1.out_skip); 12562306a36Sopenharmony_ci BUG_ON(index >= ARRAY_SIZE(con->v1.out_kvec)); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci con->v1.out_kvec[index].iov_len = size; 12862306a36Sopenharmony_ci con->v1.out_kvec[index].iov_base = data; 12962306a36Sopenharmony_ci con->v1.out_kvec_left++; 13062306a36Sopenharmony_ci con->v1.out_kvec_bytes += size; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* 13462306a36Sopenharmony_ci * Chop off a kvec from the end. Return residual number of bytes for 13562306a36Sopenharmony_ci * that kvec, i.e. how many bytes would have been written if the kvec 13662306a36Sopenharmony_ci * hadn't been nuked. 13762306a36Sopenharmony_ci */ 13862306a36Sopenharmony_cistatic int con_out_kvec_skip(struct ceph_connection *con) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci int skip = 0; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (con->v1.out_kvec_bytes > 0) { 14362306a36Sopenharmony_ci skip = con->v1.out_kvec_cur[con->v1.out_kvec_left - 1].iov_len; 14462306a36Sopenharmony_ci BUG_ON(con->v1.out_kvec_bytes < skip); 14562306a36Sopenharmony_ci BUG_ON(!con->v1.out_kvec_left); 14662306a36Sopenharmony_ci con->v1.out_kvec_bytes -= skip; 14762306a36Sopenharmony_ci con->v1.out_kvec_left--; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci return skip; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic size_t sizeof_footer(struct ceph_connection *con) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci return (con->peer_features & CEPH_FEATURE_MSG_AUTH) ? 15662306a36Sopenharmony_ci sizeof(struct ceph_msg_footer) : 15762306a36Sopenharmony_ci sizeof(struct ceph_msg_footer_old); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic void prepare_message_data(struct ceph_msg *msg, u32 data_len) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci /* Initialize data cursor if it's not a sparse read */ 16362306a36Sopenharmony_ci u64 len = msg->sparse_read_total ? : data_len; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci ceph_msg_data_cursor_init(&msg->cursor, msg, len); 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci/* 16962306a36Sopenharmony_ci * Prepare footer for currently outgoing message, and finish things 17062306a36Sopenharmony_ci * off. Assumes out_kvec* are already valid.. we just add on to the end. 17162306a36Sopenharmony_ci */ 17262306a36Sopenharmony_cistatic void prepare_write_message_footer(struct ceph_connection *con) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct ceph_msg *m = con->out_msg; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci m->footer.flags |= CEPH_MSG_FOOTER_COMPLETE; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci dout("prepare_write_message_footer %p\n", con); 17962306a36Sopenharmony_ci con_out_kvec_add(con, sizeof_footer(con), &m->footer); 18062306a36Sopenharmony_ci if (con->peer_features & CEPH_FEATURE_MSG_AUTH) { 18162306a36Sopenharmony_ci if (con->ops->sign_message) 18262306a36Sopenharmony_ci con->ops->sign_message(m); 18362306a36Sopenharmony_ci else 18462306a36Sopenharmony_ci m->footer.sig = 0; 18562306a36Sopenharmony_ci } else { 18662306a36Sopenharmony_ci m->old_footer.flags = m->footer.flags; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci con->v1.out_more = m->more_to_follow; 18962306a36Sopenharmony_ci con->v1.out_msg_done = true; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci/* 19362306a36Sopenharmony_ci * Prepare headers for the next outgoing message. 19462306a36Sopenharmony_ci */ 19562306a36Sopenharmony_cistatic void prepare_write_message(struct ceph_connection *con) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci struct ceph_msg *m; 19862306a36Sopenharmony_ci u32 crc; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci con_out_kvec_reset(con); 20162306a36Sopenharmony_ci con->v1.out_msg_done = false; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* Sneak an ack in there first? If we can get it into the same 20462306a36Sopenharmony_ci * TCP packet that's a good thing. */ 20562306a36Sopenharmony_ci if (con->in_seq > con->in_seq_acked) { 20662306a36Sopenharmony_ci con->in_seq_acked = con->in_seq; 20762306a36Sopenharmony_ci con_out_kvec_add(con, sizeof (tag_ack), &tag_ack); 20862306a36Sopenharmony_ci con->v1.out_temp_ack = cpu_to_le64(con->in_seq_acked); 20962306a36Sopenharmony_ci con_out_kvec_add(con, sizeof(con->v1.out_temp_ack), 21062306a36Sopenharmony_ci &con->v1.out_temp_ack); 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci ceph_con_get_out_msg(con); 21462306a36Sopenharmony_ci m = con->out_msg; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci dout("prepare_write_message %p seq %lld type %d len %d+%d+%zd\n", 21762306a36Sopenharmony_ci m, con->out_seq, le16_to_cpu(m->hdr.type), 21862306a36Sopenharmony_ci le32_to_cpu(m->hdr.front_len), le32_to_cpu(m->hdr.middle_len), 21962306a36Sopenharmony_ci m->data_length); 22062306a36Sopenharmony_ci WARN_ON(m->front.iov_len != le32_to_cpu(m->hdr.front_len)); 22162306a36Sopenharmony_ci WARN_ON(m->data_length != le32_to_cpu(m->hdr.data_len)); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* tag + hdr + front + middle */ 22462306a36Sopenharmony_ci con_out_kvec_add(con, sizeof (tag_msg), &tag_msg); 22562306a36Sopenharmony_ci con_out_kvec_add(con, sizeof(con->v1.out_hdr), &con->v1.out_hdr); 22662306a36Sopenharmony_ci con_out_kvec_add(con, m->front.iov_len, m->front.iov_base); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (m->middle) 22962306a36Sopenharmony_ci con_out_kvec_add(con, m->middle->vec.iov_len, 23062306a36Sopenharmony_ci m->middle->vec.iov_base); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci /* fill in hdr crc and finalize hdr */ 23362306a36Sopenharmony_ci crc = crc32c(0, &m->hdr, offsetof(struct ceph_msg_header, crc)); 23462306a36Sopenharmony_ci con->out_msg->hdr.crc = cpu_to_le32(crc); 23562306a36Sopenharmony_ci memcpy(&con->v1.out_hdr, &con->out_msg->hdr, sizeof(con->v1.out_hdr)); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* fill in front and middle crc, footer */ 23862306a36Sopenharmony_ci crc = crc32c(0, m->front.iov_base, m->front.iov_len); 23962306a36Sopenharmony_ci con->out_msg->footer.front_crc = cpu_to_le32(crc); 24062306a36Sopenharmony_ci if (m->middle) { 24162306a36Sopenharmony_ci crc = crc32c(0, m->middle->vec.iov_base, 24262306a36Sopenharmony_ci m->middle->vec.iov_len); 24362306a36Sopenharmony_ci con->out_msg->footer.middle_crc = cpu_to_le32(crc); 24462306a36Sopenharmony_ci } else 24562306a36Sopenharmony_ci con->out_msg->footer.middle_crc = 0; 24662306a36Sopenharmony_ci dout("%s front_crc %u middle_crc %u\n", __func__, 24762306a36Sopenharmony_ci le32_to_cpu(con->out_msg->footer.front_crc), 24862306a36Sopenharmony_ci le32_to_cpu(con->out_msg->footer.middle_crc)); 24962306a36Sopenharmony_ci con->out_msg->footer.flags = 0; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* is there a data payload? */ 25262306a36Sopenharmony_ci con->out_msg->footer.data_crc = 0; 25362306a36Sopenharmony_ci if (m->data_length) { 25462306a36Sopenharmony_ci prepare_message_data(con->out_msg, m->data_length); 25562306a36Sopenharmony_ci con->v1.out_more = 1; /* data + footer will follow */ 25662306a36Sopenharmony_ci } else { 25762306a36Sopenharmony_ci /* no, queue up footer too and be done */ 25862306a36Sopenharmony_ci prepare_write_message_footer(con); 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING); 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/* 26562306a36Sopenharmony_ci * Prepare an ack. 26662306a36Sopenharmony_ci */ 26762306a36Sopenharmony_cistatic void prepare_write_ack(struct ceph_connection *con) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci dout("prepare_write_ack %p %llu -> %llu\n", con, 27062306a36Sopenharmony_ci con->in_seq_acked, con->in_seq); 27162306a36Sopenharmony_ci con->in_seq_acked = con->in_seq; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci con_out_kvec_reset(con); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci con_out_kvec_add(con, sizeof (tag_ack), &tag_ack); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci con->v1.out_temp_ack = cpu_to_le64(con->in_seq_acked); 27862306a36Sopenharmony_ci con_out_kvec_add(con, sizeof(con->v1.out_temp_ack), 27962306a36Sopenharmony_ci &con->v1.out_temp_ack); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci con->v1.out_more = 1; /* more will follow.. eventually.. */ 28262306a36Sopenharmony_ci ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING); 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci/* 28662306a36Sopenharmony_ci * Prepare to share the seq during handshake 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_cistatic void prepare_write_seq(struct ceph_connection *con) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci dout("prepare_write_seq %p %llu -> %llu\n", con, 29162306a36Sopenharmony_ci con->in_seq_acked, con->in_seq); 29262306a36Sopenharmony_ci con->in_seq_acked = con->in_seq; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci con_out_kvec_reset(con); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci con->v1.out_temp_ack = cpu_to_le64(con->in_seq_acked); 29762306a36Sopenharmony_ci con_out_kvec_add(con, sizeof(con->v1.out_temp_ack), 29862306a36Sopenharmony_ci &con->v1.out_temp_ack); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING); 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci/* 30462306a36Sopenharmony_ci * Prepare to write keepalive byte. 30562306a36Sopenharmony_ci */ 30662306a36Sopenharmony_cistatic void prepare_write_keepalive(struct ceph_connection *con) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci dout("prepare_write_keepalive %p\n", con); 30962306a36Sopenharmony_ci con_out_kvec_reset(con); 31062306a36Sopenharmony_ci if (con->peer_features & CEPH_FEATURE_MSGR_KEEPALIVE2) { 31162306a36Sopenharmony_ci struct timespec64 now; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci ktime_get_real_ts64(&now); 31462306a36Sopenharmony_ci con_out_kvec_add(con, sizeof(tag_keepalive2), &tag_keepalive2); 31562306a36Sopenharmony_ci ceph_encode_timespec64(&con->v1.out_temp_keepalive2, &now); 31662306a36Sopenharmony_ci con_out_kvec_add(con, sizeof(con->v1.out_temp_keepalive2), 31762306a36Sopenharmony_ci &con->v1.out_temp_keepalive2); 31862306a36Sopenharmony_ci } else { 31962306a36Sopenharmony_ci con_out_kvec_add(con, sizeof(tag_keepalive), &tag_keepalive); 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING); 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci/* 32562306a36Sopenharmony_ci * Connection negotiation. 32662306a36Sopenharmony_ci */ 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic int get_connect_authorizer(struct ceph_connection *con) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci struct ceph_auth_handshake *auth; 33162306a36Sopenharmony_ci int auth_proto; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (!con->ops->get_authorizer) { 33462306a36Sopenharmony_ci con->v1.auth = NULL; 33562306a36Sopenharmony_ci con->v1.out_connect.authorizer_protocol = CEPH_AUTH_UNKNOWN; 33662306a36Sopenharmony_ci con->v1.out_connect.authorizer_len = 0; 33762306a36Sopenharmony_ci return 0; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci auth = con->ops->get_authorizer(con, &auth_proto, con->v1.auth_retry); 34162306a36Sopenharmony_ci if (IS_ERR(auth)) 34262306a36Sopenharmony_ci return PTR_ERR(auth); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci con->v1.auth = auth; 34562306a36Sopenharmony_ci con->v1.out_connect.authorizer_protocol = cpu_to_le32(auth_proto); 34662306a36Sopenharmony_ci con->v1.out_connect.authorizer_len = 34762306a36Sopenharmony_ci cpu_to_le32(auth->authorizer_buf_len); 34862306a36Sopenharmony_ci return 0; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci/* 35262306a36Sopenharmony_ci * We connected to a peer and are saying hello. 35362306a36Sopenharmony_ci */ 35462306a36Sopenharmony_cistatic void prepare_write_banner(struct ceph_connection *con) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci con_out_kvec_add(con, strlen(CEPH_BANNER), CEPH_BANNER); 35762306a36Sopenharmony_ci con_out_kvec_add(con, sizeof (con->msgr->my_enc_addr), 35862306a36Sopenharmony_ci &con->msgr->my_enc_addr); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci con->v1.out_more = 0; 36162306a36Sopenharmony_ci ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING); 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic void __prepare_write_connect(struct ceph_connection *con) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci con_out_kvec_add(con, sizeof(con->v1.out_connect), 36762306a36Sopenharmony_ci &con->v1.out_connect); 36862306a36Sopenharmony_ci if (con->v1.auth) 36962306a36Sopenharmony_ci con_out_kvec_add(con, con->v1.auth->authorizer_buf_len, 37062306a36Sopenharmony_ci con->v1.auth->authorizer_buf); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci con->v1.out_more = 0; 37362306a36Sopenharmony_ci ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING); 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic int prepare_write_connect(struct ceph_connection *con) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci unsigned int global_seq = ceph_get_global_seq(con->msgr, 0); 37962306a36Sopenharmony_ci int proto; 38062306a36Sopenharmony_ci int ret; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci switch (con->peer_name.type) { 38362306a36Sopenharmony_ci case CEPH_ENTITY_TYPE_MON: 38462306a36Sopenharmony_ci proto = CEPH_MONC_PROTOCOL; 38562306a36Sopenharmony_ci break; 38662306a36Sopenharmony_ci case CEPH_ENTITY_TYPE_OSD: 38762306a36Sopenharmony_ci proto = CEPH_OSDC_PROTOCOL; 38862306a36Sopenharmony_ci break; 38962306a36Sopenharmony_ci case CEPH_ENTITY_TYPE_MDS: 39062306a36Sopenharmony_ci proto = CEPH_MDSC_PROTOCOL; 39162306a36Sopenharmony_ci break; 39262306a36Sopenharmony_ci default: 39362306a36Sopenharmony_ci BUG(); 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci dout("prepare_write_connect %p cseq=%d gseq=%d proto=%d\n", con, 39762306a36Sopenharmony_ci con->v1.connect_seq, global_seq, proto); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci con->v1.out_connect.features = 40062306a36Sopenharmony_ci cpu_to_le64(from_msgr(con->msgr)->supported_features); 40162306a36Sopenharmony_ci con->v1.out_connect.host_type = cpu_to_le32(CEPH_ENTITY_TYPE_CLIENT); 40262306a36Sopenharmony_ci con->v1.out_connect.connect_seq = cpu_to_le32(con->v1.connect_seq); 40362306a36Sopenharmony_ci con->v1.out_connect.global_seq = cpu_to_le32(global_seq); 40462306a36Sopenharmony_ci con->v1.out_connect.protocol_version = cpu_to_le32(proto); 40562306a36Sopenharmony_ci con->v1.out_connect.flags = 0; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci ret = get_connect_authorizer(con); 40862306a36Sopenharmony_ci if (ret) 40962306a36Sopenharmony_ci return ret; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci __prepare_write_connect(con); 41262306a36Sopenharmony_ci return 0; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci/* 41662306a36Sopenharmony_ci * write as much of pending kvecs to the socket as we can. 41762306a36Sopenharmony_ci * 1 -> done 41862306a36Sopenharmony_ci * 0 -> socket full, but more to do 41962306a36Sopenharmony_ci * <0 -> error 42062306a36Sopenharmony_ci */ 42162306a36Sopenharmony_cistatic int write_partial_kvec(struct ceph_connection *con) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci int ret; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci dout("write_partial_kvec %p %d left\n", con, con->v1.out_kvec_bytes); 42662306a36Sopenharmony_ci while (con->v1.out_kvec_bytes > 0) { 42762306a36Sopenharmony_ci ret = ceph_tcp_sendmsg(con->sock, con->v1.out_kvec_cur, 42862306a36Sopenharmony_ci con->v1.out_kvec_left, 42962306a36Sopenharmony_ci con->v1.out_kvec_bytes, 43062306a36Sopenharmony_ci con->v1.out_more); 43162306a36Sopenharmony_ci if (ret <= 0) 43262306a36Sopenharmony_ci goto out; 43362306a36Sopenharmony_ci con->v1.out_kvec_bytes -= ret; 43462306a36Sopenharmony_ci if (!con->v1.out_kvec_bytes) 43562306a36Sopenharmony_ci break; /* done */ 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* account for full iov entries consumed */ 43862306a36Sopenharmony_ci while (ret >= con->v1.out_kvec_cur->iov_len) { 43962306a36Sopenharmony_ci BUG_ON(!con->v1.out_kvec_left); 44062306a36Sopenharmony_ci ret -= con->v1.out_kvec_cur->iov_len; 44162306a36Sopenharmony_ci con->v1.out_kvec_cur++; 44262306a36Sopenharmony_ci con->v1.out_kvec_left--; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci /* and for a partially-consumed entry */ 44562306a36Sopenharmony_ci if (ret) { 44662306a36Sopenharmony_ci con->v1.out_kvec_cur->iov_len -= ret; 44762306a36Sopenharmony_ci con->v1.out_kvec_cur->iov_base += ret; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci con->v1.out_kvec_left = 0; 45162306a36Sopenharmony_ci ret = 1; 45262306a36Sopenharmony_ciout: 45362306a36Sopenharmony_ci dout("write_partial_kvec %p %d left in %d kvecs ret = %d\n", con, 45462306a36Sopenharmony_ci con->v1.out_kvec_bytes, con->v1.out_kvec_left, ret); 45562306a36Sopenharmony_ci return ret; /* done! */ 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci/* 45962306a36Sopenharmony_ci * Write as much message data payload as we can. If we finish, queue 46062306a36Sopenharmony_ci * up the footer. 46162306a36Sopenharmony_ci * 1 -> done, footer is now queued in out_kvec[]. 46262306a36Sopenharmony_ci * 0 -> socket full, but more to do 46362306a36Sopenharmony_ci * <0 -> error 46462306a36Sopenharmony_ci */ 46562306a36Sopenharmony_cistatic int write_partial_message_data(struct ceph_connection *con) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci struct ceph_msg *msg = con->out_msg; 46862306a36Sopenharmony_ci struct ceph_msg_data_cursor *cursor = &msg->cursor; 46962306a36Sopenharmony_ci bool do_datacrc = !ceph_test_opt(from_msgr(con->msgr), NOCRC); 47062306a36Sopenharmony_ci u32 crc; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci dout("%s %p msg %p\n", __func__, con, msg); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (!msg->num_data_items) 47562306a36Sopenharmony_ci return -EINVAL; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci /* 47862306a36Sopenharmony_ci * Iterate through each page that contains data to be 47962306a36Sopenharmony_ci * written, and send as much as possible for each. 48062306a36Sopenharmony_ci * 48162306a36Sopenharmony_ci * If we are calculating the data crc (the default), we will 48262306a36Sopenharmony_ci * need to map the page. If we have no pages, they have 48362306a36Sopenharmony_ci * been revoked, so use the zero page. 48462306a36Sopenharmony_ci */ 48562306a36Sopenharmony_ci crc = do_datacrc ? le32_to_cpu(msg->footer.data_crc) : 0; 48662306a36Sopenharmony_ci while (cursor->total_resid) { 48762306a36Sopenharmony_ci struct page *page; 48862306a36Sopenharmony_ci size_t page_offset; 48962306a36Sopenharmony_ci size_t length; 49062306a36Sopenharmony_ci int ret; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (!cursor->resid) { 49362306a36Sopenharmony_ci ceph_msg_data_advance(cursor, 0); 49462306a36Sopenharmony_ci continue; 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci page = ceph_msg_data_next(cursor, &page_offset, &length); 49862306a36Sopenharmony_ci ret = ceph_tcp_sendpage(con->sock, page, page_offset, length, 49962306a36Sopenharmony_ci MSG_MORE); 50062306a36Sopenharmony_ci if (ret <= 0) { 50162306a36Sopenharmony_ci if (do_datacrc) 50262306a36Sopenharmony_ci msg->footer.data_crc = cpu_to_le32(crc); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci return ret; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci if (do_datacrc && cursor->need_crc) 50762306a36Sopenharmony_ci crc = ceph_crc32c_page(crc, page, page_offset, length); 50862306a36Sopenharmony_ci ceph_msg_data_advance(cursor, (size_t)ret); 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci dout("%s %p msg %p done\n", __func__, con, msg); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci /* prepare and queue up footer, too */ 51462306a36Sopenharmony_ci if (do_datacrc) 51562306a36Sopenharmony_ci msg->footer.data_crc = cpu_to_le32(crc); 51662306a36Sopenharmony_ci else 51762306a36Sopenharmony_ci msg->footer.flags |= CEPH_MSG_FOOTER_NOCRC; 51862306a36Sopenharmony_ci con_out_kvec_reset(con); 51962306a36Sopenharmony_ci prepare_write_message_footer(con); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci return 1; /* must return > 0 to indicate success */ 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci/* 52562306a36Sopenharmony_ci * write some zeros 52662306a36Sopenharmony_ci */ 52762306a36Sopenharmony_cistatic int write_partial_skip(struct ceph_connection *con) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci int ret; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci dout("%s %p %d left\n", __func__, con, con->v1.out_skip); 53262306a36Sopenharmony_ci while (con->v1.out_skip > 0) { 53362306a36Sopenharmony_ci size_t size = min(con->v1.out_skip, (int)PAGE_SIZE); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci ret = ceph_tcp_sendpage(con->sock, ceph_zero_page, 0, size, 53662306a36Sopenharmony_ci MSG_MORE); 53762306a36Sopenharmony_ci if (ret <= 0) 53862306a36Sopenharmony_ci goto out; 53962306a36Sopenharmony_ci con->v1.out_skip -= ret; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci ret = 1; 54262306a36Sopenharmony_ciout: 54362306a36Sopenharmony_ci return ret; 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci/* 54762306a36Sopenharmony_ci * Prepare to read connection handshake, or an ack. 54862306a36Sopenharmony_ci */ 54962306a36Sopenharmony_cistatic void prepare_read_banner(struct ceph_connection *con) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci dout("prepare_read_banner %p\n", con); 55262306a36Sopenharmony_ci con->v1.in_base_pos = 0; 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic void prepare_read_connect(struct ceph_connection *con) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci dout("prepare_read_connect %p\n", con); 55862306a36Sopenharmony_ci con->v1.in_base_pos = 0; 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic void prepare_read_ack(struct ceph_connection *con) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci dout("prepare_read_ack %p\n", con); 56462306a36Sopenharmony_ci con->v1.in_base_pos = 0; 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_cistatic void prepare_read_seq(struct ceph_connection *con) 56862306a36Sopenharmony_ci{ 56962306a36Sopenharmony_ci dout("prepare_read_seq %p\n", con); 57062306a36Sopenharmony_ci con->v1.in_base_pos = 0; 57162306a36Sopenharmony_ci con->v1.in_tag = CEPH_MSGR_TAG_SEQ; 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cistatic void prepare_read_tag(struct ceph_connection *con) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci dout("prepare_read_tag %p\n", con); 57762306a36Sopenharmony_ci con->v1.in_base_pos = 0; 57862306a36Sopenharmony_ci con->v1.in_tag = CEPH_MSGR_TAG_READY; 57962306a36Sopenharmony_ci} 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_cistatic void prepare_read_keepalive_ack(struct ceph_connection *con) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci dout("prepare_read_keepalive_ack %p\n", con); 58462306a36Sopenharmony_ci con->v1.in_base_pos = 0; 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci/* 58862306a36Sopenharmony_ci * Prepare to read a message. 58962306a36Sopenharmony_ci */ 59062306a36Sopenharmony_cistatic int prepare_read_message(struct ceph_connection *con) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci dout("prepare_read_message %p\n", con); 59362306a36Sopenharmony_ci BUG_ON(con->in_msg != NULL); 59462306a36Sopenharmony_ci con->v1.in_base_pos = 0; 59562306a36Sopenharmony_ci con->in_front_crc = con->in_middle_crc = con->in_data_crc = 0; 59662306a36Sopenharmony_ci return 0; 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic int read_partial(struct ceph_connection *con, 60062306a36Sopenharmony_ci int end, int size, void *object) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci while (con->v1.in_base_pos < end) { 60362306a36Sopenharmony_ci int left = end - con->v1.in_base_pos; 60462306a36Sopenharmony_ci int have = size - left; 60562306a36Sopenharmony_ci int ret = ceph_tcp_recvmsg(con->sock, object + have, left); 60662306a36Sopenharmony_ci if (ret <= 0) 60762306a36Sopenharmony_ci return ret; 60862306a36Sopenharmony_ci con->v1.in_base_pos += ret; 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci return 1; 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci/* 61462306a36Sopenharmony_ci * Read all or part of the connect-side handshake on a new connection 61562306a36Sopenharmony_ci */ 61662306a36Sopenharmony_cistatic int read_partial_banner(struct ceph_connection *con) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci int size; 61962306a36Sopenharmony_ci int end; 62062306a36Sopenharmony_ci int ret; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci dout("read_partial_banner %p at %d\n", con, con->v1.in_base_pos); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci /* peer's banner */ 62562306a36Sopenharmony_ci size = strlen(CEPH_BANNER); 62662306a36Sopenharmony_ci end = size; 62762306a36Sopenharmony_ci ret = read_partial(con, end, size, con->v1.in_banner); 62862306a36Sopenharmony_ci if (ret <= 0) 62962306a36Sopenharmony_ci goto out; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci size = sizeof(con->v1.actual_peer_addr); 63262306a36Sopenharmony_ci end += size; 63362306a36Sopenharmony_ci ret = read_partial(con, end, size, &con->v1.actual_peer_addr); 63462306a36Sopenharmony_ci if (ret <= 0) 63562306a36Sopenharmony_ci goto out; 63662306a36Sopenharmony_ci ceph_decode_banner_addr(&con->v1.actual_peer_addr); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci size = sizeof(con->v1.peer_addr_for_me); 63962306a36Sopenharmony_ci end += size; 64062306a36Sopenharmony_ci ret = read_partial(con, end, size, &con->v1.peer_addr_for_me); 64162306a36Sopenharmony_ci if (ret <= 0) 64262306a36Sopenharmony_ci goto out; 64362306a36Sopenharmony_ci ceph_decode_banner_addr(&con->v1.peer_addr_for_me); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ciout: 64662306a36Sopenharmony_ci return ret; 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistatic int read_partial_connect(struct ceph_connection *con) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci int size; 65262306a36Sopenharmony_ci int end; 65362306a36Sopenharmony_ci int ret; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci dout("read_partial_connect %p at %d\n", con, con->v1.in_base_pos); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci size = sizeof(con->v1.in_reply); 65862306a36Sopenharmony_ci end = size; 65962306a36Sopenharmony_ci ret = read_partial(con, end, size, &con->v1.in_reply); 66062306a36Sopenharmony_ci if (ret <= 0) 66162306a36Sopenharmony_ci goto out; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (con->v1.auth) { 66462306a36Sopenharmony_ci size = le32_to_cpu(con->v1.in_reply.authorizer_len); 66562306a36Sopenharmony_ci if (size > con->v1.auth->authorizer_reply_buf_len) { 66662306a36Sopenharmony_ci pr_err("authorizer reply too big: %d > %zu\n", size, 66762306a36Sopenharmony_ci con->v1.auth->authorizer_reply_buf_len); 66862306a36Sopenharmony_ci ret = -EINVAL; 66962306a36Sopenharmony_ci goto out; 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci end += size; 67362306a36Sopenharmony_ci ret = read_partial(con, end, size, 67462306a36Sopenharmony_ci con->v1.auth->authorizer_reply_buf); 67562306a36Sopenharmony_ci if (ret <= 0) 67662306a36Sopenharmony_ci goto out; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci dout("read_partial_connect %p tag %d, con_seq = %u, g_seq = %u\n", 68062306a36Sopenharmony_ci con, con->v1.in_reply.tag, 68162306a36Sopenharmony_ci le32_to_cpu(con->v1.in_reply.connect_seq), 68262306a36Sopenharmony_ci le32_to_cpu(con->v1.in_reply.global_seq)); 68362306a36Sopenharmony_ciout: 68462306a36Sopenharmony_ci return ret; 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci/* 68862306a36Sopenharmony_ci * Verify the hello banner looks okay. 68962306a36Sopenharmony_ci */ 69062306a36Sopenharmony_cistatic int verify_hello(struct ceph_connection *con) 69162306a36Sopenharmony_ci{ 69262306a36Sopenharmony_ci if (memcmp(con->v1.in_banner, CEPH_BANNER, strlen(CEPH_BANNER))) { 69362306a36Sopenharmony_ci pr_err("connect to %s got bad banner\n", 69462306a36Sopenharmony_ci ceph_pr_addr(&con->peer_addr)); 69562306a36Sopenharmony_ci con->error_msg = "protocol error, bad banner"; 69662306a36Sopenharmony_ci return -1; 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci return 0; 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_cistatic int process_banner(struct ceph_connection *con) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci struct ceph_entity_addr *my_addr = &con->msgr->inst.addr; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci dout("process_banner on %p\n", con); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci if (verify_hello(con) < 0) 70862306a36Sopenharmony_ci return -1; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* 71162306a36Sopenharmony_ci * Make sure the other end is who we wanted. note that the other 71262306a36Sopenharmony_ci * end may not yet know their ip address, so if it's 0.0.0.0, give 71362306a36Sopenharmony_ci * them the benefit of the doubt. 71462306a36Sopenharmony_ci */ 71562306a36Sopenharmony_ci if (memcmp(&con->peer_addr, &con->v1.actual_peer_addr, 71662306a36Sopenharmony_ci sizeof(con->peer_addr)) != 0 && 71762306a36Sopenharmony_ci !(ceph_addr_is_blank(&con->v1.actual_peer_addr) && 71862306a36Sopenharmony_ci con->v1.actual_peer_addr.nonce == con->peer_addr.nonce)) { 71962306a36Sopenharmony_ci pr_warn("wrong peer, want %s/%u, got %s/%u\n", 72062306a36Sopenharmony_ci ceph_pr_addr(&con->peer_addr), 72162306a36Sopenharmony_ci le32_to_cpu(con->peer_addr.nonce), 72262306a36Sopenharmony_ci ceph_pr_addr(&con->v1.actual_peer_addr), 72362306a36Sopenharmony_ci le32_to_cpu(con->v1.actual_peer_addr.nonce)); 72462306a36Sopenharmony_ci con->error_msg = "wrong peer at address"; 72562306a36Sopenharmony_ci return -1; 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci /* 72962306a36Sopenharmony_ci * did we learn our address? 73062306a36Sopenharmony_ci */ 73162306a36Sopenharmony_ci if (ceph_addr_is_blank(my_addr)) { 73262306a36Sopenharmony_ci memcpy(&my_addr->in_addr, 73362306a36Sopenharmony_ci &con->v1.peer_addr_for_me.in_addr, 73462306a36Sopenharmony_ci sizeof(con->v1.peer_addr_for_me.in_addr)); 73562306a36Sopenharmony_ci ceph_addr_set_port(my_addr, 0); 73662306a36Sopenharmony_ci ceph_encode_my_addr(con->msgr); 73762306a36Sopenharmony_ci dout("process_banner learned my addr is %s\n", 73862306a36Sopenharmony_ci ceph_pr_addr(my_addr)); 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci return 0; 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_cistatic int process_connect(struct ceph_connection *con) 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci u64 sup_feat = from_msgr(con->msgr)->supported_features; 74762306a36Sopenharmony_ci u64 req_feat = from_msgr(con->msgr)->required_features; 74862306a36Sopenharmony_ci u64 server_feat = le64_to_cpu(con->v1.in_reply.features); 74962306a36Sopenharmony_ci int ret; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci dout("process_connect on %p tag %d\n", con, con->v1.in_tag); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci if (con->v1.auth) { 75462306a36Sopenharmony_ci int len = le32_to_cpu(con->v1.in_reply.authorizer_len); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci /* 75762306a36Sopenharmony_ci * Any connection that defines ->get_authorizer() 75862306a36Sopenharmony_ci * should also define ->add_authorizer_challenge() and 75962306a36Sopenharmony_ci * ->verify_authorizer_reply(). 76062306a36Sopenharmony_ci * 76162306a36Sopenharmony_ci * See get_connect_authorizer(). 76262306a36Sopenharmony_ci */ 76362306a36Sopenharmony_ci if (con->v1.in_reply.tag == 76462306a36Sopenharmony_ci CEPH_MSGR_TAG_CHALLENGE_AUTHORIZER) { 76562306a36Sopenharmony_ci ret = con->ops->add_authorizer_challenge( 76662306a36Sopenharmony_ci con, con->v1.auth->authorizer_reply_buf, len); 76762306a36Sopenharmony_ci if (ret < 0) 76862306a36Sopenharmony_ci return ret; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci con_out_kvec_reset(con); 77162306a36Sopenharmony_ci __prepare_write_connect(con); 77262306a36Sopenharmony_ci prepare_read_connect(con); 77362306a36Sopenharmony_ci return 0; 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci if (len) { 77762306a36Sopenharmony_ci ret = con->ops->verify_authorizer_reply(con); 77862306a36Sopenharmony_ci if (ret < 0) { 77962306a36Sopenharmony_ci con->error_msg = "bad authorize reply"; 78062306a36Sopenharmony_ci return ret; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci switch (con->v1.in_reply.tag) { 78662306a36Sopenharmony_ci case CEPH_MSGR_TAG_FEATURES: 78762306a36Sopenharmony_ci pr_err("%s%lld %s feature set mismatch," 78862306a36Sopenharmony_ci " my %llx < server's %llx, missing %llx\n", 78962306a36Sopenharmony_ci ENTITY_NAME(con->peer_name), 79062306a36Sopenharmony_ci ceph_pr_addr(&con->peer_addr), 79162306a36Sopenharmony_ci sup_feat, server_feat, server_feat & ~sup_feat); 79262306a36Sopenharmony_ci con->error_msg = "missing required protocol features"; 79362306a36Sopenharmony_ci return -1; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci case CEPH_MSGR_TAG_BADPROTOVER: 79662306a36Sopenharmony_ci pr_err("%s%lld %s protocol version mismatch," 79762306a36Sopenharmony_ci " my %d != server's %d\n", 79862306a36Sopenharmony_ci ENTITY_NAME(con->peer_name), 79962306a36Sopenharmony_ci ceph_pr_addr(&con->peer_addr), 80062306a36Sopenharmony_ci le32_to_cpu(con->v1.out_connect.protocol_version), 80162306a36Sopenharmony_ci le32_to_cpu(con->v1.in_reply.protocol_version)); 80262306a36Sopenharmony_ci con->error_msg = "protocol version mismatch"; 80362306a36Sopenharmony_ci return -1; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci case CEPH_MSGR_TAG_BADAUTHORIZER: 80662306a36Sopenharmony_ci con->v1.auth_retry++; 80762306a36Sopenharmony_ci dout("process_connect %p got BADAUTHORIZER attempt %d\n", con, 80862306a36Sopenharmony_ci con->v1.auth_retry); 80962306a36Sopenharmony_ci if (con->v1.auth_retry == 2) { 81062306a36Sopenharmony_ci con->error_msg = "connect authorization failure"; 81162306a36Sopenharmony_ci return -1; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci con_out_kvec_reset(con); 81462306a36Sopenharmony_ci ret = prepare_write_connect(con); 81562306a36Sopenharmony_ci if (ret < 0) 81662306a36Sopenharmony_ci return ret; 81762306a36Sopenharmony_ci prepare_read_connect(con); 81862306a36Sopenharmony_ci break; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci case CEPH_MSGR_TAG_RESETSESSION: 82162306a36Sopenharmony_ci /* 82262306a36Sopenharmony_ci * If we connected with a large connect_seq but the peer 82362306a36Sopenharmony_ci * has no record of a session with us (no connection, or 82462306a36Sopenharmony_ci * connect_seq == 0), they will send RESETSESION to indicate 82562306a36Sopenharmony_ci * that they must have reset their session, and may have 82662306a36Sopenharmony_ci * dropped messages. 82762306a36Sopenharmony_ci */ 82862306a36Sopenharmony_ci dout("process_connect got RESET peer seq %u\n", 82962306a36Sopenharmony_ci le32_to_cpu(con->v1.in_reply.connect_seq)); 83062306a36Sopenharmony_ci pr_info("%s%lld %s session reset\n", 83162306a36Sopenharmony_ci ENTITY_NAME(con->peer_name), 83262306a36Sopenharmony_ci ceph_pr_addr(&con->peer_addr)); 83362306a36Sopenharmony_ci ceph_con_reset_session(con); 83462306a36Sopenharmony_ci con_out_kvec_reset(con); 83562306a36Sopenharmony_ci ret = prepare_write_connect(con); 83662306a36Sopenharmony_ci if (ret < 0) 83762306a36Sopenharmony_ci return ret; 83862306a36Sopenharmony_ci prepare_read_connect(con); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci /* Tell ceph about it. */ 84162306a36Sopenharmony_ci mutex_unlock(&con->mutex); 84262306a36Sopenharmony_ci if (con->ops->peer_reset) 84362306a36Sopenharmony_ci con->ops->peer_reset(con); 84462306a36Sopenharmony_ci mutex_lock(&con->mutex); 84562306a36Sopenharmony_ci if (con->state != CEPH_CON_S_V1_CONNECT_MSG) 84662306a36Sopenharmony_ci return -EAGAIN; 84762306a36Sopenharmony_ci break; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci case CEPH_MSGR_TAG_RETRY_SESSION: 85062306a36Sopenharmony_ci /* 85162306a36Sopenharmony_ci * If we sent a smaller connect_seq than the peer has, try 85262306a36Sopenharmony_ci * again with a larger value. 85362306a36Sopenharmony_ci */ 85462306a36Sopenharmony_ci dout("process_connect got RETRY_SESSION my seq %u, peer %u\n", 85562306a36Sopenharmony_ci le32_to_cpu(con->v1.out_connect.connect_seq), 85662306a36Sopenharmony_ci le32_to_cpu(con->v1.in_reply.connect_seq)); 85762306a36Sopenharmony_ci con->v1.connect_seq = le32_to_cpu(con->v1.in_reply.connect_seq); 85862306a36Sopenharmony_ci con_out_kvec_reset(con); 85962306a36Sopenharmony_ci ret = prepare_write_connect(con); 86062306a36Sopenharmony_ci if (ret < 0) 86162306a36Sopenharmony_ci return ret; 86262306a36Sopenharmony_ci prepare_read_connect(con); 86362306a36Sopenharmony_ci break; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci case CEPH_MSGR_TAG_RETRY_GLOBAL: 86662306a36Sopenharmony_ci /* 86762306a36Sopenharmony_ci * If we sent a smaller global_seq than the peer has, try 86862306a36Sopenharmony_ci * again with a larger value. 86962306a36Sopenharmony_ci */ 87062306a36Sopenharmony_ci dout("process_connect got RETRY_GLOBAL my %u peer_gseq %u\n", 87162306a36Sopenharmony_ci con->v1.peer_global_seq, 87262306a36Sopenharmony_ci le32_to_cpu(con->v1.in_reply.global_seq)); 87362306a36Sopenharmony_ci ceph_get_global_seq(con->msgr, 87462306a36Sopenharmony_ci le32_to_cpu(con->v1.in_reply.global_seq)); 87562306a36Sopenharmony_ci con_out_kvec_reset(con); 87662306a36Sopenharmony_ci ret = prepare_write_connect(con); 87762306a36Sopenharmony_ci if (ret < 0) 87862306a36Sopenharmony_ci return ret; 87962306a36Sopenharmony_ci prepare_read_connect(con); 88062306a36Sopenharmony_ci break; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci case CEPH_MSGR_TAG_SEQ: 88362306a36Sopenharmony_ci case CEPH_MSGR_TAG_READY: 88462306a36Sopenharmony_ci if (req_feat & ~server_feat) { 88562306a36Sopenharmony_ci pr_err("%s%lld %s protocol feature mismatch," 88662306a36Sopenharmony_ci " my required %llx > server's %llx, need %llx\n", 88762306a36Sopenharmony_ci ENTITY_NAME(con->peer_name), 88862306a36Sopenharmony_ci ceph_pr_addr(&con->peer_addr), 88962306a36Sopenharmony_ci req_feat, server_feat, req_feat & ~server_feat); 89062306a36Sopenharmony_ci con->error_msg = "missing required protocol features"; 89162306a36Sopenharmony_ci return -1; 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci WARN_ON(con->state != CEPH_CON_S_V1_CONNECT_MSG); 89562306a36Sopenharmony_ci con->state = CEPH_CON_S_OPEN; 89662306a36Sopenharmony_ci con->v1.auth_retry = 0; /* we authenticated; clear flag */ 89762306a36Sopenharmony_ci con->v1.peer_global_seq = 89862306a36Sopenharmony_ci le32_to_cpu(con->v1.in_reply.global_seq); 89962306a36Sopenharmony_ci con->v1.connect_seq++; 90062306a36Sopenharmony_ci con->peer_features = server_feat; 90162306a36Sopenharmony_ci dout("process_connect got READY gseq %d cseq %d (%d)\n", 90262306a36Sopenharmony_ci con->v1.peer_global_seq, 90362306a36Sopenharmony_ci le32_to_cpu(con->v1.in_reply.connect_seq), 90462306a36Sopenharmony_ci con->v1.connect_seq); 90562306a36Sopenharmony_ci WARN_ON(con->v1.connect_seq != 90662306a36Sopenharmony_ci le32_to_cpu(con->v1.in_reply.connect_seq)); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci if (con->v1.in_reply.flags & CEPH_MSG_CONNECT_LOSSY) 90962306a36Sopenharmony_ci ceph_con_flag_set(con, CEPH_CON_F_LOSSYTX); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci con->delay = 0; /* reset backoff memory */ 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci if (con->v1.in_reply.tag == CEPH_MSGR_TAG_SEQ) { 91462306a36Sopenharmony_ci prepare_write_seq(con); 91562306a36Sopenharmony_ci prepare_read_seq(con); 91662306a36Sopenharmony_ci } else { 91762306a36Sopenharmony_ci prepare_read_tag(con); 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci break; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci case CEPH_MSGR_TAG_WAIT: 92262306a36Sopenharmony_ci /* 92362306a36Sopenharmony_ci * If there is a connection race (we are opening 92462306a36Sopenharmony_ci * connections to each other), one of us may just have 92562306a36Sopenharmony_ci * to WAIT. This shouldn't happen if we are the 92662306a36Sopenharmony_ci * client. 92762306a36Sopenharmony_ci */ 92862306a36Sopenharmony_ci con->error_msg = "protocol error, got WAIT as client"; 92962306a36Sopenharmony_ci return -1; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci default: 93262306a36Sopenharmony_ci con->error_msg = "protocol error, garbage tag during connect"; 93362306a36Sopenharmony_ci return -1; 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci return 0; 93662306a36Sopenharmony_ci} 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci/* 93962306a36Sopenharmony_ci * read (part of) an ack 94062306a36Sopenharmony_ci */ 94162306a36Sopenharmony_cistatic int read_partial_ack(struct ceph_connection *con) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci int size = sizeof(con->v1.in_temp_ack); 94462306a36Sopenharmony_ci int end = size; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci return read_partial(con, end, size, &con->v1.in_temp_ack); 94762306a36Sopenharmony_ci} 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci/* 95062306a36Sopenharmony_ci * We can finally discard anything that's been acked. 95162306a36Sopenharmony_ci */ 95262306a36Sopenharmony_cistatic void process_ack(struct ceph_connection *con) 95362306a36Sopenharmony_ci{ 95462306a36Sopenharmony_ci u64 ack = le64_to_cpu(con->v1.in_temp_ack); 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci if (con->v1.in_tag == CEPH_MSGR_TAG_ACK) 95762306a36Sopenharmony_ci ceph_con_discard_sent(con, ack); 95862306a36Sopenharmony_ci else 95962306a36Sopenharmony_ci ceph_con_discard_requeued(con, ack); 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci prepare_read_tag(con); 96262306a36Sopenharmony_ci} 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_cistatic int read_partial_message_chunk(struct ceph_connection *con, 96562306a36Sopenharmony_ci struct kvec *section, 96662306a36Sopenharmony_ci unsigned int sec_len, u32 *crc) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci int ret, left; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci BUG_ON(!section); 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci while (section->iov_len < sec_len) { 97362306a36Sopenharmony_ci BUG_ON(section->iov_base == NULL); 97462306a36Sopenharmony_ci left = sec_len - section->iov_len; 97562306a36Sopenharmony_ci ret = ceph_tcp_recvmsg(con->sock, (char *)section->iov_base + 97662306a36Sopenharmony_ci section->iov_len, left); 97762306a36Sopenharmony_ci if (ret <= 0) 97862306a36Sopenharmony_ci return ret; 97962306a36Sopenharmony_ci section->iov_len += ret; 98062306a36Sopenharmony_ci } 98162306a36Sopenharmony_ci if (section->iov_len == sec_len) 98262306a36Sopenharmony_ci *crc = crc32c(*crc, section->iov_base, section->iov_len); 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci return 1; 98562306a36Sopenharmony_ci} 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_cistatic inline int read_partial_message_section(struct ceph_connection *con, 98862306a36Sopenharmony_ci struct kvec *section, 98962306a36Sopenharmony_ci unsigned int sec_len, u32 *crc) 99062306a36Sopenharmony_ci{ 99162306a36Sopenharmony_ci *crc = 0; 99262306a36Sopenharmony_ci return read_partial_message_chunk(con, section, sec_len, crc); 99362306a36Sopenharmony_ci} 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_cistatic int read_partial_sparse_msg_extent(struct ceph_connection *con, u32 *crc) 99662306a36Sopenharmony_ci{ 99762306a36Sopenharmony_ci struct ceph_msg_data_cursor *cursor = &con->in_msg->cursor; 99862306a36Sopenharmony_ci bool do_bounce = ceph_test_opt(from_msgr(con->msgr), RXBOUNCE); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci if (do_bounce && unlikely(!con->bounce_page)) { 100162306a36Sopenharmony_ci con->bounce_page = alloc_page(GFP_NOIO); 100262306a36Sopenharmony_ci if (!con->bounce_page) { 100362306a36Sopenharmony_ci pr_err("failed to allocate bounce page\n"); 100462306a36Sopenharmony_ci return -ENOMEM; 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci } 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci while (cursor->sr_resid > 0) { 100962306a36Sopenharmony_ci struct page *page, *rpage; 101062306a36Sopenharmony_ci size_t off, len; 101162306a36Sopenharmony_ci int ret; 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci page = ceph_msg_data_next(cursor, &off, &len); 101462306a36Sopenharmony_ci rpage = do_bounce ? con->bounce_page : page; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci /* clamp to what remains in extent */ 101762306a36Sopenharmony_ci len = min_t(int, len, cursor->sr_resid); 101862306a36Sopenharmony_ci ret = ceph_tcp_recvpage(con->sock, rpage, (int)off, len); 101962306a36Sopenharmony_ci if (ret <= 0) 102062306a36Sopenharmony_ci return ret; 102162306a36Sopenharmony_ci *crc = ceph_crc32c_page(*crc, rpage, off, ret); 102262306a36Sopenharmony_ci ceph_msg_data_advance(cursor, (size_t)ret); 102362306a36Sopenharmony_ci cursor->sr_resid -= ret; 102462306a36Sopenharmony_ci if (do_bounce) 102562306a36Sopenharmony_ci memcpy_page(page, off, rpage, off, ret); 102662306a36Sopenharmony_ci } 102762306a36Sopenharmony_ci return 1; 102862306a36Sopenharmony_ci} 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_cistatic int read_partial_sparse_msg_data(struct ceph_connection *con) 103162306a36Sopenharmony_ci{ 103262306a36Sopenharmony_ci struct ceph_msg_data_cursor *cursor = &con->in_msg->cursor; 103362306a36Sopenharmony_ci bool do_datacrc = !ceph_test_opt(from_msgr(con->msgr), NOCRC); 103462306a36Sopenharmony_ci u32 crc = 0; 103562306a36Sopenharmony_ci int ret = 1; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci if (do_datacrc) 103862306a36Sopenharmony_ci crc = con->in_data_crc; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci while (cursor->total_resid) { 104162306a36Sopenharmony_ci if (con->v1.in_sr_kvec.iov_base) 104262306a36Sopenharmony_ci ret = read_partial_message_chunk(con, 104362306a36Sopenharmony_ci &con->v1.in_sr_kvec, 104462306a36Sopenharmony_ci con->v1.in_sr_len, 104562306a36Sopenharmony_ci &crc); 104662306a36Sopenharmony_ci else if (cursor->sr_resid > 0) 104762306a36Sopenharmony_ci ret = read_partial_sparse_msg_extent(con, &crc); 104862306a36Sopenharmony_ci if (ret <= 0) 104962306a36Sopenharmony_ci break; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci memset(&con->v1.in_sr_kvec, 0, sizeof(con->v1.in_sr_kvec)); 105262306a36Sopenharmony_ci ret = con->ops->sparse_read(con, cursor, 105362306a36Sopenharmony_ci (char **)&con->v1.in_sr_kvec.iov_base); 105462306a36Sopenharmony_ci if (ret <= 0) { 105562306a36Sopenharmony_ci ret = ret ? ret : 1; /* must return > 0 to indicate success */ 105662306a36Sopenharmony_ci break; 105762306a36Sopenharmony_ci } 105862306a36Sopenharmony_ci con->v1.in_sr_len = ret; 105962306a36Sopenharmony_ci } 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci if (do_datacrc) 106262306a36Sopenharmony_ci con->in_data_crc = crc; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci return ret; 106562306a36Sopenharmony_ci} 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_cistatic int read_partial_msg_data(struct ceph_connection *con) 106862306a36Sopenharmony_ci{ 106962306a36Sopenharmony_ci struct ceph_msg_data_cursor *cursor = &con->in_msg->cursor; 107062306a36Sopenharmony_ci bool do_datacrc = !ceph_test_opt(from_msgr(con->msgr), NOCRC); 107162306a36Sopenharmony_ci struct page *page; 107262306a36Sopenharmony_ci size_t page_offset; 107362306a36Sopenharmony_ci size_t length; 107462306a36Sopenharmony_ci u32 crc = 0; 107562306a36Sopenharmony_ci int ret; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci if (do_datacrc) 107862306a36Sopenharmony_ci crc = con->in_data_crc; 107962306a36Sopenharmony_ci while (cursor->total_resid) { 108062306a36Sopenharmony_ci if (!cursor->resid) { 108162306a36Sopenharmony_ci ceph_msg_data_advance(cursor, 0); 108262306a36Sopenharmony_ci continue; 108362306a36Sopenharmony_ci } 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci page = ceph_msg_data_next(cursor, &page_offset, &length); 108662306a36Sopenharmony_ci ret = ceph_tcp_recvpage(con->sock, page, page_offset, length); 108762306a36Sopenharmony_ci if (ret <= 0) { 108862306a36Sopenharmony_ci if (do_datacrc) 108962306a36Sopenharmony_ci con->in_data_crc = crc; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci return ret; 109262306a36Sopenharmony_ci } 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci if (do_datacrc) 109562306a36Sopenharmony_ci crc = ceph_crc32c_page(crc, page, page_offset, ret); 109662306a36Sopenharmony_ci ceph_msg_data_advance(cursor, (size_t)ret); 109762306a36Sopenharmony_ci } 109862306a36Sopenharmony_ci if (do_datacrc) 109962306a36Sopenharmony_ci con->in_data_crc = crc; 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci return 1; /* must return > 0 to indicate success */ 110262306a36Sopenharmony_ci} 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_cistatic int read_partial_msg_data_bounce(struct ceph_connection *con) 110562306a36Sopenharmony_ci{ 110662306a36Sopenharmony_ci struct ceph_msg_data_cursor *cursor = &con->in_msg->cursor; 110762306a36Sopenharmony_ci struct page *page; 110862306a36Sopenharmony_ci size_t off, len; 110962306a36Sopenharmony_ci u32 crc; 111062306a36Sopenharmony_ci int ret; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci if (unlikely(!con->bounce_page)) { 111362306a36Sopenharmony_ci con->bounce_page = alloc_page(GFP_NOIO); 111462306a36Sopenharmony_ci if (!con->bounce_page) { 111562306a36Sopenharmony_ci pr_err("failed to allocate bounce page\n"); 111662306a36Sopenharmony_ci return -ENOMEM; 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci } 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci crc = con->in_data_crc; 112162306a36Sopenharmony_ci while (cursor->total_resid) { 112262306a36Sopenharmony_ci if (!cursor->resid) { 112362306a36Sopenharmony_ci ceph_msg_data_advance(cursor, 0); 112462306a36Sopenharmony_ci continue; 112562306a36Sopenharmony_ci } 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci page = ceph_msg_data_next(cursor, &off, &len); 112862306a36Sopenharmony_ci ret = ceph_tcp_recvpage(con->sock, con->bounce_page, 0, len); 112962306a36Sopenharmony_ci if (ret <= 0) { 113062306a36Sopenharmony_ci con->in_data_crc = crc; 113162306a36Sopenharmony_ci return ret; 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci crc = crc32c(crc, page_address(con->bounce_page), ret); 113562306a36Sopenharmony_ci memcpy_to_page(page, off, page_address(con->bounce_page), ret); 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci ceph_msg_data_advance(cursor, ret); 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci con->in_data_crc = crc; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci return 1; /* must return > 0 to indicate success */ 114262306a36Sopenharmony_ci} 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci/* 114562306a36Sopenharmony_ci * read (part of) a message. 114662306a36Sopenharmony_ci */ 114762306a36Sopenharmony_cistatic int read_partial_message(struct ceph_connection *con) 114862306a36Sopenharmony_ci{ 114962306a36Sopenharmony_ci struct ceph_msg *m = con->in_msg; 115062306a36Sopenharmony_ci int size; 115162306a36Sopenharmony_ci int end; 115262306a36Sopenharmony_ci int ret; 115362306a36Sopenharmony_ci unsigned int front_len, middle_len, data_len; 115462306a36Sopenharmony_ci bool do_datacrc = !ceph_test_opt(from_msgr(con->msgr), NOCRC); 115562306a36Sopenharmony_ci bool need_sign = (con->peer_features & CEPH_FEATURE_MSG_AUTH); 115662306a36Sopenharmony_ci u64 seq; 115762306a36Sopenharmony_ci u32 crc; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci dout("read_partial_message con %p msg %p\n", con, m); 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci /* header */ 116262306a36Sopenharmony_ci size = sizeof(con->v1.in_hdr); 116362306a36Sopenharmony_ci end = size; 116462306a36Sopenharmony_ci ret = read_partial(con, end, size, &con->v1.in_hdr); 116562306a36Sopenharmony_ci if (ret <= 0) 116662306a36Sopenharmony_ci return ret; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci crc = crc32c(0, &con->v1.in_hdr, offsetof(struct ceph_msg_header, crc)); 116962306a36Sopenharmony_ci if (cpu_to_le32(crc) != con->v1.in_hdr.crc) { 117062306a36Sopenharmony_ci pr_err("read_partial_message bad hdr crc %u != expected %u\n", 117162306a36Sopenharmony_ci crc, con->v1.in_hdr.crc); 117262306a36Sopenharmony_ci return -EBADMSG; 117362306a36Sopenharmony_ci } 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci front_len = le32_to_cpu(con->v1.in_hdr.front_len); 117662306a36Sopenharmony_ci if (front_len > CEPH_MSG_MAX_FRONT_LEN) 117762306a36Sopenharmony_ci return -EIO; 117862306a36Sopenharmony_ci middle_len = le32_to_cpu(con->v1.in_hdr.middle_len); 117962306a36Sopenharmony_ci if (middle_len > CEPH_MSG_MAX_MIDDLE_LEN) 118062306a36Sopenharmony_ci return -EIO; 118162306a36Sopenharmony_ci data_len = le32_to_cpu(con->v1.in_hdr.data_len); 118262306a36Sopenharmony_ci if (data_len > CEPH_MSG_MAX_DATA_LEN) 118362306a36Sopenharmony_ci return -EIO; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci /* verify seq# */ 118662306a36Sopenharmony_ci seq = le64_to_cpu(con->v1.in_hdr.seq); 118762306a36Sopenharmony_ci if ((s64)seq - (s64)con->in_seq < 1) { 118862306a36Sopenharmony_ci pr_info("skipping %s%lld %s seq %lld expected %lld\n", 118962306a36Sopenharmony_ci ENTITY_NAME(con->peer_name), 119062306a36Sopenharmony_ci ceph_pr_addr(&con->peer_addr), 119162306a36Sopenharmony_ci seq, con->in_seq + 1); 119262306a36Sopenharmony_ci con->v1.in_base_pos = -front_len - middle_len - data_len - 119362306a36Sopenharmony_ci sizeof_footer(con); 119462306a36Sopenharmony_ci con->v1.in_tag = CEPH_MSGR_TAG_READY; 119562306a36Sopenharmony_ci return 1; 119662306a36Sopenharmony_ci } else if ((s64)seq - (s64)con->in_seq > 1) { 119762306a36Sopenharmony_ci pr_err("read_partial_message bad seq %lld expected %lld\n", 119862306a36Sopenharmony_ci seq, con->in_seq + 1); 119962306a36Sopenharmony_ci con->error_msg = "bad message sequence # for incoming message"; 120062306a36Sopenharmony_ci return -EBADE; 120162306a36Sopenharmony_ci } 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci /* allocate message? */ 120462306a36Sopenharmony_ci if (!con->in_msg) { 120562306a36Sopenharmony_ci int skip = 0; 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci dout("got hdr type %d front %d data %d\n", con->v1.in_hdr.type, 120862306a36Sopenharmony_ci front_len, data_len); 120962306a36Sopenharmony_ci ret = ceph_con_in_msg_alloc(con, &con->v1.in_hdr, &skip); 121062306a36Sopenharmony_ci if (ret < 0) 121162306a36Sopenharmony_ci return ret; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci BUG_ON((!con->in_msg) ^ skip); 121462306a36Sopenharmony_ci if (skip) { 121562306a36Sopenharmony_ci /* skip this message */ 121662306a36Sopenharmony_ci dout("alloc_msg said skip message\n"); 121762306a36Sopenharmony_ci con->v1.in_base_pos = -front_len - middle_len - 121862306a36Sopenharmony_ci data_len - sizeof_footer(con); 121962306a36Sopenharmony_ci con->v1.in_tag = CEPH_MSGR_TAG_READY; 122062306a36Sopenharmony_ci con->in_seq++; 122162306a36Sopenharmony_ci return 1; 122262306a36Sopenharmony_ci } 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci BUG_ON(!con->in_msg); 122562306a36Sopenharmony_ci BUG_ON(con->in_msg->con != con); 122662306a36Sopenharmony_ci m = con->in_msg; 122762306a36Sopenharmony_ci m->front.iov_len = 0; /* haven't read it yet */ 122862306a36Sopenharmony_ci if (m->middle) 122962306a36Sopenharmony_ci m->middle->vec.iov_len = 0; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci /* prepare for data payload, if any */ 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci if (data_len) 123462306a36Sopenharmony_ci prepare_message_data(con->in_msg, data_len); 123562306a36Sopenharmony_ci } 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci /* front */ 123862306a36Sopenharmony_ci ret = read_partial_message_section(con, &m->front, front_len, 123962306a36Sopenharmony_ci &con->in_front_crc); 124062306a36Sopenharmony_ci if (ret <= 0) 124162306a36Sopenharmony_ci return ret; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci /* middle */ 124462306a36Sopenharmony_ci if (m->middle) { 124562306a36Sopenharmony_ci ret = read_partial_message_section(con, &m->middle->vec, 124662306a36Sopenharmony_ci middle_len, 124762306a36Sopenharmony_ci &con->in_middle_crc); 124862306a36Sopenharmony_ci if (ret <= 0) 124962306a36Sopenharmony_ci return ret; 125062306a36Sopenharmony_ci } 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci /* (page) data */ 125362306a36Sopenharmony_ci if (data_len) { 125462306a36Sopenharmony_ci if (!m->num_data_items) 125562306a36Sopenharmony_ci return -EIO; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci if (m->sparse_read_total) 125862306a36Sopenharmony_ci ret = read_partial_sparse_msg_data(con); 125962306a36Sopenharmony_ci else if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE)) 126062306a36Sopenharmony_ci ret = read_partial_msg_data_bounce(con); 126162306a36Sopenharmony_ci else 126262306a36Sopenharmony_ci ret = read_partial_msg_data(con); 126362306a36Sopenharmony_ci if (ret <= 0) 126462306a36Sopenharmony_ci return ret; 126562306a36Sopenharmony_ci } 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci /* footer */ 126862306a36Sopenharmony_ci size = sizeof_footer(con); 126962306a36Sopenharmony_ci end += size; 127062306a36Sopenharmony_ci ret = read_partial(con, end, size, &m->footer); 127162306a36Sopenharmony_ci if (ret <= 0) 127262306a36Sopenharmony_ci return ret; 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci if (!need_sign) { 127562306a36Sopenharmony_ci m->footer.flags = m->old_footer.flags; 127662306a36Sopenharmony_ci m->footer.sig = 0; 127762306a36Sopenharmony_ci } 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci dout("read_partial_message got msg %p %d (%u) + %d (%u) + %d (%u)\n", 128062306a36Sopenharmony_ci m, front_len, m->footer.front_crc, middle_len, 128162306a36Sopenharmony_ci m->footer.middle_crc, data_len, m->footer.data_crc); 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci /* crc ok? */ 128462306a36Sopenharmony_ci if (con->in_front_crc != le32_to_cpu(m->footer.front_crc)) { 128562306a36Sopenharmony_ci pr_err("read_partial_message %p front crc %u != exp. %u\n", 128662306a36Sopenharmony_ci m, con->in_front_crc, m->footer.front_crc); 128762306a36Sopenharmony_ci return -EBADMSG; 128862306a36Sopenharmony_ci } 128962306a36Sopenharmony_ci if (con->in_middle_crc != le32_to_cpu(m->footer.middle_crc)) { 129062306a36Sopenharmony_ci pr_err("read_partial_message %p middle crc %u != exp %u\n", 129162306a36Sopenharmony_ci m, con->in_middle_crc, m->footer.middle_crc); 129262306a36Sopenharmony_ci return -EBADMSG; 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci if (do_datacrc && 129562306a36Sopenharmony_ci (m->footer.flags & CEPH_MSG_FOOTER_NOCRC) == 0 && 129662306a36Sopenharmony_ci con->in_data_crc != le32_to_cpu(m->footer.data_crc)) { 129762306a36Sopenharmony_ci pr_err("read_partial_message %p data crc %u != exp. %u\n", m, 129862306a36Sopenharmony_ci con->in_data_crc, le32_to_cpu(m->footer.data_crc)); 129962306a36Sopenharmony_ci return -EBADMSG; 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci if (need_sign && con->ops->check_message_signature && 130362306a36Sopenharmony_ci con->ops->check_message_signature(m)) { 130462306a36Sopenharmony_ci pr_err("read_partial_message %p signature check failed\n", m); 130562306a36Sopenharmony_ci return -EBADMSG; 130662306a36Sopenharmony_ci } 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci return 1; /* done! */ 130962306a36Sopenharmony_ci} 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_cistatic int read_keepalive_ack(struct ceph_connection *con) 131262306a36Sopenharmony_ci{ 131362306a36Sopenharmony_ci struct ceph_timespec ceph_ts; 131462306a36Sopenharmony_ci size_t size = sizeof(ceph_ts); 131562306a36Sopenharmony_ci int ret = read_partial(con, size, size, &ceph_ts); 131662306a36Sopenharmony_ci if (ret <= 0) 131762306a36Sopenharmony_ci return ret; 131862306a36Sopenharmony_ci ceph_decode_timespec64(&con->last_keepalive_ack, &ceph_ts); 131962306a36Sopenharmony_ci prepare_read_tag(con); 132062306a36Sopenharmony_ci return 1; 132162306a36Sopenharmony_ci} 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci/* 132462306a36Sopenharmony_ci * Read what we can from the socket. 132562306a36Sopenharmony_ci */ 132662306a36Sopenharmony_ciint ceph_con_v1_try_read(struct ceph_connection *con) 132762306a36Sopenharmony_ci{ 132862306a36Sopenharmony_ci int ret = -1; 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_cimore: 133162306a36Sopenharmony_ci dout("try_read start %p state %d\n", con, con->state); 133262306a36Sopenharmony_ci if (con->state != CEPH_CON_S_V1_BANNER && 133362306a36Sopenharmony_ci con->state != CEPH_CON_S_V1_CONNECT_MSG && 133462306a36Sopenharmony_ci con->state != CEPH_CON_S_OPEN) 133562306a36Sopenharmony_ci return 0; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci BUG_ON(!con->sock); 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci dout("try_read tag %d in_base_pos %d\n", con->v1.in_tag, 134062306a36Sopenharmony_ci con->v1.in_base_pos); 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci if (con->state == CEPH_CON_S_V1_BANNER) { 134362306a36Sopenharmony_ci ret = read_partial_banner(con); 134462306a36Sopenharmony_ci if (ret <= 0) 134562306a36Sopenharmony_ci goto out; 134662306a36Sopenharmony_ci ret = process_banner(con); 134762306a36Sopenharmony_ci if (ret < 0) 134862306a36Sopenharmony_ci goto out; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci con->state = CEPH_CON_S_V1_CONNECT_MSG; 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci /* 135362306a36Sopenharmony_ci * Received banner is good, exchange connection info. 135462306a36Sopenharmony_ci * Do not reset out_kvec, as sending our banner raced 135562306a36Sopenharmony_ci * with receiving peer banner after connect completed. 135662306a36Sopenharmony_ci */ 135762306a36Sopenharmony_ci ret = prepare_write_connect(con); 135862306a36Sopenharmony_ci if (ret < 0) 135962306a36Sopenharmony_ci goto out; 136062306a36Sopenharmony_ci prepare_read_connect(con); 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci /* Send connection info before awaiting response */ 136362306a36Sopenharmony_ci goto out; 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci if (con->state == CEPH_CON_S_V1_CONNECT_MSG) { 136762306a36Sopenharmony_ci ret = read_partial_connect(con); 136862306a36Sopenharmony_ci if (ret <= 0) 136962306a36Sopenharmony_ci goto out; 137062306a36Sopenharmony_ci ret = process_connect(con); 137162306a36Sopenharmony_ci if (ret < 0) 137262306a36Sopenharmony_ci goto out; 137362306a36Sopenharmony_ci goto more; 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci WARN_ON(con->state != CEPH_CON_S_OPEN); 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci if (con->v1.in_base_pos < 0) { 137962306a36Sopenharmony_ci /* 138062306a36Sopenharmony_ci * skipping + discarding content. 138162306a36Sopenharmony_ci */ 138262306a36Sopenharmony_ci ret = ceph_tcp_recvmsg(con->sock, NULL, -con->v1.in_base_pos); 138362306a36Sopenharmony_ci if (ret <= 0) 138462306a36Sopenharmony_ci goto out; 138562306a36Sopenharmony_ci dout("skipped %d / %d bytes\n", ret, -con->v1.in_base_pos); 138662306a36Sopenharmony_ci con->v1.in_base_pos += ret; 138762306a36Sopenharmony_ci if (con->v1.in_base_pos) 138862306a36Sopenharmony_ci goto more; 138962306a36Sopenharmony_ci } 139062306a36Sopenharmony_ci if (con->v1.in_tag == CEPH_MSGR_TAG_READY) { 139162306a36Sopenharmony_ci /* 139262306a36Sopenharmony_ci * what's next? 139362306a36Sopenharmony_ci */ 139462306a36Sopenharmony_ci ret = ceph_tcp_recvmsg(con->sock, &con->v1.in_tag, 1); 139562306a36Sopenharmony_ci if (ret <= 0) 139662306a36Sopenharmony_ci goto out; 139762306a36Sopenharmony_ci dout("try_read got tag %d\n", con->v1.in_tag); 139862306a36Sopenharmony_ci switch (con->v1.in_tag) { 139962306a36Sopenharmony_ci case CEPH_MSGR_TAG_MSG: 140062306a36Sopenharmony_ci prepare_read_message(con); 140162306a36Sopenharmony_ci break; 140262306a36Sopenharmony_ci case CEPH_MSGR_TAG_ACK: 140362306a36Sopenharmony_ci prepare_read_ack(con); 140462306a36Sopenharmony_ci break; 140562306a36Sopenharmony_ci case CEPH_MSGR_TAG_KEEPALIVE2_ACK: 140662306a36Sopenharmony_ci prepare_read_keepalive_ack(con); 140762306a36Sopenharmony_ci break; 140862306a36Sopenharmony_ci case CEPH_MSGR_TAG_CLOSE: 140962306a36Sopenharmony_ci ceph_con_close_socket(con); 141062306a36Sopenharmony_ci con->state = CEPH_CON_S_CLOSED; 141162306a36Sopenharmony_ci goto out; 141262306a36Sopenharmony_ci default: 141362306a36Sopenharmony_ci goto bad_tag; 141462306a36Sopenharmony_ci } 141562306a36Sopenharmony_ci } 141662306a36Sopenharmony_ci if (con->v1.in_tag == CEPH_MSGR_TAG_MSG) { 141762306a36Sopenharmony_ci ret = read_partial_message(con); 141862306a36Sopenharmony_ci if (ret <= 0) { 141962306a36Sopenharmony_ci switch (ret) { 142062306a36Sopenharmony_ci case -EBADMSG: 142162306a36Sopenharmony_ci con->error_msg = "bad crc/signature"; 142262306a36Sopenharmony_ci fallthrough; 142362306a36Sopenharmony_ci case -EBADE: 142462306a36Sopenharmony_ci ret = -EIO; 142562306a36Sopenharmony_ci break; 142662306a36Sopenharmony_ci case -EIO: 142762306a36Sopenharmony_ci con->error_msg = "io error"; 142862306a36Sopenharmony_ci break; 142962306a36Sopenharmony_ci } 143062306a36Sopenharmony_ci goto out; 143162306a36Sopenharmony_ci } 143262306a36Sopenharmony_ci if (con->v1.in_tag == CEPH_MSGR_TAG_READY) 143362306a36Sopenharmony_ci goto more; 143462306a36Sopenharmony_ci ceph_con_process_message(con); 143562306a36Sopenharmony_ci if (con->state == CEPH_CON_S_OPEN) 143662306a36Sopenharmony_ci prepare_read_tag(con); 143762306a36Sopenharmony_ci goto more; 143862306a36Sopenharmony_ci } 143962306a36Sopenharmony_ci if (con->v1.in_tag == CEPH_MSGR_TAG_ACK || 144062306a36Sopenharmony_ci con->v1.in_tag == CEPH_MSGR_TAG_SEQ) { 144162306a36Sopenharmony_ci /* 144262306a36Sopenharmony_ci * the final handshake seq exchange is semantically 144362306a36Sopenharmony_ci * equivalent to an ACK 144462306a36Sopenharmony_ci */ 144562306a36Sopenharmony_ci ret = read_partial_ack(con); 144662306a36Sopenharmony_ci if (ret <= 0) 144762306a36Sopenharmony_ci goto out; 144862306a36Sopenharmony_ci process_ack(con); 144962306a36Sopenharmony_ci goto more; 145062306a36Sopenharmony_ci } 145162306a36Sopenharmony_ci if (con->v1.in_tag == CEPH_MSGR_TAG_KEEPALIVE2_ACK) { 145262306a36Sopenharmony_ci ret = read_keepalive_ack(con); 145362306a36Sopenharmony_ci if (ret <= 0) 145462306a36Sopenharmony_ci goto out; 145562306a36Sopenharmony_ci goto more; 145662306a36Sopenharmony_ci } 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ciout: 145962306a36Sopenharmony_ci dout("try_read done on %p ret %d\n", con, ret); 146062306a36Sopenharmony_ci return ret; 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_cibad_tag: 146362306a36Sopenharmony_ci pr_err("try_read bad tag %d\n", con->v1.in_tag); 146462306a36Sopenharmony_ci con->error_msg = "protocol error, garbage tag"; 146562306a36Sopenharmony_ci ret = -1; 146662306a36Sopenharmony_ci goto out; 146762306a36Sopenharmony_ci} 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci/* 147062306a36Sopenharmony_ci * Write something to the socket. Called in a worker thread when the 147162306a36Sopenharmony_ci * socket appears to be writeable and we have something ready to send. 147262306a36Sopenharmony_ci */ 147362306a36Sopenharmony_ciint ceph_con_v1_try_write(struct ceph_connection *con) 147462306a36Sopenharmony_ci{ 147562306a36Sopenharmony_ci int ret = 1; 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci dout("try_write start %p state %d\n", con, con->state); 147862306a36Sopenharmony_ci if (con->state != CEPH_CON_S_PREOPEN && 147962306a36Sopenharmony_ci con->state != CEPH_CON_S_V1_BANNER && 148062306a36Sopenharmony_ci con->state != CEPH_CON_S_V1_CONNECT_MSG && 148162306a36Sopenharmony_ci con->state != CEPH_CON_S_OPEN) 148262306a36Sopenharmony_ci return 0; 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci /* open the socket first? */ 148562306a36Sopenharmony_ci if (con->state == CEPH_CON_S_PREOPEN) { 148662306a36Sopenharmony_ci BUG_ON(con->sock); 148762306a36Sopenharmony_ci con->state = CEPH_CON_S_V1_BANNER; 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci con_out_kvec_reset(con); 149062306a36Sopenharmony_ci prepare_write_banner(con); 149162306a36Sopenharmony_ci prepare_read_banner(con); 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci BUG_ON(con->in_msg); 149462306a36Sopenharmony_ci con->v1.in_tag = CEPH_MSGR_TAG_READY; 149562306a36Sopenharmony_ci dout("try_write initiating connect on %p new state %d\n", 149662306a36Sopenharmony_ci con, con->state); 149762306a36Sopenharmony_ci ret = ceph_tcp_connect(con); 149862306a36Sopenharmony_ci if (ret < 0) { 149962306a36Sopenharmony_ci con->error_msg = "connect error"; 150062306a36Sopenharmony_ci goto out; 150162306a36Sopenharmony_ci } 150262306a36Sopenharmony_ci } 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_cimore: 150562306a36Sopenharmony_ci dout("try_write out_kvec_bytes %d\n", con->v1.out_kvec_bytes); 150662306a36Sopenharmony_ci BUG_ON(!con->sock); 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci /* kvec data queued? */ 150962306a36Sopenharmony_ci if (con->v1.out_kvec_left) { 151062306a36Sopenharmony_ci ret = write_partial_kvec(con); 151162306a36Sopenharmony_ci if (ret <= 0) 151262306a36Sopenharmony_ci goto out; 151362306a36Sopenharmony_ci } 151462306a36Sopenharmony_ci if (con->v1.out_skip) { 151562306a36Sopenharmony_ci ret = write_partial_skip(con); 151662306a36Sopenharmony_ci if (ret <= 0) 151762306a36Sopenharmony_ci goto out; 151862306a36Sopenharmony_ci } 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci /* msg pages? */ 152162306a36Sopenharmony_ci if (con->out_msg) { 152262306a36Sopenharmony_ci if (con->v1.out_msg_done) { 152362306a36Sopenharmony_ci ceph_msg_put(con->out_msg); 152462306a36Sopenharmony_ci con->out_msg = NULL; /* we're done with this one */ 152562306a36Sopenharmony_ci goto do_next; 152662306a36Sopenharmony_ci } 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci ret = write_partial_message_data(con); 152962306a36Sopenharmony_ci if (ret == 1) 153062306a36Sopenharmony_ci goto more; /* we need to send the footer, too! */ 153162306a36Sopenharmony_ci if (ret == 0) 153262306a36Sopenharmony_ci goto out; 153362306a36Sopenharmony_ci if (ret < 0) { 153462306a36Sopenharmony_ci dout("try_write write_partial_message_data err %d\n", 153562306a36Sopenharmony_ci ret); 153662306a36Sopenharmony_ci goto out; 153762306a36Sopenharmony_ci } 153862306a36Sopenharmony_ci } 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_cido_next: 154162306a36Sopenharmony_ci if (con->state == CEPH_CON_S_OPEN) { 154262306a36Sopenharmony_ci if (ceph_con_flag_test_and_clear(con, 154362306a36Sopenharmony_ci CEPH_CON_F_KEEPALIVE_PENDING)) { 154462306a36Sopenharmony_ci prepare_write_keepalive(con); 154562306a36Sopenharmony_ci goto more; 154662306a36Sopenharmony_ci } 154762306a36Sopenharmony_ci /* is anything else pending? */ 154862306a36Sopenharmony_ci if (!list_empty(&con->out_queue)) { 154962306a36Sopenharmony_ci prepare_write_message(con); 155062306a36Sopenharmony_ci goto more; 155162306a36Sopenharmony_ci } 155262306a36Sopenharmony_ci if (con->in_seq > con->in_seq_acked) { 155362306a36Sopenharmony_ci prepare_write_ack(con); 155462306a36Sopenharmony_ci goto more; 155562306a36Sopenharmony_ci } 155662306a36Sopenharmony_ci } 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci /* Nothing to do! */ 155962306a36Sopenharmony_ci ceph_con_flag_clear(con, CEPH_CON_F_WRITE_PENDING); 156062306a36Sopenharmony_ci dout("try_write nothing else to write.\n"); 156162306a36Sopenharmony_ci ret = 0; 156262306a36Sopenharmony_ciout: 156362306a36Sopenharmony_ci dout("try_write done on %p ret %d\n", con, ret); 156462306a36Sopenharmony_ci return ret; 156562306a36Sopenharmony_ci} 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_civoid ceph_con_v1_revoke(struct ceph_connection *con) 156862306a36Sopenharmony_ci{ 156962306a36Sopenharmony_ci struct ceph_msg *msg = con->out_msg; 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci WARN_ON(con->v1.out_skip); 157262306a36Sopenharmony_ci /* footer */ 157362306a36Sopenharmony_ci if (con->v1.out_msg_done) { 157462306a36Sopenharmony_ci con->v1.out_skip += con_out_kvec_skip(con); 157562306a36Sopenharmony_ci } else { 157662306a36Sopenharmony_ci WARN_ON(!msg->data_length); 157762306a36Sopenharmony_ci con->v1.out_skip += sizeof_footer(con); 157862306a36Sopenharmony_ci } 157962306a36Sopenharmony_ci /* data, middle, front */ 158062306a36Sopenharmony_ci if (msg->data_length) 158162306a36Sopenharmony_ci con->v1.out_skip += msg->cursor.total_resid; 158262306a36Sopenharmony_ci if (msg->middle) 158362306a36Sopenharmony_ci con->v1.out_skip += con_out_kvec_skip(con); 158462306a36Sopenharmony_ci con->v1.out_skip += con_out_kvec_skip(con); 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci dout("%s con %p out_kvec_bytes %d out_skip %d\n", __func__, con, 158762306a36Sopenharmony_ci con->v1.out_kvec_bytes, con->v1.out_skip); 158862306a36Sopenharmony_ci} 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_civoid ceph_con_v1_revoke_incoming(struct ceph_connection *con) 159162306a36Sopenharmony_ci{ 159262306a36Sopenharmony_ci unsigned int front_len = le32_to_cpu(con->v1.in_hdr.front_len); 159362306a36Sopenharmony_ci unsigned int middle_len = le32_to_cpu(con->v1.in_hdr.middle_len); 159462306a36Sopenharmony_ci unsigned int data_len = le32_to_cpu(con->v1.in_hdr.data_len); 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci /* skip rest of message */ 159762306a36Sopenharmony_ci con->v1.in_base_pos = con->v1.in_base_pos - 159862306a36Sopenharmony_ci sizeof(struct ceph_msg_header) - 159962306a36Sopenharmony_ci front_len - 160062306a36Sopenharmony_ci middle_len - 160162306a36Sopenharmony_ci data_len - 160262306a36Sopenharmony_ci sizeof(struct ceph_msg_footer); 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci con->v1.in_tag = CEPH_MSGR_TAG_READY; 160562306a36Sopenharmony_ci con->in_seq++; 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci dout("%s con %p in_base_pos %d\n", __func__, con, con->v1.in_base_pos); 160862306a36Sopenharmony_ci} 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_cibool ceph_con_v1_opened(struct ceph_connection *con) 161162306a36Sopenharmony_ci{ 161262306a36Sopenharmony_ci return con->v1.connect_seq; 161362306a36Sopenharmony_ci} 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_civoid ceph_con_v1_reset_session(struct ceph_connection *con) 161662306a36Sopenharmony_ci{ 161762306a36Sopenharmony_ci con->v1.connect_seq = 0; 161862306a36Sopenharmony_ci con->v1.peer_global_seq = 0; 161962306a36Sopenharmony_ci} 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_civoid ceph_con_v1_reset_protocol(struct ceph_connection *con) 162262306a36Sopenharmony_ci{ 162362306a36Sopenharmony_ci con->v1.out_skip = 0; 162462306a36Sopenharmony_ci} 1625