|
@@ -131,19 +131,34 @@ xfs_file_fsync(
|
|
|
{
|
|
|
struct inode *inode = file->f_mapping->host;
|
|
|
struct xfs_inode *ip = XFS_I(inode);
|
|
|
+ struct xfs_mount *mp = ip->i_mount;
|
|
|
struct xfs_trans *tp;
|
|
|
int error = 0;
|
|
|
int log_flushed = 0;
|
|
|
|
|
|
trace_xfs_file_fsync(ip);
|
|
|
|
|
|
- if (XFS_FORCED_SHUTDOWN(ip->i_mount))
|
|
|
+ if (XFS_FORCED_SHUTDOWN(mp))
|
|
|
return -XFS_ERROR(EIO);
|
|
|
|
|
|
xfs_iflags_clear(ip, XFS_ITRUNCATED);
|
|
|
|
|
|
xfs_ioend_wait(ip);
|
|
|
|
|
|
+ if (mp->m_flags & XFS_MOUNT_BARRIER) {
|
|
|
+ /*
|
|
|
+ * If we have an RT and/or log subvolume we need to make sure
|
|
|
+ * to flush the write cache the device used for file data
|
|
|
+ * first. This is to ensure newly written file data make
|
|
|
+ * it to disk before logging the new inode size in case of
|
|
|
+ * an extending write.
|
|
|
+ */
|
|
|
+ if (XFS_IS_REALTIME_INODE(ip))
|
|
|
+ xfs_blkdev_issue_flush(mp->m_rtdev_targp);
|
|
|
+ else if (mp->m_logdev_targp != mp->m_ddev_targp)
|
|
|
+ xfs_blkdev_issue_flush(mp->m_ddev_targp);
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* We always need to make sure that the required inode state is safe on
|
|
|
* disk. The inode might be clean but we still might need to force the
|
|
@@ -175,9 +190,9 @@ xfs_file_fsync(
|
|
|
* updates. The sync transaction will also force the log.
|
|
|
*/
|
|
|
xfs_iunlock(ip, XFS_ILOCK_SHARED);
|
|
|
- tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_FSYNC_TS);
|
|
|
+ tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
|
|
|
error = xfs_trans_reserve(tp, 0,
|
|
|
- XFS_FSYNC_TS_LOG_RES(ip->i_mount), 0, 0, 0);
|
|
|
+ XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
|
|
|
if (error) {
|
|
|
xfs_trans_cancel(tp, 0);
|
|
|
return -error;
|
|
@@ -209,28 +224,25 @@ xfs_file_fsync(
|
|
|
* force the log.
|
|
|
*/
|
|
|
if (xfs_ipincount(ip)) {
|
|
|
- error = _xfs_log_force_lsn(ip->i_mount,
|
|
|
+ error = _xfs_log_force_lsn(mp,
|
|
|
ip->i_itemp->ili_last_lsn,
|
|
|
XFS_LOG_SYNC, &log_flushed);
|
|
|
}
|
|
|
xfs_iunlock(ip, XFS_ILOCK_SHARED);
|
|
|
}
|
|
|
|
|
|
- if (ip->i_mount->m_flags & XFS_MOUNT_BARRIER) {
|
|
|
- /*
|
|
|
- * If the log write didn't issue an ordered tag we need
|
|
|
- * to flush the disk cache for the data device now.
|
|
|
- */
|
|
|
- if (!log_flushed)
|
|
|
- xfs_blkdev_issue_flush(ip->i_mount->m_ddev_targp);
|
|
|
-
|
|
|
- /*
|
|
|
- * If this inode is on the RT dev we need to flush that
|
|
|
- * cache as well.
|
|
|
- */
|
|
|
- if (XFS_IS_REALTIME_INODE(ip))
|
|
|
- xfs_blkdev_issue_flush(ip->i_mount->m_rtdev_targp);
|
|
|
- }
|
|
|
+ /*
|
|
|
+ * If we only have a single device, and the log force about was
|
|
|
+ * a no-op we might have to flush the data device cache here.
|
|
|
+ * This can only happen for fdatasync/O_DSYNC if we were overwriting
|
|
|
+ * an already allocated file and thus do not have any metadata to
|
|
|
+ * commit.
|
|
|
+ */
|
|
|
+ if ((mp->m_flags & XFS_MOUNT_BARRIER) &&
|
|
|
+ mp->m_logdev_targp == mp->m_ddev_targp &&
|
|
|
+ !XFS_IS_REALTIME_INODE(ip) &&
|
|
|
+ !log_flushed)
|
|
|
+ xfs_blkdev_issue_flush(mp->m_ddev_targp);
|
|
|
|
|
|
return -error;
|
|
|
}
|