• Filipe Manana's avatar
    Btrfs: fix page reading in extent_same ioctl leading to csum errors · 31314002
    Filipe Manana authored
    In the extent_same ioctl, we were grabbing the pages (locked) and
    attempting to read them without bothering about any concurrent IO
    against them. That is, we were not checking for any ongoing ordered
    extents nor waiting for them to complete, which leads to a race where
    the extent_same() code gets a checksum verification error when it
    reads the pages, producing a message like the following in dmesg
    and making the operation fail to user space with -ENOMEM:
    
    [18990.161265] BTRFS warning (device sdc): csum failed ino 259 off 495616 csum 685204116 expected csum 1515870868
    
    Fix this by using btrfs_readpage() for reading the pages instead of
    extent_read_full_page_nolock(), which waits for any concurrent ordered
    extents to complete and locks the io range. Also do better error handling
    and don't treat all failures as -ENOMEM, as that's clearly misleasing,
    becoming identical to the checks and operation of prepare_uptodate_page().
    
    The use of extent_read_full_page_nolock() was required before
    commit f4414602 ("btrfs: fix deadlock with extent-same and readpage"),
    as we had the range locked in an inode's io tree before attempting to
    read the pages.
    
    Fixes: f4414602 ("btrfs: fix deadlock with extent-same and readpage")
    Cc: stable@vger.kernel.org   # 4.2+
    Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
    31314002
ioctl.c 137 KB