From owner-freebsd-bugs Sat Dec 28 06:21:25 1996 Return-Path: Received: (from root@localhost) by freefall.freebsd.org (8.8.4/8.8.4) id GAA13209 for bugs-outgoing; Sat, 28 Dec 1996 06:21:25 -0800 (PST) Received: from godzilla.zeta.org.au (godzilla.zeta.org.au [203.2.228.19]) by freefall.freebsd.org (8.8.4/8.8.4) with ESMTP id GAA13202 for ; Sat, 28 Dec 1996 06:21:17 -0800 (PST) Received: (from bde@localhost) by godzilla.zeta.org.au (8.8.3/8.6.9) id BAA20220; Sun, 29 Dec 1996 01:17:04 +1100 Date: Sun, 29 Dec 1996 01:17:04 +1100 From: Bruce Evans Message-Id: <199612281417.BAA20220@godzilla.zeta.org.au> To: bugs@freebsd.org Subject: another POSIX access timestamp pessimization Cc: bde@zeta.org.au Sender: owner-bugs@freebsd.org X-Loop: FreeBSD.org Precedence: bulk POSIX says that "Upon successful completion, the exec functions shall mark for update the st_atime field of the file". Not content with this pessimization, it also specifies that exec shall be considered as doing an open() and close() where the close() occurs before the process terminates and before the next successful exec. The access time must be updated if the close() leaves the file completely closed. In FreeBSD, marking for update dirties inodes just as much as update and update is cheap, so the second pessimization doesn't make much difference. Here is a (not very good) implementation. It updates the access time immediately. This slows down execs on ufs a little (caching works) and slows down execs on an nfs file system a lot (about 1 msec per exec for a 10Mbps ethernet). It's remarkably inconvenient to get at the update flags and/or the access times from the vfs level. I used VFS_SETATTR() and added a flag to tell it what to do. There was a bug in handling the existing flag VA_UTIMES_NULL - suser() was sometimes called although no superuser privilege was used. Bruce diff -c2 src/sys/sys/vnode.h~ src/sys/sys/vnode.h *** src/sys/sys/vnode.h~ Fri Oct 18 07:07:42 1996 --- src/sys/sys/vnode.h Wed Dec 11 18:34:10 1996 *************** *** 156,159 **** --- 156,160 ---- */ #define VA_UTIMES_NULL 0x01 /* utimes argument was NULL */ + #define VA_EXECVE_ATIME 0x02 /* setting atime for execve */ /* diff -c2 src/sys/kern/kern_exec.c~ src/sys/kern/kern_exec.c *** src/sys/kern/kern_exec.c~ Sun Nov 10 05:00:02 1996 --- src/sys/kern/kern_exec.c Wed Dec 11 19:12:39 1996 *************** *** 323,326 **** --- 323,341 ---- (vm_offset_t)imgp->image_header + PAGE_SIZE)) panic("execve: header dealloc failed (2)"); + + if (!(ndp->ni_vp->v_mount->mnt_flag & MNT_NOATIME)) { + struct timeval tv; + struct vattr vattr; + + VATTR_NULL(&vattr); + microtime(&tv); + TIMEVAL_TO_TIMESPEC(&tv, &vattr.va_atime); + vattr.va_vaflags |= VA_EXECVE_ATIME; + LEASE_CHECK(ndp->ni_vp, p, p->p_ucred, LEASE_WRITE); + VOP_LOCK(ndp->ni_vp); + (void) VOP_SETATTR(ndp->ni_vp, &vattr, p->p_ucred, p); + VOP_UNLOCK(ndp->ni_vp); + } + vrele(ndp->ni_vp); FREE(ndp->ni_cnd.cn_pnbuf, M_NAMEI); diff -c2 src/sys/ufs/ufs/ufs_vnops.c~ src/sys/ufs/ufs/ufs_vnops.c *** src/sys/ufs/ufs/ufs_vnops.c~ Tue Nov 5 21:05:36 1996 --- src/sys/ufs/ufs/ufs_vnops.c Wed Dec 11 19:11:37 1996 *************** *** 422,438 **** return (EROFS); if (cred->cr_uid != ip->i_uid && ! (error = suser(cred, &p->p_acflag)) && ! ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || ! (error = VOP_ACCESS(vp, VWRITE, cred, p)))) ! return (error); if (vap->va_atime.tv_sec != VNOVAL) ip->i_flag |= IN_ACCESS; if (vap->va_mtime.tv_sec != VNOVAL) ip->i_flag |= IN_CHANGE | IN_UPDATE; atimeval.tv_sec = vap->va_atime.tv_sec; atimeval.tv_usec = vap->va_atime.tv_nsec / 1000; mtimeval.tv_sec = vap->va_mtime.tv_sec; mtimeval.tv_usec = vap->va_mtime.tv_nsec / 1000; ! error = VOP_UPDATE(vp, &atimeval, &mtimeval, 1); if (error) return (error); --- 417,438 ---- return (EROFS); if (cred->cr_uid != ip->i_uid && ! !(vap->va_vaflags & VA_EXECVE_ATIME)) { ! if (vap->va_vaflags & VA_UTIMES_NULL) ! error = VOP_ACCESS(vp, VWRITE, cred, p); ! else ! error = suser(cred, &p->p_acflag); ! if (error != 0) ! return (error); ! } if (vap->va_atime.tv_sec != VNOVAL) ip->i_flag |= IN_ACCESS; if (vap->va_mtime.tv_sec != VNOVAL) ip->i_flag |= IN_CHANGE | IN_UPDATE; atimeval.tv_sec = vap->va_atime.tv_sec; atimeval.tv_usec = vap->va_atime.tv_nsec / 1000; mtimeval.tv_sec = vap->va_mtime.tv_sec; mtimeval.tv_usec = vap->va_mtime.tv_nsec / 1000; ! error = VOP_UPDATE(vp, &atimeval, &mtimeval, + vap->va_vaflags & VA_EXECVE_ATIME ? 0 : 1); if (error) return (error);