]> git.hungrycats.org Git - linux/commitdiff
Btrfs: set page and mapping error on compressed write failure
authorFilipe Manana <fdmanana@suse.com>
Mon, 6 Oct 2014 21:14:22 +0000 (22:14 +0100)
committerZygo Blaxell <zblaxell@serenity.furryterror.org>
Fri, 23 Jan 2015 02:50:25 +0000 (21:50 -0500)
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>
(cherry picked from commit 704de49d2be665be44933300f60023c889832fca)

fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/inode.c

index bf3f424e0013c17d3a47047e5c7301abba93bfac..420fe26d32d56b60f57454f9daa8356b9318ed50 100644 (file)
@@ -1746,6 +1746,9 @@ int extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,
        if (page_ops == 0)
                return 0;
 
+       if ((page_ops & PAGE_SET_ERROR) && nr_pages > 0)
+               mapping_set_error(inode->i_mapping, -EIO);
+
        while (nr_pages > 0) {
                ret = find_get_pages_contig(inode->i_mapping, index,
                                     min_t(unsigned long,
@@ -1763,6 +1766,8 @@ int extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,
                                clear_page_dirty_for_io(pages[i]);
                        if (page_ops & PAGE_SET_WRITEBACK)
                                set_page_writeback(pages[i]);
+                       if (page_ops & PAGE_SET_ERROR)
+                               SetPageError(pages[i]);
                        if (page_ops & PAGE_END_WRITEBACK)
                                end_page_writeback(pages[i]);
                        if (page_ops & PAGE_UNLOCK)
index 6d4b938be98678660cc51fb55bd51a5688279ed8..ece9ce87edff521fa0a54f38bca0cb47059c638b 100644 (file)
@@ -49,6 +49,7 @@
 #define PAGE_SET_WRITEBACK     (1 << 2)
 #define PAGE_END_WRITEBACK     (1 << 3)
 #define PAGE_SET_PRIVATE2      (1 << 4)
+#define PAGE_SET_ERROR         (1 << 5)
 
 /*
  * page->private values.  Every page that is controlled by the extent
index 85a3e9b1f4588c4e7943ecb54045ca07be4654fb..ec68eaef05d7ed39bfc3c9a10065a91b0375bfe2 100644 (file)
@@ -846,7 +846,8 @@ out_free:
                                     NULL, EXTENT_LOCKED | EXTENT_DELALLOC |
                                     EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING,
                                     PAGE_UNLOCK | PAGE_CLEAR_DIRTY |
-                                    PAGE_SET_WRITEBACK | PAGE_END_WRITEBACK);
+                                    PAGE_SET_WRITEBACK | PAGE_END_WRITEBACK |
+                                    PAGE_SET_ERROR);
        kfree(async_extent);
        goto again;
 }