diff options
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/extent-tree.c | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index add4af641cfa..cf8983e4a2eb 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -3768,6 +3768,25 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, | |||
3768 | } | 3768 | } |
3769 | if (!ret) { | 3769 | if (!ret) { |
3770 | ret = write_one_cache_group(trans, root, path, cache); | 3770 | ret = write_one_cache_group(trans, root, path, cache); |
3771 | /* | ||
3772 | * One of the free space endio workers might have | ||
3773 | * created a new block group while updating a free space | ||
3774 | * cache's inode (at inode.c:btrfs_finish_ordered_io()) | ||
3775 | * and hasn't released its transaction handle yet, in | ||
3776 | * which case the new block group is still attached to | ||
3777 | * its transaction handle and its creation has not | ||
3778 | * finished yet (no block group item in the extent tree | ||
3779 | * yet, etc). If this is the case, wait for all free | ||
3780 | * space endio workers to finish and retry. This is a | ||
3781 | * a very rare case so no need for a more efficient and | ||
3782 | * complex approach. | ||
3783 | */ | ||
3784 | if (ret == -ENOENT) { | ||
3785 | wait_event(cur_trans->writer_wait, | ||
3786 | atomic_read(&cur_trans->num_writers) == 1); | ||
3787 | ret = write_one_cache_group(trans, root, path, | ||
3788 | cache); | ||
3789 | } | ||
3771 | if (ret) | 3790 | if (ret) |
3772 | btrfs_abort_transaction(trans, root, ret); | 3791 | btrfs_abort_transaction(trans, root, ret); |
3773 | } | 3792 | } |