All of lore.kernel.org
 help / color / mirror / Atom feed
From: Liu Bo <bo.li.liu@oracle.com>
To: Omar Sandoval <osandov@osandov.com>
Cc: Chris Mason <clm@fb.com>,
	linux-btrfs@vger.kernel.org, Christoph Hellwig <hch@lst.de>,
	Pat Erley <pat-lkml@erley.org>,
	kernel-team@fb.com
Subject: Re: [PATCH] Btrfs: fix btrfs_decompress_buf2page()
Date: Fri, 10 Feb 2017 14:57:52 -0800	[thread overview]
Message-ID: <20170210225752.GC30334@localhost.localdomain> (raw)
In-Reply-To: <20170210225211.GA20287@vader.DHCP.thefacebook.com>

On Fri, Feb 10, 2017 at 02:52:11PM -0800, Omar Sandoval wrote:
> On Fri, Feb 10, 2017 at 02:46:09PM -0800, Liu Bo wrote:
> > On Fri, Feb 10, 2017 at 12:15:11PM -0800, Omar Sandoval wrote:
> > > From: Omar Sandoval <osandov@fb.com>
> > > 
> > > If btrfs_decompress_buf2page() is handed a bio with its page in the
> > > middle of the working buffer, then we adjust the offset into the working
> > > buffer. After we copy into the bio, we advance the iterator by the
> > > number of bytes we copied. Then, we have some logic to handle the case
> > > of discontiguous pages and adjust the offset into the working buffer
> > > again. However, if we didn't advance the bio to a new page, we may enter
> > > this case in error, essentially repeating the adjustment that we already
> > > made when we entered the function. The end result is bogus data in the
> > > bio.
> > > 
> > > Previously, we only checked for this case when we advanced to a new
> > > page, but the conversion to bio iterators changed that. This restores
> > > the old, correct behavior.
> > 
> > The fix looks good to me, just one comment below.
> > 
> > > 
> > > Fixes: 974b1adc3b10 ("btrfs: use bio iterators for the decompression handlers")
> > > Reported-by: Pat Erley <pat-lkml@erley.org>
> > > Signed-off-by: Omar Sandoval <osandov@fb.com>
> > > ---
> > > A case I saw when testing with zlib was:
> > > 
> > >     buf_start = 42769
> > >     total_out = 46865
> > >     working_bytes = total_out - buf_start = 4096
> > >     start_byte = 45056
> > > 
> > > 
> > > The condition (total_out > start_byte && buf_start < start_byte) is
> > > true, so we adjust the offset:
> > > 
> > >     buf_offset = start_byte - buf_start = 2287
> > >     working_bytes -= buf_offset = 1809
> > >     current_buf_start = buf_start = 42769
> > > 
> > > Then, we copy
> > > 
> > >     bytes = min(bvec.bv_len, PAGE_SIZE - buf_offset, working_bytes) = 1809
> > >     buf_offset += bytes = 4096
> > >     working_bytes -= bytes = 0
> > >     current_buf_start += bytes = 44578
> > > 
> > > After bio_advance(), we are still in the same page, so start_byte is the
> > > same. Then, we check (total_out > start_byte && current_buf_start < start_byte),
> > > which is true! So, we adjust the values again:
> > > 
> > >     buf_offset = start_byte - buf_start = 2287
> > >     working_bytes = total_out - start_byte = 1809
> > >     current_buf_start = buf_start + buf_offset = 45056
> > > 
> > > But note that working_bytes was already zero before this, so we should
> > > have stopped copying.
> > > 
> > >  fs/btrfs/compression.c | 36 +++++++++++++++++++-----------------
> > >  1 file changed, 19 insertions(+), 17 deletions(-)
> > > 
> > > diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
> > > index 7f390849343b..f9f22976d77d 100644
> > > --- a/fs/btrfs/compression.c
> > > +++ b/fs/btrfs/compression.c
> > > @@ -1072,25 +1072,27 @@ int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,
> > >  			return 0;
> > >  		bvec = bio_iter_iovec(bio, bio->bi_iter);
> > >  
> > > -		start_byte = page_offset(bvec.bv_page) - disk_start;
> > > +		if (bvec.bv_offset == 0) {
> > > +			start_byte = page_offset(bvec.bv_page) - disk_start;
> > 
> > I'm not fully convinced that the next bvec's bv_offset is always
> > zero, since the pages are all locked, can we keep a orig_page and
> > check if (orig_page == bvec.bv_page)?
> 
> That's a good point, that's more foolproof. I'll send a v2.

With that, you can have

Reviewed-by: Liu Bo <bo.li.liu@oracle.com>
Tested-by: Liu Bo <bo.li.liu@oracle.com>

We may add ASSERT(bvec.bv_offset == 0) in the if statement of
(orig_page == bvec.bv_page), then we could know whether it's true :)

Thanks,

-liubo

      reply	other threads:[~2017-02-10 22:58 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-02-10 20:15 [PATCH] Btrfs: fix btrfs_decompress_buf2page() Omar Sandoval
2017-02-10 22:46 ` Liu Bo
2017-02-10 22:52   ` Omar Sandoval
2017-02-10 22:57     ` Liu Bo [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170210225752.GC30334@localhost.localdomain \
    --to=bo.li.liu@oracle.com \
    --cc=clm@fb.com \
    --cc=hch@lst.de \
    --cc=kernel-team@fb.com \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=osandov@osandov.com \
    --cc=pat-lkml@erley.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.