• Chandan Rajendra's avatar
    Btrfs: Fix deadlock between direct IO and fast fsync · 97dcdea0
    Chandan Rajendra authored
    The following deadlock is seen when executing generic/113 test,
    
     ---------------------------------------------------------+----------------------------------------------------
      Direct I/O task                                           Fast fsync task
     ---------------------------------------------------------+----------------------------------------------------
      btrfs_direct_IO
        __blockdev_direct_IO
         do_blockdev_direct_IO
          do_direct_IO
           btrfs_get_blocks_direct
            while (blocks needs to written)
             get_more_blocks (first iteration)
              btrfs_get_blocks_direct
               btrfs_create_dio_extent
                 down_read(&BTRFS_I(inode) >dio_sem)
                 Create and add extent map and ordered extent
                 up_read(&BTRFS_I(inode) >dio_sem)
                                                                btrfs_sync_file
                                                                  btrfs_log_dentry_safe
                                                                   btrfs_log_inode_parent
                                                                    btrfs_log_inode
                                                                     btrfs_log_changed_extents
                                                                      down_write(&BTRFS_I(inode) >dio_sem)
                                                                       Collect new extent maps and ordered extents
                                                                        wait for ordered extent completion
             get_more_blocks (second iteration)
              btrfs_get_blocks_direct
               btrfs_create_dio_extent
                 down_read(&BTRFS_I(inode) >dio_sem)
     --------------------------------------------------------------------------------------------------------------
    
    In the above description, Btrfs direct I/O code path has not yet started
    submitting bios for file range covered by the initial ordered
    extent. Meanwhile, The fast fsync task obtains the write semaphore and
    waits for I/O on the ordered extent to get completed. However, the
    Direct I/O task is now blocked on obtaining the read semaphore.
    
    To resolve the deadlock, this commit modifies the Direct I/O code path
    to obtain the read semaphore before invoking
    __blockdev_direct_IO(). The semaphore is then given up after
    __blockdev_direct_IO() returns. This allows the Direct I/O code to
    complete I/O on all the ordered extents it creates.
    Signed-off-by: default avatarChandan Rajendra <chandan@linux.vnet.ibm.com>
    Reviewed-by: default avatarFilipe Manana <fdmanana@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    97dcdea0
inode.c 283 KB