[PATCH] fs: fix forced iversion increment on lazytime timestamp updates

Pankaj Raghav posted 1 patch 1 month ago
fs/inode.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
[PATCH] fs: fix forced iversion increment on lazytime timestamp updates
Posted by Pankaj Raghav 1 month ago
When updating timestamps with lazytime enabled, if only I_DIRTY_TIME is
set (pure lazytime update), inode_maybe_inc_iversion() should not be
forced to increment i_version. The force parameter should only be true
when actual data or metadata changes require an iversion bump.

The current code uses "!!dirty" which evaluates to true whenever dirty
has any bits set, including the I_DIRTY_TIME bit alone. This forces an
iversion increment on every lazytime timestamp update, which then sets
I_DIRTY_SYNC, triggering expensive log flushes on subsequent fdatasync
calls. Andres reported this issue when he noticed a perf regression[1].

Fix this by using "dirty != I_DIRTY_TIME" as the force parameter. This
passes false for pure lazytime updates (allowing the I_VERSION_QUERIED
optimization to work), while still forcing the increment when dirty
contains other flags indicating real changes that require iversion
updates.

[1] https://lore.kernel.org/linux-xfs/7ys6erh3nnyeerv2nybyfvp7dmaknuxrlxv74wx56ocdothkc6@ekfiadtkfn2r/

Fixes: 85c871a02b03 ("fs: add support for non-blocking timestamp updates")
Signed-off-by: Pankaj Raghav <p.raghav@samsung.com>
---
 fs/inode.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/fs/inode.c b/fs/inode.c
index 6a3cbc7dcd28..62c579a0cf7d 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -2124,7 +2124,13 @@ static int inode_update_cmtime(struct inode *inode, unsigned int flags)
 			    inode_iversion_need_inc(inode))
 				return -EAGAIN;
 		} else {
-			if (inode_maybe_inc_iversion(inode, !!dirty))
+			/*
+			 * Don't force iversion increment for pure lazytime
+			 * updates (I_DIRTY_TIME only), let I_VERSION_QUERIED
+			 * dictate whether the increment is needed.
+			 */
+			if (inode_maybe_inc_iversion(inode,
+						     dirty != I_DIRTY_TIME))
 				dirty |= I_DIRTY_SYNC;
 		}
 	}

base-commit: 4cd074ae20bbcc293bbbce9163abe99d68ae6ae0
-- 
2.51.2
Re: [PATCH] fs: fix forced iversion increment on lazytime timestamp updates
Posted by Christian Brauner 1 month ago
On Mon, 11 May 2026 13:19:18 +0200, Pankaj Raghav wrote:
> When updating timestamps with lazytime enabled, if only I_DIRTY_TIME is
> set (pure lazytime update), inode_maybe_inc_iversion() should not be
> forced to increment i_version. The force parameter should only be true
> when actual data or metadata changes require an iversion bump.
> 
> The current code uses "!!dirty" which evaluates to true whenever dirty
> has any bits set, including the I_DIRTY_TIME bit alone. This forces an
> iversion increment on every lazytime timestamp update, which then sets
> I_DIRTY_SYNC, triggering expensive log flushes on subsequent fdatasync
> calls. Andres reported this issue when he noticed a perf regression[1].
> 
> [...]

Applied to the vfs.fixes branch of the vfs/vfs.git tree.
Patches in the vfs.fixes branch should appear in linux-next soon.

Please report any outstanding bugs that were missed during review in a
new review to the original patch series allowing us to drop it.

It's encouraged to provide Acked-bys and Reviewed-bys even though the
patch has now been applied. If possible patch trailers will be updated.

Note that commit hashes shown below are subject to change due to rebase,
trailer updates or similar. If in doubt, please check the listed branch.

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git
branch: vfs.fixes

[1/1] fs: fix forced iversion increment on lazytime timestamp updates
      https://git.kernel.org/vfs/vfs/c/834e98acb748
Re: [PATCH] fs: fix forced iversion increment on lazytime timestamp updates
Posted by Carlos Maiolino 1 month ago
On Mon, May 11, 2026 at 01:19:18PM +0200, Pankaj Raghav wrote:
> When updating timestamps with lazytime enabled, if only I_DIRTY_TIME is
> set (pure lazytime update), inode_maybe_inc_iversion() should not be
> forced to increment i_version. The force parameter should only be true
> when actual data or metadata changes require an iversion bump.
> 
> The current code uses "!!dirty" which evaluates to true whenever dirty
> has any bits set, including the I_DIRTY_TIME bit alone. This forces an
> iversion increment on every lazytime timestamp update, which then sets
> I_DIRTY_SYNC, triggering expensive log flushes on subsequent fdatasync
> calls. Andres reported this issue when he noticed a perf regression[1].
> 
> Fix this by using "dirty != I_DIRTY_TIME" as the force parameter. This
> passes false for pure lazytime updates (allowing the I_VERSION_QUERIED
> optimization to work), while still forcing the increment when dirty
> contains other flags indicating real changes that require iversion
> updates.
> 
> [1] https://lore.kernel.org/linux-xfs/7ys6erh3nnyeerv2nybyfvp7dmaknuxrlxv74wx56ocdothkc6@ekfiadtkfn2r/
> 
> Fixes: 85c871a02b03 ("fs: add support for non-blocking timestamp updates")
> Signed-off-by: Pankaj Raghav <p.raghav@samsung.com>
> ---
>  fs/inode.c | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/inode.c b/fs/inode.c
> index 6a3cbc7dcd28..62c579a0cf7d 100644
> --- a/fs/inode.c
> +++ b/fs/inode.c
> @@ -2124,7 +2124,13 @@ static int inode_update_cmtime(struct inode *inode, unsigned int flags)
>  			    inode_iversion_need_inc(inode))
>  				return -EAGAIN;
>  		} else {
> -			if (inode_maybe_inc_iversion(inode, !!dirty))
> +			/*
> +			 * Don't force iversion increment for pure lazytime
> +			 * updates (I_DIRTY_TIME only), let I_VERSION_QUERIED
> +			 * dictate whether the increment is needed.
> +			 */
> +			if (inode_maybe_inc_iversion(inode,
> +						     dirty != I_DIRTY_TIME))
>  				dirty |= I_DIRTY_SYNC;
>  		}
>  	}
> 

Looks good.
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>


> base-commit: 4cd074ae20bbcc293bbbce9163abe99d68ae6ae0
> -- 
> 2.51.2
> 
>
Re: [PATCH] fs: fix forced iversion increment on lazytime timestamp updates
Posted by Christoph Hellwig 1 month ago
Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>
Re: [PATCH] fs: fix forced iversion increment on lazytime timestamp updates
Posted by Jeff Layton 1 month ago
On Mon, 2026-05-11 at 13:19 +0200, Pankaj Raghav wrote:
> When updating timestamps with lazytime enabled, if only I_DIRTY_TIME is
> set (pure lazytime update), inode_maybe_inc_iversion() should not be
> forced to increment i_version. The force parameter should only be true
> when actual data or metadata changes require an iversion bump.
> 
> The current code uses "!!dirty" which evaluates to true whenever dirty
> has any bits set, including the I_DIRTY_TIME bit alone. This forces an
> iversion increment on every lazytime timestamp update, which then sets
> I_DIRTY_SYNC, triggering expensive log flushes on subsequent fdatasync
> calls. Andres reported this issue when he noticed a perf regression[1].
> 
> Fix this by using "dirty != I_DIRTY_TIME" as the force parameter. This
> passes false for pure lazytime updates (allowing the I_VERSION_QUERIED
> optimization to work), while still forcing the increment when dirty
> contains other flags indicating real changes that require iversion
> updates.
> 
> [1] https://lore.kernel.org/linux-xfs/7ys6erh3nnyeerv2nybyfvp7dmaknuxrlxv74wx56ocdothkc6@ekfiadtkfn2r/
> 
> Fixes: 85c871a02b03 ("fs: add support for non-blocking timestamp updates")
> Signed-off-by: Pankaj Raghav <p.raghav@samsung.com>
> ---
>  fs/inode.c | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/inode.c b/fs/inode.c
> index 6a3cbc7dcd28..62c579a0cf7d 100644
> --- a/fs/inode.c
> +++ b/fs/inode.c
> @@ -2124,7 +2124,13 @@ static int inode_update_cmtime(struct inode *inode, unsigned int flags)
>  			    inode_iversion_need_inc(inode))
>  				return -EAGAIN;
>  		} else {
> -			if (inode_maybe_inc_iversion(inode, !!dirty))
> +			/*
> +			 * Don't force iversion increment for pure lazytime
> +			 * updates (I_DIRTY_TIME only), let I_VERSION_QUERIED
> +			 * dictate whether the increment is needed.
> +			 */
> +			if (inode_maybe_inc_iversion(inode,
> +						     dirty != I_DIRTY_TIME))
>  				dirty |= I_DIRTY_SYNC;
>  		}
>  	}
> 
> base-commit: 4cd074ae20bbcc293bbbce9163abe99d68ae6ae0

Reviewed-by: Jeff Layton <jlayton@kernel.org>