diff --git a/fs/xfs/xfs_export.c b/fs/xfs/xfs_export.c index 9afda52ed1a2..9dd6dd8c27c8 100644 --- a/fs/xfs/xfs_export.c +++ b/fs/xfs/xfs_export.c @@ -234,7 +234,7 @@ STATIC int xfs_fs_nfs_commit_metadata( struct inode *inode) { - return xfs_log_force_inode(XFS_I(inode)); + return xfs_log_force_inode(XFS_I(inode), false, NULL); } const struct export_operations xfs_export_operations = { diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index d2a2124bff54..396aca8c66a9 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -76,49 +76,7 @@ xfs_dir_fsync( struct xfs_inode *ip = XFS_I(file->f_mapping->host); trace_xfs_dir_fsync(ip); - return xfs_log_force_inode(ip); -} - -/* - * All metadata updates are logged, which means that we just have to push the - * journal to the required sequence number than holds the updates. We track - * datasync commits separately to full sync commits, and hence only need to - * select the correct sequence number for the log force here. - * - * We don't have to serialise against concurrent modifications, as we do not - * have to wait for modifications that have not yet completed. We define a - * transaction commit as completing when the commit sequence number is updated, - * hence if the sequence number has not updated, the sync operation has been - * run before the commit completed and we don't have to wait for it. - * - * If we have concurrent fsync/fdatasync() calls, the sequence numbers remain - * set on the log item until - at least - the journal flush completes. In - * reality, they are only cleared when the inode is fully unpinned (i.e. - * persistent in the journal and not dirty in the CIL), and so we rely on - * xfs_log_force_seq() either skipping sequences that have been persisted or - * waiting on sequences that are still in flight to correctly order concurrent - * sync operations. - */ -static int -xfs_fsync_flush_log( - struct xfs_inode *ip, - bool datasync, - int *log_flushed) -{ - struct xfs_inode_log_item *iip = ip->i_itemp; - xfs_csn_t seq = 0; - - spin_lock(&iip->ili_lock); - if (datasync) - seq = iip->ili_datasync_seq; - else - seq = iip->ili_commit_seq; - spin_unlock(&iip->ili_lock); - - if (!seq) - return 0; - - return xfs_log_force_seq(ip->i_mount, seq, XFS_LOG_SYNC, log_flushed); + return xfs_log_force_inode(ip, false, NULL); } STATIC int @@ -151,7 +109,7 @@ xfs_file_fsync( * no modifications to this inode that need to be pushed out. */ if (ip->i_itemp) { - error = xfs_fsync_flush_log(ip, datasync, &log_flushed); + error = xfs_log_force_inode(ip, datasync, &log_flushed); if (error) return error; } @@ -1600,7 +1558,7 @@ __xfs_file_fallocate( } if (!error && xfs_file_sync_writes(file)) - error = xfs_log_force_inode(ip); + error = xfs_log_force_inode(ip, false, NULL); out_unlock: xfs_iunlock(ip, iolock); @@ -1751,7 +1709,7 @@ xfs_file_remap_range( goto out_unlock; if (xfs_file_sync_writes(file_in) || xfs_file_sync_writes(file_out)) - xfs_log_force_inode(dest); + xfs_log_force_inode(dest, false, NULL); out_unlock: xfs_iunlock2_remapping(src, dest); if (ret) diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index fceedb699bcf..cb61305e4b80 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -2678,11 +2678,36 @@ xfs_irele( } /* - * Ensure all committed transactions touching the inode are written to the log. + * Ensure all committed transactions touching the inode are written to the log, + * or with @datasync only those that fdatasync has to wait for. + * + * All metadata updates are logged, which means that we just have to push the + * journal to the required sequence number that holds the updates. We track + * datasync commits separately to full sync commits, and hence only need to + * select the correct sequence number for the log force here. + * + * We don't have to serialise against concurrent modifications, as we do not + * have to wait for modifications that have not yet completed. We define a + * transaction commit as completing when the commit sequence number is updated, + * hence if the sequence number has not updated, the sync operation has been + * run before the commit completed and we don't have to wait for it. + * + * If we have concurrent fsync/fdatasync() calls, the sequence numbers remain + * set on the log item until - at least - the journal flush completes. In + * reality, they are only cleared when the inode is fully unpinned (i.e. + * persistent in the journal and not dirty in the CIL), and so we rely on + * xfs_log_force_seq() either skipping sequences that have been persisted or + * waiting on sequences that are still in flight to correctly order concurrent + * sync operations. + * + * If @log_flushed is not NULL, it is set when the log force wrote an iclog, + * which flushes the device caches before the log write. */ int xfs_log_force_inode( - struct xfs_inode *ip) + struct xfs_inode *ip, + bool datasync, + int *log_flushed) { struct xfs_inode_log_item *iip = ip->i_itemp; xfs_csn_t seq = 0; @@ -2691,12 +2716,15 @@ xfs_log_force_inode( return 0; spin_lock(&iip->ili_lock); - seq = iip->ili_commit_seq; + if (datasync) + seq = iip->ili_datasync_seq; + else + seq = iip->ili_commit_seq; spin_unlock(&iip->ili_lock); if (!seq) return 0; - return xfs_log_force_seq(ip->i_mount, seq, XFS_LOG_SYNC, NULL); + return xfs_log_force_seq(ip->i_mount, seq, XFS_LOG_SYNC, log_flushed); } /* diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 75eff68c1e39..b16eee99b567 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -595,7 +595,8 @@ int xfs_ifree(struct xfs_trans *, struct xfs_inode *); int xfs_itruncate_extents_flags(struct xfs_trans **, struct xfs_inode *, int, xfs_fsize_t, int); -int xfs_log_force_inode(struct xfs_inode *ip); +int xfs_log_force_inode(struct xfs_inode *ip, bool datasync, + int *log_flushed); void xfs_iunpin_wait(xfs_inode_t *); #define xfs_ipincount(ip) ((unsigned int) atomic_read(&ip->i_pincount)) diff --git a/fs/xfs/xfs_pnfs.c b/fs/xfs/xfs_pnfs.c index c1a6409f0092..f4c4a02e5c9a 100644 --- a/fs/xfs/xfs_pnfs.c +++ b/fs/xfs/xfs_pnfs.c @@ -118,7 +118,7 @@ xfs_fs_map_update_inode( * Force the log so that the blocks handed out to the client are * guaranteed to be present even after a server crash. */ - return xfs_log_force_inode(ip); + return xfs_log_force_inode(ip, false, NULL); } /* diff --git a/fs/xfs/xfs_zone_gc.c b/fs/xfs/xfs_zone_gc.c index 54b70ed2922f..cea5447a886d 100644 --- a/fs/xfs/xfs_zone_gc.c +++ b/fs/xfs/xfs_zone_gc.c @@ -1018,7 +1018,7 @@ xfs_zone_gc_reset_zones( struct xfs_gc_bio *chunk; struct bio *bio; - xfs_log_force_inode(rtg_rmap(rtg)); + xfs_log_force_inode(rtg_rmap(rtg), false, NULL); next = rtg_group(rtg)->xg_next_reset; rtg_group(rtg)->xg_next_reset = NULL;