The fdatasync() description in POSIX specifies that
all I/O operations shall be completed as defined for synchronized I/O data integrity completion.
and then the explanation of Synchronized I/O Data Integrity Completion
The write is complete only when the data specified in the write request is successfully transferred and all file system information required to retrieve the data is successfully transferred.
For UFS this means that all pointers must be on disk. Indirect pointers already contribute to the list of dirty data blocks, so only direct blocks and root pointers for indirect blocks, both of which reside in inode block, should be taken care of. In ffs_balloc(), mark the inode with the new flag IN_IBLKDATA that specifies that ffs_syncvnode() call to ffs_update() needs to flush the inode block.
N.B. I will do additional pass after this change, to redefine waitfor argument for ffs_update() symbolically.