must avoid bogus dump headers when resynchronizing
[unix-history] / usr / src / sbin / newfs / mkfs.c
CommitLineData
19538291
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
8char copyright[] =
9"@(#) Copyright (c) 1980 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
14b4eb74 13#ifndef lint
75e589fc 14static char sccsid[] = "@(#)mkfs.c 5.3 (Berkeley) %G%";
19538291 15#endif not lint
d746d022
KM
16
17/*
18 * make file system for cylinder-group style file systems
19 *
75e589fc
KM
20 * usage:
21 * mkfs -N special size [ nsect ntrak bsize fsize cpg minfree rps nbpi opt ]
d746d022
KM
22 */
23
c6ff3ebb
KM
24/*
25 * The following constants set the defaults used for the number
26 * of sectors (fs_nsect), and number of tracks (fs_ntrak).
27 */
28#define DFLNSECT 32
29#define DFLNTRAK 16
30
31/*
32 * The following two constants set the default block and fragment sizes.
33 * Both constants must be a power of 2 and meet the following constraints:
34 * MINBSIZE <= DESBLKSIZE <= MAXBSIZE
35 * DEV_BSIZE <= DESFRAGSIZE <= DESBLKSIZE
36 * DESBLKSIZE / DESFRAGSIZE <= 8
37 */
38#define DESBLKSIZE 8192
39#define DESFRAGSIZE 1024
40
41/*
42 * Cylinder groups may have up to MAXCPG cylinders. The actual
43 * number used depends upon how much information can be stored
44 * on a single cylinder. The default is to used 16 cylinders
45 * per group.
46 */
47#define DESCPG 16 /* desired fs_cpg */
48
49/*
50 * MINFREE gives the minimum acceptable percentage of file system
51 * blocks which may be free. If the freelist drops below this level
52 * only the superuser may continue to allocate blocks. This may
53 * be set to 0 if no reserve of free blocks is deemed necessary,
54 * however throughput drops by fifty percent if the file system
55 * is run at between 90% and 100% full; thus the default value of
75e589fc
KM
56 * fs_minfree is 10%. With 10% free space, fragmentation is not a
57 * problem, so we choose to optimize for time.
c6ff3ebb
KM
58 */
59#define MINFREE 10
75e589fc 60#define DEFAULTOPT FS_OPTTIME
c6ff3ebb
KM
61
62/*
63 * ROTDELAY gives the minimum number of milliseconds to initiate
64 * another disk transfer on the same cylinder. It is used in
65 * determining the rotationally optimal layout for disk blocks
66dd907b 66 * within a file; the default of fs_rotdelay is 4ms.
c6ff3ebb 67 */
66dd907b 68#define ROTDELAY 4
c6ff3ebb
KM
69
70/*
71 * MAXCONTIG sets the default for the maximum number of blocks
72 * that may be allocated sequentially. Since UNIX drivers are
73 * not capable of scheduling multi-block transfers, this defaults
74 * to 1 (ie no contiguous blocks are allocated).
75 */
76#define MAXCONTIG 1
77
78/*
79 * MAXBLKPG determines the maximum number of data blocks which are
80 * placed in a single cylinder group. This is currently a function
81 * of the block and fragment size of the file system.
82 */
83#define MAXBLKPG(fs) ((fs)->fs_fsize / sizeof(daddr_t))
84
85/*
86 * Each file system has a number of inodes statically allocated.
87 * We allocate one inode slot per NBPI bytes, expecting this
88 * to be far more than we will ever need.
89 */
90#define NBPI 2048
91
a4222b50
SL
92/*
93 * Disks are assumed to rotate at 60HZ, unless otherwise specified.
94 */
95#define DEFHZ 60
96
d746d022
KM
97#ifndef STANDALONE
98#include <stdio.h>
99#include <a.out.h>
100#endif
101
45eb394d
KM
102#include <sys/param.h>
103#include <sys/inode.h>
104#include <sys/fs.h>
14b4eb74 105#include <sys/dir.h>
d746d022 106
2fd3d252 107#define UMASK 0755
c312eebd 108#define MAXINOPB (MAXBSIZE / sizeof(struct dinode))
2fd3d252 109#define POWEROF2(num) (((num) & ((num) - 1)) == 0)
d746d022
KM
110
111union {
112 struct fs fs;
b6407c9d 113 char pad[MAXBSIZE];
d746d022
KM
114} fsun;
115#define sblock fsun.fs
116struct csum *fscs;
117
118union {
119 struct cg cg;
b6407c9d 120 char pad[MAXBSIZE];
d746d022
KM
121} cgun;
122#define acg cgun.cg
123
2fd3d252
KM
124struct dinode zino[MAXIPG];
125
d746d022 126char *fsys;
2fd3d252
KM
127time_t utime;
128int fsi;
129int fso;
56a085eb 130int Nflag;
d746d022
KM
131daddr_t alloc();
132
d746d022 133main(argc, argv)
b6407c9d
KM
134 int argc;
135 char *argv[];
d746d022 136{
bf541624 137 long cylno, rpos, blk, i, j, inos, fssize, warn = 0;
d746d022 138
d746d022 139#ifndef STANDALONE
2fd3d252 140 argc--, argv++;
56a085eb
KM
141 if (argv[0][0] == '-') {
142 switch (argv[0][1]) {
143 case 'N':
144 Nflag++;
145 break;
146 default:
147 printf("%s: unknown flag\n", &argv[0][1]);
148 argc = 1; /* force usage message */
149 break;
150 }
151 argc--, argv++;
152 }
d746d022 153 time(&utime);
2fd3d252 154 if (argc < 2) {
56a085eb 155 printf("usage: mkfs -N special size [ nsect ntrak bsize fsize cpg minfree rps nbpi ]\n");
d746d022
KM
156 exit(1);
157 }
158 fsys = argv[0];
2fd3d252 159 fssize = atoi(argv[1]);
56a085eb
KM
160 if (!Nflag) {
161 fso = creat(fsys, 0666);
162 if(fso < 0) {
163 printf("%s: cannot create\n", fsys);
164 exit(1);
165 }
2fd3d252
KM
166 }
167 fsi = open(fsys, 0);
168 if(fsi < 0) {
169 printf("%s: cannot open\n", fsys);
170 exit(1);
171 }
d746d022
KM
172#else
173 {
174 static char protos[60];
2fd3d252 175 char fsbuf[100];
d746d022
KM
176
177 printf("file sys size: ");
178 gets(protos);
2fd3d252 179 fssize = atoi(protos);
d746d022
KM
180 do {
181 printf("file system: ");
182 gets(fsbuf);
183 fso = open(fsbuf, 1);
184 fsi = open(fsbuf, 0);
185 } while (fso < 0 || fsi < 0);
186 }
d746d022 187 argc = 0;
2fd3d252 188#endif
51fe1c64
KM
189 /*
190 * Validate the given file system size.
191 * Verify that its last block can actually be accessed.
192 */
2fd3d252
KM
193 if (fssize <= 0)
194 printf("preposterous size %d\n", fssize), exit(1);
51fe1c64 195 wtfs(fssize - 1, DEV_BSIZE, (char *)&sblock);
2fd3d252
KM
196 /*
197 * collect and verify the sector and track info
198 */
199 if (argc > 2)
200 sblock.fs_nsect = atoi(argv[2]);
201 else
202 sblock.fs_nsect = DFLNSECT;
203 if (argc > 3)
204 sblock.fs_ntrak = atoi(argv[3]);
205 else
206 sblock.fs_ntrak = DFLNTRAK;
207 if (sblock.fs_ntrak <= 0)
208 printf("preposterous ntrak %d\n", sblock.fs_ntrak), exit(1);
209 if (sblock.fs_nsect <= 0)
210 printf("preposterous nsect %d\n", sblock.fs_nsect), exit(1);
211 sblock.fs_spc = sblock.fs_ntrak * sblock.fs_nsect;
212 /*
213 * collect and verify the block and fragment sizes
214 */
215 if (argc > 4)
216 sblock.fs_bsize = atoi(argv[4]);
217 else
c6ff3ebb 218 sblock.fs_bsize = DESBLKSIZE;
2fd3d252
KM
219 if (argc > 5)
220 sblock.fs_fsize = atoi(argv[5]);
221 else
c6ff3ebb 222 sblock.fs_fsize = DESFRAGSIZE;
2fd3d252
KM
223 if (!POWEROF2(sblock.fs_bsize)) {
224 printf("block size must be a power of 2, not %d\n",
225 sblock.fs_bsize);
d746d022
KM
226 exit(1);
227 }
2fd3d252
KM
228 if (!POWEROF2(sblock.fs_fsize)) {
229 printf("fragment size must be a power of 2, not %d\n",
230 sblock.fs_fsize);
d746d022
KM
231 exit(1);
232 }
b6407c9d
KM
233 if (sblock.fs_fsize < DEV_BSIZE) {
234 printf("fragment size %d is too small, minimum is %d\n",
235 sblock.fs_fsize, DEV_BSIZE);
236 exit(1);
237 }
238 if (sblock.fs_bsize < MINBSIZE) {
239 printf("block size %d is too small, minimum is %d\n",
240 sblock.fs_bsize, MINBSIZE);
241 exit(1);
242 }
2fd3d252
KM
243 if (sblock.fs_bsize < sblock.fs_fsize) {
244 printf("block size (%d) cannot be smaller than fragment size (%d)\n",
245 sblock.fs_bsize, sblock.fs_fsize);
d746d022
KM
246 exit(1);
247 }
3352e84a
KM
248 sblock.fs_bmask = ~(sblock.fs_bsize - 1);
249 sblock.fs_fmask = ~(sblock.fs_fsize - 1);
250 for (sblock.fs_bshift = 0, i = sblock.fs_bsize; i > 1; i >>= 1)
251 sblock.fs_bshift++;
252 for (sblock.fs_fshift = 0, i = sblock.fs_fsize; i > 1; i >>= 1)
253 sblock.fs_fshift++;
254 sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize);
19782540
KM
255 for (sblock.fs_fragshift = 0, i = sblock.fs_frag; i > 1; i >>= 1)
256 sblock.fs_fragshift++;
2fd3d252
KM
257 if (sblock.fs_frag > MAXFRAG) {
258 printf("fragment size %d is too small, minimum with block size %d is %d\n",
259 sblock.fs_fsize, sblock.fs_bsize,
260 sblock.fs_bsize / MAXFRAG);
261 exit(1);
d746d022 262 }
19782540
KM
263 sblock.fs_nindir = sblock.fs_bsize / sizeof(daddr_t);
264 sblock.fs_inopb = sblock.fs_bsize / sizeof(struct dinode);
265 sblock.fs_nspf = sblock.fs_fsize / DEV_BSIZE;
266 for (sblock.fs_fsbtodb = 0, i = sblock.fs_nspf; i > 1; i >>= 1)
267 sblock.fs_fsbtodb++;
bf541624 268 sblock.fs_sblkno =
aca50d72 269 roundup(howmany(BBSIZE + SBSIZE, sblock.fs_fsize), sblock.fs_frag);
bf541624
KM
270 sblock.fs_cblkno = (daddr_t)(sblock.fs_sblkno +
271 roundup(howmany(SBSIZE, sblock.fs_fsize), sblock.fs_frag));
aca50d72 272 sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag;
bf541624
KM
273 sblock.fs_cgoffset = roundup(
274 howmany(sblock.fs_nsect, sblock.fs_fsize / DEV_BSIZE),
275 sblock.fs_frag);
276 for (sblock.fs_cgmask = 0xffffffff, i = sblock.fs_ntrak; i > 1; i >>= 1)
277 sblock.fs_cgmask <<= 1;
278 if (!POWEROF2(sblock.fs_ntrak))
279 sblock.fs_cgmask <<= 1;
3aaf0f69
KM
280 for (sblock.fs_cpc = NSPB(&sblock), i = sblock.fs_spc;
281 sblock.fs_cpc > 1 && (i & 1) == 0;
282 sblock.fs_cpc >>= 1, i >>= 1)
283 /* void */;
173a62ff
KM
284 if (sblock.fs_cpc > MAXCPG) {
285 printf("maximum block size with nsect %d and ntrak %d is %d\n",
286 sblock.fs_nsect, sblock.fs_ntrak,
287 sblock.fs_bsize / (sblock.fs_cpc / MAXCPG));
288 exit(1);
289 }
2fd3d252
KM
290 /*
291 * collect and verify the number of cylinders per group
d746d022 292 */
2fd3d252
KM
293 if (argc > 6) {
294 sblock.fs_cpg = atoi(argv[6]);
295 sblock.fs_fpg = (sblock.fs_cpg * sblock.fs_spc) / NSPF(&sblock);
d746d022 296 } else {
3aaf0f69 297 sblock.fs_cpg = MAX(sblock.fs_cpc, DESCPG);
2fd3d252 298 sblock.fs_fpg = (sblock.fs_cpg * sblock.fs_spc) / NSPF(&sblock);
173a62ff
KM
299 while (sblock.fs_fpg / sblock.fs_frag > MAXBPG(&sblock) &&
300 sblock.fs_cpg > sblock.fs_cpc) {
301 sblock.fs_cpg -= sblock.fs_cpc;
2fd3d252
KM
302 sblock.fs_fpg =
303 (sblock.fs_cpg * sblock.fs_spc) / NSPF(&sblock);
304 }
305 }
306 if (sblock.fs_cpg < 1) {
307 printf("cylinder groups must have at least 1 cylinder\n");
308 exit(1);
309 }
310 if (sblock.fs_cpg > MAXCPG) {
311 printf("cylinder groups are limited to %d cylinders\n", MAXCPG);
312 exit(1);
d746d022 313 }
3aaf0f69
KM
314 if (sblock.fs_cpg % sblock.fs_cpc != 0) {
315 printf("cylinder groups must have a multiple of %d cylinders\n",
316 sblock.fs_cpc);
317 exit(1);
318 }
2fd3d252
KM
319 /*
320 * Now have size for file system and nsect and ntrak.
321 * Determine number of cylinders and blocks in the file system.
322 */
323 sblock.fs_size = fssize = dbtofsb(&sblock, fssize);
324 sblock.fs_ncyl = fssize * NSPF(&sblock) / sblock.fs_spc;
aca50d72 325 if (fssize * NSPF(&sblock) > sblock.fs_ncyl * sblock.fs_spc) {
aca50d72 326 sblock.fs_ncyl++;
bf541624 327 warn = 1;
aca50d72
KM
328 }
329 if (sblock.fs_ncyl < 1) {
330 printf("file systems must have at least one cylinder\n");
2fd3d252
KM
331 exit(1);
332 }
aca50d72
KM
333 /*
334 * determine feasability/values of rotational layout tables
335 */
336 if (sblock.fs_ntrak == 1) {
337 sblock.fs_cpc = 0;
338 goto next;
339 }
aca50d72
KM
340 if (sblock.fs_spc * sblock.fs_cpc > MAXBPC * NSPB(&sblock) ||
341 sblock.fs_nsect > (1 << NBBY) * NSPB(&sblock)) {
342 printf("%s %s %d %s %d.%s",
343 "Warning: insufficient space in super block for\n",
344 "rotational layout tables with nsect", sblock.fs_nsect,
345 "and ntrak", sblock.fs_ntrak,
2373c2b8 346 "\nFile system performance may be impared.\n");
aca50d72
KM
347 sblock.fs_cpc = 0;
348 goto next;
349 }
350 /*
351 * calculate the available blocks for each rotational position
352 */
353 for (cylno = 0; cylno < MAXCPG; cylno++)
354 for (rpos = 0; rpos < NRPOS; rpos++)
355 sblock.fs_postbl[cylno][rpos] = -1;
356 blk = sblock.fs_spc * sblock.fs_cpc / NSPF(&sblock);
357 for (i = 0; i < blk; i += sblock.fs_frag)
358 /* void */;
359 for (i -= sblock.fs_frag; i >= 0; i -= sblock.fs_frag) {
360 cylno = cbtocylno(&sblock, i);
361 rpos = cbtorpos(&sblock, i);
362 blk = i / sblock.fs_frag;
363 if (sblock.fs_postbl[cylno][rpos] == -1)
364 sblock.fs_rotbl[blk] = 0;
365 else
366 sblock.fs_rotbl[blk] =
367 sblock.fs_postbl[cylno][rpos] - blk;
368 sblock.fs_postbl[cylno][rpos] = blk;
369 }
370next:
2fd3d252
KM
371 /*
372 * Validate specified/determined cpg.
373 */
374 if (sblock.fs_spc > MAXBPG(&sblock) * NSPB(&sblock)) {
375 printf("too many sectors per cylinder (%d sectors)\n",
376 sblock.fs_spc);
377 while(sblock.fs_spc > MAXBPG(&sblock) * NSPB(&sblock)) {
378 sblock.fs_bsize <<= 1;
379 if (sblock.fs_frag < MAXFRAG)
380 sblock.fs_frag <<= 1;
381 else
382 sblock.fs_fsize <<= 1;
383 }
384 printf("nsect %d, and ntrak %d, requires block size of %d,\n",
385 sblock.fs_nsect, sblock.fs_ntrak, sblock.fs_bsize);
386 printf("\tand fragment size of %d\n", sblock.fs_fsize);
387 exit(1);
388 }
389 if (sblock.fs_fpg > MAXBPG(&sblock) * sblock.fs_frag) {
390 printf("cylinder group too large (%d cylinders); ",
391 sblock.fs_cpg);
aca50d72 392 printf("max: %d cylinders per group\n",
2fd3d252
KM
393 MAXBPG(&sblock) * sblock.fs_frag /
394 (sblock.fs_fpg / sblock.fs_cpg));
395 exit(1);
396 }
3352e84a
KM
397 sblock.fs_cgsize = fragroundup(&sblock,
398 sizeof(struct cg) + howmany(sblock.fs_fpg, NBBY));
d746d022
KM
399 /*
400 * Compute/validate number of cylinder groups.
401 */
402 sblock.fs_ncg = sblock.fs_ncyl / sblock.fs_cpg;
403 if (sblock.fs_ncyl % sblock.fs_cpg)
404 sblock.fs_ncg++;
2fd3d252 405 if ((sblock.fs_spc * sblock.fs_cpg) % NSPF(&sblock)) {
d746d022
KM
406 printf("mkfs: nsect %d, ntrak %d, cpg %d is not tolerable\n",
407 sblock.fs_nsect, sblock.fs_ntrak, sblock.fs_cpg);
408 printf("as this would would have cyl groups whose size\n");
b6407c9d 409 printf("is not a multiple of %d; choke!\n", sblock.fs_fsize);
d746d022
KM
410 exit(1);
411 }
d746d022
KM
412 /*
413 * Compute number of inode blocks per cylinder group.
414 * Start with one inode per NBPI bytes; adjust as necessary.
415 */
b8daa521
KM
416 inos = MAX(NBPI, sblock.fs_fsize);
417 if (argc > 9) {
418 i = atoi(argv[9]);
419 if (i <= 0)
420 printf("%s: bogus nbpi reset to %d\n", argv[9], inos);
421 else
422 inos = i;
423 }
aca50d72 424 i = sblock.fs_iblkno + MAXIPG / INOPF(&sblock);
b8daa521
KM
425 inos = (fssize - sblock.fs_ncg * i) * sblock.fs_fsize / inos /
426 INOPB(&sblock);
2fd3d252
KM
427 if (inos <= 0)
428 inos = 1;
429 sblock.fs_ipg = ((inos / sblock.fs_ncg) + 1) * INOPB(&sblock);
d746d022
KM
430 if (sblock.fs_ipg > MAXIPG)
431 sblock.fs_ipg = MAXIPG;
aca50d72 432 sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock);
bf541624
KM
433 i = MIN(~sblock.fs_cgmask, sblock.fs_ncg - 1);
434 if (cgdmin(&sblock, i) - cgbase(&sblock, i) >= sblock.fs_fpg) {
d746d022 435 printf("inode blocks/cyl group (%d) >= data blocks (%d)\n",
bf541624 436 cgdmin(&sblock, i) - cgbase(&sblock, i) / sblock.fs_frag,
b6407c9d 437 sblock.fs_fpg / sblock.fs_frag);
bf541624 438 printf("number of cylinders per cylinder group must be increased\n");
b6407c9d
KM
439 exit(1);
440 }
bf541624
KM
441 j = sblock.fs_ncg - 1;
442 if ((i = fssize - j * sblock.fs_fpg) < sblock.fs_fpg &&
443 cgdmin(&sblock, j) - cgbase(&sblock, j) > i) {
444 printf("Warning: inode blocks/cyl group (%d) >= data blocks (%d) in last\n",
445 (cgdmin(&sblock, j) - cgbase(&sblock, j)) / sblock.fs_frag,
446 i / sblock.fs_frag);
447 printf(" cylinder group. This implies %d sector(s) cannot be allocated.\n",
448 i * NSPF(&sblock));
449 sblock.fs_ncg--;
450 sblock.fs_ncyl -= sblock.fs_ncyl % sblock.fs_cpg;
451 sblock.fs_size = fssize = sblock.fs_ncyl * sblock.fs_spc /
452 NSPF(&sblock);
453 warn = 0;
454 }
455 if (warn) {
456 printf("Warning: %d sector(s) in last cylinder unallocated\n",
457 sblock.fs_spc -
458 (fssize * NSPF(&sblock) - (sblock.fs_ncyl - 1)
459 * sblock.fs_spc));
460 }
2fd3d252
KM
461 /*
462 * fill in remaining fields of the super block
463 */
6994bf5d 464 sblock.fs_csaddr = cgdmin(&sblock, 0);
bf541624
KM
465 sblock.fs_cssize =
466 fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum));
19782540
KM
467 i = sblock.fs_bsize / sizeof(struct csum);
468 sblock.fs_csmask = ~(i - 1);
469 for (sblock.fs_csshift = 0; i > 1; i >>= 1)
470 sblock.fs_csshift++;
471 i = sizeof(struct fs) +
472 howmany(sblock.fs_spc * sblock.fs_cpc, NSPB(&sblock));
473 sblock.fs_sbsize = fragroundup(&sblock, i);
bf541624 474 fscs = (struct csum *)calloc(1, sblock.fs_cssize);
aca50d72 475 sblock.fs_magic = FS_MAGIC;
2fd3d252 476 sblock.fs_rotdelay = ROTDELAY;
a4222b50
SL
477 if (argc > 7) {
478 sblock.fs_minfree = atoi(argv[7]);
479 if (sblock.fs_minfree < 0 || sblock.fs_minfree > 99) {
480 printf("%s: bogus minfree reset to %d%%\n", argv[7],
481 MINFREE);
482 sblock.fs_minfree = MINFREE;
483 }
484 } else
485 sblock.fs_minfree = MINFREE;
c6ff3ebb
KM
486 sblock.fs_maxcontig = MAXCONTIG;
487 sblock.fs_maxbpg = MAXBLKPG(&sblock);
a4222b50
SL
488 if (argc > 8)
489 sblock.fs_rps = atoi(argv[8]);
490 else
491 sblock.fs_rps = DEFHZ;
75e589fc
KM
492 if (argc > 10)
493 if (*argv[10] == 's')
494 sblock.fs_optim = FS_OPTSPACE;
495 else if (*argv[10] == 't')
496 sblock.fs_optim = FS_OPTTIME;
497 else {
498 printf("%s: bogus optimization preference %s\n",
499 argv[10], "reset to time");
500 sblock.fs_optim = FS_OPTTIME;
501 }
502 else
503 sblock.fs_optim = DEFAULTOPT;
2fd3d252
KM
504 sblock.fs_cgrotor = 0;
505 sblock.fs_cstotal.cs_ndir = 0;
506 sblock.fs_cstotal.cs_nbfree = 0;
507 sblock.fs_cstotal.cs_nifree = 0;
508 sblock.fs_cstotal.cs_nffree = 0;
d746d022
KM
509 sblock.fs_fmod = 0;
510 sblock.fs_ronly = 0;
d746d022 511 /*
2fd3d252 512 * Dump out summary information about file system.
d746d022
KM
513 */
514 printf("%s:\t%d sectors in %d cylinders of %d tracks, %d sectors\n",
2fd3d252 515 fsys, sblock.fs_size * NSPF(&sblock), sblock.fs_ncyl,
b6407c9d 516 sblock.fs_ntrak, sblock.fs_nsect);
d746d022 517 printf("\t%.1fMb in %d cyl groups (%d c/g, %.2fMb/g, %d i/g)\n",
b6407c9d
KM
518 (float)sblock.fs_size * sblock.fs_fsize * 1e-6, sblock.fs_ncg,
519 sblock.fs_cpg, (float)sblock.fs_fpg * sblock.fs_fsize * 1e-6,
520 sblock.fs_ipg);
d746d022
KM
521 /*
522 * Now build the cylinders group blocks and
2fd3d252 523 * then print out indices of cylinder groups.
d746d022 524 */
bf541624
KM
525 printf("super-block backups (for fsck -b#) at:");
526 for (cylno = 0; cylno < sblock.fs_ncg; cylno++) {
aca50d72 527 initcg(cylno);
bf541624
KM
528 if (cylno % 10 == 0)
529 printf("\n");
530 printf(" %d,", fsbtodb(&sblock, cgsblock(&sblock, cylno)));
531 }
4f38a6d0 532 printf("\n");
56a085eb
KM
533 if (Nflag)
534 exit(0);
d746d022 535 /*
2fd3d252 536 * Now construct the initial file system,
d746d022
KM
537 * then write out the super-block.
538 */
2fd3d252 539 fsinit();
d746d022 540 sblock.fs_time = utime;
2fd3d252 541 wtfs(SBLOCK, SBSIZE, (char *)&sblock);
b6407c9d 542 for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize)
3352e84a 543 wtfs(fsbtodb(&sblock, sblock.fs_csaddr + numfrags(&sblock, i)),
bf541624
KM
544 sblock.fs_cssize - i < sblock.fs_bsize ?
545 sblock.fs_cssize - i : sblock.fs_bsize,
546 ((char *)fscs) + i);
2fd3d252
KM
547 /*
548 * Write out the duplicate super blocks
549 */
c2b9e883 550 for (cylno = 0; cylno < sblock.fs_ncg; cylno++)
bf541624
KM
551 wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)),
552 SBSIZE, (char *)&sblock);
d746d022 553#ifndef STANDALONE
2fd3d252 554 exit(0);
d746d022
KM
555#endif
556}
557
558/*
559 * Initialize a cylinder group.
560 */
aca50d72
KM
561initcg(cylno)
562 int cylno;
d746d022 563{
bf541624 564 daddr_t cbase, d, dlower, dupper, dmax;
d746d022
KM
565 long i, j, s;
566 register struct csum *cs;
567
568 /*
569 * Determine block bounds for cylinder group.
570 * Allow space for super block summary information in first
571 * cylinder group.
572 */
6994bf5d 573 cbase = cgbase(&sblock, cylno);
d746d022
KM
574 dmax = cbase + sblock.fs_fpg;
575 if (dmax > sblock.fs_size)
576 dmax = sblock.fs_size;
bf541624
KM
577 dlower = cgsblock(&sblock, cylno) - cbase;
578 dupper = cgdmin(&sblock, cylno) - cbase;
aca50d72 579 cs = fscs + cylno;
d746d022
KM
580 acg.cg_time = utime;
581 acg.cg_magic = CG_MAGIC;
aca50d72 582 acg.cg_cgx = cylno;
bb40745e
KM
583 if (cylno == sblock.fs_ncg - 1)
584 acg.cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg;
585 else
586 acg.cg_ncyl = sblock.fs_cpg;
d746d022
KM
587 acg.cg_niblk = sblock.fs_ipg;
588 acg.cg_ndblk = dmax - cbase;
0947395d
KM
589 acg.cg_cs.cs_ndir = 0;
590 acg.cg_cs.cs_nffree = 0;
591 acg.cg_cs.cs_nbfree = 0;
592 acg.cg_cs.cs_nifree = 0;
bf541624
KM
593 acg.cg_rotor = 0;
594 acg.cg_frotor = 0;
92ea6158 595 acg.cg_irotor = 0;
b6407c9d 596 for (i = 0; i < sblock.fs_frag; i++) {
f3c028b7
KM
597 acg.cg_frsum[i] = 0;
598 }
599 for (i = 0; i < sblock.fs_ipg; ) {
b6407c9d 600 for (j = INOPB(&sblock); j > 0; j--) {
d746d022
KM
601 clrbit(acg.cg_iused, i);
602 i++;
603 }
b6407c9d 604 acg.cg_cs.cs_nifree += INOPB(&sblock);
d746d022 605 }
aca50d72 606 if (cylno == 0)
2fd3d252
KM
607 for (i = 0; i < ROOTINO; i++) {
608 setbit(acg.cg_iused, i);
609 acg.cg_cs.cs_nifree--;
610 }
d746d022
KM
611 while (i < MAXIPG) {
612 clrbit(acg.cg_iused, i);
613 i++;
614 }
56a085eb
KM
615 wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno)),
616 sblock.fs_ipg * sizeof (struct dinode), (char *)zino);
43f6367c
KM
617 for (i = 0; i < MAXCPG; i++) {
618 acg.cg_btot[i] = 0;
d746d022
KM
619 for (j = 0; j < NRPOS; j++)
620 acg.cg_b[i][j] = 0;
43f6367c 621 }
aca50d72 622 if (cylno == 0) {
bf541624
KM
623 /*
624 * reserve space for summary info and Boot block
625 */
626 dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
627 for (d = 0; d < dlower; d += sblock.fs_frag)
628 clrblock(&sblock, acg.cg_free, d/sblock.fs_frag);
629 } else {
630 for (d = 0; d < dlower; d += sblock.fs_frag) {
631 setblock(&sblock, acg.cg_free, d/sblock.fs_frag);
632 acg.cg_cs.cs_nbfree++;
633 acg.cg_btot[cbtocylno(&sblock, d)]++;
634 acg.cg_b[cbtocylno(&sblock, d)][cbtorpos(&sblock, d)]++;
635 }
636 sblock.fs_dsize += dlower;
d746d022 637 }
bf541624
KM
638 sblock.fs_dsize += acg.cg_ndblk - dupper;
639 for (; d < dupper; d += sblock.fs_frag)
b6407c9d 640 clrblock(&sblock, acg.cg_free, d/sblock.fs_frag);
bf541624
KM
641 if (d > dupper) {
642 acg.cg_frsum[d - dupper]++;
643 for (i = d - 1; i >= dupper; i--) {
644 setbit(acg.cg_free, i);
645 acg.cg_cs.cs_nffree++;
646 }
647 }
648 while ((d + sblock.fs_frag) <= dmax - cbase) {
b6407c9d 649 setblock(&sblock, acg.cg_free, d/sblock.fs_frag);
0947395d 650 acg.cg_cs.cs_nbfree++;
43f6367c 651 acg.cg_btot[cbtocylno(&sblock, d)]++;
aca50d72 652 acg.cg_b[cbtocylno(&sblock, d)][cbtorpos(&sblock, d)]++;
b6407c9d 653 d += sblock.fs_frag;
d746d022 654 }
bf541624 655 if (d < dmax - cbase) {
aca50d72 656 acg.cg_frsum[dmax - cbase - d]++;
56d45dcd
KM
657 for (; d < dmax - cbase; d++) {
658 setbit(acg.cg_free, d);
0947395d 659 acg.cg_cs.cs_nffree++;
56d45dcd 660 }
bb40745e
KM
661 for (; d % sblock.fs_frag != 0; d++)
662 clrbit(acg.cg_free, d);
bf541624 663 }
bb40745e
KM
664 for (d /= sblock.fs_frag; d < MAXBPG(&sblock); d ++)
665 clrblock(&sblock, acg.cg_free, d);
0947395d
KM
666 sblock.fs_cstotal.cs_ndir += acg.cg_cs.cs_ndir;
667 sblock.fs_cstotal.cs_nffree += acg.cg_cs.cs_nffree;
668 sblock.fs_cstotal.cs_nbfree += acg.cg_cs.cs_nbfree;
669 sblock.fs_cstotal.cs_nifree += acg.cg_cs.cs_nifree;
670 *cs = acg.cg_cs;
6994bf5d 671 wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)),
b6407c9d 672 sblock.fs_bsize, (char *)&acg);
d746d022
KM
673}
674
2fd3d252
KM
675/*
676 * initialize the file system
677 */
678struct inode node;
679#define PREDEFDIR 3
052efd62
KM
680struct direct root_dir[] = {
681 { ROOTINO, sizeof(struct direct), 1, "." },
682 { ROOTINO, sizeof(struct direct), 2, ".." },
683 { LOSTFOUNDINO, sizeof(struct direct), 10, "lost+found" },
2fd3d252 684};
052efd62
KM
685struct direct lost_found_dir[] = {
686 { LOSTFOUNDINO, sizeof(struct direct), 1, "." },
687 { ROOTINO, sizeof(struct direct), 2, ".." },
688 { 0, DIRBLKSIZ, 0, 0 },
2fd3d252 689};
052efd62 690char buf[MAXBSIZE];
2fd3d252
KM
691
692fsinit()
d746d022 693{
052efd62
KM
694 int i;
695
d746d022 696 /*
2fd3d252 697 * initialize the node
d746d022 698 */
2fd3d252
KM
699 node.i_atime = utime;
700 node.i_mtime = utime;
701 node.i_ctime = utime;
d746d022 702 /*
2fd3d252 703 * create the lost+found directory
d746d022 704 */
052efd62
KM
705 (void)makedir(lost_found_dir, 2);
706 for (i = DIRBLKSIZ; i < sblock.fs_bsize; i += DIRBLKSIZ)
707 bcopy(&lost_found_dir[2], &buf[i], DIRSIZ(&lost_found_dir[2]));
2fd3d252
KM
708 node.i_number = LOSTFOUNDINO;
709 node.i_mode = IFDIR | UMASK;
710 node.i_nlink = 2;
711 node.i_size = sblock.fs_bsize;
712 node.i_db[0] = alloc(node.i_size, node.i_mode);
cdbcf1b5 713 node.i_blocks = btodb(fragroundup(&sblock, node.i_size));
052efd62 714 wtfs(fsbtodb(&sblock, node.i_db[0]), node.i_size, buf);
2fd3d252
KM
715 iput(&node);
716 /*
717 * create the root directory
718 */
719 node.i_number = ROOTINO;
720 node.i_mode = IFDIR | UMASK;
721 node.i_nlink = PREDEFDIR;
052efd62 722 node.i_size = makedir(root_dir, PREDEFDIR);
2fd3d252 723 node.i_db[0] = alloc(sblock.fs_fsize, node.i_mode);
cdbcf1b5 724 node.i_blocks = btodb(fragroundup(&sblock, node.i_size));
052efd62 725 wtfs(fsbtodb(&sblock, node.i_db[0]), sblock.fs_fsize, buf);
2fd3d252 726 iput(&node);
d746d022
KM
727}
728
052efd62
KM
729/*
730 * construct a set of directory entries in "buf".
731 * return size of directory.
732 */
733makedir(protodir, entries)
734 register struct direct *protodir;
735 int entries;
736{
737 char *cp;
738 int i, spcleft;
739
740 spcleft = DIRBLKSIZ;
741 for (cp = buf, i = 0; i < entries - 1; i++) {
742 protodir[i].d_reclen = DIRSIZ(&protodir[i]);
743 bcopy(&protodir[i], cp, protodir[i].d_reclen);
744 cp += protodir[i].d_reclen;
745 spcleft -= protodir[i].d_reclen;
746 }
747 protodir[i].d_reclen = spcleft;
748 bcopy(&protodir[i], cp, DIRSIZ(&protodir[i]));
4b47cead 749 return (DIRBLKSIZ);
052efd62
KM
750}
751
2fd3d252
KM
752/*
753 * allocate a block or frag
754 */
d746d022 755daddr_t
07670f7d
KM
756alloc(size, mode)
757 int size;
758 int mode;
d746d022 759{
aca50d72 760 int i, frag;
d746d022
KM
761 daddr_t d;
762
3352e84a
KM
763 rdfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
764 (char *)&acg);
bf541624
KM
765 if (acg.cg_magic != CG_MAGIC) {
766 printf("cg 0: bad magic number\n");
767 return (0);
768 }
0947395d 769 if (acg.cg_cs.cs_nbfree == 0) {
d746d022
KM
770 printf("first cylinder group ran out of space\n");
771 return (0);
772 }
b6407c9d
KM
773 for (d = 0; d < acg.cg_ndblk; d += sblock.fs_frag)
774 if (isblock(&sblock, acg.cg_free, d / sblock.fs_frag))
d746d022
KM
775 goto goth;
776 printf("internal error: can't find block in cyl 0\n");
777 return (0);
778goth:
b6407c9d 779 clrblock(&sblock, acg.cg_free, d / sblock.fs_frag);
0947395d
KM
780 acg.cg_cs.cs_nbfree--;
781 sblock.fs_cstotal.cs_nbfree--;
d746d022 782 fscs[0].cs_nbfree--;
07670f7d 783 if (mode & IFDIR) {
0947395d
KM
784 acg.cg_cs.cs_ndir++;
785 sblock.fs_cstotal.cs_ndir++;
07670f7d
KM
786 fscs[0].cs_ndir++;
787 }
43f6367c 788 acg.cg_btot[cbtocylno(&sblock, d)]--;
aca50d72 789 acg.cg_b[cbtocylno(&sblock, d)][cbtorpos(&sblock, d)]--;
b6407c9d
KM
790 if (size != sblock.fs_bsize) {
791 frag = howmany(size, sblock.fs_fsize);
792 fscs[0].cs_nffree += sblock.fs_frag - frag;
793 sblock.fs_cstotal.cs_nffree += sblock.fs_frag - frag;
794 acg.cg_cs.cs_nffree += sblock.fs_frag - frag;
795 acg.cg_frsum[sblock.fs_frag - frag]++;
796 for (i = frag; i < sblock.fs_frag; i++)
bf541624 797 setbit(acg.cg_free, d + i);
d746d022 798 }
3352e84a
KM
799 wtfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
800 (char *)&acg);
d746d022
KM
801 return (d);
802}
803
2fd3d252
KM
804/*
805 * Allocate an inode on the disk
806 */
807iput(ip)
808 register struct inode *ip;
d746d022 809{
2fd3d252 810 struct dinode buf[MAXINOPB];
d746d022 811 daddr_t d;
2fd3d252 812 int c;
d746d022 813
6994bf5d 814 c = itog(&sblock, ip->i_number);
3352e84a
KM
815 rdfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
816 (char *)&acg);
bf541624
KM
817 if (acg.cg_magic != CG_MAGIC) {
818 printf("cg 0: bad magic number\n");
819 exit(1);
820 }
0947395d 821 acg.cg_cs.cs_nifree--;
d746d022 822 setbit(acg.cg_iused, ip->i_number);
3352e84a
KM
823 wtfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
824 (char *)&acg);
0947395d 825 sblock.fs_cstotal.cs_nifree--;
d746d022 826 fscs[0].cs_nifree--;
d746d022 827 if(ip->i_number >= sblock.fs_ipg * sblock.fs_ncg) {
2fd3d252
KM
828 printf("fsinit: inode value out of range (%d).\n",
829 ip->i_number);
830 exit(1);
d746d022 831 }
6994bf5d 832 d = fsbtodb(&sblock, itod(&sblock, ip->i_number));
2fd3d252 833 rdfs(d, sblock.fs_bsize, buf);
6994bf5d 834 buf[itoo(&sblock, ip->i_number)].di_ic = ip->i_ic;
2fd3d252
KM
835 wtfs(d, sblock.fs_bsize, buf);
836}
837
838/*
839 * read a block from the file system
840 */
841rdfs(bno, size, bf)
842 daddr_t bno;
843 int size;
844 char *bf;
845{
846 int n;
847
c312eebd
KM
848 if (lseek(fsi, bno * DEV_BSIZE, 0) < 0) {
849 printf("seek error: %ld\n", bno);
850 perror("rdfs");
851 exit(1);
852 }
2fd3d252
KM
853 n = read(fsi, bf, size);
854 if(n != size) {
855 printf("read error: %ld\n", bno);
c312eebd 856 perror("rdfs");
2fd3d252 857 exit(1);
b6407c9d 858 }
b6407c9d
KM
859}
860
861/*
2fd3d252 862 * write a block to the file system
b6407c9d 863 */
2fd3d252
KM
864wtfs(bno, size, bf)
865 daddr_t bno;
866 int size;
867 char *bf;
868{
869 int n;
870
56a085eb
KM
871 if (Nflag)
872 return;
c312eebd
KM
873 if (lseek(fso, bno * DEV_BSIZE, 0) < 0) {
874 printf("seek error: %ld\n", bno);
875 perror("wtfs");
876 exit(1);
877 }
2fd3d252
KM
878 n = write(fso, bf, size);
879 if(n != size) {
880 printf("write error: %D\n", bno);
c312eebd 881 perror("wtfs");
2fd3d252
KM
882 exit(1);
883 }
884}
b6407c9d 885
2fd3d252
KM
886/*
887 * check if a block is available
888 */
b6407c9d
KM
889isblock(fs, cp, h)
890 struct fs *fs;
891 unsigned char *cp;
892 int h;
893{
894 unsigned char mask;
895
896 switch (fs->fs_frag) {
897 case 8:
898 return (cp[h] == 0xff);
899 case 4:
900 mask = 0x0f << ((h & 0x1) << 2);
901 return ((cp[h >> 1] & mask) == mask);
902 case 2:
903 mask = 0x03 << ((h & 0x3) << 1);
904 return ((cp[h >> 2] & mask) == mask);
905 case 1:
906 mask = 0x01 << (h & 0x7);
907 return ((cp[h >> 3] & mask) == mask);
908 default:
4384e5a5
KM
909#ifdef STANDALONE
910 printf("isblock bad fs_frag %d\n", fs->fs_frag);
911#else
b6407c9d 912 fprintf(stderr, "isblock bad fs_frag %d\n", fs->fs_frag);
4384e5a5 913#endif
b6407c9d
KM
914 return;
915 }
916}
917
2fd3d252
KM
918/*
919 * take a block out of the map
920 */
b6407c9d
KM
921clrblock(fs, cp, h)
922 struct fs *fs;
923 unsigned char *cp;
924 int h;
925{
926 switch ((fs)->fs_frag) {
927 case 8:
928 cp[h] = 0;
929 return;
930 case 4:
931 cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
932 return;
933 case 2:
934 cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
935 return;
936 case 1:
937 cp[h >> 3] &= ~(0x01 << (h & 0x7));
938 return;
939 default:
4384e5a5
KM
940#ifdef STANDALONE
941 printf("clrblock bad fs_frag %d\n", fs->fs_frag);
942#else
b6407c9d 943 fprintf(stderr, "clrblock bad fs_frag %d\n", fs->fs_frag);
4384e5a5 944#endif
b6407c9d
KM
945 return;
946 }
947}
948
2fd3d252
KM
949/*
950 * put a block into the map
951 */
b6407c9d
KM
952setblock(fs, cp, h)
953 struct fs *fs;
954 unsigned char *cp;
955 int h;
956{
957 switch (fs->fs_frag) {
958 case 8:
959 cp[h] = 0xff;
960 return;
961 case 4:
962 cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
963 return;
964 case 2:
965 cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
966 return;
967 case 1:
968 cp[h >> 3] |= (0x01 << (h & 0x7));
969 return;
970 default:
4384e5a5
KM
971#ifdef STANDALONE
972 printf("setblock bad fs_frag %d\n", fs->fs_frag);
973#else
b6407c9d 974 fprintf(stderr, "setblock bad fs_frag %d\n", fs->fs_frag);
4384e5a5 975#endif
b6407c9d 976 return;
d746d022 977 }
d746d022 978}