git: 007322a94cee - stable/13 - Add the ability to adjust directory depths to background fsck_ffs(8).

From: Kirk McKusick <mckusick_at_FreeBSD.org>
Date: Wed, 07 Jun 2023 22:35:10 UTC
The branch stable/13 has been updated by mckusick:

URL: https://cgit.FreeBSD.org/src/commit/?id=007322a94ceeca654c3bb3bf1fdf6e2bea30d683

commit 007322a94ceeca654c3bb3bf1fdf6e2bea30d683
Author:     Kirk McKusick <mckusick@FreeBSD.org>
AuthorDate: 2023-05-26 02:27:04 +0000
Commit:     Kirk McKusick <mckusick@FreeBSD.org>
CommitDate: 2023-06-07 22:34:39 +0000

    Add the ability to adjust directory depths to background fsck_ffs(8).
    
    Sponsored by: The FreeBSD Foundation
    
    (cherry picked from commit e4a905d1e0d94ddb8e15de50d37e67f13e058047)
---
 sbin/fsck_ffs/dir.c     | 26 +++++++++++++++++++++-----
 sbin/fsck_ffs/fsck.h    |  1 +
 sbin/fsck_ffs/globs.c   |  2 ++
 sys/ufs/ffs/ffs_alloc.c | 28 ++++++++++++++++++++++++++++
 sys/ufs/ffs/fs.h        |  3 ++-
 5 files changed, 54 insertions(+), 6 deletions(-)

diff --git a/sbin/fsck_ffs/dir.c b/sbin/fsck_ffs/dir.c
index cc5305c390a4..e5f0e1e7e7f4 100644
--- a/sbin/fsck_ffs/dir.c
+++ b/sbin/fsck_ffs/dir.c
@@ -105,6 +105,7 @@ check_dirdepth(struct inoinfo *inp)
 	struct inode ip;
 	union dinode *dp;
 	int saveresolved;
+	size_t size;
 	static int updateasked, dirdepthupdate;
 
 	if ((parentinp = getinoinfo(inp->i_parent)) == NULL) {
@@ -141,9 +142,11 @@ check_dirdepth(struct inoinfo *inp)
 		}
 	}
 	/*
-	 * If we are not converting, nothing more to do.
+	 * If we are not converting or we are running in no-write mode
+	 * there is nothing more to do.
 	 */
-	if (inp->i_depth == 0 && dirdepthupdate == 0)
+	if ((inp->i_depth == 0 && dirdepthupdate == 0) ||
+	    (fswritefd < 0 && bkgrdflag == 0))
 		return;
 	/*
 	 * Individual directory at wrong depth. Report it and correct if
@@ -174,8 +177,20 @@ check_dirdepth(struct inoinfo *inp)
 			printf(" (ADJUSTED)\n");
 	}
 	inp->i_depth = parentinp->i_depth + 1;
-	DIP_SET(dp, di_dirdepth, inp->i_depth);
-	inodirty(&ip);
+	if (bkgrdflag == 0) {
+		DIP_SET(dp, di_dirdepth, inp->i_depth);
+		inodirty(&ip);
+	} else {
+		cmd.value = inp->i_number;
+		cmd.size = (int64_t)inp->i_depth - DIP(dp, di_dirdepth);
+		if (debug)
+			printf("adjdepth ino %ld amt %jd\n", (long)cmd.value,
+			    (intmax_t)cmd.size);
+		size = MIBSIZE;
+		if (sysctlnametomib("vfs.ffs.adjdepth", adjdepth, &size) < 0 ||
+		    sysctl(adjdepth, MIBSIZE, 0, 0, &cmd, sizeof cmd) == -1)
+			rwerror("ADJUST INODE DEPTH", cmd.value);
+	}
 	irelse(&ip);
 }
 
@@ -506,7 +521,8 @@ adjust(struct inodesc *idesc, int lcnt)
 					    (long long)cmd.size);
 				if (sysctl(adjrefcnt, MIBSIZE, 0, 0,
 				    &cmd, sizeof cmd) == -1)
-					rwerror("ADJUST INODE", cmd.value);
+					rwerror("ADJUST INODE LINK COUNT",
+					    cmd.value);
 			}
 		}
 	}
diff --git a/sbin/fsck_ffs/fsck.h b/sbin/fsck_ffs/fsck.h
index 4e5878b0b12f..9f9b1e0a8857 100644
--- a/sbin/fsck_ffs/fsck.h
+++ b/sbin/fsck_ffs/fsck.h
@@ -333,6 +333,7 @@ extern int adjnbfree[MIBSIZE];	/* MIB cmd to adjust number of free blocks */
 extern int adjnifree[MIBSIZE];	/* MIB cmd to adjust number of free inodes */
 extern int adjnffree[MIBSIZE];	/* MIB cmd to adjust number of free frags */
 extern int adjnumclusters[MIBSIZE]; /* MIB cmd adjust number of free clusters */
+extern int adjdepth[MIBSIZE];	/* MIB cmd to adjust directory depth count */
 extern int freefiles[MIBSIZE];	/* MIB cmd to free a set of files */
 extern int freedirs[MIBSIZE];	/* MIB cmd to free a set of directories */
 extern int freeblks[MIBSIZE];	/* MIB cmd to free a set of data blocks */
diff --git a/sbin/fsck_ffs/globs.c b/sbin/fsck_ffs/globs.c
index 92e77b61f9d4..2340636fe3a9 100644
--- a/sbin/fsck_ffs/globs.c
+++ b/sbin/fsck_ffs/globs.c
@@ -68,6 +68,7 @@ int	adjnbfree[MIBSIZE];	/* MIB command to adjust number of free blocks */
 int	adjnifree[MIBSIZE];	/* MIB command to adjust number of free inodes */
 int	adjnffree[MIBSIZE];	/* MIB command to adjust number of free frags */
 int	adjnumclusters[MIBSIZE];	/* MIB command to adjust number of free clusters */
+int	adjdepth[MIBSIZE];	/* MIB cmd to adjust directory depth count */
 int	freefiles[MIBSIZE];	/* MIB command to free a set of files */
 int	freedirs[MIBSIZE];	/* MIB command to free a set of directories */
 int	freeblks[MIBSIZE];	/* MIB command to free a set of data blocks */
@@ -141,6 +142,7 @@ fsckinit(void)
 	bzero(adjnifree, sizeof(int) * MIBSIZE);
 	bzero(adjnffree, sizeof(int) * MIBSIZE);
 	bzero(adjnumclusters, sizeof(int) * MIBSIZE);
+	bzero(adjdepth, sizeof(int) * MIBSIZE);
 	bzero(freefiles, sizeof(int) * MIBSIZE);
 	bzero(freedirs, sizeof(int) * MIBSIZE);
 	bzero(freeblks, sizeof(int) * MIBSIZE);
diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c
index 6d37afcfadf6..195ba9f8a299 100644
--- a/sys/ufs/ffs/ffs_alloc.c
+++ b/sys/ufs/ffs/ffs_alloc.c
@@ -3108,6 +3108,8 @@ ffs_fserr(struct fs *fs,
  *	the count to zero will cause the inode to be freed.
  * adjblkcnt(inode, amt) - adjust the number of blocks used by the
  *	inode by the specified amount.
+ * adjdepth(inode, amt) - adjust the depth of the specified directory
+ *	inode by the specified amount.
  * setsize(inode, size) - set the size of the inode to the
  *	specified size.
  * adjndir, adjbfree, adjifree, adjffree, adjnumclusters(amt) -
@@ -3142,6 +3144,10 @@ static SYSCTL_NODE(_vfs_ffs, FFS_ADJ_BLKCNT, adjblkcnt,
     CTLFLAG_WR | CTLFLAG_NEEDGIANT, sysctl_ffs_fsck,
     "Adjust Inode Used Blocks Count");
 
+static SYSCTL_NODE(_vfs_ffs, FFS_ADJ_DEPTH, adjdepth,
+    CTLFLAG_WR | CTLFLAG_NEEDGIANT, sysctl_ffs_fsck,
+    "Adjust Directory Inode Depth");
+
 static SYSCTL_NODE(_vfs_ffs, FFS_SET_SIZE, setsize,
     CTLFLAG_WR | CTLFLAG_NEEDGIANT, sysctl_ffs_fsck,
     "Set the inode size");
@@ -3299,6 +3305,28 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS)
 		vput(vp);
 		break;
 
+	case FFS_ADJ_DEPTH:
+#ifdef DIAGNOSTIC
+		if (fsckcmds) {
+			printf("%s: adjust directory inode %jd depth by %jd\n",
+			    mp->mnt_stat.f_mntonname, (intmax_t)cmd.value,
+			    (intmax_t)cmd.size);
+		}
+#endif /* DIAGNOSTIC */
+		if ((error = ffs_vget(mp, (ino_t)cmd.value, LK_EXCLUSIVE, &vp)))
+			break;
+		if (vp->v_type != VDIR) {
+			vput(vp);
+			error = ENOTDIR;
+			break;
+		}
+		ip = VTOI(vp);
+		DIP_SET(ip, i_dirdepth, DIP(ip, i_dirdepth) + cmd.size);
+		UFS_INODE_SET_FLAG(ip, IN_CHANGE | IN_MODIFIED);
+		error = ffs_update(vp, 1);
+		vput(vp);
+		break;
+
 	case FFS_SET_SIZE:
 #ifdef DIAGNOSTIC
 		if (fsckcmds) {
diff --git a/sys/ufs/ffs/fs.h b/sys/ufs/ffs/fs.h
index b2ed2051471c..70e24242b01b 100644
--- a/sys/ufs/ffs/fs.h
+++ b/sys/ufs/ffs/fs.h
@@ -224,7 +224,8 @@
 /* Was FFS_SET_INODE		15 */
 /* Was FFS_SET_BUFOUTPUT	16 */
 #define	FFS_SET_SIZE		17	/* set inode size */
-#define	FFS_MAXID		17	/* number of valid ffs ids */
+#define	FFS_ADJ_DEPTH		18	/* adjust directory inode depth */
+#define	FFS_MAXID		18	/* number of valid ffs ids */
 
 /*
  * Command structure passed in to the filesystem to adjust filesystem values.