Mercurial > illumos > illumos-gate
changeset 4920:8b23b71806fa
4693666 fix for 4235823 reintroduced 1199162 (mmap'ed writes may fail to update mtime)
6460239 snv_46; Panic:assertion failed:(threadp())->t_flag file: ../../common/fs/ufs/lufs_debug.c, line: 198
author | frankho |
---|---|
date | Tue, 21 Aug 2007 04:08:01 -0700 |
parents | b6b235c6e23b |
children | 6179db775944 |
files | usr/src/uts/common/fs/ufs/ufs_vnops.c usr/src/uts/common/sys/fs/ufs_inode.h |
diffstat | 2 files changed, 53 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/fs/ufs/ufs_vnops.c Tue Aug 21 00:30:10 2007 -0700 +++ b/usr/src/uts/common/fs/ufs/ufs_vnops.c Tue Aug 21 04:08:01 2007 -0700 @@ -2252,6 +2252,12 @@ if (mask & AT_MTIME) { ip->i_mtime.tv_sec = vap->va_mtime.tv_sec; ip->i_mtime.tv_usec = vap->va_mtime.tv_nsec / 1000; + /* + * Allow ufs_putapage() to distinguish manual mtime + * update from one done on the fly by e.g. write(). + */ + ip->i_mtime_last = ip->i_mtime; + gethrestime(&now); if (now.tv_sec > TIME32_MAX) { /* @@ -5241,6 +5247,7 @@ daddr_t bn; int err; int contig; + int dotrans; ASSERT(RW_LOCK_HELD(&ip->i_contents)); @@ -5254,12 +5261,19 @@ /* * If the modified time on the inode has not already been - * set elsewhere (e.g. for write/setattr) we set the time now. + * set elsewhere (e.g. for write) we set the time now. * This gives us approximate modified times for mmap'ed files * which are modified via stores in the user address space. + * We _will_ override timestamps from setattr here, because + * these can be arbitrary, not "approximate" (anywhere close + * to "now"). So check whether the last timestamp update on + * this file came from setattr. */ - if ((ip->i_flag & IMODTIME) == 0) { + if ((ip->i_flag & IMODTIME) == 0 || + (ip->i_mtime.tv_sec == ip->i_mtime_last.tv_sec && + ip->i_mtime.tv_usec == ip->i_mtime_last.tv_usec)) { mutex_enter(&ip->i_tlock); + ip->i_flag &= ~IMODTIME; ip->i_flag |= IUPD; ip->i_seq++; ITIMES_NOLOCK(ip); @@ -5367,6 +5381,25 @@ bp->b_un.b_addr = (caddr_t)0; bp->b_file = ip->i_vnode; + /* + * File contents of shadow or quota inodes are metadata, and updates + * to these need to be put into a logging transaction. All direct + * callers in UFS do that, but fsflush can come here _before_ the + * normal codepath, for example on updating ACL information that'd be + * ufs_si_store()->ufs_rdwri()->wrip()->segmap_release()->VOP_PUTPAGE() + * reaches this point. + * We therefore need to test whether a transaction exists, and if not + * create one - for fsflush. + */ + dotrans = + (((ip->i_mode & IFMT) == IFSHAD || ufsvfsp->vfs_qinod == ip) && + ((curthread->t_flag & T_DONTBLOCK) == 0) && + (TRANS_ISTRANS(ufsvfsp))); + + if (dotrans) { + curthread->t_flag |= T_DONTBLOCK; + TRANS_BEGIN_ASYNC(ufsvfsp, TOP_PUTPAGE, TOP_PUTPAGE_SIZE(ip)); + } if (TRANS_ISTRANS(ufsvfsp)) { if ((ip->i_mode & IFMT) == IFSHAD) { TRANS_BUF(ufsvfsp, 0, io_len, bp, DT_SHAD); @@ -5375,6 +5408,10 @@ 0, 0); } } + if (dotrans) { + TRANS_END_ASYNC(ufsvfsp, TOP_PUTPAGE, TOP_PUTPAGE_SIZE(ip)); + curthread->t_flag &= ~T_DONTBLOCK; + } /* write throttle */ @@ -5565,8 +5602,21 @@ } mutex_enter(&ip->i_tlock); + ip->i_mapcnt -= btopr(len); /* Count released mappings */ ASSERT(ip->i_mapcnt >= 0); + + /* + * If there are cached pages on this vnode, a timestamp update + * on the next fsflush run might be required to preserve mmap + * semantics for mtime/atime updates. + * We have to force this by clearing the IMODTIME flag here. + */ + if ((flags & MAP_SHARED) && (prot & PROT_WRITE) && + vn_has_cached_data(vp)) { + ip->i_flag &= ~IMODTIME; + } + mutex_exit(&ip->i_tlock); return (0); }
--- a/usr/src/uts/common/sys/fs/ufs_inode.h Tue Aug 21 00:30:10 2007 -0700 +++ b/usr/src/uts/common/sys/fs/ufs_inode.h Tue Aug 21 04:08:01 2007 -0700 @@ -271,6 +271,7 @@ si_t *i_ufs_acl; /* pointer to acl entry */ dcanchor_t i_danchor; /* directory cache anchor */ kthread_t *i_writer; /* thread which is in window in wrip() */ + struct timeval32 i_mtime_last; /* last explicit mtime modification */ } inode_t; struct dinode {