summaryrefslogtreecommitdiffstats
path: root/module/zfs
diff options
context:
space:
mode:
Diffstat (limited to 'module/zfs')
-rw-r--r--module/zfs/zfs_vnops.c36
1 files changed, 32 insertions, 4 deletions
diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c
index 5765c9aa6..415ba7191 100644
--- a/module/zfs/zfs_vnops.c
+++ b/module/zfs/zfs_vnops.c
@@ -218,11 +218,32 @@ zfs_close(struct inode *ip, int flag, cred_t *cr)
{
znode_t *zp = ITOZ(ip);
zfs_sb_t *zsb = ITOZSB(ip);
+ int error = 0;
ZFS_ENTER(zsb);
ZFS_VERIFY_ZP(zp);
/*
+ * When closing an mmap()'ed file ensure the inode atime, mtime, and
+ * ctime are written to disk. These values may have been updated in
+ * memory by filemap_page_mkwrite() bit are not yet reflected in the
+ * znode since writepage() may occur after the close.
+ */
+ if (zp->z_is_mapped) {
+ vattr_t *vap;
+
+ vap = kmem_zalloc(sizeof(vattr_t), KM_SLEEP);
+ vap->va_mask = ATTR_ATIME | ATTR_MTIME | ATTR_CTIME;
+ vap->va_atime = ip->i_atime;
+ vap->va_mtime = ip->i_mtime;
+ vap->va_ctime = ip->i_ctime;
+
+ error = zfs_setattr(ip, vap, 0, cr);
+
+ kmem_free(vap, sizeof(vattr_t));
+ }
+
+ /*
* Zero the synchronous opens in the znode. Under Linux the
* zfs_close() hook is not symmetric with zfs_open(), it is
* only called once when the last reference is dropped.
@@ -235,7 +256,7 @@ zfs_close(struct inode *ip, int flag, cred_t *cr)
VERIFY(zfs_vscan(ip, cr, 1) == 0);
ZFS_EXIT(zsb);
- return (0);
+ return (error);
}
EXPORT_SYMBOL(zfs_close);
@@ -3876,12 +3897,19 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc)
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_MTIME(zsb), NULL, &mtime, 16);
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_CTIME(zsb), NULL, &ctime, 16);
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_FLAGS(zsb), NULL, &zp->z_pflags, 8);
- zfs_tstamp_update_setup(zp, CONTENT_MODIFIED, mtime, ctime, B_TRUE);
- zfs_log_write(zsb->z_log, tx, TX_WRITE, zp, pgoff, pglen, 0);
+ /* Preserve the mtime and ctime provided by the inode */
+ ZFS_TIME_ENCODE(&ip->i_mtime, mtime);
+ ZFS_TIME_ENCODE(&ip->i_ctime, ctime);
+ zp->z_atime_dirty = 0;
+ zp->z_seq++;
+
+ err = sa_bulk_update(zp->z_sa_hdl, bulk, cnt, tx);
+
+ zfs_log_write(zsb->z_log, tx, TX_WRITE, zp, pgoff, pglen, 0);
dmu_tx_commit(tx);
+
zfs_range_unlock(rl);
- ASSERT3S(err, ==, 0);
if (sync) {
zil_commit(zsb->z_log, zp->z_id);