aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorFilipe Manana <fdmanana@suse.com>2014-10-06 17:14:22 -0400
committerChris Mason <clm@fb.com>2014-11-20 20:14:25 -0500
commit704de49d2be665be44933300f60023c889832fca (patch)
tree99105c7f389873f692c946bc6e36bb95653ff152 /fs
parentfc14f9c1272f62c3e8d01300f52467c0d9af50f9 (diff)
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: Filipe Manana <fdmanana@suse.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/extent_io.c5
-rw-r--r--fs/btrfs/extent_io.h1
-rw-r--r--fs/btrfs/inode.c3
3 files changed, 8 insertions, 1 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index bf3f424e0013..420fe26d32d5 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -1746,6 +1746,9 @@ int extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,
1746 if (page_ops == 0) 1746 if (page_ops == 0)
1747 return 0; 1747 return 0;
1748 1748
1749 if ((page_ops & PAGE_SET_ERROR) && nr_pages > 0)
1750 mapping_set_error(inode->i_mapping, -EIO);
1751
1749 while (nr_pages > 0) { 1752 while (nr_pages > 0) {
1750 ret = find_get_pages_contig(inode->i_mapping, index, 1753 ret = find_get_pages_contig(inode->i_mapping, index,
1751 min_t(unsigned long, 1754 min_t(unsigned long,
@@ -1763,6 +1766,8 @@ int extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,
1763 clear_page_dirty_for_io(pages[i]); 1766 clear_page_dirty_for_io(pages[i]);
1764 if (page_ops & PAGE_SET_WRITEBACK) 1767 if (page_ops & PAGE_SET_WRITEBACK)
1765 set_page_writeback(pages[i]); 1768 set_page_writeback(pages[i]);
1769 if (page_ops & PAGE_SET_ERROR)
1770 SetPageError(pages[i]);
1766 if (page_ops & PAGE_END_WRITEBACK) 1771 if (page_ops & PAGE_END_WRITEBACK)
1767 end_page_writeback(pages[i]); 1772 end_page_writeback(pages[i]);
1768 if (page_ops & PAGE_UNLOCK) 1773 if (page_ops & PAGE_UNLOCK)
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index 6d4b938be986..ece9ce87edff 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -49,6 +49,7 @@
49#define PAGE_SET_WRITEBACK (1 << 2) 49#define PAGE_SET_WRITEBACK (1 << 2)
50#define PAGE_END_WRITEBACK (1 << 3) 50#define PAGE_END_WRITEBACK (1 << 3)
51#define PAGE_SET_PRIVATE2 (1 << 4) 51#define PAGE_SET_PRIVATE2 (1 << 4)
52#define PAGE_SET_ERROR (1 << 5)
52 53
53/* 54/*
54 * page->private values. Every page that is controlled by the extent 55 * page->private values. Every page that is controlled by the extent
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index d23362f4464e..fcb9a38fc9d3 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -832,7 +832,8 @@ out_free:
832 NULL, EXTENT_LOCKED | EXTENT_DELALLOC | 832 NULL, EXTENT_LOCKED | EXTENT_DELALLOC |
833 EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING, 833 EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING,
834 PAGE_UNLOCK | PAGE_CLEAR_DIRTY | 834 PAGE_UNLOCK | PAGE_CLEAR_DIRTY |
835 PAGE_SET_WRITEBACK | PAGE_END_WRITEBACK); 835 PAGE_SET_WRITEBACK | PAGE_END_WRITEBACK |
836 PAGE_SET_ERROR);
836 kfree(async_extent); 837 kfree(async_extent);
837 goto again; 838 goto again;
838} 839}