On Thu, Oct 08, 2020 at 06:59:54PM +0800, Anand Jain wrote:
From: Qu Wenruo wqu@suse.com
commit 6d4572a9d71d5fc2affee0258d8582d39859188c upstream.
[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: Martin Doucha martin.doucha@suse.com Reviewed-by: Filipe Manana fdmanana@suse.com Reviewed-by: Anand Jain anand.jain@oracle.com Signed-off-by: Qu Wenruo wqu@suse.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Anand Jain anand.jain@oracle.com Conflicts: fs/btrfs/ctree.h fs/btrfs/file.c fs/btrfs/inode.c
Why are these Conflicts: lines here?
Anyway, fixed up, and all queued up now, thansk!
greg k-h