ufs: make fdatasync(2) and O_DSYNC writes update the inode

ffs_syncvnode() in the DATA_ONLY case and ffs_write() for IO_DATASYNC
decide whether the inode has to be written by testing IN_SIZEMOD and
IN_IBLKDATA against ip->i_flags, the chflags(2) word, instead of the
in-core state ip->i_flag.  IN_SIZEMOD and IN_IBLKDATA alias UF_READONLY
and UF_ARCHIVE, so for ordinary files the test was always false: after
an fdatasync() or an O_DSYNC write that extended a file or filled a
hole, the data blocks were on disk but the inode size and block pointers
were not, and a crash before the syncer got to the inode lost the
"synced" data.  Files with uarchive or urdonly set got a synchronous
inode write on every call instead.

journal_mount() has the same mixup and sets IN_MODIFIED in i_flags,
which leaves UF_OPAQUE set on the in-core .sujournal inode.  The
synchronous ffs_update() that follows writes the inode regardless, so
only the stray flag is fixed here.

Fixes:	7428630b75 ("UFS: write inode block for fdatasync(2) if pointers in inode where allocated")
Fixes:	52488b5148 ("Further evaluation of the POSIX spec for fdatasync()...")
Fixes:	e7347be9e3 ("ffs: Support O_DSYNC.")
Fixes:	113db2dddb ("Merge soft-updates journaling from projects/suj/head into head.")

Sponsored by:	Sippy Software, Inc.
Reviewed by:	kib
Tested by:	pho
Differential Revision:	https://reviews.freebsd.org/D60134
MFC after:	1 month
This commit is contained in:
Maxim Sobolev committed 2026-10-12 21:28:32 -07:00
1 parent 2aca5deff7
commit 8ff663dde2
2 files changed
+3 -3

No files matched your search

+1 -1
View File
@@ -2976,7 +2976,7 @@ journal_mount(struct mount *mp,
*/
if (fs->fs_clean) {
DIP_SET(ip, i_modrev, fs->fs_mtime);
ip->i_flags |= IN_MODIFIED;
ip->i_flag |= IN_MODIFIED;
ffs_update(vp, 1);
}
out:
+2 -2
View File
@@ -458,7 +458,7 @@ next_locked:
error = ffs_update(vp, 1);
if (DOINGSUJ(vp))
softdep_journal_fsync(VTOI(vp));
} else if ((ip->i_flags & (IN_SIZEMOD | IN_IBLKDATA)) != 0) {
} else if ((ip->i_flag & (IN_SIZEMOD | IN_IBLKDATA)) != 0) {
error = ffs_update(vp, 1);
}
if (error == 0 && unlocked)
@@ -1044,7 +1044,7 @@ ffs_write(
}
} else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) {
if (!(ioflag & IO_DATASYNC) ||
(ip->i_flags & (IN_SIZEMOD | IN_IBLKDATA)))
(ip->i_flag & (IN_SIZEMOD | IN_IBLKDATA)))
error = ffs_update(vp, 1);
if (ffs_fsfail_cleanup(VFSTOUFS(vp->v_mount), error))
error = ENXIO;