* [PATCH] rbd: Clear ceph_msg->bio_iter for retransmitted message
@ 2012-06-06 8:03 Yan, Zheng
2012-06-06 14:10 ` Alex Elder
2012-06-06 22:10 ` Alex Elder
0 siblings, 2 replies; 7+ messages in thread
From: Yan, Zheng @ 2012-06-06 8:03 UTC (permalink / raw)
To: ceph-devel
From: "Yan, Zheng" <zheng.z.yan@intel.com>
The bug can cause NULL pointer dereference in write_partial_msg_pages
Signed-off-by: Zheng Yan <zheng.z.yan@intel.com>
---
net/ceph/messenger.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
index 1a80907..785b953 100644
--- a/net/ceph/messenger.c
+++ b/net/ceph/messenger.c
@@ -598,6 +598,7 @@ static void prepare_write_message(struct ceph_connection *con)
le32_to_cpu(con->out_msg->footer.front_crc),
le32_to_cpu(con->out_msg->footer.middle_crc));
+ m->bio_iter = NULL;
/* is there a data payload? */
if (le32_to_cpu(m->hdr.data_len) > 0) {
/* initialize page iterator */
--
1.7.7.6
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH] rbd: Clear ceph_msg->bio_iter for retransmitted message
2012-06-06 8:03 [PATCH] rbd: Clear ceph_msg->bio_iter for retransmitted message Yan, Zheng
@ 2012-06-06 14:10 ` Alex Elder
2012-06-08 6:17 ` Hannes Reinecke
2012-06-06 22:10 ` Alex Elder
1 sibling, 1 reply; 7+ messages in thread
From: Alex Elder @ 2012-06-06 14:10 UTC (permalink / raw)
To: Yan, Zheng; +Cc: ceph-devel
On 06/06/2012 03:03 AM, Yan, Zheng wrote:
> From: "Yan, Zheng" <zheng.z.yan@intel.com>
>
> The bug can cause NULL pointer dereference in write_partial_msg_pages
Although this looks simple enough, I want to study it a little more
before committing it. I've been wanting to walk through this bit
of code anyway so I'll do that today.
One quick observation though: m->bio_iter really ought to be
initialized only within #ifdef CONFIG_BLOCK (although I see it's
defined without it in the structure definition). At some point
I'll put together a cleanup patch to do that everywhere; feel free
to do that yourself if you are so inclined.
-Alex
> Signed-off-by: Zheng Yan <zheng.z.yan@intel.com>
> ---
> net/ceph/messenger.c | 1 +
> 1 files changed, 1 insertions(+), 0 deletions(-)
>
> diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
> index 1a80907..785b953 100644
> --- a/net/ceph/messenger.c
> +++ b/net/ceph/messenger.c
> @@ -598,6 +598,7 @@ static void prepare_write_message(struct ceph_connection *con)
> le32_to_cpu(con->out_msg->footer.front_crc),
> le32_to_cpu(con->out_msg->footer.middle_crc));
>
> + m->bio_iter = NULL;
> /* is there a data payload? */
> if (le32_to_cpu(m->hdr.data_len) > 0) {
> /* initialize page iterator */
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] rbd: Clear ceph_msg->bio_iter for retransmitted message
2012-06-06 8:03 [PATCH] rbd: Clear ceph_msg->bio_iter for retransmitted message Yan, Zheng
2012-06-06 14:10 ` Alex Elder
@ 2012-06-06 22:10 ` Alex Elder
2012-06-06 22:35 ` Yan, Zheng
1 sibling, 1 reply; 7+ messages in thread
From: Alex Elder @ 2012-06-06 22:10 UTC (permalink / raw)
To: Yan, Zheng; +Cc: ceph-devel
On 06/06/2012 03:03 AM, Yan, Zheng wrote:
> From: "Yan, Zheng" <zheng.z.yan@intel.com>
>
> The bug can cause NULL pointer dereference in write_partial_msg_pages
>
> Signed-off-by: Zheng Yan <zheng.z.yan@intel.com>
> ---
> net/ceph/messenger.c | 1 +
> 1 files changed, 1 insertions(+), 0 deletions(-)
>
> diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
> index 1a80907..785b953 100644
> --- a/net/ceph/messenger.c
> +++ b/net/ceph/messenger.c
> @@ -598,6 +598,7 @@ static void prepare_write_message(struct ceph_connection *con)
> le32_to_cpu(con->out_msg->footer.front_crc),
> le32_to_cpu(con->out_msg->footer.middle_crc));
>
> + m->bio_iter = NULL;
> /* is there a data payload? */
> if (le32_to_cpu(m->hdr.data_len) > 0) {
> /* initialize page iterator */
OK, now that I've looked at this a little bit I think I have a small
preference for doing this assignment earlier in that function, where
there is already special handling that is dependent on whether the
message being processed is being re-sent or not:
/*
* only assign outgoing seq # if we haven't sent this message
* yet. if it is requeued, resend with it's original seq.
*/
if (m->needs_out_seq) {
m->hdr.seq = cpu_to_le64(++con->out_seq);
m->needs_out_seq = false;
}
So I'd suggest it look like:
/*
* only assign outgoing seq # if we haven't sent this message
* yet. if it is requeued, resend with it's original seq.
*/
if (m->needs_out_seq) {
m->hdr.seq = cpu_to_le64(++con->out_seq);
m->needs_out_seq = false;
}
#ifdef CONFIG_BLOCK
else {
/* Need to reinitialize the iterator on resends */
m->bio_iter = NULL;
}
#endif
Please let me know if you concur with my proposed modification or
whether you feel strongly we should go with your original fix.
In any case, I think your fix looks like the right thing to do.
Reviewed-by: Alex Elder <elder@inktank.com>
Now let me know if you see anything wrong in the following explanation
of the problem.
The first time a message is sent, it will have been allocated via
ceph_msg_new(), which will initialize both the bio and bio_iter
fields to NULL (and bio_seg to 0).
rbd is an osd client. It sets up its request queue with
request_queue->request_fn = rbd_rq_fn()
So here's the path that leads to a bio in a message:
rbd_rq_fn()
->rbd_req_{read,write}()
->rbd_do_op()
->rbd_do_request()
->ceph_osdc_alloc_request()
And rbd_osdc_alloc_request() assigns the passed-in bio to req->r_bio
and grabs a reference to it.
Later, ceph_osdc_start_request() will copy the osd request's r_bio
pointer value into the request message that will be sent to the osd
server. It does not update either of the other two bio-related fields
in that message--in particular, bio_iter is still NULL.
Then, in write_partial_msg_pages(), this code uses the null bio_iter
as an indicator that we're just starting with processing the message
that is currently referred to in con->out_msg, and initializes the
iteration fields.
#ifdef CONFIG_BLOCK
if (msg->bio && !msg->bio_iter)
init_bio_iter(msg->bio, &msg->bio_iter, &msg->bio_seg);
#endif
So...
In order for this to work properly, msg->bio_iter needs to be
a null pointer when we're first processing a message in
write_partial_msg_pages(). And that's fine the first time through,
but if a connection failure occurs in the middle of processing
a bio request, and ceph_fault() gets called, all sent messages get
re-queued to be re-sent, and at that point, msg->bio_iter is not
guaranteed to be a null pointer.
(I worked through describing all this because in doing so I can
convince myself I understand the problem enough to know this is
the right fix.)
-Alex
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] rbd: Clear ceph_msg->bio_iter for retransmitted message
2012-06-06 22:10 ` Alex Elder
@ 2012-06-06 22:35 ` Yan, Zheng
0 siblings, 0 replies; 7+ messages in thread
From: Yan, Zheng @ 2012-06-06 22:35 UTC (permalink / raw)
To: elder; +Cc: Yan, Zheng, ceph-devel
On Thu, Jun 7, 2012 at 6:10 AM, Alex Elder <elder@dreamhost.com> wrote:
> On 06/06/2012 03:03 AM, Yan, Zheng wrote:
>> From: "Yan, Zheng" <zheng.z.yan@intel.com>
>>
>> The bug can cause NULL pointer dereference in write_partial_msg_pages
>>
>> Signed-off-by: Zheng Yan <zheng.z.yan@intel.com>
>> ---
>> net/ceph/messenger.c | 1 +
>> 1 files changed, 1 insertions(+), 0 deletions(-)
>>
>> diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
>> index 1a80907..785b953 100644
>> --- a/net/ceph/messenger.c
>> +++ b/net/ceph/messenger.c
>> @@ -598,6 +598,7 @@ static void prepare_write_message(struct ceph_connection *con)
>> le32_to_cpu(con->out_msg->footer.front_crc),
>> le32_to_cpu(con->out_msg->footer.middle_crc));
>>
>> + m->bio_iter = NULL;
>> /* is there a data payload? */
>> if (le32_to_cpu(m->hdr.data_len) > 0) {
>> /* initialize page iterator */
>
> OK, now that I've looked at this a little bit I think I have a small
> preference for doing this assignment earlier in that function, where
> there is already special handling that is dependent on whether the
> message being processed is being re-sent or not:
>
> /*
> * only assign outgoing seq # if we haven't sent this message
> * yet. if it is requeued, resend with it's original seq.
> */
> if (m->needs_out_seq) {
> m->hdr.seq = cpu_to_le64(++con->out_seq);
> m->needs_out_seq = false;
> }
>
> So I'd suggest it look like:
>
> /*
> * only assign outgoing seq # if we haven't sent this message
> * yet. if it is requeued, resend with it's original seq.
> */
> if (m->needs_out_seq) {
> m->hdr.seq = cpu_to_le64(++con->out_seq);
> m->needs_out_seq = false;
> }
> #ifdef CONFIG_BLOCK
> else {
> /* Need to reinitialize the iterator on resends */
> m->bio_iter = NULL;
> }
> #endif
>
> Please let me know if you concur with my proposed modification or
> whether you feel strongly we should go with your original fix.
>
I'm OK with it.
Thanks
Yan, Zheng
--
To unsubscribe from this list: send the line "unsubscribe ceph-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] rbd: Clear ceph_msg->bio_iter for retransmitted message
2012-06-06 14:10 ` Alex Elder
@ 2012-06-08 6:17 ` Hannes Reinecke
2012-06-08 6:32 ` Yan, Zheng
2012-06-11 15:48 ` Alex Elder
0 siblings, 2 replies; 7+ messages in thread
From: Hannes Reinecke @ 2012-06-08 6:17 UTC (permalink / raw)
To: elder; +Cc: Alex Elder, Yan, Zheng, ceph-devel
On 06/06/2012 04:10 PM, Alex Elder wrote:
> On 06/06/2012 03:03 AM, Yan, Zheng wrote:
>> From: "Yan, Zheng" <zheng.z.yan@intel.com>
>>
>> The bug can cause NULL pointer dereference in write_partial_msg_pages
>
> Although this looks simple enough, I want to study it a little more
> before committing it. I've been wanting to walk through this bit
> of code anyway so I'll do that today.
>
> One quick observation though: m->bio_iter really ought to be
> initialized only within #ifdef CONFIG_BLOCK (although I see it's
> defined without it in the structure definition). At some point
> I'll put together a cleanup patch to do that everywhere; feel free
> to do that yourself if you are so inclined.
>
> -Alex
>
>> Signed-off-by: Zheng Yan <zheng.z.yan@intel.com>
>> ---
>> net/ceph/messenger.c | 1 +
>> 1 files changed, 1 insertions(+), 0 deletions(-)
>>
>> diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
>> index 1a80907..785b953 100644
>> --- a/net/ceph/messenger.c
>> +++ b/net/ceph/messenger.c
>> @@ -598,6 +598,7 @@ static void prepare_write_message(struct ceph_connection *con)
>> le32_to_cpu(con->out_msg->footer.front_crc),
>> le32_to_cpu(con->out_msg->footer.middle_crc));
>>
>> + m->bio_iter = NULL;
>> /* is there a data payload? */
>> if (le32_to_cpu(m->hdr.data_len) > 0) {
>> /* initialize page iterator */
>
Incidentally, we've come across the same issue. First thing which
struck me was this:
diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
index 524f4e4..759d4d2 100644
--- a/net/ceph/messenger.c
+++ b/net/ceph/messenger.c
@@ -874,7 +874,7 @@ static int write_partial_msg_pages(struct
ceph_connection *c
on)
page = list_first_entry(&msg->pagelist->head,
struct page, lru);
#ifdef CONFIG_BLOCK
- } else if (msg->bio) {
+ } else if (msg->bio_iter) {
struct bio_vec *bv;
bv = bio_iovec_idx(msg->bio_iter, msg->bio_seg);
We've called bio_list_init() a few lines above; however, it might
return with a NULL bio_iter. So for consistency we should be
checking for ->bio_iter here, as this is what we'll be using
afterwards anyway.
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe ceph-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH] rbd: Clear ceph_msg->bio_iter for retransmitted message
2012-06-08 6:17 ` Hannes Reinecke
@ 2012-06-08 6:32 ` Yan, Zheng
2012-06-11 15:48 ` Alex Elder
1 sibling, 0 replies; 7+ messages in thread
From: Yan, Zheng @ 2012-06-08 6:32 UTC (permalink / raw)
To: Hannes Reinecke; +Cc: elder, Alex Elder, ceph-devel
On 06/08/2012 02:17 PM, Hannes Reinecke wrote:
> On 06/06/2012 04:10 PM, Alex Elder wrote:
>> On 06/06/2012 03:03 AM, Yan, Zheng wrote:
>>> From: "Yan, Zheng" <zheng.z.yan@intel.com>
>>>
>>> The bug can cause NULL pointer dereference in write_partial_msg_pages
>>
>> Although this looks simple enough, I want to study it a little more
>> before committing it. I've been wanting to walk through this bit
>> of code anyway so I'll do that today.
>>
>> One quick observation though: m->bio_iter really ought to be
>> initialized only within #ifdef CONFIG_BLOCK (although I see it's
>> defined without it in the structure definition). At some point
>> I'll put together a cleanup patch to do that everywhere; feel free
>> to do that yourself if you are so inclined.
>>
>> -Alex
>>
>>> Signed-off-by: Zheng Yan <zheng.z.yan@intel.com>
>>> ---
>>> net/ceph/messenger.c | 1 +
>>> 1 files changed, 1 insertions(+), 0 deletions(-)
>>>
>>> diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
>>> index 1a80907..785b953 100644
>>> --- a/net/ceph/messenger.c
>>> +++ b/net/ceph/messenger.c
>>> @@ -598,6 +598,7 @@ static void prepare_write_message(struct ceph_connection *con)
>>> le32_to_cpu(con->out_msg->footer.front_crc),
>>> le32_to_cpu(con->out_msg->footer.middle_crc));
>>>
>>> + m->bio_iter = NULL;
>>> /* is there a data payload? */
>>> if (le32_to_cpu(m->hdr.data_len) > 0) {
>>> /* initialize page iterator */
>>
> Incidentally, we've come across the same issue. First thing which
> struck me was this:
>
> diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
> index 524f4e4..759d4d2 100644
> --- a/net/ceph/messenger.c
> +++ b/net/ceph/messenger.c
> @@ -874,7 +874,7 @@ static int write_partial_msg_pages(struct
> ceph_connection *c
> on)
> page = list_first_entry(&msg->pagelist->head,
> struct page, lru);
> #ifdef CONFIG_BLOCK
> - } else if (msg->bio) {
> + } else if (msg->bio_iter) {
> struct bio_vec *bv;
>
> bv = bio_iovec_idx(msg->bio_iter, msg->bio_seg);
>
> We've called bio_list_init() a few lines above; however, it might
> return with a NULL bio_iter. So for consistency we should be
> checking for ->bio_iter here, as this is what we'll be using
> afterwards anyway.
>
Only when msg->bio is NULL, bio_list_init() can return with a NULL bio_iter.
So I think this change is not necessary.
Regards
Yan, Zheng
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] rbd: Clear ceph_msg->bio_iter for retransmitted message
2012-06-08 6:17 ` Hannes Reinecke
2012-06-08 6:32 ` Yan, Zheng
@ 2012-06-11 15:48 ` Alex Elder
1 sibling, 0 replies; 7+ messages in thread
From: Alex Elder @ 2012-06-11 15:48 UTC (permalink / raw)
To: Hannes Reinecke; +Cc: elder, Yan, Zheng, ceph-devel
On 06/08/2012 01:17 AM, Hannes Reinecke wrote:
> On 06/06/2012 04:10 PM, Alex Elder wrote:
>> On 06/06/2012 03:03 AM, Yan, Zheng wrote:
>>> From: "Yan, Zheng" <zheng.z.yan@intel.com>
>>>
>>> The bug can cause NULL pointer dereference in write_partial_msg_pages
>>
>> Although this looks simple enough, I want to study it a little more
>> before committing it. I've been wanting to walk through this bit
>> of code anyway so I'll do that today.
>>
>> One quick observation though: m->bio_iter really ought to be
>> initialized only within #ifdef CONFIG_BLOCK (although I see it's
>> defined without it in the structure definition). At some point
>> I'll put together a cleanup patch to do that everywhere; feel free
>> to do that yourself if you are so inclined.
>>
>> -Alex
>>
>>> Signed-off-by: Zheng Yan <zheng.z.yan@intel.com>
>>> ---
>>> net/ceph/messenger.c | 1 +
>>> 1 files changed, 1 insertions(+), 0 deletions(-)
>>>
>>> diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
>>> index 1a80907..785b953 100644
>>> --- a/net/ceph/messenger.c
>>> +++ b/net/ceph/messenger.c
>>> @@ -598,6 +598,7 @@ static void prepare_write_message(struct ceph_connection *con)
>>> le32_to_cpu(con->out_msg->footer.front_crc),
>>> le32_to_cpu(con->out_msg->footer.middle_crc));
>>>
>>> + m->bio_iter = NULL;
>>> /* is there a data payload? */
>>> if (le32_to_cpu(m->hdr.data_len) > 0) {
>>> /* initialize page iterator */
>>
> Incidentally, we've come across the same issue. First thing which
> struck me was this:
>
> diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
> index 524f4e4..759d4d2 100644
> --- a/net/ceph/messenger.c
> +++ b/net/ceph/messenger.c
> @@ -874,7 +874,7 @@ static int write_partial_msg_pages(struct
> ceph_connection *c
> on)
> page = list_first_entry(&msg->pagelist->head,
> struct page, lru);
> #ifdef CONFIG_BLOCK
> - } else if (msg->bio) {
> + } else if (msg->bio_iter) {
> struct bio_vec *bv;
>
> bv = bio_iovec_idx(msg->bio_iter, msg->bio_seg);
>
> We've called bio_list_init() a few lines above; however, it might
> return with a NULL bio_iter. So for consistency we should be
> checking for ->bio_iter here, as this is what we'll be using
> afterwards anyway.
Zheng is right, the only way bio_iter will be null following the
call to init_bio_iter() is if bio is also null, so it's roughly
equivalent either way. I do think it would be reassuring to have
the check be against bio_iter as you suggest in this case, since
that's the pointer we're then dereferencing.
I'm reworking this code today, and will update it to check the
bio_iter pointer instead if this suggestion still applies.
-Alex
> Cheers,
>
> Hannes
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2012-06-11 15:48 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-06-06 8:03 [PATCH] rbd: Clear ceph_msg->bio_iter for retransmitted message Yan, Zheng
2012-06-06 14:10 ` Alex Elder
2012-06-08 6:17 ` Hannes Reinecke
2012-06-08 6:32 ` Yan, Zheng
2012-06-11 15:48 ` Alex Elder
2012-06-06 22:10 ` Alex Elder
2012-06-06 22:35 ` Yan, Zheng
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.