fs: add a ->sync_lazytime method

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>
Link: https://patch.msgid.link/20260108141934.2052404-8-hch@lst.de
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
Christoph Hellwig 2026-01-08 15:19:07 +01:00 committed by Christian Brauner
parent 188344c8ac
commit 5cf06ea56e
No known key found for this signature in database
GPG Key ID: 91C61BC06578DCA2
4 changed files with 20 additions and 2 deletions

View File

@ -82,6 +82,7 @@ prototypes::
int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len); int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len);
void (*update_time)(struct inode *inode, enum fs_update_time type, void (*update_time)(struct inode *inode, enum fs_update_time type,
int flags); int flags);
void (*sync_lazytime)(struct inode *inode);
int (*atomic_open)(struct inode *, struct dentry *, int (*atomic_open)(struct inode *, struct dentry *,
struct file *, unsigned open_flag, struct file *, unsigned open_flag,
umode_t create_mode); umode_t create_mode);
@ -118,6 +119,7 @@ getattr: no
listxattr: no listxattr: no
fiemap: no fiemap: no
update_time: no update_time: no
sync_lazytime: no
atomic_open: shared (exclusive if O_CREAT is set in open flags) atomic_open: shared (exclusive if O_CREAT is set in open flags)
tmpfile: no tmpfile: no
fileattr_get: no or exclusive fileattr_get: no or exclusive

View File

@ -487,6 +487,7 @@ As of kernel 2.6.22, the following members are defined:
ssize_t (*listxattr) (struct dentry *, char *, size_t); ssize_t (*listxattr) (struct dentry *, char *, size_t);
void (*update_time)(struct inode *inode, enum fs_update_time type, void (*update_time)(struct inode *inode, enum fs_update_time type,
int flags); int flags);
void (*sync_lazytime)(struct inode *inode);
int (*atomic_open)(struct inode *, struct dentry *, struct file *, int (*atomic_open)(struct inode *, struct dentry *, struct file *,
unsigned open_flag, umode_t create_mode); unsigned open_flag, umode_t create_mode);
int (*tmpfile) (struct mnt_idmap *, struct inode *, struct file *, umode_t); int (*tmpfile) (struct mnt_idmap *, struct inode *, struct file *, umode_t);
@ -643,6 +644,11 @@ otherwise noted.
an inode. If this is not defined the VFS will update the inode an inode. If this is not defined the VFS will update the inode
itself and call mark_inode_dirty_sync. 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`` ``atomic_open``
called on the last component of an open. Using this optional called on the last component of an open. Using this optional
method the filesystem can look up, possibly create and open the method the filesystem can look up, possibly create and open the

View File

@ -1717,7 +1717,10 @@ bool sync_lazytime(struct inode *inode)
return false; return false;
trace_writeback_lazytime(inode); 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; return true;
} }
@ -2569,6 +2572,8 @@ void __mark_inode_dirty(struct inode *inode, int flags)
trace_writeback_mark_inode_dirty(inode, flags); trace_writeback_mark_inode_dirty(inode, flags);
if (flags & I_DIRTY_INODE) { if (flags & I_DIRTY_INODE) {
bool was_dirty_time = false;
/* /*
* Inode timestamp update will piggback on this dirtying. * Inode timestamp update will piggback on this dirtying.
* We tell ->dirty_inode callback that timestamps need to * We tell ->dirty_inode callback that timestamps need to
@ -2579,6 +2584,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
if (inode_state_read(inode) & I_DIRTY_TIME) { if (inode_state_read(inode) & I_DIRTY_TIME) {
inode_state_clear(inode, I_DIRTY_TIME); inode_state_clear(inode, I_DIRTY_TIME);
flags |= I_DIRTY_TIME; flags |= I_DIRTY_TIME;
was_dirty_time = true;
} }
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
@ -2591,9 +2597,12 @@ void __mark_inode_dirty(struct inode *inode, int flags)
* for just I_DIRTY_PAGES or I_DIRTY_TIME. * for just I_DIRTY_PAGES or I_DIRTY_TIME.
*/ */
trace_writeback_dirty_inode_start(inode, flags); 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, sb->s_op->dirty_inode(inode,
flags & (I_DIRTY_INODE | I_DIRTY_TIME)); 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); trace_writeback_dirty_inode(inode, flags);
/* I_DIRTY_INODE supersedes I_DIRTY_TIME. */ /* I_DIRTY_INODE supersedes I_DIRTY_TIME. */

View File

@ -2024,6 +2024,7 @@ struct inode_operations {
u64 len); u64 len);
int (*update_time)(struct inode *inode, enum fs_update_time type, int (*update_time)(struct inode *inode, enum fs_update_time type,
unsigned int flags); unsigned int flags);
void (*sync_lazytime)(struct inode *inode);
int (*atomic_open)(struct inode *, struct dentry *, int (*atomic_open)(struct inode *, struct dentry *,
struct file *, unsigned open_flag, struct file *, unsigned open_flag,
umode_t create_mode); umode_t create_mode);