xref: /netbsd-src/usr.sbin/makefs/ffs/mkfs.c (revision f298a94b738ab130659689d3f04c17f6991b6de5)
1*f298a94bSchs /*	$NetBSD: mkfs.c,v 1.42 2023/01/07 19:41:30 chs Exp $	*/
26325773eSlukem 
36325773eSlukem /*
442614ed3Sfvdl  * Copyright (c) 2002 Networks Associates Technology, Inc.
542614ed3Sfvdl  * All rights reserved.
642614ed3Sfvdl  *
742614ed3Sfvdl  * This software was developed for the FreeBSD Project by Marshall
842614ed3Sfvdl  * Kirk McKusick and Network Associates Laboratories, the Security
942614ed3Sfvdl  * Research Division of Network Associates, Inc. under DARPA/SPAWAR
1042614ed3Sfvdl  * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
1142614ed3Sfvdl  * research program
1242614ed3Sfvdl  *
136325773eSlukem  * Copyright (c) 1980, 1989, 1993
146325773eSlukem  *	The Regents of the University of California.  All rights reserved.
156325773eSlukem  *
166325773eSlukem  * Redistribution and use in source and binary forms, with or without
176325773eSlukem  * modification, are permitted provided that the following conditions
186325773eSlukem  * are met:
196325773eSlukem  * 1. Redistributions of source code must retain the above copyright
206325773eSlukem  *    notice, this list of conditions and the following disclaimer.
216325773eSlukem  * 2. Redistributions in binary form must reproduce the above copyright
226325773eSlukem  *    notice, this list of conditions and the following disclaimer in the
236325773eSlukem  *    documentation and/or other materials provided with the distribution.
24326b2259Sagc  * 3. Neither the name of the University nor the names of its contributors
256325773eSlukem  *    may be used to endorse or promote products derived from this software
266325773eSlukem  *    without specific prior written permission.
276325773eSlukem  *
286325773eSlukem  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
296325773eSlukem  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
306325773eSlukem  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
316325773eSlukem  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
326325773eSlukem  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
336325773eSlukem  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
346325773eSlukem  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
356325773eSlukem  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
366325773eSlukem  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
376325773eSlukem  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
386325773eSlukem  * SUCH DAMAGE.
396325773eSlukem  */
406325773eSlukem 
41b2f78261Sjmc #if HAVE_NBTOOL_CONFIG_H
42b2f78261Sjmc #include "nbtool_config.h"
43b2f78261Sjmc #endif
44b2f78261Sjmc 
456325773eSlukem #include <sys/cdefs.h>
4642614ed3Sfvdl #ifndef lint
476325773eSlukem #if 0
486325773eSlukem static char sccsid[] = "@(#)mkfs.c	8.11 (Berkeley) 5/3/95";
496325773eSlukem #else
50755a56f6Sbriggs #ifdef __RCSID
51*f298a94bSchs __RCSID("$NetBSD: mkfs.c,v 1.42 2023/01/07 19:41:30 chs Exp $");
52755a56f6Sbriggs #endif
536325773eSlukem #endif
546325773eSlukem #endif /* not lint */
556325773eSlukem 
566325773eSlukem #include <sys/param.h>
576325773eSlukem #include <sys/time.h>
586325773eSlukem #include <sys/resource.h>
596325773eSlukem 
606325773eSlukem #include <stdio.h>
616325773eSlukem #include <stdlib.h>
626325773eSlukem #include <string.h>
636325773eSlukem #include <unistd.h>
6442614ed3Sfvdl #include <errno.h>
65e4989541Schristos #include <util.h>
666325773eSlukem 
67d74b2fc0Slukem #include "makefs.h"
682406596eSjmc #include "ffs.h"
69d74b2fc0Slukem 
703d765797Slukem #include <ufs/ufs/dinode.h>
71557afc60Slukem #include <ufs/ufs/ufs_bswap.h>
72557afc60Slukem #include <ufs/ffs/fs.h>
736325773eSlukem 
74944794a5Slukem #include "ffs/ufs_inode.h"
756325773eSlukem #include "ffs/ffs_extern.h"
766325773eSlukem #include "ffs/newfs_extern.h"
776325773eSlukem 
78*f298a94bSchs static void initcg(uint32_t, time_t, const fsinfo_t *);
7942614ed3Sfvdl static int ilog2(int);
806325773eSlukem 
816325773eSlukem static int count_digits(int);
826325773eSlukem 
836325773eSlukem /*
846325773eSlukem  * make file system for cylinder-group style file systems
856325773eSlukem  */
866325773eSlukem #define	UMASK		0755
876325773eSlukem #define	POWEROF2(num)	(((num) & ((num) - 1)) == 0)
886325773eSlukem 
896325773eSlukem union {
906325773eSlukem 	struct fs fs;
9142614ed3Sfvdl 	char pad[SBLOCKSIZE];
926325773eSlukem } fsun;
936325773eSlukem #define	sblock	fsun.fs
9442614ed3Sfvdl struct	csum *fscs;
956325773eSlukem 
966325773eSlukem union {
976325773eSlukem 	struct cg cg;
98be48f412Slukem 	char pad[FFS_MAXBSIZE];
996325773eSlukem } cgun;
1006325773eSlukem #define	acg	cgun.cg
1016325773eSlukem 
10242614ed3Sfvdl char *iobuf;
10342614ed3Sfvdl int iobufsize;
1046325773eSlukem 
105db38a065Schristos union {
106db38a065Schristos 	struct fs fs;
107db38a065Schristos 	char pad[FFS_MAXBSIZE];
108db38a065Schristos } wb;
109db38a065Schristos #define writebuf wb.pad
1106325773eSlukem 
1116325773eSlukem static int     Oflag;	   /* format as an 4.3BSD file system */
11287ba0e2aSchs static int     extattr;	   /* use UFS2ea magic */
11342614ed3Sfvdl static int64_t fssize;	   /* file system size */
1146325773eSlukem static int     sectorsize;	   /* bytes/sector */
1156325773eSlukem static int     fsize;	   /* fragment size */
1166325773eSlukem static int     bsize;	   /* block size */
11742614ed3Sfvdl static int     maxbsize;   /* maximum clustering */
11842614ed3Sfvdl static int     maxblkspercg;
1196325773eSlukem static int     minfree;	   /* free space threshold */
1206325773eSlukem static int     opt;		   /* optimization preference (space or time) */
1216325773eSlukem static int     density;	   /* number of bytes per inode */
1226325773eSlukem static int     maxcontig;	   /* max contiguous blocks to allocate */
1236325773eSlukem static int     maxbpg;	   /* maximum blocks per file in a cyl group */
1246325773eSlukem static int     bbsize;	   /* boot block size */
1256325773eSlukem static int     sbsize;	   /* superblock size */
1266325773eSlukem static int     avgfilesize;	   /* expected average file size */
1276325773eSlukem static int     avgfpdir;	   /* expected number of files per directory */
1286325773eSlukem 
129db38a065Schristos static void
ffs_sb_copy(struct fs * o,const struct fs * i,size_t l,const fsinfo_t * fsopts)1300368fad2Skre ffs_sb_copy(struct fs *o, const struct fs *i, size_t l, const fsinfo_t *fsopts)
131db38a065Schristos {
132db38a065Schristos 	memcpy(o, i, l);
133db38a065Schristos 	/* Zero out pointers */
134db38a065Schristos 	o->fs_csp = NULL;
135db38a065Schristos 	o->fs_maxcluster = NULL;
136db38a065Schristos 	if (fsopts->needswap)
137db38a065Schristos 		ffs_sb_swap(i, o);
138db38a065Schristos }
139db38a065Schristos 
1406325773eSlukem struct fs *
ffs_mkfs(const char * fsys,const fsinfo_t * fsopts,time_t tstamp)141911dc957Schristos ffs_mkfs(const char *fsys, const fsinfo_t *fsopts, time_t tstamp)
1426325773eSlukem {
14342614ed3Sfvdl 	int fragsperinode, optimalfpg, origdensity, minfpg, lastminfpg;
144*f298a94bSchs 	uint32_t cylno, i;
145*f298a94bSchs 	int32_t csfrags;
1466325773eSlukem 	long long sizepb;
1476325773eSlukem 	void *space;
1480a77b69aSchristos 	int size;
1496325773eSlukem 	int nprintcols, printcolwidth;
1502406596eSjmc 	ffs_opt_t	*ffs_opts = fsopts->fs_specific;
1516325773eSlukem 
1522406596eSjmc 	Oflag =		ffs_opts->version;
15387ba0e2aSchs 	extattr =	ffs_opts->extattr;
1546325773eSlukem 	fssize =        fsopts->size / fsopts->sectorsize;
1556325773eSlukem 	sectorsize =    fsopts->sectorsize;
1562406596eSjmc 	fsize =         ffs_opts->fsize;
1572406596eSjmc 	bsize =         ffs_opts->bsize;
1582406596eSjmc 	maxbsize =      ffs_opts->maxbsize;
1592406596eSjmc 	maxblkspercg =  ffs_opts->maxblkspercg;
1602406596eSjmc 	minfree =       ffs_opts->minfree;
1612406596eSjmc 	opt =           ffs_opts->optimization;
1622406596eSjmc 	density =       ffs_opts->density;
1632406596eSjmc 	maxcontig =     ffs_opts->maxcontig;
1642406596eSjmc 	maxbpg =        ffs_opts->maxbpg;
1652406596eSjmc 	avgfilesize =   ffs_opts->avgfilesize;
1662406596eSjmc 	avgfpdir =      ffs_opts->avgfpdir;
16742614ed3Sfvdl 	bbsize =        BBSIZE;
16842614ed3Sfvdl 	sbsize =        SBLOCKSIZE;
1696325773eSlukem 
1704a5d3145Schristos 	strlcpy((char *)sblock.fs_volname, ffs_opts->label,
1714a5d3145Schristos 	    sizeof(sblock.fs_volname));
1724a5d3145Schristos 
17342614ed3Sfvdl 	if (Oflag == 0) {
17442614ed3Sfvdl 		sblock.fs_old_inodefmt = FS_42INODEFMT;
1756325773eSlukem 		sblock.fs_maxsymlinklen = 0;
17642614ed3Sfvdl 		sblock.fs_old_flags = 0;
1776325773eSlukem 	} else {
17842614ed3Sfvdl 		sblock.fs_old_inodefmt = FS_44INODEFMT;
179dcd34a91Sdholland 		sblock.fs_maxsymlinklen = (Oflag == 1 ? UFS1_MAXSYMLINKLEN :
180dcd34a91Sdholland 		    UFS2_MAXSYMLINKLEN);
18142614ed3Sfvdl 		sblock.fs_old_flags = FS_FLAGS_UPDATED;
18242614ed3Sfvdl 		sblock.fs_flags = 0;
1836325773eSlukem 	}
1846325773eSlukem 	/*
1856325773eSlukem 	 * Validate the given file system size.
1866325773eSlukem 	 * Verify that its last block can actually be accessed.
18742614ed3Sfvdl 	 * Convert to file system fragment sized units.
1886325773eSlukem 	 */
18942614ed3Sfvdl 	if (fssize <= 0) {
19042614ed3Sfvdl 		printf("preposterous size %lld\n", (long long)fssize);
19142614ed3Sfvdl 		exit(13);
19242614ed3Sfvdl 	}
1936325773eSlukem 	ffs_wtfs(fssize - 1, sectorsize, (char *)&sblock, fsopts);
1946325773eSlukem 
1956325773eSlukem 	/*
1966325773eSlukem 	 * collect and verify the filesystem density info
1976325773eSlukem 	 */
1986325773eSlukem 	sblock.fs_avgfilesize = avgfilesize;
1996325773eSlukem 	sblock.fs_avgfpdir = avgfpdir;
2006325773eSlukem 	if (sblock.fs_avgfilesize <= 0)
2016325773eSlukem 		printf("illegal expected average file size %d\n",
2026325773eSlukem 		    sblock.fs_avgfilesize), exit(14);
2036325773eSlukem 	if (sblock.fs_avgfpdir <= 0)
2046325773eSlukem 		printf("illegal expected number of files per directory %d\n",
2056325773eSlukem 		    sblock.fs_avgfpdir), exit(15);
2066325773eSlukem 	/*
2076325773eSlukem 	 * collect and verify the block and fragment sizes
2086325773eSlukem 	 */
2096325773eSlukem 	sblock.fs_bsize = bsize;
2106325773eSlukem 	sblock.fs_fsize = fsize;
2116325773eSlukem 	if (!POWEROF2(sblock.fs_bsize)) {
2126325773eSlukem 		printf("block size must be a power of 2, not %d\n",
2136325773eSlukem 		    sblock.fs_bsize);
2146325773eSlukem 		exit(16);
2156325773eSlukem 	}
2166325773eSlukem 	if (!POWEROF2(sblock.fs_fsize)) {
2176325773eSlukem 		printf("fragment size must be a power of 2, not %d\n",
2186325773eSlukem 		    sblock.fs_fsize);
2196325773eSlukem 		exit(17);
2206325773eSlukem 	}
2216325773eSlukem 	if (sblock.fs_fsize < sectorsize) {
2226325773eSlukem 		printf("fragment size %d is too small, minimum is %d\n",
2236325773eSlukem 		    sblock.fs_fsize, sectorsize);
2246325773eSlukem 		exit(18);
2256325773eSlukem 	}
2266325773eSlukem 	if (sblock.fs_bsize < MINBSIZE) {
2276325773eSlukem 		printf("block size %d is too small, minimum is %d\n",
2286325773eSlukem 		    sblock.fs_bsize, MINBSIZE);
2296325773eSlukem 		exit(19);
2306325773eSlukem 	}
231be48f412Slukem 	if (sblock.fs_bsize > FFS_MAXBSIZE) {
23242614ed3Sfvdl 		printf("block size %d is too large, maximum is %d\n",
233be48f412Slukem 		    sblock.fs_bsize, FFS_MAXBSIZE);
23442614ed3Sfvdl 		exit(19);
23542614ed3Sfvdl 	}
2366325773eSlukem 	if (sblock.fs_bsize < sblock.fs_fsize) {
2376325773eSlukem 		printf("block size (%d) cannot be smaller than fragment size (%d)\n",
2386325773eSlukem 		    sblock.fs_bsize, sblock.fs_fsize);
2396325773eSlukem 		exit(20);
2406325773eSlukem 	}
24142614ed3Sfvdl 
24242614ed3Sfvdl 	if (maxbsize < bsize || !POWEROF2(maxbsize)) {
24342614ed3Sfvdl 		sblock.fs_maxbsize = sblock.fs_bsize;
24442614ed3Sfvdl 		printf("Extent size set to %d\n", sblock.fs_maxbsize);
24542614ed3Sfvdl 	} else if (sblock.fs_maxbsize > FS_MAXCONTIG * sblock.fs_bsize) {
24642614ed3Sfvdl 		sblock.fs_maxbsize = FS_MAXCONTIG * sblock.fs_bsize;
24742614ed3Sfvdl 		printf("Extent size reduced to %d\n", sblock.fs_maxbsize);
24842614ed3Sfvdl 	} else {
24942614ed3Sfvdl 		sblock.fs_maxbsize = maxbsize;
25042614ed3Sfvdl 	}
25142614ed3Sfvdl 	sblock.fs_maxcontig = maxcontig;
25242614ed3Sfvdl 	if (sblock.fs_maxcontig < sblock.fs_maxbsize / sblock.fs_bsize) {
25342614ed3Sfvdl 		sblock.fs_maxcontig = sblock.fs_maxbsize / sblock.fs_bsize;
25442614ed3Sfvdl 		printf("Maxcontig raised to %d\n", sblock.fs_maxbsize);
25542614ed3Sfvdl 	}
25642614ed3Sfvdl 
25742614ed3Sfvdl 	if (sblock.fs_maxcontig > 1)
25842614ed3Sfvdl 		sblock.fs_contigsumsize = MIN(sblock.fs_maxcontig,FS_MAXCONTIG);
25942614ed3Sfvdl 
2606325773eSlukem 	sblock.fs_bmask = ~(sblock.fs_bsize - 1);
2616325773eSlukem 	sblock.fs_fmask = ~(sblock.fs_fsize - 1);
2626325773eSlukem 	sblock.fs_qbmask = ~sblock.fs_bmask;
2636325773eSlukem 	sblock.fs_qfmask = ~sblock.fs_fmask;
2646325773eSlukem 	for (sblock.fs_bshift = 0, i = sblock.fs_bsize; i > 1; i >>= 1)
2656325773eSlukem 		sblock.fs_bshift++;
2666325773eSlukem 	for (sblock.fs_fshift = 0, i = sblock.fs_fsize; i > 1; i >>= 1)
2676325773eSlukem 		sblock.fs_fshift++;
268e1610ba4Sdholland 	sblock.fs_frag = ffs_numfrags(&sblock, sblock.fs_bsize);
2696325773eSlukem 	for (sblock.fs_fragshift = 0, i = sblock.fs_frag; i > 1; i >>= 1)
2706325773eSlukem 		sblock.fs_fragshift++;
2716325773eSlukem 	if (sblock.fs_frag > MAXFRAG) {
2726325773eSlukem 		printf("fragment size %d is too small, "
2736325773eSlukem 			"minimum with block size %d is %d\n",
2746325773eSlukem 		    sblock.fs_fsize, sblock.fs_bsize,
2756325773eSlukem 		    sblock.fs_bsize / MAXFRAG);
2766325773eSlukem 		exit(21);
2776325773eSlukem 	}
27842614ed3Sfvdl 	sblock.fs_fsbtodb = ilog2(sblock.fs_fsize / sectorsize);
2792737439dSdholland 	sblock.fs_size = fssize = FFS_DBTOFSB(&sblock, fssize);
28042614ed3Sfvdl 
28142614ed3Sfvdl 	if (Oflag <= 1) {
28242614ed3Sfvdl 		sblock.fs_magic = FS_UFS1_MAGIC;
28342614ed3Sfvdl 		sblock.fs_sblockloc = SBLOCK_UFS1;
284a3ff3a30Sfvdl 		sblock.fs_nindir = sblock.fs_bsize / sizeof(int32_t);
28542614ed3Sfvdl 		sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs1_dinode);
286dcd34a91Sdholland 		sblock.fs_maxsymlinklen = ((UFS_NDADDR + UFS_NIADDR) *
28742614ed3Sfvdl 		    sizeof (int32_t));
28842614ed3Sfvdl 		sblock.fs_old_inodefmt = FS_44INODEFMT;
28942614ed3Sfvdl 		sblock.fs_old_cgoffset = 0;
29042614ed3Sfvdl 		sblock.fs_old_cgmask = 0xffffffff;
29142614ed3Sfvdl 		sblock.fs_old_size = sblock.fs_size;
29242614ed3Sfvdl 		sblock.fs_old_rotdelay = 0;
29342614ed3Sfvdl 		sblock.fs_old_rps = 60;
29442614ed3Sfvdl 		sblock.fs_old_nspf = sblock.fs_fsize / sectorsize;
29542614ed3Sfvdl 		sblock.fs_old_cpg = 1;
29642614ed3Sfvdl 		sblock.fs_old_interleave = 1;
29742614ed3Sfvdl 		sblock.fs_old_trackskew = 0;
29842614ed3Sfvdl 		sblock.fs_old_cpc = 0;
29942614ed3Sfvdl 		sblock.fs_old_postblformat = 1;
30042614ed3Sfvdl 		sblock.fs_old_nrpos = 1;
30142614ed3Sfvdl 	} else {
30287ba0e2aSchs 		if (extattr)
30387ba0e2aSchs 			sblock.fs_magic = FS_UFS2EA_MAGIC;
30487ba0e2aSchs 		else
30542614ed3Sfvdl 			sblock.fs_magic = FS_UFS2_MAGIC;
30642614ed3Sfvdl #if 0 /* XXX makefs is used for small filesystems. */
30742614ed3Sfvdl 		sblock.fs_sblockloc = SBLOCK_UFS2;
30842614ed3Sfvdl #else
30942614ed3Sfvdl 		sblock.fs_sblockloc = SBLOCK_UFS1;
31042614ed3Sfvdl #endif
31142614ed3Sfvdl 		sblock.fs_nindir = sblock.fs_bsize / sizeof(int64_t);
31242614ed3Sfvdl 		sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs2_dinode);
313dcd34a91Sdholland 		sblock.fs_maxsymlinklen = ((UFS_NDADDR + UFS_NIADDR) *
31442614ed3Sfvdl 		    sizeof (int64_t));
31542614ed3Sfvdl 	}
31642614ed3Sfvdl 
3176325773eSlukem 	sblock.fs_sblkno =
31842614ed3Sfvdl 	    roundup(howmany(sblock.fs_sblockloc + SBLOCKSIZE, sblock.fs_fsize),
31942614ed3Sfvdl 		sblock.fs_frag);
3206325773eSlukem 	sblock.fs_cblkno = (daddr_t)(sblock.fs_sblkno +
32142614ed3Sfvdl 	    roundup(howmany(SBLOCKSIZE, sblock.fs_fsize), sblock.fs_frag));
3226325773eSlukem 	sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag;
323dcd34a91Sdholland 	sblock.fs_maxfilesize = sblock.fs_bsize * UFS_NDADDR - 1;
324dcd34a91Sdholland 	for (sizepb = sblock.fs_bsize, i = 0; i < UFS_NIADDR; i++) {
325f1333577Sdholland 		sizepb *= FFS_NINDIR(&sblock);
3266325773eSlukem 		sblock.fs_maxfilesize += sizepb;
3276325773eSlukem 	}
32842614ed3Sfvdl 
3296325773eSlukem 	/*
33042614ed3Sfvdl 	 * Calculate the number of blocks to put into each cylinder group.
33142614ed3Sfvdl 	 *
33242614ed3Sfvdl 	 * This algorithm selects the number of blocks per cylinder
33342614ed3Sfvdl 	 * group. The first goal is to have at least enough data blocks
33442614ed3Sfvdl 	 * in each cylinder group to meet the density requirement. Once
33542614ed3Sfvdl 	 * this goal is achieved we try to expand to have at least
33642614ed3Sfvdl 	 * 1 cylinder group. Once this goal is achieved, we pack as
33742614ed3Sfvdl 	 * many blocks into each cylinder group map as will fit.
33842614ed3Sfvdl 	 *
33942614ed3Sfvdl 	 * We start by calculating the smallest number of blocks that we
34042614ed3Sfvdl 	 * can put into each cylinder group. If this is too big, we reduce
34142614ed3Sfvdl 	 * the density until it fits.
3426325773eSlukem 	 */
34342614ed3Sfvdl 	origdensity = density;
34442614ed3Sfvdl 	for (;;) {
345e1610ba4Sdholland 		fragsperinode = MAX(ffs_numfrags(&sblock, density), 1);
346f1333577Sdholland 		minfpg = fragsperinode * FFS_INOPB(&sblock);
34742614ed3Sfvdl 		if (minfpg > sblock.fs_size)
34842614ed3Sfvdl 			minfpg = sblock.fs_size;
349f1333577Sdholland 		sblock.fs_ipg = FFS_INOPB(&sblock);
35042614ed3Sfvdl 		sblock.fs_fpg = roundup(sblock.fs_iblkno +
351f1333577Sdholland 		    sblock.fs_ipg / FFS_INOPF(&sblock), sblock.fs_frag);
35242614ed3Sfvdl 		if (sblock.fs_fpg < minfpg)
35342614ed3Sfvdl 			sblock.fs_fpg = minfpg;
35442614ed3Sfvdl 		sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
355f1333577Sdholland 		    FFS_INOPB(&sblock));
35642614ed3Sfvdl 		sblock.fs_fpg = roundup(sblock.fs_iblkno +
357f1333577Sdholland 		    sblock.fs_ipg / FFS_INOPF(&sblock), sblock.fs_frag);
35842614ed3Sfvdl 		if (sblock.fs_fpg < minfpg)
35942614ed3Sfvdl 			sblock.fs_fpg = minfpg;
36042614ed3Sfvdl 		sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
361f1333577Sdholland 		    FFS_INOPB(&sblock));
36242614ed3Sfvdl 		if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize)
36342614ed3Sfvdl 			break;
36442614ed3Sfvdl 		density -= sblock.fs_fsize;
3656325773eSlukem 	}
36642614ed3Sfvdl 	if (density != origdensity)
36742614ed3Sfvdl 		printf("density reduced from %d to %d\n", origdensity, density);
36842614ed3Sfvdl 
36942614ed3Sfvdl 	if (maxblkspercg <= 0 || maxblkspercg >= fssize)
37042614ed3Sfvdl 		maxblkspercg = fssize - 1;
37142614ed3Sfvdl 	/*
37242614ed3Sfvdl 	 * Start packing more blocks into the cylinder group until
37342614ed3Sfvdl 	 * it cannot grow any larger, the number of cylinder groups
37442614ed3Sfvdl 	 * drops below 1, or we reach the size requested.
37542614ed3Sfvdl 	 */
37642614ed3Sfvdl 	for ( ; sblock.fs_fpg < maxblkspercg; sblock.fs_fpg += sblock.fs_frag) {
37742614ed3Sfvdl 		sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
378f1333577Sdholland 		    FFS_INOPB(&sblock));
37942614ed3Sfvdl 		if (sblock.fs_size / sblock.fs_fpg < 1)
38042614ed3Sfvdl 			break;
38142614ed3Sfvdl 		if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize)
3826325773eSlukem 			continue;
38342614ed3Sfvdl 		if (CGSIZE(&sblock) == (unsigned long)sblock.fs_bsize)
3846325773eSlukem 			break;
38542614ed3Sfvdl 		sblock.fs_fpg -= sblock.fs_frag;
38642614ed3Sfvdl 		sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
387f1333577Sdholland 		    FFS_INOPB(&sblock));
3886325773eSlukem 		break;
3896325773eSlukem 	}
3906325773eSlukem 	/*
39142614ed3Sfvdl 	 * Check to be sure that the last cylinder group has enough blocks
39242614ed3Sfvdl 	 * to be viable. If it is too small, reduce the number of blocks
39342614ed3Sfvdl 	 * per cylinder group which will have the effect of moving more
39442614ed3Sfvdl 	 * blocks into the last cylinder group.
3956325773eSlukem 	 */
39642614ed3Sfvdl 	optimalfpg = sblock.fs_fpg;
39742614ed3Sfvdl 	for (;;) {
39842614ed3Sfvdl 		sblock.fs_ncg = howmany(sblock.fs_size, sblock.fs_fpg);
39942614ed3Sfvdl 		lastminfpg = roundup(sblock.fs_iblkno +
400f1333577Sdholland 		    sblock.fs_ipg / FFS_INOPF(&sblock), sblock.fs_frag);
40142614ed3Sfvdl 		if (sblock.fs_size < lastminfpg) {
40242614ed3Sfvdl 			printf("Filesystem size %lld < minimum size of %d\n",
40342614ed3Sfvdl 			    (long long)sblock.fs_size, lastminfpg);
4046325773eSlukem 			exit(28);
4056325773eSlukem 		}
40642614ed3Sfvdl 		if (sblock.fs_size % sblock.fs_fpg >= lastminfpg ||
40742614ed3Sfvdl 		    sblock.fs_size % sblock.fs_fpg == 0)
40842614ed3Sfvdl 			break;
40942614ed3Sfvdl 		sblock.fs_fpg -= sblock.fs_frag;
41042614ed3Sfvdl 		sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
411f1333577Sdholland 		    FFS_INOPB(&sblock));
4126325773eSlukem 	}
41342614ed3Sfvdl 	if (optimalfpg != sblock.fs_fpg)
41442614ed3Sfvdl 		printf("Reduced frags per cylinder group from %d to %d %s\n",
41542614ed3Sfvdl 		   optimalfpg, sblock.fs_fpg, "to enlarge last cyl group");
416e1610ba4Sdholland 	sblock.fs_cgsize = ffs_fragroundup(&sblock, CGSIZE(&sblock));
417f1333577Sdholland 	sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / FFS_INOPF(&sblock);
41842614ed3Sfvdl 	if (Oflag <= 1) {
41942614ed3Sfvdl 		sblock.fs_old_spc = sblock.fs_fpg * sblock.fs_old_nspf;
42042614ed3Sfvdl 		sblock.fs_old_nsect = sblock.fs_old_spc;
42142614ed3Sfvdl 		sblock.fs_old_npsect = sblock.fs_old_spc;
42242614ed3Sfvdl 		sblock.fs_old_ncyl = sblock.fs_ncg;
4236325773eSlukem 	}
42442614ed3Sfvdl 
4256325773eSlukem 	/*
4266325773eSlukem 	 * fill in remaining fields of the super block
4276325773eSlukem 	 */
4286325773eSlukem 	sblock.fs_csaddr = cgdmin(&sblock, 0);
4296325773eSlukem 	sblock.fs_cssize =
430e1610ba4Sdholland 	    ffs_fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum));
4316325773eSlukem 
4326325773eSlukem 	/*
4336325773eSlukem 	 * Setup memory for temporary in-core cylgroup summaries.
4346325773eSlukem 	 * Cribbed from ffs_mountfs().
4356325773eSlukem 	 */
4366325773eSlukem 	size = sblock.fs_cssize;
4376325773eSlukem 	if (sblock.fs_contigsumsize > 0)
4386325773eSlukem 		size += sblock.fs_ncg * sizeof(int32_t);
439e4989541Schristos 	space = ecalloc(1, size);
4406325773eSlukem 	sblock.fs_csp = space;
4416325773eSlukem 	space = (char *)space + sblock.fs_cssize;
4426325773eSlukem 	if (sblock.fs_contigsumsize > 0) {
4436325773eSlukem 		int32_t *lp;
4446325773eSlukem 
4456325773eSlukem 		sblock.fs_maxcluster = lp = space;
4466325773eSlukem 		for (i = 0; i < sblock.fs_ncg; i++)
4476325773eSlukem 			*lp++ = sblock.fs_contigsumsize;
4486325773eSlukem 	}
4496325773eSlukem 
450e1610ba4Sdholland 	sblock.fs_sbsize = ffs_fragroundup(&sblock, sizeof(struct fs));
45142614ed3Sfvdl 	if (sblock.fs_sbsize > SBLOCKSIZE)
45242614ed3Sfvdl 		sblock.fs_sbsize = SBLOCKSIZE;
4536325773eSlukem 	sblock.fs_minfree = minfree;
4546325773eSlukem 	sblock.fs_maxcontig = maxcontig;
4556325773eSlukem 	sblock.fs_maxbpg = maxbpg;
4566325773eSlukem 	sblock.fs_optim = opt;
4576325773eSlukem 	sblock.fs_cgrotor = 0;
45842614ed3Sfvdl 	sblock.fs_pendingblocks = 0;
45942614ed3Sfvdl 	sblock.fs_pendinginodes = 0;
4606325773eSlukem 	sblock.fs_cstotal.cs_ndir = 0;
4616325773eSlukem 	sblock.fs_cstotal.cs_nbfree = 0;
4626325773eSlukem 	sblock.fs_cstotal.cs_nifree = 0;
4636325773eSlukem 	sblock.fs_cstotal.cs_nffree = 0;
4646325773eSlukem 	sblock.fs_fmod = 0;
46542614ed3Sfvdl 	sblock.fs_ronly = 0;
46642614ed3Sfvdl 	sblock.fs_state = 0;
4676325773eSlukem 	sblock.fs_clean = FS_ISCLEAN;
4686325773eSlukem 	sblock.fs_ronly = 0;
469911dc957Schristos 	sblock.fs_id[0] = tstamp;
470bd84ee9cSfvdl 	sblock.fs_id[1] = random();
47142614ed3Sfvdl 	sblock.fs_fsmnt[0] = '\0';
47242614ed3Sfvdl 	csfrags = howmany(sblock.fs_cssize, sblock.fs_fsize);
47342614ed3Sfvdl 	sblock.fs_dsize = sblock.fs_size - sblock.fs_sblkno -
47442614ed3Sfvdl 	    sblock.fs_ncg * (sblock.fs_dblkno - sblock.fs_sblkno);
47542614ed3Sfvdl 	sblock.fs_cstotal.cs_nbfree =
47675571afdSdholland 	    ffs_fragstoblks(&sblock, sblock.fs_dsize) -
47742614ed3Sfvdl 	    howmany(csfrags, sblock.fs_frag);
47842614ed3Sfvdl 	sblock.fs_cstotal.cs_nffree =
47975571afdSdholland 	    ffs_fragnum(&sblock, sblock.fs_size) +
48075571afdSdholland 	    (ffs_fragnum(&sblock, csfrags) > 0 ?
48175571afdSdholland 	    sblock.fs_frag - ffs_fragnum(&sblock, csfrags) : 0);
482dcd34a91Sdholland 	sblock.fs_cstotal.cs_nifree = sblock.fs_ncg * sblock.fs_ipg - UFS_ROOTINO;
48342614ed3Sfvdl 	sblock.fs_cstotal.cs_ndir = 0;
48442614ed3Sfvdl 	sblock.fs_dsize -= csfrags;
485911dc957Schristos 	sblock.fs_time = tstamp;
48642614ed3Sfvdl 	if (Oflag <= 1) {
487911dc957Schristos 		sblock.fs_old_time = tstamp;
48842614ed3Sfvdl 		sblock.fs_old_dsize = sblock.fs_dsize;
48942614ed3Sfvdl 		sblock.fs_old_csaddr = sblock.fs_csaddr;
49042614ed3Sfvdl 		sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir;
49142614ed3Sfvdl 		sblock.fs_old_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree;
49242614ed3Sfvdl 		sblock.fs_old_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree;
49342614ed3Sfvdl 		sblock.fs_old_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree;
49442614ed3Sfvdl 	}
4956325773eSlukem 	/*
4966325773eSlukem 	 * Dump out summary information about file system.
4976325773eSlukem 	 */
4986325773eSlukem #define	B2MBFACTOR (1 / (1024.0 * 1024.0))
49942614ed3Sfvdl 	printf("%s: %.1fMB (%lld sectors) block size %d, "
50042614ed3Sfvdl 	       "fragment size %d\n",
50142614ed3Sfvdl 	    fsys, (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR,
5022737439dSdholland 	    (long long)FFS_FSBTODB(&sblock, sblock.fs_size),
50342614ed3Sfvdl 	    sblock.fs_bsize, sblock.fs_fsize);
50442614ed3Sfvdl 	printf("\tusing %d cylinder groups of %.2fMB, %d blks, "
50542614ed3Sfvdl 	       "%d inodes.\n",
50642614ed3Sfvdl 	    sblock.fs_ncg,
5076325773eSlukem 	    (float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR,
50842614ed3Sfvdl 	    sblock.fs_fpg / sblock.fs_frag, sblock.fs_ipg);
5096325773eSlukem #undef B2MBFACTOR
5106325773eSlukem 	/*
5116325773eSlukem 	 * Now determine how wide each column will be, and calculate how
5126325773eSlukem 	 * many columns will fit in a 76 char line. 76 is the width of the
5136325773eSlukem 	 * subwindows in sysinst.
5146325773eSlukem 	 */
5156325773eSlukem 	printcolwidth = count_digits(
5162737439dSdholland 			FFS_FSBTODB(&sblock, cgsblock(&sblock, sblock.fs_ncg -1)));
5176325773eSlukem 	nprintcols = 76 / (printcolwidth + 2);
51842614ed3Sfvdl 
5196325773eSlukem 	/*
52042614ed3Sfvdl 	 * allocate space for superblock, cylinder group map, and
52142614ed3Sfvdl 	 * two sets of inode blocks.
5226325773eSlukem 	 */
52342614ed3Sfvdl 	if (sblock.fs_bsize < SBLOCKSIZE)
52442614ed3Sfvdl 		iobufsize = SBLOCKSIZE + 3 * sblock.fs_bsize;
52542614ed3Sfvdl 	else
52642614ed3Sfvdl 		iobufsize = 4 * sblock.fs_bsize;
527e4989541Schristos 	iobuf = ecalloc(1, iobufsize);
52842614ed3Sfvdl 	/*
52942614ed3Sfvdl 	 * Make a copy of the superblock into the buffer that we will be
53042614ed3Sfvdl 	 * writing out in each cylinder group.
53142614ed3Sfvdl 	 */
532db38a065Schristos 	ffs_sb_copy(&wb.fs, &sblock, sbsize, fsopts);
53342614ed3Sfvdl 	memcpy(iobuf, writebuf, SBLOCKSIZE);
53442614ed3Sfvdl 
5356325773eSlukem 	printf("super-block backups (for fsck -b #) at:");
5366325773eSlukem 	for (cylno = 0; cylno < sblock.fs_ncg; cylno++) {
537911dc957Schristos 		initcg(cylno, tstamp, fsopts);
5386325773eSlukem 		if (cylno % nprintcols == 0)
5396325773eSlukem 			printf("\n");
540a3ff3a30Sfvdl 		printf(" %*lld,", printcolwidth,
5412737439dSdholland 			(long long)FFS_FSBTODB(&sblock, cgsblock(&sblock, cylno)));
5426325773eSlukem 		fflush(stdout);
5436325773eSlukem 	}
5446325773eSlukem 	printf("\n");
5456325773eSlukem 
5466325773eSlukem 	/*
5476325773eSlukem 	 * Now construct the initial file system,
5486325773eSlukem 	 * then write out the super-block.
5496325773eSlukem 	 */
550911dc957Schristos 	sblock.fs_time = tstamp;
55142614ed3Sfvdl 	if (Oflag <= 1) {
55242614ed3Sfvdl 		sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir;
55342614ed3Sfvdl 		sblock.fs_old_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree;
55442614ed3Sfvdl 		sblock.fs_old_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree;
55542614ed3Sfvdl 		sblock.fs_old_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree;
55642614ed3Sfvdl 	}
5576325773eSlukem 	if (fsopts->needswap)
5586325773eSlukem 		sblock.fs_flags |= FS_SWAPPED;
5596325773eSlukem 	ffs_write_superblock(&sblock, fsopts);
5606325773eSlukem 	return (&sblock);
5616325773eSlukem }
5626325773eSlukem 
5636325773eSlukem /*
5646325773eSlukem  * Write out the superblock and its duplicates,
5656325773eSlukem  * and the cylinder group summaries
5666325773eSlukem  */
5676325773eSlukem void
ffs_write_superblock(struct fs * fs,const fsinfo_t * fsopts)5686325773eSlukem ffs_write_superblock(struct fs *fs, const fsinfo_t *fsopts)
5696325773eSlukem {
570*f298a94bSchs 	int size, blks, i, saveflag;
571*f298a94bSchs 	uint32_t cylno;
5726325773eSlukem 	void *space;
5736325773eSlukem 	char *wrbuf;
5746325773eSlukem 
5756325773eSlukem 	saveflag = fs->fs_flags & FS_INTERNAL;
5766325773eSlukem 	fs->fs_flags &= ~FS_INTERNAL;
5776325773eSlukem 
578db38a065Schristos 	ffs_sb_copy(&wb.fs, &sblock, sbsize, fsopts);
57942614ed3Sfvdl 	ffs_wtfs(fs->fs_sblockloc / sectorsize, sbsize, writebuf, fsopts);
5806325773eSlukem 
5816325773eSlukem 	/* Write out the duplicate super blocks */
58242614ed3Sfvdl 	for (cylno = 0; cylno < fs->fs_ncg; cylno++)
5832737439dSdholland 		ffs_wtfs(FFS_FSBTODB(fs, cgsblock(fs, cylno)),
5846325773eSlukem 		    sbsize, writebuf, fsopts);
5856325773eSlukem 
5866325773eSlukem 	/* Write out the cylinder group summaries */
5876325773eSlukem 	size = fs->fs_cssize;
5886325773eSlukem 	blks = howmany(size, fs->fs_fsize);
5896325773eSlukem 	space = (void *)fs->fs_csp;
590e4989541Schristos 	wrbuf = emalloc(size);
5916325773eSlukem 	for (i = 0; i < blks; i+= fs->fs_frag) {
5926325773eSlukem 		size = fs->fs_bsize;
5936325773eSlukem 		if (i + fs->fs_frag > blks)
5946325773eSlukem 			size = (blks - i) * fs->fs_fsize;
5956325773eSlukem 		if (fsopts->needswap)
5966325773eSlukem 			ffs_csum_swap((struct csum *)space,
5976325773eSlukem 			    (struct csum *)wrbuf, size);
5986325773eSlukem 		else
5996325773eSlukem 			memcpy(wrbuf, space, (u_int)size);
6002737439dSdholland 		ffs_wtfs(FFS_FSBTODB(fs, fs->fs_csaddr + i), size, wrbuf, fsopts);
6016325773eSlukem 		space = (char *)space + size;
6026325773eSlukem 	}
6036325773eSlukem 	free(wrbuf);
6046325773eSlukem 	fs->fs_flags |= saveflag;
6056325773eSlukem }
6066325773eSlukem 
6076325773eSlukem /*
6086325773eSlukem  * Initialize a cylinder group.
6096325773eSlukem  */
6106325773eSlukem static void
initcg(uint32_t cylno,time_t utime,const fsinfo_t * fsopts)611*f298a94bSchs initcg(uint32_t cylno, time_t utime, const fsinfo_t *fsopts)
6126325773eSlukem {
61342614ed3Sfvdl 	daddr_t cbase, dmax;
614*f298a94bSchs 	uint32_t i, j, d, dlower, dupper, blkno;
61542614ed3Sfvdl 	struct ufs1_dinode *dp1;
61642614ed3Sfvdl 	struct ufs2_dinode *dp2;
61742614ed3Sfvdl 	int start;
6186325773eSlukem 
6196325773eSlukem 	/*
6206325773eSlukem 	 * Determine block bounds for cylinder group.
6216325773eSlukem 	 * Allow space for super block summary information in first
6226325773eSlukem 	 * cylinder group.
6236325773eSlukem 	 */
6246325773eSlukem 	cbase = cgbase(&sblock, cylno);
6256325773eSlukem 	dmax = cbase + sblock.fs_fpg;
6266325773eSlukem 	if (dmax > sblock.fs_size)
6276325773eSlukem 		dmax = sblock.fs_size;
6286325773eSlukem 	dlower = cgsblock(&sblock, cylno) - cbase;
6296325773eSlukem 	dupper = cgdmin(&sblock, cylno) - cbase;
6306325773eSlukem 	if (cylno == 0)
6316325773eSlukem 		dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
6326325773eSlukem 	memset(&acg, 0, sblock.fs_cgsize);
6336325773eSlukem 	acg.cg_time = utime;
6346325773eSlukem 	acg.cg_magic = CG_MAGIC;
6356325773eSlukem 	acg.cg_cgx = cylno;
6366325773eSlukem 	acg.cg_niblk = sblock.fs_ipg;
637f1333577Sdholland 	acg.cg_initediblk = sblock.fs_ipg < 2 * FFS_INOPB(&sblock) ?
638f1333577Sdholland 	    sblock.fs_ipg : 2 * FFS_INOPB(&sblock);
6396325773eSlukem 	acg.cg_ndblk = dmax - cbase;
6406325773eSlukem 	if (sblock.fs_contigsumsize > 0)
64142614ed3Sfvdl 		acg.cg_nclusterblks = acg.cg_ndblk >> sblock.fs_fragshift;
64242614ed3Sfvdl 	start = &acg.cg_space[0] - (u_char *)(&acg.cg_firstfield);
64342614ed3Sfvdl 	if (Oflag == 2) {
64442614ed3Sfvdl 		acg.cg_iusedoff = start;
64542614ed3Sfvdl 	} else {
64642614ed3Sfvdl 		if (cylno == sblock.fs_ncg - 1)
64742614ed3Sfvdl 			acg.cg_old_ncyl = howmany(acg.cg_ndblk,
64842614ed3Sfvdl 			    sblock.fs_fpg / sblock.fs_old_cpg);
64942614ed3Sfvdl 		else
65042614ed3Sfvdl 			acg.cg_old_ncyl = sblock.fs_old_cpg;
65142614ed3Sfvdl 		acg.cg_old_time = acg.cg_time;
65242614ed3Sfvdl 		acg.cg_time = 0;
65342614ed3Sfvdl 		acg.cg_old_niblk = acg.cg_niblk;
65442614ed3Sfvdl 		acg.cg_niblk = 0;
65542614ed3Sfvdl 		acg.cg_initediblk = 0;
65642614ed3Sfvdl 		acg.cg_old_btotoff = start;
65742614ed3Sfvdl 		acg.cg_old_boff = acg.cg_old_btotoff +
65842614ed3Sfvdl 		    sblock.fs_old_cpg * sizeof(int32_t);
65942614ed3Sfvdl 		acg.cg_iusedoff = acg.cg_old_boff +
66042614ed3Sfvdl 		    sblock.fs_old_cpg * sizeof(u_int16_t);
66142614ed3Sfvdl 	}
66242614ed3Sfvdl 	acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT);
6636325773eSlukem 	if (sblock.fs_contigsumsize <= 0) {
6646325773eSlukem 		acg.cg_nextfreeoff = acg.cg_freeoff +
66542614ed3Sfvdl 		   howmany(sblock.fs_fpg, CHAR_BIT);
6666325773eSlukem 	} else {
66742614ed3Sfvdl 		acg.cg_clustersumoff = acg.cg_freeoff +
66842614ed3Sfvdl 		    howmany(sblock.fs_fpg, CHAR_BIT) - sizeof(int32_t);
6696325773eSlukem 		acg.cg_clustersumoff =
6706325773eSlukem 		    roundup(acg.cg_clustersumoff, sizeof(int32_t));
6716325773eSlukem 		acg.cg_clusteroff = acg.cg_clustersumoff +
6726325773eSlukem 		    (sblock.fs_contigsumsize + 1) * sizeof(int32_t);
67342614ed3Sfvdl 		acg.cg_nextfreeoff = acg.cg_clusteroff +
67475571afdSdholland 		    howmany(ffs_fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT);
6756325773eSlukem 	}
676*f298a94bSchs 	if (acg.cg_nextfreeoff > (unsigned)sblock.fs_cgsize) {
6776325773eSlukem 		printf("Panic: cylinder group too big\n");
6786325773eSlukem 		exit(37);
6796325773eSlukem 	}
6806325773eSlukem 	acg.cg_cs.cs_nifree += sblock.fs_ipg;
6810a7a01f2Sdholland 	if (cylno == 0) {
6820a7a01f2Sdholland 		size_t r;
6830a7a01f2Sdholland 
684dcd34a91Sdholland 		for (r = 0; r < UFS_ROOTINO; r++) {
685b825b96bSchristos 			setbit(cg_inosused(&acg, 0), r);
6866325773eSlukem 			acg.cg_cs.cs_nifree--;
6876325773eSlukem 		}
6880a7a01f2Sdholland 	}
6896325773eSlukem 	if (cylno > 0) {
6906325773eSlukem 		/*
6916325773eSlukem 		 * In cylno 0, beginning space is reserved
6926325773eSlukem 		 * for boot and super blocks.
6936325773eSlukem 		 */
69442614ed3Sfvdl 		for (d = 0, blkno = 0; d < dlower;) {
6956325773eSlukem 			ffs_setblock(&sblock, cg_blksfree(&acg, 0), blkno);
6966325773eSlukem 			if (sblock.fs_contigsumsize > 0)
6976325773eSlukem 				setbit(cg_clustersfree(&acg, 0), blkno);
6986325773eSlukem 			acg.cg_cs.cs_nbfree++;
69942614ed3Sfvdl 			d += sblock.fs_frag;
70042614ed3Sfvdl 			blkno++;
7016325773eSlukem 		}
7026325773eSlukem 	}
70342614ed3Sfvdl 	if ((i = (dupper & (sblock.fs_frag - 1))) != 0) {
7046325773eSlukem 		acg.cg_frsum[sblock.fs_frag - i]++;
7056325773eSlukem 		for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) {
7066325773eSlukem 			setbit(cg_blksfree(&acg, 0), dupper);
7076325773eSlukem 			acg.cg_cs.cs_nffree++;
7086325773eSlukem 		}
7096325773eSlukem 	}
71042614ed3Sfvdl 	for (d = dupper, blkno = dupper >> sblock.fs_fragshift;
71142614ed3Sfvdl 	     d + sblock.fs_frag <= acg.cg_ndblk; ) {
7126325773eSlukem 		ffs_setblock(&sblock, cg_blksfree(&acg, 0), blkno);
7136325773eSlukem 		if (sblock.fs_contigsumsize > 0)
7146325773eSlukem 			setbit(cg_clustersfree(&acg, 0), blkno);
7156325773eSlukem 		acg.cg_cs.cs_nbfree++;
7166325773eSlukem 		d += sblock.fs_frag;
71742614ed3Sfvdl 		blkno++;
7186325773eSlukem 	}
71942614ed3Sfvdl 	if (d < acg.cg_ndblk) {
72042614ed3Sfvdl 		acg.cg_frsum[acg.cg_ndblk - d]++;
72142614ed3Sfvdl 		for (; d < acg.cg_ndblk; d++) {
7226325773eSlukem 			setbit(cg_blksfree(&acg, 0), d);
7236325773eSlukem 			acg.cg_cs.cs_nffree++;
7246325773eSlukem 		}
7256325773eSlukem 	}
7266325773eSlukem 	if (sblock.fs_contigsumsize > 0) {
7276325773eSlukem 		int32_t *sump = cg_clustersum(&acg, 0);
7286325773eSlukem 		u_char *mapp = cg_clustersfree(&acg, 0);
7296325773eSlukem 		int map = *mapp++;
7306325773eSlukem 		int bit = 1;
7316325773eSlukem 		int run = 0;
7326325773eSlukem 
7336325773eSlukem 		for (i = 0; i < acg.cg_nclusterblks; i++) {
7346325773eSlukem 			if ((map & bit) != 0) {
7356325773eSlukem 				run++;
7366325773eSlukem 			} else if (run != 0) {
7376325773eSlukem 				if (run > sblock.fs_contigsumsize)
7386325773eSlukem 					run = sblock.fs_contigsumsize;
7396325773eSlukem 				sump[run]++;
7406325773eSlukem 				run = 0;
7416325773eSlukem 			}
74242614ed3Sfvdl 			if ((i & (CHAR_BIT - 1)) != (CHAR_BIT - 1)) {
7436325773eSlukem 				bit <<= 1;
7446325773eSlukem 			} else {
7456325773eSlukem 				map = *mapp++;
7466325773eSlukem 				bit = 1;
7476325773eSlukem 			}
7486325773eSlukem 		}
7496325773eSlukem 		if (run != 0) {
7506325773eSlukem 			if (run > sblock.fs_contigsumsize)
7516325773eSlukem 				run = sblock.fs_contigsumsize;
7526325773eSlukem 			sump[run]++;
7536325773eSlukem 		}
7546325773eSlukem 	}
7556325773eSlukem 	sblock.fs_cs(&sblock, cylno) = acg.cg_cs;
75642614ed3Sfvdl 	/*
75742614ed3Sfvdl 	 * Write out the duplicate super block, the cylinder group map
75842614ed3Sfvdl 	 * and two blocks worth of inodes in a single write.
75942614ed3Sfvdl 	 */
76042614ed3Sfvdl 	start = sblock.fs_bsize > SBLOCKSIZE ? sblock.fs_bsize : SBLOCKSIZE;
76142614ed3Sfvdl 	memcpy(&iobuf[start], &acg, sblock.fs_cgsize);
7626325773eSlukem 	if (fsopts->needswap)
76342614ed3Sfvdl 		ffs_cg_swap(&acg, (struct cg*)&iobuf[start], &sblock);
76442614ed3Sfvdl 	start += sblock.fs_bsize;
76542614ed3Sfvdl 	dp1 = (struct ufs1_dinode *)(&iobuf[start]);
76642614ed3Sfvdl 	dp2 = (struct ufs2_dinode *)(&iobuf[start]);
76742614ed3Sfvdl 	for (i = 0; i < acg.cg_initediblk; i++) {
76842614ed3Sfvdl 		if (sblock.fs_magic == FS_UFS1_MAGIC) {
76942614ed3Sfvdl 			/* No need to swap, it'll stay random */
770bd84ee9cSfvdl 			dp1->di_gen = random();
77142614ed3Sfvdl 			dp1++;
77242614ed3Sfvdl 		} else {
773bd84ee9cSfvdl 			dp2->di_gen = random();
77442614ed3Sfvdl 			dp2++;
7756325773eSlukem 		}
77642614ed3Sfvdl 	}
7772737439dSdholland 	ffs_wtfs(FFS_FSBTODB(&sblock, cgsblock(&sblock, cylno)), iobufsize, iobuf,
77842614ed3Sfvdl 	    fsopts);
7796325773eSlukem 	/*
78042614ed3Sfvdl 	 * For the old file system, we have to initialize all the inodes.
7816325773eSlukem 	 */
78242614ed3Sfvdl 	if (Oflag <= 1) {
78342614ed3Sfvdl 		for (i = 2 * sblock.fs_frag;
784f1333577Sdholland 		     i < sblock.fs_ipg / FFS_INOPF(&sblock);
78542614ed3Sfvdl 		     i += sblock.fs_frag) {
78642614ed3Sfvdl 			dp1 = (struct ufs1_dinode *)(&iobuf[start]);
787f1333577Sdholland 			for (j = 0; j < FFS_INOPB(&sblock); j++) {
788bd84ee9cSfvdl 				dp1->di_gen = random();
78942614ed3Sfvdl 				dp1++;
7906325773eSlukem 			}
7912737439dSdholland 			ffs_wtfs(FFS_FSBTODB(&sblock, cgimin(&sblock, cylno) + i),
79242614ed3Sfvdl 			    sblock.fs_bsize, &iobuf[start], fsopts);
7936325773eSlukem 		}
7946325773eSlukem 	}
79542614ed3Sfvdl }
7966325773eSlukem 
7976325773eSlukem /*
7986325773eSlukem  * read a block from the file system
7996325773eSlukem  */
8006325773eSlukem void
ffs_rdfs(daddr_t bno,int size,void * bf,const fsinfo_t * fsopts)8016325773eSlukem ffs_rdfs(daddr_t bno, int size, void *bf, const fsinfo_t *fsopts)
8026325773eSlukem {
8036325773eSlukem 	int n;
8046325773eSlukem 	off_t offset;
8056325773eSlukem 
8062c701485Smlelstv 	offset = bno * (off_t)fsopts->sectorsize + fsopts->offset;
8076325773eSlukem 	if (lseek(fsopts->fd, offset, SEEK_SET) < 0)
8086125bf59Schristos 		err(EXIT_FAILURE, "%s: seek error for sector %lld", __func__,
809c5e90147Schristos 		    (long long)bno);
8106325773eSlukem 	n = read(fsopts->fd, bf, size);
81142614ed3Sfvdl 	if (n == -1) {
8126125bf59Schristos 		err(EXIT_FAILURE, "%s: read error bno %lld size %d", __func__,
813c5e90147Schristos 		    (long long)bno, size);
81442614ed3Sfvdl 	}
8156325773eSlukem 	else if (n != size)
8166125bf59Schristos 		errx(EXIT_FAILURE, "%s: short read error for sector %lld", __func__,
817c5e90147Schristos 		    (long long)bno);
8186325773eSlukem }
8196325773eSlukem 
8206325773eSlukem /*
8216325773eSlukem  * write a block to the file system
8226325773eSlukem  */
8236325773eSlukem void
ffs_wtfs(daddr_t bno,int size,void * bf,const fsinfo_t * fsopts)8246325773eSlukem ffs_wtfs(daddr_t bno, int size, void *bf, const fsinfo_t *fsopts)
8256325773eSlukem {
8266325773eSlukem 	int n;
8276325773eSlukem 	off_t offset;
8286325773eSlukem 
8292c701485Smlelstv 	offset = bno * (off_t)fsopts->sectorsize + fsopts->offset;
830c5e90147Schristos 	if (lseek(fsopts->fd, offset, SEEK_SET) == -1)
8311083ca28Skre 		err(EXIT_FAILURE, "%s: seek error @%jd for sector %jd",
8321083ca28Skre 		    __func__, (intmax_t)offset, (intmax_t)bno);
8336325773eSlukem 	n = write(fsopts->fd, bf, size);
8346325773eSlukem 	if (n == -1)
835bc2a9073Schristos 		err(EXIT_FAILURE, "%s: write error for sector %jd", __func__,
836bc2a9073Schristos 		    (intmax_t)bno);
8376325773eSlukem 	else if (n != size)
838bc2a9073Schristos 		errx(EXIT_FAILURE, "%s: short write error for sector %jd",
839bc2a9073Schristos 		    __func__, (intmax_t)bno);
8406325773eSlukem }
8416325773eSlukem 
8426325773eSlukem 
8436325773eSlukem /* Determine how many digits are needed to print a given integer */
8446325773eSlukem static int
count_digits(int num)8456325773eSlukem count_digits(int num)
8466325773eSlukem {
8476325773eSlukem 	int ndig;
8486325773eSlukem 
8496325773eSlukem 	for(ndig = 1; num > 9; num /=10, ndig++);
8506325773eSlukem 
8516325773eSlukem 	return (ndig);
8526325773eSlukem }
85342614ed3Sfvdl 
85442614ed3Sfvdl static int
ilog2(int val)85542614ed3Sfvdl ilog2(int val)
85642614ed3Sfvdl {
85742614ed3Sfvdl 	u_int n;
85842614ed3Sfvdl 
85942614ed3Sfvdl 	for (n = 0; n < sizeof(n) * CHAR_BIT; n++)
86042614ed3Sfvdl 		if (1 << n == val)
86142614ed3Sfvdl 			return (n);
8626125bf59Schristos 	errx(EXIT_FAILURE, "%s: %d is not a power of 2", __func__, val);
86342614ed3Sfvdl }
864