summaryrefslogtreecommitdiffstats
path: root/fs/cifs/file.c
diff options
context:
space:
mode:
authorDave Kleikamp <shaggy@linux.vnet.ibm.com>2008-11-18 03:49:05 +0000
committerSteve French <sfrench@us.ibm.com>2008-11-18 04:30:07 +0000
commitb066a48c9532243894f93a06ca5a0ee2cc21a8dc (patch)
treedcb1aeb0e2b6a9af57479287ff4b9c94b070d0d3 /fs/cifs/file.c
parent2c55608f28444c3f33b10312881384c470ceed56 (diff)
downloadlinux-stable-b066a48c9532243894f93a06ca5a0ee2cc21a8dc.tar.gz
linux-stable-b066a48c9532243894f93a06ca5a0ee2cc21a8dc.tar.bz2
linux-stable-b066a48c9532243894f93a06ca5a0ee2cc21a8dc.zip
prevent cifs_writepages() from skipping unwritten pages
Fixes a data corruption under heavy stress in which pages could be left dirty after all open instances of a inode have been closed. In order to write contiguous pages whenever possible, cifs_writepages() asks pagevec_lookup_tag() for more pages than it may write at one time. Normally, it then resets index just past the last page written before calling pagevec_lookup_tag() again. If cifs_writepages() can't write the first page returned, it wasn't resetting index, and the next call to pagevec_lookup_tag() resulted in skipping all of the pages it previously returned, even though cifs_writepages() did nothing with them. This can result in data loss when the file descriptor is about to be closed. This patch ensures that index gets set back to the next returned page so that none get skipped. Signed-off-by: Dave Kleikamp <shaggy@linux.vnet.ibm.com> Acked-by: Jeff Layton <jlayton@redhat.com> Cc: Shirish S Pargaonkar <shirishp@us.ibm.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r--fs/cifs/file.c5
1 files changed, 4 insertions, 1 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 1540adaa593d..6449e1aae621 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1404,7 +1404,10 @@ retry:
if ((wbc->nr_to_write -= n_iov) <= 0)
done = 1;
index = next;
- }
+ } else
+ /* Need to re-find the pages we skipped */
+ index = pvec.pages[0]->index + 1;
+
pagevec_release(&pvec);
}
if (!scanned && !done) {