|
@@ -242,19 +242,30 @@ xfs_file_fsync(
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * All metadata updates are logged, which means that we just have
|
|
|
- * to flush the log up to the latest LSN that touched the inode.
|
|
|
+ * All metadata updates are logged, which means that we just have to
|
|
|
+ * flush the log up to the latest LSN that touched the inode. If we have
|
|
|
+ * concurrent fsync/fdatasync() calls, we need them to all block on the
|
|
|
+ * log force before we clear the ili_fsync_fields field. This ensures
|
|
|
+ * that we don't get a racing sync operation that does not wait for the
|
|
|
+ * metadata to hit the journal before returning. If we race with
|
|
|
+ * clearing the ili_fsync_fields, then all that will happen is the log
|
|
|
+ * force will do nothing as the lsn will already be on disk. We can't
|
|
|
+ * race with setting ili_fsync_fields because that is done under
|
|
|
+ * XFS_ILOCK_EXCL, and that can't happen because we hold the lock shared
|
|
|
+ * until after the ili_fsync_fields is cleared.
|
|
|
*/
|
|
|
xfs_ilock(ip, XFS_ILOCK_SHARED);
|
|
|
if (xfs_ipincount(ip)) {
|
|
|
if (!datasync ||
|
|
|
- (ip->i_itemp->ili_fields & ~XFS_ILOG_TIMESTAMP))
|
|
|
+ (ip->i_itemp->ili_fsync_fields & ~XFS_ILOG_TIMESTAMP))
|
|
|
lsn = ip->i_itemp->ili_last_lsn;
|
|
|
}
|
|
|
- xfs_iunlock(ip, XFS_ILOCK_SHARED);
|
|
|
|
|
|
- if (lsn)
|
|
|
+ if (lsn) {
|
|
|
error = _xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, &log_flushed);
|
|
|
+ ip->i_itemp->ili_fsync_fields = 0;
|
|
|
+ }
|
|
|
+ xfs_iunlock(ip, XFS_ILOCK_SHARED);
|
|
|
|
|
|
/*
|
|
|
* If we only have a single device, and the log force about was
|