1 /* $NetBSD: make_lfs.c,v 1.14 2009/02/22 20:28:05 ad Exp $ */
4 * Copyright (c) 2003 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Konrad E. Schroder <perseant@hhhh.org>.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 * Copyright (c) 1991, 1993
33 * The Regents of the University of California. All rights reserved.
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
43 * 3. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 #include <sys/cdefs.h>
63 static char sccsid
[] = "@(#)lfs.c 8.5 (Berkeley) 5/24/95";
65 __RCSID("$NetBSD: make_lfs.c,v 1.14 2009/02/22 20:28:05 ad Exp $");
69 #include <sys/param.h>
72 #include <sys/mount.h>
75 #include <ufs/ufs/dir.h>
76 #include <ufs/ufs/quota.h>
77 #include <ufs/ufs/inode.h>
79 /* Override certain things to make <ufs/lfs/lfs.h> work */
81 # define simple_lock(x)
83 # define simple_unlock(x)
86 # define panic call_panic
87 #include <ufs/lfs/lfs.h>
100 #include "bufcache.h"
102 #include "lfs_user.h"
103 #include "segwrite.h"
105 extern int Nflag
; /* Don't write anything */
106 ufs_daddr_t ifibc
; /* How many indirect blocks */
109 # define HIGHEST_USED_INO LOSTFOUNDINO
111 # define HIGHEST_USED_INO ROOTINO
114 static struct lfs lfs_default
= {
115 .lfs_dlfs
= { /* lfs_dlfs */
116 /* dlfs_magic */ LFS_MAGIC
,
117 /* dlfs_version */ LFS_VERSION
,
119 /* dlfs_ssize */ DFL_LFSSEG
,
121 /* dlfs_bsize */ DFL_LFSBLOCK
,
122 /* dlfs_fsize */ DFL_LFSFRAG
,
123 /* dlfs_frag */ DFL_LFSBLOCK
/DFL_LFSFRAG
,
124 /* dlfs_freehd */ HIGHEST_USED_INO
+ 1,
128 /* dlfs_uinodes */ 0,
130 /* dlfs_ifile */ LFS_IFILE_INUM
,
131 /* dlfs_lastseg */ 0,
132 /* dlfs_nextseg */ 0,
135 /* dlfs_lastpseg */ 0,
137 /* dlfs_minfree */ MINFREE
,
138 /* dlfs_maxfilesize */ 0,
139 /* dlfs_fsbpseg */ 0,
140 /* dlfs_inopb */ DFL_LFSBLOCK
/sizeof(struct ufs1_dinode
),
141 /* dlfs_ifpb */ DFL_LFSBLOCK
/sizeof(IFILE
),
142 /* dlfs_sepb */ DFL_LFSBLOCK
/sizeof(SEGUSE
),
144 /* dlfs_nindir */ DFL_LFSBLOCK
/sizeof(int32_t),
147 /* dlfs_cleansz */ 0,
148 /* dlfs_segtabsz */ 0,
149 /* dlfs_segmask */ DFL_LFSSEG_MASK
,
150 /* dlfs_segshift */ DFL_LFSSEG_SHIFT
,
151 /* dlfs_bshift */ DFL_LFSBLOCK_SHIFT
,
152 /* dlfs_ffshift */ DFL_LFS_FFSHIFT
,
153 /* dlfs_fbshift */ DFL_LFS_FBSHIFT
,
154 /* dlfs_bmask */ DFL_LFSBLOCK_MASK
,
155 /* dlfs_ffmask */ DFL_LFS_FFMASK
,
156 /* dlfs_fbmask */ DFL_LFS_FBMASK
,
157 /* dlfs_blktodb */ 0,
158 /* dlfs_sushift */ 0,
159 /* dlfs_maxsymlinklen */ MAXSYMLINKLEN_UFS1
,
160 /* dlfs_sboffs */ { 0 },
162 /* dlfs_fsmnt */ { 0 },
163 /* dlfs_pflags */ LFS_PF_CLEAN
,
165 /* dlfs_minfreeseg */ 0,
166 /* dlfs_sumsize */ 0,
168 /* dlfs_ibsize */ DFL_LFSFRAG
,
171 /* dlfs_inodefmt */ LFS_44INODEFMT
,
172 /* dlfs_interleave */ 0,
174 /* dlfs_fsbtodb */ 0,
175 /* dlfs_resvseg */ 0,
177 /* dlfs_pad */ { 0 },
184 struct direct lfs_root_dir
[] = {
185 { ROOTINO
, sizeof(struct direct
), DT_DIR
, 1, "."},
186 { ROOTINO
, sizeof(struct direct
), DT_DIR
, 2, ".."},
187 /* { LFS_IFILE_INUM, sizeof(struct direct), DT_REG, 5, "ifile"}, */
189 { LOSTFOUNDINO
, sizeof(struct direct
), DT_DIR
, 10, "lost+found"},
194 struct direct lfs_lf_dir
[] = {
195 { LOSTFOUNDINO
, sizeof(struct direct
), DT_DIR
, 1, "." },
196 { ROOTINO
, sizeof(struct direct
), DT_DIR
, 2, ".." },
200 void pwarn(const char *, ...);
201 static void make_dinode(ino_t
, struct ufs1_dinode
*, int, struct lfs
*);
202 static void make_dir( void *, struct direct
*, int);
203 static uint64_t maxfilesize(int);
206 * calculate the maximum file size allowed with the specified block shift.
209 maxfilesize(int bshift
)
211 uint64_t nptr
; /* number of block pointers per block */
214 nptr
= (1 << bshift
) / sizeof(uint32_t);
215 maxblock
= NDADDR
+ nptr
+ nptr
* nptr
+ nptr
* nptr
* nptr
;
217 return maxblock
<< bshift
;
221 * Create the root directory for this file system and the lost+found
225 make_dinode(ino_t ino
, struct ufs1_dinode
*dip
, int nfrags
, struct lfs
*fs
)
228 int nblocks
, bb
, base
, factor
, lvl
;
230 nblocks
= howmany(nfrags
, fs
->lfs_frag
);
231 if(nblocks
>= NDADDR
)
232 nfrags
= roundup(nfrags
, fs
->lfs_frag
);
235 dip
->di_blocks
= fragstofsb(fs
, nfrags
);
237 dip
->di_size
= (nfrags
<< fs
->lfs_ffshift
);
238 dip
->di_atime
= dip
->di_mtime
= dip
->di_ctime
= fs
->lfs_tstamp
;
239 dip
->di_atimensec
= dip
->di_mtimensec
= dip
->di_ctimensec
= 0;
240 dip
->di_inumber
= ino
;
243 fsb_per_blk
= fragstofsb(fs
, blkstofrags(fs
, 1));
245 if (NDADDR
< nblocks
) {
246 /* Count up how many indirect blocks we need, recursively */
247 /* XXX We are only called with nblocks > 1 for Ifile */
248 bb
= nblocks
- NDADDR
;
250 bb
= howmany(bb
, NINDIR(fs
));
254 dip
->di_blocks
+= fragstofsb(fs
, blkstofrags(fs
, ifibc
));
257 /* Assign the block addresses for the ifile */
258 for (i
= 0; i
< MIN(nblocks
,NDADDR
); i
++) {
261 if(nblocks
> NDADDR
) {
263 bb
= howmany(nblocks
- NDADDR
, NINDIR(fs
)) - 1;
265 base
= -NDADDR
- factor
;
268 dip
->di_ib
[lvl
] = 0x0;
269 bb
= howmany(bb
, NINDIR(fs
));
271 factor
*= NINDIR(fs
);
279 * Construct a set of directory entries in "bufp". We assume that all the
280 * entries in protodir fir in the first DIRBLKSIZ.
283 make_dir(void *bufp
, struct direct
*protodir
, int entries
)
289 for (cp
= bufp
, i
= 0; i
< entries
- 1; i
++) {
290 protodir
[i
].d_reclen
= DIRSIZ(NEWDIRFMT
, &protodir
[i
], 0);
291 memmove(cp
, &protodir
[i
], protodir
[i
].d_reclen
);
292 cp
+= protodir
[i
].d_reclen
;
293 if ((spcleft
-= protodir
[i
].d_reclen
) < 0)
294 fatal("%s: %s", special
, "directory too big");
296 protodir
[i
].d_reclen
= spcleft
;
297 memmove(cp
, &protodir
[i
], DIRSIZ(NEWDIRFMT
, &protodir
[i
], 0));
301 make_lfs(int devfd
, uint secsize
, struct dkwedge_info
*dkw
, int minfree
,
302 int block_size
, int frag_size
, int seg_size
, int minfreeseg
,
303 int resvseg
, int version
, daddr_t start
, int ibsize
, int interleave
,
306 struct ufs1_dinode
*dip
; /* Pointer to a disk inode */
307 CLEANERINFO
*cip
; /* Segment cleaner information table */
308 IFILE
*ip
; /* Pointer to array of ifile structures */
309 IFILE_V1
*ip_v1
= NULL
;
310 struct lfs
*fs
; /* Superblock */
311 SEGUSE
*segp
; /* Segment usage table */
312 daddr_t sb_addr
; /* Address of superblocks */
313 daddr_t seg_addr
; /* Address of current segment */
314 int bsize
; /* Block size */
315 int fsize
; /* Fragment size */
316 int db_per_blk
; /* Disk blocks per file block */
318 int sb_interval
; /* number of segs between super blocks */
319 int ssize
; /* Segment size */
321 int warned_segtoobig
=0;
322 int label_fsb
, sb_fsb
;
326 struct uvnode
*vp
, *save_devvp
;
327 int bb
, ubb
, dmeta
, labelskew
;
328 u_int64_t tsepb
, tnseg
;
331 * Initialize buffer cache. Use a ballpark guess of the length of
332 * the segment table for the number of hash chains.
334 tnseg
= dkw
->dkw_size
/ ((seg_size
? seg_size
: DFL_LFSSEG
) / secsize
);
335 tsepb
= (block_size
? block_size
: DFL_LFSBLOCK
) / sizeof(SEGSUM
);
337 fatal("zero size partition");
338 bufinit(tnseg
/ tsepb
);
340 /* Initialize LFS subsystem with blank superblock and ifile. */
341 fs
= lfs_init(devfd
, start
, (ufs_daddr_t
)0, 1, 1/* XXX debug*/);
342 save_devvp
= fs
->lfs_devvp
;
346 fs
->lfs_devvp
= save_devvp
;
349 /* Set version first of all since it is used to compute other fields */
350 fs
->lfs_version
= version
;
352 /* If partition is not an LFS partition, warn that that is the case */
353 if (strcmp(dkw
->dkw_ptype
, DKW_PTYPE_LFS
) != 0) {
354 fatal("partition label indicated fs type \"%s\", "
355 "expected \"%s\"", dkw
->dkw_ptype
, DKW_PTYPE_LFS
);
358 if (!(bsize
= block_size
))
359 bsize
= DFL_LFSBLOCK
;
360 if (!(fsize
= frag_size
))
362 if (!(ssize
= seg_size
)) {
368 if (ibsize
<= 0 || ibsize
% fsize
)
369 fatal("illegal inode block size: %d\n", ibsize
);
370 } else if (ibsize
&& ibsize
!= bsize
)
371 fatal("cannot specify inode block size when version == 1\n");
373 /* Sanity check: fsize<=bsize<ssize */
375 /* Only complain if fsize was explicitly set */
377 fatal("fragment size must be <= block size %d", bsize
);
380 if (bsize
>= ssize
) {
381 /* Only fatal if ssize was explicitly set */
383 fatal("block size must be < segment size");
384 warnx("%s: disklabel segment size (%d) too small, using default (%d)",
385 progname
, ssize
, DFL_LFSSEG
);
388 if (start
< 0 || start
>= dkw
->dkw_size
)
389 fatal("filesystem offset %ld out of range", (long)start
);
392 warnx("filesystem offset ignored for version 1 filesystem");
393 start
= LFS_LABELPAD
/ secsize
;
397 /* Modify parts of superblock overridden by command line arguments */
398 if (bsize
!= DFL_LFSBLOCK
|| fsize
!= DFL_LFSFRAG
) {
399 fs
->lfs_bshift
= lfs_log2(bsize
);
400 if (1 << fs
->lfs_bshift
!= bsize
)
401 fatal("%d: block size not a power of 2", bsize
);
402 fs
->lfs_bsize
= bsize
;
403 fs
->lfs_fsize
= fsize
;
404 fs
->lfs_bmask
= bsize
- 1;
405 fs
->lfs_ffmask
= fsize
- 1;
406 fs
->lfs_ffshift
= lfs_log2(fsize
);
407 if (1 << fs
->lfs_ffshift
!= fsize
)
408 fatal("%d: frag size not a power of 2", fsize
);
409 fs
->lfs_frag
= numfrags(fs
, bsize
);
410 fs
->lfs_fbmask
= fs
->lfs_frag
- 1;
411 fs
->lfs_fbshift
= lfs_log2(fs
->lfs_frag
);
412 fs
->lfs_ifpb
= bsize
/ sizeof(IFILE
);
414 fs
->lfs_nindir
= bsize
/ sizeof(int32_t);
417 if (fs
->lfs_version
== 1) {
418 fs
->lfs_sumsize
= LFS_V1_SUMMARY_SIZE
;
419 fs
->lfs_segshift
= lfs_log2(ssize
);
420 if (1 << fs
->lfs_segshift
!= ssize
)
421 fatal("%d: segment size not power of 2", ssize
);
422 fs
->lfs_segmask
= ssize
- 1;
423 fs
->lfs_ifpb
= fs
->lfs_bsize
/ sizeof(IFILE_V1
);
424 fs
->lfs_ibsize
= fs
->lfs_bsize
;
425 fs
->lfs_sepb
= bsize
/ sizeof(SEGUSE_V1
);
426 fs
->lfs_ssize
= ssize
>> fs
->lfs_bshift
;
430 "Segment size %d is not a multiple of frag size; ",
432 ssize
= roundup(ssize
, fsize
);
433 fprintf(stderr
, "trying size %d.\n", ssize
);
436 fs
->lfs_sumsize
= fsize
;
437 fs
->lfs_segshift
= 0;
439 fs
->lfs_sepb
= bsize
/ sizeof(SEGUSE
);
440 fs
->lfs_ssize
= ssize
;
441 fs
->lfs_ibsize
= ibsize
;
443 fs
->lfs_inopb
= fs
->lfs_ibsize
/ sizeof(struct ufs1_dinode
);
444 fs
->lfs_minfree
= minfree
;
447 fs
->lfs_inopf
= secsize
/DINODE1_SIZE
;
448 fs
->lfs_interleave
= interleave
;
450 roll_id
= arc4random();
451 fs
->lfs_ident
= roll_id
;
455 * Fill in parts of superblock that can be computed from file system
456 * size, disk geometry and current time.
458 db_per_blk
= bsize
/secsize
;
459 fs
->lfs_blktodb
= lfs_log2(db_per_blk
);
460 fs
->lfs_fsbtodb
= lfs_log2(fsize
/ secsize
);
462 fs
->lfs_sushift
= lfs_log2(fs
->lfs_sepb
);
464 fs
->lfs_size
= dkw
->dkw_size
>> fs
->lfs_blktodb
;
466 label_fsb
= btofsb(fs
, roundup(LFS_LABELPAD
, fsize
));
467 sb_fsb
= btofsb(fs
, roundup(LFS_SBPAD
, fsize
));
468 fs
->lfs_fsbpseg
= dbtofsb(fs
, ssize
/ secsize
);
469 fs
->lfs_size
= dkw
->dkw_size
>> fs
->lfs_fsbtodb
;
470 fs
->lfs_dsize
= dbtofsb(fs
, dkw
->dkw_size
) -
471 MAX(label_fsb
, dbtofsb(fs
, start
));
472 fs
->lfs_nseg
= fs
->lfs_dsize
/ segtod(fs
, 1);
474 fs
->lfs_nclean
= fs
->lfs_nseg
- 1;
475 fs
->lfs_maxfilesize
= maxfilesize(fs
->lfs_bshift
);
478 fs
->lfs_minfreeseg
= fs
->lfs_nseg
/ DFL_MIN_FREE_SEGS
;
480 fs
->lfs_minfreeseg
= minfreeseg
;
481 if (fs
->lfs_minfreeseg
< MIN_FREE_SEGS
)
482 fs
->lfs_minfreeseg
= MIN_FREE_SEGS
;
485 fs
->lfs_resvseg
= fs
->lfs_minfreeseg
/ 2 + 1;
487 fs
->lfs_resvseg
= resvseg
;
488 if (fs
->lfs_resvseg
< MIN_RESV_SEGS
)
489 fs
->lfs_resvseg
= MIN_RESV_SEGS
;
491 if(fs
->lfs_nseg
< fs
->lfs_minfreeseg
+ 1
492 || fs
->lfs_nseg
< LFS_MIN_SBINTERVAL
+ 1)
494 if(seg_size
== 0 && ssize
> (bsize
<<1)) {
495 if(!warned_segtoobig
) {
496 fprintf(stderr
,"Segment size %d is too large; "
497 "trying smaller sizes.\n", ssize
);
498 if (ssize
== (bsize
<< 16)) {
499 fprintf(stderr
, "(Did you perhaps "
500 "accidentally leave \"16\" "
501 "in the disklabel's sgs "
509 fatal("Could not allocate enough segments with segment "
510 "size %d and block size %d;\nplease decrease the "
511 "segment size.\n", ssize
, fs
->lfs_bsize
);
515 * Now that we've determined what we're going to do, announce it
518 printf("Creating a version %d LFS", fs
->lfs_version
);
519 if (fs
->lfs_version
> 1)
520 printf(" with roll-forward ident 0x%x", fs
->lfs_ident
);
522 fssize
= (double)fs
->lfs_nseg
;
523 fssize
*= (double)ssize
;
525 printf("%.1fMB in %d segments of size %d\n", fssize
,
526 fs
->lfs_nseg
, ssize
);
529 * The number of free blocks is set from the number of segments
530 * times the segment size - lfs_minfreesegs (that we never write
531 * because we need to make sure the cleaner can run). Then
532 * we'll subtract off the room for the superblocks ifile entries
533 * and segment usage table, and half a block per segment that can't
534 * be written due to fragmentation.
536 fs
->lfs_dsize
= (fs
->lfs_nseg
- fs
->lfs_minfreeseg
) *
538 fs
->lfs_bfree
= fs
->lfs_dsize
;
539 fs
->lfs_bfree
-= dbtofsb(fs
, ((fs
->lfs_nseg
/ 2) <<
542 fs
->lfs_segtabsz
= SEGTABSIZE_SU(fs
);
543 fs
->lfs_cleansz
= CLEANSIZE_SU(fs
);
544 if ((fs
->lfs_tstamp
= time(NULL
)) == -1)
545 fatal("time: %s", strerror(errno
));
547 fs
->lfs_otstamp
= fs
->lfs_tstamp
;
549 if ((sb_interval
= fs
->lfs_nseg
/ LFS_MAXNUMSB
) < LFS_MIN_SBINTERVAL
)
550 sb_interval
= LFS_MIN_SBINTERVAL
;
553 * Figure out where the superblocks are going to live.
555 * Make segment 0 start at either zero, or LFS_LABELPAD, or
556 * >= LFS_SBPAD+LFS_LABELPAD, in order to prevent segment 0
557 * from having half a superblock in it.
559 if (fsbtodb(fs
, dbtofsb(fs
, start
)) != start
)
560 fatal("Segment 0 offset is not multiple of frag size\n");
561 if (start
!= 0 && dbtob(start
) != LFS_LABELPAD
&&
562 dbtob(start
) < LFS_SBPAD
+ LFS_LABELPAD
) {
563 fatal("Using flags \"-O %" PRId64
"\" would result in the "
564 "first segment containing only\npart of a superblock. "
565 "Please choose an offset of 0, %d, or %d or more,\n",
566 start
, btodb(LFS_LABELPAD
),
567 btodb(LFS_LABELPAD
+ LFS_SBPAD
));
569 fs
->lfs_sboffs
[0] = label_fsb
;
571 fs
->lfs_start
= fs
->lfs_sboffs
[0];
573 fs
->lfs_start
= dbtofsb(fs
, start
);
574 fs
->lfs_dsize
-= sb_fsb
;
575 for (i
= 1; i
< LFS_MAXNUMSB
; i
++) {
576 sb_addr
= ((i
* sb_interval
) * segtod(fs
, 1))
578 /* Segment 0 eats the label, except for version 1 */
579 if (fs
->lfs_version
> 1 && fs
->lfs_start
< label_fsb
)
580 sb_addr
-= label_fsb
- start
;
581 if (sb_addr
+ sizeof(struct dlfs
)
582 >= dbtofsb(fs
, dkw
->dkw_size
))
584 fs
->lfs_sboffs
[i
] = sb_addr
;
585 fs
->lfs_dsize
-= sb_fsb
;
588 /* We need >= 2 superblocks */
589 if(fs
->lfs_sboffs
[1] == 0x0) {
590 fatal("Could not assign a disk address for the second "
591 "superblock.\nPlease decrease the segment size.\n");
594 fs
->lfs_lastseg
= sntod(fs
, fs
->lfs_nseg
- 2);
595 fs
->lfs_curseg
= sntod(fs
, fs
->lfs_nseg
- 1);
596 fs
->lfs_offset
= sntod(fs
, fs
->lfs_nseg
);
597 fs
->lfs_nextseg
= sntod(fs
, 0);
600 * Initialize the Ifile inode. Do this before we do anything
601 * with the Ifile or segment tables.
603 dip
= VTOI(fs
->lfs_ivnode
)->i_din
.ffs1_din
= (struct ufs1_dinode
*)
604 malloc(sizeof(*dip
));
607 memset(dip
, 0, sizeof(*dip
));
608 dip
->di_mode
= IFREG
|IREAD
|IWRITE
;
609 dip
->di_flags
= SF_IMMUTABLE
;
610 make_dinode(LFS_IFILE_INUM
, dip
,
611 blkstofrags(fs
, fs
->lfs_cleansz
+ fs
->lfs_segtabsz
+ 1), fs
);
612 dip
->di_size
= (fs
->lfs_cleansz
+ fs
->lfs_segtabsz
+ 1) << fs
->lfs_bshift
;
613 for (i
= 0; i
< NDADDR
&& i
< (dip
->di_size
>> fs
->lfs_bshift
); i
++)
614 VTOI(fs
->lfs_ivnode
)->i_lfs_fragsize
[i
] = fs
->lfs_bsize
;
617 * Set up in-superblock segment usage cache
619 fs
->lfs_suflags
= (u_int32_t
**) malloc(2 * sizeof(u_int32_t
*));
620 if (fs
->lfs_suflags
== NULL
)
622 fs
->lfs_suflags
[0] = (u_int32_t
*) malloc(fs
->lfs_nseg
* sizeof(u_int32_t
));
623 if (fs
->lfs_suflags
[0] == NULL
)
625 fs
->lfs_suflags
[1] = (u_int32_t
*) malloc(fs
->lfs_nseg
* sizeof(u_int32_t
));
626 if (fs
->lfs_suflags
[1] == NULL
)
630 * Initialize the cleanerinfo block
632 LFS_CLEANERINFO(cip
, fs
, bp
);
633 cip
->clean
= fs
->lfs_nseg
;
636 cip
->free_head
= HIGHEST_USED_INO
+ 1;
637 cip
->free_tail
= fs
->lfs_ifpb
- 1;
639 LFS_SYNC_CLEANERINFO(cip
, fs
, bp
, 1);
642 * Run through segment table and initialize that
644 for (i
= j
= 0; i
< fs
->lfs_nseg
; i
++) {
645 LFS_SEGENTRY(segp
, fs
, i
, bp
);
648 fs
->lfs_start
< btofsb(fs
, LFS_LABELPAD
+ LFS_SBPAD
)) {
649 segp
->su_flags
= SEGUSE_SUPERBLOCK
;
650 fs
->lfs_bfree
-= sb_fsb
;
654 if ((i
% sb_interval
) == 0 && j
< LFS_MAXNUMSB
) {
655 segp
->su_flags
= SEGUSE_SUPERBLOCK
;
656 fs
->lfs_bfree
-= sb_fsb
;
661 segp
->su_lastmod
= 0;
666 LFS_WRITESEGENTRY(segp
, fs
, i
, bp
);
669 /* Initialize root directory */
670 vp
= lfs_raw_vget(fs
, ROOTINO
, devfd
, 0x0);
671 dip
= VTOI(vp
)->i_din
.ffs1_din
;
672 make_dinode(ROOTINO
, dip
, howmany(DIRBLKSIZ
,fs
->lfs_fsize
), fs
);
673 dip
->di_mode
= IFDIR
| UMASK
;
674 VTOI(vp
)->i_lfs_osize
= dip
->di_size
= DIRBLKSIZ
;
676 VTOI(vp
)->i_nlink
= dip
->di_nlink
= 3;
678 VTOI(vp
)->i_nlink
= dip
->di_nlink
= 2;
680 VTOI(vp
)->i_lfs_effnblks
= dip
->di_blocks
=
681 btofsb(fs
, roundup(DIRBLKSIZ
,fs
->lfs_fsize
));
682 for (i
= 0; i
< NDADDR
&& i
< howmany(DIRBLKSIZ
, fs
->lfs_bsize
); i
++)
683 VTOI(vp
)->i_lfs_fragsize
[i
] = fs
->lfs_bsize
;
684 if (DIRBLKSIZ
< fs
->lfs_bsize
)
685 VTOI(vp
)->i_lfs_fragsize
[i
- 1] =
686 roundup(DIRBLKSIZ
,fs
->lfs_fsize
);
687 bread(vp
, 0, fs
->lfs_fsize
, NOCRED
, 0, &bp
);
688 make_dir(bp
->b_data
, lfs_root_dir
,
689 sizeof(lfs_root_dir
) / sizeof(struct direct
));
693 /* Initialize lost+found directory */
694 vp
= lfs_raw_vget(fs
, LOSTFOUNDINO
, devfd
, 0x0);
695 dip
= VTOI(vp
)->i_din
.ffs1_din
;
696 make_dinode(LOSTFOUNDINO
, dip
, howmany(DIRBLKSIZ
,fs
->lfs_fsize
), fs
);
697 dip
->di_mode
= IFDIR
| UMASK
;
698 VTOI(vp
)->i_lfs_osize
= dip
->di_size
= DIRBLKSIZ
;
699 VTOI(vp
)->i_nlink
= dip
->di_nlink
= 2;
700 VTOI(vp
)->i_lfs_effnblks
= dip
->di_blocks
=
701 btofsb(fs
, roundup(DIRBLKSIZ
,fs
->lfs_fsize
));
702 for (i
= 0; i
< NDADDR
&& i
< howmany(DIRBLKSIZ
, fs
->lfs_bsize
); i
++)
703 VTOI(vp
)->i_lfs_fragsize
[i
] = fs
->lfs_bsize
;
704 if (DIRBLKSIZ
< fs
->lfs_bsize
)
705 VTOI(vp
)->i_lfs_fragsize
[i
- 1] =
706 roundup(DIRBLKSIZ
,fs
->lfs_fsize
);
707 bread(vp
, 0, fs
->lfs_fsize
, NOCRED
, 0, &bp
);
708 make_dir(bp
->b_data
, lfs_lf_dir
,
709 sizeof(lfs_lf_dir
) / sizeof(struct direct
));
711 #endif /* MAKE_LF_DIR */
713 /* Set their IFILE entry version numbers to 1 */
714 LFS_IENTRY(ip
, fs
, 1, bp
);
716 ip_v1
= (IFILE_V1
*)ip
;
717 for (i
= LFS_IFILE_INUM
; i
<= HIGHEST_USED_INO
; i
++) {
718 ip_v1
->if_version
= 1;
719 ip_v1
->if_daddr
= 0x0;
720 ip_v1
->if_nextfree
= 0;
724 for (i
= LFS_IFILE_INUM
; i
<= HIGHEST_USED_INO
; i
++) {
731 /* Link remaining IFILE entries in free list */
734 i
< fs
->lfs_ifpb
; ++ip_v1
) {
735 ip_v1
->if_version
= 1;
736 ip_v1
->if_daddr
= LFS_UNUSED_DADDR
;
737 ip_v1
->if_nextfree
= ++i
;
740 ip_v1
->if_nextfree
= LFS_UNUSED_INUM
;
743 i
< fs
->lfs_ifpb
; ++ip
) {
745 ip
->if_daddr
= LFS_UNUSED_DADDR
;
746 ip
->if_nextfree
= ++i
;
749 ip
->if_nextfree
= LFS_UNUSED_INUM
;
753 /* Write it all to disk. */
755 lfs_segwrite(fs
, SEGM_CKP
);
758 * Now that we've written everything, look to see what's available
762 bb
= ubb
= dmeta
= 0;
763 for (i
= 0; i
< fs
->lfs_nseg
; i
++) {
764 LFS_SEGENTRY(segp
, fs
, i
, bp
);
765 if (segp
->su_flags
& SEGUSE_DIRTY
) {
766 bb
+= btofsb(fs
, segp
->su_nbytes
+
767 segp
->su_nsums
* fs
->lfs_sumsize
);
768 ubb
+= btofsb(fs
, segp
->su_nbytes
+
769 segp
->su_nsums
* fs
->lfs_sumsize
+
770 segp
->su_ninos
* fs
->lfs_ibsize
);
772 fs
->lfs_sumsize
* segp
->su_nsums
);
774 fs
->lfs_ibsize
* segp
->su_ninos
);
776 fs
->lfs_avail
+= segtod(fs
, 1);
777 if (segp
->su_flags
& SEGUSE_SUPERBLOCK
)
778 fs
->lfs_avail
-= btofsb(fs
, LFS_SBPAD
);
779 if (i
== 0 && fs
->lfs_version
> 1 &&
780 fs
->lfs_start
< btofsb(fs
, LFS_LABELPAD
))
781 fs
->lfs_avail
-= btofsb(fs
, LFS_LABELPAD
) -
786 /* Also may be available bytes in current seg */
787 i
= dtosn(fs
, fs
->lfs_offset
);
788 fs
->lfs_avail
+= sntod(fs
, i
+ 1) - fs
->lfs_offset
;
789 /* But do not count minfreesegs */
790 fs
->lfs_avail
-= segtod(fs
, (fs
->lfs_minfreeseg
- (fs
->lfs_minfreeseg
/ 2)));
793 if (fs
->lfs_version
> 1 && fs
->lfs_start
< btofsb(fs
, LFS_LABELPAD
))
794 labelskew
= btofsb(fs
, LFS_LABELPAD
);
795 fs
->lfs_bfree
= fs
->lfs_dsize
- labelskew
- (ubb
+ bb
) / 2;
797 /* Put that in the Ifile version too, and write it */
798 LFS_CLEANERINFO(cip
, fs
, bp
);
799 cip
->bfree
= fs
->lfs_bfree
;
800 cip
->avail
= fs
->lfs_avail
;
801 LFS_SYNC_CLEANERINFO(cip
, fs
, bp
, 1);
803 lfs_segwrite(fs
, SEGM_CKP
);
806 * Finally write out superblocks.
808 printf("super-block backups (for fsck -b #) at:\n");
810 for (i
= 0; i
< LFS_MAXNUMSB
; i
++) {
811 seg_addr
= fs
->lfs_sboffs
[i
];
816 curw
+= printf(", ");
817 ww
= snprintf(tbuf
, sizeof(tbuf
), "%lld",
818 (long long)fsbtodb(fs
, seg_addr
));
821 printf("\n%s", tbuf
);
827 /* Leave the time stamp on the alt sb, zero the rest */
830 fs
->lfs_cksum
= lfs_sb_cksum(&(fs
->lfs_dlfs
));
833 lfs_writesuper(fs
, seg_addr
);
841 * Compatibility with fsck_lfs, since the "generic" LFS userland code uses it.
844 pwarn(const char *fmt
, ...)
849 vfprintf(stderr
, fmt
, ap
);