[PATCH 4.16 22/31] Btrfs: fix unexpected cow in run_delalloc_nocow

2018-04-06 Thread Greg Kroah-Hartman
4.16-stable review patch.  If anyone has any objections, please let me know.

--

From: Liu Bo 

commit 5811375325420052fcadd944792a416a43072b7f upstream.

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.

cc:  v2.6.28+
Fixes: 17d217fe970d ("Btrfs: fix nodatasum handling in balancing code")
Signed-off-by: Liu Bo 
Signed-off-by: David Sterba 
Signed-off-by: Greg Kroah-Hartman 

---
 fs/btrfs/inode.c |   37 -
 1 file changed, 32 insertions(+), 5 deletions(-)

--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1262,6 +1262,8 @@ static noinline int csum_exist_in_range(
list_del(>list);
kfree(sums);
}
+   if (ret < 0)
+   return ret;
return 1;
 }
 
@@ -1394,10 +1396,23 @@ next_slot:
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;
@@ -1415,10 +1430,22 @@ next_slot:
 * 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)) {




[PATCH 4.16 22/31] Btrfs: fix unexpected cow in run_delalloc_nocow

2018-04-06 Thread Greg Kroah-Hartman
4.16-stable review patch.  If anyone has any objections, please let me know.

--

From: Liu Bo 

commit 5811375325420052fcadd944792a416a43072b7f upstream.

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.

cc:  v2.6.28+
Fixes: 17d217fe970d ("Btrfs: fix nodatasum handling in balancing code")
Signed-off-by: Liu Bo 
Signed-off-by: David Sterba 
Signed-off-by: Greg Kroah-Hartman 

---
 fs/btrfs/inode.c |   37 -
 1 file changed, 32 insertions(+), 5 deletions(-)

--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1262,6 +1262,8 @@ static noinline int csum_exist_in_range(
list_del(>list);
kfree(sums);
}
+   if (ret < 0)
+   return ret;
return 1;
 }
 
@@ -1394,10 +1396,23 @@ next_slot:
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;
@@ -1415,10 +1430,22 @@ next_slot:
 * 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)) {