• Omar Sandoval's avatar
    Btrfs: deal with existing encompassing extent map in btrfs_get_extent() · 8e2bd3b7
    Omar Sandoval authored
    My QEMU VM was seeing inexplicable I/O errors that I tracked down to
    errors coming from the qcow2 virtual drive in the host system. The qcow2
    file is a nocow file on my Btrfs drive, which QEMU opens with O_DIRECT.
    Every once in awhile, pread() or pwrite() would return EEXIST, which
    makes no sense. This turned out to be a bug in btrfs_get_extent().
    
    Commit 8dff9c85 ("Btrfs: deal with duplciates during extent_map
    insertion in btrfs_get_extent") fixed a case in btrfs_get_extent() where
    two threads race on adding the same extent map to an inode's extent map
    tree. However, if the added em is merged with an adjacent em in the
    extent tree, then we'll end up with an existing extent that is not
    identical to but instead encompasses the extent we tried to add. When we
    call merge_extent_mapping() to find the nonoverlapping part of the new
    em, the arithmetic overflows because there is no such thing. We then end
    up trying to add a bogus em to the em_tree, which results in a EEXIST
    that can bubble all the way up to userspace.
    
    Fix it by extending the identical extent map special case.
    Signed-off-by: default avatarOmar Sandoval <osandov@fb.com>
    Reviewed-by: default avatarLiu Bo <bo.li.liu@oracle.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    8e2bd3b7
inode.c 283 KB