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
This commit is contained in:
Kirk McKusick 2023-05-29 14:54:52 -07:00
parent a94018e200
commit 5267120645
2 changed files with 16 additions and 4 deletions

View file

@ -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;

View file

@ -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++;