2 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
5 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
6 /* All Rights Reserved */
9 * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
10 * All rights reserved.
12 * Redistribution and use in source and binary forms are permitted
13 * provided that: (1) source distributions retain this entire copyright
14 * notice and comment, and (2) distributions including binaries display
15 * the following acknowledgement: ``This product includes software
16 * developed by the University of California, Berkeley and its contributors''
17 * in the documentation or other materials provided with the distribution
18 * and in all advertising materials mentioning features or use of this
19 * software. Neither the name of the University nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
31 #include <sys/param.h>
32 #include <sys/mntent.h>
33 #include <sys/fs/ufs_fs.h>
34 #include <sys/vnode.h>
35 #include <sys/fs/ufs_inode.h>
38 static int check_maps(uchar_t
*, uchar_t
*, int, int, char *, int, int);
44 int32_t c
, blk
, frags
;
45 size_t basesize
, sumsize
, mapsize
;
47 int inomapsize
, blkmapsize
;
48 int update_csums
, update_bitmaps
;
49 int bad_csum_sb
, bad_csum_cg
, bad_cgblks_cg
, bad_cgblktot_cg
;
50 struct fs
*fs
= &sblock
;
51 struct cg
*cg
= &cgrp
;
52 diskaddr_t dbase
, dmax
;
56 struct csum backup_cs
;
60 union { /* keep lint happy about alignment */
61 struct cg cg
; /* the rest of buf has the bitmaps */
65 struct cg
*newcg
= &u
.cg
;
67 (void) memset((void *)buf
, 0, sizeof (u
.buf
));
68 newcg
->cg_niblk
= fs
->fs_ipg
;
70 if (fs
->fs_postblformat
!= FS_DYNAMICPOSTBLFMT
) {
71 pfatal("UNSUPPORTED ROTATIONAL TABLE FORMAT %d\n",
73 errexit("Program terminated.");
77 /* LINTED this subtraction can't overflow and is int32-aligned */
78 basesize
= &newcg
->cg_space
[0] - (uchar_t
*)newcg
;
81 * We reserve the space for the old rotation summary
82 * tables for the benefit of old kernels, but do not
83 * maintain them in modern kernels. In time, they could
84 * theoretically go away, if we wanted to deal with
85 * changing the on-disk format.
89 * Note that we don't use any of the cg_*() macros until
90 * after cg_sanity() has approved of what we've got.
92 newcg
->cg_btotoff
= basesize
;
93 newcg
->cg_boff
= newcg
->cg_btotoff
+ fs
->fs_cpg
* sizeof (daddr32_t
);
94 newcg
->cg_iusedoff
= newcg
->cg_boff
+
95 fs
->fs_cpg
* fs
->fs_nrpos
* sizeof (uint16_t);
96 (void) memset(&newcg
->cg_space
[0], 0, newcg
->cg_iusedoff
- basesize
);
98 inomapsize
= howmany(fs
->fs_ipg
, NBBY
);
99 newcg
->cg_freeoff
= newcg
->cg_iusedoff
+ inomapsize
;
100 blkmapsize
= howmany(fs
->fs_fpg
, NBBY
);
101 newcg
->cg_nextfreeoff
= newcg
->cg_freeoff
+ blkmapsize
;
102 newcg
->cg_magic
= CG_MAGIC
;
104 sumsize
= newcg
->cg_iusedoff
- newcg
->cg_btotoff
;
105 mapsize
= newcg
->cg_nextfreeoff
- newcg
->cg_iusedoff
;
107 init_inodesc(&idesc
);
108 idesc
.id_type
= ADDR
;
109 (void) memset((void *)&cstotal
, 0, sizeof (struct csum
));
113 * If the last fragments in the file system don't make up a
114 * full file system block, mark the bits in the blockmap
115 * that correspond to those missing fragments as "allocated",
116 * so that the last block doesn't get counted as a free block
117 * and those missing fragments don't get counted as free frags.
119 j
= blknum(fs
, (uint64_t)fs
->fs_size
+ fs
->fs_frag
- 1);
120 for (i
= fs
->fs_size
; i
< j
; i
++)
124 * The cg summaries are not always updated when using
125 * logging. Since we're really concerned with getting a
126 * sane filesystem, rather than in trying to debug UFS
127 * corner cases, logically we would just always recompute
128 * them. However, it is disconcerting to users to be asked
129 * about updating the summaries when, from their point of
130 * view, there's been no indication of a problem up to this
131 * point. So, only do it if we find a discrepancy.
135 for (c
= 0; c
< fs
->fs_ncg
; c
++) {
139 * cg_sanity() will catch i/o errors for us.
141 (void) getblk(&cgblk
, (diskaddr_t
)cgtod(fs
, c
),
142 (size_t)fs
->fs_cgsize
);
143 err
= cg_sanity(cg
, c
);
145 pfatal("CG %d: %s\n", c
, err
);
147 if (reply("REPAIR") == 0)
148 errexit("Program terminated.");
152 * If the on-disk timestamp is in the future, then it
153 * by definition is wrong. Otherwise, if it's in
154 * the past, then use that value so that we don't
155 * declare a spurious mismatch.
157 if (now
> cg
->cg_time
)
158 newcg
->cg_time
= cg
->cg_time
;
160 newcg
->cg_time
= now
;
162 dbase
= cgbase(fs
, c
);
163 dmax
= dbase
+ fs
->fs_fpg
;
164 if (dmax
> fs
->fs_size
)
166 newcg
->cg_ndblk
= dmax
- dbase
;
167 if (c
== fs
->fs_ncg
- 1)
168 newcg
->cg_ncyl
= fs
->fs_ncyl
- (fs
->fs_cpg
* c
);
170 newcg
->cg_ncyl
= fs
->fs_cpg
;
171 newcg
->cg_niblk
= sblock
.fs_ipg
;
172 newcg
->cg_cs
.cs_ndir
= 0;
173 newcg
->cg_cs
.cs_nffree
= 0;
174 newcg
->cg_cs
.cs_nbfree
= 0;
175 newcg
->cg_cs
.cs_nifree
= fs
->fs_ipg
;
176 if ((cg
->cg_rotor
>= 0) && (cg
->cg_rotor
< newcg
->cg_ndblk
))
177 newcg
->cg_rotor
= cg
->cg_rotor
;
180 if ((cg
->cg_frotor
>= 0) && (cg
->cg_frotor
< newcg
->cg_ndblk
))
181 newcg
->cg_frotor
= cg
->cg_frotor
;
183 newcg
->cg_frotor
= 0;
184 if ((cg
->cg_irotor
>= 0) && (cg
->cg_irotor
< newcg
->cg_niblk
))
185 newcg
->cg_irotor
= cg
->cg_irotor
;
187 newcg
->cg_irotor
= 0;
188 (void) memset((void *)&newcg
->cg_frsum
[0], 0,
189 sizeof (newcg
->cg_frsum
));
190 (void) memset((void *)cg_inosused(newcg
), 0, (size_t)mapsize
);
191 /* LINTED macro is int32-aligned per newcg->cg_btotoff above */
192 (void) memset((void *)&cg_blktot(newcg
)[0], 0,
195 for (i
= 0; i
< fs
->fs_ipg
; j
++, i
++) {
196 switch (statemap
[j
] & ~(INORPHAN
| INDELAYD
)) {
205 newcg
->cg_cs
.cs_ndir
++;
213 newcg
->cg_cs
.cs_nifree
--;
214 setbit(cg_inosused(newcg
), i
);
220 errexit("BAD STATE 0x%x FOR INODE I=%d",
221 statemap
[j
], (int)j
);
225 for (i
= 0; i
< UFSROOTINO
; i
++) {
226 setbit(cg_inosused(newcg
), i
);
227 newcg
->cg_cs
.cs_nifree
--;
231 * Count up what fragments and blocks are free, and
232 * reflect the relevant section of blockmap[] into
235 for (i
= 0, d
= dbase
;
237 d
+= fs
->fs_frag
, i
+= fs
->fs_frag
) {
239 for (j
= 0; j
< fs
->fs_frag
; j
++) {
242 setbit(cg_blksfree(newcg
), i
+ j
);
245 if (frags
== fs
->fs_frag
) {
246 newcg
->cg_cs
.cs_nbfree
++;
247 j
= cbtocylno(fs
, i
);
248 /* LINTED macro is int32-aligned per above */
249 cg_blktot(newcg
)[j
]++;
250 /* LINTED cg_blks(newcg) is aligned */
251 cg_blks(fs
, newcg
, j
)[cbtorpos(fs
, i
)]++;
252 } else if (frags
> 0) {
253 newcg
->cg_cs
.cs_nffree
+= frags
;
254 blk
= blkmap(fs
, cg_blksfree(newcg
), i
);
255 fragacct(fs
, blk
, newcg
->cg_frsum
, 1);
258 cstotal
.cs_nffree
+= newcg
->cg_cs
.cs_nffree
;
259 cstotal
.cs_nbfree
+= newcg
->cg_cs
.cs_nbfree
;
260 cstotal
.cs_nifree
+= newcg
->cg_cs
.cs_nifree
;
261 cstotal
.cs_ndir
+= newcg
->cg_cs
.cs_ndir
;
264 * Note that, just like the kernel, we dynamically
265 * allocated an array to hold the csums and stuffed
266 * the pointer into the in-core superblock's fs_u.fs_csp
267 * field. This means that the fs_u field contains a
268 * random value when the disk version is examined, but
269 * fs_cs() gives us a valid pointer nonetheless.
270 * We need to compare the recalculated summaries to
271 * both the superblock version and the on disk version.
272 * If either is bad, copy the calculated version over
273 * the corrupt values.
276 cs
= &fs
->fs_cs(fs
, c
);
277 bad_csum_sb
= (memcmp((void *)cs
, (void *)&newcg
->cg_cs
,
280 bad_csum_cg
= (memcmp((void *)&cg
->cg_cs
, (void *)&newcg
->cg_cs
,
281 sizeof (struct csum
)) != 0);
284 * Has the user told us what to do yet? If not, find out.
286 if ((bad_csum_sb
|| bad_csum_cg
) && (update_csums
== -1)) {
289 (void) printf("CORRECTING BAD CG SUMMARIES"
291 } else if (update_csums
== -1) {
292 update_csums
= (reply(
293 "CORRECT BAD CG SUMMARIES FOR CG %d",
298 if (bad_csum_sb
&& (update_csums
== 1)) {
299 (void) memmove((void *)cs
, (void *)&newcg
->cg_cs
,
302 (void) printf("CORRECTED SUPERBLOCK SUMMARIES FOR"
306 if (bad_csum_cg
&& (update_csums
== 1)) {
307 (void) memmove((void *)cg
, (void *)newcg
,
309 /* LINTED per cg_sanity() */
310 (void) memmove((void *)&cg_blktot(cg
)[0],
311 /* LINTED macro aligned as above */
312 (void *)&cg_blktot(newcg
)[0], sumsize
);
314 (void) printf("CORRECTED SUMMARIES FOR CG %d\n", c
);
317 excessdirs
= cg
->cg_cs
.cs_ndir
- newcg
->cg_cs
.cs_ndir
;
318 if (excessdirs
< 0) {
319 pfatal("LOST %d DIRECTORIES IN CG %d\n",
323 if (excessdirs
> 0) {
324 if (check_maps((uchar_t
*)cg_inosused(newcg
),
325 (uchar_t
*)cg_inosused(cg
), inomapsize
,
326 cg
->cg_cgx
* fs
->fs_ipg
, "DIR", 0, excessdirs
)) {
328 (void) printf("DIR BITMAP WRONG ");
329 if (preen
|| update_bitmaps
||
331 (void) memmove((void *)cg_inosused(cg
),
332 (void *)cg_inosused(newcg
),
336 (!verbose
&& update_bitmaps
))
337 (void) printf("(CORRECTED)\n");
343 if (check_maps((uchar_t
*)cg_inosused(newcg
),
344 (uchar_t
*)cg_inosused(cg
), inomapsize
,
345 cg
->cg_cgx
* fs
->fs_ipg
, "FILE", excessdirs
, fs
->fs_ipg
)) {
347 (void) printf("FILE BITMAP WRONG ");
348 if (preen
|| update_bitmaps
|| reply("FIX") == 1) {
349 (void) memmove((void *)cg_inosused(cg
),
350 (void *)cg_inosused(newcg
), inomapsize
);
353 (!verbose
&& update_bitmaps
))
354 (void) printf("(CORRECTED)\n");
359 if (check_maps((uchar_t
*)cg_blksfree(cg
),
360 (uchar_t
*)cg_blksfree(newcg
), blkmapsize
,
361 cg
->cg_cgx
* fs
->fs_fpg
, "FRAG", 0, fs
->fs_fpg
)) {
363 (void) printf("FRAG BITMAP WRONG ");
364 if (preen
|| update_bitmaps
|| reply("FIX") == 1) {
365 (void) memmove((void *)cg_blksfree(cg
),
366 (void *)cg_blksfree(newcg
), blkmapsize
);
369 (!verbose
&& update_bitmaps
))
370 (void) printf("(CORRECTED)\n");
375 bad_cgblks_cg
= (memcmp((void *)&cg_blks(fs
, cg
, 0)[0],
376 (void *)&cg_blks(fs
, newcg
, 0)[0],
377 fs
->fs_cpg
* fs
->fs_nrpos
* sizeof (int16_t)) != 0);
381 (void) printf("ROTATIONAL POSITIONS "
382 "BLOCK COUNT WRONG ");
383 if (preen
|| update_bitmaps
|| reply("FIX") == 1) {
384 (void) memmove((void *)&cg_blks(fs
, cg
, 0)[0],
385 (void *)&cg_blks(fs
, newcg
, 0)[0],
386 fs
->fs_cpg
* fs
->fs_nrpos
*
390 (!verbose
&& update_bitmaps
))
391 (void) printf("(CORRECTED)\n");
396 bad_cgblktot_cg
= (memcmp((void *)&cg_blktot(cg
)[0],
397 (void *)&cg_blktot(newcg
)[0],
398 fs
->fs_cpg
* sizeof (int32_t)) != 0);
400 if (bad_cgblktot_cg
) {
402 (void) printf("ROTATIONAL POSITIONS "
403 "BLOCK TOTAL WRONG ");
404 if (preen
|| update_bitmaps
|| reply("FIX") == 1) {
405 (void) memmove((void *)&cg_blktot(cg
)[0],
406 (void *)&cg_blktot(newcg
)[0],
407 fs
->fs_cpg
* sizeof (int32_t));
410 (!verbose
&& update_bitmaps
))
411 (void) printf("(CORRECTED)\n");
417 * Fixing one set of problems often shows up more in the
418 * same cg. Just to make sure, go back and check it
419 * again if we found something this time through.
428 if ((fflag
|| !(islog
&& islogok
)) &&
429 (memcmp((void *)&cstotal
, (void *)&fs
->fs_cstotal
,
430 sizeof (struct csum
)) != 0)) {
431 if (dofix(&idesc
, "CORRECT GLOBAL SUMMARY")) {
432 (void) memmove((void *)&fs
->fs_cstotal
,
433 (void *)&cstotal
, sizeof (struct csum
));
444 * Compare two allocation bitmaps, reporting any discrepancies.
446 * If a mismatch is found, if the bit is set in map1, it's considered
447 * to be an indication that the corresponding resource is supposed
448 * to be free, but isn't. Otherwise, it's considered marked as allocated
449 * but not found to be so. In other words, if the two maps being compared
450 * use a set bit to indicate something is free, pass the on-disk map
451 * first. Otherwise, pass the calculated map first.
455 uchar_t
*map1
, /* map of claimed allocations */
456 uchar_t
*map2
, /* map of determined allocations */
457 int mapsize
, /* size of above two maps */
458 int startvalue
, /* resource value for first element in map */
459 char *name
, /* name of resource found in maps */
460 int skip
, /* number of entries to skip before starting to free */
461 int limit
) /* limit on number of entries to free */
463 long i
, j
, k
, l
, m
, n
, size
;
464 int astart
, aend
, ustart
, uend
;
468 astart
= ustart
= aend
= uend
= -1;
469 for (i
= 0; i
< mapsize
; i
++) {
474 for (m
= 0, l
= 1; m
< NBBY
; m
++, l
<<= 1) {
475 if ((j
& l
) == (k
& l
))
477 n
= startvalue
+ i
* NBBY
+ m
;
490 "ALLOCATED %s %d WAS MARKED FREE ON DISK\n",
494 "ALLOCATED %sS %d-%d WERE MARKED FREE ON DISK\n",
508 size
= uend
- ustart
+ 1;
524 "UNALLOCATED %s %d WAS MARKED USED ON DISK\n",
528 "UNALLOCATED %sS %d-%ld WERE MARKED USED ON DISK\n",
544 "ALLOCATED %s %d WAS MARKED FREE ON DISK\n",
548 "ALLOCATED %sS %d-%d WERE MARKED FREE ON DISK\n",
554 size
= uend
- ustart
+ 1;
566 "UNALLOCATED %s %d WAS MARKED USED ON DISK\n",
570 "UNALLOCATED %sS %d-%ld WERE MARKED USED ON DISK\n",
571 name
, ustart
, ustart
+ size
- 1);