[XFS] Sleeping with the ilock waiting for I/O completion is Bad.
Recent fixes to the filesystem freezing code introduced a vn_iowait call in the middle of the sync code. Unfortunately, at the point where this call was added we are holding the ilock. The ilock is needed by I/O completion for unwritten extent conversion and now updating the file size. Hence I/o cannot complete if we hold the ilock while waiting for I/O completion. Fix up the bug and clean the code up around it. SGI-PV: 963674 SGI-Modid: xfs-linux-melb:xfs-kern:28566a Signed-off-by: David Chinner <dgc@sgi.com> Signed-off-by: Christoph Hellwig <hch@infradead.org> Signed-off-by: Tim Shimmin <tes@sgi.com>
This commit is contained in:
parent
4cc929ee30
commit
40095b64f5
|
@ -1128,58 +1128,41 @@ xfs_sync_inodes(
|
||||||
* in the inode list.
|
* in the inode list.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((flags & SYNC_CLOSE) && (vp != NULL)) {
|
/*
|
||||||
/*
|
* If we have to flush data or wait for I/O completion
|
||||||
* This is the shutdown case. We just need to
|
* we need to drop the ilock that we currently hold.
|
||||||
* flush and invalidate all the pages associated
|
* If we need to drop the lock, insert a marker if we
|
||||||
* with the inode. Drop the inode lock since
|
* have not already done so.
|
||||||
* we can't hold it across calls to the buffer
|
*/
|
||||||
* cache.
|
if ((flags & (SYNC_CLOSE|SYNC_IOWAIT)) ||
|
||||||
*
|
((flags & SYNC_DELWRI) && VN_DIRTY(vp))) {
|
||||||
* We don't set the VREMAPPING bit in the vnode
|
if (mount_locked) {
|
||||||
* here, because we don't hold the vnode lock
|
IPOINTER_INSERT(ip, mp);
|
||||||
* exclusively. It doesn't really matter, though,
|
}
|
||||||
* because we only come here when we're shutting
|
|
||||||
* down anyway.
|
|
||||||
*/
|
|
||||||
xfs_iunlock(ip, XFS_ILOCK_SHARED);
|
xfs_iunlock(ip, XFS_ILOCK_SHARED);
|
||||||
|
|
||||||
if (XFS_FORCED_SHUTDOWN(mp)) {
|
if (flags & SYNC_CLOSE) {
|
||||||
bhv_vop_toss_pages(vp, 0, -1, FI_REMAPF);
|
/* Shutdown case. Flush and invalidate. */
|
||||||
} else {
|
if (XFS_FORCED_SHUTDOWN(mp))
|
||||||
error = bhv_vop_flushinval_pages(vp, 0, -1, FI_REMAPF);
|
bhv_vop_toss_pages(vp, 0, -1, FI_REMAPF);
|
||||||
}
|
else
|
||||||
|
error = bhv_vop_flushinval_pages(vp, 0,
|
||||||
xfs_ilock(ip, XFS_ILOCK_SHARED);
|
-1, FI_REMAPF);
|
||||||
|
} else if ((flags & SYNC_DELWRI) && VN_DIRTY(vp)) {
|
||||||
} else if ((flags & SYNC_DELWRI) && (vp != NULL)) {
|
|
||||||
if (VN_DIRTY(vp)) {
|
|
||||||
/* We need to have dropped the lock here,
|
|
||||||
* so insert a marker if we have not already
|
|
||||||
* done so.
|
|
||||||
*/
|
|
||||||
if (mount_locked) {
|
|
||||||
IPOINTER_INSERT(ip, mp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Drop the inode lock since we can't hold it
|
|
||||||
* across calls to the buffer cache.
|
|
||||||
*/
|
|
||||||
xfs_iunlock(ip, XFS_ILOCK_SHARED);
|
|
||||||
error = bhv_vop_flush_pages(vp, (xfs_off_t)0,
|
error = bhv_vop_flush_pages(vp, (xfs_off_t)0,
|
||||||
-1, fflag, FI_NONE);
|
-1, fflag, FI_NONE);
|
||||||
xfs_ilock(ip, XFS_ILOCK_SHARED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When freezing, we need to wait ensure all I/O (including direct
|
||||||
|
* I/O) is complete to ensure no further data modification can take
|
||||||
|
* place after this point
|
||||||
|
*/
|
||||||
|
if (flags & SYNC_IOWAIT)
|
||||||
|
vn_iowait(vp);
|
||||||
|
|
||||||
|
xfs_ilock(ip, XFS_ILOCK_SHARED);
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* When freezing, we need to wait ensure all I/O (including direct
|
|
||||||
* I/O) is complete to ensure no further data modification can take
|
|
||||||
* place after this point
|
|
||||||
*/
|
|
||||||
if (flags & SYNC_IOWAIT)
|
|
||||||
vn_iowait(vp);
|
|
||||||
|
|
||||||
if (flags & SYNC_BDFLUSH) {
|
if (flags & SYNC_BDFLUSH) {
|
||||||
if ((flags & SYNC_ATTR) &&
|
if ((flags & SYNC_ATTR) &&
|
||||||
|
|
Loading…
Reference in New Issue