• Josef Bacik's avatar
    btrfs: don't double put our subpage reference in alloc_extent_buffer · 4a565c80
    Josef Bacik authored
    
    
    This fixes as case in "btrfs: refactor alloc_extent_buffer() to
    allocate-then-attach method".
    
    We have been seeing panics in the CI for the subpage stuff recently, it
    happens on btrfs/187 but could potentially happen anywhere.
    
    In the subpage case, if we race with somebody else inserting the same
    extent buffer, the error case will end up calling
    detach_extent_buffer_page() on the page twice.
    
    This is done first in the bit
    
    for (int i = 0; i < attached; i++)
    	detach_extent_buffer_page(eb, eb->pages[i];
    
    and then again in btrfs_release_extent_buffer().
    
    This works fine for !subpage because we're the only person who ever has
    ourselves on the private, and so when we do the initial
    detach_extent_buffer_page() we know we've completely removed it.
    
    However for subpage we could be using this page private elsewhere, so
    this results in a double put on the subpage, which can result in an
    early freeing.
    
    The fix here is to clear eb->pages[i] for everything we detach.  Then
    anything still attached to the eb is freed in
    btrfs_release_extent_buffer().
    
    Because of this change we must update
    btrfs_release_extent_buffer_pages() to not use num_extent_folios,
    because it assumes eb->folio[0] is set properly.  Since this is only
    interested in freeing any pages we have on the extent buffer we can
    simply use INLINE_EXTENT_BUFFER_PAGES.
    Reviewed-by: default avatarQu Wenruo <wqu@suse.com>
    Signed-off-by: default avatarJosef Bacik <josef@toxicpanda.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    4a565c80
extent_io.c 135 KB