From e8534ba3ad36b88e94de0a3174e9ab7ac04a929d Mon Sep 17 00:00:00 2001 From: Maxim Sobolev Date: Mon, 12 Oct 2026 19:44:40 -0700 Subject: [PATCH] ufs: do not let a rolled back inode write end a data-only sync With soft updates, ffs_syncvnode() writes the inode between its passes while buffers are still dirty. That write can go out with new block pointers rolled back, for instance a new indirect block whose contents are only written in a later pass, yet ffs_update() clears IN_SIZEMOD and IN_IBLKDATA because the write was synchronous. A data-only sync then decides at the end that the inode need not be written, and fdatasync(2) or an O_DSYNC write that allocated the first indirect block returned with the on-disk inode not pointing to it. Note on entry whether a data-only sync has to write the inode, and base the final write, done once all dependencies are flushed, on that alone: nothing else can set IN_SIZEMOD or IN_IBLKDATA meanwhile, as the vnode is locked. A full sync always writes the inode last and was not affected. Sponsored by: Sippy Software, Inc. Reviewed by: kib Tested by: pho Differential Revision: https://reviews.freebsd.org/D60134 MFC after: 1 month --- sys/ufs/ffs/ffs_vnops.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c index 493936578095..8cdad58a3096 100644 --- a/sys/ufs/ffs/ffs_vnops.c +++ b/sys/ufs/ffs/ffs_vnops.c @@ -271,11 +271,18 @@ ffs_syncvnode(struct vnode *vp, int waitfor, int flags) struct buf *bp, *nbp; ufs_lbn_t lbn; int error, passes, wflag; - bool unlocked, wait; + bool inoupdt, unlocked, wait; ip = VTOI(vp); bo = &vp->v_bufobj; ump = VFSTOUFS(vp->v_mount); + /* + * With soft updates, the passes below may write the inode while + * new block pointers in it are still rolled back. That clears + * IN_SIZEMOD and IN_IBLKDATA all the same, so note up front + * whether a data-only sync has to write the inode. + */ + inoupdt = (ip->i_flag & (IN_SIZEMOD | IN_IBLKDATA)) != 0; #ifdef WITNESS wflag = IS_SNAPSHOT(ip) ? LK_NOWITNESS : 0; #else @@ -442,7 +449,7 @@ next_locked: error = ffs_update(vp, 1); if (DOINGSUJ(vp)) softdep_journal_fsync(VTOI(vp)); - } else if ((ip->i_flag & (IN_SIZEMOD | IN_IBLKDATA)) != 0) { + } else if (inoupdt) { error = ffs_update(vp, 1); } if (error == 0 && unlocked)