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