Commit fce2a4e6 authored by Filipe Manana's avatar Filipe Manana Committed by Chris Mason

Btrfs: fix hang on compressed write error

In inode.c:submit_compressed_extents(), before calling btrfs_submit_compressed_write()
we start writeback for all pages, clear their dirty flag, unlock them, etc, but if
btrfs_submit_compressed_write() fails (at the moment it can only fail with -ENOMEM),
we never end the writeback on the pages, so any filemap_fdatawait_range() call will
hang forever. We were also not calling the writepage end io hook, which means the
corresponding ordered extent will never complete and all its waiters will block
forever, such as a full fsync (via btrfs_wait_ordered_range()).
Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
Signed-off-by: default avatarChris Mason <clm@fb.com>
parent 704de49d
...@@ -814,6 +814,20 @@ static noinline int submit_compressed_extents(struct inode *inode, ...@@ -814,6 +814,20 @@ static noinline int submit_compressed_extents(struct inode *inode,
ins.objectid, ins.objectid,
ins.offset, async_extent->pages, ins.offset, async_extent->pages,
async_extent->nr_pages); async_extent->nr_pages);
if (ret) {
struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree;
struct page *p = async_extent->pages[0];
const u64 start = async_extent->start;
const u64 end = start + async_extent->ram_size - 1;
p->mapping = inode->i_mapping;
tree->ops->writepage_end_io_hook(p, start, end,
NULL, 0);
p->mapping = NULL;
extent_clear_unlock_delalloc(inode, start, end, NULL, 0,
PAGE_END_WRITEBACK |
PAGE_SET_ERROR);
}
alloc_hint = ins.objectid + ins.offset; alloc_hint = ins.objectid + ins.offset;
kfree(async_extent); kfree(async_extent);
if (ret) if (ret)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment