pass1.c revision 98879
1118652Sache/* 2118652Sache * Copyright (c) 1980, 1986, 1993 3118652Sache * The Regents of the University of California. All rights reserved. 4118652Sache * 5118652Sache * Redistribution and use in source and binary forms, with or without 6118652Sache * modification, are permitted provided that the following conditions 7118652Sache * are met: 8118652Sache * 1. Redistributions of source code must retain the above copyright 9118652Sache * notice, this list of conditions and the following disclaimer. 10118652Sache * 2. Redistributions in binary form must reproduce the above copyright 11118652Sache * notice, this list of conditions and the following disclaimer in the 12118652Sache * documentation and/or other materials provided with the distribution. 13118652Sache * 3. All advertising materials mentioning features or use of this software 14118652Sache * must display the following acknowledgement: 15118653Sache * This product includes software developed by the University of 16118652Sache * California, Berkeley and its contributors. 17118652Sache * 4. Neither the name of the University nor the names of its contributors 18118652Sache * may be used to endorse or promote products derived from this software 19118652Sache * without specific prior written permission. 20118652Sache * 21118652Sache * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22118652Sache * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23118652Sache * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24118652Sache * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25118652Sache * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26118652Sache * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27118652Sache * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28118652Sache * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29118652Sache * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30118652Sache * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31118652Sache * SUCH DAMAGE. 32118652Sache */ 33118652Sache 34118652Sache#ifndef lint 35118652Sache#if 0 36118652Sachestatic const char sccsid[] = "@(#)pass1.c 8.6 (Berkeley) 4/28/95"; 37118652Sache#endif 38118652Sachestatic const char rcsid[] = 39118652Sache "$FreeBSD: head/sbin/fsck_ffs/pass1.c 98879 2002-06-26 16:40:25Z iedowse $"; 40118652Sache#endif /* not lint */ 41118652Sache 42118652Sache#include <sys/param.h> 43118652Sache#include <sys/stat.h> 44118652Sache#include <sys/sysctl.h> 45118652Sache 46118652Sache#include <ufs/ufs/dinode.h> 47118652Sache#include <ufs/ufs/dir.h> 48118652Sache#include <ufs/ffs/fs.h> 49118652Sache 50118652Sache#include <err.h> 51118652Sache#include <string.h> 52118652Sache 53118652Sache#include "fsck.h" 54118652Sache 55118652Sachestatic ufs2_daddr_t badblk; 56118652Sachestatic ufs2_daddr_t dupblk; 57118652Sachestatic ino_t lastino; /* last inode in use */ 58118652Sache 59118652Sachestatic void checkinode(ino_t inumber, struct inodesc *); 60118652Sache 61118652Sachevoid 62118652Sachepass1(void) 63118652Sache{ 64118652Sache struct inostat *info; 65118652Sache struct inodesc idesc; 66118652Sache ino_t inumber, inosused; 67118652Sache ufs2_daddr_t i, cgd; 68118652Sache u_int8_t *cp; 69118652Sache int c; 70118652Sache 71118652Sache /* 72118652Sache * Set filesystem reserved blocks in used block map. 73118652Sache */ 74118652Sache for (c = 0; c < sblock.fs_ncg; c++) { 75118652Sache cgd = cgdmin(&sblock, c); 76118652Sache if (c == 0) { 77118652Sache i = cgbase(&sblock, c); 78118652Sache } else 79118652Sache i = cgsblock(&sblock, c); 80118652Sache for (; i < cgd; i++) 81118652Sache setbmap(i); 82118652Sache } 83118652Sache i = sblock.fs_csaddr; 84118652Sache cgd = i + howmany(sblock.fs_cssize, sblock.fs_fsize); 85118652Sache for (; i < cgd; i++) 86118652Sache setbmap(i); 87118652Sache 88118652Sache /* 89118652Sache * Find all allocated blocks. 90118652Sache */ 91118652Sache memset(&idesc, 0, sizeof(struct inodesc)); 92118652Sache idesc.id_func = pass1check; 93118652Sache n_files = n_blks = 0; 94118652Sache for (c = 0; c < sblock.fs_ncg; c++) { 95118652Sache inumber = c * sblock.fs_ipg; 96118652Sache setinodebuf(inumber); 97118652Sache getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize); 98118652Sache if (sblock.fs_magic == FS_UFS2_MAGIC) 99118652Sache inosused = cgrp.cg_initediblk; 100118652Sache else 101118652Sache inosused = sblock.fs_ipg; 102118652Sache if (got_siginfo) { 103118652Sache printf("%s: phase 1: cyl group %d of %d (%d%%)\n", 104118652Sache cdevname, c, sblock.fs_ncg, 105118652Sache c * 100 / sblock.fs_ncg); 106118652Sache got_siginfo = 0; 107118652Sache } 108118652Sache /* 109118652Sache * If we are using soft updates, then we can trust the 110118652Sache * cylinder group inode allocation maps to tell us which 111118652Sache * inodes are allocated. We will scan the used inode map 112118652Sache * to find the inodes that are really in use, and then 113118652Sache * read only those inodes in from disk. 114118652Sache */ 115118652Sache if (preen && usedsoftdep) { 116118652Sache if (!cg_chkmagic(&cgrp)) 117118652Sache pfatal("CG %d: BAD MAGIC NUMBER\n", c); 118118652Sache cp = &cg_inosused(&cgrp)[(inosused - 1) / NBBY]; 119118652Sache for ( ; inosused > 0; inosused -= NBBY, cp--) { 120118652Sache if (*cp == 0) 121118652Sache continue; 122118652Sache for (i = 1 << (NBBY - 1); i > 0; i >>= 1) { 123118652Sache if (*cp & i) 124118652Sache break; 125118652Sache inosused--; 126118652Sache } 127118652Sache break; 128118652Sache } 129118652Sache if (inosused < 0) 130118652Sache inosused = 0; 131118652Sache } 132118652Sache /* 133118652Sache * Allocate inoinfo structures for the allocated inodes. 134118652Sache */ 135118652Sache inostathead[c].il_numalloced = inosused; 136118652Sache if (inosused == 0) { 137118652Sache inostathead[c].il_stat = 0; 138118652Sache continue; 139118652Sache } 140118652Sache info = calloc((unsigned)inosused, sizeof(struct inostat)); 141118652Sache if (info == NULL) 142118652Sache pfatal("cannot alloc %u bytes for inoinfo\n", 143118652Sache (unsigned)(sizeof(struct inostat) * inosused)); 144118652Sache inostathead[c].il_stat = info; 145118652Sache /* 146118652Sache * Scan the allocated inodes. 147118652Sache */ 148118652Sache for (i = 0; i < inosused; i++, inumber++) { 149118652Sache if (inumber < ROOTINO) { 150118652Sache (void)getnextinode(inumber); 151118652Sache continue; 152118652Sache } 153118652Sache checkinode(inumber, &idesc); 154118652Sache } 155118652Sache lastino += 1; 156118652Sache if (inosused < sblock.fs_ipg || inumber == lastino) 157118652Sache continue; 158118652Sache /* 159118652Sache * If we were not able to determine in advance which inodes 160118652Sache * were in use, then reduce the size of the inoinfo structure 161118652Sache * to the size necessary to describe the inodes that we 162118652Sache * really found. 163118652Sache */ 164118652Sache if (lastino < (c * sblock.fs_ipg)) 165118652Sache inosused = 0; 166118652Sache else 167118652Sache inosused = lastino - (c * sblock.fs_ipg); 168118652Sache inostathead[c].il_numalloced = inosused; 169118652Sache if (inosused == 0) { 170118652Sache free(inostathead[c].il_stat); 171118652Sache inostathead[c].il_stat = 0; 172118652Sache continue; 173118652Sache } 174118652Sache info = calloc((unsigned)inosused, sizeof(struct inostat)); 175118652Sache if (info == NULL) 176118652Sache pfatal("cannot alloc %u bytes for inoinfo\n", 177118652Sache (unsigned)(sizeof(struct inostat) * inosused)); 178118652Sache memmove(info, inostathead[c].il_stat, inosused * sizeof(*info)); 179118652Sache free(inostathead[c].il_stat); 180118652Sache inostathead[c].il_stat = info; 181118652Sache } 182118652Sache freeinodebuf(); 183118652Sache} 184118652Sache 185118652Sachestatic void 186118652Sachecheckinode(ino_t inumber, struct inodesc *idesc) 187118652Sache{ 188118652Sache union dinode *dp; 189 struct zlncnt *zlnp; 190 off_t kernmaxfilesize; 191 ufs2_daddr_t ndb; 192 mode_t mode; 193 char *symbuf; 194 int j; 195 196 dp = getnextinode(inumber); 197 mode = DIP(dp, di_mode) & IFMT; 198 if (mode == 0) { 199 if ((sblock.fs_magic == FS_UFS1_MAGIC && 200 (memcmp(dp->dp1.di_db, ufs1_zino.di_db, 201 NDADDR * sizeof(ufs1_daddr_t)) || 202 memcmp(dp->dp1.di_ib, ufs1_zino.di_ib, 203 NIADDR * sizeof(ufs1_daddr_t)) || 204 dp->dp1.di_mode || dp->dp1.di_size)) || 205 (sblock.fs_magic == FS_UFS2_MAGIC && 206 (memcmp(dp->dp2.di_db, ufs2_zino.di_db, 207 NDADDR * sizeof(ufs2_daddr_t)) || 208 memcmp(dp->dp2.di_ib, ufs2_zino.di_ib, 209 NIADDR * sizeof(ufs2_daddr_t)) || 210 dp->dp2.di_mode || dp->dp2.di_size))) { 211 pfatal("PARTIALLY ALLOCATED INODE I=%lu", 212 (u_long)inumber); 213 if (reply("CLEAR") == 1) { 214 dp = ginode(inumber); 215 clearinode(dp); 216 inodirty(); 217 } 218 } 219 inoinfo(inumber)->ino_state = USTATE; 220 return; 221 } 222 lastino = inumber; 223 /* This should match the file size limit in ffs_mountfs(). */ 224 kernmaxfilesize = (off_t)0x40000000 * sblock.fs_bsize - 1; 225 if (DIP(dp, di_size) > kernmaxfilesize || 226 DIP(dp, di_size) > sblock.fs_maxfilesize || 227 (mode == IFDIR && DIP(dp, di_size) > MAXDIRSIZE)) { 228 if (debug) 229 printf("bad size %qu:", DIP(dp, di_size)); 230 goto unknown; 231 } 232 if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) { 233 dp = ginode(inumber); 234 DIP(dp, di_size) = sblock.fs_fsize; 235 DIP(dp, di_mode) = IFREG|0600; 236 inodirty(); 237 } 238 if ((mode == IFBLK || mode == IFCHR || mode == IFIFO || 239 mode == IFSOCK) && DIP(dp, di_size) != 0) { 240 if (debug) 241 printf("bad special-file size %qu:", DIP(dp, di_size)); 242 goto unknown; 243 } 244 if ((mode == IFBLK || mode == IFCHR) && 245 (dev_t)DIP(dp, di_rdev) == NODEV) { 246 if (debug) 247 printf("bad special-file rdev NODEV:"); 248 goto unknown; 249 } 250 ndb = howmany(DIP(dp, di_size), sblock.fs_bsize); 251 if (ndb < 0) { 252 if (debug) 253 printf("bad size %qu ndb %qu:", 254 DIP(dp, di_size), ndb); 255 goto unknown; 256 } 257 if (mode == IFBLK || mode == IFCHR) 258 ndb++; 259 if (mode == IFLNK) { 260 /* 261 * Fake ndb value so direct/indirect block checks below 262 * will detect any garbage after symlink string. 263 */ 264 if (DIP(dp, di_size) < (off_t)sblock.fs_maxsymlinklen) { 265 if (sblock.fs_magic == FS_UFS1_MAGIC) 266 ndb = howmany(DIP(dp, di_size), 267 sizeof(ufs1_daddr_t)); 268 else 269 ndb = howmany(DIP(dp, di_size), 270 sizeof(ufs2_daddr_t)); 271 if (ndb > NDADDR) { 272 j = ndb - NDADDR; 273 for (ndb = 1; j > 1; j--) 274 ndb *= NINDIR(&sblock); 275 ndb += NDADDR; 276 } 277 } 278 } 279 for (j = ndb; ndb < NDADDR && j < NDADDR; j++) 280 if (DIP(dp, di_db[j]) != 0) { 281 if (debug) 282 printf("bad direct addr[%d]: %qu\n", j, 283 (ufs2_daddr_t)DIP(dp, di_db[j])); 284 goto unknown; 285 } 286 for (j = 0, ndb -= NDADDR; ndb > 0; j++) 287 ndb /= NINDIR(&sblock); 288 for (; j < NIADDR; j++) 289 if (DIP(dp, di_ib[j]) != 0) { 290 if (debug) 291 printf("bad indirect addr: %qu\n", 292 DIP(dp, di_ib[j])); 293 goto unknown; 294 } 295 if (ftypeok(dp) == 0) 296 goto unknown; 297 n_files++; 298 inoinfo(inumber)->ino_linkcnt = DIP(dp, di_nlink); 299 if (DIP(dp, di_nlink) <= 0) { 300 zlnp = (struct zlncnt *)malloc(sizeof *zlnp); 301 if (zlnp == NULL) { 302 pfatal("LINK COUNT TABLE OVERFLOW"); 303 if (reply("CONTINUE") == 0) { 304 ckfini(0); 305 exit(EEXIT); 306 } 307 } else { 308 zlnp->zlncnt = inumber; 309 zlnp->next = zlnhead; 310 zlnhead = zlnp; 311 } 312 } 313 if (mode == IFDIR) { 314 if (DIP(dp, di_size) == 0) 315 inoinfo(inumber)->ino_state = DCLEAR; 316 else 317 inoinfo(inumber)->ino_state = DSTATE; 318 cacheino(dp, inumber); 319 countdirs++; 320 } else 321 inoinfo(inumber)->ino_state = FSTATE; 322 inoinfo(inumber)->ino_type = IFTODT(mode); 323 badblk = dupblk = 0; 324 idesc->id_number = inumber; 325 if (DIP(dp, di_flags) & SF_SNAPSHOT) 326 idesc->id_type = SNAP; 327 else 328 idesc->id_type = ADDR; 329 (void)ckinode(dp, idesc); 330 idesc->id_entryno *= btodb(sblock.fs_fsize); 331 if (DIP(dp, di_blocks) != idesc->id_entryno) { 332 pwarn("INCORRECT BLOCK COUNT I=%lu (%qu should be %qu)", 333 (u_long)inumber, DIP(dp, di_blocks), 334 idesc->id_entryno); 335 if (preen) 336 printf(" (CORRECTED)\n"); 337 else if (reply("CORRECT") == 0) 338 return; 339 if (bkgrdflag == 0) { 340 dp = ginode(inumber); 341 DIP(dp, di_blocks) = idesc->id_entryno; 342 inodirty(); 343 } else { 344 cmd.value = idesc->id_number; 345 cmd.size = idesc->id_entryno - DIP(dp, di_blocks); 346 if (debug) 347 printf("adjblkcnt ino %qu amount %ld\n", 348 cmd.value, cmd.size); 349 if (sysctl(adjblkcnt, MIBSIZE, 0, 0, 350 &cmd, sizeof cmd) == -1) 351 rwerror("ADJUST INODE BLOCK COUNT", cmd.value); 352 } 353 } 354 return; 355unknown: 356 pfatal("UNKNOWN FILE TYPE I=%lu", (u_long)inumber); 357 inoinfo(inumber)->ino_state = FCLEAR; 358 if (reply("CLEAR") == 1) { 359 inoinfo(inumber)->ino_state = USTATE; 360 dp = ginode(inumber); 361 clearinode(dp); 362 inodirty(); 363 } 364} 365 366int 367pass1check(struct inodesc *idesc) 368{ 369 int res = KEEPON; 370 int anyout, nfrags; 371 ufs2_daddr_t blkno = idesc->id_blkno; 372 struct dups *dlp; 373 struct dups *new; 374 375 if (idesc->id_type == SNAP) { 376 if (blkno == BLK_NOCOPY) 377 return (KEEPON); 378 if (idesc->id_number == cursnapshot) { 379 if (blkno == blkstofrags(&sblock, idesc->id_lbn)) 380 return (KEEPON); 381 if (blkno == BLK_SNAP) { 382 blkno = blkstofrags(&sblock, idesc->id_lbn); 383 idesc->id_entryno -= idesc->id_numfrags; 384 } 385 } else { 386 if (blkno == BLK_SNAP) 387 return (KEEPON); 388 } 389 } 390 if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) { 391 blkerror(idesc->id_number, "BAD", blkno); 392 if (badblk++ >= MAXBAD) { 393 pwarn("EXCESSIVE BAD BLKS I=%lu", 394 (u_long)idesc->id_number); 395 if (preen) 396 printf(" (SKIPPING)\n"); 397 else if (reply("CONTINUE") == 0) { 398 ckfini(0); 399 exit(EEXIT); 400 } 401 return (STOP); 402 } 403 } 404 for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { 405 if (anyout && chkrange(blkno, 1)) { 406 res = SKIP; 407 } else if (!testbmap(blkno)) { 408 n_blks++; 409 setbmap(blkno); 410 } else { 411 blkerror(idesc->id_number, "DUP", blkno); 412 if (dupblk++ >= MAXDUP) { 413 pwarn("EXCESSIVE DUP BLKS I=%lu", 414 (u_long)idesc->id_number); 415 if (preen) 416 printf(" (SKIPPING)\n"); 417 else if (reply("CONTINUE") == 0) { 418 ckfini(0); 419 exit(EEXIT); 420 } 421 return (STOP); 422 } 423 new = (struct dups *)malloc(sizeof(struct dups)); 424 if (new == NULL) { 425 pfatal("DUP TABLE OVERFLOW."); 426 if (reply("CONTINUE") == 0) { 427 ckfini(0); 428 exit(EEXIT); 429 } 430 return (STOP); 431 } 432 new->dup = blkno; 433 if (muldup == 0) { 434 duplist = muldup = new; 435 new->next = 0; 436 } else { 437 new->next = muldup->next; 438 muldup->next = new; 439 } 440 for (dlp = duplist; dlp != muldup; dlp = dlp->next) 441 if (dlp->dup == blkno) 442 break; 443 if (dlp == muldup && dlp->dup != blkno) 444 muldup = new; 445 } 446 /* 447 * count the number of blocks found in id_entryno 448 */ 449 idesc->id_entryno++; 450 } 451 return (res); 452} 453