diff mbox series

[RFC] xfs: don't bump the i_version on an atime update in xfs_vn_update_time

Message ID 20220817130002.93592-1-jlayton@kernel.org (mailing list archive)
State New, archived
Headers show
Series [RFC] xfs: don't bump the i_version on an atime update in xfs_vn_update_time | expand

Commit Message

Jeff Layton Aug. 17, 2022, 1 p.m. UTC
xfs will update the i_version when updating only the atime value, which
is not desirable for any of the current consumers of i_version. Doing so
leads to unnecessary cache invalidations on NFS and extra measurement
activity in IMA.

Add a new XFS_ILOG_NOIVER flag, and use that to indicate that the
transaction should not update the i_version. Set that value in
xfs_vn_update_time if we're only updating the atime.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 fs/xfs/libxfs/xfs_log_format.h  |  2 +-
 fs/xfs/libxfs/xfs_trans_inode.c |  2 +-
 fs/xfs/xfs_iops.c               | 10 +++++++---
 3 files changed, 9 insertions(+), 5 deletions(-)

Dave,

How about this for an alternate approach? This just explicitly ensures
that we don't bump the i_version on an atime-only update, and seems to
fix the testcase I have.

Comments

Darrick J. Wong Aug. 18, 2022, 12:04 a.m. UTC | #1
On Wed, Aug 17, 2022 at 09:00:02AM -0400, Jeff Layton wrote:
> xfs will update the i_version when updating only the atime value, which
> is not desirable for any of the current consumers of i_version. Doing so
> leads to unnecessary cache invalidations on NFS and extra measurement
> activity in IMA.
> 
> Add a new XFS_ILOG_NOIVER flag, and use that to indicate that the
> transaction should not update the i_version. Set that value in
> xfs_vn_update_time if we're only updating the atime.

I suppose that would work, since explicit atime updates from futimens()
go through notify_change/setattr and not ->update_time.

--D

> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
>  fs/xfs/libxfs/xfs_log_format.h  |  2 +-
>  fs/xfs/libxfs/xfs_trans_inode.c |  2 +-
>  fs/xfs/xfs_iops.c               | 10 +++++++---
>  3 files changed, 9 insertions(+), 5 deletions(-)
> 
> Dave,
> 
> How about this for an alternate approach? This just explicitly ensures
> that we don't bump the i_version on an atime-only update, and seems to
> fix the testcase I have.
> 
> diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
> index b351b9dc6561..866a4c5cf70c 100644
> --- a/fs/xfs/libxfs/xfs_log_format.h
> +++ b/fs/xfs/libxfs/xfs_log_format.h
> @@ -323,7 +323,7 @@ struct xfs_inode_log_format_32 {
>  #define	XFS_ILOG_ABROOT	0x100	/* log i_af.i_broot */
>  #define XFS_ILOG_DOWNER	0x200	/* change the data fork owner on replay */
>  #define XFS_ILOG_AOWNER	0x400	/* change the attr fork owner on replay */
> -
> +#define XFS_ILOG_NOIVER	0x800	/* don't bump i_version */
>  
>  /*
>   * The timestamps are dirty, but not necessarily anything else in the inode
> diff --git a/fs/xfs/libxfs/xfs_trans_inode.c b/fs/xfs/libxfs/xfs_trans_inode.c
> index 8b5547073379..ffe6d296e7f9 100644
> --- a/fs/xfs/libxfs/xfs_trans_inode.c
> +++ b/fs/xfs/libxfs/xfs_trans_inode.c
> @@ -126,7 +126,7 @@ xfs_trans_log_inode(
>  	 * unconditionally.
>  	 */
>  	if (!test_and_set_bit(XFS_LI_DIRTY, &iip->ili_item.li_flags)) {
> -		if (IS_I_VERSION(inode) &&
> +		if (!(flags & XFS_ILOG_NOIVER) && IS_I_VERSION(inode) &&
>  		    inode_maybe_inc_iversion(inode, flags & XFS_ILOG_CORE))
>  			iversion_flags = XFS_ILOG_CORE;
>  	}
> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> index 45518b8c613c..54db85a43dfb 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -1021,7 +1021,7 @@ xfs_vn_update_time(
>  {
>  	struct xfs_inode	*ip = XFS_I(inode);
>  	struct xfs_mount	*mp = ip->i_mount;
> -	int			log_flags = XFS_ILOG_TIMESTAMP;
> +	int			log_flags = XFS_ILOG_TIMESTAMP|XFS_ILOG_NOIVER;
>  	struct xfs_trans	*tp;
>  	int			error;
>  
> @@ -1041,10 +1041,14 @@ xfs_vn_update_time(
>  		return error;
>  
>  	xfs_ilock(ip, XFS_ILOCK_EXCL);
> -	if (flags & S_CTIME)
> +	if (flags & S_CTIME) {
>  		inode->i_ctime = *now;
> -	if (flags & S_MTIME)
> +		log_flags &= ~XFS_ILOG_NOIVER;
> +	}
> +	if (flags & S_MTIME) {
>  		inode->i_mtime = *now;
> +		log_flags &= ~XFS_ILOG_NOIVER;
> +	}
>  	if (flags & S_ATIME)
>  		inode->i_atime = *now;
>  
> -- 
> 2.37.2
>
Dave Chinner Aug. 18, 2022, 1:35 a.m. UTC | #2
On Wed, Aug 17, 2022 at 09:00:02AM -0400, Jeff Layton wrote:
> xfs will update the i_version when updating only the atime value, which
> is not desirable for any of the current consumers of i_version. Doing so
> leads to unnecessary cache invalidations on NFS and extra measurement
> activity in IMA.
> 
> Add a new XFS_ILOG_NOIVER flag, and use that to indicate that the
> transaction should not update the i_version. Set that value in
> xfs_vn_update_time if we're only updating the atime.
> 
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
>  fs/xfs/libxfs/xfs_log_format.h  |  2 +-
>  fs/xfs/libxfs/xfs_trans_inode.c |  2 +-
>  fs/xfs/xfs_iops.c               | 10 +++++++---
>  3 files changed, 9 insertions(+), 5 deletions(-)
> 
> Dave,
> 
> How about this for an alternate approach? This just explicitly ensures
> that we don't bump the i_version on an atime-only update, and seems to
> fix the testcase I have.

This just duplicates lazytime functionality, only now users
can't opt-in or out.

atime update filtering is a VFS function so behaviour is common
across all filesystems. Deficiencies in VFS filtering behaviour
should not be hacked around by individual filesystems, the VFS
filtering should be fixed.

Cheers,

Dave.
diff mbox series

Patch

diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
index b351b9dc6561..866a4c5cf70c 100644
--- a/fs/xfs/libxfs/xfs_log_format.h
+++ b/fs/xfs/libxfs/xfs_log_format.h
@@ -323,7 +323,7 @@  struct xfs_inode_log_format_32 {
 #define	XFS_ILOG_ABROOT	0x100	/* log i_af.i_broot */
 #define XFS_ILOG_DOWNER	0x200	/* change the data fork owner on replay */
 #define XFS_ILOG_AOWNER	0x400	/* change the attr fork owner on replay */
-
+#define XFS_ILOG_NOIVER	0x800	/* don't bump i_version */
 
 /*
  * The timestamps are dirty, but not necessarily anything else in the inode
diff --git a/fs/xfs/libxfs/xfs_trans_inode.c b/fs/xfs/libxfs/xfs_trans_inode.c
index 8b5547073379..ffe6d296e7f9 100644
--- a/fs/xfs/libxfs/xfs_trans_inode.c
+++ b/fs/xfs/libxfs/xfs_trans_inode.c
@@ -126,7 +126,7 @@  xfs_trans_log_inode(
 	 * unconditionally.
 	 */
 	if (!test_and_set_bit(XFS_LI_DIRTY, &iip->ili_item.li_flags)) {
-		if (IS_I_VERSION(inode) &&
+		if (!(flags & XFS_ILOG_NOIVER) && IS_I_VERSION(inode) &&
 		    inode_maybe_inc_iversion(inode, flags & XFS_ILOG_CORE))
 			iversion_flags = XFS_ILOG_CORE;
 	}
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 45518b8c613c..54db85a43dfb 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -1021,7 +1021,7 @@  xfs_vn_update_time(
 {
 	struct xfs_inode	*ip = XFS_I(inode);
 	struct xfs_mount	*mp = ip->i_mount;
-	int			log_flags = XFS_ILOG_TIMESTAMP;
+	int			log_flags = XFS_ILOG_TIMESTAMP|XFS_ILOG_NOIVER;
 	struct xfs_trans	*tp;
 	int			error;
 
@@ -1041,10 +1041,14 @@  xfs_vn_update_time(
 		return error;
 
 	xfs_ilock(ip, XFS_ILOCK_EXCL);
-	if (flags & S_CTIME)
+	if (flags & S_CTIME) {
 		inode->i_ctime = *now;
-	if (flags & S_MTIME)
+		log_flags &= ~XFS_ILOG_NOIVER;
+	}
+	if (flags & S_MTIME) {
 		inode->i_mtime = *now;
+		log_flags &= ~XFS_ILOG_NOIVER;
+	}
 	if (flags & S_ATIME)
 		inode->i_atime = *now;