lkml.org 
[lkml]   [2020]   [Feb]   [8]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Date
    Subject[PATCH 3.16 103/148] btrfs: check page->mapping when loading free space cache
    3.16.82-rc1 review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Josef Bacik <josef@toxicpanda.com>

    commit 3797136b626ad4b6582223660c041efdea8f26b2 upstream.

    While testing 5.2 we ran into the following panic

    [52238.017028] BUG: kernel NULL pointer dereference, address: 0000000000000001
    [52238.105608] RIP: 0010:drop_buffers+0x3d/0x150
    [52238.304051] Call Trace:
    [52238.308958] try_to_free_buffers+0x15b/0x1b0
    [52238.317503] shrink_page_list+0x1164/0x1780
    [52238.325877] shrink_inactive_list+0x18f/0x3b0
    [52238.334596] shrink_node_memcg+0x23e/0x7d0
    [52238.342790] ? do_shrink_slab+0x4f/0x290
    [52238.350648] shrink_node+0xce/0x4a0
    [52238.357628] balance_pgdat+0x2c7/0x510
    [52238.365135] kswapd+0x216/0x3e0
    [52238.371425] ? wait_woken+0x80/0x80
    [52238.378412] ? balance_pgdat+0x510/0x510
    [52238.386265] kthread+0x111/0x130
    [52238.392727] ? kthread_create_on_node+0x60/0x60
    [52238.401782] ret_from_fork+0x1f/0x30

    The page we were trying to drop had a page->private, but had no
    page->mapping and so called drop_buffers, assuming that we had a
    buffer_head on the page, and then panic'ed trying to deref 1, which is
    our page->private for data pages.

    This is happening because we're truncating the free space cache while
    we're trying to load the free space cache. This isn't supposed to
    happen, and I'll fix that in a followup patch. However we still
    shouldn't allow those sort of mistakes to result in messing with pages
    that do not belong to us. So add the page->mapping check to verify that
    we still own this page after dropping and re-acquiring the page lock.

    This page being unlocked as:
    btrfs_readpage
    extent_read_full_page
    __extent_read_full_page
    __do_readpage
    if (!nr)
    unlock_page <-- nr can be 0 only if submit_extent_page
    returns an error

    Reviewed-by: Filipe Manana <fdmanana@suse.com>
    Reviewed-by: Nikolay Borisov <nborisov@suse.com>
    Signed-off-by: Josef Bacik <josef@toxicpanda.com>
    [ add callchain ]
    Signed-off-by: David Sterba <dsterba@suse.com>
    Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
    ---
    fs/btrfs/free-space-cache.c | 6 ++++++
    1 file changed, 6 insertions(+)

    --- a/fs/btrfs/free-space-cache.c
    +++ b/fs/btrfs/free-space-cache.c
    @@ -360,6 +360,12 @@ static int io_ctl_prepare_pages(struct i
    if (uptodate && !PageUptodate(page)) {
    btrfs_readpage(NULL, page);
    lock_page(page);
    + if (page->mapping != inode->i_mapping) {
    + btrfs_err(BTRFS_I(inode)->root->fs_info,
    + "free space cache page truncated");
    + io_ctl_drop_pages(io_ctl);
    + return -EIO;
    + }
    if (!PageUptodate(page)) {
    btrfs_err(BTRFS_I(inode)->root->fs_info,
    "error reading free space cache");
    \
     
     \ /
      Last update: 2020-02-08 19:35    [W:4.198 / U:0.004 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site