diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c index 5765c9aa62..415ba71911 100644 --- a/module/zfs/zfs_vnops.c +++ b/module/zfs/zfs_vnops.c @@ -218,10 +218,31 @@ 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 @@ -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);