writeback: Fix data corruption on NFS
Commit4f8ad655db
"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:4f8ad655db
Reported-and-tested-by: Dan Duval <dan.duval@oracle.com> Signed-off-by: Jan Kara <jack@suse.cz>
This commit is contained in:
Родитель
374b105797
Коммит
f9b0e058cb
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче