Commit 704de49d authored by Filipe Manana's avatar Filipe Manana Committed by Chris Mason

Btrfs: set page and mapping error on compressed write failure

If we fail in submit_compressed_extents() before calling btrfs_submit_compressed_write(),
we start and end the writeback for the pages (clear their dirty flag, unlock them, etc)
but we don't tag the pages, nor the inode's mapping, with an error. This makes it
impossible for a caller of filemap_fdatawait_range() (fsync, or transaction commit
for e.g.) know that there was an error.

Note that the return value of submit_compressed_extents() is useless, as that function
is executed by a workqueue task and not directly by the fill_delalloc callback. This
means the writepage/s callbacks of the inode's address space operations don't get that
return value.
Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
Signed-off-by: default avatarChris Mason <clm@fb.com>
parent fc14f9c1
...@@ -1746,6 +1746,9 @@ int extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end, ...@@ -1746,6 +1746,9 @@ int extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,
if (page_ops == 0) if (page_ops == 0)
return 0; return 0;
if ((page_ops & PAGE_SET_ERROR) && nr_pages > 0)
mapping_set_error(inode->i_mapping, -EIO);
while (nr_pages > 0) { while (nr_pages > 0) {
ret = find_get_pages_contig(inode->i_mapping, index, ret = find_get_pages_contig(inode->i_mapping, index,
min_t(unsigned long, min_t(unsigned long,
...@@ -1763,6 +1766,8 @@ int extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end, ...@@ -1763,6 +1766,8 @@ int extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,
clear_page_dirty_for_io(pages[i]); clear_page_dirty_for_io(pages[i]);
if (page_ops & PAGE_SET_WRITEBACK) if (page_ops & PAGE_SET_WRITEBACK)
set_page_writeback(pages[i]); set_page_writeback(pages[i]);
if (page_ops & PAGE_SET_ERROR)
SetPageError(pages[i]);
if (page_ops & PAGE_END_WRITEBACK) if (page_ops & PAGE_END_WRITEBACK)
end_page_writeback(pages[i]); end_page_writeback(pages[i]);
if (page_ops & PAGE_UNLOCK) if (page_ops & PAGE_UNLOCK)
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#define PAGE_SET_WRITEBACK (1 << 2) #define PAGE_SET_WRITEBACK (1 << 2)
#define PAGE_END_WRITEBACK (1 << 3) #define PAGE_END_WRITEBACK (1 << 3)
#define PAGE_SET_PRIVATE2 (1 << 4) #define PAGE_SET_PRIVATE2 (1 << 4)
#define PAGE_SET_ERROR (1 << 5)
/* /*
* page->private values. Every page that is controlled by the extent * page->private values. Every page that is controlled by the extent
......
...@@ -832,7 +832,8 @@ static noinline int submit_compressed_extents(struct inode *inode, ...@@ -832,7 +832,8 @@ static noinline int submit_compressed_extents(struct inode *inode,
NULL, EXTENT_LOCKED | EXTENT_DELALLOC | NULL, EXTENT_LOCKED | EXTENT_DELALLOC |
EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING, EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING,
PAGE_UNLOCK | PAGE_CLEAR_DIRTY | PAGE_UNLOCK | PAGE_CLEAR_DIRTY |
PAGE_SET_WRITEBACK | PAGE_END_WRITEBACK); PAGE_SET_WRITEBACK | PAGE_END_WRITEBACK |
PAGE_SET_ERROR);
kfree(async_extent); kfree(async_extent);
goto again; goto again;
} }
......
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