summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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