summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordelphij <delphij@FreeBSD.org>2005-02-20 08:02:15 +0000
committerdelphij <delphij@FreeBSD.org>2005-02-20 08:02:15 +0000
commitb62e1ca825bfc519be7b8934f4184f9b0fe96e9e (patch)
treecacb781306afa3ef7a585d142dfcfeee26259805
parentdf2cf6c4d1ca8e709672406f2c2ffb760bb938a3 (diff)
downloadFreeBSD-src-b62e1ca825bfc519be7b8934f4184f9b0fe96e9e.zip
FreeBSD-src-b62e1ca825bfc519be7b8934f4184f9b0fe96e9e.tar.gz
The recomputation of file system summary at mount time can be a
very slow process, especially for large file systems that is just recovered from a crash. Since the summary is already re-sync'ed every 30 second, we will not lag behind too much after a crash. With this consideration in mind, it is more reasonable to transfer the responsibility to background fsck, to reduce the delay after a crash. Add a new sysctl variable, vfs.ffs.compute_summary_at_mount, to control this behavior. When set to nonzero, we will get the "old" behavior, that the summary is computed immediately at mount time. Add five new sysctl variables to adjust ndir, nbfree, nifree, nffree and numclusters respectively. Teach fsck_ffs about these API, however, intentionally not to check the existence, since kernels without these sysctls must have recomputed the summary and hence no adjustments are necessary. This change has eliminated the usual tens of minutes of delay of mounting large dirty volumes. Reviewed by: mckusick MFC After: 1 week
-rw-r--r--sbin/fsck_ffs/fsck.h5
-rw-r--r--sbin/fsck_ffs/pass5.c55
-rw-r--r--sys/ufs/ffs/ffs_alloc.c69
-rw-r--r--sys/ufs/ffs/ffs_softdep.c15
-rw-r--r--sys/ufs/ffs/fs.h7
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.
OpenPOWER on IntegriCloud