• Omar Sandoval's avatar
    Btrfs: fix btrfs_decompress_buf2page() · 6e78b3f7
    Omar Sandoval authored
    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.
    
    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.
    
    Fixes: 974b1adc ("btrfs: use bio iterators for the decompression handlers")
    Reported-by: default avatarPat Erley <pat-lkml@erley.org>
    Reviewed-by: default avatarChris Mason <clm@fb.com>
    Signed-off-by: default avatarOmar Sandoval <osandov@fb.com>
    Signed-off-by: default avatarChris Mason <clm@fb.com>
    Reviewed-by: default avatarLiu Bo <bo.li.liu@oracle.com>
    Tested-by: default avatarLiu Bo <bo.li.liu@oracle.com>
    6e78b3f7
compression.c 27.9 KB