|
|
|
@ -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; |
|
|
|
|
} |
|
|
|
|