fix up tracing info; add default, but disable for now (could cause
[unix-history] / usr / src / sbin / newfs / mkfs.c
CommitLineData
19538291
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
62f283da 8static char sccsid[] = "@(#)mkfs.c 6.7 (Berkeley) %G%";
19538291 9#endif not lint
d746d022 10
d746d022
KM
11#ifndef STANDALONE
12#include <stdio.h>
13#include <a.out.h>
14#endif
15
45eb394d
KM
16#include <sys/param.h>
17#include <sys/inode.h>
18#include <sys/fs.h>
14b4eb74 19#include <sys/dir.h>
8485bb11 20#include <sys/disklabel.h>
62f283da
KM
21#include <machine/endian.h>
22
23/*
24 * make file system for cylinder-group style file systems
25 */
26
27/*
28 * The size of a cylinder group is calculated by CGSIZE. The maximum size
29 * is limited by the fact that cylinder groups are at most one block.
30 * Its size is derived from the size of the maps maintained in the
31 * cylinder group and the (struct cg) size.
32 */
33#define CGSIZE(fs) \
34 /* base cg */ (sizeof(struct cg) + \
35 /* blktot size */ (fs)->fs_cpg * sizeof(long) + \
36 /* blks size */ (fs)->fs_cpg * (fs)->fs_nrpos * sizeof(short) + \
37 /* inode map */ howmany((fs)->fs_ipg, NBBY) + \
38 /* block map */ howmany((fs)->fs_cpg * (fs)->fs_spc / NSPF(fs), NBBY))
39
40/*
41 * We limit the size of the inode map to be no more than a
42 * third of the cylinder group space, since we must leave at
43 * least an equal amount of space for the block map.
44 *
45 * N.B.: MAXIPG must be a multiple of INOPB(fs).
46 */
47#define MAXIPG(fs) roundup((fs)->fs_bsize * NBBY / 3, INOPB(fs))
8485bb11 48
2fd3d252 49#define UMASK 0755
c312eebd 50#define MAXINOPB (MAXBSIZE / sizeof(struct dinode))
2fd3d252 51#define POWEROF2(num) (((num) & ((num) - 1)) == 0)
d746d022 52
8485bb11
KM
53/*
54 * variables set up by front end.
55 */
a20edd44
KM
56extern int Nflag; /* run mkfs without writing file system */
57extern int fssize; /* file system size */
58extern int ntracks; /* # tracks/cylinder */
59extern int nsectors; /* # sectors/track */
60extern int nphyssectors; /* # sectors/track including spares */
61extern int secpercyl; /* sectors per cylinder */
62extern int sectorsize; /* bytes/sector */
63extern int rpm; /* revolutions/minute of drive */
64extern int interleave; /* hardware sector interleave */
65extern int trackskew; /* sector 0 skew, per track */
66extern int headswitch; /* head switch time, usec */
67extern int trackseek; /* track-to-track seek, usec */
68extern int fsize; /* fragment size */
69extern int bsize; /* block size */
70extern int cpg; /* cylinders/cylinder group */
7292dd7c 71extern int cpgflg; /* cylinders/cylinder group flag was given */
a20edd44
KM
72extern int minfree; /* free space threshold */
73extern int opt; /* optimization preference (space or time) */
74extern int density; /* number of bytes per inode */
75extern int maxcontig; /* max contiguous blocks to allocate */
76extern int rotdelay; /* rotational delay between blocks */
3d632f12 77extern int maxbpg; /* maximum blocks per file in a cyl group */
62f283da 78extern int nrpos; /* # of distinguished rotational positions */
c5d3fd78
MK
79extern int bbsize; /* boot block size */
80extern int sbsize; /* superblock size */
8485bb11 81
d746d022
KM
82union {
83 struct fs fs;
62f283da 84 char pad[SBSIZE];
d746d022
KM
85} fsun;
86#define sblock fsun.fs
87struct csum *fscs;
88
89union {
90 struct cg cg;
b6407c9d 91 char pad[MAXBSIZE];
d746d022
KM
92} cgun;
93#define acg cgun.cg
94
62f283da 95struct dinode zino[MAXBSIZE / sizeof(struct dinode)];
2fd3d252 96
8485bb11 97int fsi, fso;
2fd3d252 98time_t utime;
d746d022
KM
99daddr_t alloc();
100
8485bb11
KM
101mkfs(pp, fsys, fi, fo)
102 struct partition *pp;
103 char *fsys;
104 int fi, fo;
d746d022 105{
7292dd7c
KM
106 register long i, mincpc, mincpg, inospercg;
107 long cylno, rpos, blk, j, warn = 0;
108 long used, mincpgcnt, bpcg;
109 long mapcramped, inodecramped;
62f283da 110 long postblsize, rotblsize, totalsbsize;
d746d022 111
d746d022
KM
112#ifndef STANDALONE
113 time(&utime);
2fd3d252 114#endif
8485bb11
KM
115 fsi = fi;
116 fso = fo;
51fe1c64
KM
117 /*
118 * Validate the given file system size.
119 * Verify that its last block can actually be accessed.
120 */
2fd3d252
KM
121 if (fssize <= 0)
122 printf("preposterous size %d\n", fssize), exit(1);
8485bb11 123 wtfs(fssize - 1, sectorsize, (char *)&sblock);
2fd3d252
KM
124 /*
125 * collect and verify the sector and track info
126 */
8485bb11
KM
127 sblock.fs_nsect = nsectors;
128 sblock.fs_ntrak = ntracks;
2fd3d252
KM
129 if (sblock.fs_ntrak <= 0)
130 printf("preposterous ntrak %d\n", sblock.fs_ntrak), exit(1);
131 if (sblock.fs_nsect <= 0)
132 printf("preposterous nsect %d\n", sblock.fs_nsect), exit(1);
2fd3d252
KM
133 /*
134 * collect and verify the block and fragment sizes
135 */
8485bb11
KM
136 sblock.fs_bsize = bsize;
137 sblock.fs_fsize = fsize;
2fd3d252
KM
138 if (!POWEROF2(sblock.fs_bsize)) {
139 printf("block size must be a power of 2, not %d\n",
140 sblock.fs_bsize);
d746d022
KM
141 exit(1);
142 }
2fd3d252
KM
143 if (!POWEROF2(sblock.fs_fsize)) {
144 printf("fragment size must be a power of 2, not %d\n",
145 sblock.fs_fsize);
d746d022
KM
146 exit(1);
147 }
8485bb11 148 if (sblock.fs_fsize < sectorsize) {
b6407c9d 149 printf("fragment size %d is too small, minimum is %d\n",
8485bb11 150 sblock.fs_fsize, sectorsize);
b6407c9d
KM
151 exit(1);
152 }
153 if (sblock.fs_bsize < MINBSIZE) {
154 printf("block size %d is too small, minimum is %d\n",
155 sblock.fs_bsize, MINBSIZE);
156 exit(1);
157 }
2fd3d252
KM
158 if (sblock.fs_bsize < sblock.fs_fsize) {
159 printf("block size (%d) cannot be smaller than fragment size (%d)\n",
160 sblock.fs_bsize, sblock.fs_fsize);
d746d022
KM
161 exit(1);
162 }
3352e84a
KM
163 sblock.fs_bmask = ~(sblock.fs_bsize - 1);
164 sblock.fs_fmask = ~(sblock.fs_fsize - 1);
62f283da
KM
165 /*
166 * Planning now for future expansion.
167 */
168# if (BYTE_ORDER == BIG_ENDIAN)
169 sblock.fs_qbmask.val[0] = 0;
170 sblock.fs_qbmask.val[1] = ~sblock.fs_bmask;
171 sblock.fs_qfmask.val[0] = 0;
172 sblock.fs_qfmask.val[1] = ~sblock.fs_fmask;
173# endif /* BIG_ENDIAN */
174# if (BYTE_ORDER == LITTLE_ENDIAN)
175 sblock.fs_qbmask.val[0] = ~sblock.fs_bmask;
176 sblock.fs_qbmask.val[1] = 0;
177 sblock.fs_qfmask.val[0] = ~sblock.fs_fmask;
178 sblock.fs_qfmask.val[1] = 0;
179# endif /* LITTLE_ENDIAN */
3352e84a
KM
180 for (sblock.fs_bshift = 0, i = sblock.fs_bsize; i > 1; i >>= 1)
181 sblock.fs_bshift++;
182 for (sblock.fs_fshift = 0, i = sblock.fs_fsize; i > 1; i >>= 1)
183 sblock.fs_fshift++;
184 sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize);
19782540
KM
185 for (sblock.fs_fragshift = 0, i = sblock.fs_frag; i > 1; i >>= 1)
186 sblock.fs_fragshift++;
2fd3d252
KM
187 if (sblock.fs_frag > MAXFRAG) {
188 printf("fragment size %d is too small, minimum with block size %d is %d\n",
189 sblock.fs_fsize, sblock.fs_bsize,
190 sblock.fs_bsize / MAXFRAG);
191 exit(1);
d746d022 192 }
62f283da 193 sblock.fs_nrpos = nrpos;
19782540
KM
194 sblock.fs_nindir = sblock.fs_bsize / sizeof(daddr_t);
195 sblock.fs_inopb = sblock.fs_bsize / sizeof(struct dinode);
8485bb11
KM
196 sblock.fs_nspf = sblock.fs_fsize / sectorsize;
197 for (sblock.fs_fsbtodb = 0, i = NSPF(&sblock); i > 1; i >>= 1)
19782540 198 sblock.fs_fsbtodb++;
bf541624 199 sblock.fs_sblkno =
c5d3fd78 200 roundup(howmany(bbsize + sbsize, sblock.fs_fsize), sblock.fs_frag);
bf541624 201 sblock.fs_cblkno = (daddr_t)(sblock.fs_sblkno +
c5d3fd78 202 roundup(howmany(sbsize, sblock.fs_fsize), sblock.fs_frag));
aca50d72 203 sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag;
bf541624 204 sblock.fs_cgoffset = roundup(
8485bb11 205 howmany(sblock.fs_nsect, NSPF(&sblock)), sblock.fs_frag);
bf541624
KM
206 for (sblock.fs_cgmask = 0xffffffff, i = sblock.fs_ntrak; i > 1; i >>= 1)
207 sblock.fs_cgmask <<= 1;
208 if (!POWEROF2(sblock.fs_ntrak))
209 sblock.fs_cgmask <<= 1;
7292dd7c
KM
210 /*
211 * Validate specified/determined secpercyl
212 * and calculate minimum cylinders per group.
213 */
214 sblock.fs_spc = secpercyl;
3aaf0f69
KM
215 for (sblock.fs_cpc = NSPB(&sblock), i = sblock.fs_spc;
216 sblock.fs_cpc > 1 && (i & 1) == 0;
217 sblock.fs_cpc >>= 1, i >>= 1)
218 /* void */;
7292dd7c 219 mincpc = sblock.fs_cpc;
7292dd7c
KM
220 bpcg = sblock.fs_spc * sectorsize;
221 inospercg = roundup(bpcg / sizeof(struct dinode), INOPB(&sblock));
62f283da
KM
222 if (inospercg > MAXIPG(&sblock))
223 inospercg = MAXIPG(&sblock);
7292dd7c
KM
224 used = (sblock.fs_iblkno + inospercg / INOPF(&sblock)) * NSPF(&sblock);
225 mincpgcnt = howmany(sblock.fs_cgoffset * (~sblock.fs_cgmask) + used,
226 sblock.fs_spc);
227 mincpg = roundup(mincpgcnt, mincpc);
228 /*
229 * Insure that cylinder group with mincpg has enough space
230 * for block maps
231 */
62f283da
KM
232 sblock.fs_cpg = mincpg;
233 sblock.fs_ipg = inospercg;
7292dd7c 234 mapcramped = 0;
62f283da 235 while (CGSIZE(&sblock) > sblock.fs_bsize) {
7292dd7c
KM
236 mapcramped = 1;
237 if (sblock.fs_bsize < MAXBSIZE) {
238 sblock.fs_bsize <<= 1;
239 if ((i & 1) == 0) {
240 i >>= 1;
241 } else {
242 sblock.fs_cpc <<= 1;
243 mincpc <<= 1;
244 mincpg = roundup(mincpgcnt, mincpc);
62f283da 245 sblock.fs_cpg = mincpg;
7292dd7c
KM
246 }
247 sblock.fs_frag <<= 1;
248 sblock.fs_fragshift += 1;
249 if (sblock.fs_frag <= MAXFRAG)
250 continue;
251 }
252 if (sblock.fs_fsize == sblock.fs_bsize) {
253 printf("There is no block size that");
254 printf(" can support this disk\n");
255 exit(1);
256 }
257 sblock.fs_frag >>= 1;
258 sblock.fs_fragshift -= 1;
259 sblock.fs_fsize <<= 1;
260 sblock.fs_nspf <<= 1;
261 }
262 /*
263 * Insure that cylinder group with mincpg has enough space for inodes
264 */
265 inodecramped = 0;
266 used *= sectorsize;
62f283da
KM
267 inospercg = roundup((mincpg * bpcg - used) / density, INOPB(&sblock));
268 sblock.fs_ipg = inospercg;
269 while (inospercg > MAXIPG(&sblock)) {
7292dd7c
KM
270 inodecramped = 1;
271 if (mincpc == 1 || sblock.fs_frag == 1 ||
272 sblock.fs_bsize == MINBSIZE)
273 break;
274 printf("With a block size of %d %s %d\n", sblock.fs_bsize,
275 "minimum bytes per inode is",
62f283da 276 (mincpg * bpcg - used) / MAXIPG(&sblock) + 1);
7292dd7c
KM
277 sblock.fs_bsize >>= 1;
278 sblock.fs_frag >>= 1;
279 sblock.fs_fragshift -= 1;
280 mincpc >>= 1;
62f283da
KM
281 sblock.fs_cpg = roundup(mincpgcnt, mincpc);
282 if (CGSIZE(&sblock) > sblock.fs_bsize) {
7292dd7c
KM
283 sblock.fs_bsize <<= 1;
284 break;
285 }
62f283da
KM
286 mincpg = sblock.fs_cpg;
287 inospercg =
288 roundup((mincpg * bpcg - used) / density, INOPB(&sblock));
289 sblock.fs_ipg = inospercg;
7292dd7c
KM
290 }
291 if (inodecramped) {
62f283da 292 if (inospercg > MAXIPG(&sblock)) {
7292dd7c 293 printf("Minimum bytes per inode is %d\n",
62f283da 294 (mincpg * bpcg - used) / MAXIPG(&sblock) + 1);
7292dd7c
KM
295 } else if (!mapcramped) {
296 printf("With %d bytes per inode, ", density);
297 printf("minimum cylinders per group is %d\n", mincpg);
298 }
299 }
300 if (mapcramped) {
301 printf("With %d sectors per cylinder, ", sblock.fs_spc);
302 printf("minimum cylinders per group is %d\n", mincpg);
303 }
304 if (inodecramped || mapcramped) {
305 if (sblock.fs_bsize != bsize)
306 printf("%s to be changed from %d to %d\n",
307 "This requires the block size",
308 bsize, sblock.fs_bsize);
309 if (sblock.fs_fsize != fsize)
310 printf("\t%s to be changed from %d to %d\n",
311 "and the fragment size",
62f283da 312 fsize, sblock.fs_fsize);
173a62ff
KM
313 exit(1);
314 }
2fd3d252 315 /*
7292dd7c 316 * Calculate the number of cylinders per group
d746d022 317 */
8485bb11 318 sblock.fs_cpg = cpg;
7292dd7c 319 if (sblock.fs_cpg % mincpc != 0) {
8485bb11 320 printf("%s groups must have a multiple of %d cylinders\n",
7292dd7c
KM
321 cpgflg ? "Cylinder" : "Warning: cylinder", mincpc);
322 sblock.fs_cpg = roundup(sblock.fs_cpg, mincpc);
62f283da
KM
323 if (!cpgflg)
324 cpg = sblock.fs_cpg;
8485bb11 325 }
7292dd7c 326 /*
62f283da 327 * Must insure there is enough space for inodes
7292dd7c 328 */
62f283da
KM
329 sblock.fs_ipg = roundup((sblock.fs_cpg * bpcg - used) / density,
330 INOPB(&sblock));
331 while (sblock.fs_ipg > MAXIPG(&sblock)) {
332 inodecramped = 1;
7292dd7c 333 sblock.fs_cpg -= mincpc;
62f283da
KM
334 sblock.fs_ipg = roundup((sblock.fs_cpg * bpcg - used) / density,
335 INOPB(&sblock));
2fd3d252 336 }
7292dd7c 337 /*
62f283da 338 * Must insure there is enough space to hold block map
7292dd7c 339 */
62f283da
KM
340 while (CGSIZE(&sblock) > sblock.fs_bsize) {
341 mapcramped = 1;
7292dd7c 342 sblock.fs_cpg -= mincpc;
62f283da
KM
343 sblock.fs_ipg = roundup((sblock.fs_cpg * bpcg - used) / density,
344 INOPB(&sblock));
7292dd7c 345 }
62f283da 346 sblock.fs_fpg = (sblock.fs_cpg * sblock.fs_spc) / NSPF(&sblock);
7292dd7c
KM
347 if ((sblock.fs_cpg * sblock.fs_spc) % NSPB(&sblock) != 0) {
348 printf("newfs: panic (fs_cpg * fs_spc) % NSPF != 0");
349 exit(2);
350 }
351 if (sblock.fs_cpg < mincpg) {
352 printf("cylinder groups must have at least %d cylinders\n",
353 mincpg);
2fd3d252 354 exit(1);
7292dd7c
KM
355 } else if (sblock.fs_cpg != cpg) {
356 if (!cpgflg)
357 printf("Warning: ");
62f283da
KM
358 else if (!mapcramped && !inodecramped)
359 exit(1);
7292dd7c
KM
360 if (mapcramped && inodecramped)
361 printf("Block size and bytes per inode restrict");
362 else if (mapcramped)
363 printf("Block size restricts");
364 else
365 printf("Bytes per inode restrict");
366 printf(" cylinders per group to %d.\n", sblock.fs_cpg);
367 if (cpgflg)
368 exit(1);
3aaf0f69 369 }
62f283da 370 sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock));
2fd3d252
KM
371 /*
372 * Now have size for file system and nsect and ntrak.
373 * Determine number of cylinders and blocks in the file system.
374 */
375 sblock.fs_size = fssize = dbtofsb(&sblock, fssize);
376 sblock.fs_ncyl = fssize * NSPF(&sblock) / sblock.fs_spc;
aca50d72 377 if (fssize * NSPF(&sblock) > sblock.fs_ncyl * sblock.fs_spc) {
aca50d72 378 sblock.fs_ncyl++;
bf541624 379 warn = 1;
aca50d72
KM
380 }
381 if (sblock.fs_ncyl < 1) {
382 printf("file systems must have at least one cylinder\n");
2fd3d252
KM
383 exit(1);
384 }
aca50d72 385 /*
62f283da
KM
386 * Determine feasability/values of rotational layout tables.
387 *
388 * The size of the rotational layout tables is limited by the
389 * size of the superblock, SBSIZE. The amount of space available
390 * for tables is calculated as (SBSIZE - sizeof (struct fs)).
391 * The size of these tables is inversely proportional to the block
392 * size of the file system. The size increases if sectors per track
393 * are not powers of two, because more cylinders must be described
394 * by the tables before the rotational pattern repeats (fs_cpc).
aca50d72 395 */
7292dd7c
KM
396 sblock.fs_interleave = interleave;
397 sblock.fs_trackskew = trackskew;
398 sblock.fs_npsect = nphyssectors;
62f283da
KM
399 sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT;
400 sblock.fs_sbsize = fragroundup(&sblock, sizeof(struct fs));
aca50d72
KM
401 if (sblock.fs_ntrak == 1) {
402 sblock.fs_cpc = 0;
403 goto next;
404 }
62f283da
KM
405 postblsize = sblock.fs_nrpos * sblock.fs_cpc * sizeof(short);
406 rotblsize = sblock.fs_cpc * sblock.fs_spc / NSPB(&sblock);
407 totalsbsize = sizeof(struct fs) + rotblsize;
408 if (sblock.fs_nrpos == 8 && sblock.fs_cpc <= 16) {
409 /* use old static table space */
410 sblock.fs_postbloff = (char *)(&sblock.fs_opostbl[0][0]) -
411 (char *)(&sblock.fs_link);
412 sblock.fs_rotbloff = &sblock.fs_space[0] -
413 (u_char *)(&sblock.fs_link);
414 } else {
415 /* use dynamic table space */
416 sblock.fs_postbloff = &sblock.fs_space[0] -
417 (u_char *)(&sblock.fs_link);
418 sblock.fs_rotbloff = sblock.fs_postbloff + postblsize;
419 totalsbsize += postblsize;
420 }
421 if (totalsbsize > SBSIZE ||
aca50d72
KM
422 sblock.fs_nsect > (1 << NBBY) * NSPB(&sblock)) {
423 printf("%s %s %d %s %d.%s",
424 "Warning: insufficient space in super block for\n",
425 "rotational layout tables with nsect", sblock.fs_nsect,
426 "and ntrak", sblock.fs_ntrak,
2373c2b8 427 "\nFile system performance may be impared.\n");
aca50d72
KM
428 sblock.fs_cpc = 0;
429 goto next;
430 }
62f283da 431 sblock.fs_sbsize = fragroundup(&sblock, totalsbsize);
aca50d72
KM
432 /*
433 * calculate the available blocks for each rotational position
434 */
62f283da
KM
435 for (cylno = 0; cylno < sblock.fs_cpc; cylno++)
436 for (rpos = 0; rpos < sblock.fs_nrpos; rpos++)
437 fs_postbl(&sblock, cylno)[rpos] = -1;
438 for (i = (rotblsize - 1) * sblock.fs_frag;
439 i >= 0; i -= sblock.fs_frag) {
aca50d72
KM
440 cylno = cbtocylno(&sblock, i);
441 rpos = cbtorpos(&sblock, i);
62f283da
KM
442 blk = fragstoblks(&sblock, i);
443 if (fs_postbl(&sblock, cylno)[rpos] == -1)
444 fs_rotbl(&sblock)[blk] = 0;
aca50d72 445 else
62f283da
KM
446 fs_rotbl(&sblock)[blk] =
447 fs_postbl(&sblock, cylno)[rpos] - blk;
448 fs_postbl(&sblock, cylno)[rpos] = blk;
aca50d72
KM
449 }
450next:
d746d022
KM
451 /*
452 * Compute/validate number of cylinder groups.
453 */
454 sblock.fs_ncg = sblock.fs_ncyl / sblock.fs_cpg;
455 if (sblock.fs_ncyl % sblock.fs_cpg)
456 sblock.fs_ncg++;
aca50d72 457 sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock);
bf541624
KM
458 i = MIN(~sblock.fs_cgmask, sblock.fs_ncg - 1);
459 if (cgdmin(&sblock, i) - cgbase(&sblock, i) >= sblock.fs_fpg) {
d746d022 460 printf("inode blocks/cyl group (%d) >= data blocks (%d)\n",
bf541624 461 cgdmin(&sblock, i) - cgbase(&sblock, i) / sblock.fs_frag,
b6407c9d 462 sblock.fs_fpg / sblock.fs_frag);
7292dd7c 463 printf("number of cylinders per cylinder group (%d) %s.\n",
62f283da 464 sblock.fs_cpg, "must be increased");
b6407c9d
KM
465 exit(1);
466 }
bf541624
KM
467 j = sblock.fs_ncg - 1;
468 if ((i = fssize - j * sblock.fs_fpg) < sblock.fs_fpg &&
469 cgdmin(&sblock, j) - cgbase(&sblock, j) > i) {
470 printf("Warning: inode blocks/cyl group (%d) >= data blocks (%d) in last\n",
471 (cgdmin(&sblock, j) - cgbase(&sblock, j)) / sblock.fs_frag,
472 i / sblock.fs_frag);
473 printf(" cylinder group. This implies %d sector(s) cannot be allocated.\n",
474 i * NSPF(&sblock));
475 sblock.fs_ncg--;
476 sblock.fs_ncyl -= sblock.fs_ncyl % sblock.fs_cpg;
477 sblock.fs_size = fssize = sblock.fs_ncyl * sblock.fs_spc /
478 NSPF(&sblock);
479 warn = 0;
480 }
481 if (warn) {
482 printf("Warning: %d sector(s) in last cylinder unallocated\n",
483 sblock.fs_spc -
484 (fssize * NSPF(&sblock) - (sblock.fs_ncyl - 1)
485 * sblock.fs_spc));
486 }
2fd3d252
KM
487 /*
488 * fill in remaining fields of the super block
489 */
6994bf5d 490 sblock.fs_csaddr = cgdmin(&sblock, 0);
bf541624
KM
491 sblock.fs_cssize =
492 fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum));
19782540
KM
493 i = sblock.fs_bsize / sizeof(struct csum);
494 sblock.fs_csmask = ~(i - 1);
495 for (sblock.fs_csshift = 0; i > 1; i >>= 1)
496 sblock.fs_csshift++;
bf541624 497 fscs = (struct csum *)calloc(1, sblock.fs_cssize);
aca50d72 498 sblock.fs_magic = FS_MAGIC;
8485bb11
KM
499 sblock.fs_rotdelay = rotdelay;
500 sblock.fs_minfree = minfree;
501 sblock.fs_maxcontig = maxcontig;
a20edd44
KM
502 sblock.fs_headswitch = headswitch;
503 sblock.fs_trkseek = trackseek;
3d632f12 504 sblock.fs_maxbpg = maxbpg;
8485bb11
KM
505 sblock.fs_rps = rpm / 60;
506 sblock.fs_optim = opt;
2fd3d252
KM
507 sblock.fs_cgrotor = 0;
508 sblock.fs_cstotal.cs_ndir = 0;
509 sblock.fs_cstotal.cs_nbfree = 0;
510 sblock.fs_cstotal.cs_nifree = 0;
511 sblock.fs_cstotal.cs_nffree = 0;
d746d022
KM
512 sblock.fs_fmod = 0;
513 sblock.fs_ronly = 0;
d746d022 514 /*
2fd3d252 515 * Dump out summary information about file system.
d746d022
KM
516 */
517 printf("%s:\t%d sectors in %d cylinders of %d tracks, %d sectors\n",
2fd3d252 518 fsys, sblock.fs_size * NSPF(&sblock), sblock.fs_ncyl,
b6407c9d 519 sblock.fs_ntrak, sblock.fs_nsect);
d746d022 520 printf("\t%.1fMb in %d cyl groups (%d c/g, %.2fMb/g, %d i/g)\n",
b6407c9d
KM
521 (float)sblock.fs_size * sblock.fs_fsize * 1e-6, sblock.fs_ncg,
522 sblock.fs_cpg, (float)sblock.fs_fpg * sblock.fs_fsize * 1e-6,
523 sblock.fs_ipg);
d746d022
KM
524 /*
525 * Now build the cylinders group blocks and
2fd3d252 526 * then print out indices of cylinder groups.
d746d022 527 */
62f283da 528 printf("super-block backups (for fsck -b #) at:");
bf541624 529 for (cylno = 0; cylno < sblock.fs_ncg; cylno++) {
aca50d72 530 initcg(cylno);
7292dd7c 531 if (cylno % 9 == 0)
bf541624
KM
532 printf("\n");
533 printf(" %d,", fsbtodb(&sblock, cgsblock(&sblock, cylno)));
534 }
4f38a6d0 535 printf("\n");
56a085eb
KM
536 if (Nflag)
537 exit(0);
d746d022 538 /*
2fd3d252 539 * Now construct the initial file system,
d746d022
KM
540 * then write out the super-block.
541 */
2fd3d252 542 fsinit();
d746d022 543 sblock.fs_time = utime;
c5d3fd78 544 wtfs(SBOFF / sectorsize, sbsize, (char *)&sblock);
b6407c9d 545 for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize)
3352e84a 546 wtfs(fsbtodb(&sblock, sblock.fs_csaddr + numfrags(&sblock, i)),
bf541624
KM
547 sblock.fs_cssize - i < sblock.fs_bsize ?
548 sblock.fs_cssize - i : sblock.fs_bsize,
549 ((char *)fscs) + i);
2fd3d252
KM
550 /*
551 * Write out the duplicate super blocks
552 */
c2b9e883 553 for (cylno = 0; cylno < sblock.fs_ncg; cylno++)
bf541624 554 wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)),
c5d3fd78 555 sbsize, (char *)&sblock);
8485bb11
KM
556 /*
557 * Update information about this partion in pack
558 * label, to that it may be updated on disk.
559 */
560 pp->p_fstype = FS_BSDFFS;
561 pp->p_fsize = sblock.fs_fsize;
562 pp->p_frag = sblock.fs_frag;
563 pp->p_cpg = sblock.fs_cpg;
d746d022
KM
564}
565
566/*
567 * Initialize a cylinder group.
568 */
aca50d72
KM
569initcg(cylno)
570 int cylno;
d746d022 571{
bf541624 572 daddr_t cbase, d, dlower, dupper, dmax;
d746d022
KM
573 long i, j, s;
574 register struct csum *cs;
575
576 /*
577 * Determine block bounds for cylinder group.
578 * Allow space for super block summary information in first
579 * cylinder group.
580 */
6994bf5d 581 cbase = cgbase(&sblock, cylno);
d746d022
KM
582 dmax = cbase + sblock.fs_fpg;
583 if (dmax > sblock.fs_size)
584 dmax = sblock.fs_size;
bf541624
KM
585 dlower = cgsblock(&sblock, cylno) - cbase;
586 dupper = cgdmin(&sblock, cylno) - cbase;
62f283da
KM
587 if (cylno == 0)
588 dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
aca50d72 589 cs = fscs + cylno;
d746d022
KM
590 acg.cg_time = utime;
591 acg.cg_magic = CG_MAGIC;
aca50d72 592 acg.cg_cgx = cylno;
bb40745e
KM
593 if (cylno == sblock.fs_ncg - 1)
594 acg.cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg;
595 else
596 acg.cg_ncyl = sblock.fs_cpg;
d746d022
KM
597 acg.cg_niblk = sblock.fs_ipg;
598 acg.cg_ndblk = dmax - cbase;
0947395d
KM
599 acg.cg_cs.cs_ndir = 0;
600 acg.cg_cs.cs_nffree = 0;
601 acg.cg_cs.cs_nbfree = 0;
602 acg.cg_cs.cs_nifree = 0;
bf541624
KM
603 acg.cg_rotor = 0;
604 acg.cg_frotor = 0;
92ea6158 605 acg.cg_irotor = 0;
62f283da
KM
606 acg.cg_btotoff = &acg.cg_space[0] - (u_char *)(&acg.cg_link);
607 acg.cg_boff = acg.cg_btotoff + sblock.fs_cpg * sizeof(long);
608 acg.cg_iusedoff = acg.cg_boff +
609 sblock.fs_cpg * sblock.fs_nrpos * sizeof(short);
610 acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, NBBY);
611 acg.cg_nextfreeoff = acg.cg_freeoff +
612 howmany(sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock), NBBY);
b6407c9d 613 for (i = 0; i < sblock.fs_frag; i++) {
f3c028b7
KM
614 acg.cg_frsum[i] = 0;
615 }
62f283da
KM
616 bzero((caddr_t)cg_inosused(&acg), acg.cg_freeoff - acg.cg_iusedoff);
617 acg.cg_cs.cs_nifree += sblock.fs_ipg;
aca50d72 618 if (cylno == 0)
2fd3d252 619 for (i = 0; i < ROOTINO; i++) {
62f283da 620 setbit(cg_inosused(&acg), i);
2fd3d252
KM
621 acg.cg_cs.cs_nifree--;
622 }
62f283da
KM
623 for (i = 0; i < sblock.fs_ipg / INOPF(&sblock); i += sblock.fs_frag)
624 wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i),
625 sblock.fs_bsize, (char *)zino);
626 bzero((caddr_t)cg_blktot(&acg), acg.cg_boff - acg.cg_btotoff);
627 bzero((caddr_t)cg_blks(&sblock, &acg, 0),
628 acg.cg_iusedoff - acg.cg_boff);
629 bzero((caddr_t)cg_blksfree(&acg), acg.cg_nextfreeoff - acg.cg_freeoff);
630 if (cylno > 0) {
bf541624 631 /*
62f283da
KM
632 * In cylno 0, beginning space is reserved
633 * for boot and super blocks.
bf541624 634 */
bf541624 635 for (d = 0; d < dlower; d += sblock.fs_frag) {
62f283da 636 setblock(&sblock, cg_blksfree(&acg), d/sblock.fs_frag);
bf541624 637 acg.cg_cs.cs_nbfree++;
62f283da
KM
638 cg_blktot(&acg)[cbtocylno(&sblock, d)]++;
639 cg_blks(&sblock, &acg, cbtocylno(&sblock, d))
640 [cbtorpos(&sblock, d)]++;
bf541624
KM
641 }
642 sblock.fs_dsize += dlower;
d746d022 643 }
bf541624 644 sblock.fs_dsize += acg.cg_ndblk - dupper;
62f283da
KM
645 if (i = dupper % sblock.fs_frag) {
646 acg.cg_frsum[sblock.fs_frag - i]++;
647 for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) {
648 setbit(cg_blksfree(&acg), dupper);
bf541624
KM
649 acg.cg_cs.cs_nffree++;
650 }
651 }
62f283da
KM
652 for (d = dupper; d + sblock.fs_frag <= dmax - cbase; ) {
653 setblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag);
0947395d 654 acg.cg_cs.cs_nbfree++;
62f283da
KM
655 cg_blktot(&acg)[cbtocylno(&sblock, d)]++;
656 cg_blks(&sblock, &acg, cbtocylno(&sblock, d))
657 [cbtorpos(&sblock, d)]++;
b6407c9d 658 d += sblock.fs_frag;
d746d022 659 }
bf541624 660 if (d < dmax - cbase) {
aca50d72 661 acg.cg_frsum[dmax - cbase - d]++;
56d45dcd 662 for (; d < dmax - cbase; d++) {
62f283da 663 setbit(cg_blksfree(&acg), d);
0947395d 664 acg.cg_cs.cs_nffree++;
56d45dcd 665 }
bf541624 666 }
0947395d
KM
667 sblock.fs_cstotal.cs_ndir += acg.cg_cs.cs_ndir;
668 sblock.fs_cstotal.cs_nffree += acg.cg_cs.cs_nffree;
669 sblock.fs_cstotal.cs_nbfree += acg.cg_cs.cs_nbfree;
670 sblock.fs_cstotal.cs_nifree += acg.cg_cs.cs_nifree;
671 *cs = acg.cg_cs;
6994bf5d 672 wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)),
b6407c9d 673 sblock.fs_bsize, (char *)&acg);
d746d022
KM
674}
675
2fd3d252
KM
676/*
677 * initialize the file system
678 */
679struct inode node;
8485bb11
KM
680
681#ifdef LOSTDIR
2fd3d252 682#define PREDEFDIR 3
8485bb11
KM
683#else
684#define PREDEFDIR 2
685#endif
686
052efd62
KM
687struct direct root_dir[] = {
688 { ROOTINO, sizeof(struct direct), 1, "." },
689 { ROOTINO, sizeof(struct direct), 2, ".." },
8485bb11 690#ifdef LOSTDIR
052efd62 691 { LOSTFOUNDINO, sizeof(struct direct), 10, "lost+found" },
8485bb11 692#endif
2fd3d252 693};
8485bb11 694#ifdef LOSTDIR
052efd62
KM
695struct direct lost_found_dir[] = {
696 { LOSTFOUNDINO, sizeof(struct direct), 1, "." },
697 { ROOTINO, sizeof(struct direct), 2, ".." },
698 { 0, DIRBLKSIZ, 0, 0 },
2fd3d252 699};
8485bb11 700#endif
052efd62 701char buf[MAXBSIZE];
2fd3d252
KM
702
703fsinit()
d746d022 704{
052efd62
KM
705 int i;
706
d746d022 707 /*
2fd3d252 708 * initialize the node
d746d022 709 */
2fd3d252
KM
710 node.i_atime = utime;
711 node.i_mtime = utime;
712 node.i_ctime = utime;
8485bb11 713#ifdef LOSTDIR
d746d022 714 /*
2fd3d252 715 * create the lost+found directory
d746d022 716 */
052efd62
KM
717 (void)makedir(lost_found_dir, 2);
718 for (i = DIRBLKSIZ; i < sblock.fs_bsize; i += DIRBLKSIZ)
719 bcopy(&lost_found_dir[2], &buf[i], DIRSIZ(&lost_found_dir[2]));
2fd3d252
KM
720 node.i_number = LOSTFOUNDINO;
721 node.i_mode = IFDIR | UMASK;
722 node.i_nlink = 2;
723 node.i_size = sblock.fs_bsize;
724 node.i_db[0] = alloc(node.i_size, node.i_mode);
cdbcf1b5 725 node.i_blocks = btodb(fragroundup(&sblock, node.i_size));
052efd62 726 wtfs(fsbtodb(&sblock, node.i_db[0]), node.i_size, buf);
2fd3d252 727 iput(&node);
8485bb11 728#endif
2fd3d252
KM
729 /*
730 * create the root directory
731 */
732 node.i_number = ROOTINO;
733 node.i_mode = IFDIR | UMASK;
734 node.i_nlink = PREDEFDIR;
052efd62 735 node.i_size = makedir(root_dir, PREDEFDIR);
2fd3d252 736 node.i_db[0] = alloc(sblock.fs_fsize, node.i_mode);
cdbcf1b5 737 node.i_blocks = btodb(fragroundup(&sblock, node.i_size));
052efd62 738 wtfs(fsbtodb(&sblock, node.i_db[0]), sblock.fs_fsize, buf);
2fd3d252 739 iput(&node);
d746d022
KM
740}
741
052efd62
KM
742/*
743 * construct a set of directory entries in "buf".
744 * return size of directory.
745 */
746makedir(protodir, entries)
747 register struct direct *protodir;
748 int entries;
749{
750 char *cp;
751 int i, spcleft;
752
753 spcleft = DIRBLKSIZ;
754 for (cp = buf, i = 0; i < entries - 1; i++) {
755 protodir[i].d_reclen = DIRSIZ(&protodir[i]);
756 bcopy(&protodir[i], cp, protodir[i].d_reclen);
757 cp += protodir[i].d_reclen;
758 spcleft -= protodir[i].d_reclen;
759 }
760 protodir[i].d_reclen = spcleft;
761 bcopy(&protodir[i], cp, DIRSIZ(&protodir[i]));
4b47cead 762 return (DIRBLKSIZ);
052efd62
KM
763}
764
2fd3d252
KM
765/*
766 * allocate a block or frag
767 */
d746d022 768daddr_t
07670f7d
KM
769alloc(size, mode)
770 int size;
771 int mode;
d746d022 772{
aca50d72 773 int i, frag;
d746d022
KM
774 daddr_t d;
775
3352e84a
KM
776 rdfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
777 (char *)&acg);
bf541624
KM
778 if (acg.cg_magic != CG_MAGIC) {
779 printf("cg 0: bad magic number\n");
780 return (0);
781 }
0947395d 782 if (acg.cg_cs.cs_nbfree == 0) {
d746d022
KM
783 printf("first cylinder group ran out of space\n");
784 return (0);
785 }
b6407c9d 786 for (d = 0; d < acg.cg_ndblk; d += sblock.fs_frag)
62f283da 787 if (isblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag))
d746d022
KM
788 goto goth;
789 printf("internal error: can't find block in cyl 0\n");
790 return (0);
791goth:
62f283da 792 clrblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag);
0947395d
KM
793 acg.cg_cs.cs_nbfree--;
794 sblock.fs_cstotal.cs_nbfree--;
d746d022 795 fscs[0].cs_nbfree--;
07670f7d 796 if (mode & IFDIR) {
0947395d
KM
797 acg.cg_cs.cs_ndir++;
798 sblock.fs_cstotal.cs_ndir++;
07670f7d
KM
799 fscs[0].cs_ndir++;
800 }
62f283da
KM
801 cg_blktot(&acg)[cbtocylno(&sblock, d)]--;
802 cg_blks(&sblock, &acg, cbtocylno(&sblock, d))[cbtorpos(&sblock, d)]--;
b6407c9d
KM
803 if (size != sblock.fs_bsize) {
804 frag = howmany(size, sblock.fs_fsize);
805 fscs[0].cs_nffree += sblock.fs_frag - frag;
806 sblock.fs_cstotal.cs_nffree += sblock.fs_frag - frag;
807 acg.cg_cs.cs_nffree += sblock.fs_frag - frag;
808 acg.cg_frsum[sblock.fs_frag - frag]++;
809 for (i = frag; i < sblock.fs_frag; i++)
62f283da 810 setbit(cg_blksfree(&acg), d + i);
d746d022 811 }
3352e84a
KM
812 wtfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
813 (char *)&acg);
d746d022
KM
814 return (d);
815}
816
2fd3d252
KM
817/*
818 * Allocate an inode on the disk
819 */
820iput(ip)
821 register struct inode *ip;
d746d022 822{
2fd3d252 823 struct dinode buf[MAXINOPB];
d746d022 824 daddr_t d;
2fd3d252 825 int c;
d746d022 826
6994bf5d 827 c = itog(&sblock, ip->i_number);
3352e84a
KM
828 rdfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
829 (char *)&acg);
bf541624
KM
830 if (acg.cg_magic != CG_MAGIC) {
831 printf("cg 0: bad magic number\n");
832 exit(1);
833 }
0947395d 834 acg.cg_cs.cs_nifree--;
62f283da 835 setbit(cg_inosused(&acg), ip->i_number);
3352e84a
KM
836 wtfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
837 (char *)&acg);
0947395d 838 sblock.fs_cstotal.cs_nifree--;
d746d022 839 fscs[0].cs_nifree--;
62f283da 840 if (ip->i_number >= sblock.fs_ipg * sblock.fs_ncg) {
2fd3d252
KM
841 printf("fsinit: inode value out of range (%d).\n",
842 ip->i_number);
843 exit(1);
d746d022 844 }
6994bf5d 845 d = fsbtodb(&sblock, itod(&sblock, ip->i_number));
2fd3d252 846 rdfs(d, sblock.fs_bsize, buf);
6994bf5d 847 buf[itoo(&sblock, ip->i_number)].di_ic = ip->i_ic;
2fd3d252
KM
848 wtfs(d, sblock.fs_bsize, buf);
849}
850
851/*
852 * read a block from the file system
853 */
854rdfs(bno, size, bf)
855 daddr_t bno;
856 int size;
857 char *bf;
858{
859 int n;
860
8485bb11 861 if (lseek(fsi, bno * sectorsize, 0) < 0) {
c312eebd
KM
862 printf("seek error: %ld\n", bno);
863 perror("rdfs");
864 exit(1);
865 }
2fd3d252
KM
866 n = read(fsi, bf, size);
867 if(n != size) {
868 printf("read error: %ld\n", bno);
c312eebd 869 perror("rdfs");
2fd3d252 870 exit(1);
b6407c9d 871 }
b6407c9d
KM
872}
873
874/*
2fd3d252 875 * write a block to the file system
b6407c9d 876 */
2fd3d252
KM
877wtfs(bno, size, bf)
878 daddr_t bno;
879 int size;
880 char *bf;
881{
882 int n;
883
56a085eb
KM
884 if (Nflag)
885 return;
8485bb11 886 if (lseek(fso, bno * sectorsize, 0) < 0) {
c312eebd
KM
887 printf("seek error: %ld\n", bno);
888 perror("wtfs");
889 exit(1);
890 }
2fd3d252
KM
891 n = write(fso, bf, size);
892 if(n != size) {
893 printf("write error: %D\n", bno);
c312eebd 894 perror("wtfs");
2fd3d252
KM
895 exit(1);
896 }
897}
b6407c9d 898
2fd3d252
KM
899/*
900 * check if a block is available
901 */
b6407c9d
KM
902isblock(fs, cp, h)
903 struct fs *fs;
904 unsigned char *cp;
905 int h;
906{
907 unsigned char mask;
908
909 switch (fs->fs_frag) {
910 case 8:
911 return (cp[h] == 0xff);
912 case 4:
913 mask = 0x0f << ((h & 0x1) << 2);
914 return ((cp[h >> 1] & mask) == mask);
915 case 2:
916 mask = 0x03 << ((h & 0x3) << 1);
917 return ((cp[h >> 2] & mask) == mask);
918 case 1:
919 mask = 0x01 << (h & 0x7);
920 return ((cp[h >> 3] & mask) == mask);
921 default:
4384e5a5
KM
922#ifdef STANDALONE
923 printf("isblock bad fs_frag %d\n", fs->fs_frag);
924#else
b6407c9d 925 fprintf(stderr, "isblock bad fs_frag %d\n", fs->fs_frag);
4384e5a5 926#endif
edc611b2 927 return (0);
b6407c9d
KM
928 }
929}
930
2fd3d252
KM
931/*
932 * take a block out of the map
933 */
b6407c9d
KM
934clrblock(fs, cp, h)
935 struct fs *fs;
936 unsigned char *cp;
937 int h;
938{
939 switch ((fs)->fs_frag) {
940 case 8:
941 cp[h] = 0;
942 return;
943 case 4:
944 cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
945 return;
946 case 2:
947 cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
948 return;
949 case 1:
950 cp[h >> 3] &= ~(0x01 << (h & 0x7));
951 return;
952 default:
4384e5a5
KM
953#ifdef STANDALONE
954 printf("clrblock bad fs_frag %d\n", fs->fs_frag);
955#else
b6407c9d 956 fprintf(stderr, "clrblock bad fs_frag %d\n", fs->fs_frag);
4384e5a5 957#endif
b6407c9d
KM
958 return;
959 }
960}
961
2fd3d252
KM
962/*
963 * put a block into the map
964 */
b6407c9d
KM
965setblock(fs, cp, h)
966 struct fs *fs;
967 unsigned char *cp;
968 int h;
969{
970 switch (fs->fs_frag) {
971 case 8:
972 cp[h] = 0xff;
973 return;
974 case 4:
975 cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
976 return;
977 case 2:
978 cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
979 return;
980 case 1:
981 cp[h >> 3] |= (0x01 << (h & 0x7));
982 return;
983 default:
4384e5a5
KM
984#ifdef STANDALONE
985 printf("setblock bad fs_frag %d\n", fs->fs_frag);
986#else
b6407c9d 987 fprintf(stderr, "setblock bad fs_frag %d\n", fs->fs_frag);
4384e5a5 988#endif
b6407c9d 989 return;
d746d022 990 }
d746d022 991}