diff options
author | Filipe Manana <fdmanana@suse.com> | 2014-10-06 20:48:26 -0400 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2014-11-20 20:14:26 -0500 |
commit | 7bdcefc103849386ef7f3029dd94ecfd4a822a67 (patch) | |
tree | c55af204cb18c4fe3679dd2a06a19b78618a5a76 /fs/btrfs/compression.c | |
parent | dec8f1756342c92fc31ba8bc7060b55dd62836a0 (diff) |
Btrfs: don't ignore compressed bio write errors
Our compressed bio write end callback was essentially ignoring the error
parameter. When a write error happens, it must pass a value of 0 to the
inode's write_page_end_io_hook callback, SetPageError on the respective
pages and set AS_EIO in the inode's mapping flags, so that a call to
filemap_fdatawait_range() / filemap_fdatawait() can find out that errors
happened (we surely don't want silent failures on fsync for example).
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs/btrfs/compression.c')
-rw-r--r-- | fs/btrfs/compression.c | 18 |
1 files changed, 12 insertions, 6 deletions
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index d3220d31d3cb..1bf411bc28fd 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c | |||
@@ -224,16 +224,19 @@ out: | |||
224 | * Clear the writeback bits on all of the file | 224 | * Clear the writeback bits on all of the file |
225 | * pages for a compressed write | 225 | * pages for a compressed write |
226 | */ | 226 | */ |
227 | static noinline void end_compressed_writeback(struct inode *inode, u64 start, | 227 | static noinline void end_compressed_writeback(struct inode *inode, |
228 | unsigned long ram_size) | 228 | const struct compressed_bio *cb) |
229 | { | 229 | { |
230 | unsigned long index = start >> PAGE_CACHE_SHIFT; | 230 | unsigned long index = cb->start >> PAGE_CACHE_SHIFT; |
231 | unsigned long end_index = (start + ram_size - 1) >> PAGE_CACHE_SHIFT; | 231 | unsigned long end_index = (cb->start + cb->len - 1) >> PAGE_CACHE_SHIFT; |
232 | struct page *pages[16]; | 232 | struct page *pages[16]; |
233 | unsigned long nr_pages = end_index - index + 1; | 233 | unsigned long nr_pages = end_index - index + 1; |
234 | int i; | 234 | int i; |
235 | int ret; | 235 | int ret; |
236 | 236 | ||
237 | if (cb->errors) | ||
238 | mapping_set_error(inode->i_mapping, -EIO); | ||
239 | |||
237 | while (nr_pages > 0) { | 240 | while (nr_pages > 0) { |
238 | ret = find_get_pages_contig(inode->i_mapping, index, | 241 | ret = find_get_pages_contig(inode->i_mapping, index, |
239 | min_t(unsigned long, | 242 | min_t(unsigned long, |
@@ -244,6 +247,8 @@ static noinline void end_compressed_writeback(struct inode *inode, u64 start, | |||
244 | continue; | 247 | continue; |
245 | } | 248 | } |
246 | for (i = 0; i < ret; i++) { | 249 | for (i = 0; i < ret; i++) { |
250 | if (cb->errors) | ||
251 | SetPageError(pages[i]); | ||
247 | end_page_writeback(pages[i]); | 252 | end_page_writeback(pages[i]); |
248 | page_cache_release(pages[i]); | 253 | page_cache_release(pages[i]); |
249 | } | 254 | } |
@@ -287,10 +292,11 @@ static void end_compressed_bio_write(struct bio *bio, int err) | |||
287 | tree->ops->writepage_end_io_hook(cb->compressed_pages[0], | 292 | tree->ops->writepage_end_io_hook(cb->compressed_pages[0], |
288 | cb->start, | 293 | cb->start, |
289 | cb->start + cb->len - 1, | 294 | cb->start + cb->len - 1, |
290 | NULL, 1); | 295 | NULL, |
296 | err ? 0 : 1); | ||
291 | cb->compressed_pages[0]->mapping = NULL; | 297 | cb->compressed_pages[0]->mapping = NULL; |
292 | 298 | ||
293 | end_compressed_writeback(inode, cb->start, cb->len); | 299 | end_compressed_writeback(inode, cb); |
294 | /* note, our inode could be gone now */ | 300 | /* note, our inode could be gone now */ |
295 | 301 | ||
296 | /* | 302 | /* |