Skip to content

Commit 77ef2c3

Browse files
committed
Merge patch series "re-enable IOCB_NOWAIT writes to files v6"
Christoph Hellwig <hch@lst.de> says: Hi all, commit 66fa3ce ("fs: Add async write file modification handling.") effectively disabled IOCB_NOWAIT writes as timestamp updates currently always require blocking, and the modern timestamp resolution means we always update timestamps. This leads to a lot of context switches from applications using io_uring to submit file writes, making it often worse than using the legacy aio code that is not using IOCB_NOWAIT. This series allows non-blocking updates for lazytime if the file system supports it, and adds that support for XFS. * patches from https://patch.msgid.link/20260108141934.2052404-1-hch@lst.de: xfs: enable non-blocking timestamp updates xfs: implement ->sync_lazytime fs: refactor file_update_time_flags fs: add support for non-blocking timestamp updates fs: add a ->sync_lazytime method fs: factor out a sync_lazytime helper fs: refactor ->update_time handling fat: cleanup the flags for fat_truncate_time nfs: split nfs_update_timestamps fs: allow error returns from generic_update_time fs: remove inode_update_time Link: https://patch.msgid.link/20260108141934.2052404-1-hch@lst.de Signed-off-by: Christian Brauner <brauner@kernel.org>
2 parents 8f0b4cc + 08489c4 commit 77ef2c3

File tree

27 files changed

+325
-290
lines changed

27 files changed

+325
-290
lines changed

Documentation/filesystems/locking.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ prototypes::
8080
int (*getattr) (struct mnt_idmap *, const struct path *, struct kstat *, u32, unsigned int);
8181
ssize_t (*listxattr) (struct dentry *, char *, size_t);
8282
int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len);
83-
void (*update_time)(struct inode *, struct timespec *, int);
83+
void (*update_time)(struct inode *inode, enum fs_update_time type,
84+
int flags);
85+
void (*sync_lazytime)(struct inode *inode);
8486
int (*atomic_open)(struct inode *, struct dentry *,
8587
struct file *, unsigned open_flag,
8688
umode_t create_mode);
@@ -117,6 +119,7 @@ getattr: no
117119
listxattr: no
118120
fiemap: no
119121
update_time: no
122+
sync_lazytime: no
120123
atomic_open: shared (exclusive if O_CREAT is set in open flags)
121124
tmpfile: no
122125
fileattr_get: no or exclusive

Documentation/filesystems/vfs.rst

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,9 @@ As of kernel 2.6.22, the following members are defined:
485485
int (*setattr) (struct mnt_idmap *, struct dentry *, struct iattr *);
486486
int (*getattr) (struct mnt_idmap *, const struct path *, struct kstat *, u32, unsigned int);
487487
ssize_t (*listxattr) (struct dentry *, char *, size_t);
488-
void (*update_time)(struct inode *, struct timespec *, int);
488+
void (*update_time)(struct inode *inode, enum fs_update_time type,
489+
int flags);
490+
void (*sync_lazytime)(struct inode *inode);
489491
int (*atomic_open)(struct inode *, struct dentry *, struct file *,
490492
unsigned open_flag, umode_t create_mode);
491493
int (*tmpfile) (struct mnt_idmap *, struct inode *, struct file *, umode_t);
@@ -642,6 +644,11 @@ otherwise noted.
642644
an inode. If this is not defined the VFS will update the inode
643645
itself and call mark_inode_dirty_sync.
644646

647+
``sync_lazytime``:
648+
called by the writeback code to update the lazy time stamps to
649+
regular time stamp updates that get syncing into the on-disk
650+
inode.
651+
645652
``atomic_open``
646653
called on the last component of an open. Using this optional
647654
method the filesystem can look up, possibly create and open the

fs/bad_inode.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ static int bad_inode_fiemap(struct inode *inode,
133133
return -EIO;
134134
}
135135

136-
static int bad_inode_update_time(struct inode *inode, int flags)
136+
static int bad_inode_update_time(struct inode *inode, enum fs_update_time type,
137+
unsigned int flags)
137138
{
138139
return -EIO;
139140
}

fs/btrfs/inode.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6345,16 +6345,21 @@ static int btrfs_dirty_inode(struct btrfs_inode *inode)
63456345
* We need our own ->update_time so that we can return error on ENOSPC for
63466346
* updating the inode in the case of file write and mmap writes.
63476347
*/
6348-
static int btrfs_update_time(struct inode *inode, int flags)
6348+
static int btrfs_update_time(struct inode *inode, enum fs_update_time type,
6349+
unsigned int flags)
63496350
{
63506351
struct btrfs_root *root = BTRFS_I(inode)->root;
6351-
bool dirty;
6352+
int dirty;
63526353

63536354
if (btrfs_root_readonly(root))
63546355
return -EROFS;
6356+
if (flags & IOCB_NOWAIT)
6357+
return -EAGAIN;
63556358

6356-
dirty = inode_update_timestamps(inode, flags);
6357-
return dirty ? btrfs_dirty_inode(BTRFS_I(inode)) : 0;
6359+
dirty = inode_update_time(inode, type, flags);
6360+
if (dirty <= 0)
6361+
return dirty;
6362+
return btrfs_dirty_inode(BTRFS_I(inode));
63586363
}
63596364

63606365
/*

fs/fat/dir.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1080,7 +1080,7 @@ int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo)
10801080
}
10811081
}
10821082

1083-
fat_truncate_time(dir, NULL, S_ATIME|S_MTIME);
1083+
fat_truncate_time(dir, NULL, FAT_UPDATE_ATIME | FAT_UPDATE_CMTIME);
10841084
if (IS_DIRSYNC(dir))
10851085
(void)fat_sync_inode(dir);
10861086
else

fs/fat/fat.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -468,11 +468,12 @@ extern void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec64 *ts,
468468
__le16 *time, __le16 *date, u8 *time_cs);
469469
extern struct timespec64 fat_truncate_atime(const struct msdos_sb_info *sbi,
470470
const struct timespec64 *ts);
471-
extern struct timespec64 fat_truncate_mtime(const struct msdos_sb_info *sbi,
472-
const struct timespec64 *ts);
473-
extern int fat_truncate_time(struct inode *inode, struct timespec64 *now,
474-
int flags);
475-
extern int fat_update_time(struct inode *inode, int flags);
471+
#define FAT_UPDATE_ATIME (1u << 0)
472+
#define FAT_UPDATE_CMTIME (1u << 1)
473+
void fat_truncate_time(struct inode *inode, struct timespec64 *now,
474+
unsigned int flags);
475+
int fat_update_time(struct inode *inode, enum fs_update_time type,
476+
unsigned int flags);
476477
extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs);
477478

478479
int fat_cache_init(void);

fs/fat/file.c

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ static int fat_cont_expand(struct inode *inode, loff_t size)
224224
if (err)
225225
goto out;
226226

227-
fat_truncate_time(inode, NULL, S_CTIME|S_MTIME);
227+
fat_truncate_time(inode, NULL, FAT_UPDATE_CMTIME);
228228
mark_inode_dirty(inode);
229229
if (IS_SYNC(inode)) {
230230
int err2;
@@ -327,7 +327,7 @@ static int fat_free(struct inode *inode, int skip)
327327
MSDOS_I(inode)->i_logstart = 0;
328328
}
329329
MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
330-
fat_truncate_time(inode, NULL, S_CTIME|S_MTIME);
330+
fat_truncate_time(inode, NULL, FAT_UPDATE_CMTIME);
331331
if (wait) {
332332
err = fat_sync_inode(inode);
333333
if (err) {
@@ -553,15 +553,13 @@ int fat_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
553553
}
554554

555555
/*
556-
* setattr_copy can't truncate these appropriately, so we'll
557-
* copy them ourselves
556+
* setattr_copy can't truncate these appropriately, so we'll copy them
557+
* ourselves. See fat_truncate_time for the c/mtime logic on fat.
558558
*/
559559
if (attr->ia_valid & ATTR_ATIME)
560-
fat_truncate_time(inode, &attr->ia_atime, S_ATIME);
561-
if (attr->ia_valid & ATTR_CTIME)
562-
fat_truncate_time(inode, &attr->ia_ctime, S_CTIME);
560+
fat_truncate_time(inode, &attr->ia_atime, FAT_UPDATE_ATIME);
563561
if (attr->ia_valid & ATTR_MTIME)
564-
fat_truncate_time(inode, &attr->ia_mtime, S_MTIME);
562+
fat_truncate_time(inode, &attr->ia_mtime, FAT_UPDATE_CMTIME);
565563
attr->ia_valid &= ~(ATTR_ATIME|ATTR_CTIME|ATTR_MTIME);
566564

567565
setattr_copy(idmap, inode, attr);

fs/fat/inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ static int fat_write_end(const struct kiocb *iocb,
246246
if (err < len)
247247
fat_write_failed(mapping, pos + len);
248248
if (!(err < 0) && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) {
249-
fat_truncate_time(inode, NULL, S_CTIME|S_MTIME);
249+
fat_truncate_time(inode, NULL, FAT_UPDATE_CMTIME);
250250
MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
251251
mark_inode_dirty(inode);
252252
}

fs/fat/misc.c

Lines changed: 22 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -299,62 +299,47 @@ struct timespec64 fat_truncate_atime(const struct msdos_sb_info *sbi,
299299
}
300300

301301
/*
302-
* truncate mtime to 2 second granularity
303-
*/
304-
struct timespec64 fat_truncate_mtime(const struct msdos_sb_info *sbi,
305-
const struct timespec64 *ts)
306-
{
307-
return fat_timespec64_trunc_2secs(*ts);
308-
}
309-
310-
/*
311-
* truncate the various times with appropriate granularity:
312-
* all times in root node are always 0
302+
* Update the in-inode atime and/or mtime after truncating the timestamp to the
303+
* granularity. All timestamps in root inode are always 0.
304+
*
305+
* ctime and mtime share the same on-disk field, and should be identical in
306+
* memory. All mtime updates will be applied to ctime, but ctime updates are
307+
* ignored.
313308
*/
314-
int fat_truncate_time(struct inode *inode, struct timespec64 *now, int flags)
309+
void fat_truncate_time(struct inode *inode, struct timespec64 *now,
310+
unsigned int flags)
315311
{
316312
struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
317313
struct timespec64 ts;
318314

319315
if (inode->i_ino == MSDOS_ROOT_INO)
320-
return 0;
316+
return;
321317

322318
if (now == NULL) {
323319
now = &ts;
324320
ts = current_time(inode);
325321
}
326322

327-
if (flags & S_ATIME)
323+
if (flags & FAT_UPDATE_ATIME)
328324
inode_set_atime_to_ts(inode, fat_truncate_atime(sbi, now));
329-
/*
330-
* ctime and mtime share the same on-disk field, and should be
331-
* identical in memory. all mtime updates will be applied to ctime,
332-
* but ctime updates are ignored.
333-
*/
334-
if (flags & S_MTIME)
335-
inode_set_mtime_to_ts(inode,
336-
inode_set_ctime_to_ts(inode, fat_truncate_mtime(sbi, now)));
325+
if (flags & FAT_UPDATE_CMTIME) {
326+
/* truncate mtime to 2 second granularity */
327+
struct timespec64 mtime = fat_timespec64_trunc_2secs(*now);
337328

338-
return 0;
329+
inode_set_mtime_to_ts(inode, mtime);
330+
inode_set_ctime_to_ts(inode, mtime);
331+
}
339332
}
340333
EXPORT_SYMBOL_GPL(fat_truncate_time);
341334

342-
int fat_update_time(struct inode *inode, int flags)
335+
int fat_update_time(struct inode *inode, enum fs_update_time type,
336+
unsigned int flags)
343337
{
344-
int dirty_flags = 0;
345-
346-
if (inode->i_ino == MSDOS_ROOT_INO)
347-
return 0;
348-
349-
if (flags & (S_ATIME | S_CTIME | S_MTIME)) {
350-
fat_truncate_time(inode, NULL, flags);
351-
if (inode->i_sb->s_flags & SB_LAZYTIME)
352-
dirty_flags |= I_DIRTY_TIME;
353-
else
354-
dirty_flags |= I_DIRTY_SYNC;
338+
if (inode->i_ino != MSDOS_ROOT_INO) {
339+
fat_truncate_time(inode, NULL, type == FS_UPD_ATIME ?
340+
FAT_UPDATE_ATIME : FAT_UPDATE_CMTIME);
341+
__mark_inode_dirty(inode, inode_time_dirty_flag(inode));
355342
}
356-
357-
__mark_inode_dirty(inode, dirty_flags);
358343
return 0;
359344
}
360345
EXPORT_SYMBOL_GPL(fat_update_time);

fs/fat/namei_msdos.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ static int msdos_add_entry(struct inode *dir, const unsigned char *name,
251251
if (err)
252252
return err;
253253

254-
fat_truncate_time(dir, ts, S_CTIME|S_MTIME);
254+
fat_truncate_time(dir, ts, FAT_UPDATE_CMTIME);
255255
if (IS_DIRSYNC(dir))
256256
(void)fat_sync_inode(dir);
257257
else
@@ -295,7 +295,7 @@ static int msdos_create(struct mnt_idmap *idmap, struct inode *dir,
295295
err = PTR_ERR(inode);
296296
goto out;
297297
}
298-
fat_truncate_time(inode, &ts, S_ATIME|S_CTIME|S_MTIME);
298+
fat_truncate_time(inode, &ts, FAT_UPDATE_ATIME | FAT_UPDATE_CMTIME);
299299
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
300300

301301
d_instantiate(dentry, inode);
@@ -328,7 +328,6 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
328328
drop_nlink(dir);
329329

330330
clear_nlink(inode);
331-
fat_truncate_time(inode, NULL, S_CTIME);
332331
fat_detach(inode);
333332
out:
334333
mutex_unlock(&MSDOS_SB(sb)->s_lock);
@@ -382,7 +381,7 @@ static struct dentry *msdos_mkdir(struct mnt_idmap *idmap, struct inode *dir,
382381
goto out;
383382
}
384383
set_nlink(inode, 2);
385-
fat_truncate_time(inode, &ts, S_ATIME|S_CTIME|S_MTIME);
384+
fat_truncate_time(inode, &ts, FAT_UPDATE_ATIME | FAT_UPDATE_CMTIME);
386385
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
387386

388387
d_instantiate(dentry, inode);
@@ -415,7 +414,6 @@ static int msdos_unlink(struct inode *dir, struct dentry *dentry)
415414
if (err)
416415
goto out;
417416
clear_nlink(inode);
418-
fat_truncate_time(inode, NULL, S_CTIME);
419417
fat_detach(inode);
420418
out:
421419
mutex_unlock(&MSDOS_SB(sb)->s_lock);
@@ -480,7 +478,7 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
480478
mark_inode_dirty(old_inode);
481479

482480
inode_inc_iversion(old_dir);
483-
fat_truncate_time(old_dir, NULL, S_CTIME|S_MTIME);
481+
fat_truncate_time(old_dir, NULL, FAT_UPDATE_CMTIME);
484482
if (IS_DIRSYNC(old_dir))
485483
(void)fat_sync_inode(old_dir);
486484
else
@@ -540,7 +538,7 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
540538
if (err)
541539
goto error_dotdot;
542540
inode_inc_iversion(old_dir);
543-
fat_truncate_time(old_dir, &ts, S_CTIME|S_MTIME);
541+
fat_truncate_time(old_dir, &ts, FAT_UPDATE_CMTIME);
544542
if (IS_DIRSYNC(old_dir))
545543
(void)fat_sync_inode(old_dir);
546544
else
@@ -550,7 +548,6 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
550548
drop_nlink(new_inode);
551549
if (is_dir)
552550
drop_nlink(new_inode);
553-
fat_truncate_time(new_inode, &ts, S_CTIME);
554551
}
555552
out:
556553
brelse(sinfo.bh);

0 commit comments

Comments
 (0)