svn commit: r249788 - in stable/9/sbin: fsck_ffs fsdb

Kirk McKusick mckusick at FreeBSD.org
Tue Apr 23 06:28:51 UTC 2013


Author: mckusick
Date: Tue Apr 23 06:28:49 2013
New Revision: 249788
URL: http://svnweb.freebsd.org/changeset/base/249788

Log:
  Merge checked by: Glen Barber (gjb@)
  
  MFC of 247212:
  When running with the -d option, instrument fsck_ffs to track the number,
  data type, and running time of its I/O operations.
  
  No functional changes.
  
  MFC of 247234:
  Catch up with internal API changes for initbarea() and getdatablk()
  of fsck_ffs introduced with r247212.
  
  Submitted by:   David Wolfskill <david at catwhisker.org>
  
  MFC of 248625:
  Speed up fsck by caching the cylinder group maps in pass1 so
  that they do not need to be read again in pass5. As this nearly
  doubles the memory requirement for fsck, the cache is thrown away
  if other memory needs in fsck would otherwise fail. Thus, the
  memory footprint of fsck remains unchanged in memory constrained
  environments.
  
  This work was inspired by a paper presented at Usenix's FAST '13:
  www.usenix.org/conference/fast13/ffsck-fast-file-system-checker
  
  Details of this implementation appears in the April 2013 of ;login:
  www.usenix.org/publications/login/april-2013-volume-38-number-2.
  A copy of the April 2013 ;login: paper can also be downloaded
  from: www.mckusick.com/publications/faster_fsck.pdf.
  
  Reviewed by: kib
  Tested by:   Peter Holm
  
  MFC of 248639:
  Fix the build after addition of cylinder group cacheing (r248625)
  
  Reported by:   Glen Barber (gjb@)
  Pointy hat to: Kirk McKusick (mckusick@)
  
  MFC of 248673:
  Minor formatting fix for printf() to fix clang builds.
  
  Submitted by:   db
  Reviewed by:    gjb
  
  MFC of 248680:
  Resolve clang compile errors on amd64/i386 for certain by casting.
  
  compile tested with clang on i386, amd64
  compile tested with gcc on i386, amd64, sparc64
  
  Submitted by:   delphij
  
  MFC of 248691:
  Note that output is in seconds, not msec.
  KNF indentation.
  No functional change.
  No change to printf strings.
  No change to casting of printf arguments.
  
  Reported by: Bruce Evans

Modified:
  stable/9/sbin/fsck_ffs/dir.c
  stable/9/sbin/fsck_ffs/ea.c
  stable/9/sbin/fsck_ffs/fsck.h
  stable/9/sbin/fsck_ffs/fsutil.c
  stable/9/sbin/fsck_ffs/inode.c
  stable/9/sbin/fsck_ffs/main.c
  stable/9/sbin/fsck_ffs/pass1.c
  stable/9/sbin/fsck_ffs/pass5.c
  stable/9/sbin/fsck_ffs/setup.c
  stable/9/sbin/fsck_ffs/suj.c
  stable/9/sbin/fsdb/fsdb.c
  stable/9/sbin/fsdb/fsdbutil.c
Directory Properties:
  stable/9/sbin/fsck_ffs/   (props changed)
  stable/9/sbin/fsdb/   (props changed)

Modified: stable/9/sbin/fsck_ffs/dir.c
==============================================================================
--- stable/9/sbin/fsck_ffs/dir.c	Tue Apr 23 06:28:35 2013	(r249787)
+++ stable/9/sbin/fsck_ffs/dir.c	Tue Apr 23 06:28:49 2013	(r249788)
@@ -708,6 +708,6 @@ getdirblk(ufs2_daddr_t blkno, long size)
 
 	if (pdirbp != 0)
 		pdirbp->b_flags &= ~B_INUSE;
-	pdirbp = getdatablk(blkno, size);
+	pdirbp = getdatablk(blkno, size, BT_DIRDATA);
 	return (pdirbp);
 }

Modified: stable/9/sbin/fsck_ffs/ea.c
==============================================================================
--- stable/9/sbin/fsck_ffs/ea.c	Tue Apr 23 06:28:35 2013	(r249787)
+++ stable/9/sbin/fsck_ffs/ea.c	Tue Apr 23 06:28:49 2013	(r249788)
@@ -73,7 +73,7 @@ eascan(struct inodesc *idesc, struct ufs
 	else
 		blksiz = sblock.fs_bsize;
 	printf("blksiz = %ju\n", (intmax_t)blksiz);
-	bp = getdatablk(dp->di_extb[0], blksiz);
+	bp = getdatablk(dp->di_extb[0], blksiz, BT_EXTATTR);
 	cp = (u_char *)bp->b_un.b_buf;
 	for (n = 0; n < blksiz; n++) {
 		printf("%02x", cp[n]);

Modified: stable/9/sbin/fsck_ffs/fsck.h
==============================================================================
--- stable/9/sbin/fsck_ffs/fsck.h	Tue Apr 23 06:28:35 2013	(r249787)
+++ stable/9/sbin/fsck_ffs/fsck.h	Tue Apr 23 06:28:49 2013	(r249788)
@@ -138,6 +138,7 @@ struct bufarea {
 	int b_size;
 	int b_errs;
 	int b_flags;
+	int b_type;
 	union {
 		char *b_buf;			/* buffer space */
 		ufs1_daddr_t *b_indir1;		/* UFS1 indirect block */
@@ -165,9 +166,38 @@ struct bufarea {
  * Buffer flags
  */
 #define	B_INUSE 	0x00000001	/* Buffer is in use */
+/*
+ * Type of data in buffer
+ */
+#define	BT_UNKNOWN 	 0	/* Buffer holds a superblock */
+#define	BT_SUPERBLK 	 1	/* Buffer holds a superblock */
+#define	BT_CYLGRP 	 2	/* Buffer holds a cylinder group map */
+#define	BT_LEVEL1 	 3	/* Buffer holds single level indirect */
+#define	BT_LEVEL2 	 4	/* Buffer holds double level indirect */
+#define	BT_LEVEL3 	 5	/* Buffer holds triple level indirect */
+#define	BT_EXTATTR 	 6	/* Buffer holds external attribute data */
+#define	BT_INODES 	 7	/* Buffer holds external attribute data */
+#define	BT_DIRDATA 	 8	/* Buffer holds directory data */
+#define	BT_DATA	 	 9	/* Buffer holds user data */
+#define BT_NUMBUFTYPES	10
+#define BT_NAMES {			\
+	"unknown",			\
+	"Superblock",			\
+	"Cylinder Group",		\
+	"Single Level Indirect",	\
+	"Double Level Indirect",	\
+	"Triple Level Indirect",	\
+	"External Attribute",		\
+	"Inode Block",			\
+	"Directory Contents",		\
+	"User Data" }
+long readcnt[BT_NUMBUFTYPES];
+long totalreadcnt[BT_NUMBUFTYPES];
+struct timespec readtime[BT_NUMBUFTYPES];
+struct timespec totalreadtime[BT_NUMBUFTYPES];
+struct timespec startprog;
 
 struct bufarea sblk;		/* file system superblock */
-struct bufarea cgblk;		/* cylinder group blocks */
 struct bufarea *pdirbp;		/* current directory contents */
 struct bufarea *pbp;		/* current inode block */
 
@@ -177,16 +207,15 @@ struct bufarea *pbp;		/* current inode b
 	else \
 		(bp)->b_dirty = 1; \
 } while (0)
-#define	initbarea(bp) do { \
+#define	initbarea(bp, type) do { \
 	(bp)->b_dirty = 0; \
 	(bp)->b_bno = (ufs2_daddr_t)-1; \
 	(bp)->b_flags = 0; \
+	(bp)->b_type = type; \
 } while (0)
 
 #define	sbdirty()	dirty(&sblk)
-#define	cgdirty()	dirty(&cgblk)
 #define	sblock		(*sblk.b_un.b_fs)
-#define	cgrp		(*cgblk.b_un.b_cg)
 
 enum fixstate {DONTKNOW, NOFIX, FIX, IGNORE};
 ino_t cursnapshot;
@@ -329,6 +358,37 @@ struct	ufs2_dinode ufs2_zino;
 
 #define	EEXIT	8		/* Standard error exit. */
 
+int flushentry(void);
+/*
+ * Wrapper for malloc() that flushes the cylinder group cache to try 
+ * to get space.
+ */
+static inline void*
+Malloc(int size)
+{
+	void *retval;
+
+	while ((retval = malloc(size)) == NULL)
+		if (flushentry() == 0)
+			break;
+	return (retval);
+}
+
+/*
+ * Wrapper for calloc() that flushes the cylinder group cache to try 
+ * to get space.
+ */
+static inline void*
+Calloc(int cnt, int size)
+{
+	void *retval;
+
+	while ((retval = calloc(cnt, size)) == NULL)
+		if (flushentry() == 0)
+			break;
+	return (retval);
+}
+
 struct fstab;
 
 
@@ -346,7 +406,7 @@ void		cacheino(union dinode *dp, ino_t i
 void		catch(int);
 void		catchquit(int);
 int		changeino(ino_t dir, const char *name, ino_t newnum);
-int		check_cgmagic(int cg, struct cg *cgp);
+int		check_cgmagic(int cg, struct bufarea *cgbp);
 int		chkrange(ufs2_daddr_t blk, int cnt);
 void		ckfini(int markclean);
 int		ckinode(union dinode *dp, struct inodesc *);
@@ -357,6 +417,7 @@ int		dirscan(struct inodesc *);
 int		dofix(struct inodesc *, const char *msg);
 int		eascan(struct inodesc *, struct ufs2_dinode *dp);
 void		fileerror(ino_t cwd, ino_t ino, const char *errmesg);
+void		finalIOstats(void);
 int		findino(struct inodesc *);
 int		findname(struct inodesc *);
 void		flush(int fd, struct bufarea *bp);
@@ -365,7 +426,8 @@ void		freeino(ino_t ino);
 void		freeinodebuf(void);
 int		ftypeok(union dinode *dp);
 void		getblk(struct bufarea *bp, ufs2_daddr_t blk, long size);
-struct bufarea *getdatablk(ufs2_daddr_t blkno, long size);
+struct bufarea *cgget(int cg);
+struct bufarea *getdatablk(ufs2_daddr_t blkno, long size, int type);
 struct inoinfo *getinoinfo(ino_t inumber);
 union dinode   *getnextinode(ino_t inumber, int rebuildcg);
 void		getpathname(char *namebuf, ino_t curdir, ino_t ino);
@@ -375,6 +437,7 @@ void		alarmhandler(int sig);
 void		inocleanup(void);
 void		inodirty(void);
 struct inostat *inoinfo(ino_t inum);
+void		IOstats(char *what);
 int		linkup(ino_t orphan, ino_t parentdir, char *name);
 int		makeentry(ino_t parent, ino_t ino, const char *name);
 void		panic(const char *fmt, ...) __printflike(1, 2);

Modified: stable/9/sbin/fsck_ffs/fsutil.c
==============================================================================
--- stable/9/sbin/fsck_ffs/fsutil.c	Tue Apr 23 06:28:35 2013	(r249787)
+++ stable/9/sbin/fsck_ffs/fsutil.c	Tue Apr 23 06:28:49 2013	(r249788)
@@ -56,19 +56,24 @@ __FBSDID("$FreeBSD$");
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <time.h>
 #include <unistd.h>
 
 #include "fsck.h"
 
 static void slowio_start(void);
 static void slowio_end(void);
+static void printIOstats(void);
 
-long	diskreads, totalreads;	/* Disk cache statistics */
+static long diskreads, totaldiskreads, totalreads; /* Disk cache statistics */
+static struct timespec startpass, finishpass;
 struct timeval slowio_starttime;
 int slowio_delay_usec = 10000;	/* Initial IO delay for background fsck */
 int slowio_pollcnt;
+static struct bufarea cgblk;	/* backup buffer for cylinder group blocks */
 static TAILQ_HEAD(buflist, bufarea) bufhead;	/* head of buffer cache list */
 static int numbufs;				/* size of buffer cache */
+static char *buftype[BT_NUMBUFTYPES] = BT_NAMES;
 
 int
 ftypeok(union dinode *dp)
@@ -158,18 +163,18 @@ bufinit(void)
 	char *bufp;
 
 	pbp = pdirbp = (struct bufarea *)0;
-	bufp = malloc((unsigned int)sblock.fs_bsize);
+	bufp = Malloc((unsigned int)sblock.fs_bsize);
 	if (bufp == 0)
 		errx(EEXIT, "cannot allocate buffer pool");
 	cgblk.b_un.b_buf = bufp;
-	initbarea(&cgblk);
+	initbarea(&cgblk, BT_CYLGRP);
 	TAILQ_INIT(&bufhead);
 	bufcnt = MAXBUFS;
 	if (bufcnt < MINBUFS)
 		bufcnt = MINBUFS;
 	for (i = 0; i < bufcnt; i++) {
-		bp = (struct bufarea *)malloc(sizeof(struct bufarea));
-		bufp = malloc((unsigned int)sblock.fs_bsize);
+		bp = (struct bufarea *)Malloc(sizeof(struct bufarea));
+		bufp = Malloc((unsigned int)sblock.fs_bsize);
 		if (bp == NULL || bufp == NULL) {
 			if (i >= MINBUFS)
 				break;
@@ -177,16 +182,72 @@ bufinit(void)
 		}
 		bp->b_un.b_buf = bufp;
 		TAILQ_INSERT_HEAD(&bufhead, bp, b_list);
-		initbarea(bp);
+		initbarea(bp, BT_UNKNOWN);
 	}
 	numbufs = i;	/* save number of buffers */
+	for (i = 0; i < BT_NUMBUFTYPES; i++) {
+		readtime[i].tv_sec = totalreadtime[i].tv_sec = 0;
+		readtime[i].tv_nsec = totalreadtime[i].tv_nsec = 0;
+		readcnt[i] = totalreadcnt[i] = 0;
+	}
+}
+
+/*
+ * Manage cylinder group buffers.
+ */
+static struct bufarea *cgbufs;	/* header for cylinder group cache */
+static int flushtries;		/* number of tries to reclaim memory */
+
+struct bufarea *
+cgget(int cg)
+{
+	struct bufarea *cgbp;
+	struct cg *cgp;
+
+	if (cgbufs == NULL) {
+		cgbufs = Calloc(sblock.fs_ncg, sizeof(struct bufarea));
+		if (cgbufs == NULL)
+			errx(EEXIT, "cannot allocate cylinder group buffers");
+	}
+	cgbp = &cgbufs[cg];
+	if (cgbp->b_un.b_cg != NULL)
+		return (cgbp);
+	cgp = NULL;
+	if (flushtries == 0)
+		cgp = malloc((unsigned int)sblock.fs_cgsize);
+	if (cgp == NULL) {
+		getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
+		return (&cgblk);
+	}
+	cgbp->b_un.b_cg = cgp;
+	initbarea(cgbp, BT_CYLGRP);
+	getblk(cgbp, cgtod(&sblock, cg), sblock.fs_cgsize);
+	return (cgbp);
+}
+
+/*
+ * Attempt to flush a cylinder group cache entry.
+ * Return whether the flush was successful.
+ */
+int
+flushentry(void)
+{
+	struct bufarea *cgbp;
+
+	cgbp = &cgbufs[flushtries++];
+	if (cgbp->b_un.b_cg == NULL)
+		return (0);
+	flush(fswritefd, cgbp);
+	free(cgbp->b_un.b_buf);
+	cgbp->b_un.b_buf = NULL;
+	return (1);
 }
 
 /*
  * Manage a cache of directory blocks.
  */
 struct bufarea *
-getdatablk(ufs2_daddr_t blkno, long size)
+getdatablk(ufs2_daddr_t blkno, long size, int type)
 {
 	struct bufarea *bp;
 
@@ -198,26 +259,62 @@ getdatablk(ufs2_daddr_t blkno, long size
 			break;
 	if (bp == NULL)
 		errx(EEXIT, "deadlocked buffer pool");
+	bp->b_type = type;
 	getblk(bp, blkno, size);
 	/* fall through */
 foundit:
+	if (debug && bp->b_type != type)
+		printf("Buffer type changed from %s to %s\n",
+		    buftype[bp->b_type], buftype[type]);
 	TAILQ_REMOVE(&bufhead, bp, b_list);
 	TAILQ_INSERT_HEAD(&bufhead, bp, b_list);
 	bp->b_flags |= B_INUSE;
 	return (bp);
 }
 
+/*
+ * Timespec operations (from <sys/time.h>).
+ */
+#define	timespecsub(vvp, uvp)						\
+	do {								\
+		(vvp)->tv_sec -= (uvp)->tv_sec;				\
+		(vvp)->tv_nsec -= (uvp)->tv_nsec;			\
+		if ((vvp)->tv_nsec < 0) {				\
+			(vvp)->tv_sec--;				\
+			(vvp)->tv_nsec += 1000000000;			\
+		}							\
+	} while (0)
+#define	timespecadd(vvp, uvp)						\
+	do {								\
+		(vvp)->tv_sec += (uvp)->tv_sec;				\
+		(vvp)->tv_nsec += (uvp)->tv_nsec;			\
+		if ((vvp)->tv_nsec >= 1000000000) {			\
+			(vvp)->tv_sec++;				\
+			(vvp)->tv_nsec -= 1000000000;			\
+		}							\
+	} while (0)
+
 void
 getblk(struct bufarea *bp, ufs2_daddr_t blk, long size)
 {
 	ufs2_daddr_t dblk;
+	struct timespec start, finish;
 
-	totalreads++;
 	dblk = fsbtodb(&sblock, blk);
-	if (bp->b_bno != dblk) {
+	if (bp->b_bno == dblk) {
+		totalreads++;
+	} else {
 		flush(fswritefd, bp);
-		diskreads++;
+		if (debug) {
+			readcnt[bp->b_type]++;
+			clock_gettime(CLOCK_REALTIME_PRECISE, &start);
+		}
 		bp->b_errs = blread(fsreadfd, bp->b_un.b_buf, dblk, size);
+		if (debug) {
+			clock_gettime(CLOCK_REALTIME_PRECISE, &finish);
+			timespecsub(&finish, &start);
+			timespecadd(&readtime[bp->b_type], &finish);
+		}
 		bp->b_bno = dblk;
 		bp->b_size = size;
 	}
@@ -291,8 +388,8 @@ ckfini(int markclean)
 	}
 	if (debug && totalreads > 0)
 		printf("cache with %d buffers missed %ld of %ld (%d%%)\n",
-		    numbufs, diskreads, totalreads,
-		    (int)(diskreads * 100 / totalreads));
+		    numbufs, totaldiskreads, totalreads,
+		    (int)(totaldiskreads * 100 / totalreads));
 	if (fswritefd < 0) {
 		(void)close(fsreadfd);
 		return;
@@ -317,6 +414,13 @@ ckfini(int markclean)
 	}
 	if (numbufs != cnt)
 		errx(EEXIT, "panic: lost %d buffers", numbufs - cnt);
+	for (cnt = 0; cnt < sblock.fs_ncg; cnt++) {
+		if (cgbufs[cnt].b_un.b_cg == NULL)
+			continue;
+		flush(fswritefd, &cgbufs[cnt]);
+		free(cgbufs[cnt].b_un.b_cg);
+	}
+	free(cgbufs);
 	pbp = pdirbp = (struct bufarea *)0;
 	if (cursnapshot == 0 && sblock.fs_clean != markclean) {
 		if ((sblock.fs_clean = markclean) != 0) {
@@ -346,6 +450,84 @@ ckfini(int markclean)
 	(void)close(fswritefd);
 }
 
+/*
+ * Print out I/O statistics.
+ */
+void
+IOstats(char *what)
+{
+	int i;
+
+	if (debug == 0)
+		return;
+	if (diskreads == 0) {
+		printf("%s: no I/O\n\n", what);
+		return;
+	}
+	if (startpass.tv_sec == 0)
+		startpass = startprog;
+	printf("%s: I/O statistics\n", what);
+	printIOstats();
+	totaldiskreads += diskreads;
+	diskreads = 0;
+	for (i = 0; i < BT_NUMBUFTYPES; i++) {
+		timespecadd(&totalreadtime[i], &readtime[i]);
+		totalreadcnt[i] += readcnt[i];
+		readtime[i].tv_sec = readtime[i].tv_nsec = 0;
+		readcnt[i] = 0;
+	}
+	clock_gettime(CLOCK_REALTIME_PRECISE, &startpass);
+}
+
+void
+finalIOstats(void)
+{
+	int i;
+
+	if (debug == 0)
+		return;
+	printf("Final I/O statistics\n");
+	totaldiskreads += diskreads;
+	diskreads = totaldiskreads;
+	startpass = startprog;
+	for (i = 0; i < BT_NUMBUFTYPES; i++) {
+		timespecadd(&totalreadtime[i], &readtime[i]);
+		totalreadcnt[i] += readcnt[i];
+		readtime[i] = totalreadtime[i];
+		readcnt[i] = totalreadcnt[i];
+	}
+	printIOstats();
+}
+
+static void printIOstats(void)
+{
+	long long msec, totalmsec;
+	int i;
+
+	clock_gettime(CLOCK_REALTIME_PRECISE, &finishpass);
+	timespecsub(&finishpass, &startpass);
+	printf("Running time: %jd.%03ld sec\n",
+		(intmax_t)finishpass.tv_sec, finishpass.tv_nsec / 1000000);
+	printf("buffer reads by type:\n");
+	for (totalmsec = 0, i = 0; i < BT_NUMBUFTYPES; i++)
+		totalmsec += readtime[i].tv_sec * 1000 +
+		    readtime[i].tv_nsec / 1000000;
+	if (totalmsec == 0)
+		totalmsec = 1;
+	for (i = 0; i < BT_NUMBUFTYPES; i++) {
+		if (readcnt[i] == 0)
+			continue;
+		msec =
+		    readtime[i].tv_sec * 1000 + readtime[i].tv_nsec / 1000000;
+		printf("%21s:%8ld %2ld.%ld%% %4jd.%03ld sec %2lld.%lld%%\n",
+		    buftype[i], readcnt[i], readcnt[i] * 100 / diskreads,
+		    (readcnt[i] * 1000 / diskreads) % 10,
+		    (intmax_t)readtime[i].tv_sec, readtime[i].tv_nsec / 1000000,
+		    msec * 100 / totalmsec, (msec * 1000 / totalmsec) % 10);
+	}
+	printf("\n");
+}
+
 int
 blread(int fd, char *buf, ufs2_daddr_t blk, long size)
 {
@@ -357,6 +539,8 @@ blread(int fd, char *buf, ufs2_daddr_t b
 	offset *= dev_bsize;
 	if (bkgrdflag)
 		slowio_start();
+	totalreads++;
+	diskreads++;
 	if (lseek(fd, offset, 0) < 0)
 		rwerror("SEEK BLK", blk);
 	else if (read(fd, buf, (int)size) == size) {
@@ -438,8 +622,9 @@ blerase(int fd, ufs2_daddr_t blk, long s
  * test fails, offer an option to rebuild the whole cylinder group.
  */
 int
-check_cgmagic(int cg, struct cg *cgp)
+check_cgmagic(int cg, struct bufarea *cgbp)
 {
+	struct cg *cgp = cgbp->b_un.b_cg;
 
 	/*
 	 * Extended cylinder group checks.
@@ -499,7 +684,7 @@ check_cgmagic(int cg, struct cg *cgp)
 		cgp->cg_nextfreeoff = cgp->cg_clusteroff +
 		    howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT);
 	}
-	cgdirty();
+	dirty(cgbp);
 	return (0);
 }
 
@@ -510,7 +695,8 @@ ufs2_daddr_t
 allocblk(long frags)
 {
 	int i, j, k, cg, baseblk;
-	struct cg *cgp = &cgrp;
+	struct bufarea *cgbp;
+	struct cg *cgp;
 
 	if (frags <= 0 || frags > sblock.fs_frag)
 		return (0);
@@ -526,8 +712,9 @@ allocblk(long frags)
 				continue;
 			}
 			cg = dtog(&sblock, i + j);
-			getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
-			if (!check_cgmagic(cg, cgp))
+			cgbp = cgget(cg);
+			cgp = cgbp->b_un.b_cg;
+			if (!check_cgmagic(cg, cgbp))
 				return (0);
 			baseblk = dtogd(&sblock, i + j);
 			for (k = 0; k < frags; k++) {
@@ -539,7 +726,7 @@ allocblk(long frags)
 				cgp->cg_cs.cs_nbfree--;
 			else
 				cgp->cg_cs.cs_nffree -= frags;
-			cgdirty();
+			dirty(cgbp);
 			return (i + j);
 		}
 	}

Modified: stable/9/sbin/fsck_ffs/inode.c
==============================================================================
--- stable/9/sbin/fsck_ffs/inode.c	Tue Apr 23 06:28:35 2013	(r249787)
+++ stable/9/sbin/fsck_ffs/inode.c	Tue Apr 23 06:28:49 2013	(r249788)
@@ -52,7 +52,7 @@ __FBSDID("$FreeBSD$");
 
 static ino_t startinum;
 
-static int iblock(struct inodesc *, long ilevel, off_t isize);
+static int iblock(struct inodesc *, long ilevel, off_t isize, int type);
 
 int
 ckinode(union dinode *dp, struct inodesc *idesc)
@@ -121,7 +121,7 @@ ckinode(union dinode *dp, struct inodesc
 		sizepb *= NINDIR(&sblock);
 		if (DIP(&dino, di_ib[i])) {
 			idesc->id_blkno = DIP(&dino, di_ib[i]);
-			ret = iblock(idesc, i + 1, remsize);
+			ret = iblock(idesc, i + 1, remsize, BT_LEVEL1 + i);
 			if (ret & STOP)
 				return (ret);
 		} else {
@@ -151,7 +151,7 @@ ckinode(union dinode *dp, struct inodesc
 }
 
 static int
-iblock(struct inodesc *idesc, long ilevel, off_t isize)
+iblock(struct inodesc *idesc, long ilevel, off_t isize, int type)
 {
 	struct bufarea *bp;
 	int i, n, (*func)(struct inodesc *), nif;
@@ -168,7 +168,7 @@ iblock(struct inodesc *idesc, long ileve
 		func = dirscan;
 	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
 		return (SKIP);
-	bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
+	bp = getdatablk(idesc->id_blkno, sblock.fs_bsize, type);
 	ilevel--;
 	for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
 		sizepb *= NINDIR(&sblock);
@@ -199,7 +199,7 @@ iblock(struct inodesc *idesc, long ileve
 			if (ilevel == 0)
 				n = (*func)(idesc);
 			else
-				n = iblock(idesc, ilevel, isize);
+				n = iblock(idesc, ilevel, isize, type);
 			if (n & STOP) {
 				bp->b_flags &= ~B_INUSE;
 				return (n);
@@ -291,7 +291,7 @@ ginode(ino_t inumber)
 		iblk = ino_to_fsba(&sblock, inumber);
 		if (pbp != 0)
 			pbp->b_flags &= ~B_INUSE;
-		pbp = getdatablk(iblk, sblock.fs_bsize);
+		pbp = getdatablk(iblk, sblock.fs_bsize, BT_INODES);
 		startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
 	}
 	if (sblock.fs_magic == FS_UFS1_MAGIC)
@@ -305,8 +305,8 @@ ginode(ino_t inumber)
  * over all the inodes in numerical order.
  */
 static ino_t nextino, lastinum, lastvalidinum;
-static long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
-static caddr_t inodebuf;
+static long readcount, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
+static struct bufarea inobuf;
 
 union dinode *
 getnextinode(ino_t inumber, int rebuildcg)
@@ -314,16 +314,16 @@ getnextinode(ino_t inumber, int rebuildc
 	int j;
 	long size;
 	mode_t mode;
-	ufs2_daddr_t ndb, dblk;
+	ufs2_daddr_t ndb, blk;
 	union dinode *dp;
 	static caddr_t nextinop;
 
 	if (inumber != nextino++ || inumber > lastvalidinum)
 		errx(EEXIT, "bad inode number %d to nextinode", inumber);
 	if (inumber >= lastinum) {
-		readcnt++;
-		dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum));
-		if (readcnt % readpercg == 0) {
+		readcount++;
+		blk = ino_to_fsba(&sblock, lastinum);
+		if (readcount % readpercg == 0) {
 			size = partialsize;
 			lastinum += partialcnt;
 		} else {
@@ -331,14 +331,14 @@ getnextinode(ino_t inumber, int rebuildc
 			lastinum += fullcnt;
 		}
 		/*
-		 * If blread returns an error, it will already have zeroed
+		 * If getblk encounters an error, it will already have zeroed
 		 * out the buffer, so we do not need to do so here.
 		 */
-		(void)blread(fsreadfd, inodebuf, dblk, size);
-		nextinop = inodebuf;
+		getblk(&inobuf, blk, size);
+		nextinop = inobuf.b_un.b_buf;
 	}
 	dp = (union dinode *)nextinop;
-	if (rebuildcg && nextinop == inodebuf) {
+	if (rebuildcg && nextinop == inobuf.b_un.b_buf) {
 		/*
 		 * Try to determine if we have reached the end of the
 		 * allocated inodes.
@@ -403,8 +403,8 @@ setinodebuf(ino_t inum)
 	startinum = 0;
 	nextino = inum;
 	lastinum = inum;
-	readcnt = 0;
-	if (inodebuf != NULL)
+	readcount = 0;
+	if (inobuf.b_un.b_buf != NULL)
 		return;
 	inobufsize = blkroundup(&sblock, INOBUFSIZE);
 	fullcnt = inobufsize / ((sblock.fs_magic == FS_UFS1_MAGIC) ?
@@ -419,7 +419,8 @@ setinodebuf(ino_t inum)
 		partialcnt = fullcnt;
 		partialsize = inobufsize;
 	}
-	if ((inodebuf = malloc((unsigned)inobufsize)) == NULL)
+	initbarea(&inobuf, BT_INODES);
+	if ((inobuf.b_un.b_buf = Malloc((unsigned)inobufsize)) == NULL)
 		errx(EEXIT, "cannot allocate space for inode buffer");
 }
 
@@ -427,9 +428,9 @@ void
 freeinodebuf(void)
 {
 
-	if (inodebuf != NULL)
-		free((char *)inodebuf);
-	inodebuf = NULL;
+	if (inobuf.b_un.b_buf != NULL)
+		free((char *)inobuf.b_un.b_buf);
+	inobuf.b_un.b_buf = NULL;
 }
 
 /*
@@ -450,7 +451,7 @@ cacheino(union dinode *dp, ino_t inumber
 	else
 		blks = howmany(DIP(dp, di_size), sblock.fs_bsize);
 	inp = (struct inoinfo *)
-		malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs2_daddr_t));
+		Malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs2_daddr_t));
 	if (inp == NULL)
 		errx(EEXIT, "cannot increase directory list");
 	inpp = &inphead[inumber % dirhash];
@@ -653,7 +654,8 @@ allocino(ino_t request, int type)
 {
 	ino_t ino;
 	union dinode *dp;
-	struct cg *cgp = &cgrp;
+	struct bufarea *cgbp;
+	struct cg *cgp;
 	int cg;
 
 	if (request == 0)
@@ -666,8 +668,9 @@ allocino(ino_t request, int type)
 	if (ino == maxino)
 		return (0);
 	cg = ino_to_cg(&sblock, ino);
-	getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
-	if (!check_cgmagic(cg, cgp))
+	cgbp = cgget(cg);
+	cgp = cgbp->b_un.b_cg;
+	if (!check_cgmagic(cg, cgbp))
 		return (0);
 	setbit(cg_inosused(cgp), ino % sblock.fs_ipg);
 	cgp->cg_cs.cs_nifree--;
@@ -683,7 +686,7 @@ allocino(ino_t request, int type)
 	default:
 		return (0);
 	}
-	cgdirty();
+	dirty(cgbp);
 	dp = ginode(ino);
 	DIP_SET(dp, di_db[0], allocblk((long)1));
 	if (DIP(dp, di_db[0]) == 0) {

Modified: stable/9/sbin/fsck_ffs/main.c
==============================================================================
--- stable/9/sbin/fsck_ffs/main.c	Tue Apr 23 06:28:35 2013	(r249787)
+++ stable/9/sbin/fsck_ffs/main.c	Tue Apr 23 06:28:49 2013	(r249788)
@@ -426,7 +426,9 @@ checkfilesys(char *filesys)
 			printf("** Root file system\n");
 		printf("** Phase 1 - Check Blocks and Sizes\n");
 	}
+	clock_gettime(CLOCK_REALTIME_PRECISE, &startprog);
 	pass1();
+	IOstats("Pass1");
 
 	/*
 	 * 1b: locate first references to duplicates, if any
@@ -439,6 +441,7 @@ checkfilesys(char *filesys)
 			    usedsoftdep ? "softupdates" : "");
 		printf("** Phase 1b - Rescan For More DUPS\n");
 		pass1b();
+		IOstats("Pass1b");
 	}
 
 	/*
@@ -447,6 +450,7 @@ checkfilesys(char *filesys)
 	if (preen == 0)
 		printf("** Phase 2 - Check Pathnames\n");
 	pass2();
+	IOstats("Pass2");
 
 	/*
 	 * 3: scan inodes looking for disconnected directories
@@ -454,6 +458,7 @@ checkfilesys(char *filesys)
 	if (preen == 0)
 		printf("** Phase 3 - Check Connectivity\n");
 	pass3();
+	IOstats("Pass3");
 
 	/*
 	 * 4: scan inodes looking for disconnected files; check reference counts
@@ -461,6 +466,7 @@ checkfilesys(char *filesys)
 	if (preen == 0)
 		printf("** Phase 4 - Check Reference Counts\n");
 	pass4();
+	IOstats("Pass4");
 
 	/*
 	 * 5: check and repair resource counts in cylinder groups
@@ -468,6 +474,7 @@ checkfilesys(char *filesys)
 	if (preen == 0)
 		printf("** Phase 5 - Check Cyl groups\n");
 	pass5();
+	IOstats("Pass5");
 
 	/*
 	 * print out summary statistics
@@ -521,6 +528,7 @@ checkfilesys(char *filesys)
 	}
 	if (rerun)
 		resolved = 0;
+	finalIOstats();
 
 	/*
 	 * Check to see if the file system is mounted read-write.

Modified: stable/9/sbin/fsck_ffs/pass1.c
==============================================================================
--- stable/9/sbin/fsck_ffs/pass1.c	Tue Apr 23 06:28:35 2013	(r249787)
+++ stable/9/sbin/fsck_ffs/pass1.c	Tue Apr 23 06:28:49 2013	(r249788)
@@ -61,6 +61,8 @@ pass1(void)
 {
 	struct inostat *info;
 	struct inodesc idesc;
+	struct bufarea *cgbp;
+	struct cg *cgp;
 	ino_t inumber, inosused, mininos;
 	ufs2_daddr_t i, cgd;
 	u_int8_t *cp;
@@ -92,12 +94,13 @@ pass1(void)
 	for (c = 0; c < sblock.fs_ncg; c++) {
 		inumber = c * sblock.fs_ipg;
 		setinodebuf(inumber);
-		getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize);
+		cgbp = cgget(c);
+		cgp = cgbp->b_un.b_cg;
 		rebuildcg = 0;
-		if (!check_cgmagic(c, &cgrp))
+		if (!check_cgmagic(c, cgbp))
 			rebuildcg = 1;
 		if (!rebuildcg && sblock.fs_magic == FS_UFS2_MAGIC) {
-			inosused = cgrp.cg_initediblk;
+			inosused = cgp->cg_initediblk;
 			if (inosused > sblock.fs_ipg) {
 				pfatal("%s (%d > %d) %s %d\nReset to %d\n",
 				    "Too many initialized inodes", inosused,
@@ -127,7 +130,7 @@ pass1(void)
 		 * read only those inodes in from disk.
 		 */
 		if ((preen || inoopt) && usedsoftdep && !rebuildcg) {
-			cp = &cg_inosused(&cgrp)[(inosused - 1) / CHAR_BIT];
+			cp = &cg_inosused(cgp)[(inosused - 1) / CHAR_BIT];
 			for ( ; inosused > 0; inosused -= CHAR_BIT, cp--) {
 				if (*cp == 0)
 					continue;
@@ -149,7 +152,7 @@ pass1(void)
 			inostathead[c].il_stat = 0;
 			continue;
 		}
-		info = calloc((unsigned)inosused, sizeof(struct inostat));
+		info = Calloc((unsigned)inosused, sizeof(struct inostat));
 		if (info == NULL)
 			errx(EEXIT, "cannot alloc %u bytes for inoinfo",
 			    (unsigned)(sizeof(struct inostat) * inosused));
@@ -169,7 +172,7 @@ pass1(void)
 			 * valid number for this cylinder group.
 			 */
 			if (checkinode(inumber, &idesc, rebuildcg) == 0 &&
-			    i > cgrp.cg_initediblk)
+			    i > cgp->cg_initediblk)
 				break;
 		}
 		/*
@@ -181,16 +184,16 @@ pass1(void)
 		mininos = roundup(inosused + INOPB(&sblock), INOPB(&sblock));
 		if (inoopt && !preen && !rebuildcg &&
 		    sblock.fs_magic == FS_UFS2_MAGIC &&
-		    cgrp.cg_initediblk > 2 * INOPB(&sblock) &&
-		    mininos < cgrp.cg_initediblk) {
-			i = cgrp.cg_initediblk;
+		    cgp->cg_initediblk > 2 * INOPB(&sblock) &&
+		    mininos < cgp->cg_initediblk) {
+			i = cgp->cg_initediblk;
 			if (mininos < 2 * INOPB(&sblock))
-				cgrp.cg_initediblk = 2 * INOPB(&sblock);
+				cgp->cg_initediblk = 2 * INOPB(&sblock);
 			else
-				cgrp.cg_initediblk = mininos;
+				cgp->cg_initediblk = mininos;
 			pwarn("CYLINDER GROUP %d: RESET FROM %ju TO %d %s\n",
-			    c, i, cgrp.cg_initediblk, "VALID INODES");
-			cgdirty();
+			    c, i, cgp->cg_initediblk, "VALID INODES");
+			dirty(cgbp);
 		}
 		if (inosused < sblock.fs_ipg)
 			continue;
@@ -199,11 +202,11 @@ pass1(void)
 			inosused = 0;
 		else
 			inosused = lastino - (c * sblock.fs_ipg);
-		if (rebuildcg && inosused > cgrp.cg_initediblk &&
+		if (rebuildcg && inosused > cgp->cg_initediblk &&
 		    sblock.fs_magic == FS_UFS2_MAGIC) {
-			cgrp.cg_initediblk = roundup(inosused, INOPB(&sblock));
+			cgp->cg_initediblk = roundup(inosused, INOPB(&sblock));
 			pwarn("CYLINDER GROUP %d: FOUND %d VALID INODES\n", c,
-			    cgrp.cg_initediblk);
+			    cgp->cg_initediblk);
 		}
 		/*
 		 * If we were not able to determine in advance which inodes
@@ -219,7 +222,7 @@ pass1(void)
 			inostathead[c].il_stat = 0;
 			continue;
 		}
-		info = calloc((unsigned)inosused, sizeof(struct inostat));
+		info = Calloc((unsigned)inosused, sizeof(struct inostat));
 		if (info == NULL)
 			errx(EEXIT, "cannot alloc %u bytes for inoinfo",
 			    (unsigned)(sizeof(struct inostat) * inosused));
@@ -482,7 +485,7 @@ pass1check(struct inodesc *idesc)
 				}
 				return (STOP);
 			}
-			new = (struct dups *)malloc(sizeof(struct dups));
+			new = (struct dups *)Malloc(sizeof(struct dups));
 			if (new == NULL) {
 				pfatal("DUP TABLE OVERFLOW.");
 				if (reply("CONTINUE") == 0) {

Modified: stable/9/sbin/fsck_ffs/pass5.c
==============================================================================
--- stable/9/sbin/fsck_ffs/pass5.c	Tue Apr 23 06:28:35 2013	(r249787)
+++ stable/9/sbin/fsck_ffs/pass5.c	Tue Apr 23 06:28:49 2013	(r249788)
@@ -59,14 +59,14 @@ pass5(void)
 	int c, i, j, blk, frags, basesize, mapsize;
 	int inomapsize, blkmapsize;
 	struct fs *fs = &sblock;
-	struct cg *cg = &cgrp;
 	ufs2_daddr_t d, dbase, dmax, start;
 	int rewritecg = 0;
 	struct csum *cs;
 	struct csum_total cstotal;
 	struct inodesc idesc[3];
 	char buf[MAXBSIZE];
-	struct cg *newcg = (struct cg *)buf;
+	struct cg *cg, *newcg = (struct cg *)buf;
+	struct bufarea *cgbp;
 
 	inoinfo(WINO)->ino_state = USTATE;
 	memset(newcg, 0, (size_t)fs->fs_cgsize);
@@ -162,7 +162,8 @@ pass5(void)
 			    c * 100 / sblock.fs_ncg);
 			got_sigalarm = 0;
 		}
-		getblk(&cgblk, cgtod(fs, c), fs->fs_cgsize);
+		cgbp = cgget(c);
+		cg = cgbp->b_un.b_cg;
 		if (!cg_chkmagic(cg))
 			pfatal("CG %d: BAD MAGIC NUMBER\n", c);
 		newcg->cg_time = cg->cg_time;
@@ -324,14 +325,14 @@ pass5(void)
 		}
 		if (rewritecg) {
 			memmove(cg, newcg, (size_t)fs->fs_cgsize);
-			cgdirty();
+			dirty(cgbp);
 			continue;
 		}
 		if (cursnapshot == 0 &&
 		    memcmp(newcg, cg, basesize) != 0 &&
 		    dofix(&idesc[2], "SUMMARY INFORMATION BAD")) {
 			memmove(cg, newcg, (size_t)basesize);
-			cgdirty();
+			dirty(cgbp);
 		}
 		if (bkgrdflag != 0 || usedsoftdep || debug)
 			update_maps(cg, newcg, bkgrdflag);
@@ -340,7 +341,7 @@ pass5(void)
 		    dofix(&idesc[1], "BLK(S) MISSING IN BIT MAPS")) {
 			memmove(cg_inosused(cg), cg_inosused(newcg),
 			      (size_t)mapsize);
-			cgdirty();
+			dirty(cgbp);
 		}
 	}
 	if (cursnapshot == 0 &&

Modified: stable/9/sbin/fsck_ffs/setup.c
==============================================================================
--- stable/9/sbin/fsck_ffs/setup.c	Tue Apr 23 06:28:35 2013	(r249787)
+++ stable/9/sbin/fsck_ffs/setup.c	Tue Apr 23 06:28:49 2013	(r249788)
@@ -240,7 +240,7 @@ setup(char *dev)
 	 * read in the summary info.
 	 */
 	asked = 0;
-	sblock.fs_csp = calloc(1, sblock.fs_cssize);
+	sblock.fs_csp = Calloc(1, sblock.fs_cssize);
 	if (sblock.fs_csp == NULL) {
 		printf("cannot alloc %u bytes for cg summary info\n",
 		    (unsigned)sblock.fs_cssize);
@@ -249,6 +249,7 @@ setup(char *dev)
 	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
 		size = sblock.fs_cssize - i < sblock.fs_bsize ?
 		    sblock.fs_cssize - i : sblock.fs_bsize;
+		readcnt[sblk.b_type]++;
 		if (blread(fsreadfd, (char *)sblock.fs_csp + i,
 		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
 		    size) != 0 && !asked) {
@@ -264,13 +265,13 @@ setup(char *dev)
 	 * allocate and initialize the necessary maps
 	 */
 	bmapsize = roundup(howmany(maxfsblock, CHAR_BIT), sizeof(short));
-	blockmap = calloc((unsigned)bmapsize, sizeof (char));
+	blockmap = Calloc((unsigned)bmapsize, sizeof (char));
 	if (blockmap == NULL) {
 		printf("cannot alloc %u bytes for blockmap\n",
 		    (unsigned)bmapsize);
 		goto badsb;
 	}
-	inostathead = calloc((unsigned)(sblock.fs_ncg),
+	inostathead = Calloc((unsigned)(sblock.fs_ncg),
 	    sizeof(struct inostatlist));
 	if (inostathead == NULL) {
 		printf("cannot alloc %u bytes for inostathead\n",
@@ -281,9 +282,9 @@ setup(char *dev)
 	dirhash = numdirs;
 	inplast = 0;
 	listmax = numdirs + 10;
-	inpsort = (struct inoinfo **)calloc((unsigned)listmax,
+	inpsort = (struct inoinfo **)Calloc((unsigned)listmax,
 	    sizeof(struct inoinfo *));
-	inphead = (struct inoinfo **)calloc((unsigned)numdirs,
+	inphead = (struct inoinfo **)Calloc((unsigned)numdirs,
 	    sizeof(struct inoinfo *));
 	if (inpsort == NULL || inphead == NULL) {
 		printf("cannot alloc %ju bytes for inphead\n",
@@ -322,6 +323,7 @@ readsb(int listerr)
 
 	if (bflag) {
 		super = bflag;
+		readcnt[sblk.b_type]++;
 		if ((blread(fsreadfd, (char *)&sblock, super, (long)SBLOCKSIZE)))
 			return (0);
 		if (sblock.fs_magic == FS_BAD_MAGIC) {
@@ -337,6 +339,7 @@ readsb(int listerr)
 	} else {
 		for (i = 0; sblock_try[i] != -1; i++) {
 			super = sblock_try[i] / dev_bsize;
+			readcnt[sblk.b_type]++;
 			if ((blread(fsreadfd, (char *)&sblock, super,
 			    (long)SBLOCKSIZE)))
 				return (0);
@@ -439,10 +442,10 @@ sblock_init(void)
 	fswritefd = -1;
 	fsmodified = 0;
 	lfdir = 0;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list