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