aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunichi Nomura <j-nomura@ce.jp.nec.com>2015-11-05 21:47:23 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2015-11-05 22:34:48 -0500
commitaa750fd71c242dba02ee2034e15fbd7d0cdb2461 (patch)
treee050f066844b2e18c2618f57376ab9d576a23b54
parent21c527a3cba07f9a9ce17b3a445f110a847793e2 (diff)
mm/filemap.c: make global sync not clear error status of individual inodes
filemap_fdatawait() is a function to wait for on-going writeback to complete but also consume and clear error status of the mapping set during writeback. The latter functionality is critical for applications to detect writeback error with system calls like fsync(2)/fdatasync(2). However filemap_fdatawait() is also used by sync(2) or FIFREEZE ioctl, which don't check error status of individual mappings. As a result, fsync() may not be able to detect writeback error if events happen in the following order: Application System admin ---------------------------------------------------------- write data on page cache Run sync command writeback completes with error filemap_fdatawait() clears error fsync returns success (but the data is not on disk) This patch adds filemap_fdatawait_keep_errors() for call sites where writeback error is not handled so that they don't clear error status. Signed-off-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com> Acked-by: Andi Kleen <ak@linux.intel.com> Reviewed-by: Tejun Heo <tj@kernel.org> Cc: Fengguang Wu <fengguang.wu@gmail.com> Cc: Dave Chinner <david@fromorbit.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/fs-writeback.c7
-rw-r--r--fs/sync.c7
-rw-r--r--include/linux/fs.h1
-rw-r--r--mm/filemap.c67
4 files changed, 67 insertions, 15 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 7378169e90be..206a68b1db1a 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -2149,7 +2149,12 @@ static void wait_sb_inodes(struct super_block *sb)
2149 iput(old_inode); 2149 iput(old_inode);
2150 old_inode = inode; 2150 old_inode = inode;
2151 2151
2152 filemap_fdatawait(mapping); 2152 /*
2153 * We keep the error status of individual mapping so that
2154 * applications can catch the writeback error using fsync(2).
2155 * See filemap_fdatawait_keep_errors() for details.
2156 */
2157 filemap_fdatawait_keep_errors(mapping);
2153 2158
2154 cond_resched(); 2159 cond_resched();
2155 2160
diff --git a/fs/sync.c b/fs/sync.c
index fbc98ee62044..4ec430ae2b0d 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -86,7 +86,12 @@ static void fdatawrite_one_bdev(struct block_device *bdev, void *arg)
86 86
87static void fdatawait_one_bdev(struct block_device *bdev, void *arg) 87static void fdatawait_one_bdev(struct block_device *bdev, void *arg)
88{ 88{
89 filemap_fdatawait(bdev->bd_inode->i_mapping); 89 /*
90 * We keep the error status of individual mapping so that
91 * applications can catch the writeback error using fsync(2).
92 * See filemap_fdatawait_keep_errors() for details.
93 */
94 filemap_fdatawait_keep_errors(bdev->bd_inode->i_mapping);
90} 95}
91 96
92/* 97/*
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 72d8a844c692..9355f377fd46 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2422,6 +2422,7 @@ extern int write_inode_now(struct inode *, int);
2422extern int filemap_fdatawrite(struct address_space *); 2422extern int filemap_fdatawrite(struct address_space *);
2423extern int filemap_flush(struct address_space *); 2423extern int filemap_flush(struct address_space *);
2424extern int filemap_fdatawait(struct address_space *); 2424extern int filemap_fdatawait(struct address_space *);
2425extern void filemap_fdatawait_keep_errors(struct address_space *);
2425extern int filemap_fdatawait_range(struct address_space *, loff_t lstart, 2426extern int filemap_fdatawait_range(struct address_space *, loff_t lstart,
2426 loff_t lend); 2427 loff_t lend);
2427extern int filemap_write_and_wait(struct address_space *mapping); 2428extern int filemap_write_and_wait(struct address_space *mapping);
diff --git a/mm/filemap.c b/mm/filemap.c
index 1fe962b49f31..884766da1165 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -331,23 +331,14 @@ int filemap_flush(struct address_space *mapping)
331} 331}
332EXPORT_SYMBOL(filemap_flush); 332EXPORT_SYMBOL(filemap_flush);
333 333
334/** 334static int __filemap_fdatawait_range(struct address_space *mapping,
335 * filemap_fdatawait_range - wait for writeback to complete 335 loff_t start_byte, loff_t end_byte)
336 * @mapping: address space structure to wait for
337 * @start_byte: offset in bytes where the range starts
338 * @end_byte: offset in bytes where the range ends (inclusive)
339 *
340 * Walk the list of under-writeback pages of the given address space
341 * in the given range and wait for all of them.
342 */
343int filemap_fdatawait_range(struct address_space *mapping, loff_t start_byte,
344 loff_t end_byte)
345{ 336{
346 pgoff_t index = start_byte >> PAGE_CACHE_SHIFT; 337 pgoff_t index = start_byte >> PAGE_CACHE_SHIFT;
347 pgoff_t end = end_byte >> PAGE_CACHE_SHIFT; 338 pgoff_t end = end_byte >> PAGE_CACHE_SHIFT;
348 struct pagevec pvec; 339 struct pagevec pvec;
349 int nr_pages; 340 int nr_pages;
350 int ret2, ret = 0; 341 int ret = 0;
351 342
352 if (end_byte < start_byte) 343 if (end_byte < start_byte)
353 goto out; 344 goto out;
@@ -374,6 +365,29 @@ int filemap_fdatawait_range(struct address_space *mapping, loff_t start_byte,
374 cond_resched(); 365 cond_resched();
375 } 366 }
376out: 367out:
368 return ret;
369}
370
371/**
372 * filemap_fdatawait_range - wait for writeback to complete
373 * @mapping: address space structure to wait for
374 * @start_byte: offset in bytes where the range starts
375 * @end_byte: offset in bytes where the range ends (inclusive)
376 *
377 * Walk the list of under-writeback pages of the given address space
378 * in the given range and wait for all of them. Check error status of
379 * the address space and return it.
380 *
381 * Since the error status of the address space is cleared by this function,
382 * callers are responsible for checking the return value and handling and/or
383 * reporting the error.
384 */
385int filemap_fdatawait_range(struct address_space *mapping, loff_t start_byte,
386 loff_t end_byte)
387{
388 int ret, ret2;
389
390 ret = __filemap_fdatawait_range(mapping, start_byte, end_byte);
377 ret2 = filemap_check_errors(mapping); 391 ret2 = filemap_check_errors(mapping);
378 if (!ret) 392 if (!ret)
379 ret = ret2; 393 ret = ret2;
@@ -383,11 +397,38 @@ out:
383EXPORT_SYMBOL(filemap_fdatawait_range); 397EXPORT_SYMBOL(filemap_fdatawait_range);
384 398
385/** 399/**
400 * filemap_fdatawait_keep_errors - wait for writeback without clearing errors
401 * @mapping: address space structure to wait for
402 *
403 * Walk the list of under-writeback pages of the given address space
404 * and wait for all of them. Unlike filemap_fdatawait(), this function
405 * does not clear error status of the address space.
406 *
407 * Use this function if callers don't handle errors themselves. Expected
408 * call sites are system-wide / filesystem-wide data flushers: e.g. sync(2),
409 * fsfreeze(8)
410 */
411void filemap_fdatawait_keep_errors(struct address_space *mapping)
412{
413 loff_t i_size = i_size_read(mapping->host);
414
415 if (i_size == 0)
416 return;
417
418 __filemap_fdatawait_range(mapping, 0, i_size - 1);
419}
420
421/**
386 * filemap_fdatawait - wait for all under-writeback pages to complete 422 * filemap_fdatawait - wait for all under-writeback pages to complete
387 * @mapping: address space structure to wait for 423 * @mapping: address space structure to wait for
388 * 424 *
389 * Walk the list of under-writeback pages of the given address space 425 * Walk the list of under-writeback pages of the given address space
390 * and wait for all of them. 426 * and wait for all of them. Check error status of the address space
427 * and return it.
428 *
429 * Since the error status of the address space is cleared by this function,
430 * callers are responsible for checking the return value and handling and/or
431 * reporting the error.
391 */ 432 */
392int filemap_fdatawait(struct address_space *mapping) 433int filemap_fdatawait(struct address_space *mapping)
393{ 434{