aboutsummaryrefslogtreecommitdiff
path: root/sys/ufs/ffs
diff options
context:
space:
mode:
Diffstat (limited to 'sys/ufs/ffs')
-rw-r--r--sys/ufs/ffs/ffs_inode.c22
1 files changed, 21 insertions, 1 deletions
diff --git a/sys/ufs/ffs/ffs_inode.c b/sys/ufs/ffs/ffs_inode.c
index dbe3c9b8aa16..93836a222e5b 100644
--- a/sys/ufs/ffs/ffs_inode.c
+++ b/sys/ufs/ffs/ffs_inode.c
@@ -94,7 +94,27 @@ ffs_update(vp, waitfor)
ip = VTOI(vp);
if ((ip->i_flag & IN_MODIFIED) == 0 && waitfor == 0)
return (0);
- ip->i_flag &= ~(IN_LAZYACCESS | IN_LAZYMOD | IN_MODIFIED | IN_IBLKDATA);
+ ip->i_flag &= ~(IN_LAZYACCESS | IN_LAZYMOD | IN_MODIFIED);
+ /*
+ * The IN_SIZEMOD and IN_IBLKDATA flags indicate changes to the
+ * file size and block pointer fields in the inode. When these
+ * fields have been changed, the fsync() and fsyncdata() system
+ * calls must write the inode to ensure their semantics that the
+ * file is on stable store.
+ *
+ * The IN_SIZEMOD and IN_IBLKDATA flags cannot be cleared until
+ * a synchronous write of the inode is done. If they are cleared
+ * on an asynchronous write, then the inode may not yet have been
+ * written to the disk when an fsync() or fsyncdata() call is done.
+ * Absent these flags, these calls would not know that they needed
+ * to write the inode. Thus, these flags only can be cleared on
+ * synchronous writes of the inode. Since the inode will be locked
+ * for the duration of the I/O that writes it to disk, no fsync()
+ * or fsyncdata() will be able to run before the on-disk inode
+ * is complete.
+ */
+ if (waitfor)
+ ip->i_flag &= ~(IN_SIZEMOD | IN_IBLKDATA);
fs = ITOFS(ip);
if (fs->fs_ronly && ITOUMP(ip)->um_fsckpid == 0)
return (0);