git: e8534ba3ad36 - main - ufs: do not let a rolled back inode write end a data-only sync
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 13 Oct 2026 04:29:56 UTC
The branch main has been updated by sobomax:
URL: https://cgit.FreeBSD.org/src/commit/?id=e8534ba3ad36b88e94de0a3174e9ab7ac04a929d
commit e8534ba3ad36b88e94de0a3174e9ab7ac04a929d
Author: Maxim Sobolev <sobomax@FreeBSD.org>
AuthorDate: 2026-10-13 02:44:40 +0000
Commit: Maxim Sobolev <sobomax@FreeBSD.org>
CommitDate: 2026-10-13 04:28:32 +0000
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)