| From e75fd33b3f744f644061a4f9662bd63f5434f806 Mon Sep 17 00:00:00 2001 |
| From: Filipe Manana <fdmanana@suse.com> |
| Date: Thu, 13 Feb 2020 12:29:50 +0000 |
| Subject: Btrfs: fix btrfs_wait_ordered_range() so that it waits for all ordered extents |
| |
| From: Filipe Manana <fdmanana@suse.com> |
| |
| commit e75fd33b3f744f644061a4f9662bd63f5434f806 upstream. |
| |
| In btrfs_wait_ordered_range() once we find an ordered extent that has |
| finished with an error we exit the loop and don't wait for any other |
| ordered extents that might be still in progress. |
| |
| All the users of btrfs_wait_ordered_range() expect that there are no more |
| ordered extents in progress after that function returns. So past fixes |
| such like the ones from the two following commits: |
| |
| ff612ba7849964 ("btrfs: fix panic during relocation after ENOSPC before |
| writeback happens") |
| |
| 28aeeac1dd3080 ("Btrfs: fix panic when starting bg cache writeout after |
| IO error") |
| |
| don't work when there are multiple ordered extents in the range. |
| |
| Fix that by making btrfs_wait_ordered_range() wait for all ordered extents |
| even after it finds one that had an error. |
| |
| Link: https://github.com/kdave/btrfs-progs/issues/228#issuecomment-569777554 |
| CC: stable@vger.kernel.org # 4.4+ |
| Reviewed-by: Qu Wenruo <wqu@suse.com> |
| Reviewed-by: Josef Bacik <josef@toxicpanda.com> |
| Signed-off-by: Filipe Manana <fdmanana@suse.com> |
| Signed-off-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/btrfs/ordered-data.c | 7 ++++++- |
| 1 file changed, 6 insertions(+), 1 deletion(-) |
| |
| --- a/fs/btrfs/ordered-data.c |
| +++ b/fs/btrfs/ordered-data.c |
| @@ -686,10 +686,15 @@ int btrfs_wait_ordered_range(struct inod |
| } |
| btrfs_start_ordered_extent(inode, ordered, 1); |
| end = ordered->file_offset; |
| + /* |
| + * If the ordered extent had an error save the error but don't |
| + * exit without waiting first for all other ordered extents in |
| + * the range to complete. |
| + */ |
| if (test_bit(BTRFS_ORDERED_IOERR, &ordered->flags)) |
| ret = -EIO; |
| btrfs_put_ordered_extent(ordered); |
| - if (ret || end == 0 || end == start) |
| + if (end == 0 || end == start) |
| break; |
| end--; |
| } |