Skip to content
  • Chandan Rajendra's avatar
    Btrfs: Fix deadlock between direct IO and fast fsync · e8b5068b
    Chandan Rajendra authored
    
    [ Upstream commit 97dcdea0
    
     ]
    
    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>
    Signed-off-by: default avatarSasha Levin <alexander.levin@verizon.com>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    e8b5068b