diff options
-rw-r--r-- | sbin/fsck_ffs/fsck.h | 5 | ||||
-rw-r--r-- | sbin/fsck_ffs/pass5.c | 55 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_alloc.c | 69 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_softdep.c | 15 | ||||
-rw-r--r-- | sys/ufs/ffs/fs.h | 7 |
5 files changed, 146 insertions, 5 deletions
diff --git a/sbin/fsck_ffs/fsck.h b/sbin/fsck_ffs/fsck.h index 487dcd4..55a57bc 100644 --- a/sbin/fsck_ffs/fsck.h +++ b/sbin/fsck_ffs/fsck.h @@ -252,6 +252,11 @@ long countdirs; /* number of directories we actually found */ #define MIBSIZE 3 /* size of fsck sysctl MIBs */ int adjrefcnt[MIBSIZE]; /* MIB command to adjust inode reference cnt */ int adjblkcnt[MIBSIZE]; /* MIB command to adjust inode block count */ +int adjndir[MIBSIZE]; /* MIB command to adjust number of directories */ +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 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 */ diff --git a/sbin/fsck_ffs/pass5.c b/sbin/fsck_ffs/pass5.c index c3c564e..796b546 100644 --- a/sbin/fsck_ffs/pass5.c +++ b/sbin/fsck_ffs/pass5.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <ufs/ffs/fs.h> #include <err.h> +#include <inttypes.h> #include <limits.h> #include <string.h> @@ -344,6 +345,60 @@ pass5(void) fs->fs_fmod = 0; sbdirty(); } + + /* + * When doing background fsck on a snapshot, figure out whether + * the superblock summary is inaccurate and correct it when + * necessary. + */ + if (cursnapshot != 0) { + cmd.size = 1; + + cmd.value = cstotal.cs_ndir - fs->fs_cstotal.cs_ndir; + if (cmd.value != 0) { + if (debug) + printf("adjndir by %+" PRIi64 "\n", cmd.value); + if (sysctl(adjndir, MIBSIZE, 0, 0, + &cmd, sizeof cmd) == -1) + rwerror("ADJUST NUMBER OF DIRECTORIES", cmd.value); + } + + cmd.value = cstotal.cs_nbfree - fs->fs_cstotal.cs_nbfree; + if (cmd.value != 0) { + if (debug) + printf("adjnbfree by %+" PRIi64 "\n", cmd.value); + if (sysctl(adjnbfree, MIBSIZE, 0, 0, + &cmd, sizeof cmd) == -1) + rwerror("ADJUST NUMBER OF FREE BLOCKS", cmd.value); + } + + cmd.value = cstotal.cs_nifree - fs->fs_cstotal.cs_nifree; + if (cmd.value != 0) { + if (debug) + printf("adjnifree by %+" PRIi64 "\n", cmd.value); + if (sysctl(adjnifree, MIBSIZE, 0, 0, + &cmd, sizeof cmd) == -1) + rwerror("ADJUST NUMBER OF FREE INODES", cmd.value); + } + + cmd.value = cstotal.cs_nffree - fs->fs_cstotal.cs_nffree; + if (cmd.value != 0) { + if (debug) + printf("adjnffree by %+" PRIi64 "\n", cmd.value); + if (sysctl(adjnffree, MIBSIZE, 0, 0, + &cmd, sizeof cmd) == -1) + rwerror("ADJUST NUMBER OF FREE FRAGS", cmd.value); + } + + cmd.value = cstotal.cs_numclusters - fs->fs_cstotal.cs_numclusters; + if (cmd.value != 0) { + if (debug) + printf("adjnumclusters by %+" PRIi64 "\n", cmd.value); + if (sysctl(adjnumclusters, MIBSIZE, 0, 0, + &cmd, sizeof cmd) == -1) + rwerror("ADJUST NUMBER OF FREE CLUSTERS", cmd.value); + } + } } static void diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c index 9878694..f5583a6 100644 --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -2263,7 +2263,7 @@ ffs_fserr(fs, inum, cp) /* * This function provides the capability for the fsck program to - * update an active filesystem. Six operations are provided: + * update an active filesystem. Eleven operations are provided: * * adjrefcnt(inode, amt) - adjusts the reference count on the * specified inode by the specified amount. Under normal @@ -2271,6 +2271,8 @@ ffs_fserr(fs, inum, cp) * the count to zero will cause the inode to be freed. * adjblkcnt(inode, amt) - adjust the number of blocks used to * by the specifed amount. + * adjndir, adjbfree, adjifree, adjffree, adjnumclusters(amt) - + * adjust the superblock summary. * freedirs(inode, count) - directory inodes [inode..inode + count - 1] * are marked as free. Inodes should never have to be marked * as in use. @@ -2292,6 +2294,21 @@ SYSCTL_PROC(_vfs_ffs, FFS_ADJ_REFCNT, adjrefcnt, CTLFLAG_WR|CTLTYPE_STRUCT, static SYSCTL_NODE(_vfs_ffs, FFS_ADJ_BLKCNT, adjblkcnt, CTLFLAG_WR, sysctl_ffs_fsck, "Adjust Inode Used Blocks Count"); +static SYSCTL_NODE(_vfs_ffs, FFS_ADJ_NDIR, adjndir, CTLFLAG_WR, + sysctl_ffs_fsck, "Adjust number of directories"); + +static SYSCTL_NODE(_vfs_ffs, FFS_ADJ_NBFREE, adjnbfree, CTLFLAG_WR, + sysctl_ffs_fsck, "Adjust number of free blocks"); + +static SYSCTL_NODE(_vfs_ffs, FFS_ADJ_NIFREE, adjnifree, CTLFLAG_WR, + sysctl_ffs_fsck, "Adjust number of free inodes"); + +static SYSCTL_NODE(_vfs_ffs, FFS_ADJ_NFFREE, adjnffree, CTLFLAG_WR, + sysctl_ffs_fsck, "Adjust number of free frags"); + +static SYSCTL_NODE(_vfs_ffs, FFS_ADJ_NUMCLUSTERS, adjnumclusters, CTLFLAG_WR, + sysctl_ffs_fsck, "Adjust number of free clusters"); + static SYSCTL_NODE(_vfs_ffs, FFS_DIR_FREE, freedirs, CTLFLAG_WR, sysctl_ffs_fsck, "Free Range of Directory Inodes"); @@ -2453,6 +2470,56 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) } break; + /* + * Adjust superblock summaries. fsck(8) is expected to + * submit deltas when necessary. + */ + case FFS_ADJ_NDIR: +#ifdef DEBUG + if (fsckcmds) { + printf("%s: adjust number of directories by %jd\n", + mp->mnt_stat.f_mntonname, (intmax_t)cmd.value); + } +#endif /* DEBUG */ + fs->fs_cstotal.cs_ndir += cmd.value; + break; + case FFS_ADJ_NBFREE: +#ifdef DEBUG + if (fsckcmds) { + printf("%s: adjust number of free blocks by %+jd\n", + mp->mnt_stat.f_mntonname, (intmax_t)cmd.value); + } +#endif /* DEBUG */ + fs->fs_cstotal.cs_nbfree += cmd.value; + break; + case FFS_ADJ_NIFREE: +#ifdef DEBUG + if (fsckcmds) { + printf("%s: adjust number of free inodes by %+jd\n", + mp->mnt_stat.f_mntonname, (intmax_t)cmd.value); + } +#endif /* DEBUG */ + fs->fs_cstotal.cs_nifree += cmd.value; + break; + case FFS_ADJ_NFFREE: +#ifdef DEBUG + if (fsckcmds) { + printf("%s: adjust number of free frags by %+jd\n", + mp->mnt_stat.f_mntonname, (intmax_t)cmd.value); + } +#endif /* DEBUG */ + fs->fs_cstotal.cs_nffree += cmd.value; + break; + case FFS_ADJ_NUMCLUSTERS: +#ifdef DEBUG + if (fsckcmds) { + printf("%s: adjust number of free clusters by %+jd\n", + mp->mnt_stat.f_mntonname, (intmax_t)cmd.value); + } +#endif /* DEBUG */ + fs->fs_cstotal.cs_numclusters += cmd.value; + break; + default: #ifdef DEBUG if (fsckcmds) { diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index 1861e84..1462ce0 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -611,6 +611,12 @@ SYSCTL_INT(_debug, OID_AUTO, direct_blk_ptrs, CTLFLAG_RW, &stat_direct_blk_ptrs, SYSCTL_INT(_debug, OID_AUTO, dir_entry, CTLFLAG_RW, &stat_dir_entry, 0, ""); #endif /* DEBUG */ +SYSCTL_DECL(_vfs_ffs); + +static int compute_summary_at_mount = 0; /* Whether to recompute the summary at mount time */ +SYSCTL_INT(_vfs_ffs, OID_AUTO, compute_summary_at_mount, CTLFLAG_RW, + &compute_summary_at_mount, 0, "Recompute summary at mount"); + /* * Add an item to the end of the work queue. * This routine requires that the lock be held. @@ -1295,10 +1301,13 @@ softdep_mount(devvp, mp, fs, cred) mp->mnt_flag |= MNT_SOFTDEP; /* * When doing soft updates, the counters in the - * superblock may have gotten out of sync, so we have - * to scan the cylinder groups and recalculate them. + * superblock may have gotten out of sync. Recomputation + * can take a long time and can be deferred for background + * fsck. However, the old behavior of scanning the cylinder + * groups and recalculating them at mount time is available + * by setting vfs.ffs.compute_summary_at_mount to one. */ - if (fs->fs_clean != 0) + if (compute_summary_at_mount == 0 || fs->fs_clean != 0) return (0); bzero(&cstotal, sizeof cstotal); for (cyl = 0; cyl < fs->fs_ncg; cyl++) { diff --git a/sys/ufs/ffs/fs.h b/sys/ufs/ffs/fs.h index f57669f..572996e 100644 --- a/sys/ufs/ffs/fs.h +++ b/sys/ufs/ffs/fs.h @@ -206,7 +206,12 @@ #define FFS_DIR_FREE 4 /* free specified dir inodes in map */ #define FFS_FILE_FREE 5 /* free specified file inodes in map */ #define FFS_SET_FLAGS 6 /* set filesystem flags */ -#define FFS_MAXID 7 /* number of valid ffs ids */ +#define FFS_ADJ_NDIR 7 /* adjust number of directories */ +#define FFS_ADJ_NBFREE 8 /* adjust number of free blocks */ +#define FFS_ADJ_NIFREE 9 /* adjust number of free inodes */ +#define FFS_ADJ_NFFREE 10 /* adjust number of free frags */ +#define FFS_ADJ_NUMCLUSTERS 11 /* adjust number of free clusters */ +#define FFS_MAXID 12 /* number of valid ffs ids */ /* * Command structure passed in to the filesystem to adjust filesystem values. |