1198892Srdivacky/* $NetBSD: mkfs.c,v 1.20 2004/06/24 22:30:13 lukem Exp $ */ 2198892Srdivacky 3198892Srdivacky/* 4198892Srdivacky * Copyright (c) 2002 Networks Associates Technology, Inc. 5198892Srdivacky * All rights reserved. 6198892Srdivacky * 7198892Srdivacky * This software was developed for the FreeBSD Project by Marshall 8198892Srdivacky * Kirk McKusick and Network Associates Laboratories, the Security 9198892Srdivacky * Research Division of Network Associates, Inc. under DARPA/SPAWAR 10198892Srdivacky * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS 11249423Sdim * research program 12198892Srdivacky * 13198892Srdivacky * Copyright (c) 1980, 1989, 1993 14198892Srdivacky * The Regents of the University of California. All rights reserved. 15239462Sdim * 16249423Sdim * Redistribution and use in source and binary forms, with or without 17249423Sdim * modification, are permitted provided that the following conditions 18239462Sdim * are met: 19199481Srdivacky * 1. Redistributions of source code must retain the above copyright 20249423Sdim * notice, this list of conditions and the following disclaimer. 21249423Sdim * 2. Redistributions in binary form must reproduce the above copyright 22249423Sdim * notice, this list of conditions and the following disclaimer in the 23249423Sdim * documentation and/or other materials provided with the distribution. 24249423Sdim * 3. Neither the name of the University nor the names of its contributors 25249423Sdim * may be used to endorse or promote products derived from this software 26239462Sdim * without specific prior written permission. 27239462Sdim * 28239462Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29243830Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30239462Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31198892Srdivacky * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32198892Srdivacky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33239462Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34263508Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35263508Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36263508Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37263508Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38263508Sdim * SUCH DAMAGE. 39239462Sdim */ 40263508Sdim 41239462Sdim#include <sys/cdefs.h> 42198892Srdivacky__FBSDID("$FreeBSD: releng/10.3/usr.sbin/makefs/ffs/mkfs.c 290599 2015-11-09 09:28:34Z ngie $"); 43239462Sdim 44243830Sdim#include <sys/param.h> 45239462Sdim#include <sys/time.h> 46239462Sdim#include <sys/resource.h> 47239462Sdim 48239462Sdim#include <stdio.h> 49239462Sdim#include <stdlib.h> 50239462Sdim#include <string.h> 51239462Sdim#include <unistd.h> 52239462Sdim#include <errno.h> 53239462Sdim 54243830Sdim#include "makefs.h" 55243830Sdim#include "ffs.h" 56263508Sdim 57243830Sdim#include <ufs/ufs/dinode.h> 58263508Sdim#include <ufs/ffs/fs.h> 59243830Sdim 60263508Sdim#include "ffs/ufs_bswap.h" 61243830Sdim#include "ffs/ufs_inode.h" 62263508Sdim#include "ffs/ffs_extern.h" 63243830Sdim#include "ffs/newfs_extern.h" 64243830Sdim 65243830Sdim#ifndef BBSIZE 66243830Sdim#define BBSIZE 8192 /* size of boot area, with label */ 67243830Sdim#endif 68243830Sdim 69263508Sdimstatic void initcg(int, time_t, const fsinfo_t *); 70239462Sdimstatic int ilog2(int); 71239462Sdim 72239462Sdimstatic int count_digits(int); 73239462Sdim 74239462Sdim/* 75239462Sdim * make file system for cylinder-group style file systems 76239462Sdim */ 77239462Sdim#define UMASK 0755 78239462Sdim#define POWEROF2(num) (((num) & ((num) - 1)) == 0) 79239462Sdim 80239462Sdimunion { 81263508Sdim struct fs fs; 82263508Sdim char pad[SBLOCKSIZE]; 83263508Sdim} fsun; 84239462Sdim#define sblock fsun.fs 85239462Sdimstruct csum *fscs; 86239462Sdim 87239462Sdimunion { 88198892Srdivacky struct cg cg; 89198892Srdivacky char pad[FFS_MAXBSIZE]; 90239462Sdim} cgun; 91239462Sdim#define acg cgun.cg 92239462Sdim 93243830Sdimchar *iobuf; 94239462Sdimint iobufsize; 95249423Sdim 96249423Sdimchar writebuf[FFS_MAXBSIZE]; 97249423Sdim 98249423Sdimstatic int Oflag; /* format as an 4.3BSD file system */ 99239462Sdimstatic int64_t fssize; /* file system size */ 100239462Sdimstatic int sectorsize; /* bytes/sector */ 101239462Sdimstatic int fsize; /* fragment size */ 102198892Srdivackystatic int bsize; /* block size */ 103243830Sdimstatic int maxbsize; /* maximum clustering */ 104243830Sdimstatic int maxblkspercg; 105243830Sdimstatic int minfree; /* free space threshold */ 106243830Sdimstatic int opt; /* optimization preference (space or time) */ 107243830Sdimstatic int density; /* number of bytes per inode */ 108243830Sdimstatic int maxcontig; /* max contiguous blocks to allocate */ 109239462Sdimstatic int maxbpg; /* maximum blocks per file in a cyl group */ 110239462Sdimstatic int bbsize; /* boot block size */ 111239462Sdimstatic int sbsize; /* superblock size */ 112243830Sdimstatic int avgfilesize; /* expected average file size */ 113239462Sdimstatic int avgfpdir; /* expected number of files per directory */ 114239462Sdim 115239462Sdimstruct fs * 116239462Sdimffs_mkfs(const char *fsys, const fsinfo_t *fsopts) 117239462Sdim{ 118239462Sdim int fragsperinode, optimalfpg, origdensity, minfpg, lastminfpg; 119198892Srdivacky int32_t cylno, i, csfrags; 120239462Sdim long long sizepb; 121263508Sdim void *space; 122239462Sdim int size, blks; 123239462Sdim int nprintcols, printcolwidth; 124239462Sdim ffs_opt_t *ffs_opts = fsopts->fs_specific; 125239462Sdim 126239462Sdim Oflag = ffs_opts->version; 127226633Sdim fssize = fsopts->size / fsopts->sectorsize; 128239462Sdim sectorsize = fsopts->sectorsize; 129239462Sdim fsize = ffs_opts->fsize; 130239462Sdim bsize = ffs_opts->bsize; 131239462Sdim maxbsize = ffs_opts->maxbsize; 132239462Sdim maxblkspercg = ffs_opts->maxblkspercg; 133239462Sdim minfree = ffs_opts->minfree; 134239462Sdim opt = ffs_opts->optimization; 135239462Sdim density = ffs_opts->density; 136239462Sdim maxcontig = ffs_opts->maxcontig; 137239462Sdim maxbpg = ffs_opts->maxbpg; 138239462Sdim avgfilesize = ffs_opts->avgfilesize; 139198892Srdivacky avgfpdir = ffs_opts->avgfpdir; 140198892Srdivacky bbsize = BBSIZE; 141239462Sdim sbsize = SBLOCKSIZE; 142239462Sdim 143249423Sdim strlcpy(sblock.fs_volname, ffs_opts->label, sizeof(sblock.fs_volname)); 144198892Srdivacky 145198892Srdivacky if (Oflag == 0) { 146239462Sdim sblock.fs_old_inodefmt = FS_42INODEFMT; 147239462Sdim sblock.fs_maxsymlinklen = 0; 148239462Sdim sblock.fs_old_flags = 0; 149239462Sdim } else { 150243830Sdim sblock.fs_old_inodefmt = FS_44INODEFMT; 151243830Sdim sblock.fs_maxsymlinklen = (Oflag == 1 ? MAXSYMLINKLEN_UFS1 : 152243830Sdim MAXSYMLINKLEN_UFS2); 153198892Srdivacky sblock.fs_old_flags = FS_FLAGS_UPDATED; 154198892Srdivacky sblock.fs_flags = 0; 155239462Sdim } 156239462Sdim /* 157243830Sdim * Validate the given file system size. 158243830Sdim * Verify that its last block can actually be accessed. 159239462Sdim * Convert to file system fragment sized units. 160239462Sdim */ 161243830Sdim if (fssize <= 0) { 162239462Sdim printf("preposterous size %lld\n", (long long)fssize); 163198892Srdivacky exit(13); 164198892Srdivacky } 165239462Sdim ffs_wtfs(fssize - 1, sectorsize, (char *)&sblock, fsopts); 166239462Sdim 167243830Sdim /* 168243830Sdim * collect and verify the filesystem density info 169243830Sdim */ 170198892Srdivacky sblock.fs_avgfilesize = avgfilesize; 171198892Srdivacky sblock.fs_avgfpdir = avgfpdir; 172239462Sdim if (sblock.fs_avgfilesize <= 0) 173239462Sdim printf("illegal expected average file size %d\n", 174243830Sdim sblock.fs_avgfilesize), exit(14); 175243830Sdim if (sblock.fs_avgfpdir <= 0) 176243830Sdim printf("illegal expected number of files per directory %d\n", 177198892Srdivacky sblock.fs_avgfpdir), exit(15); 178198892Srdivacky /* 179239462Sdim * collect and verify the block and fragment sizes 180239462Sdim */ 181243830Sdim sblock.fs_bsize = bsize; 182243830Sdim sblock.fs_fsize = fsize; 183243830Sdim if (!POWEROF2(sblock.fs_bsize)) { 184239462Sdim printf("block size must be a power of 2, not %d\n", 185239462Sdim sblock.fs_bsize); 186239462Sdim exit(16); 187239462Sdim } 188243830Sdim if (!POWEROF2(sblock.fs_fsize)) { 189243830Sdim printf("fragment size must be a power of 2, not %d\n", 190243830Sdim sblock.fs_fsize); 191239462Sdim exit(17); 192239462Sdim } 193263508Sdim if (sblock.fs_fsize < sectorsize) { 194263508Sdim printf("fragment size %d is too small, minimum is %d\n", 195263508Sdim sblock.fs_fsize, sectorsize); 196263508Sdim exit(18); 197263508Sdim } 198263508Sdim if (sblock.fs_bsize < MINBSIZE) { 199263508Sdim printf("block size %d is too small, minimum is %d\n", 200239462Sdim sblock.fs_bsize, MINBSIZE); 201239462Sdim exit(19); 202239462Sdim } 203243830Sdim if (sblock.fs_bsize > FFS_MAXBSIZE) { 204243830Sdim printf("block size %d is too large, maximum is %d\n", 205243830Sdim sblock.fs_bsize, FFS_MAXBSIZE); 206239462Sdim exit(19); 207239462Sdim } 208263508Sdim if (sblock.fs_bsize < sblock.fs_fsize) { 209243830Sdim printf("block size (%d) cannot be smaller than fragment size (%d)\n", 210199481Srdivacky sblock.fs_bsize, sblock.fs_fsize); 211198892Srdivacky exit(20); 212249423Sdim } 213198892Srdivacky 214198953Srdivacky if (maxbsize < bsize || !POWEROF2(maxbsize)) { 215243830Sdim sblock.fs_maxbsize = sblock.fs_bsize; 216263508Sdim printf("Extent size set to %d\n", sblock.fs_maxbsize); 217249423Sdim } else if (sblock.fs_maxbsize > FS_MAXCONTIG * sblock.fs_bsize) { 218198892Srdivacky sblock.fs_maxbsize = FS_MAXCONTIG * sblock.fs_bsize; 219263508Sdim printf("Extent size reduced to %d\n", sblock.fs_maxbsize); 220226633Sdim } else { 221263508Sdim sblock.fs_maxbsize = maxbsize; 222198892Srdivacky } 223210299Sed sblock.fs_maxcontig = maxcontig; 224199481Srdivacky if (sblock.fs_maxcontig < sblock.fs_maxbsize / sblock.fs_bsize) { 225210299Sed sblock.fs_maxcontig = sblock.fs_maxbsize / sblock.fs_bsize; 226249423Sdim printf("Maxcontig raised to %d\n", sblock.fs_maxbsize); 227199481Srdivacky } 228199481Srdivacky 229199481Srdivacky if (sblock.fs_maxcontig > 1) 230198892Srdivacky sblock.fs_contigsumsize = MIN(sblock.fs_maxcontig,FS_MAXCONTIG); 231249423Sdim 232198892Srdivacky sblock.fs_bmask = ~(sblock.fs_bsize - 1); 233198892Srdivacky sblock.fs_fmask = ~(sblock.fs_fsize - 1); 234249423Sdim sblock.fs_qbmask = ~sblock.fs_bmask; 235198892Srdivacky sblock.fs_qfmask = ~sblock.fs_fmask; 236198892Srdivacky for (sblock.fs_bshift = 0, i = sblock.fs_bsize; i > 1; i >>= 1) 237243830Sdim sblock.fs_bshift++; 238263508Sdim for (sblock.fs_fshift = 0, i = sblock.fs_fsize; i > 1; i >>= 1) 239243830Sdim sblock.fs_fshift++; 240243830Sdim sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize); 241263508Sdim for (sblock.fs_fragshift = 0, i = sblock.fs_frag; i > 1; i >>= 1) 242198892Srdivacky sblock.fs_fragshift++; 243249423Sdim if (sblock.fs_frag > MAXFRAG) { 244249423Sdim printf("fragment size %d is too small, " 245249423Sdim "minimum with block size %d is %d\n", 246198892Srdivacky sblock.fs_fsize, sblock.fs_bsize, 247198892Srdivacky sblock.fs_bsize / MAXFRAG); 248249423Sdim exit(21); 249198892Srdivacky } 250198892Srdivacky sblock.fs_fsbtodb = ilog2(sblock.fs_fsize / sectorsize); 251198892Srdivacky sblock.fs_size = sblock.fs_providersize = fssize = 252198953Srdivacky dbtofsb(&sblock, fssize); 253198953Srdivacky 254198953Srdivacky if (Oflag <= 1) { 255198953Srdivacky sblock.fs_magic = FS_UFS1_MAGIC; 256243830Sdim sblock.fs_sblockloc = SBLOCK_UFS1; 257243830Sdim sblock.fs_nindir = sblock.fs_bsize / sizeof(ufs1_daddr_t); 258243830Sdim sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs1_dinode); 259249423Sdim sblock.fs_maxsymlinklen = ((NDADDR + NIADDR) * 260249423Sdim sizeof (ufs1_daddr_t)); 261198953Srdivacky sblock.fs_old_inodefmt = FS_44INODEFMT; 262198953Srdivacky sblock.fs_old_cgoffset = 0; 263198892Srdivacky sblock.fs_old_cgmask = 0xffffffff; 264206083Srdivacky sblock.fs_old_size = sblock.fs_size; 265198892Srdivacky sblock.fs_old_rotdelay = 0; 266198953Srdivacky sblock.fs_old_rps = 60; 267198953Srdivacky sblock.fs_old_nspf = sblock.fs_fsize / sectorsize; 268198953Srdivacky sblock.fs_old_cpg = 1; 269198953Srdivacky sblock.fs_old_interleave = 1; 270198892Srdivacky sblock.fs_old_trackskew = 0; 271198953Srdivacky sblock.fs_old_cpc = 0; 272198953Srdivacky sblock.fs_old_postblformat = 1; 273198953Srdivacky sblock.fs_old_nrpos = 1; 274198892Srdivacky } else { 275198892Srdivacky sblock.fs_magic = FS_UFS2_MAGIC; 276198953Srdivacky sblock.fs_sblockloc = SBLOCK_UFS2; 277198892Srdivacky sblock.fs_nindir = sblock.fs_bsize / sizeof(ufs2_daddr_t); 278198892Srdivacky sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs2_dinode); 279198892Srdivacky sblock.fs_maxsymlinklen = ((NDADDR + NIADDR) * 280249423Sdim sizeof (ufs2_daddr_t)); 281198892Srdivacky } 282198892Srdivacky 283198953Srdivacky sblock.fs_sblkno = 284198953Srdivacky roundup(howmany(sblock.fs_sblockloc + SBLOCKSIZE, sblock.fs_fsize), 285198953Srdivacky sblock.fs_frag); 286198953Srdivacky sblock.fs_cblkno = (daddr_t)(sblock.fs_sblkno + 287198953Srdivacky roundup(howmany(SBLOCKSIZE, sblock.fs_fsize), sblock.fs_frag)); 288243830Sdim sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag; 289243830Sdim sblock.fs_maxfilesize = sblock.fs_bsize * NDADDR - 1; 290243830Sdim for (sizepb = sblock.fs_bsize, i = 0; i < NIADDR; i++) { 291249423Sdim sizepb *= NINDIR(&sblock); 292198892Srdivacky sblock.fs_maxfilesize += sizepb; 293198892Srdivacky } 294249423Sdim 295198892Srdivacky /* 296198892Srdivacky * Calculate the number of blocks to put into each cylinder group. 297198892Srdivacky * 298198892Srdivacky * This algorithm selects the number of blocks per cylinder 299263508Sdim * group. The first goal is to have at least enough data blocks 300243830Sdim * in each cylinder group to meet the density requirement. Once 301199481Srdivacky * this goal is achieved we try to expand to have at least 302243830Sdim * 1 cylinder group. Once this goal is achieved, we pack as 303263508Sdim * many blocks into each cylinder group map as will fit. 304198892Srdivacky * 305198892Srdivacky * We start by calculating the smallest number of blocks that we 306198892Srdivacky * can put into each cylinder group. If this is too big, we reduce 307239462Sdim * the density until it fits. 308239462Sdim */ 309243830Sdim origdensity = density; 310243830Sdim for (;;) { 311243830Sdim fragsperinode = MAX(numfrags(&sblock, density), 1); 312239462Sdim minfpg = fragsperinode * INOPB(&sblock); 313239462Sdim if (minfpg > sblock.fs_size) 314239462Sdim minfpg = sblock.fs_size; 315210299Sed sblock.fs_ipg = INOPB(&sblock); 316243830Sdim sblock.fs_fpg = roundup(sblock.fs_iblkno + 317198892Srdivacky sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); 318249423Sdim if (sblock.fs_fpg < minfpg) 319210299Sed sblock.fs_fpg = minfpg; 320198892Srdivacky sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), 321221345Sdim INOPB(&sblock)); 322210299Sed sblock.fs_fpg = roundup(sblock.fs_iblkno + 323198892Srdivacky sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); 324243830Sdim if (sblock.fs_fpg < minfpg) 325243830Sdim sblock.fs_fpg = minfpg; 326243830Sdim sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), 327221345Sdim INOPB(&sblock)); 328221345Sdim if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize) 329263508Sdim break; 330263508Sdim density -= sblock.fs_fsize; 331263508Sdim } 332263508Sdim if (density != origdensity) 333263508Sdim printf("density reduced from %d to %d\n", origdensity, density); 334263508Sdim 335263508Sdim if (maxblkspercg <= 0 || maxblkspercg >= fssize) 336263508Sdim maxblkspercg = fssize - 1; 337263508Sdim /* 338243830Sdim * Start packing more blocks into the cylinder group until 339243830Sdim * it cannot grow any larger, the number of cylinder groups 340198892Srdivacky * drops below 1, or we reach the size requested. 341249423Sdim */ 342198892Srdivacky for ( ; sblock.fs_fpg < maxblkspercg; sblock.fs_fpg += sblock.fs_frag) { 343226633Sdim sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), 344198892Srdivacky INOPB(&sblock)); 345210299Sed if (sblock.fs_size / sblock.fs_fpg < 1) 346263508Sdim break; 347210299Sed if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize) 348224145Sdim continue; 349210299Sed if (CGSIZE(&sblock) == (unsigned long)sblock.fs_bsize) 350198892Srdivacky break; 351210299Sed sblock.fs_fpg -= sblock.fs_frag; 352198892Srdivacky sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), 353239462Sdim INOPB(&sblock)); 354239462Sdim break; 355239462Sdim } 356239462Sdim /* 357239462Sdim * Check to be sure that the last cylinder group has enough blocks 358239462Sdim * to be viable. If it is too small, reduce the number of blocks 359239462Sdim * per cylinder group which will have the effect of moving more 360239462Sdim * blocks into the last cylinder group. 361239462Sdim */ 362239462Sdim optimalfpg = sblock.fs_fpg; 363239462Sdim for (;;) { 364239462Sdim sblock.fs_ncg = howmany(sblock.fs_size, sblock.fs_fpg); 365263508Sdim lastminfpg = roundup(sblock.fs_iblkno + 366243830Sdim sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); 367263508Sdim if (sblock.fs_size < lastminfpg) { 368239462Sdim printf("Filesystem size %lld < minimum size of %d\n", 369239462Sdim (long long)sblock.fs_size, lastminfpg); 370263508Sdim exit(28); 371239462Sdim } 372239462Sdim if (sblock.fs_size % sblock.fs_fpg >= lastminfpg || 373239462Sdim sblock.fs_size % sblock.fs_fpg == 0) 374239462Sdim break; 375239462Sdim sblock.fs_fpg -= sblock.fs_frag; 376239462Sdim sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), 377239462Sdim INOPB(&sblock)); 378239462Sdim } 379239462Sdim if (optimalfpg != sblock.fs_fpg) 380239462Sdim printf("Reduced frags per cylinder group from %d to %d %s\n", 381239462Sdim optimalfpg, sblock.fs_fpg, "to enlarge last cyl group"); 382239462Sdim sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock)); 383239462Sdim sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock); 384239462Sdim if (Oflag <= 1) { 385239462Sdim sblock.fs_old_spc = sblock.fs_fpg * sblock.fs_old_nspf; 386239462Sdim sblock.fs_old_nsect = sblock.fs_old_spc; 387239462Sdim sblock.fs_old_npsect = sblock.fs_old_spc; 388239462Sdim sblock.fs_old_ncyl = sblock.fs_ncg; 389239462Sdim } 390239462Sdim 391239462Sdim /* 392239462Sdim * fill in remaining fields of the super block 393239462Sdim */ 394239462Sdim sblock.fs_csaddr = cgdmin(&sblock, 0); 395239462Sdim sblock.fs_cssize = 396239462Sdim fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum)); 397263508Sdim 398243830Sdim /* 399239462Sdim * Setup memory for temporary in-core cylgroup summaries. 400239462Sdim * Cribbed from ffs_mountfs(). 401263508Sdim */ 402263508Sdim size = sblock.fs_cssize; 403239462Sdim blks = howmany(size, sblock.fs_fsize); 404239462Sdim if (sblock.fs_contigsumsize > 0) 405239462Sdim size += sblock.fs_ncg * sizeof(int32_t); 406239462Sdim if ((space = (char *)calloc(1, size)) == NULL) 407239462Sdim err(1, "memory allocation error for cg summaries"); 408239462Sdim sblock.fs_csp = space; 409251662Sdim space = (char *)space + sblock.fs_cssize; 410251662Sdim if (sblock.fs_contigsumsize > 0) { 411251662Sdim int32_t *lp; 412251662Sdim 413251662Sdim sblock.fs_maxcluster = lp = space; 414239462Sdim for (i = 0; i < sblock.fs_ncg; i++) 415243830Sdim *lp++ = sblock.fs_contigsumsize; 416251662Sdim } 417251662Sdim 418243830Sdim sblock.fs_sbsize = fragroundup(&sblock, sizeof(struct fs)); 419239462Sdim if (sblock.fs_sbsize > SBLOCKSIZE) 420239462Sdim sblock.fs_sbsize = SBLOCKSIZE; 421239462Sdim sblock.fs_minfree = minfree; 422239462Sdim sblock.fs_maxcontig = maxcontig; 423249423Sdim sblock.fs_maxbpg = maxbpg; 424249423Sdim sblock.fs_optim = opt; 425239462Sdim sblock.fs_cgrotor = 0; 426239462Sdim sblock.fs_pendingblocks = 0; 427239462Sdim sblock.fs_pendinginodes = 0; 428239462Sdim sblock.fs_cstotal.cs_ndir = 0; 429243830Sdim sblock.fs_cstotal.cs_nbfree = 0; 430239462Sdim sblock.fs_cstotal.cs_nifree = 0; 431239462Sdim sblock.fs_cstotal.cs_nffree = 0; 432251662Sdim sblock.fs_fmod = 0; 433251662Sdim sblock.fs_ronly = 0; 434243830Sdim sblock.fs_state = 0; 435239462Sdim sblock.fs_clean = FS_ISCLEAN; 436239462Sdim sblock.fs_ronly = 0; 437239462Sdim sblock.fs_id[0] = start_time.tv_sec; 438239462Sdim sblock.fs_id[1] = random(); 439239462Sdim sblock.fs_fsmnt[0] = '\0'; 440239462Sdim csfrags = howmany(sblock.fs_cssize, sblock.fs_fsize); 441239462Sdim sblock.fs_dsize = sblock.fs_size - sblock.fs_sblkno - 442239462Sdim sblock.fs_ncg * (sblock.fs_dblkno - sblock.fs_sblkno); 443239462Sdim sblock.fs_cstotal.cs_nbfree = 444239462Sdim fragstoblks(&sblock, sblock.fs_dsize) - 445263508Sdim howmany(csfrags, sblock.fs_frag); 446239462Sdim sblock.fs_cstotal.cs_nffree = 447239462Sdim fragnum(&sblock, sblock.fs_size) + 448239462Sdim (fragnum(&sblock, csfrags) > 0 ? 449239462Sdim sblock.fs_frag - fragnum(&sblock, csfrags) : 0); 450239462Sdim sblock.fs_cstotal.cs_nifree = sblock.fs_ncg * sblock.fs_ipg - ROOTINO; 451239462Sdim sblock.fs_cstotal.cs_ndir = 0; 452239462Sdim sblock.fs_dsize -= csfrags; 453239462Sdim sblock.fs_time = start_time.tv_sec; 454239462Sdim if (Oflag <= 1) { 455239462Sdim sblock.fs_old_time = start_time.tv_sec; 456239462Sdim sblock.fs_old_dsize = sblock.fs_dsize; 457239462Sdim sblock.fs_old_csaddr = sblock.fs_csaddr; 458239462Sdim sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir; 459239462Sdim sblock.fs_old_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree; 460239462Sdim sblock.fs_old_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree; 461239462Sdim sblock.fs_old_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree; 462239462Sdim } 463239462Sdim /* 464263508Sdim * Dump out summary information about file system. 465239462Sdim */ 466239462Sdim#define B2MBFACTOR (1 / (1024.0 * 1024.0)) 467239462Sdim printf("%s: %.1fMB (%lld sectors) block size %d, " 468239462Sdim "fragment size %d\n", 469243830Sdim fsys, (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR, 470243830Sdim (long long)fsbtodb(&sblock, sblock.fs_size), 471239462Sdim sblock.fs_bsize, sblock.fs_fsize); 472239462Sdim printf("\tusing %d cylinder groups of %.2fMB, %d blks, " 473239462Sdim "%d inodes.\n", 474239462Sdim sblock.fs_ncg, 475239462Sdim (float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR, 476239462Sdim sblock.fs_fpg / sblock.fs_frag, sblock.fs_ipg); 477239462Sdim#undef B2MBFACTOR 478239462Sdim /* 479239462Sdim * Now determine how wide each column will be, and calculate how 480239462Sdim * many columns will fit in a 76 char line. 76 is the width of the 481239462Sdim * subwindows in sysinst. 482239462Sdim */ 483239462Sdim printcolwidth = count_digits( 484239462Sdim fsbtodb(&sblock, cgsblock(&sblock, sblock.fs_ncg -1))); 485239462Sdim nprintcols = 76 / (printcolwidth + 2); 486239462Sdim 487239462Sdim /* 488239462Sdim * allocate space for superblock, cylinder group map, and 489239462Sdim * two sets of inode blocks. 490239462Sdim */ 491239462Sdim if (sblock.fs_bsize < SBLOCKSIZE) 492239462Sdim iobufsize = SBLOCKSIZE + 3 * sblock.fs_bsize; 493239462Sdim else 494239462Sdim iobufsize = 4 * sblock.fs_bsize; 495239462Sdim if ((iobuf = malloc(iobufsize)) == 0) { 496239462Sdim printf("Cannot allocate I/O buffer\n"); 497239462Sdim exit(38); 498239462Sdim } 499239462Sdim memset(iobuf, 0, iobufsize); 500239462Sdim /* 501239462Sdim * Make a copy of the superblock into the buffer that we will be 502239462Sdim * writing out in each cylinder group. 503239462Sdim */ 504239462Sdim memcpy(writebuf, &sblock, sbsize); 505239462Sdim if (fsopts->needswap) 506239462Sdim ffs_sb_swap(&sblock, (struct fs*)writebuf); 507239462Sdim memcpy(iobuf, writebuf, SBLOCKSIZE); 508239462Sdim 509239462Sdim printf("super-block backups (for fsck -b #) at:"); 510239462Sdim for (cylno = 0; cylno < sblock.fs_ncg; cylno++) { 511239462Sdim initcg(cylno, start_time.tv_sec, fsopts); 512239462Sdim if (cylno % nprintcols == 0) 513239462Sdim printf("\n"); 514239462Sdim printf(" %*lld,", printcolwidth, 515239462Sdim (long long)fsbtodb(&sblock, cgsblock(&sblock, cylno))); 516239462Sdim fflush(stdout); 517239462Sdim } 518239462Sdim printf("\n"); 519239462Sdim 520239462Sdim /* 521239462Sdim * Now construct the initial file system, 522239462Sdim * then write out the super-block. 523239462Sdim */ 524239462Sdim sblock.fs_time = start_time.tv_sec; 525239462Sdim if (Oflag <= 1) { 526239462Sdim sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir; 527239462Sdim sblock.fs_old_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree; 528239462Sdim sblock.fs_old_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree; 529239462Sdim sblock.fs_old_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree; 530239462Sdim } 531239462Sdim if (fsopts->needswap) 532239462Sdim sblock.fs_flags |= FS_SWAPPED; 533239462Sdim ffs_write_superblock(&sblock, fsopts); 534239462Sdim return (&sblock); 535239462Sdim} 536249423Sdim 537263508Sdim/* 538239462Sdim * Write out the superblock and its duplicates, 539239462Sdim * and the cylinder group summaries 540239462Sdim */ 541239462Sdimvoid 542239462Sdimffs_write_superblock(struct fs *fs, const fsinfo_t *fsopts) 543249423Sdim{ 544249423Sdim int cylno, size, blks, i, saveflag; 545249423Sdim void *space; 546249423Sdim char *wrbuf; 547249423Sdim 548249423Sdim saveflag = fs->fs_flags & FS_INTERNAL; 549239462Sdim fs->fs_flags &= ~FS_INTERNAL; 550239462Sdim 551239462Sdim memcpy(writebuf, &sblock, sbsize); 552239462Sdim if (fsopts->needswap) 553263508Sdim ffs_sb_swap(fs, (struct fs*)writebuf); 554239462Sdim ffs_wtfs(fs->fs_sblockloc / sectorsize, sbsize, writebuf, fsopts); 555239462Sdim 556239462Sdim /* Write out the duplicate super blocks */ 557239462Sdim for (cylno = 0; cylno < fs->fs_ncg; cylno++) 558239462Sdim ffs_wtfs(fsbtodb(fs, cgsblock(fs, cylno)), 559239462Sdim sbsize, writebuf, fsopts); 560239462Sdim 561239462Sdim /* Write out the cylinder group summaries */ 562239462Sdim size = fs->fs_cssize; 563239462Sdim blks = howmany(size, fs->fs_fsize); 564239462Sdim space = (void *)fs->fs_csp; 565239462Sdim if ((wrbuf = malloc(size)) == NULL) 566239462Sdim err(1, "ffs_write_superblock: malloc %d", size); 567251662Sdim for (i = 0; i < blks; i+= fs->fs_frag) { 568251662Sdim size = fs->fs_bsize; 569251662Sdim if (i + fs->fs_frag > blks) 570239462Sdim size = (blks - i) * fs->fs_fsize; 571239462Sdim if (fsopts->needswap) 572239462Sdim ffs_csum_swap((struct csum *)space, 573239462Sdim (struct csum *)wrbuf, size); 574239462Sdim else 575239462Sdim memcpy(wrbuf, space, (u_int)size); 576239462Sdim ffs_wtfs(fsbtodb(fs, fs->fs_csaddr + i), size, wrbuf, fsopts); 577239462Sdim space = (char *)space + size; 578239462Sdim } 579239462Sdim free(wrbuf); 580239462Sdim fs->fs_flags |= saveflag; 581239462Sdim} 582239462Sdim 583239462Sdim/* 584239462Sdim * Initialize a cylinder group. 585239462Sdim */ 586239462Sdimstatic void 587239462Sdiminitcg(int cylno, time_t utime, const fsinfo_t *fsopts) 588239462Sdim{ 589263508Sdim daddr_t cbase, dmax; 590263508Sdim int32_t i, j, d, dlower, dupper, blkno; 591263508Sdim struct ufs1_dinode *dp1; 592263508Sdim struct ufs2_dinode *dp2; 593263508Sdim int start; 594263508Sdim 595263508Sdim /* 596239462Sdim * Determine block bounds for cylinder group. 597239462Sdim * Allow space for super block summary information in first 598239462Sdim * cylinder group. 599239462Sdim */ 600239462Sdim cbase = cgbase(&sblock, cylno); 601239462Sdim dmax = cbase + sblock.fs_fpg; 602239462Sdim if (dmax > sblock.fs_size) 603239462Sdim dmax = sblock.fs_size; 604239462Sdim dlower = cgsblock(&sblock, cylno) - cbase; 605239462Sdim dupper = cgdmin(&sblock, cylno) - cbase; 606239462Sdim if (cylno == 0) 607239462Sdim dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); 608239462Sdim memset(&acg, 0, sblock.fs_cgsize); 609239462Sdim acg.cg_time = utime; 610239462Sdim acg.cg_magic = CG_MAGIC; 611239462Sdim acg.cg_cgx = cylno; 612239462Sdim acg.cg_niblk = sblock.fs_ipg; 613239462Sdim acg.cg_initediblk = sblock.fs_ipg < 2 * INOPB(&sblock) ? 614239462Sdim sblock.fs_ipg : 2 * INOPB(&sblock); 615239462Sdim acg.cg_ndblk = dmax - cbase; 616239462Sdim if (sblock.fs_contigsumsize > 0) 617239462Sdim acg.cg_nclusterblks = acg.cg_ndblk >> sblock.fs_fragshift; 618239462Sdim start = &acg.cg_space[0] - (u_char *)(&acg.cg_firstfield); 619263508Sdim if (Oflag == 2) { 620239462Sdim acg.cg_iusedoff = start; 621239462Sdim } else { 622239462Sdim if (cylno == sblock.fs_ncg - 1) 623239462Sdim acg.cg_old_ncyl = howmany(acg.cg_ndblk, 624239462Sdim sblock.fs_fpg / sblock.fs_old_cpg); 625239462Sdim else 626239462Sdim acg.cg_old_ncyl = sblock.fs_old_cpg; 627239462Sdim acg.cg_old_time = acg.cg_time; 628239462Sdim acg.cg_time = 0; 629239462Sdim acg.cg_old_niblk = acg.cg_niblk; 630239462Sdim acg.cg_niblk = 0; 631239462Sdim acg.cg_initediblk = 0; 632239462Sdim acg.cg_old_btotoff = start; 633239462Sdim acg.cg_old_boff = acg.cg_old_btotoff + 634239462Sdim sblock.fs_old_cpg * sizeof(int32_t); 635239462Sdim acg.cg_iusedoff = acg.cg_old_boff + 636239462Sdim sblock.fs_old_cpg * sizeof(u_int16_t); 637239462Sdim } 638239462Sdim acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT); 639239462Sdim if (sblock.fs_contigsumsize <= 0) { 640263508Sdim acg.cg_nextfreeoff = acg.cg_freeoff + 641263508Sdim howmany(sblock.fs_fpg, CHAR_BIT); 642263508Sdim } else { 643263508Sdim acg.cg_clustersumoff = acg.cg_freeoff + 644263508Sdim howmany(sblock.fs_fpg, CHAR_BIT) - sizeof(int32_t); 645263508Sdim acg.cg_clustersumoff = 646263508Sdim roundup(acg.cg_clustersumoff, sizeof(int32_t)); 647239462Sdim acg.cg_clusteroff = acg.cg_clustersumoff + 648239462Sdim (sblock.fs_contigsumsize + 1) * sizeof(int32_t); 649239462Sdim acg.cg_nextfreeoff = acg.cg_clusteroff + 650239462Sdim howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT); 651239462Sdim } 652239462Sdim if (acg.cg_nextfreeoff > sblock.fs_cgsize) { 653249423Sdim printf("Panic: cylinder group too big\n"); 654239462Sdim exit(37); 655239462Sdim } 656239462Sdim acg.cg_cs.cs_nifree += sblock.fs_ipg; 657239462Sdim if (cylno == 0) 658239462Sdim for (i = 0; i < ROOTINO; i++) { 659239462Sdim setbit(cg_inosused_swap(&acg, 0), i); 660239462Sdim acg.cg_cs.cs_nifree--; 661239462Sdim } 662239462Sdim if (cylno > 0) { 663239462Sdim /* 664239462Sdim * In cylno 0, beginning space is reserved 665239462Sdim * for boot and super blocks. 666239462Sdim */ 667239462Sdim for (d = 0, blkno = 0; d < dlower;) { 668239462Sdim ffs_setblock(&sblock, cg_blksfree_swap(&acg, 0), blkno); 669239462Sdim if (sblock.fs_contigsumsize > 0) 670239462Sdim setbit(cg_clustersfree_swap(&acg, 0), blkno); 671239462Sdim acg.cg_cs.cs_nbfree++; 672239462Sdim d += sblock.fs_frag; 673239462Sdim blkno++; 674239462Sdim } 675239462Sdim } 676239462Sdim if ((i = (dupper & (sblock.fs_frag - 1))) != 0) { 677239462Sdim acg.cg_frsum[sblock.fs_frag - i]++; 678239462Sdim for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) { 679263508Sdim setbit(cg_blksfree_swap(&acg, 0), dupper); 680239462Sdim acg.cg_cs.cs_nffree++; 681239462Sdim } 682239462Sdim } 683239462Sdim for (d = dupper, blkno = dupper >> sblock.fs_fragshift; 684239462Sdim d + sblock.fs_frag <= acg.cg_ndblk; ) { 685243830Sdim ffs_setblock(&sblock, cg_blksfree_swap(&acg, 0), blkno); 686243830Sdim if (sblock.fs_contigsumsize > 0) 687239462Sdim setbit(cg_clustersfree_swap(&acg, 0), blkno); 688239462Sdim acg.cg_cs.cs_nbfree++; 689239462Sdim d += sblock.fs_frag; 690239462Sdim blkno++; 691239462Sdim } 692239462Sdim if (d < acg.cg_ndblk) { 693239462Sdim acg.cg_frsum[acg.cg_ndblk - d]++; 694239462Sdim for (; d < acg.cg_ndblk; d++) { 695239462Sdim setbit(cg_blksfree_swap(&acg, 0), d); 696239462Sdim acg.cg_cs.cs_nffree++; 697239462Sdim } 698239462Sdim } 699239462Sdim if (sblock.fs_contigsumsize > 0) { 700239462Sdim int32_t *sump = cg_clustersum_swap(&acg, 0); 701239462Sdim u_char *mapp = cg_clustersfree_swap(&acg, 0); 702239462Sdim int map = *mapp++; 703239462Sdim int bit = 1; 704239462Sdim int run = 0; 705239462Sdim 706239462Sdim for (i = 0; i < acg.cg_nclusterblks; i++) { 707239462Sdim if ((map & bit) != 0) { 708239462Sdim run++; 709239462Sdim } else if (run != 0) { 710239462Sdim if (run > sblock.fs_contigsumsize) 711239462Sdim run = sblock.fs_contigsumsize; 712239462Sdim sump[run]++; 713239462Sdim run = 0; 714239462Sdim } 715239462Sdim if ((i & (CHAR_BIT - 1)) != (CHAR_BIT - 1)) { 716239462Sdim bit <<= 1; 717239462Sdim } else { 718239462Sdim map = *mapp++; 719239462Sdim bit = 1; 720239462Sdim } 721239462Sdim } 722239462Sdim if (run != 0) { 723239462Sdim if (run > sblock.fs_contigsumsize) 724239462Sdim run = sblock.fs_contigsumsize; 725239462Sdim sump[run]++; 726239462Sdim } 727239462Sdim } 728239462Sdim sblock.fs_cs(&sblock, cylno) = acg.cg_cs; 729239462Sdim /* 730239462Sdim * Write out the duplicate super block, the cylinder group map 731263508Sdim * and two blocks worth of inodes in a single write. 732239462Sdim */ 733239462Sdim start = sblock.fs_bsize > SBLOCKSIZE ? sblock.fs_bsize : SBLOCKSIZE; 734239462Sdim memcpy(&iobuf[start], &acg, sblock.fs_cgsize); 735239462Sdim if (fsopts->needswap) 736239462Sdim ffs_cg_swap(&acg, (struct cg*)&iobuf[start], &sblock); 737239462Sdim start += sblock.fs_bsize; 738239462Sdim dp1 = (struct ufs1_dinode *)(&iobuf[start]); 739239462Sdim dp2 = (struct ufs2_dinode *)(&iobuf[start]); 740239462Sdim for (i = 0; i < acg.cg_initediblk; i++) { 741239462Sdim if (sblock.fs_magic == FS_UFS1_MAGIC) { 742239462Sdim /* No need to swap, it'll stay random */ 743239462Sdim dp1->di_gen = random(); 744239462Sdim dp1++; 745239462Sdim } else { 746239462Sdim dp2->di_gen = random(); 747239462Sdim dp2++; 748239462Sdim } 749239462Sdim } 750239462Sdim ffs_wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)), iobufsize, iobuf, 751239462Sdim fsopts); 752239462Sdim /* 753239462Sdim * For the old file system, we have to initialize all the inodes. 754239462Sdim */ 755239462Sdim if (Oflag <= 1) { 756239462Sdim for (i = 2 * sblock.fs_frag; 757239462Sdim i < sblock.fs_ipg / INOPF(&sblock); 758239462Sdim i += sblock.fs_frag) { 759239462Sdim dp1 = (struct ufs1_dinode *)(&iobuf[start]); 760239462Sdim for (j = 0; j < INOPB(&sblock); j++) { 761239462Sdim dp1->di_gen = random(); 762239462Sdim dp1++; 763239462Sdim } 764239462Sdim ffs_wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i), 765239462Sdim sblock.fs_bsize, &iobuf[start], fsopts); 766239462Sdim } 767239462Sdim } 768239462Sdim} 769239462Sdim 770239462Sdim/* 771239462Sdim * read a block from the file system 772239462Sdim */ 773239462Sdimvoid 774239462Sdimffs_rdfs(daddr_t bno, int size, void *bf, const fsinfo_t *fsopts) 775239462Sdim{ 776239462Sdim int n; 777239462Sdim off_t offset; 778239462Sdim 779239462Sdim offset = bno; 780239462Sdim offset *= fsopts->sectorsize; 781239462Sdim if (lseek(fsopts->fd, offset, SEEK_SET) < 0) 782239462Sdim err(1, "ffs_rdfs: seek error for sector %lld: %s\n", 783239462Sdim (long long)bno, strerror(errno)); 784239462Sdim n = read(fsopts->fd, bf, size); 785239462Sdim if (n == -1) { 786239462Sdim abort(); 787239462Sdim err(1, "ffs_rdfs: read error bno %lld size %d", (long long)bno, 788239462Sdim size); 789239462Sdim } 790239462Sdim else if (n != size) 791239462Sdim errx(1, "ffs_rdfs: read error for sector %lld: %s\n", 792239462Sdim (long long)bno, strerror(errno)); 793239462Sdim} 794239462Sdim 795239462Sdim/* 796239462Sdim * write a block to the file system 797239462Sdim */ 798239462Sdimvoid 799239462Sdimffs_wtfs(daddr_t bno, int size, void *bf, const fsinfo_t *fsopts) 800239462Sdim{ 801239462Sdim int n; 802239462Sdim off_t offset; 803 804 offset = bno; 805 offset *= fsopts->sectorsize; 806 if (lseek(fsopts->fd, offset, SEEK_SET) < 0) 807 err(1, "wtfs: seek error for sector %lld: %s\n", 808 (long long)bno, strerror(errno)); 809 n = write(fsopts->fd, bf, size); 810 if (n == -1) 811 err(1, "wtfs: write error for sector %lld: %s\n", 812 (long long)bno, strerror(errno)); 813 else if (n != size) 814 errx(1, "wtfs: write error for sector %lld: %s\n", 815 (long long)bno, strerror(errno)); 816} 817 818 819/* Determine how many digits are needed to print a given integer */ 820static int 821count_digits(int num) 822{ 823 int ndig; 824 825 for(ndig = 1; num > 9; num /=10, ndig++); 826 827 return (ndig); 828} 829 830static int 831ilog2(int val) 832{ 833 u_int n; 834 835 for (n = 0; n < sizeof(n) * CHAR_BIT; n++) 836 if (1 << n == val) 837 return (n); 838 errx(1, "ilog2: %d is not a power of 2\n", val); 839} 840