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