aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKirk McKusick <mckusick@FreeBSD.org>2020-06-06 20:17:56 +0000
committerKirk McKusick <mckusick@FreeBSD.org>2020-06-06 20:17:56 +0000
commit513274c79c6a7757b580be03ffd2e022f2f047fb (patch)
treef99cd3dbdf01664baa4a3d0dbdfd3e05869d2bcc
parent9016fac6a2e6d1060b954134e0bccb9b7a033afd (diff)
downloadsrc-513274c79c6a7757b580be03ffd2e022f2f047fb.tar.gz
src-513274c79c6a7757b580be03ffd2e022f2f047fb.zip
Clear the IN_SIZEMOD and IN_IBLKDATA flags only when doing a
synchronous inode update. 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. Reviewed by: kib MFC with: -r361785 Differential revision: https://reviews.freebsd.org/D25072
Notes
Notes: svn path=/head/; revision=361875
-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);