From 5267120645fa52eac771c9bd8e28d68620a3bb89 Mon Sep 17 00:00:00 2001 From: Kirk McKusick Date: Mon, 29 May 2023 14:54:52 -0700 Subject: [PATCH] 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 7ea471bcb30..3ff6c467ee0 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 7dca95129ed..c56d938cce4 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++;