Re: git: 1111a44301da - main - Defer the January 19, 2038 date limit in UFS1 filesystems to February 7, 2106

From: Andre Albsmeier <mail_at_fbsd2.e4m.org>
Date: Wed, 20 May 2026 15:47:35 UTC
On Fri, 31-Jan-2025 at 01:31:27 +0000, Kirk McKusick wrote:
> The branch main has been updated by mckusick:
> 
> URL: https://cgit.FreeBSD.org/src/commit/?id=1111a44301da39d7b7459c784230e1405e8980f8
> 
> commit 1111a44301da39d7b7459c784230e1405e8980f8
> Author:     Kirk McKusick <mckusick@FreeBSD.org>
> AuthorDate: 2025-01-31 01:27:59 +0000
> Commit:     Kirk McKusick <mckusick@FreeBSD.org>
> CommitDate: 2025-01-31 01:31:08 +0000
> 
>     Defer the January 19, 2038 date limit in UFS1 filesystems to February 7, 2106
> ...

Should the calls to ffs_oldfscompat_inode_read() in ffsck's inode.c (see below)
be made conditionally? Maybe depending on some loader hint or wheter fsck runs
in preen mode?

This is what happened:

A server which runs 24/7 and is using UFS1 had a short power outage. Next day
I found stuff like

...
- 32705 -r-sr-xr-x  1 root wheel     23744 2026-05-08T18:40:37 /usr/bin/login
+ 32705 -r-sr-xr-x  1 root wheel     23744 2024-02-16T16:34:12 /usr/bin/login
@@ -20 +20 @@
- 32751 -r-xr-sr-x  1 root kmem     190944 2026-05-08T18:40:39 /usr/bin/netstat
+ 32751 -r-xr-sr-x  1 root kmem     190944 2024-02-16T16:33:25 /usr/bin/netstat
...

in the daily security output. In fact, timestamps of most files were set to
2024-02-16. This happened because the CMOS battery was down and when power
came back, the machine started with the BIOS build date. When fsck ran,
ffs_oldfscompat_inode_read() found that this is UFS1 with the various inode
times being newer than "now" and changed them to "now".

So maybe some knob to disable this (at least for fsck when being run during
startup) could help - at least for people who are sure not to have files
older that 1970...


> --- a/sbin/fsck_ffs/inode.c
> +++ b/sbin/fsck_ffs/inode.c
> @@ -46,6 +46,7 @@
>  #include "fsck.h"
>  
>  struct bufarea *icachebp;	/* inode cache buffer */
> +static time_t now;		/* current time of day */
>  
>  static int iblock(struct inodesc *, off_t isize, int type);
>  static ufs2_daddr_t indir_blkatoff(ufs2_daddr_t, ino_t, ufs_lbn_t, ufs_lbn_t,
> @@ -429,6 +430,7 @@ void
>  ginode(ino_t inumber, struct inode *ip)
>  {
>  	ufs2_daddr_t iblk;
> +	union dinodep dpp;
>  	struct ufs2_dinode *dp;
>  
>  	if (inumber < UFS_ROOTINO || inumber >= maxino)
> @@ -466,10 +468,14 @@ ginode(ino_t inumber, struct inode *ip)
>  	if (sblock.fs_magic == FS_UFS1_MAGIC) {
>  		ip->i_dp = (union dinode *)
>  		    &ip->i_bp->b_un.b_dinode1[inumber - ip->i_bp->b_index];
> +		dpp.dp1 = (struct ufs1_dinode *)ip->i_dp;
> +		if (ffs_oldfscompat_inode_read(&sblock, dpp, now))
> +			inodirty(ip);
>  		return;
>  	}
>  	ip->i_dp = (union dinode *)
>  	    &ip->i_bp->b_un.b_dinode2[inumber - ip->i_bp->b_index];
> +	dpp.dp2 = dp = (struct ufs2_dinode *)ip->i_dp;
>  	/* Do not check hash of inodes being created */
>  	if (dp->di_mode != 0 && ffs_verify_dinode_ckhash(&sblock, dp)) {
>  		pwarn("INODE CHECK-HASH FAILED");
> @@ -481,6 +487,8 @@ ginode(ino_t inumber, struct inode *ip)
>  			inodirty(ip);
>  		}
>  	}
> +	if (ffs_oldfscompat_inode_read(&sblock, dpp, now))
> +		inodirty(ip);
>  }
>  
>  /*
> @@ -519,6 +527,7 @@ getnextinode(ino_t inumber, int rebuiltcg)
>  	mode_t mode;
>  	ufs2_daddr_t ndb, blk;
>  	union dinode *dp;
> +	union dinodep dpp;
>  	struct inode ip;
>  	static caddr_t nextinop;
>  
> @@ -551,8 +560,10 @@ getnextinode(ino_t inumber, int rebuiltcg)
>  	dp = (union dinode *)nextinop;
>  	if (sblock.fs_magic == FS_UFS1_MAGIC) {
>  		nextinop += sizeof(struct ufs1_dinode);
> +		dpp.dp1 = (struct ufs1_dinode *)dp;
>  	} else {
>  		nextinop += sizeof(struct ufs2_dinode);
> +		dpp.dp2 = (struct ufs2_dinode *)dp;
>  	}
>  	if ((ckhashadd & CK_INODE) != 0) {
>  		ffs_update_dinode_ckhash(&sblock, (struct ufs2_dinode *)dp);
> @@ -572,6 +583,8 @@ getnextinode(ino_t inumber, int rebuiltcg)
>  			dirty(&inobuf);
>  		}
>  	}
> +	if (ffs_oldfscompat_inode_read(&sblock, dpp, now))
> +		dirty(&inobuf);
>  	if (rebuiltcg && (char *)dp == inobuf.b_un.b_buf) {
>  		/*
>  		 * Try to determine if we have reached the end of the