mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-31 16:38:12 +00:00
btrfs: fallback if compressed IO fails for ENOSPC
In commitb4ccace878
("btrfs: refactor submit_compressed_extents()"), if an async extent compressed but failed to find enough space, we changed from falling back to an uncompressed write to just failing the write altogether. The principle was that if there's not enough space to write the compressed version of the data, there can't possibly be enough space to write the larger, uncompressed version of the data. However, this isn't necessarily true: due to fragmentation, there could be enough discontiguous free blocks to write the uncompressed version, but not enough contiguous free blocks to write the smaller but unsplittable compressed version. This has occurred to an internal workload which relied on write()'s return value indicating there was space. While rare, it has happened a few times. Thus, in order to prevent early ENOSPC, re-add a fallback to uncompressed writing. Fixes:b4ccace878
("btrfs: refactor submit_compressed_extents()") CC: stable@vger.kernel.org # 6.1+ Reviewed-by: Qu Wenruo <wqu@suse.com> Co-developed-by: Neal Gompa <neal@gompa.dev> Signed-off-by: Neal Gompa <neal@gompa.dev> Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
7192833c4e
commit
131a821a24
1 changed files with 6 additions and 7 deletions
|
@ -1145,13 +1145,13 @@ static void submit_one_async_extent(struct async_chunk *async_chunk,
|
|||
0, *alloc_hint, &ins, 1, 1);
|
||||
if (ret) {
|
||||
/*
|
||||
* Here we used to try again by going back to non-compressed
|
||||
* path for ENOSPC. But we can't reserve space even for
|
||||
* compressed size, how could it work for uncompressed size
|
||||
* which requires larger size? So here we directly go error
|
||||
* path.
|
||||
* We can't reserve contiguous space for the compressed size.
|
||||
* Unlikely, but it's possible that we could have enough
|
||||
* non-contiguous space for the uncompressed size instead. So
|
||||
* fall back to uncompressed.
|
||||
*/
|
||||
goto out_free;
|
||||
submit_uncompressed_range(inode, async_extent, locked_page);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Here we're doing allocation and writeback of the compressed pages */
|
||||
|
@ -1203,7 +1203,6 @@ static void submit_one_async_extent(struct async_chunk *async_chunk,
|
|||
out_free_reserve:
|
||||
btrfs_dec_block_group_reservations(fs_info, ins.objectid);
|
||||
btrfs_free_reserved_extent(fs_info, ins.objectid, ins.offset, 1);
|
||||
out_free:
|
||||
mapping_set_error(inode->vfs_inode.i_mapping, -EIO);
|
||||
extent_clear_unlock_delalloc(inode, start, end,
|
||||
NULL, EXTENT_LOCKED | EXTENT_DELALLOC |
|
||||
|
|
Loading…
Reference in a new issue