Skip to content

Commit 7d839e3

Browse files
author
Darrick J. Wong
committed
xfs: check return codes when flushing block devices
If a blkdev_issue_flush fails, fsync needs to report that to upper levels. Modify xfs_file_fsync to capture the errors, while trying to flush as much data and log updates to disk as possible. If log writes cannot flush the data device, we need to shut down the log immediately because we've violated a log invariant. Modify this code to check the return value of blkdev_issue_flush as well. This behavior seems to go back to about 2.6.15 or so, which makes this fixes tag a bit misleading. Link: https://elixir.bootlin.com/linux/v2.6.15/source/fs/xfs/xfs_vnodeops.c#L1187 Fixes: b5071ad ("xfs: remove xfs_blkdev_issue_flush") Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com>
1 parent 5e9466a commit 7d839e3

File tree

2 files changed

+24
-10
lines changed

2 files changed

+24
-10
lines changed

fs/xfs/xfs_file.c

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ xfs_file_fsync(
142142
{
143143
struct xfs_inode *ip = XFS_I(file->f_mapping->host);
144144
struct xfs_mount *mp = ip->i_mount;
145-
int error = 0;
145+
int error, err2;
146146
int log_flushed = 0;
147147

148148
trace_xfs_file_fsync(ip);
@@ -163,18 +163,21 @@ xfs_file_fsync(
163163
* inode size in case of an extending write.
164164
*/
165165
if (XFS_IS_REALTIME_INODE(ip))
166-
blkdev_issue_flush(mp->m_rtdev_targp->bt_bdev);
166+
error = blkdev_issue_flush(mp->m_rtdev_targp->bt_bdev);
167167
else if (mp->m_logdev_targp != mp->m_ddev_targp)
168-
blkdev_issue_flush(mp->m_ddev_targp->bt_bdev);
168+
error = blkdev_issue_flush(mp->m_ddev_targp->bt_bdev);
169169

170170
/*
171171
* Any inode that has dirty modifications in the log is pinned. The
172-
* racy check here for a pinned inode while not catch modifications
172+
* racy check here for a pinned inode will not catch modifications
173173
* that happen concurrently to the fsync call, but fsync semantics
174174
* only require to sync previously completed I/O.
175175
*/
176-
if (xfs_ipincount(ip))
177-
error = xfs_fsync_flush_log(ip, datasync, &log_flushed);
176+
if (xfs_ipincount(ip)) {
177+
err2 = xfs_fsync_flush_log(ip, datasync, &log_flushed);
178+
if (err2 && !error)
179+
error = err2;
180+
}
178181

179182
/*
180183
* If we only have a single device, and the log force about was
@@ -184,8 +187,11 @@ xfs_file_fsync(
184187
* commit.
185188
*/
186189
if (!log_flushed && !XFS_IS_REALTIME_INODE(ip) &&
187-
mp->m_logdev_targp == mp->m_ddev_targp)
188-
blkdev_issue_flush(mp->m_ddev_targp->bt_bdev);
190+
mp->m_logdev_targp == mp->m_ddev_targp) {
191+
err2 = blkdev_issue_flush(mp->m_ddev_targp->bt_bdev);
192+
if (err2 && !error)
193+
error = err2;
194+
}
189195

190196
return error;
191197
}

fs/xfs/xfs_log.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1925,9 +1925,17 @@ xlog_write_iclog(
19251925
* device cache first to ensure all metadata writeback covered
19261926
* by the LSN in this iclog is on stable storage. This is slow,
19271927
* but it *must* complete before we issue the external log IO.
1928+
*
1929+
* If the flush fails, we cannot conclude that past metadata
1930+
* writeback from the log succeeded. Repeating the flush is
1931+
* not possible, hence we must shut down with log IO error to
1932+
* avoid shutdown re-entering this path and erroring out again.
19281933
*/
1929-
if (log->l_targ != log->l_mp->m_ddev_targp)
1930-
blkdev_issue_flush(log->l_mp->m_ddev_targp->bt_bdev);
1934+
if (log->l_targ != log->l_mp->m_ddev_targp &&
1935+
blkdev_issue_flush(log->l_mp->m_ddev_targp->bt_bdev)) {
1936+
xlog_force_shutdown(log, SHUTDOWN_LOG_IO_ERROR);
1937+
return;
1938+
}
19311939
}
19321940
if (iclog->ic_flags & XLOG_ICL_NEED_FUA)
19331941
iclog->ic_bio.bi_opf |= REQ_FUA;

0 commit comments

Comments
 (0)