X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=module%2Fzfs%2Fzfs_vnops.c;h=415ba71911e278a7e4c5a1d7ff3d96edb7601a44;hb=d3aa3ea96e02547166563bbd60bc8581567a140a;hp=300330231dda97cd0d1bd9da52e53b7760c2f2b7;hpb=5915791096e6b5be0bad7d2e3f683b4e7908cf19;p=zfs.git diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c index 3003302..415ba71 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); @@ -3790,7 +3811,8 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc) zfs_sb_t *zsb = ITOZSB(ip); loff_t offset; loff_t pgoff; - unsigned int pglen; + unsigned int pglen; + rl_t *rl; dmu_tx_t *tx; caddr_t va; int err = 0; @@ -3799,6 +3821,8 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc) int cnt = 0; int sync; + ZFS_ENTER(zsb); + ZFS_VERIFY_ZP(zp); ASSERT(PageLocked(pp)); @@ -3810,6 +3834,7 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc) /* Page is beyond end of file */ if (pgoff >= offset) { unlock_page(pp); + ZFS_EXIT(zsb); return (0); } @@ -3832,6 +3857,7 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc) set_page_writeback(pp); unlock_page(pp); + rl = zfs_range_lock(zp, pgoff, pglen, RL_WRITER); tx = dmu_tx_create(zsb->z_os); sync = ((zsb->z_os->os_sync == ZFS_SYNC_ALWAYS) || @@ -3848,7 +3874,18 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc) if (err == ERESTART) dmu_tx_wait(tx); + /* Will call all registered commit callbacks */ dmu_tx_abort(tx); + + /* + * For the synchronous case the commit callback must be + * explicitly called because there is no registered callback. + */ + if (sync) + zfs_putpage_commit_cb(pp, ECANCELED); + + zfs_range_unlock(rl); + ZFS_EXIT(zsb); return (err); } @@ -3860,17 +3897,26 @@ 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); - ASSERT3S(err, ==, 0); + + zfs_range_unlock(rl); if (sync) { zil_commit(zsb->z_log, zp->z_id); zfs_putpage_commit_cb(pp, err); } + ZFS_EXIT(zsb); return (err); }