1 /* 2 * Copyright (c) 1980, 1986, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 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 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #if 0 31 #ifndef lint 32 static const char sccsid[] = "@(#)pass1.c 8.6 (Berkeley) 4/28/95"; 33 #endif /* not lint */ 34 #endif 35 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 #include <sys/param.h> 39 #include <sys/stat.h> 40 #include <sys/sysctl.h> 41 42 #include <ufs/ufs/dinode.h> 43 #include <ufs/ufs/dir.h> 44 #include <ufs/ffs/fs.h> 45 46 #include <err.h> 47 #include <limits.h> 48 #include <stdint.h> 49 #include <string.h> 50 51 #include "fsck.h" 52 53 static ufs2_daddr_t badblk; 54 static ufs2_daddr_t dupblk; 55 static ino_t lastino; /* last inode in use */ 56 57 static void checkinode(ino_t inumber, struct inodesc *); 58 59 void 60 pass1(void) 61 { 62 struct inostat *info; 63 struct inodesc idesc; 64 ino_t inumber, inosused; 65 ufs2_daddr_t i, cgd; 66 u_int8_t *cp; 67 int c; 68 69 /* 70 * Set file system reserved blocks in used block map. 71 */ 72 for (c = 0; c < sblock.fs_ncg; c++) { 73 cgd = cgdmin(&sblock, c); 74 if (c == 0) { 75 i = cgbase(&sblock, c); 76 } else 77 i = cgsblock(&sblock, c); 78 for (; i < cgd; i++) 79 setbmap(i); 80 } 81 i = sblock.fs_csaddr; 82 cgd = i + howmany(sblock.fs_cssize, sblock.fs_fsize); 83 for (; i < cgd; i++) 84 setbmap(i); 85 86 /* 87 * Find all allocated blocks. 88 */ 89 memset(&idesc, 0, sizeof(struct inodesc)); 90 idesc.id_func = pass1check; 91 n_files = n_blks = 0; 92 for (c = 0; c < sblock.fs_ncg; c++) { 93 inumber = c * sblock.fs_ipg; 94 setinodebuf(inumber); 95 getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize); 96 if (sblock.fs_magic == FS_UFS2_MAGIC) { 97 inosused = cgrp.cg_initediblk; 98 if (inosused > sblock.fs_ipg) 99 inosused = sblock.fs_ipg; 100 } else 101 inosused = sblock.fs_ipg; 102 if (got_siginfo) { 103 printf("%s: phase 1: cyl group %d of %d (%d%%)\n", 104 cdevname, c, sblock.fs_ncg, 105 c * 100 / sblock.fs_ncg); 106 got_siginfo = 0; 107 } 108 if (got_sigalarm) { 109 setproctitle("%s p1 %d%%", cdevname, 110 c * 100 / sblock.fs_ncg); 111 got_sigalarm = 0; 112 } 113 /* 114 * If we are using soft updates, then we can trust the 115 * cylinder group inode allocation maps to tell us which 116 * inodes are allocated. We will scan the used inode map 117 * to find the inodes that are really in use, and then 118 * read only those inodes in from disk. 119 */ 120 if (preen && usedsoftdep) { 121 if (!cg_chkmagic(&cgrp)) 122 pfatal("CG %d: BAD MAGIC NUMBER\n", c); 123 cp = &cg_inosused(&cgrp)[(inosused - 1) / CHAR_BIT]; 124 for ( ; inosused > 0; inosused -= CHAR_BIT, cp--) { 125 if (*cp == 0) 126 continue; 127 for (i = 1 << (CHAR_BIT - 1); i > 0; i >>= 1) { 128 if (*cp & i) 129 break; 130 inosused--; 131 } 132 break; 133 } 134 if (inosused < 0) 135 inosused = 0; 136 } 137 /* 138 * Allocate inoinfo structures for the allocated inodes. 139 */ 140 inostathead[c].il_numalloced = inosused; 141 if (inosused == 0) { 142 inostathead[c].il_stat = 0; 143 continue; 144 } 145 info = calloc((unsigned)inosused, sizeof(struct inostat)); 146 if (info == NULL) 147 errx(EEXIT, "cannot alloc %u bytes for inoinfo", 148 (unsigned)(sizeof(struct inostat) * inosused)); 149 inostathead[c].il_stat = info; 150 /* 151 * Scan the allocated inodes. 152 */ 153 for (i = 0; i < inosused; i++, inumber++) { 154 if (inumber < ROOTINO) { 155 (void)getnextinode(inumber); 156 continue; 157 } 158 checkinode(inumber, &idesc); 159 } 160 lastino += 1; 161 if (inosused < sblock.fs_ipg || inumber == lastino) 162 continue; 163 /* 164 * If we were not able to determine in advance which inodes 165 * were in use, then reduce the size of the inoinfo structure 166 * to the size necessary to describe the inodes that we 167 * really found. 168 */ 169 if (lastino < (c * sblock.fs_ipg)) 170 inosused = 0; 171 else 172 inosused = lastino - (c * sblock.fs_ipg); 173 inostathead[c].il_numalloced = inosused; 174 if (inosused == 0) { 175 free(inostathead[c].il_stat); 176 inostathead[c].il_stat = 0; 177 continue; 178 } 179 info = calloc((unsigned)inosused, sizeof(struct inostat)); 180 if (info == NULL) 181 errx(EEXIT, "cannot alloc %u bytes for inoinfo", 182 (unsigned)(sizeof(struct inostat) * inosused)); 183 memmove(info, inostathead[c].il_stat, inosused * sizeof(*info)); 184 free(inostathead[c].il_stat); 185 inostathead[c].il_stat = info; 186 } 187 freeinodebuf(); 188 } 189 190 static void 191 checkinode(ino_t inumber, struct inodesc *idesc) 192 { 193 union dinode *dp; 194 off_t kernmaxfilesize; 195 ufs2_daddr_t ndb; 196 mode_t mode; 197 int j, ret, offset; 198 199 dp = getnextinode(inumber); 200 mode = DIP(dp, di_mode) & IFMT; 201 if (mode == 0) { 202 if ((sblock.fs_magic == FS_UFS1_MAGIC && 203 (memcmp(dp->dp1.di_db, ufs1_zino.di_db, 204 NDADDR * sizeof(ufs1_daddr_t)) || 205 memcmp(dp->dp1.di_ib, ufs1_zino.di_ib, 206 NIADDR * sizeof(ufs1_daddr_t)) || 207 dp->dp1.di_mode || dp->dp1.di_size)) || 208 (sblock.fs_magic == FS_UFS2_MAGIC && 209 (memcmp(dp->dp2.di_db, ufs2_zino.di_db, 210 NDADDR * sizeof(ufs2_daddr_t)) || 211 memcmp(dp->dp2.di_ib, ufs2_zino.di_ib, 212 NIADDR * sizeof(ufs2_daddr_t)) || 213 dp->dp2.di_mode || dp->dp2.di_size))) { 214 pfatal("PARTIALLY ALLOCATED INODE I=%lu", 215 (u_long)inumber); 216 if (reply("CLEAR") == 1) { 217 dp = ginode(inumber); 218 clearinode(dp); 219 inodirty(); 220 } 221 } 222 inoinfo(inumber)->ino_state = USTATE; 223 return; 224 } 225 lastino = inumber; 226 /* This should match the file size limit in ffs_mountfs(). */ 227 if (sblock.fs_magic == FS_UFS1_MAGIC) 228 kernmaxfilesize = (off_t)0x40000000 * sblock.fs_bsize - 1; 229 else 230 kernmaxfilesize = sblock.fs_maxfilesize; 231 if (DIP(dp, di_size) > kernmaxfilesize || 232 DIP(dp, di_size) > sblock.fs_maxfilesize || 233 (mode == IFDIR && DIP(dp, di_size) > MAXDIRSIZE)) { 234 if (debug) 235 printf("bad size %ju:", (uintmax_t)DIP(dp, di_size)); 236 goto unknown; 237 } 238 if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) { 239 dp = ginode(inumber); 240 DIP_SET(dp, di_size, sblock.fs_fsize); 241 DIP_SET(dp, di_mode, IFREG|0600); 242 inodirty(); 243 } 244 if ((mode == IFBLK || mode == IFCHR || mode == IFIFO || 245 mode == IFSOCK) && DIP(dp, di_size) != 0) { 246 if (debug) 247 printf("bad special-file size %ju:", 248 (uintmax_t)DIP(dp, di_size)); 249 goto unknown; 250 } 251 if ((mode == IFBLK || mode == IFCHR) && 252 (dev_t)DIP(dp, di_rdev) == NODEV) { 253 if (debug) 254 printf("bad special-file rdev NODEV:"); 255 goto unknown; 256 } 257 ndb = howmany(DIP(dp, di_size), sblock.fs_bsize); 258 if (ndb < 0) { 259 if (debug) 260 printf("bad size %ju ndb %ju:", 261 (uintmax_t)DIP(dp, di_size), (uintmax_t)ndb); 262 goto unknown; 263 } 264 if (mode == IFBLK || mode == IFCHR) 265 ndb++; 266 if (mode == IFLNK) { 267 /* 268 * Fake ndb value so direct/indirect block checks below 269 * will detect any garbage after symlink string. 270 */ 271 if (DIP(dp, di_size) < (off_t)sblock.fs_maxsymlinklen) { 272 if (sblock.fs_magic == FS_UFS1_MAGIC) 273 ndb = howmany(DIP(dp, di_size), 274 sizeof(ufs1_daddr_t)); 275 else 276 ndb = howmany(DIP(dp, di_size), 277 sizeof(ufs2_daddr_t)); 278 if (ndb > NDADDR) { 279 j = ndb - NDADDR; 280 for (ndb = 1; j > 1; j--) 281 ndb *= NINDIR(&sblock); 282 ndb += NDADDR; 283 } 284 } 285 } 286 for (j = ndb; ndb < NDADDR && j < NDADDR; j++) 287 if (DIP(dp, di_db[j]) != 0) { 288 if (debug) 289 printf("bad direct addr[%d]: %ju\n", j, 290 (uintmax_t)DIP(dp, di_db[j])); 291 goto unknown; 292 } 293 for (j = 0, ndb -= NDADDR; ndb > 0; j++) 294 ndb /= NINDIR(&sblock); 295 for (; j < NIADDR; j++) 296 if (DIP(dp, di_ib[j]) != 0) { 297 if (debug) 298 printf("bad indirect addr: %ju\n", 299 (uintmax_t)DIP(dp, di_ib[j])); 300 goto unknown; 301 } 302 if (ftypeok(dp) == 0) 303 goto unknown; 304 n_files++; 305 inoinfo(inumber)->ino_linkcnt = DIP(dp, di_nlink); 306 if (mode == IFDIR) { 307 if (DIP(dp, di_size) == 0) 308 inoinfo(inumber)->ino_state = DCLEAR; 309 else if (DIP(dp, di_nlink) <= 0) 310 inoinfo(inumber)->ino_state = DZLINK; 311 else 312 inoinfo(inumber)->ino_state = DSTATE; 313 cacheino(dp, inumber); 314 countdirs++; 315 } else if (DIP(dp, di_nlink) <= 0) 316 inoinfo(inumber)->ino_state = FZLINK; 317 else 318 inoinfo(inumber)->ino_state = FSTATE; 319 inoinfo(inumber)->ino_type = IFTODT(mode); 320 badblk = dupblk = 0; 321 idesc->id_number = inumber; 322 if (DIP(dp, di_flags) & SF_SNAPSHOT) 323 idesc->id_type = SNAP; 324 else 325 idesc->id_type = ADDR; 326 (void)ckinode(dp, idesc); 327 if (sblock.fs_magic == FS_UFS2_MAGIC && dp->dp2.di_extsize > 0) { 328 idesc->id_type = ADDR; 329 ndb = howmany(dp->dp2.di_extsize, sblock.fs_bsize); 330 for (j = 0; j < NXADDR; j++) { 331 if (--ndb == 0 && 332 (offset = blkoff(&sblock, dp->dp2.di_extsize)) != 0) 333 idesc->id_numfrags = numfrags(&sblock, 334 fragroundup(&sblock, offset)); 335 else 336 idesc->id_numfrags = sblock.fs_frag; 337 if (dp->dp2.di_extb[j] == 0) 338 continue; 339 idesc->id_blkno = dp->dp2.di_extb[j]; 340 ret = (*idesc->id_func)(idesc); 341 if (ret & STOP) 342 break; 343 } 344 } 345 if (sblock.fs_magic == FS_UFS2_MAGIC) 346 eascan(idesc, &dp->dp2); 347 idesc->id_entryno *= btodb(sblock.fs_fsize); 348 if (DIP(dp, di_blocks) != idesc->id_entryno) { 349 pwarn("INCORRECT BLOCK COUNT I=%lu (%ju should be %ju)", 350 (u_long)inumber, (uintmax_t)DIP(dp, di_blocks), 351 (uintmax_t)idesc->id_entryno); 352 if (preen) 353 printf(" (CORRECTED)\n"); 354 else if (reply("CORRECT") == 0) 355 return; 356 if (bkgrdflag == 0) { 357 dp = ginode(inumber); 358 DIP_SET(dp, di_blocks, idesc->id_entryno); 359 inodirty(); 360 } else { 361 cmd.value = idesc->id_number; 362 cmd.size = idesc->id_entryno - DIP(dp, di_blocks); 363 if (debug) 364 printf("adjblkcnt ino %ju amount %lld\n", 365 (uintmax_t)cmd.value, (long long)cmd.size); 366 if (sysctl(adjblkcnt, MIBSIZE, 0, 0, 367 &cmd, sizeof cmd) == -1) 368 rwerror("ADJUST INODE BLOCK COUNT", cmd.value); 369 } 370 } 371 return; 372 unknown: 373 pfatal("UNKNOWN FILE TYPE I=%lu", (u_long)inumber); 374 inoinfo(inumber)->ino_state = FCLEAR; 375 if (reply("CLEAR") == 1) { 376 inoinfo(inumber)->ino_state = USTATE; 377 dp = ginode(inumber); 378 clearinode(dp); 379 inodirty(); 380 } 381 } 382 383 int 384 pass1check(struct inodesc *idesc) 385 { 386 int res = KEEPON; 387 int anyout, nfrags; 388 ufs2_daddr_t blkno = idesc->id_blkno; 389 struct dups *dlp; 390 struct dups *new; 391 392 if (idesc->id_type == SNAP) { 393 if (blkno == BLK_NOCOPY) 394 return (KEEPON); 395 if (idesc->id_number == cursnapshot) { 396 if (blkno == blkstofrags(&sblock, idesc->id_lbn)) 397 return (KEEPON); 398 if (blkno == BLK_SNAP) { 399 blkno = blkstofrags(&sblock, idesc->id_lbn); 400 idesc->id_entryno -= idesc->id_numfrags; 401 } 402 } else { 403 if (blkno == BLK_SNAP) 404 return (KEEPON); 405 } 406 } 407 if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) { 408 blkerror(idesc->id_number, "BAD", blkno); 409 if (badblk++ >= MAXBAD) { 410 pwarn("EXCESSIVE BAD BLKS I=%lu", 411 (u_long)idesc->id_number); 412 if (preen) 413 printf(" (SKIPPING)\n"); 414 else if (reply("CONTINUE") == 0) { 415 ckfini(0); 416 exit(EEXIT); 417 } 418 return (STOP); 419 } 420 } 421 for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { 422 if (anyout && chkrange(blkno, 1)) { 423 res = SKIP; 424 } else if (!testbmap(blkno)) { 425 n_blks++; 426 setbmap(blkno); 427 } else { 428 blkerror(idesc->id_number, "DUP", blkno); 429 if (dupblk++ >= MAXDUP) { 430 pwarn("EXCESSIVE DUP BLKS I=%lu", 431 (u_long)idesc->id_number); 432 if (preen) 433 printf(" (SKIPPING)\n"); 434 else if (reply("CONTINUE") == 0) { 435 ckfini(0); 436 exit(EEXIT); 437 } 438 return (STOP); 439 } 440 new = (struct dups *)malloc(sizeof(struct dups)); 441 if (new == NULL) { 442 pfatal("DUP TABLE OVERFLOW."); 443 if (reply("CONTINUE") == 0) { 444 ckfini(0); 445 exit(EEXIT); 446 } 447 return (STOP); 448 } 449 new->dup = blkno; 450 if (muldup == 0) { 451 duplist = muldup = new; 452 new->next = 0; 453 } else { 454 new->next = muldup->next; 455 muldup->next = new; 456 } 457 for (dlp = duplist; dlp != muldup; dlp = dlp->next) 458 if (dlp->dup == blkno) 459 break; 460 if (dlp == muldup && dlp->dup != blkno) 461 muldup = new; 462 } 463 /* 464 * count the number of blocks found in id_entryno 465 */ 466 idesc->id_entryno++; 467 } 468 return (res); 469 } 470