Skip to content

Commit

Permalink
writeback: Fix data corruption on NFS
Browse files Browse the repository at this point in the history
Commit 4f8ad65 "writeback: Refactor writeback_single_inode()" added
a condition to skip clean inode. However this is wrong in WB_SYNC_ALL
mode because there we also want to wait for outstanding writeback on
possibly clean inode. This was causing occasional data corruption issues
on NFS because it uses sync_inode() to make sure all outstanding writes
are flushed to the server before truncating the inode and with
sync_inode() returning prematurely file was sometimes extended back
by an outstanding write after it was truncated.

So modify the test to also check for pages under writeback in
WB_SYNC_ALL mode.

CC: stable@vger.kernel.org # >= 3.5
Fixes: 4f8ad65
Reported-and-tested-by: Dan Duval <dan.duval@oracle.com>
Signed-off-by: Jan Kara <jack@suse.cz>
  • Loading branch information
Jan Kara authored and Fengguang Wu committed Dec 13, 2013
1 parent 374b105 commit f9b0e05
Showing 1 changed file with 9 additions and 6 deletions.
15 changes: 9 additions & 6 deletions fs/fs-writeback.c
Original file line number Diff line number Diff line change
Expand Up @@ -516,13 +516,16 @@ writeback_single_inode(struct inode *inode, struct bdi_writeback *wb,
}
WARN_ON(inode->i_state & I_SYNC);
/*
* Skip inode if it is clean. We don't want to mess with writeback
* lists in this function since flusher thread may be doing for example
* sync in parallel and if we move the inode, it could get skipped. So
* here we make sure inode is on some writeback list and leave it there
* unless we have completely cleaned the inode.
* Skip inode if it is clean and we have no outstanding writeback in
* WB_SYNC_ALL mode. We don't want to mess with writeback lists in this
* function since flusher thread may be doing for example sync in
* parallel and if we move the inode, it could get skipped. So here we
* make sure inode is on some writeback list and leave it there unless
* we have completely cleaned the inode.
*/
if (!(inode->i_state & I_DIRTY))
if (!(inode->i_state & I_DIRTY) &&
(wbc->sync_mode != WB_SYNC_ALL ||
!mapping_tagged(inode->i_mapping, PAGECACHE_TAG_WRITEBACK)))
goto out;
inode->i_state |= I_SYNC;
spin_unlock(&inode->i_lock);
Expand Down

0 comments on commit f9b0e05

Please sign in to comment.