summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorZhao Lei <zhaolei@cn.fujitsu.com>2016-01-06 18:24:43 +0800
committerDavid Sterba <dsterba@suse.com>2016-02-18 13:18:06 +0100
commit4da2e26a2a32b174878744bd0f07db180c875f26 (patch)
tree6418afad08a321846e0b39ed430507cde3e83cc5 /fs
parent388f7b1d6e8ca06762e2454d28d6c3c55ad0fe95 (diff)
downloadlinux-4da2e26a2a32b174878744bd0f07db180c875f26.tar.gz
linux-4da2e26a2a32b174878744bd0f07db180c875f26.tar.bz2
linux-4da2e26a2a32b174878744bd0f07db180c875f26.zip
btrfs: Continue write in case of can_not_nocow
btrfs failed in xfstests btrfs/080 with -o nodatacow. Can be reproduced by following script: DEV=/dev/vdg MNT=/mnt/tmp umount $DEV &>/dev/null mkfs.btrfs -f $DEV mount -o nodatacow $DEV $MNT dd if=/dev/zero of=$MNT/test bs=1 count=2048 & btrfs subvolume snapshot -r $MNT $MNT/test_snap & wait -- We can see dd failed on NO_SPACE. Reason: __btrfs_buffered_write should run cow write when no_cow impossible, and current code is designed with above logic. But check_can_nocow() have 2 type of return value(0 and <0) on can_not_no_cow, and current code only continue write on first case, the second case happened in doing subvolume. Fix: Continue write when check_can_nocow() return 0 and <0. Reviewed-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Zhao Lei <zhaolei@cn.fujitsu.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/file.c37
1 files changed, 17 insertions, 20 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 098bb8f690c9..cadfebaaf8c4 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1525,27 +1525,24 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
reserve_bytes = num_pages << PAGE_CACHE_SHIFT;
- if (BTRFS_I(inode)->flags & (BTRFS_INODE_NODATACOW |
- BTRFS_INODE_PREALLOC)) {
- ret = check_can_nocow(inode, pos, &write_bytes);
- if (ret < 0)
- break;
- if (ret > 0) {
- /*
- * For nodata cow case, no need to reserve
- * data space.
- */
- only_release_metadata = true;
- /*
- * our prealloc extent may be smaller than
- * write_bytes, so scale down.
- */
- num_pages = DIV_ROUND_UP(write_bytes + offset,
- PAGE_CACHE_SIZE);
- reserve_bytes = num_pages << PAGE_CACHE_SHIFT;
- goto reserve_metadata;
- }
+ if ((BTRFS_I(inode)->flags & (BTRFS_INODE_NODATACOW |
+ BTRFS_INODE_PREALLOC)) &&
+ check_can_nocow(inode, pos, &write_bytes) > 0) {
+ /*
+ * For nodata cow case, no need to reserve
+ * data space.
+ */
+ only_release_metadata = true;
+ /*
+ * our prealloc extent may be smaller than
+ * write_bytes, so scale down.
+ */
+ num_pages = DIV_ROUND_UP(write_bytes + offset,
+ PAGE_CACHE_SIZE);
+ reserve_bytes = num_pages << PAGE_CACHE_SHIFT;
+ goto reserve_metadata;
}
+
ret = btrfs_check_data_free_space(inode, pos, write_bytes);
if (ret < 0)
break;