• Q
    btrfs: allow btrfs_truncate_block() to fallback to nocow for data space reservation · 6d4572a9
    Qu Wenruo 提交于
    [BUG]
    When the data space is exhausted, even if the inode has NOCOW attribute,
    we will still refuse to truncate unaligned range due to ENOSPC.
    
    The following script can reproduce it pretty easily:
      #!/bin/bash
    
      dev=/dev/test/test
      mnt=/mnt/btrfs
    
      umount $dev &> /dev/null
      umount $mnt &> /dev/null
    
      mkfs.btrfs -f $dev -b 1G
      mount -o nospace_cache $dev $mnt
      touch $mnt/foobar
      chattr +C $mnt/foobar
    
      xfs_io -f -c "pwrite -b 4k 0 4k" $mnt/foobar > /dev/null
      xfs_io -f -c "pwrite -b 4k 0 1G" $mnt/padding &> /dev/null
      sync
    
      xfs_io -c "fpunch 0 2k" $mnt/foobar
      umount $mnt
    
    Currently this will fail at the fpunch part.
    
    [CAUSE]
    Because btrfs_truncate_block() always reserves space without checking
    the NOCOW attribute.
    
    Since the writeback path follows NOCOW bit, we only need to bother the
    space reservation code in btrfs_truncate_block().
    
    [FIX]
    Make btrfs_truncate_block() follow btrfs_buffered_write() to try to
    reserve data space first, and fall back to NOCOW check only when we
    don't have enough space.
    
    Such always-try-reserve is an optimization introduced in
    btrfs_buffered_write(), to avoid expensive btrfs_check_can_nocow() call.
    
    This patch will export check_can_nocow() as btrfs_check_can_nocow(), and
    use it in btrfs_truncate_block() to fix the problem.
    Reported-by: NMartin Doucha <martin.doucha@suse.com>
    Reviewed-by: NFilipe Manana <fdmanana@suse.com>
    Reviewed-by: NAnand Jain <anand.jain@oracle.com>
    Signed-off-by: NQu Wenruo <wqu@suse.com>
    Reviewed-by: NDavid Sterba <dsterba@suse.com>
    Signed-off-by: NDavid Sterba <dsterba@suse.com>
    6d4572a9
inode.c 285.9 KB