* [PATCH 01/16] fs: refactor file timestamp update logic
2025-11-20 6:47 re-enable IOCB_NOWAIT writes to files v2 Christoph Hellwig
@ 2025-11-20 6:47 ` Christoph Hellwig
2025-11-20 6:47 ` [PATCH 02/16] fs: lift the FMODE_NOCMTIME check into file_update_time_flags Christoph Hellwig
` (14 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Christoph Hellwig @ 2025-11-20 6:47 UTC (permalink / raw)
To: Christian Brauner
Cc: Al Viro, David Sterba, Jan Kara, Mike Marshall,
Martin Brandenburg, Carlos Maiolino, Stefan Roesch, Jeff Layton,
linux-kernel, linux-btrfs, linux-fsdevel, gfs2, io-uring, devel,
linux-unionfs, linux-mtd, linux-xfs, linux-nfs,
Chaitanya Kulkarni
Currently the two high-level APIs use two helper functions to implement
almost all of the logic. Refactor the two helpers and the common logic
into a new file_update_time_flags routine that gets the iocb flags or
0 in case of file_update_time passed so that the entire logic is
contained in a single function and can be easily understood and modified.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
---
fs/inode.c | 54 +++++++++++++++++-------------------------------------
1 file changed, 17 insertions(+), 37 deletions(-)
diff --git a/fs/inode.c b/fs/inode.c
index cff1d3af0d57..540f4a28c202 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -2322,10 +2322,12 @@ struct timespec64 current_time(struct inode *inode)
}
EXPORT_SYMBOL(current_time);
-static int inode_needs_update_time(struct inode *inode)
+static int file_update_time_flags(struct file *file, unsigned int flags)
{
+ struct inode *inode = file_inode(file);
struct timespec64 now, ts;
- int sync_it = 0;
+ int sync_mode = 0;
+ int ret = 0;
/* First try to exhaust all avenues to not sync */
if (IS_NOCMTIME(inode))
@@ -2335,29 +2337,23 @@ static int inode_needs_update_time(struct inode *inode)
ts = inode_get_mtime(inode);
if (!timespec64_equal(&ts, &now))
- sync_it |= S_MTIME;
-
+ sync_mode |= S_MTIME;
ts = inode_get_ctime(inode);
if (!timespec64_equal(&ts, &now))
- sync_it |= S_CTIME;
-
+ sync_mode |= S_CTIME;
if (IS_I_VERSION(inode) && inode_iversion_need_inc(inode))
- sync_it |= S_VERSION;
+ sync_mode |= S_VERSION;
- return sync_it;
-}
-
-static int __file_update_time(struct file *file, int sync_mode)
-{
- int ret = 0;
- struct inode *inode = file_inode(file);
+ if (!sync_mode)
+ return 0;
- /* try to update time settings */
- if (!mnt_get_write_access_file(file)) {
- ret = inode_update_time(inode, sync_mode);
- mnt_put_write_access_file(file);
- }
+ if (flags & IOCB_NOWAIT)
+ return -EAGAIN;
+ if (mnt_get_write_access_file(file))
+ return 0;
+ ret = inode_update_time(inode, sync_mode);
+ mnt_put_write_access_file(file);
return ret;
}
@@ -2377,14 +2373,7 @@ static int __file_update_time(struct file *file, int sync_mode)
*/
int file_update_time(struct file *file)
{
- int ret;
- struct inode *inode = file_inode(file);
-
- ret = inode_needs_update_time(inode);
- if (ret <= 0)
- return ret;
-
- return __file_update_time(file, ret);
+ return file_update_time_flags(file, 0);
}
EXPORT_SYMBOL(file_update_time);
@@ -2406,7 +2395,6 @@ EXPORT_SYMBOL(file_update_time);
static int file_modified_flags(struct file *file, int flags)
{
int ret;
- struct inode *inode = file_inode(file);
/*
* Clear the security bits if the process is not being run by root.
@@ -2415,17 +2403,9 @@ static int file_modified_flags(struct file *file, int flags)
ret = file_remove_privs_flags(file, flags);
if (ret)
return ret;
-
if (unlikely(file->f_mode & FMODE_NOCMTIME))
return 0;
-
- ret = inode_needs_update_time(inode);
- if (ret <= 0)
- return ret;
- if (flags & IOCB_NOWAIT)
- return -EAGAIN;
-
- return __file_update_time(file, ret);
+ return file_update_time_flags(file, flags);
}
/**
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 02/16] fs: lift the FMODE_NOCMTIME check into file_update_time_flags
2025-11-20 6:47 re-enable IOCB_NOWAIT writes to files v2 Christoph Hellwig
2025-11-20 6:47 ` [PATCH 01/16] fs: refactor file timestamp update logic Christoph Hellwig
@ 2025-11-20 6:47 ` Christoph Hellwig
2025-11-20 6:47 ` [PATCH 03/16] fs: export vfs_utimes Christoph Hellwig
` (13 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Christoph Hellwig @ 2025-11-20 6:47 UTC (permalink / raw)
To: Christian Brauner
Cc: Al Viro, David Sterba, Jan Kara, Mike Marshall,
Martin Brandenburg, Carlos Maiolino, Stefan Roesch, Jeff Layton,
linux-kernel, linux-btrfs, linux-fsdevel, gfs2, io-uring, devel,
linux-unionfs, linux-mtd, linux-xfs, linux-nfs,
Chaitanya Kulkarni
FMODE_NOCMTIME used to be just a hack for the legacy XFS handle-based
"invisible I/O", but commit e5e9b24ab8fa ("nfsd: freeze c/mtime updates
with outstanding WRITE_ATTRS delegation") started using it from
generic callers.
I'm not sure other file systems are actually read for this in general,
so the above commit should get a closer look, but for it to make any
sense, file_update_time needs to respect the flag.
Lift the check from file_modified_flags to file_update_time so that
users of file_update_time inherit the behavior and so that all the
checks are done in one place.
Fixes: e5e9b24ab8fa ("nfsd: freeze c/mtime updates with outstanding WRITE_ATTRS delegation")
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
---
fs/inode.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/inode.c b/fs/inode.c
index 540f4a28c202..2c55ec49b023 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -2332,6 +2332,8 @@ static int file_update_time_flags(struct file *file, unsigned int flags)
/* First try to exhaust all avenues to not sync */
if (IS_NOCMTIME(inode))
return 0;
+ if (unlikely(file->f_mode & FMODE_NOCMTIME))
+ return 0;
now = current_time(inode);
@@ -2403,8 +2405,6 @@ static int file_modified_flags(struct file *file, int flags)
ret = file_remove_privs_flags(file, flags);
if (ret)
return ret;
- if (unlikely(file->f_mode & FMODE_NOCMTIME))
- return 0;
return file_update_time_flags(file, flags);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 03/16] fs: export vfs_utimes
2025-11-20 6:47 re-enable IOCB_NOWAIT writes to files v2 Christoph Hellwig
2025-11-20 6:47 ` [PATCH 01/16] fs: refactor file timestamp update logic Christoph Hellwig
2025-11-20 6:47 ` [PATCH 02/16] fs: lift the FMODE_NOCMTIME check into file_update_time_flags Christoph Hellwig
@ 2025-11-20 6:47 ` Christoph Hellwig
2025-11-20 6:47 ` [PATCH 04/16] btrfs: use vfs_utimes to update file timestamps Christoph Hellwig
` (12 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Christoph Hellwig @ 2025-11-20 6:47 UTC (permalink / raw)
To: Christian Brauner
Cc: Al Viro, David Sterba, Jan Kara, Mike Marshall,
Martin Brandenburg, Carlos Maiolino, Stefan Roesch, Jeff Layton,
linux-kernel, linux-btrfs, linux-fsdevel, gfs2, io-uring, devel,
linux-unionfs, linux-mtd, linux-xfs, linux-nfs,
Chaitanya Kulkarni
This will be used to replace an incorrect direct call into
generic_update_time in btrfs.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
---
fs/utimes.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/fs/utimes.c b/fs/utimes.c
index c7c7958e57b2..3e7156396230 100644
--- a/fs/utimes.c
+++ b/fs/utimes.c
@@ -76,6 +76,7 @@ int vfs_utimes(const struct path *path, struct timespec64 *times)
out:
return error;
}
+EXPORT_SYMBOL_GPL(vfs_utimes);
static int do_utimes_path(int dfd, const char __user *filename,
struct timespec64 *times, int flags)
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 04/16] btrfs: use vfs_utimes to update file timestamps
2025-11-20 6:47 re-enable IOCB_NOWAIT writes to files v2 Christoph Hellwig
` (2 preceding siblings ...)
2025-11-20 6:47 ` [PATCH 03/16] fs: export vfs_utimes Christoph Hellwig
@ 2025-11-20 6:47 ` Christoph Hellwig
2025-11-20 6:47 ` [PATCH 05/16] btrfs: fix the comment on btrfs_update_time Christoph Hellwig
` (11 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Christoph Hellwig @ 2025-11-20 6:47 UTC (permalink / raw)
To: Christian Brauner
Cc: Al Viro, David Sterba, Jan Kara, Mike Marshall,
Martin Brandenburg, Carlos Maiolino, Stefan Roesch, Jeff Layton,
linux-kernel, linux-btrfs, linux-fsdevel, gfs2, io-uring, devel,
linux-unionfs, linux-mtd, linux-xfs, linux-nfs
Btrfs updates the device node timestamps for block device special files
when it stop using the device.
Commit 8f96a5bfa150 ("btrfs: update the bdev time directly when closing")
switch that update from the correct layering to directly call the
low-level helper on the bdev inode. This is wrong and got fixed in
commit 54fde91f52f5 ("btrfs: update device path inode time instead of
bd_inode") by updating the file system inode instead of the bdev inode,
but this kept the incorrect bypassing of the VFS interfaces and file
system ->update_times method. Fix this by using the propet vfs_utimes
interface.
Fixes: 8f96a5bfa150 ("btrfs: update the bdev time directly when closing")
Fixes: 54fde91f52f5 ("btrfs: update device path inode time instead of bd_inode")
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
---
fs/btrfs/volumes.c | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 2bec544d8ba3..259e8b0496df 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -2002,14 +2002,11 @@ static int btrfs_add_dev_item(struct btrfs_trans_handle *trans,
static void update_dev_time(const char *device_path)
{
struct path path;
- int ret;
- ret = kern_path(device_path, LOOKUP_FOLLOW, &path);
- if (ret)
- return;
-
- inode_update_time(d_inode(path.dentry), S_MTIME | S_CTIME | S_VERSION);
- path_put(&path);
+ if (!kern_path(device_path, LOOKUP_FOLLOW, &path)) {
+ vfs_utimes(&path, NULL);
+ path_put(&path);
+ }
}
static int btrfs_rm_dev_item(struct btrfs_trans_handle *trans,
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 05/16] btrfs: fix the comment on btrfs_update_time
2025-11-20 6:47 re-enable IOCB_NOWAIT writes to files v2 Christoph Hellwig
` (3 preceding siblings ...)
2025-11-20 6:47 ` [PATCH 04/16] btrfs: use vfs_utimes to update file timestamps Christoph Hellwig
@ 2025-11-20 6:47 ` Christoph Hellwig
2025-11-20 6:47 ` [PATCH 06/16] orangefs: use inode_update_timestamps directly Christoph Hellwig
` (10 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Christoph Hellwig @ 2025-11-20 6:47 UTC (permalink / raw)
To: Christian Brauner
Cc: Al Viro, David Sterba, Jan Kara, Mike Marshall,
Martin Brandenburg, Carlos Maiolino, Stefan Roesch, Jeff Layton,
linux-kernel, linux-btrfs, linux-fsdevel, gfs2, io-uring, devel,
linux-unionfs, linux-mtd, linux-xfs, linux-nfs
Since commit e41f941a2311 ("Btrfs: move over to use ->update_time") this
is not a copy of the high-level file_update_time helper.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/btrfs/inode.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 6282911e536f..05f6d272c5d7 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6291,8 +6291,8 @@ static int btrfs_dirty_inode(struct btrfs_inode *inode)
}
/*
- * This is a copy of file_update_time. We need this so we can return error on
- * ENOSPC for updating the inode in the case of file write and mmap writes.
+ * We need our own ->update_time so that we can return error on ENOSPC for
+ * updating the inode in the case of file write and mmap writes.
*/
static int btrfs_update_time(struct inode *inode, int flags)
{
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 06/16] orangefs: use inode_update_timestamps directly
2025-11-20 6:47 re-enable IOCB_NOWAIT writes to files v2 Christoph Hellwig
` (4 preceding siblings ...)
2025-11-20 6:47 ` [PATCH 05/16] btrfs: fix the comment on btrfs_update_time Christoph Hellwig
@ 2025-11-20 6:47 ` Christoph Hellwig
2025-11-20 6:47 ` [PATCH 07/16] fs: remove inode_update_time Christoph Hellwig
` (9 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Christoph Hellwig @ 2025-11-20 6:47 UTC (permalink / raw)
To: Christian Brauner
Cc: Al Viro, David Sterba, Jan Kara, Mike Marshall,
Martin Brandenburg, Carlos Maiolino, Stefan Roesch, Jeff Layton,
linux-kernel, linux-btrfs, linux-fsdevel, gfs2, io-uring, devel,
linux-unionfs, linux-mtd, linux-xfs, linux-nfs
Orangefs has no i_version handling and __orangefs_setattr already
explicitly marks the inode dirty. So instead of the using
the flags return value from generic_update_time, just call the
lower level inode_update_timestamps helper directly.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
---
fs/orangefs/inode.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
index a01400cd41fd..55f6c8026812 100644
--- a/fs/orangefs/inode.c
+++ b/fs/orangefs/inode.c
@@ -878,7 +878,9 @@ int orangefs_update_time(struct inode *inode, int flags)
gossip_debug(GOSSIP_INODE_DEBUG, "orangefs_update_time: %pU\n",
get_khandle_from_ino(inode));
- flags = generic_update_time(inode, flags);
+
+ flags = inode_update_timestamps(inode, flags);
+
memset(&iattr, 0, sizeof iattr);
if (flags & S_ATIME)
iattr.ia_valid |= ATTR_ATIME;
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 07/16] fs: remove inode_update_time
2025-11-20 6:47 re-enable IOCB_NOWAIT writes to files v2 Christoph Hellwig
` (5 preceding siblings ...)
2025-11-20 6:47 ` [PATCH 06/16] orangefs: use inode_update_timestamps directly Christoph Hellwig
@ 2025-11-20 6:47 ` Christoph Hellwig
2025-11-20 6:47 ` [PATCH 08/16] fs: allow error returns from generic_update_time Christoph Hellwig
` (8 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Christoph Hellwig @ 2025-11-20 6:47 UTC (permalink / raw)
To: Christian Brauner
Cc: Al Viro, David Sterba, Jan Kara, Mike Marshall,
Martin Brandenburg, Carlos Maiolino, Stefan Roesch, Jeff Layton,
linux-kernel, linux-btrfs, linux-fsdevel, gfs2, io-uring, devel,
linux-unionfs, linux-mtd, linux-xfs, linux-nfs,
Chaitanya Kulkarni
The only external user is gone now, open code it in the two VFS
callers.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
---
fs/inode.c | 23 ++++++++---------------
include/linux/fs.h | 1 -
2 files changed, 8 insertions(+), 16 deletions(-)
diff --git a/fs/inode.c b/fs/inode.c
index 2c55ec49b023..6e7e42915376 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -2119,19 +2119,6 @@ int generic_update_time(struct inode *inode, int flags)
}
EXPORT_SYMBOL(generic_update_time);
-/*
- * This does the actual work of updating an inodes time or version. Must have
- * had called mnt_want_write() before calling this.
- */
-int inode_update_time(struct inode *inode, int flags)
-{
- if (inode->i_op->update_time)
- return inode->i_op->update_time(inode, flags);
- generic_update_time(inode, flags);
- return 0;
-}
-EXPORT_SYMBOL(inode_update_time);
-
/**
* atime_needs_update - update the access time
* @path: the &struct path to update
@@ -2199,7 +2186,10 @@ void touch_atime(const struct path *path)
* We may also fail on filesystems that have the ability to make parts
* of the fs read only, e.g. subvolumes in Btrfs.
*/
- inode_update_time(inode, S_ATIME);
+ if (inode->i_op->update_time)
+ inode->i_op->update_time(inode, S_ATIME);
+ else
+ generic_update_time(inode, S_ATIME);
mnt_put_write_access(mnt);
skip_update:
sb_end_write(inode->i_sb);
@@ -2354,7 +2344,10 @@ static int file_update_time_flags(struct file *file, unsigned int flags)
if (mnt_get_write_access_file(file))
return 0;
- ret = inode_update_time(inode, sync_mode);
+ if (inode->i_op->update_time)
+ ret = inode->i_op->update_time(inode, sync_mode);
+ else
+ ret = generic_update_time(inode, sync_mode);
mnt_put_write_access_file(file);
return ret;
}
diff --git a/include/linux/fs.h b/include/linux/fs.h
index dd3b57cfadee..b54d300285b0 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2665,7 +2665,6 @@ enum file_time_flags {
extern bool atime_needs_update(const struct path *, struct inode *);
extern void touch_atime(const struct path *);
-int inode_update_time(struct inode *inode, int flags);
static inline void file_accessed(struct file *file)
{
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 08/16] fs: allow error returns from generic_update_time
2025-11-20 6:47 re-enable IOCB_NOWAIT writes to files v2 Christoph Hellwig
` (6 preceding siblings ...)
2025-11-20 6:47 ` [PATCH 07/16] fs: remove inode_update_time Christoph Hellwig
@ 2025-11-20 6:47 ` Christoph Hellwig
2025-11-20 6:47 ` [PATCH 09/16] fs: exit early in generic_update_time when there is no work Christoph Hellwig
` (7 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Christoph Hellwig @ 2025-11-20 6:47 UTC (permalink / raw)
To: Christian Brauner
Cc: Al Viro, David Sterba, Jan Kara, Mike Marshall,
Martin Brandenburg, Carlos Maiolino, Stefan Roesch, Jeff Layton,
linux-kernel, linux-btrfs, linux-fsdevel, gfs2, io-uring, devel,
linux-unionfs, linux-mtd, linux-xfs, linux-nfs,
Chaitanya Kulkarni
Now that no caller looks at the updated flags, switch generic_update_time
to the same calling convention as the ->update_time method and return 0
or a negative errno.
This prepares for adding non-blocking timestamp updates that could return
-EAGAIN.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
---
fs/gfs2/inode.c | 3 +--
fs/inode.c | 4 ++--
fs/ubifs/file.c | 6 ++----
fs/xfs/xfs_iops.c | 6 ++----
include/linux/fs.h | 2 +-
5 files changed, 8 insertions(+), 13 deletions(-)
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 8a7ed80d9f2d..601c14a3ac77 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -2242,8 +2242,7 @@ static int gfs2_update_time(struct inode *inode, int flags)
if (error)
return error;
}
- generic_update_time(inode, flags);
- return 0;
+ return generic_update_time(inode, flags);
}
static const struct inode_operations gfs2_file_iops = {
diff --git a/fs/inode.c b/fs/inode.c
index 6e7e42915376..15a8b2cf78ef 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -2103,7 +2103,7 @@ EXPORT_SYMBOL(inode_update_timestamps);
* or S_VERSION need to be updated we attempt to update all three of them. S_ATIME
* updates can be handled done independently of the rest.
*
- * Returns a S_* mask indicating which fields were updated.
+ * Returns a negative error value on error, else 0.
*/
int generic_update_time(struct inode *inode, int flags)
{
@@ -2115,7 +2115,7 @@ int generic_update_time(struct inode *inode, int flags)
if (updated & S_VERSION)
dirty_flags |= I_DIRTY_SYNC;
__mark_inode_dirty(inode, dirty_flags);
- return updated;
+ return 0;
}
EXPORT_SYMBOL(generic_update_time);
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index ca41ce8208c4..3e119cb93ea9 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1379,10 +1379,8 @@ int ubifs_update_time(struct inode *inode, int flags)
.dirtied_ino_d = ALIGN(ui->data_len, 8) };
int err, release;
- if (!IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT)) {
- generic_update_time(inode, flags);
- return 0;
- }
+ if (!IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT))
+ return generic_update_time(inode, flags);
err = ubifs_budget_space(c, &req);
if (err)
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index caff0125faea..0ace5f790006 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -1197,10 +1197,8 @@ xfs_vn_update_time(
if (inode->i_sb->s_flags & SB_LAZYTIME) {
if (!((flags & S_VERSION) &&
- inode_maybe_inc_iversion(inode, false))) {
- generic_update_time(inode, flags);
- return 0;
- }
+ inode_maybe_inc_iversion(inode, false)))
+ return generic_update_time(inode, flags);
/* Capture the iversion update that just occurred */
log_flags |= XFS_ILOG_CORE;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index b54d300285b0..4759aa61cb14 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2825,7 +2825,7 @@ extern void ihold(struct inode * inode);
extern void iput(struct inode *);
void iput_not_last(struct inode *);
int inode_update_timestamps(struct inode *inode, int flags);
-int generic_update_time(struct inode *, int);
+int generic_update_time(struct inode *inode, int flags);
/* /sys/fs */
extern struct kobject *fs_kobj;
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 09/16] fs: exit early in generic_update_time when there is no work
2025-11-20 6:47 re-enable IOCB_NOWAIT writes to files v2 Christoph Hellwig
` (7 preceding siblings ...)
2025-11-20 6:47 ` [PATCH 08/16] fs: allow error returns from generic_update_time Christoph Hellwig
@ 2025-11-20 6:47 ` Christoph Hellwig
2025-11-20 13:32 ` Jeff Layton
2025-11-20 6:47 ` [PATCH 10/16] fs: factor out a mark_inode_dirty_time helper Christoph Hellwig
` (6 subsequent siblings)
15 siblings, 1 reply; 20+ messages in thread
From: Christoph Hellwig @ 2025-11-20 6:47 UTC (permalink / raw)
To: Christian Brauner
Cc: Al Viro, David Sterba, Jan Kara, Mike Marshall,
Martin Brandenburg, Carlos Maiolino, Stefan Roesch, Jeff Layton,
linux-kernel, linux-btrfs, linux-fsdevel, gfs2, io-uring, devel,
linux-unionfs, linux-mtd, linux-xfs, linux-nfs
Exit early if not attributes are to be updated, to avoid a spurious call
to __mark_inode_dirty which can turn into a fairly expensive no-op due to
the extra checks and locking.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/inode.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/fs/inode.c b/fs/inode.c
index 15a8b2cf78ef..cda78f76e1dd 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -2110,6 +2110,9 @@ int generic_update_time(struct inode *inode, int flags)
int updated = inode_update_timestamps(inode, flags);
int dirty_flags = 0;
+ if (!updated)
+ return 0;
+
if (updated & (S_ATIME|S_MTIME|S_CTIME))
dirty_flags = inode->i_sb->s_flags & SB_LAZYTIME ? I_DIRTY_TIME : I_DIRTY_SYNC;
if (updated & S_VERSION)
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* Re: [PATCH 09/16] fs: exit early in generic_update_time when there is no work
2025-11-20 6:47 ` [PATCH 09/16] fs: exit early in generic_update_time when there is no work Christoph Hellwig
@ 2025-11-20 13:32 ` Jeff Layton
0 siblings, 0 replies; 20+ messages in thread
From: Jeff Layton @ 2025-11-20 13:32 UTC (permalink / raw)
To: Christoph Hellwig, Christian Brauner
Cc: Al Viro, David Sterba, Jan Kara, Mike Marshall,
Martin Brandenburg, Carlos Maiolino, Stefan Roesch, linux-kernel,
linux-btrfs, linux-fsdevel, gfs2, io-uring, devel, linux-unionfs,
linux-mtd, linux-xfs, linux-nfs
On Thu, 2025-11-20 at 07:47 +0100, Christoph Hellwig wrote:
> Exit early if not attributes are to be updated, to avoid a spurious call
> to __mark_inode_dirty which can turn into a fairly expensive no-op due to
> the extra checks and locking.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
> fs/inode.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/fs/inode.c b/fs/inode.c
> index 15a8b2cf78ef..cda78f76e1dd 100644
> --- a/fs/inode.c
> +++ b/fs/inode.c
> @@ -2110,6 +2110,9 @@ int generic_update_time(struct inode *inode, int flags)
> int updated = inode_update_timestamps(inode, flags);
> int dirty_flags = 0;
>
> + if (!updated)
> + return 0;
> +
> if (updated & (S_ATIME|S_MTIME|S_CTIME))
> dirty_flags = inode->i_sb->s_flags & SB_LAZYTIME ? I_DIRTY_TIME : I_DIRTY_SYNC;
> if (updated & S_VERSION)
Reviewed-by: Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 10/16] fs: factor out a mark_inode_dirty_time helper
2025-11-20 6:47 re-enable IOCB_NOWAIT writes to files v2 Christoph Hellwig
` (8 preceding siblings ...)
2025-11-20 6:47 ` [PATCH 09/16] fs: exit early in generic_update_time when there is no work Christoph Hellwig
@ 2025-11-20 6:47 ` Christoph Hellwig
2025-11-20 6:47 ` [PATCH 11/16] fs: allow error returns from inode_update_timestamps Christoph Hellwig
` (5 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Christoph Hellwig @ 2025-11-20 6:47 UTC (permalink / raw)
To: Christian Brauner
Cc: Al Viro, David Sterba, Jan Kara, Mike Marshall,
Martin Brandenburg, Carlos Maiolino, Stefan Roesch, Jeff Layton,
linux-kernel, linux-btrfs, linux-fsdevel, gfs2, io-uring, devel,
linux-unionfs, linux-mtd, linux-xfs, linux-nfs,
Chaitanya Kulkarni
Factor out the inode dirtying vs lazytime logic from generic_update_time
into a new helper so that it can be reused in file system methods.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
---
fs/fs-writeback.c | 16 ++++++++++++++++
fs/inode.c | 14 +++-----------
include/linux/fs.h | 3 ++-
3 files changed, 21 insertions(+), 12 deletions(-)
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 2b35e80037fe..a115e26e0139 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -2671,6 +2671,22 @@ void __mark_inode_dirty(struct inode *inode, int flags)
}
EXPORT_SYMBOL(__mark_inode_dirty);
+void mark_inode_dirty_time(struct inode *inode, unsigned int flags)
+{
+ if (inode->i_sb->s_flags & SB_LAZYTIME) {
+ int dirty_flags = 0;
+
+ if (flags & (S_ATIME | S_MTIME | S_CTIME))
+ dirty_flags = I_DIRTY_TIME;
+ if (flags & S_VERSION)
+ dirty_flags |= I_DIRTY_SYNC;
+ __mark_inode_dirty(inode, dirty_flags);
+ } else {
+ mark_inode_dirty_sync(inode);
+ }
+}
+EXPORT_SYMBOL_GPL(mark_inode_dirty_time);
+
/*
* The @s_sync_lock is used to serialise concurrent sync operations
* to avoid lock contention problems with concurrent wait_sb_inodes() calls.
diff --git a/fs/inode.c b/fs/inode.c
index cda78f76e1dd..edbc24a489ca 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -2107,17 +2107,9 @@ EXPORT_SYMBOL(inode_update_timestamps);
*/
int generic_update_time(struct inode *inode, int flags)
{
- int updated = inode_update_timestamps(inode, flags);
- int dirty_flags = 0;
-
- if (!updated)
- return 0;
-
- if (updated & (S_ATIME|S_MTIME|S_CTIME))
- dirty_flags = inode->i_sb->s_flags & SB_LAZYTIME ? I_DIRTY_TIME : I_DIRTY_SYNC;
- if (updated & S_VERSION)
- dirty_flags |= I_DIRTY_SYNC;
- __mark_inode_dirty(inode, dirty_flags);
+ flags = inode_update_timestamps(inode, flags);
+ if (flags)
+ mark_inode_dirty_time(inode, flags);
return 0;
}
EXPORT_SYMBOL(generic_update_time);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 4759aa61cb14..b4d82e5c6c32 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2608,7 +2608,8 @@ static inline void kiocb_clone(struct kiocb *kiocb, struct kiocb *kiocb_src,
};
}
-extern void __mark_inode_dirty(struct inode *, int);
+void mark_inode_dirty_time(struct inode *inode, unsigned int flags);
+void __mark_inode_dirty(struct inode *inode, int flags);
static inline void mark_inode_dirty(struct inode *inode)
{
__mark_inode_dirty(inode, I_DIRTY);
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 11/16] fs: allow error returns from inode_update_timestamps
2025-11-20 6:47 re-enable IOCB_NOWAIT writes to files v2 Christoph Hellwig
` (9 preceding siblings ...)
2025-11-20 6:47 ` [PATCH 10/16] fs: factor out a mark_inode_dirty_time helper Christoph Hellwig
@ 2025-11-20 6:47 ` Christoph Hellwig
2025-11-20 14:01 ` Jeff Layton
2025-11-20 6:47 ` [PATCH 12/16] fs: factor out a sync_lazytime helper Christoph Hellwig
` (4 subsequent siblings)
15 siblings, 1 reply; 20+ messages in thread
From: Christoph Hellwig @ 2025-11-20 6:47 UTC (permalink / raw)
To: Christian Brauner
Cc: Al Viro, David Sterba, Jan Kara, Mike Marshall,
Martin Brandenburg, Carlos Maiolino, Stefan Roesch, Jeff Layton,
linux-kernel, linux-btrfs, linux-fsdevel, gfs2, io-uring, devel,
linux-unionfs, linux-mtd, linux-xfs, linux-nfs
Change flags to a by reference argument so that it can be updated so that
the return value can be used for error returns. This will be used to
implement non-blocking timestamp updates.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/btrfs/inode.c | 8 +++++---
fs/inode.c | 24 ++++++++++++++++--------
fs/nfs/inode.c | 4 ++--
fs/orangefs/inode.c | 5 ++++-
fs/ubifs/file.c | 2 +-
include/linux/fs.h | 2 +-
6 files changed, 29 insertions(+), 16 deletions(-)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 05f6d272c5d7..668e4a1df7ae 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6297,13 +6297,15 @@ static int btrfs_dirty_inode(struct btrfs_inode *inode)
static int btrfs_update_time(struct inode *inode, int flags)
{
struct btrfs_root *root = BTRFS_I(inode)->root;
- bool dirty;
+ int error;
if (btrfs_root_readonly(root))
return -EROFS;
- dirty = inode_update_timestamps(inode, flags);
- return dirty ? btrfs_dirty_inode(BTRFS_I(inode)) : 0;
+ error = inode_update_timestamps(inode, &flags);
+ if (error || !flags)
+ return error;
+ return btrfs_dirty_inode(BTRFS_I(inode));
}
/*
diff --git a/fs/inode.c b/fs/inode.c
index edbc24a489ca..5b338de7a4c6 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -2057,14 +2057,18 @@ static bool relatime_need_update(struct vfsmount *mnt, struct inode *inode,
* attempt to update all three of them. S_ATIME updates can be handled
* independently of the rest.
*
- * Returns a set of S_* flags indicating which values changed.
+ * Updates @flags to contain the S_* flags which actually need changing. This
+ * can drop flags from the input when they don't need an update, or can add
+ * S_VERSION when the version needs to be bumped.
+ *
+ * Returns 0 or a negative errno.
*/
-int inode_update_timestamps(struct inode *inode, int flags)
+int inode_update_timestamps(struct inode *inode, int *flags)
{
int updated = 0;
struct timespec64 now;
- if (flags & (S_MTIME|S_CTIME|S_VERSION)) {
+ if (*flags & (S_MTIME | S_CTIME | S_VERSION)) {
struct timespec64 ctime = inode_get_ctime(inode);
struct timespec64 mtime = inode_get_mtime(inode);
@@ -2081,7 +2085,7 @@ int inode_update_timestamps(struct inode *inode, int flags)
now = current_time(inode);
}
- if (flags & S_ATIME) {
+ if (*flags & S_ATIME) {
struct timespec64 atime = inode_get_atime(inode);
if (!timespec64_equal(&now, &atime)) {
@@ -2089,7 +2093,9 @@ int inode_update_timestamps(struct inode *inode, int flags)
updated |= S_ATIME;
}
}
- return updated;
+
+ *flags = updated;
+ return 0;
}
EXPORT_SYMBOL(inode_update_timestamps);
@@ -2107,10 +2113,12 @@ EXPORT_SYMBOL(inode_update_timestamps);
*/
int generic_update_time(struct inode *inode, int flags)
{
- flags = inode_update_timestamps(inode, flags);
- if (flags)
+ int error;
+
+ error = inode_update_timestamps(inode, &flags);
+ if (!error && flags)
mark_inode_dirty_time(inode, flags);
- return 0;
+ return error;
}
EXPORT_SYMBOL(generic_update_time);
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 13ad70fc00d8..f7d5d23cd927 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -671,8 +671,8 @@ static void nfs_set_timestamps_to_ts(struct inode *inode, struct iattr *attr)
static void nfs_update_timestamps(struct inode *inode, unsigned int ia_valid)
{
- enum file_time_flags time_flags = 0;
unsigned int cache_flags = 0;
+ int time_flags = 0;
if (ia_valid & ATTR_MTIME) {
time_flags |= S_MTIME | S_CTIME;
@@ -682,7 +682,7 @@ static void nfs_update_timestamps(struct inode *inode, unsigned int ia_valid)
time_flags |= S_ATIME;
cache_flags |= NFS_INO_INVALID_ATIME;
}
- inode_update_timestamps(inode, time_flags);
+ inode_update_timestamps(inode, &time_flags);
NFS_I(inode)->cache_validity &= ~cache_flags;
}
diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
index 55f6c8026812..ec56a777053d 100644
--- a/fs/orangefs/inode.c
+++ b/fs/orangefs/inode.c
@@ -875,11 +875,14 @@ int orangefs_permission(struct mnt_idmap *idmap,
int orangefs_update_time(struct inode *inode, int flags)
{
struct iattr iattr;
+ int error;
gossip_debug(GOSSIP_INODE_DEBUG, "orangefs_update_time: %pU\n",
get_khandle_from_ino(inode));
- flags = inode_update_timestamps(inode, flags);
+ error = inode_update_timestamps(inode, &flags);
+ if (error || !flags)
+ return error;
memset(&iattr, 0, sizeof iattr);
if (flags & S_ATIME)
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index 3e119cb93ea9..7f631473da6c 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1387,7 +1387,7 @@ int ubifs_update_time(struct inode *inode, int flags)
return err;
mutex_lock(&ui->ui_mutex);
- inode_update_timestamps(inode, flags);
+ inode_update_timestamps(inode, &flags);
release = ui->dirty;
__mark_inode_dirty(inode, I_DIRTY_SYNC);
mutex_unlock(&ui->ui_mutex);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index b4d82e5c6c32..a6a38e30c998 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2825,7 +2825,7 @@ extern int current_umask(void);
extern void ihold(struct inode * inode);
extern void iput(struct inode *);
void iput_not_last(struct inode *);
-int inode_update_timestamps(struct inode *inode, int flags);
+int inode_update_timestamps(struct inode *inode, int *flags);
int generic_update_time(struct inode *inode, int flags);
/* /sys/fs */
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* Re: [PATCH 11/16] fs: allow error returns from inode_update_timestamps
2025-11-20 6:47 ` [PATCH 11/16] fs: allow error returns from inode_update_timestamps Christoph Hellwig
@ 2025-11-20 14:01 ` Jeff Layton
0 siblings, 0 replies; 20+ messages in thread
From: Jeff Layton @ 2025-11-20 14:01 UTC (permalink / raw)
To: Christoph Hellwig, Christian Brauner
Cc: Al Viro, David Sterba, Jan Kara, Mike Marshall,
Martin Brandenburg, Carlos Maiolino, Stefan Roesch, linux-kernel,
linux-btrfs, linux-fsdevel, gfs2, io-uring, devel, linux-unionfs,
linux-mtd, linux-xfs, linux-nfs
On Thu, 2025-11-20 at 07:47 +0100, Christoph Hellwig wrote:
> Change flags to a by reference argument so that it can be updated so that
> the return value can be used for error returns. This will be used to
> implement non-blocking timestamp updates.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
> fs/btrfs/inode.c | 8 +++++---
> fs/inode.c | 24 ++++++++++++++++--------
> fs/nfs/inode.c | 4 ++--
> fs/orangefs/inode.c | 5 ++++-
> fs/ubifs/file.c | 2 +-
> include/linux/fs.h | 2 +-
> 6 files changed, 29 insertions(+), 16 deletions(-)
>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 12/16] fs: factor out a sync_lazytime helper
2025-11-20 6:47 re-enable IOCB_NOWAIT writes to files v2 Christoph Hellwig
` (10 preceding siblings ...)
2025-11-20 6:47 ` [PATCH 11/16] fs: allow error returns from inode_update_timestamps Christoph Hellwig
@ 2025-11-20 6:47 ` Christoph Hellwig
2025-11-20 6:47 ` [PATCH 13/16] fs: add a ->sync_lazytime method Christoph Hellwig
` (3 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Christoph Hellwig @ 2025-11-20 6:47 UTC (permalink / raw)
To: Christian Brauner
Cc: Al Viro, David Sterba, Jan Kara, Mike Marshall,
Martin Brandenburg, Carlos Maiolino, Stefan Roesch, Jeff Layton,
linux-kernel, linux-btrfs, linux-fsdevel, gfs2, io-uring, devel,
linux-unionfs, linux-mtd, linux-xfs, linux-nfs
Centralize how we synchronize a lazytime update into the actual on-disk
timestamp into a single helper.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
---
fs/fs-writeback.c | 27 +++++++++++++++++----------
fs/inode.c | 5 +----
fs/internal.h | 3 ++-
fs/sync.c | 4 ++--
include/trace/events/writeback.h | 6 ------
5 files changed, 22 insertions(+), 23 deletions(-)
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index a115e26e0139..50e58cf399b8 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -1693,6 +1693,16 @@ static void requeue_inode(struct inode *inode, struct bdi_writeback *wb,
}
}
+bool sync_lazytime(struct inode *inode)
+{
+ if (!(inode->i_state & I_DIRTY_TIME))
+ return false;
+
+ trace_writeback_lazytime(inode);
+ mark_inode_dirty_sync(inode);
+ return true;
+}
+
/*
* Write out an inode and its dirty pages (or some of its dirty pages, depending
* on @wbc->nr_to_write), and clear the relevant dirty flags from i_state.
@@ -1732,17 +1742,14 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
}
/*
- * If the inode has dirty timestamps and we need to write them, call
- * mark_inode_dirty_sync() to notify the filesystem about it and to
- * change I_DIRTY_TIME into I_DIRTY_SYNC.
+ * For data integrity writeback, or when the dirty interval expired,
+ * ask the file system to propagata lazy timestamp updates into real
+ * dirty state.
*/
- if ((inode->i_state & I_DIRTY_TIME) &&
- (wbc->sync_mode == WB_SYNC_ALL ||
- time_after(jiffies, inode->dirtied_time_when +
- dirtytime_expire_interval * HZ))) {
- trace_writeback_lazytime(inode);
- mark_inode_dirty_sync(inode);
- }
+ if (wbc->sync_mode == WB_SYNC_ALL ||
+ time_after(jiffies, inode->dirtied_time_when +
+ dirtytime_expire_interval * HZ))
+ sync_lazytime(inode);
/*
* Get and clear the dirty flags from i_state. This needs to be done
diff --git a/fs/inode.c b/fs/inode.c
index 5b338de7a4c6..156a5fb50c7e 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1942,11 +1942,8 @@ void iput(struct inode *inode)
if (atomic_add_unless(&inode->i_count, -1, 1))
return;
- if ((inode->i_state & I_DIRTY_TIME) && inode->i_nlink) {
- trace_writeback_lazytime_iput(inode);
- mark_inode_dirty_sync(inode);
+ if (inode->i_nlink && sync_lazytime(inode))
goto retry;
- }
spin_lock(&inode->i_lock);
if (unlikely((inode->i_state & I_DIRTY_TIME) && inode->i_nlink)) {
diff --git a/fs/internal.h b/fs/internal.h
index 9b2b4d116880..da6e62f1183f 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -211,7 +211,8 @@ bool in_group_or_capable(struct mnt_idmap *idmap,
/*
* fs-writeback.c
*/
-extern long get_nr_dirty_inodes(void);
+long get_nr_dirty_inodes(void);
+bool sync_lazytime(struct inode *inode);
/*
* dcache.c
diff --git a/fs/sync.c b/fs/sync.c
index 2955cd4c77a3..a86395e266b1 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -182,8 +182,8 @@ int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync)
if (!file->f_op->fsync)
return -EINVAL;
- if (!datasync && (inode->i_state & I_DIRTY_TIME))
- mark_inode_dirty_sync(inode);
+ if (!datasync)
+ sync_lazytime(inode);
return file->f_op->fsync(file, start, end, datasync);
}
EXPORT_SYMBOL(vfs_fsync_range);
diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h
index c08aff044e80..75eae86798ba 100644
--- a/include/trace/events/writeback.h
+++ b/include/trace/events/writeback.h
@@ -856,12 +856,6 @@ DEFINE_EVENT(writeback_inode_template, writeback_lazytime,
TP_ARGS(inode)
);
-DEFINE_EVENT(writeback_inode_template, writeback_lazytime_iput,
- TP_PROTO(struct inode *inode),
-
- TP_ARGS(inode)
-);
-
DEFINE_EVENT(writeback_inode_template, writeback_dirty_inode_enqueue,
TP_PROTO(struct inode *inode),
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 13/16] fs: add a ->sync_lazytime method
2025-11-20 6:47 re-enable IOCB_NOWAIT writes to files v2 Christoph Hellwig
` (11 preceding siblings ...)
2025-11-20 6:47 ` [PATCH 12/16] fs: factor out a sync_lazytime helper Christoph Hellwig
@ 2025-11-20 6:47 ` Christoph Hellwig
2025-11-20 6:47 ` [PATCH 14/16] fs: add support for non-blocking timestamp updates Christoph Hellwig
` (2 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Christoph Hellwig @ 2025-11-20 6:47 UTC (permalink / raw)
To: Christian Brauner
Cc: Al Viro, David Sterba, Jan Kara, Mike Marshall,
Martin Brandenburg, Carlos Maiolino, Stefan Roesch, Jeff Layton,
linux-kernel, linux-btrfs, linux-fsdevel, gfs2, io-uring, devel,
linux-unionfs, linux-mtd, linux-xfs, linux-nfs
Allow the file system to explicitly implement lazytime syncing instead
of pigging back on generic inode dirtying. This allows to simplify
the XFS implementation and prepares for non-blocking lazytime timestamp
updates.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
---
Documentation/filesystems/locking.rst | 2 ++
Documentation/filesystems/vfs.rst | 6 ++++++
fs/fs-writeback.c | 15 ++++++++++++---
include/linux/fs.h | 1 +
4 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/Documentation/filesystems/locking.rst b/Documentation/filesystems/locking.rst
index 77704fde9845..9b2f14ada8cd 100644
--- a/Documentation/filesystems/locking.rst
+++ b/Documentation/filesystems/locking.rst
@@ -81,6 +81,7 @@ prototypes::
ssize_t (*listxattr) (struct dentry *, char *, size_t);
int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len);
void (*update_time)(struct inode *, struct timespec *, int);
+ void (*sync_lazytime)(struct inode *inode);
int (*atomic_open)(struct inode *, struct dentry *,
struct file *, unsigned open_flag,
umode_t create_mode);
@@ -117,6 +118,7 @@ getattr: no
listxattr: no
fiemap: no
update_time: no
+sync_lazytime: no
atomic_open: shared (exclusive if O_CREAT is set in open flags)
tmpfile: no
fileattr_get: no or exclusive
diff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/vfs.rst
index 4f13b01e42eb..ff59760daae2 100644
--- a/Documentation/filesystems/vfs.rst
+++ b/Documentation/filesystems/vfs.rst
@@ -486,6 +486,7 @@ As of kernel 2.6.22, the following members are defined:
int (*getattr) (struct mnt_idmap *, const struct path *, struct kstat *, u32, unsigned int);
ssize_t (*listxattr) (struct dentry *, char *, size_t);
void (*update_time)(struct inode *, struct timespec *, int);
+ void (*sync_lazytime)(struct inode *inode);
int (*atomic_open)(struct inode *, struct dentry *, struct file *,
unsigned open_flag, umode_t create_mode);
int (*tmpfile) (struct mnt_idmap *, struct inode *, struct file *, umode_t);
@@ -642,6 +643,11 @@ otherwise noted.
an inode. If this is not defined the VFS will update the inode
itself and call mark_inode_dirty_sync.
+``sync_lazytime``:
+ called by the writeback code to update the lazy time stamps to
+ regular time stamp updates that get syncing into the on-disk
+ inode.
+
``atomic_open``
called on the last component of an open. Using this optional
method the filesystem can look up, possibly create and open the
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 50e58cf399b8..1d614d53cce2 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -1699,7 +1699,10 @@ bool sync_lazytime(struct inode *inode)
return false;
trace_writeback_lazytime(inode);
- mark_inode_dirty_sync(inode);
+ if (inode->i_op->sync_lazytime)
+ inode->i_op->sync_lazytime(inode);
+ else
+ mark_inode_dirty_sync(inode);
return true;
}
@@ -2547,16 +2550,19 @@ void __mark_inode_dirty(struct inode *inode, int flags)
trace_writeback_mark_inode_dirty(inode, flags);
if (flags & I_DIRTY_INODE) {
+ bool was_dirty_time = inode->i_state & I_DIRTY_TIME;
+
/*
* Inode timestamp update will piggback on this dirtying.
* We tell ->dirty_inode callback that timestamps need to
* be updated by setting I_DIRTY_TIME in flags.
*/
- if (inode->i_state & I_DIRTY_TIME) {
+ if (was_dirty_time) {
spin_lock(&inode->i_lock);
if (inode->i_state & I_DIRTY_TIME) {
inode->i_state &= ~I_DIRTY_TIME;
flags |= I_DIRTY_TIME;
+ was_dirty_time = true;
}
spin_unlock(&inode->i_lock);
}
@@ -2569,9 +2575,12 @@ void __mark_inode_dirty(struct inode *inode, int flags)
* for just I_DIRTY_PAGES or I_DIRTY_TIME.
*/
trace_writeback_dirty_inode_start(inode, flags);
- if (sb->s_op->dirty_inode)
+ if (sb->s_op->dirty_inode) {
sb->s_op->dirty_inode(inode,
flags & (I_DIRTY_INODE | I_DIRTY_TIME));
+ } else if (was_dirty_time && inode->i_op->sync_lazytime) {
+ inode->i_op->sync_lazytime(inode);
+ }
trace_writeback_dirty_inode(inode, flags);
/* I_DIRTY_INODE supersedes I_DIRTY_TIME. */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index a6a38e30c998..eddb2bab0edd 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2363,6 +2363,7 @@ struct inode_operations {
int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
u64 len);
int (*update_time)(struct inode *, int);
+ void (*sync_lazytime)(struct inode *inode);
int (*atomic_open)(struct inode *, struct dentry *,
struct file *, unsigned open_flag,
umode_t create_mode);
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 14/16] fs: add support for non-blocking timestamp updates
2025-11-20 6:47 re-enable IOCB_NOWAIT writes to files v2 Christoph Hellwig
` (12 preceding siblings ...)
2025-11-20 6:47 ` [PATCH 13/16] fs: add a ->sync_lazytime method Christoph Hellwig
@ 2025-11-20 6:47 ` Christoph Hellwig
2025-11-20 6:47 ` [PATCH 15/16] xfs: implement ->sync_lazytime Christoph Hellwig
2025-11-20 6:47 ` [PATCH 16/16] xfs: enable non-blocking timestamp updates Christoph Hellwig
15 siblings, 0 replies; 20+ messages in thread
From: Christoph Hellwig @ 2025-11-20 6:47 UTC (permalink / raw)
To: Christian Brauner
Cc: Al Viro, David Sterba, Jan Kara, Mike Marshall,
Martin Brandenburg, Carlos Maiolino, Stefan Roesch, Jeff Layton,
linux-kernel, linux-btrfs, linux-fsdevel, gfs2, io-uring, devel,
linux-unionfs, linux-mtd, linux-xfs, linux-nfs
Currently file_update_time_flags unconditionally returns -EAGAIN if any
timestamp needs to be updated and IOCB_NOWAIT is passed. This makes
non-blocking direct writes impossible on file systems with granular
enough timestamps.
Add a S_NOWAIT to ask for timestamps to not block, and return -EAGAIN in
all methods for now.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
---
fs/btrfs/inode.c | 3 +++
fs/fat/misc.c | 3 +++
fs/gfs2/inode.c | 3 +++
fs/inode.c | 30 +++++++++++++++++++++++++-----
fs/orangefs/inode.c | 3 +++
fs/overlayfs/inode.c | 3 +++
fs/ubifs/file.c | 3 +++
fs/xfs/xfs_iops.c | 3 +++
include/linux/fs.h | 10 ++++++----
9 files changed, 52 insertions(+), 9 deletions(-)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 668e4a1df7ae..ea7e87bce1cd 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6302,6 +6302,9 @@ static int btrfs_update_time(struct inode *inode, int flags)
if (btrfs_root_readonly(root))
return -EROFS;
+ if (flags & S_NOWAIT)
+ return -EAGAIN;
+
error = inode_update_timestamps(inode, &flags);
if (error || !flags)
return error;
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index 950da09f0961..5df3193c35f9 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -346,6 +346,9 @@ int fat_update_time(struct inode *inode, int flags)
if (inode->i_ino == MSDOS_ROOT_INO)
return 0;
+ if (flags & S_NOWAIT)
+ return -EAGAIN;
+
if (flags & (S_ATIME | S_CTIME | S_MTIME)) {
fat_truncate_time(inode, NULL, flags);
if (inode->i_sb->s_flags & SB_LAZYTIME)
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 601c14a3ac77..0184cb64fe9f 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -2234,6 +2234,9 @@ static int gfs2_update_time(struct inode *inode, int flags)
struct gfs2_holder *gh;
int error;
+ if (flags & S_NOWAIT)
+ return -EAGAIN;
+
gh = gfs2_glock_is_locked_by_me(gl);
if (gh && gl->gl_state != LM_ST_EXCLUSIVE) {
gfs2_glock_dq(gh);
diff --git a/fs/inode.c b/fs/inode.c
index 156a5fb50c7e..577eea4e9704 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -2072,12 +2072,26 @@ int inode_update_timestamps(struct inode *inode, int *flags)
now = inode_set_ctime_current(inode);
if (!timespec64_equal(&now, &ctime))
updated |= S_CTIME;
- if (!timespec64_equal(&now, &mtime)) {
- inode_set_mtime_to_ts(inode, now);
+ if (!timespec64_equal(&now, &mtime))
updated |= S_MTIME;
+
+ if (IS_I_VERSION(inode)) {
+ if (*flags & S_NOWAIT) {
+ /*
+ * Error out if we'd need timestamp updates, as
+ * the generally requires blocking to dirty the
+ * inode in one form or another.
+ */
+ if (updated && inode_iversion_need_inc(inode))
+ goto bail;
+ } else {
+ if (inode_maybe_inc_iversion(inode, updated))
+ updated |= S_VERSION;
+ }
}
- if (IS_I_VERSION(inode) && inode_maybe_inc_iversion(inode, updated))
- updated |= S_VERSION;
+
+ if (updated & S_MTIME)
+ inode_set_mtime_to_ts(inode, now);
} else {
now = current_time(inode);
}
@@ -2093,6 +2107,9 @@ int inode_update_timestamps(struct inode *inode, int *flags)
*flags = updated;
return 0;
+bail:
+ *flags = 0;
+ return -EAGAIN;
}
EXPORT_SYMBOL(inode_update_timestamps);
@@ -2112,6 +2129,9 @@ int generic_update_time(struct inode *inode, int flags)
{
int error;
+ if (flags & S_NOWAIT)
+ return -EAGAIN;
+
error = inode_update_timestamps(inode, &flags);
if (!error && flags)
mark_inode_dirty_time(inode, flags);
@@ -2340,7 +2360,7 @@ static int file_update_time_flags(struct file *file, unsigned int flags)
return 0;
if (flags & IOCB_NOWAIT)
- return -EAGAIN;
+ sync_mode |= S_NOWAIT;
if (mnt_get_write_access_file(file))
return 0;
diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
index ec56a777053d..569280935179 100644
--- a/fs/orangefs/inode.c
+++ b/fs/orangefs/inode.c
@@ -880,6 +880,9 @@ int orangefs_update_time(struct inode *inode, int flags)
gossip_debug(GOSSIP_INODE_DEBUG, "orangefs_update_time: %pU\n",
get_khandle_from_ino(inode));
+ if (flags & S_NOWAIT)
+ return -EAGAIN;
+
error = inode_update_timestamps(inode, &flags);
if (error || !flags)
return error;
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index e11f310ce092..c132d1f5502b 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -576,6 +576,9 @@ int ovl_update_time(struct inode *inode, int flags)
.dentry = ovl_upperdentry_dereference(OVL_I(inode)),
};
+ if (flags & S_NOWAIT)
+ return -EAGAIN;
+
if (upperpath.dentry) {
touch_atime(&upperpath);
inode_set_atime_to_ts(inode,
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index 7f631473da6c..33af8bbeab4f 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1382,6 +1382,9 @@ int ubifs_update_time(struct inode *inode, int flags)
if (!IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT))
return generic_update_time(inode, flags);
+ if (flags & S_NOWAIT)
+ return -EAGAIN;
+
err = ubifs_budget_space(c, &req);
if (err)
return err;
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 0ace5f790006..da055dade25f 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -1195,6 +1195,9 @@ xfs_vn_update_time(
trace_xfs_update_time(ip);
+ if (flags & S_NOWAIT)
+ return -EAGAIN;
+
if (inode->i_sb->s_flags & SB_LAZYTIME) {
if (!((flags & S_VERSION) &&
inode_maybe_inc_iversion(inode, false)))
diff --git a/include/linux/fs.h b/include/linux/fs.h
index eddb2bab0edd..924ea0449dc6 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2659,10 +2659,12 @@ static inline void inode_dec_link_count(struct inode *inode)
}
enum file_time_flags {
- S_ATIME = 1,
- S_MTIME = 2,
- S_CTIME = 4,
- S_VERSION = 8,
+ S_ATIME = 1U << 0,
+ S_MTIME = 1U << 1,
+ S_CTIME = 1U << 2,
+ S_VERSION = 1U << 3,
+
+ S_NOWAIT = 1U << 15,
};
extern bool atime_needs_update(const struct path *, struct inode *);
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 15/16] xfs: implement ->sync_lazytime
2025-11-20 6:47 re-enable IOCB_NOWAIT writes to files v2 Christoph Hellwig
` (13 preceding siblings ...)
2025-11-20 6:47 ` [PATCH 14/16] fs: add support for non-blocking timestamp updates Christoph Hellwig
@ 2025-11-20 6:47 ` Christoph Hellwig
2025-11-20 6:47 ` [PATCH 16/16] xfs: enable non-blocking timestamp updates Christoph Hellwig
15 siblings, 0 replies; 20+ messages in thread
From: Christoph Hellwig @ 2025-11-20 6:47 UTC (permalink / raw)
To: Christian Brauner
Cc: Al Viro, David Sterba, Jan Kara, Mike Marshall,
Martin Brandenburg, Carlos Maiolino, Stefan Roesch, Jeff Layton,
linux-kernel, linux-btrfs, linux-fsdevel, gfs2, io-uring, devel,
linux-unionfs, linux-mtd, linux-xfs, linux-nfs
Switch to the new explicit lazytime syncing method instead of trying
to second guess what could be a lazytime update in ->dirty_inode.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
---
fs/xfs/xfs_iops.c | 20 ++++++++++++++++++++
fs/xfs/xfs_super.c | 29 -----------------------------
2 files changed, 20 insertions(+), 29 deletions(-)
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index da055dade25f..bd0b7e81f6ab 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -1227,6 +1227,22 @@ xfs_vn_update_time(
return xfs_trans_commit(tp);
}
+static void
+xfs_vn_sync_lazytime(
+ struct inode *inode)
+{
+ struct xfs_inode *ip = XFS_I(inode);
+ struct xfs_mount *mp = ip->i_mount;
+ struct xfs_trans *tp;
+
+ if (xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp))
+ return;
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+ xfs_trans_log_inode(tp, ip, XFS_ILOG_TIMESTAMP);
+ xfs_trans_commit(tp);
+}
+
STATIC int
xfs_vn_fiemap(
struct inode *inode,
@@ -1270,6 +1286,7 @@ static const struct inode_operations xfs_inode_operations = {
.listxattr = xfs_vn_listxattr,
.fiemap = xfs_vn_fiemap,
.update_time = xfs_vn_update_time,
+ .sync_lazytime = xfs_vn_sync_lazytime,
.fileattr_get = xfs_fileattr_get,
.fileattr_set = xfs_fileattr_set,
};
@@ -1296,6 +1313,7 @@ static const struct inode_operations xfs_dir_inode_operations = {
.setattr = xfs_vn_setattr,
.listxattr = xfs_vn_listxattr,
.update_time = xfs_vn_update_time,
+ .sync_lazytime = xfs_vn_sync_lazytime,
.tmpfile = xfs_vn_tmpfile,
.fileattr_get = xfs_fileattr_get,
.fileattr_set = xfs_fileattr_set,
@@ -1323,6 +1341,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = {
.setattr = xfs_vn_setattr,
.listxattr = xfs_vn_listxattr,
.update_time = xfs_vn_update_time,
+ .sync_lazytime = xfs_vn_sync_lazytime,
.tmpfile = xfs_vn_tmpfile,
.fileattr_get = xfs_fileattr_get,
.fileattr_set = xfs_fileattr_set,
@@ -1334,6 +1353,7 @@ static const struct inode_operations xfs_symlink_inode_operations = {
.setattr = xfs_vn_setattr,
.listxattr = xfs_vn_listxattr,
.update_time = xfs_vn_update_time,
+ .sync_lazytime = xfs_vn_sync_lazytime,
.fileattr_get = xfs_fileattr_get,
.fileattr_set = xfs_fileattr_set,
};
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index bc71aa9dcee8..094f257eff15 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -712,34 +712,6 @@ xfs_fs_destroy_inode(
xfs_inode_mark_reclaimable(ip);
}
-static void
-xfs_fs_dirty_inode(
- struct inode *inode,
- int flags)
-{
- struct xfs_inode *ip = XFS_I(inode);
- struct xfs_mount *mp = ip->i_mount;
- struct xfs_trans *tp;
-
- if (!(inode->i_sb->s_flags & SB_LAZYTIME))
- return;
-
- /*
- * Only do the timestamp update if the inode is dirty (I_DIRTY_SYNC)
- * and has dirty timestamp (I_DIRTY_TIME). I_DIRTY_TIME can be passed
- * in flags possibly together with I_DIRTY_SYNC.
- */
- if ((flags & ~I_DIRTY_TIME) != I_DIRTY_SYNC || !(flags & I_DIRTY_TIME))
- return;
-
- if (xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp))
- return;
- xfs_ilock(ip, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
- xfs_trans_log_inode(tp, ip, XFS_ILOG_TIMESTAMP);
- xfs_trans_commit(tp);
-}
-
/*
* Slab object creation initialisation for the XFS inode.
* This covers only the idempotent fields in the XFS inode;
@@ -1304,7 +1276,6 @@ xfs_fs_show_stats(
static const struct super_operations xfs_super_operations = {
.alloc_inode = xfs_fs_alloc_inode,
.destroy_inode = xfs_fs_destroy_inode,
- .dirty_inode = xfs_fs_dirty_inode,
.drop_inode = xfs_fs_drop_inode,
.evict_inode = xfs_fs_evict_inode,
.put_super = xfs_fs_put_super,
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 16/16] xfs: enable non-blocking timestamp updates
2025-11-20 6:47 re-enable IOCB_NOWAIT writes to files v2 Christoph Hellwig
` (14 preceding siblings ...)
2025-11-20 6:47 ` [PATCH 15/16] xfs: implement ->sync_lazytime Christoph Hellwig
@ 2025-11-20 6:47 ` Christoph Hellwig
2025-11-20 14:16 ` Jeff Layton
15 siblings, 1 reply; 20+ messages in thread
From: Christoph Hellwig @ 2025-11-20 6:47 UTC (permalink / raw)
To: Christian Brauner
Cc: Al Viro, David Sterba, Jan Kara, Mike Marshall,
Martin Brandenburg, Carlos Maiolino, Stefan Roesch, Jeff Layton,
linux-kernel, linux-btrfs, linux-fsdevel, gfs2, io-uring, devel,
linux-unionfs, linux-mtd, linux-xfs, linux-nfs
The lazytime path using the generic helpers can never block in XFS
because there is no ->dirty_inode method that could block. Allow
non-blocking timestamp updates for this case by replacing
generic_update_times with the open coded version without the S_NOWAIT
check.
Fixes: 66fa3cedf16a ("fs: Add async write file modification handling.")
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_iops.c | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index bd0b7e81f6ab..57ff05be5700 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -1195,16 +1195,24 @@ xfs_vn_update_time(
trace_xfs_update_time(ip);
- if (flags & S_NOWAIT)
- return -EAGAIN;
-
if (inode->i_sb->s_flags & SB_LAZYTIME) {
- if (!((flags & S_VERSION) &&
- inode_maybe_inc_iversion(inode, false)))
- return generic_update_time(inode, flags);
+ int updated = flags;
+
+ error = inode_update_timestamps(inode, &updated);
+ if (error)
+ return error;
+
+ if (!(updated & S_VERSION)) {
+ if (updated)
+ mark_inode_dirty_time(inode, updated);
+ return 0;
+ }
/* Capture the iversion update that just occurred */
log_flags |= XFS_ILOG_CORE;
+ } else {
+ if (flags & S_NOWAIT)
+ return -EAGAIN;
}
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp);
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* Re: [PATCH 16/16] xfs: enable non-blocking timestamp updates
2025-11-20 6:47 ` [PATCH 16/16] xfs: enable non-blocking timestamp updates Christoph Hellwig
@ 2025-11-20 14:16 ` Jeff Layton
0 siblings, 0 replies; 20+ messages in thread
From: Jeff Layton @ 2025-11-20 14:16 UTC (permalink / raw)
To: Christoph Hellwig, Christian Brauner
Cc: Al Viro, David Sterba, Jan Kara, Mike Marshall,
Martin Brandenburg, Carlos Maiolino, Stefan Roesch, linux-kernel,
linux-btrfs, linux-fsdevel, gfs2, io-uring, devel, linux-unionfs,
linux-mtd, linux-xfs, linux-nfs
On Thu, 2025-11-20 at 07:47 +0100, Christoph Hellwig wrote:
> The lazytime path using the generic helpers can never block in XFS
> because there is no ->dirty_inode method that could block. Allow
> non-blocking timestamp updates for this case by replacing
> generic_update_times with the open coded version without the S_NOWAIT
> check.
>
> Fixes: 66fa3cedf16a ("fs: Add async write file modification handling.")
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
> fs/xfs/xfs_iops.c | 20 ++++++++++++++------
> 1 file changed, 14 insertions(+), 6 deletions(-)
>
> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> index bd0b7e81f6ab..57ff05be5700 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -1195,16 +1195,24 @@ xfs_vn_update_time(
>
> trace_xfs_update_time(ip);
>
> - if (flags & S_NOWAIT)
> - return -EAGAIN;
> -
> if (inode->i_sb->s_flags & SB_LAZYTIME) {
> - if (!((flags & S_VERSION) &&
> - inode_maybe_inc_iversion(inode, false)))
> - return generic_update_time(inode, flags);
I especially like getting this inode_maybe_inc_iversion() out of this
function.
> + int updated = flags;
> +
> + error = inode_update_timestamps(inode, &updated);
> + if (error)
> + return error;
> +
> + if (!(updated & S_VERSION)) {
> + if (updated)
> + mark_inode_dirty_time(inode, updated);
> + return 0;
> + }
>
> /* Capture the iversion update that just occurred */
> log_flags |= XFS_ILOG_CORE;
> + } else {
> + if (flags & S_NOWAIT)
> + return -EAGAIN;
> }
>
> error = xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp);
Reviewed-by: Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 20+ messages in thread