2 * Copyright (c) 1980, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * @(#)mkfs.c 8.11 (Berkeley) 5/3/95
34 * $FreeBSD: src/sbin/newfs/mkfs.c,v 1.29.2.6 2001/09/21 19:15:21 dillon Exp $
35 * $DragonFly: src/sbin/newfs/mkfs.c,v 1.13 2006/08/13 20:55:12 swildner Exp $
44 extern int atoi(char *);
45 extern char * getenv(char *);
48 extern long random(void);
49 extern void srandomdev(void);
52 #endif /* STANDALONE */
55 * make file system for cylinder-group style file systems
59 * We limit the size of the inode map to be no more than a
60 * third of the cylinder group space, since we must leave at
61 * least an equal amount of space for the block map.
63 * N.B.: MAXIPG must be a multiple of INOPB(fs).
65 #define MAXIPG(fs) roundup((fs)->fs_bsize * NBBY / 3, INOPB(fs))
68 #define MAXINOPB (MAXBSIZE / sizeof(struct ufs1_dinode))
69 #define POWEROF2(num) (((num) & ((num) - 1)) == 0)
72 * variables set up by front end.
74 extern int mfs
; /* run as the memory based filesystem */
75 extern char *mfs_mtpt
; /* mount point for mfs */
76 extern struct stat mfs_mtstat
; /* stat prior to mount */
77 extern int Nflag
; /* run mkfs without writing file system */
78 extern int Oflag
; /* format as an 4.3BSD file system */
79 extern int Uflag
; /* enable soft updates for file system */
80 extern int fssize
; /* file system size */
81 extern int ntracks
; /* # tracks/cylinder */
82 extern int nsectors
; /* # sectors/track */
83 extern int nphyssectors
; /* # sectors/track including spares */
84 extern int secpercyl
; /* sectors per cylinder */
85 extern int sectorsize
; /* bytes/sector */
86 extern int realsectorsize
; /* bytes/sector in hardware*/
87 extern int rpm
; /* revolutions/minute of drive */
88 extern int interleave
; /* hardware sector interleave */
89 extern int trackskew
; /* sector 0 skew, per track */
90 extern int fsize
; /* fragment size */
91 extern int bsize
; /* block size */
92 extern int cpg
; /* cylinders/cylinder group */
93 extern int cpgflg
; /* cylinders/cylinder group flag was given */
94 extern int minfree
; /* free space threshold */
95 extern int opt
; /* optimization preference (space or time) */
96 extern int density
; /* number of bytes per inode */
97 extern int maxcontig
; /* max contiguous blocks to allocate */
98 extern int rotdelay
; /* rotational delay between blocks */
99 extern int maxbpg
; /* maximum blocks per file in a cyl group */
100 extern int nrpos
; /* # of distinguished rotational positions */
101 extern int bbsize
; /* boot block size */
102 extern int sbsize
; /* superblock size */
103 extern int avgfilesize
; /* expected average file size */
104 extern int avgfilesperdir
; /* expected number of files per directory */
105 extern u_long memleft
; /* virtual memory available */
106 extern caddr_t membase
; /* start address of memory based filesystem */
107 extern char * filename
;
109 extern void fatal(const char *fmt
, ...);
115 #define sblock fsun.fs
124 struct ufs1_dinode zino
[MAXBSIZE
/ sizeof(struct ufs1_dinode
)];
127 static fsnode_t copyroot
;
128 static fsnode_t copyhlinks
;
132 daddr_t
alloc(int, int);
133 long calcipg(long, long, off_t
*);
134 static int charsperline(void);
135 void clrblock(struct fs
*, unsigned char *, int);
137 void initcg(int, time_t);
138 int isblock(struct fs
*, unsigned char *, int);
139 void iput(struct ufs1_dinode
*, ino_t
);
140 int makedir(struct direct
*, int);
141 void parentready(int);
142 void rdfs(daddr_t
, int, char *);
143 void setblock(struct fs
*, unsigned char *, int);
145 void wtfs(daddr_t
, int, char *);
146 void wtfsflush(void);
149 void get_memleft(void);
150 void raise_data_limit(void);
153 char * calloc(u_long
, u_long
);
154 caddr_t
malloc(u_long
);
155 caddr_t
realloc(char *, u_long
);
159 int parentready_signalled
;
162 mkfs(struct partition
*pp
, char *fsys
, int fi
, int fo
, const char *mfscopy
)
164 long i
, mincpc
, mincpg
, inospercg
;
165 long cylno
, rpos
, blk
, j
, emitwarn
= 0;
166 long used
, mincpgcnt
, bpcg
;
168 long mapcramped
, inodecramped
;
169 long postblsize
, rotblsize
, totalsbsize
;
174 char tmpbuf
[100]; /* XXX this will break in about 2,500 years */
190 signal(SIGUSR1
, parentready
);
191 if ((child
= fork()) != 0) {
195 copyroot
= FSCopy(©hlinks
, mfscopy
);
196 signal(SIGUSR1
, started
);
197 kill(child
, SIGUSR1
);
198 if (waitpid(child
, &status
, 0) != -1 && WIFEXITED(status
))
199 exit(WEXITSTATUS(status
));
203 omask
= sigblock(1 << SIGUSR1
);
204 while (parentready_signalled
== 0)
205 sigpause(1 << SIGUSR1
);
212 if (filename
!= NULL
) {
213 unsigned char buf
[BUFSIZ
];
217 fd
= open(filename
, O_RDWR
|O_TRUNC
|O_CREAT
, 0644);
219 err(12, "%s", filename
);
220 l1
= fssize
* sectorsize
;
223 for (l
= 0; l
< (u_long
)fssize
* (u_long
)sectorsize
; l
+= l1
) {
224 w
= write(fd
, buf
, l1
);
225 if (w
< 0 || (u_long
)w
!= l1
)
226 err(12, "%s", filename
);
231 PROT_READ
|PROT_WRITE
,
235 if(membase
== MAP_FAILED
)
242 if ((u_long
)fssize
* (u_long
)sectorsize
>
244 fssize
= (memleft
- 131072) / sectorsize
;
245 if ((membase
= malloc(fssize
* sectorsize
)) == NULL
)
246 errx(13, "malloc failed");
252 sblock
.fs_inodefmt
= FS_42INODEFMT
;
253 sblock
.fs_maxsymlinklen
= 0;
255 sblock
.fs_inodefmt
= FS_44INODEFMT
;
256 sblock
.fs_maxsymlinklen
= MAXSYMLINKLEN
;
259 sblock
.fs_flags
|= FS_DOSOFTDEP
;
261 * Validate the given file system size.
262 * Verify that its last block can actually be accessed.
265 printf("preposterous size %d\n", fssize
), exit(13);
266 wtfs(fssize
- (realsectorsize
/ DEV_BSIZE
), realsectorsize
,
269 * collect and verify the sector and track info
271 sblock
.fs_nsect
= nsectors
;
272 sblock
.fs_ntrak
= ntracks
;
273 if (sblock
.fs_ntrak
<= 0)
274 printf("preposterous ntrak %d\n", sblock
.fs_ntrak
), exit(14);
275 if (sblock
.fs_nsect
<= 0)
276 printf("preposterous nsect %d\n", sblock
.fs_nsect
), exit(15);
278 * collect and verify the filesystem density info
280 sblock
.fs_avgfilesize
= avgfilesize
;
281 sblock
.fs_avgfpdir
= avgfilesperdir
;
282 if (sblock
.fs_avgfilesize
<= 0)
283 printf("illegal expected average file size %d\n",
284 sblock
.fs_avgfilesize
), exit(14);
285 if (sblock
.fs_avgfpdir
<= 0)
286 printf("illegal expected number of files per directory %d\n",
287 sblock
.fs_avgfpdir
), exit(15);
289 * collect and verify the block and fragment sizes
291 sblock
.fs_bsize
= bsize
;
292 sblock
.fs_fsize
= fsize
;
293 if (!POWEROF2(sblock
.fs_bsize
)) {
294 printf("block size must be a power of 2, not %d\n",
298 if (!POWEROF2(sblock
.fs_fsize
)) {
299 printf("fragment size must be a power of 2, not %d\n",
303 if (sblock
.fs_fsize
< sectorsize
) {
304 printf("fragment size %d is too small, minimum is %d\n",
305 sblock
.fs_fsize
, sectorsize
);
308 if (sblock
.fs_bsize
< MINBSIZE
) {
309 printf("block size %d is too small, minimum is %d\n",
310 sblock
.fs_bsize
, MINBSIZE
);
313 if (sblock
.fs_bsize
< sblock
.fs_fsize
) {
314 printf("block size (%d) cannot be smaller than fragment size (%d)\n",
315 sblock
.fs_bsize
, sblock
.fs_fsize
);
318 sblock
.fs_bmask
= ~(sblock
.fs_bsize
- 1);
319 sblock
.fs_fmask
= ~(sblock
.fs_fsize
- 1);
320 sblock
.fs_qbmask
= ~sblock
.fs_bmask
;
321 sblock
.fs_qfmask
= ~sblock
.fs_fmask
;
322 for (sblock
.fs_bshift
= 0, i
= sblock
.fs_bsize
; i
> 1; i
>>= 1)
324 for (sblock
.fs_fshift
= 0, i
= sblock
.fs_fsize
; i
> 1; i
>>= 1)
326 sblock
.fs_frag
= numfrags(&sblock
, sblock
.fs_bsize
);
327 for (sblock
.fs_fragshift
= 0, i
= sblock
.fs_frag
; i
> 1; i
>>= 1)
328 sblock
.fs_fragshift
++;
329 if (sblock
.fs_frag
> MAXFRAG
) {
330 printf("fragment size %d is too small, minimum with block size %d is %d\n",
331 sblock
.fs_fsize
, sblock
.fs_bsize
,
332 sblock
.fs_bsize
/ MAXFRAG
);
335 sblock
.fs_nrpos
= nrpos
;
336 sblock
.fs_nindir
= sblock
.fs_bsize
/ sizeof(daddr_t
);
337 sblock
.fs_inopb
= sblock
.fs_bsize
/ sizeof(struct ufs1_dinode
);
338 sblock
.fs_nspf
= sblock
.fs_fsize
/ sectorsize
;
339 for (sblock
.fs_fsbtodb
= 0, i
= NSPF(&sblock
); i
> 1; i
>>= 1)
342 roundup(howmany(bbsize
+ sbsize
, sblock
.fs_fsize
), sblock
.fs_frag
);
343 sblock
.fs_cblkno
= (daddr_t
)(sblock
.fs_sblkno
+
344 roundup(howmany(sbsize
, sblock
.fs_fsize
), sblock
.fs_frag
));
345 sblock
.fs_iblkno
= sblock
.fs_cblkno
+ sblock
.fs_frag
;
346 sblock
.fs_cgoffset
= roundup(
347 howmany(sblock
.fs_nsect
, NSPF(&sblock
)), sblock
.fs_frag
);
348 for (sblock
.fs_cgmask
= 0xffffffff, i
= sblock
.fs_ntrak
; i
> 1; i
>>= 1)
349 sblock
.fs_cgmask
<<= 1;
350 if (!POWEROF2(sblock
.fs_ntrak
))
351 sblock
.fs_cgmask
<<= 1;
352 sblock
.fs_maxfilesize
= sblock
.fs_bsize
* NDADDR
- 1;
353 for (sizepb
= sblock
.fs_bsize
, i
= 0; i
< NIADDR
; i
++) {
354 sizepb
*= NINDIR(&sblock
);
355 sblock
.fs_maxfilesize
+= sizepb
;
358 * Validate specified/determined secpercyl
359 * and calculate minimum cylinders per group.
361 sblock
.fs_spc
= secpercyl
;
362 for (sblock
.fs_cpc
= NSPB(&sblock
), i
= sblock
.fs_spc
;
363 sblock
.fs_cpc
> 1 && (i
& 1) == 0;
364 sblock
.fs_cpc
>>= 1, i
>>= 1)
366 mincpc
= sblock
.fs_cpc
;
367 bpcg
= sblock
.fs_spc
* sectorsize
;
368 inospercg
= roundup(bpcg
/ sizeof(struct ufs1_dinode
), INOPB(&sblock
));
369 if (inospercg
> MAXIPG(&sblock
))
370 inospercg
= MAXIPG(&sblock
);
371 used
= (sblock
.fs_iblkno
+ inospercg
/ INOPF(&sblock
)) * NSPF(&sblock
);
372 mincpgcnt
= howmany(sblock
.fs_cgoffset
* (~sblock
.fs_cgmask
) + used
,
374 mincpg
= roundup(mincpgcnt
, mincpc
);
376 * Ensure that cylinder group with mincpg has enough space
379 sblock
.fs_cpg
= mincpg
;
380 sblock
.fs_ipg
= inospercg
;
382 sblock
.fs_contigsumsize
= MIN(maxcontig
, FS_MAXCONTIG
);
384 while (CGSIZE(&sblock
) > (uint32_t)sblock
.fs_bsize
) {
386 if (sblock
.fs_bsize
< MAXBSIZE
) {
387 sblock
.fs_bsize
<<= 1;
393 mincpg
= roundup(mincpgcnt
, mincpc
);
394 sblock
.fs_cpg
= mincpg
;
396 sblock
.fs_frag
<<= 1;
397 sblock
.fs_fragshift
+= 1;
398 if (sblock
.fs_frag
<= MAXFRAG
)
401 if (sblock
.fs_fsize
== sblock
.fs_bsize
) {
402 printf("There is no block size that");
403 printf(" can support this disk\n");
406 sblock
.fs_frag
>>= 1;
407 sblock
.fs_fragshift
-= 1;
408 sblock
.fs_fsize
<<= 1;
409 sblock
.fs_nspf
<<= 1;
412 * Ensure that cylinder group with mincpg has enough space for inodes.
415 inospercg
= calcipg(mincpg
, bpcg
, &usedb
);
416 sblock
.fs_ipg
= inospercg
;
417 while (inospercg
> MAXIPG(&sblock
)) {
419 if (mincpc
== 1 || sblock
.fs_frag
== 1 ||
420 sblock
.fs_bsize
== MINBSIZE
)
422 printf("With a block size of %d %s %d\n", sblock
.fs_bsize
,
423 "minimum bytes per inode is",
424 (int)((mincpg
* (off_t
)bpcg
- usedb
)
425 / MAXIPG(&sblock
) + 1));
426 sblock
.fs_bsize
>>= 1;
427 sblock
.fs_frag
>>= 1;
428 sblock
.fs_fragshift
-= 1;
430 sblock
.fs_cpg
= roundup(mincpgcnt
, mincpc
);
431 if (CGSIZE(&sblock
) > (uint32_t)sblock
.fs_bsize
) {
432 sblock
.fs_bsize
<<= 1;
435 mincpg
= sblock
.fs_cpg
;
436 inospercg
= calcipg(mincpg
, bpcg
, &usedb
);
437 sblock
.fs_ipg
= inospercg
;
440 if (inospercg
> MAXIPG(&sblock
)) {
441 printf("Minimum bytes per inode is %d\n",
442 (int)((mincpg
* (off_t
)bpcg
- usedb
)
443 / MAXIPG(&sblock
) + 1));
444 } else if (!mapcramped
) {
445 printf("With %d bytes per inode, ", density
);
446 printf("minimum cylinders per group is %ld\n", mincpg
);
450 printf("With %d sectors per cylinder, ", sblock
.fs_spc
);
451 printf("minimum cylinders per group is %ld\n", mincpg
);
453 if (inodecramped
|| mapcramped
) {
454 if (sblock
.fs_bsize
!= bsize
)
455 printf("%s to be changed from %d to %d\n",
456 "This requires the block size",
457 bsize
, sblock
.fs_bsize
);
458 if (sblock
.fs_fsize
!= fsize
)
459 printf("\t%s to be changed from %d to %d\n",
460 "and the fragment size",
461 fsize
, sblock
.fs_fsize
);
465 * Calculate the number of cylinders per group
468 if (sblock
.fs_cpg
% mincpc
!= 0) {
469 printf("%s groups must have a multiple of %ld cylinders\n",
470 cpgflg
? "Cylinder" : "Warning: cylinder", mincpc
);
471 sblock
.fs_cpg
= roundup(sblock
.fs_cpg
, mincpc
);
476 * Must ensure there is enough space for inodes.
478 sblock
.fs_ipg
= calcipg(sblock
.fs_cpg
, bpcg
, &usedb
);
479 while (sblock
.fs_ipg
> MAXIPG(&sblock
)) {
481 sblock
.fs_cpg
-= mincpc
;
482 sblock
.fs_ipg
= calcipg(sblock
.fs_cpg
, bpcg
, &usedb
);
485 * Must ensure there is enough space to hold block map.
487 while (CGSIZE(&sblock
) > (uint32_t)sblock
.fs_bsize
) {
489 sblock
.fs_cpg
-= mincpc
;
490 sblock
.fs_ipg
= calcipg(sblock
.fs_cpg
, bpcg
, &usedb
);
492 sblock
.fs_fpg
= (sblock
.fs_cpg
* sblock
.fs_spc
) / NSPF(&sblock
);
493 if ((sblock
.fs_cpg
* sblock
.fs_spc
) % NSPB(&sblock
) != 0) {
494 printf("panic (fs_cpg * fs_spc) %% NSPF != 0");
497 if (sblock
.fs_cpg
< mincpg
) {
498 printf("cylinder groups must have at least %ld cylinders\n",
501 } else if (sblock
.fs_cpg
!= cpg
) {
504 else if (!mapcramped
&& !inodecramped
)
507 if (mapcramped
&& inodecramped
)
508 printf("Block size and bytes per inode restrict");
510 printf("Block size restricts");
512 printf("Bytes per inode restrict");
513 printf(" cylinders per group to %d.\n", sblock
.fs_cpg
);
518 sblock
.fs_cgsize
= fragroundup(&sblock
, CGSIZE(&sblock
));
520 * Now have size for file system and nsect and ntrak.
521 * Determine number of cylinders and blocks in the file system.
523 sblock
.fs_size
= fssize
= dbtofsb(&sblock
, fssize
);
524 sblock
.fs_ncyl
= fssize
* NSPF(&sblock
) / sblock
.fs_spc
;
525 if (fssize
* NSPF(&sblock
) > sblock
.fs_ncyl
* sblock
.fs_spc
) {
529 if (sblock
.fs_ncyl
< 1) {
530 printf("file systems must have at least one cylinder\n");
534 * Determine feasability/values of rotational layout tables.
536 * The size of the rotational layout tables is limited by the
537 * size of the superblock, SBSIZE. The amount of space available
538 * for tables is calculated as (SBSIZE - sizeof (struct fs)).
539 * The size of these tables is inversely proportional to the block
540 * size of the file system. The size increases if sectors per track
541 * are not powers of two, because more cylinders must be described
542 * by the tables before the rotational pattern repeats (fs_cpc).
544 sblock
.fs_interleave
= interleave
;
545 sblock
.fs_trackskew
= trackskew
;
546 sblock
.fs_npsect
= nphyssectors
;
547 sblock
.fs_postblformat
= FS_DYNAMICPOSTBLFMT
;
548 sblock
.fs_sbsize
= fragroundup(&sblock
, sizeof(struct fs
));
549 if (sblock
.fs_sbsize
> SBSIZE
)
550 sblock
.fs_sbsize
= SBSIZE
;
551 if (sblock
.fs_ntrak
== 1) {
555 postblsize
= sblock
.fs_nrpos
* sblock
.fs_cpc
* sizeof(int16_t);
556 rotblsize
= sblock
.fs_cpc
* sblock
.fs_spc
/ NSPB(&sblock
);
557 totalsbsize
= sizeof(struct fs
) + rotblsize
;
558 if (sblock
.fs_nrpos
== 8 && sblock
.fs_cpc
<= 16) {
559 /* use old static table space */
560 sblock
.fs_postbloff
= (char *)(&sblock
.fs_opostbl
[0][0]) -
561 (char *)(&sblock
.fs_firstfield
);
562 sblock
.fs_rotbloff
= &sblock
.fs_space
[0] -
563 (u_char
*)(&sblock
.fs_firstfield
);
565 /* use dynamic table space */
566 sblock
.fs_postbloff
= &sblock
.fs_space
[0] -
567 (u_char
*)(&sblock
.fs_firstfield
);
568 sblock
.fs_rotbloff
= sblock
.fs_postbloff
+ postblsize
;
569 totalsbsize
+= postblsize
;
571 if (totalsbsize
> SBSIZE
||
572 sblock
.fs_nsect
> (1 << NBBY
) * NSPB(&sblock
)) {
573 printf("%s %s %d %s %d.%s",
574 "Warning: insufficient space in super block for\n",
575 "rotational layout tables with nsect", sblock
.fs_nsect
,
576 "and ntrak", sblock
.fs_ntrak
,
577 "\nFile system performance may be impaired.\n");
581 sblock
.fs_sbsize
= fragroundup(&sblock
, totalsbsize
);
582 if (sblock
.fs_sbsize
> SBSIZE
)
583 sblock
.fs_sbsize
= SBSIZE
;
585 * calculate the available blocks for each rotational position
587 for (cylno
= 0; cylno
< sblock
.fs_cpc
; cylno
++)
588 for (rpos
= 0; rpos
< sblock
.fs_nrpos
; rpos
++)
589 fs_postbl(&sblock
, cylno
)[rpos
] = -1;
590 for (i
= (rotblsize
- 1) * sblock
.fs_frag
;
591 i
>= 0; i
-= sblock
.fs_frag
) {
592 cylno
= cbtocylno(&sblock
, i
);
593 rpos
= cbtorpos(&sblock
, i
);
594 blk
= fragstoblks(&sblock
, i
);
595 if (fs_postbl(&sblock
, cylno
)[rpos
] == -1)
596 fs_rotbl(&sblock
)[blk
] = 0;
598 fs_rotbl(&sblock
)[blk
] =
599 fs_postbl(&sblock
, cylno
)[rpos
] - blk
;
600 fs_postbl(&sblock
, cylno
)[rpos
] = blk
;
604 * Compute/validate number of cylinder groups.
606 sblock
.fs_ncg
= sblock
.fs_ncyl
/ sblock
.fs_cpg
;
607 if (sblock
.fs_ncyl
% sblock
.fs_cpg
)
609 sblock
.fs_dblkno
= sblock
.fs_iblkno
+ sblock
.fs_ipg
/ INOPF(&sblock
);
610 i
= MIN(~sblock
.fs_cgmask
, sblock
.fs_ncg
- 1);
611 if (cgdmin(&sblock
, i
) - cgbase(&sblock
, i
) >= sblock
.fs_fpg
) {
612 printf("inode blocks/cyl group (%ld) >= data blocks (%ld)\n",
613 cgdmin(&sblock
, i
) - cgbase(&sblock
, i
) / sblock
.fs_frag
,
614 (long)(sblock
.fs_fpg
/ sblock
.fs_frag
));
615 printf("number of cylinders per cylinder group (%d) %s.\n",
616 sblock
.fs_cpg
, "must be increased");
619 j
= sblock
.fs_ncg
- 1;
620 if ((i
= fssize
- j
* sblock
.fs_fpg
) < sblock
.fs_fpg
&&
621 cgdmin(&sblock
, j
) - cgbase(&sblock
, j
) > i
) {
623 printf("Filesystem must have at least %d sectors\n",
625 (cgdmin(&sblock
, 0) + 3 * sblock
.fs_frag
));
629 "Warning: inode blocks/cyl group (%ld) >= data blocks (%ld) in last\n",
630 (cgdmin(&sblock
, j
) - cgbase(&sblock
, j
)) / sblock
.fs_frag
,
633 " cylinder group. This implies %ld sector(s) cannot be allocated.\n",
636 sblock
.fs_ncyl
-= sblock
.fs_ncyl
% sblock
.fs_cpg
;
637 sblock
.fs_size
= fssize
= sblock
.fs_ncyl
* sblock
.fs_spc
/
641 if (emitwarn
&& !mfs
) {
642 printf("Warning: %d sector(s) in last cylinder unallocated\n",
644 (fssize
* NSPF(&sblock
) - (sblock
.fs_ncyl
- 1)
648 * fill in remaining fields of the super block
650 sblock
.fs_csaddr
= cgdmin(&sblock
, 0);
652 fragroundup(&sblock
, sblock
.fs_ncg
* sizeof(struct csum
));
654 * The superblock fields 'fs_csmask' and 'fs_csshift' are no
655 * longer used. However, we still initialise them so that the
656 * filesystem remains compatible with old kernels.
658 i
= sblock
.fs_bsize
/ sizeof(struct csum
);
659 sblock
.fs_csmask
= ~(i
- 1);
660 for (sblock
.fs_csshift
= 0; i
> 1; i
>>= 1)
662 fscs
= (struct csum
*)calloc(1, sblock
.fs_cssize
);
664 errx(31, "calloc failed");
665 sblock
.fs_magic
= FS_MAGIC
;
666 sblock
.fs_rotdelay
= rotdelay
;
667 sblock
.fs_minfree
= minfree
;
668 sblock
.fs_maxcontig
= maxcontig
;
669 sblock
.fs_maxbpg
= maxbpg
;
670 sblock
.fs_rps
= rpm
/ 60;
671 sblock
.fs_optim
= opt
;
672 sblock
.fs_cgrotor
= 0;
673 sblock
.fs_cstotal
.cs_ndir
= 0;
674 sblock
.fs_cstotal
.cs_nbfree
= 0;
675 sblock
.fs_cstotal
.cs_nifree
= 0;
676 sblock
.fs_cstotal
.cs_nffree
= 0;
681 sblock
.fs_id
[0] = (long)utime
;
682 sblock
.fs_id
[1] = random();
686 * Dump out summary information about file system.
689 printf("%s:\t%d sectors in %d %s of %d tracks, %d sectors\n",
690 fsys
, sblock
.fs_size
* NSPF(&sblock
), sblock
.fs_ncyl
,
691 "cylinders", sblock
.fs_ntrak
, sblock
.fs_nsect
);
692 #define B2MBFACTOR (1 / (1024.0 * 1024.0))
693 printf("\t%.1fMB in %d cyl groups (%d c/g, %.2fMB/g, %d i/g)%s\n",
694 (float)sblock
.fs_size
* sblock
.fs_fsize
* B2MBFACTOR
,
695 sblock
.fs_ncg
, sblock
.fs_cpg
,
696 (float)sblock
.fs_fpg
* sblock
.fs_fsize
* B2MBFACTOR
,
698 sblock
.fs_flags
& FS_DOSOFTDEP
? " SOFTUPDATES" : "");
702 * Now build the cylinders group blocks and
703 * then print out indices of cylinder groups.
706 printf("super-block backups (for fsck -b #) at:\n");
708 width
= charsperline();
709 for (cylno
= 0; cylno
< sblock
.fs_ncg
; cylno
++) {
710 initcg(cylno
, utime
);
713 j
= snprintf(tmpbuf
, sizeof(tmpbuf
), " %ld%s",
714 fsbtodb(&sblock
, cgsblock(&sblock
, cylno
)),
715 cylno
< (sblock
.fs_ncg
-1) ? "," : "" );
716 if (i
+ j
>= width
) {
721 printf("%s", tmpbuf
);
729 * Now construct the initial file system,
730 * then write out the super-block.
733 sblock
.fs_time
= utime
;
734 wtfs((int)SBOFF
/ sectorsize
, sbsize
, (char *)&sblock
);
735 for (i
= 0; i
< sblock
.fs_cssize
; i
+= sblock
.fs_bsize
)
736 wtfs(fsbtodb(&sblock
, sblock
.fs_csaddr
+ numfrags(&sblock
, i
)),
737 sblock
.fs_cssize
- i
< sblock
.fs_bsize
?
738 sblock
.fs_cssize
- i
: sblock
.fs_bsize
,
741 * Write out the duplicate super blocks
743 for (cylno
= 0; cylno
< sblock
.fs_ncg
; cylno
++)
744 wtfs(fsbtodb(&sblock
, cgsblock(&sblock
, cylno
)),
745 sbsize
, (char *)&sblock
);
748 * Update information about this partion in pack
749 * label, so that it may be updated on disk.
751 pp
->p_fstype
= FS_BSDFFS
;
752 pp
->p_fsize
= sblock
.fs_fsize
;
753 pp
->p_frag
= sblock
.fs_frag
;
754 pp
->p_cpg
= sblock
.fs_cpg
;
756 * Notify parent process of success.
757 * Dissociate from session and tty.
760 kill(mfs_ppid
, SIGUSR1
);
770 * Initialize a cylinder group.
773 initcg(int cylno
, time_t utime
)
775 daddr_t cbase
, d
, dlower
, dupper
, dmax
, blkno
;
784 * Determine block bounds for cylinder group.
785 * Allow space for super block summary information in first
788 cbase
= cgbase(&sblock
, cylno
);
789 dmax
= cbase
+ sblock
.fs_fpg
;
790 if (dmax
> sblock
.fs_size
)
791 dmax
= sblock
.fs_size
;
792 dlower
= cgsblock(&sblock
, cylno
) - cbase
;
793 dupper
= cgdmin(&sblock
, cylno
) - cbase
;
795 dupper
+= howmany(sblock
.fs_cssize
, sblock
.fs_fsize
);
797 memset(&acg
, 0, sblock
.fs_cgsize
);
799 acg
.cg_magic
= CG_MAGIC
;
801 if (cylno
== sblock
.fs_ncg
- 1)
802 acg
.cg_ncyl
= sblock
.fs_ncyl
% sblock
.fs_cpg
;
804 acg
.cg_ncyl
= sblock
.fs_cpg
;
805 acg
.cg_niblk
= sblock
.fs_ipg
;
806 acg
.cg_ndblk
= dmax
- cbase
;
807 if (sblock
.fs_contigsumsize
> 0)
808 acg
.cg_nclusterblks
= acg
.cg_ndblk
/ sblock
.fs_frag
;
809 acg
.cg_btotoff
= &acg
.cg_space
[0] - (u_char
*)(&acg
.cg_firstfield
);
810 acg
.cg_boff
= acg
.cg_btotoff
+ sblock
.fs_cpg
* sizeof(int32_t);
811 acg
.cg_iusedoff
= acg
.cg_boff
+
812 sblock
.fs_cpg
* sblock
.fs_nrpos
* sizeof(u_int16_t
);
813 acg
.cg_freeoff
= acg
.cg_iusedoff
+ howmany(sblock
.fs_ipg
, NBBY
);
814 if (sblock
.fs_contigsumsize
<= 0) {
815 acg
.cg_nextfreeoff
= acg
.cg_freeoff
+
816 howmany(sblock
.fs_cpg
* sblock
.fs_spc
/ NSPF(&sblock
), NBBY
);
818 acg
.cg_clustersumoff
= acg
.cg_freeoff
+ howmany
819 (sblock
.fs_cpg
* sblock
.fs_spc
/ NSPF(&sblock
), NBBY
) -
821 acg
.cg_clustersumoff
=
822 roundup(acg
.cg_clustersumoff
, sizeof(u_int32_t
));
823 acg
.cg_clusteroff
= acg
.cg_clustersumoff
+
824 (sblock
.fs_contigsumsize
+ 1) * sizeof(u_int32_t
);
825 acg
.cg_nextfreeoff
= acg
.cg_clusteroff
+ howmany
826 (sblock
.fs_cpg
* sblock
.fs_spc
/ NSPB(&sblock
), NBBY
);
828 if (acg
.cg_nextfreeoff
- (long)(&acg
.cg_firstfield
) > sblock
.fs_cgsize
) {
829 printf("Panic: cylinder group too big\n");
832 acg
.cg_cs
.cs_nifree
+= sblock
.fs_ipg
;
834 for (k
= 0; k
< ROOTINO
; k
++) {
835 setbit(cg_inosused(&acg
), k
);
836 acg
.cg_cs
.cs_nifree
--;
839 for (i
= 0; i
< sblock
.fs_ipg
/ INOPF(&sblock
); i
+= sblock
.fs_frag
) {
842 j
< sblock
.fs_bsize
/ sizeof(struct ufs1_dinode
);
844 zino
[j
].di_gen
= random();
847 wtfs(fsbtodb(&sblock
, cgimin(&sblock
, cylno
) + i
),
848 sblock
.fs_bsize
, (char *)zino
);
852 * In cylno 0, beginning space is reserved
853 * for boot and super blocks.
855 for (d
= 0; d
< dlower
; d
+= sblock
.fs_frag
) {
856 blkno
= d
/ sblock
.fs_frag
;
857 setblock(&sblock
, cg_blksfree(&acg
), blkno
);
858 if (sblock
.fs_contigsumsize
> 0)
859 setbit(cg_clustersfree(&acg
), blkno
);
860 acg
.cg_cs
.cs_nbfree
++;
861 cg_blktot(&acg
)[cbtocylno(&sblock
, d
)]++;
862 cg_blks(&sblock
, &acg
, cbtocylno(&sblock
, d
))
863 [cbtorpos(&sblock
, d
)]++;
865 sblock
.fs_dsize
+= dlower
;
867 sblock
.fs_dsize
+= acg
.cg_ndblk
- dupper
;
868 if ((i
= dupper
% sblock
.fs_frag
)) {
869 acg
.cg_frsum
[sblock
.fs_frag
- i
]++;
870 for (d
= dupper
+ sblock
.fs_frag
- i
; dupper
< d
; dupper
++) {
871 setbit(cg_blksfree(&acg
), dupper
);
872 acg
.cg_cs
.cs_nffree
++;
875 for (d
= dupper
; d
+ sblock
.fs_frag
<= dmax
- cbase
; ) {
876 blkno
= d
/ sblock
.fs_frag
;
877 setblock(&sblock
, cg_blksfree(&acg
), blkno
);
878 if (sblock
.fs_contigsumsize
> 0)
879 setbit(cg_clustersfree(&acg
), blkno
);
880 acg
.cg_cs
.cs_nbfree
++;
881 cg_blktot(&acg
)[cbtocylno(&sblock
, d
)]++;
882 cg_blks(&sblock
, &acg
, cbtocylno(&sblock
, d
))
883 [cbtorpos(&sblock
, d
)]++;
886 if (d
< dmax
- cbase
) {
887 acg
.cg_frsum
[dmax
- cbase
- d
]++;
888 for (; d
< dmax
- cbase
; d
++) {
889 setbit(cg_blksfree(&acg
), d
);
890 acg
.cg_cs
.cs_nffree
++;
893 if (sblock
.fs_contigsumsize
> 0) {
894 int32_t *sump
= cg_clustersum(&acg
);
895 u_char
*mapp
= cg_clustersfree(&acg
);
900 for (i
= 0; i
< acg
.cg_nclusterblks
; i
++) {
901 if ((map
& bit
) != 0) {
903 } else if (run
!= 0) {
904 if (run
> sblock
.fs_contigsumsize
)
905 run
= sblock
.fs_contigsumsize
;
909 if ((i
& (NBBY
- 1)) != (NBBY
- 1)) {
917 if (run
> sblock
.fs_contigsumsize
)
918 run
= sblock
.fs_contigsumsize
;
922 sblock
.fs_cstotal
.cs_ndir
+= acg
.cg_cs
.cs_ndir
;
923 sblock
.fs_cstotal
.cs_nffree
+= acg
.cg_cs
.cs_nffree
;
924 sblock
.fs_cstotal
.cs_nbfree
+= acg
.cg_cs
.cs_nbfree
;
925 sblock
.fs_cstotal
.cs_nifree
+= acg
.cg_cs
.cs_nifree
;
927 wtfs(fsbtodb(&sblock
, cgtod(&sblock
, cylno
)),
928 sblock
.fs_bsize
, (char *)&acg
);
932 * initialize the file system
934 struct ufs1_dinode node
;
942 struct direct root_dir
[] = {
943 { ROOTINO
, sizeof(struct direct
), DT_DIR
, 1, "." },
944 { ROOTINO
, sizeof(struct direct
), DT_DIR
, 2, ".." },
946 { LOSTFOUNDINO
, sizeof(struct direct
), DT_DIR
, 10, "lost+found" },
953 u_char d_name
[MAXNAMLEN
+ 1];
955 { ROOTINO
, sizeof(struct direct
), 1, "." },
956 { ROOTINO
, sizeof(struct direct
), 2, ".." },
958 { LOSTFOUNDINO
, sizeof(struct direct
), 10, "lost+found" },
962 struct direct lost_found_dir
[] = {
963 { LOSTFOUNDINO
, sizeof(struct direct
), DT_DIR
, 1, "." },
964 { ROOTINO
, sizeof(struct direct
), DT_DIR
, 2, ".." },
965 { 0, DIRBLKSIZ
, 0, 0, 0 },
967 struct odirect olost_found_dir
[] = {
968 { LOSTFOUNDINO
, sizeof(struct direct
), 1, "." },
969 { ROOTINO
, sizeof(struct direct
), 2, ".." },
970 { 0, DIRBLKSIZ
, 0, 0 },
983 * initialize the node
985 node
.di_atime
= utime
;
986 node
.di_mtime
= utime
;
987 node
.di_ctime
= utime
;
990 * create the lost+found directory
993 makedir((struct direct
*)olost_found_dir
, 2);
994 for (i
= DIRBLKSIZ
; i
< sblock
.fs_bsize
; i
+= DIRBLKSIZ
)
995 memmove(&buf
[i
], &olost_found_dir
[2],
996 DIRSIZ(0, &olost_found_dir
[2]));
998 makedir(lost_found_dir
, 2);
999 for (i
= DIRBLKSIZ
; i
< sblock
.fs_bsize
; i
+= DIRBLKSIZ
)
1000 memmove(&buf
[i
], &lost_found_dir
[2],
1001 DIRSIZ(0, &lost_found_dir
[2]));
1003 node
.di_mode
= IFDIR
| UMASK
;
1005 node
.di_size
= sblock
.fs_bsize
;
1006 node
.di_db
[0] = alloc(node
.di_size
, node
.di_mode
);
1007 node
.di_blocks
= btodb(fragroundup(&sblock
, node
.di_size
));
1008 wtfs(fsbtodb(&sblock
, node
.di_db
[0]), node
.di_size
, buf
);
1009 iput(&node
, LOSTFOUNDINO
);
1012 * create the root directory
1015 node
.di_mode
= IFDIR
| 01777;
1017 node
.di_mode
= IFDIR
| UMASK
;
1018 node
.di_nlink
= PREDEFDIR
;
1020 node
.di_size
= makedir((struct direct
*)oroot_dir
, PREDEFDIR
);
1022 node
.di_size
= makedir(root_dir
, PREDEFDIR
);
1023 node
.di_db
[0] = alloc(sblock
.fs_fsize
, node
.di_mode
);
1024 node
.di_blocks
= btodb(fragroundup(&sblock
, node
.di_size
));
1025 wtfs(fsbtodb(&sblock
, node
.di_db
[0]), sblock
.fs_fsize
, buf
);
1026 iput(&node
, ROOTINO
);
1030 * construct a set of directory entries in "buf".
1031 * return size of directory.
1034 makedir(struct direct
*protodir
, int entries
)
1039 spcleft
= DIRBLKSIZ
;
1040 for (cp
= buf
, i
= 0; i
< entries
- 1; i
++) {
1041 protodir
[i
].d_reclen
= DIRSIZ(0, &protodir
[i
]);
1042 memmove(cp
, &protodir
[i
], protodir
[i
].d_reclen
);
1043 cp
+= protodir
[i
].d_reclen
;
1044 spcleft
-= protodir
[i
].d_reclen
;
1046 protodir
[i
].d_reclen
= spcleft
;
1047 memmove(cp
, &protodir
[i
], DIRSIZ(0, &protodir
[i
]));
1052 * allocate a block or frag
1055 alloc(int size
, int mode
)
1060 rdfs(fsbtodb(&sblock
, cgtod(&sblock
, 0)), sblock
.fs_cgsize
,
1062 if (acg
.cg_magic
!= CG_MAGIC
) {
1063 printf("cg 0: bad magic number\n");
1066 if (acg
.cg_cs
.cs_nbfree
== 0) {
1067 printf("first cylinder group ran out of space\n");
1070 for (d
= 0; d
< acg
.cg_ndblk
; d
+= sblock
.fs_frag
)
1071 if (isblock(&sblock
, cg_blksfree(&acg
), d
/ sblock
.fs_frag
))
1073 printf("internal error: can't find block in cyl 0\n");
1076 blkno
= fragstoblks(&sblock
, d
);
1077 clrblock(&sblock
, cg_blksfree(&acg
), blkno
);
1078 if (sblock
.fs_contigsumsize
> 0)
1079 clrbit(cg_clustersfree(&acg
), blkno
);
1080 acg
.cg_cs
.cs_nbfree
--;
1081 sblock
.fs_cstotal
.cs_nbfree
--;
1082 fscs
[0].cs_nbfree
--;
1084 acg
.cg_cs
.cs_ndir
++;
1085 sblock
.fs_cstotal
.cs_ndir
++;
1088 cg_blktot(&acg
)[cbtocylno(&sblock
, d
)]--;
1089 cg_blks(&sblock
, &acg
, cbtocylno(&sblock
, d
))[cbtorpos(&sblock
, d
)]--;
1090 if (size
!= sblock
.fs_bsize
) {
1091 frag
= howmany(size
, sblock
.fs_fsize
);
1092 fscs
[0].cs_nffree
+= sblock
.fs_frag
- frag
;
1093 sblock
.fs_cstotal
.cs_nffree
+= sblock
.fs_frag
- frag
;
1094 acg
.cg_cs
.cs_nffree
+= sblock
.fs_frag
- frag
;
1095 acg
.cg_frsum
[sblock
.fs_frag
- frag
]++;
1096 for (i
= frag
; i
< sblock
.fs_frag
; i
++)
1097 setbit(cg_blksfree(&acg
), d
+ i
);
1099 wtfs(fsbtodb(&sblock
, cgtod(&sblock
, 0)), sblock
.fs_cgsize
,
1105 * Calculate number of inodes per group.
1108 calcipg(long cylspg
, long bpcg
, off_t
*usedbp
)
1111 long ipg
, new_ipg
, ncg
, ncyl
;
1115 * Prepare to scale by fssize / (number of sectors in cylinder groups).
1116 * Note that fssize is still in sectors, not filesystem blocks.
1118 ncyl
= howmany(fssize
, (u_int
)secpercyl
);
1119 ncg
= howmany(ncyl
, cylspg
);
1121 * Iterate a few times to allow for ipg depending on itself.
1124 for (i
= 0; i
< 10; i
++) {
1125 usedb
= (sblock
.fs_iblkno
+ ipg
/ INOPF(&sblock
))
1126 * NSPF(&sblock
) * (off_t
)sectorsize
;
1127 new_ipg
= (cylspg
* (quad_t
)bpcg
- usedb
) / density
* fssize
1128 / ncg
/ secpercyl
/ cylspg
;
1129 new_ipg
= roundup(new_ipg
, INOPB(&sblock
));
1139 * Allocate an inode on the disk
1142 iput(struct ufs1_dinode
*ip
, ino_t ino
)
1144 struct ufs1_dinode inobuf
[MAXINOPB
];
1149 ip
->di_gen
= random();
1151 c
= ino_to_cg(&sblock
, ino
);
1152 rdfs(fsbtodb(&sblock
, cgtod(&sblock
, 0)), sblock
.fs_cgsize
,
1154 if (acg
.cg_magic
!= CG_MAGIC
) {
1155 printf("cg 0: bad magic number\n");
1158 acg
.cg_cs
.cs_nifree
--;
1159 setbit(cg_inosused(&acg
), ino
);
1160 wtfs(fsbtodb(&sblock
, cgtod(&sblock
, 0)), sblock
.fs_cgsize
,
1162 sblock
.fs_cstotal
.cs_nifree
--;
1163 fscs
[0].cs_nifree
--;
1164 if (ino
>= (uint32_t)sblock
.fs_ipg
* (uint32_t)sblock
.fs_ncg
) {
1165 printf("fsinit: inode value out of range (%ju).\n",
1169 d
= fsbtodb(&sblock
, ino_to_fsba(&sblock
, ino
));
1170 rdfs(d
, sblock
.fs_bsize
, (char *)inobuf
);
1171 inobuf
[ino_to_fsbo(&sblock
, ino
)] = *ip
;
1172 wtfs(d
, sblock
.fs_bsize
, (char *)inobuf
);
1176 * Parent notifies child that it can proceed with the newfs and mount
1177 * operation (occurs after parent has copied the underlying filesystem
1178 * if the -C option was specified (for MFS), or immediately after the
1179 * parent forked the child otherwise).
1182 parentready(__unused
int signo
)
1184 parentready_signalled
= 1;
1188 * Notify parent process that the filesystem has created itself successfully.
1190 * We have to wait until the mount has actually completed!
1193 started(__unused
int signo
)
1195 int retry
= 100; /* 10 seconds, 100ms */
1197 while (mfs_ppid
&& retry
) {
1201 stat(mfs_mtpt
, &st
) < 0 ||
1202 st
.st_dev
!= mfs_mtstat
.st_dev
1210 fatal("mfs mount failed waiting for mount to go active");
1211 } else if (copyroot
) {
1212 FSPaste(mfs_mtpt
, copyroot
, copyhlinks
);
1219 * Replace libc function with one suited to our needs.
1230 pgsz
= getpagesize() - 1;
1231 i
= (char *)((u_long
)(base
+ pgsz
) &~ pgsz
);
1232 base
= sbrk(i
- base
);
1233 if (getrlimit(RLIMIT_DATA
, &rlp
) < 0)
1235 rlp
.rlim_cur
= rlp
.rlim_max
;
1236 if (setrlimit(RLIMIT_DATA
, &rlp
) < 0)
1238 memleft
= rlp
.rlim_max
- (u_long
)base
;
1240 size
= (size
+ pgsz
) &~ pgsz
;
1246 return ((caddr_t
)sbrk(size
));
1250 * Replace libc function with one suited to our needs.
1253 realloc(char *ptr
, u_long size
)
1257 if ((p
= malloc(size
)) == NULL
)
1259 memmove(p
, ptr
, size
);
1265 * Replace libc function with one suited to our needs.
1268 calloc(u_long size
, u_long numelm
)
1273 if ((base
= malloc(size
)) == NULL
)
1275 memset(base
, 0, size
);
1280 * Replace libc function with one suited to our needs.
1286 /* do not worry about it for now */
1289 #else /* !STANDALONE */
1292 raise_data_limit(void)
1296 if (getrlimit(RLIMIT_DATA
, &rlp
) < 0)
1298 rlp
.rlim_cur
= rlp
.rlim_max
;
1299 if (setrlimit(RLIMIT_DATA
, &rlp
) < 0)
1304 extern char *_etext
;
1305 #define etext _etext
1319 pgsz
= getpagesize() - 1;
1320 dstart
= ((u_long
)&etext
) &~ pgsz
;
1321 freestart
= ((u_long
)((char *)sbrk(0) + pgsz
) &~ pgsz
);
1322 if (getrlimit(RLIMIT_DATA
, &rlp
) < 0)
1324 memused
= freestart
- dstart
;
1325 memleft
= rlp
.rlim_cur
- memused
;
1327 #endif /* STANDALONE */
1330 * read a block from the file system
1333 rdfs(daddr_t bno
, int size
, char *bf
)
1339 memmove(bf
, membase
+ bno
* sectorsize
, size
);
1342 if (lseek(fsi
, (off_t
)bno
* sectorsize
, 0) < 0) {
1343 printf("seek error: %ld\n", (long)bno
);
1346 n
= read(fsi
, bf
, size
);
1348 printf("read error: %ld\n", (long)bno
);
1353 #define WCSIZE (128 * 1024)
1354 daddr_t wc_sect
; /* units of sectorsize */
1355 int wc_end
; /* bytes */
1356 static char wc
[WCSIZE
]; /* bytes */
1359 * Flush dirty write behind buffer.
1366 if (lseek(fso
, (off_t
)wc_sect
* sectorsize
, SEEK_SET
) < 0) {
1367 printf("seek error: %ld\n", (long)wc_sect
);
1368 err(35, "wtfs - writecombine");
1370 n
= write(fso
, wc
, wc_end
);
1372 printf("write error: %ld\n", (long)wc_sect
);
1373 err(36, "wtfs - writecombine");
1380 * write a block to the file system
1383 wtfs(daddr_t bno
, int size
, char *bf
)
1389 memmove(membase
+ bno
* sectorsize
, bf
, size
);
1395 if (wc_end
== 0 && size
<= WCSIZE
) {
1397 bcopy(bf
, wc
, size
);
1399 if (wc_end
< WCSIZE
)
1403 if ((off_t
)wc_sect
* sectorsize
+ wc_end
== (off_t
)bno
* sectorsize
&&
1404 wc_end
+ size
<= WCSIZE
) {
1405 bcopy(bf
, wc
+ wc_end
, size
);
1407 if (wc_end
< WCSIZE
)
1414 if (lseek(fso
, (off_t
)bno
* sectorsize
, SEEK_SET
) < 0) {
1415 printf("seek error: %ld\n", (long)bno
);
1418 n
= write(fso
, bf
, size
);
1420 printf("write error: %ld\n", (long)bno
);
1426 * check if a block is available
1429 isblock(struct fs
*fs
, unsigned char *cp
, int h
)
1433 switch (fs
->fs_frag
) {
1435 return (cp
[h
] == 0xff);
1437 mask
= 0x0f << ((h
& 0x1) << 2);
1438 return ((cp
[h
>> 1] & mask
) == mask
);
1440 mask
= 0x03 << ((h
& 0x3) << 1);
1441 return ((cp
[h
>> 2] & mask
) == mask
);
1443 mask
= 0x01 << (h
& 0x7);
1444 return ((cp
[h
>> 3] & mask
) == mask
);
1447 printf("isblock bad fs_frag %d\n", fs
->fs_frag
);
1449 fprintf(stderr
, "isblock bad fs_frag %d\n", fs
->fs_frag
);
1456 * take a block out of the map
1459 clrblock(struct fs
*fs
, unsigned char *cp
, int h
)
1461 switch ((fs
)->fs_frag
) {
1466 cp
[h
>> 1] &= ~(0x0f << ((h
& 0x1) << 2));
1469 cp
[h
>> 2] &= ~(0x03 << ((h
& 0x3) << 1));
1472 cp
[h
>> 3] &= ~(0x01 << (h
& 0x7));
1476 printf("clrblock bad fs_frag %d\n", fs
->fs_frag
);
1478 fprintf(stderr
, "clrblock bad fs_frag %d\n", fs
->fs_frag
);
1485 * put a block into the map
1488 setblock(struct fs
*fs
, unsigned char *cp
, int h
)
1490 switch (fs
->fs_frag
) {
1495 cp
[h
>> 1] |= (0x0f << ((h
& 0x1) << 2));
1498 cp
[h
>> 2] |= (0x03 << ((h
& 0x3) << 1));
1501 cp
[h
>> 3] |= (0x01 << (h
& 0x7));
1505 printf("setblock bad fs_frag %d\n", fs
->fs_frag
);
1507 fprintf(stderr
, "setblock bad fs_frag %d\n", fs
->fs_frag
);
1514 * Determine the number of characters in a
1526 if (ioctl(0, TIOCGWINSZ
, &ws
) != -1)
1527 columns
= ws
.ws_col
;
1528 if (columns
== 0 && (cp
= getenv("COLUMNS")))
1531 columns
= 80; /* last resort */