All of lore.kernel.org
 help / color / mirror / Atom feed
* [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.