Commit 00266770b8b3a6a77f896ca501a0613739086832

Authored by Nick Piggin
Committed by Linus Torvalds
1 parent bd19e012f6

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>

Showing 1 changed file with 20 additions and 6 deletions Side-by-side Diff

... ... @@ -944,12 +944,26 @@
944 944 }
945 945  
946 946 ret = (*writepage)(page, wbc, data);
  947 + if (unlikely(ret)) {
  948 + if (ret == AOP_WRITEPAGE_ACTIVATE) {
  949 + unlock_page(page);
  950 + ret = 0;
  951 + } else {
  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 + }
947 965  
948   - if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE)) {
949   - unlock_page(page);
950   - ret = 0;
951   - }
952   - if (ret || (--nr_to_write <= 0))
  966 + if (--nr_to_write <= 0)
953 967 done = 1;
954 968 if (wbc->nonblocking && bdi_write_congested(bdi)) {
955 969 wbc->encountered_congestion = 1;