aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Chinner <dgc@sgi.com>2007-05-14 04:24:09 -0400
committerTim Shimmin <tes@chook.melbourne.sgi.com>2007-07-14 01:22:18 -0400
commit40095b64f5da601a8ab61fbe4b40feb46830052e (patch)
tree114402c9280f5677bf1d47f4a933847912e3c314
parent4cc929ee305c69573cb842aade059dbe2a93940c (diff)
[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>
-rw-r--r--fs/xfs/xfs_vfsops.c73
1 files changed, 28 insertions, 45 deletions
diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c
index 65c561201cb8..92c1425d06ce 100644
--- a/fs/xfs/xfs_vfsops.c
+++ b/fs/xfs/xfs_vfsops.c
@@ -1128,58 +1128,41 @@ xfs_sync_inodes(
1128 * in the inode list. 1128 * in the inode list.
1129 */ 1129 */
1130 1130
1131 if ((flags & SYNC_CLOSE) && (vp != NULL)) { 1131 /*
1132 /* 1132 * If we have to flush data or wait for I/O completion
1133 * This is the shutdown case. We just need to 1133 * we need to drop the ilock that we currently hold.
1134 * flush and invalidate all the pages associated 1134 * If we need to drop the lock, insert a marker if we
1135 * with the inode. Drop the inode lock since 1135 * have not already done so.
1136 * we can't hold it across calls to the buffer 1136 */
1137 * cache. 1137 if ((flags & (SYNC_CLOSE|SYNC_IOWAIT)) ||
1138 * 1138 ((flags & SYNC_DELWRI) && VN_DIRTY(vp))) {
1139 * We don't set the VREMAPPING bit in the vnode 1139 if (mount_locked) {
1140 * here, because we don't hold the vnode lock 1140 IPOINTER_INSERT(ip, mp);
1141 * exclusively. It doesn't really matter, though,
1142 * because we only come here when we're shutting
1143 * down anyway.
1144 */
1145 xfs_iunlock(ip, XFS_ILOCK_SHARED);
1146
1147 if (XFS_FORCED_SHUTDOWN(mp)) {
1148 bhv_vop_toss_pages(vp, 0, -1, FI_REMAPF);
1149 } else {
1150 error = bhv_vop_flushinval_pages(vp, 0, -1, FI_REMAPF);
1151 } 1141 }
1142 xfs_iunlock(ip, XFS_ILOCK_SHARED);
1152 1143
1153 xfs_ilock(ip, XFS_ILOCK_SHARED); 1144 if (flags & SYNC_CLOSE) {
1154 1145 /* Shutdown case. Flush and invalidate. */
1155 } else if ((flags & SYNC_DELWRI) && (vp != NULL)) { 1146 if (XFS_FORCED_SHUTDOWN(mp))
1156 if (VN_DIRTY(vp)) { 1147 bhv_vop_toss_pages(vp, 0, -1, FI_REMAPF);
1157 /* We need to have dropped the lock here, 1148 else
1158 * so insert a marker if we have not already 1149 error = bhv_vop_flushinval_pages(vp, 0,
1159 * done so. 1150 -1, FI_REMAPF);
1160 */ 1151 } else if ((flags & SYNC_DELWRI) && VN_DIRTY(vp)) {
1161 if (mount_locked) {
1162 IPOINTER_INSERT(ip, mp);
1163 }
1164
1165 /*
1166 * Drop the inode lock since we can't hold it
1167 * across calls to the buffer cache.
1168 */
1169 xfs_iunlock(ip, XFS_ILOCK_SHARED);
1170 error = bhv_vop_flush_pages(vp, (xfs_off_t)0, 1152 error = bhv_vop_flush_pages(vp, (xfs_off_t)0,
1171 -1, fflag, FI_NONE); 1153 -1, fflag, FI_NONE);
1172 xfs_ilock(ip, XFS_ILOCK_SHARED);
1173 } 1154 }
1174 1155
1156 /*
1157 * When freezing, we need to wait ensure all I/O (including direct
1158 * I/O) is complete to ensure no further data modification can take
1159 * place after this point
1160 */
1161 if (flags & SYNC_IOWAIT)
1162 vn_iowait(vp);
1163
1164 xfs_ilock(ip, XFS_ILOCK_SHARED);
1175 } 1165 }
1176 /*
1177 * When freezing, we need to wait ensure all I/O (including direct
1178 * I/O) is complete to ensure no further data modification can take
1179 * place after this point
1180 */
1181 if (flags & SYNC_IOWAIT)
1182 vn_iowait(vp);
1183 1166
1184 if (flags & SYNC_BDFLUSH) { 1167 if (flags & SYNC_BDFLUSH) {
1185 if ((flags & SYNC_ATTR) && 1168 if ((flags & SYNC_ATTR) &&