FAILED: patch "[PATCH] Btrfs: fix unexpected cow in run_delalloc_nocow" failed to apply to 3.18-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 3.18-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
Quoted 1 line
From
5811375325420052fcadd944792a416a43072b7fMon Sep 17 00:00:00 2001
From: Liu Bo <[email protected]>
Date: Wed, 31 Jan 2018 17:09:13 -0700
Subject: [PATCH] Btrfs: fix unexpected cow in run_delalloc_nocow
Fstests generic/475 provides a way to fail metadata reads while checking if checksum exists for the inode inside run_delalloc_nocow(), and csum_exist_in_range() interprets error (-EIO) as inode having checksum and makes its caller enter the cow path.
In case of free space inode, this ends up with a warning in cow_file_range().
The same problem applies to btrfs_cross_ref_exist() since it may also read metadata in between.
With this, run_delalloc_nocow() bails out when errors occur at the two places.
fs/btrfs/inode.c +32 -5
@@ -1256,6 +1256,8 @@ static noinline int csum_exist_in_range(struct btrfs_fs_info *fs_info,list_del (&sums->list);kfree (sums); } +if (ret <0 ) +return ret;return 1 ; }
@@ -1388,10 +1390,23 @@ static noinline int run_delalloc_nocow(struct inode *inode, goto out_check;if (btrfs_extent_readonly (fs_info, disk_bytenr)) goto out_check; -if (btrfs_cross_ref_exist (root, ino, - found_key.offset - - extent_offset, disk_bytenr)) + ret =btrfs_cross_ref_exist (root, ino, + found_key.offset - + extent_offset, disk_bytenr); +if (ret) { +/* +* ret could be -EIO if the above fails to read +* metadata. +*/ +if (ret <0 ) { +if (cow_start != (u64)-1 ) + cur_offset = cow_start; + goto error; + } + +WARN_ON_ONCE (nolock); goto out_check; + } disk_bytenr += extent_offset; disk_bytenr += cur_offset - found_key.offset; num_bytes =min (end +1 , extent_end) - cur_offset;
@@ -1409,10 +1424,22 @@ static noinline int run_delalloc_nocow(struct inode *inode,* this ensure that csum for a given extent are * either valid or do not exist. */ -if (csum_exist_in_range (fs_info, disk_bytenr, - num_bytes)) { + ret =csum_exist_in_range (fs_info, disk_bytenr, + num_bytes); +if (ret) {if (!nolock)btrfs_end_write_no_snapshotting (root); + +/* +* ret could be -EIO if the above fails to read +* metadata. +*/ +if (ret <0 ) { +if (cow_start != (u64)-1 ) + cur_offset = cow_start; + goto error; + } +WARN_ON_ONCE (nolock); goto out_check; }if (!btrfs_inc_nocow_writers (fs_info, disk_bytenr)) {