提交 a4f34404 编写于 作者: C Christoph Hellwig 提交者: Zheng Zengkai

xfs: refactor xfs_file_fsync

mainline-inclusion
from mainline-v5.11-rc4
commit f22c7f87
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I4KIAO
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f22c7f87777361f94aa17f746fbadfa499248dc8

-------------------------------------------------

Factor out the log syncing logic into two helpers to make the code easier
to read and more maintainable.
Signed-off-by: NChristoph Hellwig <hch@lst.de>
Reviewed-by: NBrian Foster <bfoster@redhat.com>
Reviewed-by: NDarrick J. Wong <djwong@kernel.org>
Signed-off-by: NDarrick J. Wong <djwong@kernel.org>
Reviewed-by: NDave Chinner <dchinner@redhat.com>
Signed-off-by: NLihong Kou <koulihong@huawei.com>
Reviewed-by: NZhang Yi <yi.zhang@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 0bab43f0
...@@ -118,6 +118,54 @@ xfs_dir_fsync( ...@@ -118,6 +118,54 @@ xfs_dir_fsync(
return xfs_log_force_inode(ip); return xfs_log_force_inode(ip);
} }
static xfs_csn_t
xfs_fsync_seq(
struct xfs_inode *ip,
bool datasync)
{
if (!xfs_ipincount(ip))
return 0;
if (datasync && !(ip->i_itemp->ili_fsync_fields & ~XFS_ILOG_TIMESTAMP))
return 0;
return ip->i_itemp->ili_commit_seq;
}
/*
* 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 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.
*/
static int
xfs_fsync_flush_log(
struct xfs_inode *ip,
bool datasync,
int *log_flushed)
{
int error = 0;
xfs_csn_t seq;
xfs_ilock(ip, XFS_ILOCK_SHARED);
seq = xfs_fsync_seq(ip, datasync);
if (seq) {
error = xfs_log_force_seq(ip->i_mount, seq, XFS_LOG_SYNC,
log_flushed);
spin_lock(&ip->i_itemp->ili_lock);
ip->i_itemp->ili_fsync_fields = 0;
spin_unlock(&ip->i_itemp->ili_lock);
}
xfs_iunlock(ip, XFS_ILOCK_SHARED);
return error;
}
STATIC int STATIC int
xfs_file_fsync( xfs_file_fsync(
struct file *file, struct file *file,
...@@ -125,13 +173,10 @@ xfs_file_fsync( ...@@ -125,13 +173,10 @@ xfs_file_fsync(
loff_t end, loff_t end,
int datasync) int datasync)
{ {
struct inode *inode = file->f_mapping->host; struct xfs_inode *ip = XFS_I(file->f_mapping->host);
struct xfs_inode *ip = XFS_I(inode);
struct xfs_inode_log_item *iip = ip->i_itemp;
struct xfs_mount *mp = ip->i_mount; struct xfs_mount *mp = ip->i_mount;
int error = 0; int error = 0;
int log_flushed = 0; int log_flushed = 0;
xfs_csn_t seq = 0;
trace_xfs_file_fsync(ip); trace_xfs_file_fsync(ip);
...@@ -155,33 +200,7 @@ xfs_file_fsync( ...@@ -155,33 +200,7 @@ xfs_file_fsync(
else if (mp->m_logdev_targp != mp->m_ddev_targp) else if (mp->m_logdev_targp != mp->m_ddev_targp)
xfs_blkdev_issue_flush(mp->m_ddev_targp); xfs_blkdev_issue_flush(mp->m_ddev_targp);
/* error = xfs_fsync_flush_log(ip, datasync, &log_flushed);
* 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 seq 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 ||
(iip->ili_fsync_fields & ~XFS_ILOG_TIMESTAMP))
seq = iip->ili_commit_seq;
}
if (seq) {
error = xfs_log_force_seq(mp, seq, XFS_LOG_SYNC, &log_flushed);
spin_lock(&iip->ili_lock);
iip->ili_fsync_fields = 0;
spin_unlock(&iip->ili_lock);
}
xfs_iunlock(ip, XFS_ILOCK_SHARED);
/* /*
* If we only have a single device, and the log force about was * If we only have a single device, and the log force about was
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册