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