ceph: a few more messenger cleanups
cover ceph: a few more messenger cleanups
Here are a few more messenger cleanup patches.
[PATCH 1/6] libceph: encapsulate out message data setup [PATCH 2/6] libceph: encapsulate advancing msg page
These two encapsulate some code involved in sending message data into separate functions.
[PATCH 3/6] libceph: don't mark footer complete before it is
This moves the setting of the "FOOTER_COMPLETE" flag so that it doesn't get done until the footer really is complete.
[PATCH 4/6] libceph: move init_bio_*() functions up
This simply moves two functions, preparing for the next patch.
[PATCH 5/6] libceph: move init of bio_iter
This makes a message's bio_iter field get initialized when the rest of the message is initialized, rather than conditionally every time any attempt is made to send message data.
[PATCH 6/6] libceph: don't use bio_iter as a flag
Because bio_iter is now initialized in the "right" place we no longer need to use its value as a flag to determine whether it needs initialization.
-Alex
PATCH 1/6 libceph: encapsulate out message data setup
Move the code that prepares to write the data portion of a message into its own function.
--- net/ceph/messenger.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-)
net/ceph/messenger.c +22 -14
@@ -590,6 +590,23 @@ static void con_out_kvec_add(struct ceph con->out_kvec_bytes += size; } +static void prepare_write_message_data (struct ceph_connection *con) +{ +struct ceph_msg *msg = con->out_msg; + +BUG_ON (!msg); +BUG_ON (!msg->hdr.data_len); + +/* initialize page iterator */ +if (msg->pages) + con->out_msg_pos.page_pos = msg->page_alignment; +else + con->out_msg_pos.page_pos =0 ; + con->out_msg_pos.data_pos =0 ; + con->out_msg_pos.did_page_crc = false; + con->out_more =1 ;/* data + footer will follow */ +} +/* * Prepare footer for currently outgoing message, and finish things * off. Assumes out_kvec* are already valid.. we just add on to the end.
@@ -682,26 +699,17 @@ static void prepare_write_message(struct con->out_msg->footer.middle_crc =cpu_to_le32 (crc); }else con->out_msg->footer.middle_crc =0 ; - con->out_msg->footer.data_crc =0 ; -dout ("prepare_write_message front_crc %u data_crc %u\n" , +dout ("%s front_crc %u middle_crc %u\n" , __func__,le32_to_cpu (con->out_msg->footer.front_crc),le32_to_cpu (con->out_msg->footer.middle_crc));/* is there a data payload? */ -if (le32_to_cpu (m->hdr.data_len) >0 ) { -/* initialize page iterator */ - con->out_msg_pos.page =0 ; -if (m->pages) - con->out_msg_pos.page_pos = m->page_alignment; -else - con->out_msg_pos.page_pos =0 ; - con->out_msg_pos.data_pos =0 ; - con->out_msg_pos.did_page_crc = false; - con->out_more =1 ;/* data + footer will follow */ - }else { + con->out_msg->footer.data_crc =0 ; +if (m->hdr.data_len) +prepare_write_message_data (con); +else /* no, queue up footer too and be done */ prepare_write_message_footer (con); - }set_bit (WRITE_PENDING , &con->flags); }
PATCH 2/6 libceph: encapsulate advancing msg page
In reply to Alex ElderIn write_partial_msg_pages(), once all the data from a page has been sent we advance to the next one. Put the code that takes care of this into its own function.
While modifying write_partial_msg_pages(), make its local variable "in_trail" be Boolean, and use the local variable "msg" (which is just the connection's current out_msg pointer) consistently.
--- net/ceph/messenger.c | 58 +++++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 24 deletions(-)
net/ceph/messenger.c +1 -0
@@ -915,6 +915,33 @@ static void iter_bio_next(struct bio **b }#endif +static void out_msg_pos_next(struct ceph_connection *con, struct page
*page,
+ size_t len, size_t sent, bool in_trail)
+{
+ struct ceph_msg *msg = con->out_msg;
+
+ BUG_ON(!msg);
+ BUG_ON(!sent);
+
+ con->out_msg_pos.data_pos += sent;
+ con->out_msg_pos.page_pos += sent;
+ if (sent == len) {
+ con->out_msg_pos.page_pos = 0;
+ con->out_msg_pos.page++;
+ con->out_msg_pos.did_page_crc = false;
+ if (in_trail)
+ list_move_tail(&page->lru,
+ &msg->trail->head);
+ else if (msg->pagelist)
+ list_move_tail(&page->lru,
+ &msg->pagelist->head);
+#ifdef CONFIG_BLOCK
+ else if (msg->bio)
+ iter_bio_next(&msg->bio_iter, &msg->bio_seg);
+#endif
+ }
+}
+
/*
* Write as much message data payload as we can. If we finish, queue
* up the footer.
@@ -930,11 +957,11 @@ static int write_partial_msg_pages(struc
bool do_datacrc = !con->msgr->nocrc;
int ret;
int total_max_write;
- int in_trail = 0;
+ bool in_trail = false;
size_t trail_len = (msg->trail ? msg->trail->length : 0);
dout("write_partial_msg_pages %p msg %p page %d/%d offset %d\n",
- con, con->out_msg, con->out_msg_pos.page, con->out_msg->nr_pages,
+ con, msg, con->out_msg_pos.page, msg->nr_pages,
con->out_msg_pos.page_pos);
#ifdef CONFIG_BLOCK
@@ -958,13 +985,12 @@ static int write_partial_msg_pages(struc
/* have we reached the trail part of the data? */ if (con->out_msg_pos.data_pos >= data_len - trail_len) {
- in_trail = 1;
+ in_trail = true;
total_max_write = data_len - con->out_msg_pos.data_pos;
page = list_first_entry(&msg->trail->head,
struct page, lru);
- max_write = PAGE_SIZE;
} else if (msg->pages) {
page = msg->pages[con->out_msg_pos.page];
} else if (msg->pagelist) {
@@ -988,14 +1014,14 @@ static int write_partial_msg_pages(struc
if (do_datacrc && !con->out_msg_pos.did_page_crc) {
void *base;
u32 crc;
- u32 tmpcrc = le32_to_cpu(con->out_msg->footer.data_crc);
+ u32 tmpcrc = le32_to_cpu(msg->footer.data_crc);
char *kaddr;
kaddr = kmap(page);
BUG_ON(kaddr == NULL);
base = kaddr + con->out_msg_pos.page_pos + bio_offset; crc = crc32c(tmpcrc, base, len);
- con->out_msg->footer.data_crc = cpu_to_le32(crc);
+ msg->footer.data_crc = cpu_to_le32(crc);
con->out_msg_pos.did_page_crc = true;
}
ret = ceph_tcp_sendpage(con->sock, page,
@@ -1008,30 +1034,14 @@ static int write_partial_msg_pages(struc
if (ret <= 0)
goto out;
- con->out_msg_pos.data_pos += ret;
- con->out_msg_pos.page_pos += ret;
- if (ret == len) {
- con->out_msg_pos.page_pos = 0;
- con->out_msg_pos.page++;
- con->out_msg_pos.did_page_crc = false;
- if (in_trail)
- list_move_tail(&page->lru,
- &msg->trail->head);
- else if (msg->pagelist)
- list_move_tail(&page->lru,
- &msg->pagelist->head);
-#ifdef CONFIG_BLOCK
- else if (msg->bio)
- iter_bio_next(&msg->bio_iter, &msg->bio_seg);
-#endif
- }
+ out_msg_pos_next(con, page, len, (size_t) ret, in_trail);
}
dout("write_partial_msg_pages %p msg %p done\n", con, msg);
/* prepare and queue up footer, too */
if (!do_datacrc)
- con->out_msg->footer.flags |= CEPH_MSG_FOOTER_NOCRC;
+ msg->footer.flags |= CEPH_MSG_FOOTER_NOCRC;
con_out_kvec_reset(con);
prepare_write_message_footer(con);
ret = 1;
PATCH 3/6 libceph: don't mark footer complete before it is
In reply to Alex ElderThis is a nit, but prepare_write_message() sets the FOOTER_COMPLETE flag before the CRC for the data portion (recorded in the footer) has been completely computed. Hold off setting the complete flag until we've decided it's ready to send.
--- net/ceph/messenger.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/ceph/messenger.c +3 -1
@@ -616,6 +616,8 @@ static void prepare_write_message_footerstruct ceph_msg *m = con->out_msg;int v = con->out_kvec_left; + m->footer.flags |=CEPH_MSG_FOOTER_COMPLETE ; +dout ("prepare_write_message_footer %p\n" , con); con->out_kvec_is_msg = true; con->out_kvec[v].iov_base = &m->footer;
@@ -689,7 +691,7 @@ static void prepare_write_message(struct/* fill in crc (except data pages), footer */ crc =crc32c (0 , &m->hdr, offsetof(struct ceph_msg_header , crc)); con->out_msg->hdr.crc =cpu_to_le32 (crc); - con->out_msg->footer.flags =CEPH_MSG_FOOTER_COMPLETE ; + con->out_msg->footer.flags =0 ; crc =crc32c (0 , m->front.iov_base, m->front.iov_len); con->out_msg->footer.front_crc =cpu_to_le32 (crc);
PATCH 4/6 libceph: move init_bio_*() functions up
In reply to Alex ElderMove init_bio_iter() and iter_bio_next() up in their source file so the'll be defined before they're needed.
--- net/ceph/messenger.c | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-)
net/ceph/messenger.c +25 -25
@@ -590,6 +590,31 @@ static void con_out_kvec_add(struct ceph con->out_kvec_bytes += size; } +#ifdef CONFIG_BLOCK +static void init_bio_iter (struct bio *bio,struct bio **iter,int *seg) +{ +if (!bio) { + *iter =NULL ; + *seg =0 ; +return ; + } + *iter = bio; + *seg = bio->bi_idx; +} + +static void iter_bio_next (struct bio **bio_iter,int *seg) +{ +if (*bio_iter ==NULL ) +return ; + +BUG_ON (*seg >= (*bio_iter)->bi_vcnt); + + (*seg)++; +if (*seg == (*bio_iter)->bi_vcnt) +init_bio_iter ((*bio_iter)->bi_next, bio_iter, seg); +} +#endif +static void prepare_write_message_data (struct ceph_connection *con) {struct ceph_msg *msg = con->out_msg;
@@ -892,31 +917,6 @@ out:return ret;/* done! */ } -#ifdef CONFIG_BLOCK -static void init_bio_iter (struct bio *bio,struct bio **iter,int *seg) -{ -if (!bio) { - *iter =NULL ; - *seg =0 ; -return ; - } - *iter = bio; - *seg = bio->bi_idx; -} - -static void iter_bio_next (struct bio **bio_iter,int *seg) -{ -if (*bio_iter ==NULL ) -return ; - -BUG_ON (*seg >= (*bio_iter)->bi_vcnt); - - (*seg)++; -if (*seg == (*bio_iter)->bi_vcnt) -init_bio_iter ((*bio_iter)->bi_next, bio_iter, seg); -} -#endif - static void out_msg_pos_next(struct ceph_connection *con, struct page
*page,
size_t len, size_t sent, bool in_trail)
{
PATCH 5/6 libceph: move init of bio_iter
In reply to Alex ElderIf a message has a non-null bio pointer, its bio_iter field is initialized in write_partial_msg_pages() if this has not been done already. This is really a one-time setup operation for sending a message's (bio) data, so move that initialization code into prepare_write_message_data() which serves that purpose.
--- net/ceph/messenger.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
net/ceph/messenger.c +4 -5
@@ -627,6 +627,10 @@ static void prepare_write_message_data(s con->out_msg_pos.page_pos = msg->page_alignment; else con->out_msg_pos.page_pos = 0; +#ifdef CONFIG_BLOCK +if (msg->bio && !msg->bio_iter) +init_bio_iter (msg->bio, &msg->bio_iter, &msg->bio_seg); +#endif con->out_msg_pos.data_pos =0 ; con->out_msg_pos.did_page_crc = false; con->out_more =1 ;/* data + footer will follow */
@@ -966,11 +970,6 @@ static int write_partial_msg_pages(struc con, msg, con->out_msg_pos.page, msg->nr_pages, con->out_msg_pos.page_pos); -#ifdef CONFIG_BLOCK -if (msg->bio && !msg->bio_iter) -init_bio_iter (msg->bio, &msg->bio_iter, &msg->bio_seg); -#endif -while (data_len > con->out_msg_pos.data_pos) {struct page *page =NULL ;int max_write =PAGE_SIZE ;
PATCH 6/6 libceph: don't use bio_iter as a flag
In reply to Alex ElderRecently a bug was fixed in which the bio_iter field in a ceph message was not being properly re-initialized when a message got re-transmitted:
commit 43643528cce60ca184fe8197efa8e8da7c89a037
Author: Yan, Zheng <[email protected]>
rbd: Clear ceph_msg->bio_iter for retransmitted messageWe are now only initializing the bio_iter field when we are about to start to write message data (in prepare_write_message_data()), rather than every time we are attempting to write any portion of the message data (in write_partial_msg_pages()). This means we no longer need to use the msg->bio_iter field as a flag.
So just don't do that any more. Trust prepare_write_message_data() to ensure msg->bio_iter is properly initialized, every time we are about to begin writing (or re-writing) a message's bio data.
--- net/ceph/messenger.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
net/ceph/messenger.c +1 -5
@@ -628,7 +628,7 @@ static void prepare_write_message_data(selse con->out_msg_pos.page_pos =0 ;#ifdef CONFIG_BLOCK -if (msg->bio && !msg->bio_iter) +if (msg->bio)init_bio_iter (msg->bio, &msg->bio_iter, &msg->bio_seg);#endif con->out_msg_pos.data_pos =0 ;
@@ -696,10 +696,6 @@ static void prepare_write_message(struct m->hdr.seq =cpu_to_le64 (++con->out_seq); m->needs_out_seq = false; } -#ifdef CONFIG_BLOCK - else - m->bio_iter = NULL; -#endif dout("prepare_write_message %p seq %lld type %d len %d+%d+%d %d pgs\n", m, con->out_seq, le16_to_cpu(m->hdr.type),