aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Piggin <npiggin@suse.de>2009-01-06 17:39:06 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-01-06 18:58:59 -0500
commit00266770b8b3a6a77f896ca501a0613739086832 (patch)
treee10b01330e928b6d3eaa1040560fe133ddba6654
parentbd19e012f6fd3b7309689165ea865cbb7bb88c1e (diff)
mm: write_cache_pages writepage error fix
In write_cache_pages, if ret signals a real error, but we still have some pages left in the pagevec, done would be set to 1, but the remaining pages would continue to be processed and ret will be overwritten in the process. It could easily be overwritten with success, and thus success will be returned even if there is an error. Thus the caller is told all writes succeeded, wheras in reality some did not. Fix this by bailing immediately if there is an error, and retaining the first error code. This is a data integrity bug. Signed-off-by: Nick Piggin <npiggin@suse.de> Cc: Chris Mason <chris.mason@oracle.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--mm/page-writeback.c26
1 files changed, 20 insertions, 6 deletions
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 01b9cb8ccf68..2e847cdcad0e 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -944,12 +944,26 @@ retry:
944 } 944 }
945 945
946 ret = (*writepage)(page, wbc, data); 946 ret = (*writepage)(page, wbc, data);
947 947 if (unlikely(ret)) {
948 if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE)) { 948 if (ret == AOP_WRITEPAGE_ACTIVATE) {
949 unlock_page(page); 949 unlock_page(page);
950 ret = 0; 950 ret = 0;
951 } 951 } else {
952 if (ret || (--nr_to_write <= 0)) 952 /*
953 * done_index is set past this page,
954 * so media errors will not choke
955 * background writeout for the entire
956 * file. This has consequences for
957 * range_cyclic semantics (ie. it may
958 * not be suitable for data integrity
959 * writeout).
960 */
961 done = 1;
962 break;
963 }
964 }
965
966 if (--nr_to_write <= 0)
953 done = 1; 967 done = 1;
954 if (wbc->nonblocking && bdi_write_congested(bdi)) { 968 if (wbc->nonblocking && bdi_write_congested(bdi)) {
955 wbc->encountered_congestion = 1; 969 wbc->encountered_congestion = 1;