Add the ability to adjust directory depths to background fsck_ffs(8).

Commit fe5e6e2 improved FFS directory placement when creating new
directories. It is done by keeping track of the depth of directories
in the filesystem and placing those lower in the tree closer together
while spreading out those higher in the tree.

Fsck_ffs(8) checks these depths and if incorrect adjusts them to
their correct value. When running in background fsck_ffs(8) needs
to be able to make an adjustment to the depth. This commit adds
the sysctl to make such an adjustment and adds the code to fsck_ffs(8)
to use the new sysctl.

MFC after:    1 week
Sponsored by: The FreeBSD Foundation
This commit is contained in:
Kirk McKusick 2023-05-25 19:27:04 -07:00
parent 4b08a62ed4
commit e4a905d1e0
5 changed files with 54 additions and 6 deletions

View file

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

View file

@ -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 */

View file

@ -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 */
@ -140,6 +141,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);

View file

@ -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) {

View file

@ -263,7 +263,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.