aboutsummaryrefslogtreecommitdiffstats
path: root/fs/buffer.c
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2017-07-06 07:02:21 -0400
committerJeff Layton <jlayton@redhat.com>2017-07-06 07:02:21 -0400
commit87354e5de04fe727227ff619af164202adcfa4d4 (patch)
tree1cde8e4890ca73ce6513c19c48c151e20b867433 /fs/buffer.c
parentdac257f7419c732be3e491bbbb568a82df60208a (diff)
buffer: set errors in mapping at the time that the error occurs
I noticed on xfs that I could still sometimes get back an error on fsync on a fd that was opened after the error condition had been cleared. The problem is that the buffer code sets the write_io_error flag and then later checks that flag to set the error in the mapping. That flag perisists for quite a while however. If the file is later opened with O_TRUNC, the buffers will then be invalidated and the mapping's error set such that a subsequent fsync will return error. I think this is incorrect, as there was no writeback between the open and fsync. Add a new mark_buffer_write_io_error operation that sets the flag and the error in the mapping at the same time. Replace all calls to set_buffer_write_io_error with mark_buffer_write_io_error, and remove the places that check this flag in order to set the error in the mapping. This sets the error in the mapping earlier, at the time that it's first detected. Signed-off-by: Jeff Layton <jlayton@redhat.com> Reviewed-by: Jan Kara <jack@suse.cz> Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
Diffstat (limited to 'fs/buffer.c')
-rw-r--r--fs/buffer.c20
1 files changed, 13 insertions, 7 deletions
diff --git a/fs/buffer.c b/fs/buffer.c
index 4be8b914a222..b946149e8214 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -178,7 +178,7 @@ void end_buffer_write_sync(struct buffer_head *bh, int uptodate)
178 set_buffer_uptodate(bh); 178 set_buffer_uptodate(bh);
179 } else { 179 } else {
180 buffer_io_error(bh, ", lost sync page write"); 180 buffer_io_error(bh, ", lost sync page write");
181 set_buffer_write_io_error(bh); 181 mark_buffer_write_io_error(bh);
182 clear_buffer_uptodate(bh); 182 clear_buffer_uptodate(bh);
183 } 183 }
184 unlock_buffer(bh); 184 unlock_buffer(bh);
@@ -352,8 +352,7 @@ void end_buffer_async_write(struct buffer_head *bh, int uptodate)
352 set_buffer_uptodate(bh); 352 set_buffer_uptodate(bh);
353 } else { 353 } else {
354 buffer_io_error(bh, ", lost async page write"); 354 buffer_io_error(bh, ", lost async page write");
355 mapping_set_error(page->mapping, -EIO); 355 mark_buffer_write_io_error(bh);
356 set_buffer_write_io_error(bh);
357 clear_buffer_uptodate(bh); 356 clear_buffer_uptodate(bh);
358 SetPageError(page); 357 SetPageError(page);
359 } 358 }
@@ -481,8 +480,6 @@ static void __remove_assoc_queue(struct buffer_head *bh)
481{ 480{
482 list_del_init(&bh->b_assoc_buffers); 481 list_del_init(&bh->b_assoc_buffers);
483 WARN_ON(!bh->b_assoc_map); 482 WARN_ON(!bh->b_assoc_map);
484 if (buffer_write_io_error(bh))
485 mapping_set_error(bh->b_assoc_map, -EIO);
486 bh->b_assoc_map = NULL; 483 bh->b_assoc_map = NULL;
487} 484}
488 485
@@ -1181,6 +1178,17 @@ void mark_buffer_dirty(struct buffer_head *bh)
1181} 1178}
1182EXPORT_SYMBOL(mark_buffer_dirty); 1179EXPORT_SYMBOL(mark_buffer_dirty);
1183 1180
1181void mark_buffer_write_io_error(struct buffer_head *bh)
1182{
1183 set_buffer_write_io_error(bh);
1184 /* FIXME: do we need to set this in both places? */
1185 if (bh->b_page && bh->b_page->mapping)
1186 mapping_set_error(bh->b_page->mapping, -EIO);
1187 if (bh->b_assoc_map)
1188 mapping_set_error(bh->b_assoc_map, -EIO);
1189}
1190EXPORT_SYMBOL(mark_buffer_write_io_error);
1191
1184/* 1192/*
1185 * Decrement a buffer_head's reference count. If all buffers against a page 1193 * Decrement a buffer_head's reference count. If all buffers against a page
1186 * have zero reference count, are clean and unlocked, and if the page is clean 1194 * have zero reference count, are clean and unlocked, and if the page is clean
@@ -3279,8 +3287,6 @@ drop_buffers(struct page *page, struct buffer_head **buffers_to_free)
3279 3287
3280 bh = head; 3288 bh = head;
3281 do { 3289 do {
3282 if (buffer_write_io_error(bh) && page->mapping)
3283 mapping_set_error(page->mapping, -EIO);
3284 if (buffer_busy(bh)) 3290 if (buffer_busy(bh))
3285 goto failed; 3291 goto failed;
3286 bh = bh->b_this_page; 3292 bh = bh->b_this_page;