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