git: 069767091e54 - main - Do not panic in case of corrupted UFS/FFS directory.

From: Kirk McKusick <mckusick_at_FreeBSD.org>
Date: Sat, 18 Mar 2023 22:38:24 UTC
The branch main has been updated by mckusick:

URL: https://cgit.FreeBSD.org/src/commit/?id=069767091e54a2537ae509dcdf3005fb0f50ab84

commit 069767091e54a2537ae509dcdf3005fb0f50ab84
Author:     Kirk McKusick <mckusick@FreeBSD.org>
AuthorDate: 2023-03-18 22:36:54 +0000
Commit:     Kirk McKusick <mckusick@FreeBSD.org>
CommitDate: 2023-03-18 22:37:58 +0000

    Do not panic in case of corrupted UFS/FFS directory.
    
    Historically the system panic'ed when it encountered a corrupt
    directory. This change recovers well enough to continue operations.
    This change is made in response to a similar change made in the ext2
    filesystem as described in the cited Differential Revision.
    
    MFC after:    2 weeks
    Sponsored by: The FreeBSD Foundation
    Differential Revision: https://reviews.freebsd.org/D38503
---
 sys/ufs/ufs/ufs_lookup.c | 18 +++++-------------
 sys/ufs/ufs/ufs_vnops.c  |  4 +++-
 2 files changed, 8 insertions(+), 14 deletions(-)

diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c
index 4c390f4c42ef..cabd04a50bfd 100644
--- a/sys/ufs/ufs/ufs_lookup.c
+++ b/sys/ufs/ufs/ufs_lookup.c
@@ -548,9 +548,8 @@ found:
 	 */
 	if (i_offset + DIRSIZ(OFSFMT(vdp), ep) > dp->i_size) {
 		ufs_dirbad(dp, i_offset, "i_size too small");
-		dp->i_size = i_offset + DIRSIZ(OFSFMT(vdp), ep);
-		DIP_SET(dp, i_size, dp->i_size);
-		UFS_INODE_SET_FLAG(dp, IN_SIZEMOD | IN_CHANGE | IN_UPDATE);
+		brelse(bp);
+		return (EIO);
 	}
 	brelse(bp);
 
@@ -758,17 +757,10 @@ found:
 void
 ufs_dirbad(struct inode *ip, doff_t offset, char *how)
 {
-	struct mount *mp;
 
-	mp = ITOV(ip)->v_mount;
-	if ((mp->mnt_flag & MNT_RDONLY) == 0)
-		panic("ufs_dirbad: %s: bad dir ino %ju at offset %ld: %s",
-		    mp->mnt_stat.f_mntonname, (uintmax_t)ip->i_number,
-		    (long)offset, how);
-	else
-		(void)printf("%s: bad dir ino %ju at offset %ld: %s\n",
-		    mp->mnt_stat.f_mntonname, (uintmax_t)ip->i_number,
-		    (long)offset, how);
+	(void)printf("%s: bad dir ino %ju at offset %ld: %s\n",
+	    ITOV(ip)->v_mount->mnt_stat.f_mntonname, (uintmax_t)ip->i_number,
+	    (long)offset, how);
 }
 
 /*
diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
index ae6d963920f3..54046c285fd7 100644
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -1730,7 +1730,9 @@ relock:
 			/* Journal must account for each new link. */
 			softdep_setup_dotdot_link(tdp, fip);
 		SET_I_OFFSET(fip, mastertemplate.dot_reclen);
-		ufs_dirrewrite(fip, fdp, newparent, DT_DIR, 0);
+		if (ufs_dirrewrite(fip, fdp, newparent, DT_DIR, 0) != 0)
+			ufs_dirbad(fip, mastertemplate.dot_reclen,
+			    "rename: missing ".." entry");
 		cache_purge(fdvp);
 	}
 	error = ufs_dirremove(fdvp, fip, fcnp->cn_flags, 0);