• Nikolay Borisov's avatar
    btrfs: Correctly free extent buffer in case btree_read_extent_buffer_pages fails · 537f38f0
    Nikolay Borisov authored
    If a an eb fails to be read for whatever reason - it's corrupted on disk
    and parent transid/key validations fail or IO for eb pages fail then
    this buffer must be removed from the buffer cache. Currently the code
    calls free_extent_buffer if an error occurs. Unfortunately this doesn't
    achieve the desired behavior since btrfs_find_create_tree_block returns
    with eb->refs == 2.
    
    On the other hand free_extent_buffer will only decrement the refs once
    leaving it added to the buffer cache radix tree.  This enables later
    code to look up the buffer from the cache and utilize it potentially
    leading to a crash.
    
    The correct way to free the buffer is call free_extent_buffer_stale.
    This function will correctly call atomic_dec explicitly for the buffer
    and subsequently call release_extent_buffer which will decrement the
    final reference thus correctly remove the invalid buffer from buffer
    cache. This change affects only newly allocated buffers since they have
    eb->refs == 2.
    
    Link: https://bugzilla.kernel.org/show_bug.cgi?id=202755Reported-by: default avatarJungyeon <jungyeon@gatech.edu>
    CC: stable@vger.kernel.org # 4.4+
    Signed-off-by: default avatarNikolay Borisov <nborisov@suse.com>
    Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    537f38f0
disk-io.c 125 KB