From: Rafael Sadowski Subject: Re: relatime mount option for ffs filesystems To: tech@openbsd.org, Marcus Glocker Date: Fri, 19 Sep 2025 16:39:53 +0200 On Thu Sep 18, 2025 at 07:13:51PM +0200, Jeremie Courreges-Anglas wrote: > On Tue, Aug 05, 2025 at 10:29:53AM +0100, Stuart Henderson wrote: > > On 2025/08/05 06:59, Marcus Glocker wrote: > > > On Mon, Aug 04, 2025 at 05:35:01PM +0200, Jeremie Courreges-Anglas wrote: > > > > > > > > > > > With relatime, access time is updated on reads only if the file has > > > > been modified (mtime/ctime) since the last read. So merely reading > > > > files no longer incurs pointless writes. > > .. > > > > The diff below implements it for ffs only. It doesn't implement > > > > possible tweaks like updating atime if previous access happened more > > > > than 24 hours ago. > > > > the ">24h" possible tweak would be helpful for this: > > > > > /dev/sd0d on /tmp type ffs (local, relatime, nodev, nosuid) > > > > without that, you should probably not use it for /tmp. > > > > $ grep -A8 tmp /etc/daily > > Indeed, here's a diff that adds the >24h check. > > I still think we want something like this, though I won't push for > this before the next release cycle. > > Feedback and input still welcome. > Thanks Jeremie for the impl. I like it to have something like is. I'm running with this, so far so good. Some comments below. > > Index: lib/libc/sys/mount.2 > =================================================================== > RCS file: /home/cvs/src/lib/libc/sys/mount.2,v > diff -u -p -r1.53 mount.2 > --- lib/libc/sys/mount.2 6 Aug 2025 13:23:27 -0000 1.53 > +++ lib/libc/sys/mount.2 18 Sep 2025 16:46:57 -0000 > @@ -78,6 +78,9 @@ suppress default semantics which affect > .It Dv MNT_RDONLY > The filesystem should be treated as read-only: > even the superuser may not write to it. > +.It Dv MNT_RELATIME > +Only update the access time on files in the filesystem if the modification > +or status change times are newer. > .It Dv MNT_NOATIME > Do not update the access time on files in the filesystem unless > the modification or status change times are also being updated. > Index: sbin/mount/mntopts.h > =================================================================== > RCS file: /home/cvs/src/sbin/mount/mntopts.h,v > diff -u -p -r1.18 mntopts.h > --- sbin/mount/mntopts.h 10 Sep 2016 16:53:30 -0000 1.18 > +++ sbin/mount/mntopts.h 18 Sep 2025 16:46:57 -0000 > @@ -61,6 +61,7 @@ union mntval { > #define MOPT_NOPERM { "perm", MNT_NOPERM, MFLAG_INVERSE | MFLAG_SET } > #define MOPT_WXALLOWED { "wxallowed", MNT_WXALLOWED, MFLAG_SET } > #define MOPT_RDONLY { "rdonly", MNT_RDONLY, MFLAG_SET } > +#define MOPT_RELATIME { "relatime", MNT_RELATIME, MFLAG_SET } > #define MOPT_SYNC { "sync", MNT_SYNCHRONOUS, MFLAG_SET } > #define MOPT_USERQUOTA { "userquota", 0, MFLAG_SET | MFLAG_STRVAL \ > | MFLAG_OPT } > Index: sbin/mount/mount.8 > =================================================================== > RCS file: /home/cvs/src/sbin/mount/mount.8,v > diff -u -p -r1.92 mount.8 > --- sbin/mount/mount.8 10 Nov 2023 00:26:00 -0000 1.92 > +++ sbin/mount/mount.8 18 Sep 2025 16:46:57 -0000 > @@ -178,8 +178,16 @@ The same as > .Fl f ; > forces the revocation of write access when trying to downgrade > a file system mount status from read-write to read-only. > +.It Cm relatime > +(FFS only) > +Only update the access time on files in the filesystem if it is older > +than the modification or change time. > +Like > +.Cm noatime , > +it is useful to avoid extra disk activity, but is also more friendly > +to some applications. > .It Cm noatime > -Do not update atime on files in the system unless the mtime or ctime > +Do not update atime on files in the filesystem unless the mtime or ctime > is being changed as well. > This option is useful for laptops and news servers where one does > not want the extra disk activity associated with updating the atime. > Index: sbin/mount/mount.c > =================================================================== > RCS file: /home/cvs/src/sbin/mount/mount.c,v > diff -u -p -r1.78 mount.c > --- sbin/mount/mount.c 9 May 2024 08:35:40 -0000 1.78 > +++ sbin/mount/mount.c 18 Sep 2025 16:46:57 -0000 > @@ -84,6 +84,7 @@ static struct opt { > { MNT_EXPORTANON, 1, "anon uid mapping", "" }, > { MNT_EXRDONLY, 1, "exported read-only", "" }, > { MNT_LOCAL, 0, "local", "" }, > + { MNT_RELATIME, 0, "relatime", "relatime" }, > { MNT_NOATIME, 0, "noatime", "noatime" }, > { MNT_NODEV, 0, "nodev", "nodev" }, > { MNT_NOEXEC, 0, "noexec", "noexec" }, > Index: sbin/mount_ffs/mount_ffs.c > =================================================================== > RCS file: /home/cvs/src/sbin/mount_ffs/mount_ffs.c,v > diff -u -p -r1.26 mount_ffs.c > --- sbin/mount_ffs/mount_ffs.c 4 Dec 2022 23:50:46 -0000 1.26 > +++ sbin/mount_ffs/mount_ffs.c 18 Sep 2025 16:46:57 -0000 > @@ -52,6 +52,7 @@ static const struct mntopt mopts[] = { > MOPT_ASYNC, > MOPT_SYNC, > MOPT_UPDATE, > + MOPT_RELATIME, > MOPT_RELOAD, > MOPT_FORCE, > MOPT_SOFTDEP, > Index: sbin/newfs/newfs.c > =================================================================== > RCS file: /home/cvs/src/sbin/newfs/newfs.c,v > diff -u -p -r1.120 newfs.c > --- sbin/newfs/newfs.c 17 Sep 2025 16:07:57 -0000 1.120 > +++ sbin/newfs/newfs.c 18 Sep 2025 16:46:57 -0000 > @@ -82,6 +82,7 @@ struct mntopt mopts[] = { > MOPT_ASYNC, > MOPT_UPDATE, > MOPT_FORCE, > + MOPT_RELATIME, > { NULL }, > }; > > Index: sys/kern/vfs_syscalls.c > =================================================================== > RCS file: /home/cvs/src/sys/kern/vfs_syscalls.c,v > diff -u -p -r1.377 vfs_syscalls.c > --- sys/kern/vfs_syscalls.c 4 Aug 2025 04:59:31 -0000 1.377 > +++ sys/kern/vfs_syscalls.c 18 Sep 2025 16:46:57 -0000 > @@ -238,10 +238,11 @@ update: > else if (mp->mnt_flag & MNT_RDONLY) > mp->mnt_flag |= MNT_WANTRDWR; > mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_WXALLOWED | MNT_NODEV | > - MNT_SYNCHRONOUS | MNT_ASYNC | MNT_NOATIME | MNT_NOPERM | MNT_FORCE); > + MNT_SYNCHRONOUS | MNT_ASYNC | MNT_RELATIME | MNT_NOATIME | > + MNT_NOPERM | MNT_FORCE); > mp->mnt_flag |= flags & (MNT_NOSUID | MNT_NOEXEC | MNT_WXALLOWED | > - MNT_NODEV | MNT_SYNCHRONOUS | MNT_ASYNC | MNT_NOATIME | MNT_NOPERM | > - MNT_FORCE); > + MNT_NODEV | MNT_SYNCHRONOUS | MNT_ASYNC | MNT_RELATIME | MNT_NOATIME | > + MNT_NOPERM | MNT_FORCE); > /* > * Mount the filesystem. > */ > Index: sys/sys/mount.h > =================================================================== > RCS file: /home/cvs/src/sys/sys/mount.h,v > diff -u -p -r1.153 mount.h > --- sys/sys/mount.h 2 Jan 2025 01:19:22 -0000 1.153 > +++ sys/sys/mount.h 18 Sep 2025 16:46:57 -0000 > @@ -383,14 +383,14 @@ struct mount { > /* > * Mask of flags that are visible to statfs() > */ > -#define MNT_VISFLAGMASK 0x0400ffff > +#define MNT_VISFLAGMASK 0x0440ffff > > #define MNT_BITS \ > "\20\001RDONLY\002SYNCHRONOUS\003NOEXEC\004NOSUID\005NODEV\006NOPERM" \ > "\007ASYNC\010EXRDONLY\011EXPORTED\012DEFEXPORTED\013EXPORTANON" \ > "\014WXALLOWED\015LOCAL\016QUOTA\017ROOTFS\020NOATIME\021UPDATE" \ > - "\022DELEXPORT\023RELOAD\024FORCE\025STALLED\026SWAPPABLE\031UNMOUNT" \ > - "\032WANTRDWR\033SOFTDEP\034DOOMED" > + "\022DELEXPORT\023RELOAD\024FORCE\025STALLED\026SWAPPABLE\027RELATIME" \ > + "\031UNMOUNT\032WANTRDWR\033SOFTDEP\034DOOMED" > > /* > * filesystem control flags. > @@ -401,6 +401,7 @@ struct mount { > #define MNT_FORCE 0x00080000 /* force unmount or readonly change */ > #define MNT_STALLED 0x00100000 /* filesystem stalled */ > #define MNT_SWAPPABLE 0x00200000 /* filesystem can be used for swap */ > +#define MNT_RELATIME 0x00400000 /* update atime iff <= to ctime/mtime */ > #define MNT_UNMOUNT 0x01000000 /* unmount in progress */ > #define MNT_WANTRDWR 0x02000000 /* want upgrade to read/write */ > #define MNT_SOFTDEP 0x04000000 /* soft dependencies being done - now ignored */ > Index: sys/ufs/ufs/ufs_vnops.c > =================================================================== > RCS file: /home/cvs/src/sys/ufs/ufs/ufs_vnops.c,v > diff -u -p -r1.164 ufs_vnops.c > --- sys/ufs/ufs/ufs_vnops.c 18 Oct 2024 05:52:33 -0000 1.164 > +++ sys/ufs/ufs/ufs_vnops.c 18 Sep 2025 17:08:39 -0000 > @@ -94,6 +94,7 @@ ufs_itimes(struct vnode *vp) > { > struct inode *ip; > struct timespec ts; > + int modified = 0; > > ip = VTOI(vp); > if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0) > @@ -109,27 +110,58 @@ ufs_itimes(struct vnode *vp) > } > #endif > > - if ((vp->v_type == VBLK || vp->v_type == VCHR)) > - ip->i_flag |= IN_LAZYMOD; > - else > - ip->i_flag |= IN_MODIFIED; > - > getnanotime(&ts); > - if (ip->i_flag & IN_ACCESS) { > - DIP_ASSIGN(ip, atime, ts.tv_sec); > - DIP_ASSIGN(ip, atimensec, ts.tv_nsec); > - } > if (ip->i_flag & IN_UPDATE) { > DIP_ASSIGN(ip, mtime, ts.tv_sec); > DIP_ASSIGN(ip, mtimensec, ts.tv_nsec); > + modified = 1; > } > if (ip->i_flag & IN_CHANGE) { > DIP_ASSIGN(ip, ctime, ts.tv_sec); > DIP_ASSIGN(ip, ctimensec, ts.tv_nsec); > ip->i_modrev++; > + modified = 1; > + } > + if (ip->i_flag & IN_ACCESS) { > + if (vp->v_mount->mnt_flag & MNT_RELATIME) { > + struct timespec atime, ctime, mtime; > + > + atime.tv_sec = DIP(ip, atime); > + atime.tv_nsec = DIP(ip, atimensec); > + ctime.tv_sec = DIP(ip, ctime); > + ctime.tv_nsec = DIP(ip, ctimensec); > + mtime.tv_sec = DIP(ip, mtime); > + mtime.tv_nsec = DIP(ip, mtimensec); > + > + /* > + * Update atime in the following cases: > + * - atime is older than ctime/mtime > + * - atime is older than 24 hours > + */ > + if (timespeccmp(&atime, &ctime, <) || > + timespeccmp(&atime, &mtime, <) || > + (ts.tv_sec - atime.tv_sec) >= 86400) { Could we use something like this? #define RELATIME_THRESHOLD_SEC 86400 > + DIP_ASSIGN(ip, atime, ts.tv_sec); > + DIP_ASSIGN(ip, atimensec, ts.tv_nsec); > + modified = 1; > + } > + } else { > + DIP_ASSIGN(ip, atime, ts.tv_sec); > + DIP_ASSIGN(ip, atimensec, ts.tv_nsec); > + modified = 1; > + } I know we low endless functions in FS but all of this could also be a function. > + > } > > - out: > + if (!modified) > + goto out; > + > + if ((vp->v_type == VBLK || vp->v_type == VCHR)) > + ip->i_flag |= IN_LAZYMOD; > + else > + ip->i_flag |= IN_MODIFIED; > + > +out: > ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE); > } > > @@ -429,10 +461,14 @@ ufs_setattr(void *v) > if (vap->va_mtime.tv_nsec != VNOVAL) { > DIP_ASSIGN(ip, mtime, vap->va_mtime.tv_sec); > DIP_ASSIGN(ip, mtimensec, vap->va_mtime.tv_nsec); > + /* mtime change explicitely requested */ s/explicitely/explicitly/ > + ip->i_flag |= IN_MODIFIED; > } > if (vap->va_atime.tv_nsec != VNOVAL) { > DIP_ASSIGN(ip, atime, vap->va_atime.tv_sec); > DIP_ASSIGN(ip, atimensec, vap->va_atime.tv_nsec); > + /* atime change explicitely requested */ s/explicitely/explicitly/ > + ip->i_flag |= IN_MODIFIED; > } > error = UFS_UPDATE(ip, 0); > if (error) > Index: usr.sbin/pstat/pstat.c > =================================================================== > RCS file: /home/cvs/src/usr.sbin/pstat/pstat.c,v > diff -u -p -r1.130 pstat.c > --- usr.sbin/pstat/pstat.c 10 Jul 2024 13:29:23 -0000 1.130 > +++ usr.sbin/pstat/pstat.c 18 Sep 2025 16:46:57 -0000 > @@ -789,6 +789,11 @@ mount_print(struct mount *mp) > flags &= ~MNT_ROOTFS; > comma = ","; > } > + if (flags & MNT_RELATIME) { > + (void)printf("%srelatime", comma); > + flags &= ~MNT_RELATIME; > + comma = ","; > + } > if (flags & MNT_NOATIME) { > (void)printf("%snoatime", comma); > flags &= ~MNT_NOATIME; > > > -- > jca >