summaryrefslogtreecommitdiffstats
path: root/sys/ufs
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2015-06-17 04:46:58 +0000
committerkib <kib@FreeBSD.org>2015-06-17 04:46:58 +0000
commitbecc575eec74ac5ab5b5c8e2033984ef817278cd (patch)
treebfd022b022229bc69d32e97c26a9ebb4ba478226 /sys/ufs
parent6f06df98abde25c97a9ae45a2479ffec690e1b32 (diff)
downloadFreeBSD-src-becc575eec74ac5ab5b5c8e2033984ef817278cd.zip
FreeBSD-src-becc575eec74ac5ab5b5c8e2033984ef817278cd.tar.gz
vfs_msync(), called from syncer vnode fsync VOP, only iterates over
the active vnode list for the given mount point, with the assumption that vnodes with dirty pages are active. This is enforced by vinactive() doing vm_object_page_clean() pass over the vnode pages. The issue is, if vinactive() cannot be called during vput() due to the vnode being only shared-locked, we might end up with the dirty pages for the vnode on the free list. Such vnode is invisible to syncer, and pages are only cleaned on the vnode reactivation. In other words, the race results in the broken guarantee that user data, written through the mmap(2), is written to the disk not later than in 30 seconds after the write. Fix this by keeping the vnode which is freed but still owing inactivation, on the active list. When syncer loops find such vnode, it is deactivated and cleaned by the final vput() call. Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 2 weeks
Diffstat (limited to 'sys/ufs')
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index ce43bcd..ffd8802 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -1410,6 +1410,14 @@ ffs_statfs(mp, sbp)
return (0);
}
+static bool
+sync_doupdate(struct inode *ip)
+{
+
+ return ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED |
+ IN_UPDATE)) != 0);
+}
+
/*
* For a lazy sync, we only care about access times, quotas and the
* superblock. Other filesystem changes are already converted to
@@ -1443,15 +1451,15 @@ ffs_sync_lazy(mp)
* Test also all the other timestamp flags too, to pick up
* any other cases that could be missed.
*/
- if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED |
- IN_UPDATE)) == 0) {
+ if (!sync_doupdate(ip) && (vp->v_iflag & VI_OWEINACT) == 0) {
VI_UNLOCK(vp);
continue;
}
if ((error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK,
td)) != 0)
continue;
- error = ffs_update(vp, 0);
+ if (sync_doupdate(ip))
+ error = ffs_update(vp, 0);
if (error != 0)
allerror = error;
vput(vp);
OpenPOWER on IntegriCloud