git: 5267120645fa - main - Cleanups to fsck_ffs(8).

From: Kirk McKusick <mckusick_at_FreeBSD.org>
Date: Mon, 29 May 2023 21:57:02 UTC
The branch main has been updated by mckusick:

URL: https://cgit.FreeBSD.org/src/commit/?id=5267120645fa52eac771c9bd8e28d68620a3bb89

commit 5267120645fa52eac771c9bd8e28d68620a3bb89
Author:     Kirk McKusick <mckusick@FreeBSD.org>
AuthorDate: 2023-05-29 21:54:52 +0000
Commit:     Kirk McKusick <mckusick@FreeBSD.org>
CommitDate: 2023-05-29 21:55:54 +0000

    Cleanups to fsck_ffs(8).
    
    When checking an inode ensure that it does not have a negative size.
    Stop scaning a directory when an unallocated block is found.
    Fully clear an inode when it is first allocated.
    Ensure that an inode is marked dirty whenever it is updated and that
    it has a correct check hash when it is released.
    
    MFC-after:    1 week
    Sponsored-by: The FreeBSD Foundation
---
 sbin/fsck_ffs/dir.c   |  3 +++
 sbin/fsck_ffs/inode.c | 17 +++++++++++++----
 2 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/sbin/fsck_ffs/dir.c b/sbin/fsck_ffs/dir.c
index 7ea471bcb30a..3ff6c467ee08 100644
--- a/sbin/fsck_ffs/dir.c
+++ b/sbin/fsck_ffs/dir.c
@@ -725,6 +725,7 @@ changeino(ino_t dir, const char *name, ino_t newnum, int depth)
 	ginode(dir, &ip);
 	if (((error = ckinode(ip.i_dp, &idesc)) & ALTERED) && newnum != 0) {
 		DIP_SET(ip.i_dp, di_dirdepth, depth);
+		inodirty(&ip);
 		getinoinfo(dir)->i_depth = depth;
 	}
 	free(idesc.id_name);
@@ -879,6 +880,7 @@ expanddir(struct inode *ip, char *name)
 			DIP_SET(dp, di_ib[0], indirblk);
 			DIP_SET(dp, di_blocks,
 			    DIP(dp, di_blocks) + btodb(sblock.fs_bsize));
+			inodirty(ip);
 		}
 		IBLK_SET(nbp, lastlbn - UFS_NDADDR, newblk);
 		dirty(nbp);
@@ -969,6 +971,7 @@ allocdir(ino_t parent, ino_t request, int mode)
 	} else {
 		inp->i_depth = parentinp->i_depth + 1; 
 		DIP_SET(dp, di_dirdepth, inp->i_depth);
+		inodirty(&ip);
 	}
 	inoinfo(ino)->ino_type = DT_DIR;
 	inoinfo(ino)->ino_state = inoinfo(parent)->ino_state;
diff --git a/sbin/fsck_ffs/inode.c b/sbin/fsck_ffs/inode.c
index 7dca95129ed1..c56d938cce41 100644
--- a/sbin/fsck_ffs/inode.c
+++ b/sbin/fsck_ffs/inode.c
@@ -90,6 +90,10 @@ ckinode(union dinode *dp, struct inodesc *idesc)
 		dino.dp1 = dp->dp1;
 	else
 		dino.dp2 = dp->dp2;
+	if (DIP(&dino, di_size) < 0) {
+		pfatal("NEGATIVE INODE SIZE %jd\n", DIP(&dino, di_size));
+		return (STOP);
+	}
 	ndb = howmany(DIP(&dino, di_size), sblock.fs_bsize);
 	for (i = 0; i < UFS_NDADDR; i++) {
 		idesc->id_lbn++;
@@ -116,6 +120,7 @@ ckinode(union dinode *dp, struct inodesc *idesc)
 					inodirty(&ip);
 					irelse(&ip);
 				}
+				return (STOP);
 			}
 			continue;
 		}
@@ -498,6 +503,11 @@ irelse(struct inode *ip)
 	/* Check for failed inode read */
 	if (ip->i_bp == NULL)
 		return;
+	if (debug && sblock.fs_magic == FS_UFS2_MAGIC &&
+	    ffs_verify_dinode_ckhash(&sblock, (struct ufs2_dinode *)ip->i_dp)) {
+		pwarn("irelse: releasing inode with bad check-hash");
+		prtinode(ip);
+	}
 	if (ip->i_bp->b_refcnt <= 0)
 		pfatal("irelse: releasing unreferenced ino %ju\n",
 		    (uintmax_t) ip->i_number);
@@ -1419,21 +1429,20 @@ retry:
 	cgdirty(cgbp);
 	ginode(ino, &ip);
 	dp = ip.i_dp;
+	memset(dp, 0, ((sblock.fs_magic == FS_UFS1_MAGIC) ?
+	    sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode)));
 	DIP_SET(dp, di_db[0], allocblk(ino_to_cg(&sblock, ino), (long)1,
 	    std_checkblkavail));
 	if (DIP(dp, di_db[0]) == 0) {
 		inoinfo(ino)->ino_state = USTATE;
+		inodirty(&ip);
 		irelse(&ip);
 		return (0);
 	}
 	DIP_SET(dp, di_mode, type);
-	DIP_SET(dp, di_flags, 0);
 	DIP_SET(dp, di_atime, time(NULL));
 	DIP_SET(dp, di_ctime, DIP(dp, di_atime));
 	DIP_SET(dp, di_mtime, DIP(dp, di_ctime));
-	DIP_SET(dp, di_mtimensec, 0);
-	DIP_SET(dp, di_ctimensec, 0);
-	DIP_SET(dp, di_atimensec, 0);
 	DIP_SET(dp, di_size, sblock.fs_fsize);
 	DIP_SET(dp, di_blocks, btodb(sblock.fs_fsize));
 	n_files++;