1 /* $NetBSD: setup.c,v 1.35 2008/04/28 20:23:08 martin 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) 1980, 1986, 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 /* #define DKTYPENAMES */
62 #include <sys/types.h>
63 #include <sys/param.h>
66 #include <sys/mount.h>
67 #include <sys/queue.h>
69 #include <sys/ioctl.h>
70 #include <sys/disklabel.h>
73 #include <ufs/ufs/inode.h>
74 #include <ufs/ufs/ufsmount.h>
76 #include <ufs/lfs/lfs.h>
96 extern u_int32_t
cksum(void *, size_t);
97 static struct disklabel
*getdisklabel(const char *, int);
98 static uint64_t calcmaxfilesize(int);
100 ufs_daddr_t
*din_table
;
109 char **foo
= (char **) dktypenames
;
110 char **bar
= (char **) fscknames
;
117 * calculate the maximum file size allowed with the specified block shift.
120 calcmaxfilesize(int bshift
)
122 uint64_t nptr
; /* number of block pointers per block */
125 nptr
= (1 << bshift
) / sizeof(uint32_t);
126 maxblock
= NDADDR
+ nptr
+ nptr
* nptr
+ nptr
* nptr
* nptr
;
128 return maxblock
<< bshift
;
132 reset_maxino(ino_t len
)
135 pwarn("maxino reset from %lld to %lld\n", (long long)maxino
,
138 din_table
= erealloc(din_table
, len
* sizeof(*din_table
));
139 statemap
= erealloc(statemap
, len
* sizeof(char));
140 typemap
= erealloc(typemap
, len
* sizeof(char));
141 lncntp
= erealloc(lncntp
, len
* sizeof(int16_t));
143 memset(din_table
+ maxino
, 0, (len
- maxino
) * sizeof(*din_table
));
144 memset(statemap
+ maxino
, USTATE
, (len
- maxino
) * sizeof(char));
145 memset(typemap
+ maxino
, 0, (len
- maxino
) * sizeof(char));
146 memset(lncntp
+ maxino
, 0, (len
- maxino
) * sizeof(int16_t));
151 * We can't roll forward after allocating new inodes in previous
152 * phases, or thy would conflict (lost+found, for example, might
153 * disappear to be replaced by a file found in roll-forward).
160 extern time_t write_time
;
163 setup(const char *dev
)
166 struct disklabel
*lp
;
169 u_int64_t maxfilesize
;
178 doskipclean
= skipclean
;
179 if (stat(dev
, &statb
) < 0) {
180 pfatal("Can't stat %s: %s\n", dev
, strerror(errno
));
183 if (!S_ISCHR(statb
.st_mode
) && skipclean
) {
184 pfatal("%s is not a character device", dev
);
185 if (reply("CONTINUE") == 0)
189 open_flags
= O_RDONLY
;
193 if ((fsreadfd
= open(dev
, open_flags
)) < 0) {
194 pfatal("Can't open %s: %s\n", dev
, strerror(errno
));
199 pfatal("NO WRITE ACCESS");
200 printf("** %s (NO WRITE)\n", dev
);
202 } else if (!preen
&& !quiet
)
203 printf("** %s\n", dev
);
208 /* Initialize time in case we have to write */
211 bufinit(0); /* XXX we could make a better guess */
212 fs
= lfs_init(fsreadfd
, bflag
, idaddr
, 0, debug
);
215 printf("%s: ", cdevname());
216 errexit("BAD SUPER BLOCK OR IFILE INODE NOT FOUND");
218 if ((lp
= getdisklabel((char *) NULL
, fsreadfd
)) != NULL
)
219 dev_bsize
= secsize
= lp
->d_secsize
;
221 dev_bsize
= secsize
= DEV_BSIZE
;
223 /* Resize buffer cache now that we have a superblock to guess from. */
224 bufrehash((fs
->lfs_segtabsz
+ maxino
/ fs
->lfs_ifpb
) << 4);
226 if (fs
->lfs_pflags
& LFS_PF_CLEAN
) {
229 pwarn("%sile system is clean; not checking\n",
230 preen
? "f" : "** F");
234 pwarn("** File system is already clean\n");
244 pwarn("adjusting offset, serial for -i 0x%lx\n",
245 (unsigned long)idaddr
);
246 tdaddr
= sntod(fs
, dtosn(fs
, idaddr
));
247 if (sntod(fs
, dtosn(fs
, tdaddr
)) == tdaddr
) {
248 if (tdaddr
== fs
->lfs_start
)
249 tdaddr
+= btofsb(fs
, LFS_LABELPAD
);
250 for (i
= 0; i
< LFS_MAXNUMSB
; i
++) {
251 if (fs
->lfs_sboffs
[i
] == tdaddr
)
252 tdaddr
+= btofsb(fs
, LFS_SBPAD
);
253 if (fs
->lfs_sboffs
[i
] > tdaddr
)
257 fs
->lfs_offset
= tdaddr
;
259 pwarn("begin with offset/serial 0x%x/%d\n",
260 (int)fs
->lfs_offset
, (int)fs
->lfs_serial
);
261 while (tdaddr
< idaddr
) {
262 bread(fs
->lfs_devvp
, fsbtodb(fs
, tdaddr
),
265 sp
= (SEGSUM
*)bp
->b_data
;
266 if (sp
->ss_sumsum
!= cksum(&sp
->ss_datasum
,
268 sizeof(sp
->ss_sumsum
))) {
271 printf("bad cksum at %x\n",
275 fp
= (FINFO
*)(sp
+ 1);
276 bc
= howmany(sp
->ss_ninos
, INOPB(fs
)) <<
277 (fs
->lfs_version
> 1 ? fs
->lfs_ffshift
:
279 for (i
= 0; i
< sp
->ss_nfinfo
; i
++) {
280 bc
+= fp
->fi_lastlength
+ ((fp
->fi_nblocks
- 1)
282 fp
= (FINFO
*)(fp
->fi_blocks
+ fp
->fi_nblocks
);
285 tdaddr
+= btofsb(fs
, bc
) + 1;
286 fs
->lfs_offset
= tdaddr
;
287 fs
->lfs_serial
= sp
->ss_serial
+ 1;
292 * Set curseg, nextseg appropriately -- inlined from
295 curseg
= dtosn(fs
, fs
->lfs_offset
);
296 fs
->lfs_curseg
= sntod(fs
, curseg
);
297 for (sn
= curseg
+ fs
->lfs_interleave
;;) {
298 sn
= (sn
+ 1) % fs
->lfs_nseg
;
300 errx(1, "init: no clean segments");
301 LFS_SEGENTRY(sup
, fs
, sn
, bp
);
302 isdirty
= sup
->su_flags
& SEGUSE_DIRTY
;
309 /* Skip superblock if necessary */
310 for (i
= 0; i
< LFS_MAXNUMSB
; i
++)
311 if (fs
->lfs_offset
== fs
->lfs_sboffs
[i
])
312 fs
->lfs_offset
+= btofsb(fs
, LFS_SBPAD
);
315 fs
->lfs_nextseg
= sntod(fs
, sn
);
317 pwarn("offset = 0x%" PRIx32
", serial = %" PRId64
"\n",
318 fs
->lfs_offset
, fs
->lfs_serial
);
319 pwarn("curseg = %" PRIx32
", nextseg = %" PRIx32
"\n",
320 fs
->lfs_curseg
, fs
->lfs_nextseg
);
323 if (!nflag
&& !skipclean
) {
324 fs
->lfs_idaddr
= idaddr
;
331 pwarn("idaddr = 0x%lx\n", idaddr
? (unsigned long)idaddr
:
332 (unsigned long)fs
->lfs_idaddr
);
333 pwarn("dev_bsize = %lu\n", dev_bsize
);
334 pwarn("lfs_bsize = %lu\n", (unsigned long) fs
->lfs_bsize
);
335 pwarn("lfs_fsize = %lu\n", (unsigned long) fs
->lfs_fsize
);
336 pwarn("lfs_frag = %lu\n", (unsigned long) fs
->lfs_frag
);
337 pwarn("lfs_inopb = %lu\n", (unsigned long) fs
->lfs_inopb
);
339 if (fs
->lfs_version
== 1)
340 maxfsblock
= fs
->lfs_size
* (fs
->lfs_bsize
/ dev_bsize
);
342 maxfsblock
= fs
->lfs_size
;
343 maxfilesize
= calcmaxfilesize(fs
->lfs_bshift
);
344 if (/* fs->lfs_minfree < 0 || */ fs
->lfs_minfree
> 99) {
345 pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
347 if (reply("SET TO DEFAULT") == 1) {
348 fs
->lfs_minfree
= 10;
352 if (fs
->lfs_bmask
!= fs
->lfs_bsize
- 1) {
353 pwarn("INCORRECT BMASK=0x%x IN SUPERBLOCK (SHOULD BE 0x%x)",
354 (unsigned int) fs
->lfs_bmask
,
355 (unsigned int) fs
->lfs_bsize
- 1);
356 fs
->lfs_bmask
= fs
->lfs_bsize
- 1;
358 printf(" (FIXED)\n");
359 if (preen
|| reply("FIX") == 1) {
363 if (fs
->lfs_ffmask
!= fs
->lfs_fsize
- 1) {
364 pwarn("INCORRECT FFMASK=%" PRId64
" IN SUPERBLOCK",
366 fs
->lfs_ffmask
= fs
->lfs_fsize
- 1;
368 printf(" (FIXED)\n");
369 if (preen
|| reply("FIX") == 1) {
373 if (fs
->lfs_fbmask
!= (1 << fs
->lfs_fbshift
) - 1) {
374 pwarn("INCORRECT FFMASK=%" PRId64
" IN SUPERBLOCK",
376 fs
->lfs_fbmask
= (1 << fs
->lfs_fbshift
) - 1;
378 printf(" (FIXED)\n");
379 if (preen
|| reply("FIX") == 1) {
383 if (fs
->lfs_maxfilesize
!= maxfilesize
) {
385 "INCORRECT MAXFILESIZE=%llu IN SUPERBLOCK (SHOULD BE %llu WITH BSHIFT %d)",
386 (unsigned long long) fs
->lfs_maxfilesize
,
387 (unsigned long long) maxfilesize
, (int)fs
->lfs_bshift
);
389 printf(" (FIXED)\n");
390 if (preen
|| reply("FIX") == 1) {
391 fs
->lfs_maxfilesize
= maxfilesize
;
395 if (fs
->lfs_maxsymlinklen
!= MAXSYMLINKLEN_UFS1
) {
396 pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK",
397 fs
->lfs_maxsymlinklen
);
398 fs
->lfs_maxsymlinklen
= MAXSYMLINKLEN_UFS1
;
400 printf(" (FIXED)\n");
401 if (preen
|| reply("FIX") == 1) {
407 * Read in the Ifile; we'll be using it a lot.
408 * XXX If the Ifile is corrupted we are in bad shape. We need to
409 * XXX run through the segment headers of the entire disk to
410 * XXX reconstruct the inode table, then pretend all segments are
411 * XXX dirty while we do the rest.
413 ivp
= fs
->lfs_ivnode
;
414 maxino
= ((VTOI(ivp
)->i_ffs1_size
- (fs
->lfs_cleansz
+ fs
->lfs_segtabsz
)
415 * fs
->lfs_bsize
) / fs
->lfs_bsize
) * fs
->lfs_ifpb
;
417 pwarn("maxino = %llu\n", (unsigned long long)maxino
);
418 for (i
= 0; i
< VTOI(ivp
)->i_ffs1_size
; i
+= fs
->lfs_bsize
) {
419 bread(ivp
, i
>> fs
->lfs_bshift
, fs
->lfs_bsize
, NOCRED
, 0, &bp
);
420 /* XXX check B_ERROR */
425 * allocate and initialize the necessary maps
427 din_table
= ecalloc(maxino
, sizeof(*din_table
));
428 seg_table
= ecalloc(fs
->lfs_nseg
, sizeof(SEGUSE
));
429 /* Get segment flags */
430 for (i
= 0; i
< fs
->lfs_nseg
; i
++) {
431 LFS_SEGENTRY(sup
, fs
, i
, bp
);
432 seg_table
[i
].su_flags
= sup
->su_flags
& ~SEGUSE_ACTIVE
;
434 seg_table
[i
].su_nbytes
= sup
->su_nbytes
;
438 /* Initialize Ifile entry */
439 din_table
[fs
->lfs_ifile
] = fs
->lfs_idaddr
;
440 seg_table
[dtosn(fs
, fs
->lfs_idaddr
)].su_nbytes
+= DINODE1_SIZE
;
442 #ifndef VERBOSE_BLOCKMAP
443 bmapsize
= roundup(howmany(maxfsblock
, NBBY
), sizeof(int16_t));
444 blockmap
= ecalloc(bmapsize
, sizeof(char));
446 bmapsize
= maxfsblock
* sizeof(ino_t
);
447 blockmap
= ecalloc(maxfsblock
, sizeof(ino_t
));
449 statemap
= ecalloc(maxino
, sizeof(char));
450 typemap
= ecalloc(maxino
, sizeof(char));
451 lncntp
= ecalloc(maxino
, sizeof(int16_t));
454 n_files
= fs
->lfs_nfiles
;
455 n_blks
= fs
->lfs_dsize
- fs
->lfs_bfree
;
458 listmax
= numdirs
+ 10;
459 inpsort
= ecalloc(listmax
, sizeof(struct inoinfo
*));
460 inphead
= ecalloc(numdirs
, sizeof(struct inoinfo
*));
469 static struct disklabel
*
470 getdisklabel(const char *s
, int fd
)
472 static struct disklabel lab
;
474 if (ioctl(fd
, DIOCGDINFO
, (char *) &lab
) < 0) {
476 return ((struct disklabel
*) NULL
);
477 pwarn("ioctl (GCINFO): %s\n", strerror(errno
));