Skip to content

Commit

Permalink
btrfs: finish ordered extent cleaning if no progress is found
Browse files Browse the repository at this point in the history
__endio_write_update_ordered() repeats the search until it reaches the end
of the specified range. This works well with direct IO path, because before
the function is called, it's ensured that there are ordered extents filling
whole the range. It's not the case, however, when it's called from
run_delalloc_range(): it is possible to have error in the midle of the loop
in e.g. run_delalloc_nocow(), so that there exisits the range not covered
by any ordered extents. By cleaning such "uncomplete" range,
__endio_write_update_ordered() stucks at offset where there're no ordered
extents.

Since the ordered extents are created from head to tail, we can stop the
search if there are no offset progress.

Fixes: 5242726 ("btrfs: Handle delalloc error correctly to avoid ordered extent hang")
Cc: <[email protected]> # 4.12
Signed-off-by: Naohiro Aota <[email protected]>
Reviewed-by: Qu Wenruo <[email protected]>
Reviewed-by: Josef Bacik <[email protected]>
Signed-off-by: David Sterba <[email protected]>
  • Loading branch information
naota authored and kdave committed Sep 26, 2017
1 parent 63d7145 commit 67c003f
Showing 1 changed file with 8 additions and 0 deletions.
8 changes: 8 additions & 0 deletions fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -8396,6 +8396,7 @@ static void __endio_write_update_ordered(struct inode *inode,
btrfs_work_func_t func;
u64 ordered_offset = offset;
u64 ordered_bytes = bytes;
u64 last_offset;
int ret;

if (btrfs_is_free_space_inode(BTRFS_I(inode))) {
Expand All @@ -8407,6 +8408,7 @@ static void __endio_write_update_ordered(struct inode *inode,
}

again:
last_offset = ordered_offset;
ret = btrfs_dec_test_first_ordered_pending(inode, &ordered,
&ordered_offset,
ordered_bytes,
Expand All @@ -8417,6 +8419,12 @@ static void __endio_write_update_ordered(struct inode *inode,
btrfs_init_work(&ordered->work, func, finish_ordered_fn, NULL, NULL);
btrfs_queue_work(wq, &ordered->work);
out_test:
/*
* If btrfs_dec_test_ordered_pending does not find any ordered extent
* in the range, we can exit.
*/
if (ordered_offset == last_offset)
return;
/*
* our bio might span multiple ordered extents. If we haven't
* completed the accounting for the whole dio, go back and try again
Expand Down

0 comments on commit 67c003f

Please sign in to comment.