pass1.c revision 98542
1139738Simp/* 283364Sdfr * Copyright (c) 1980, 1986, 1993 383364Sdfr * The Regents of the University of California. All rights reserved. 483364Sdfr * 583364Sdfr * Redistribution and use in source and binary forms, with or without 683364Sdfr * modification, are permitted provided that the following conditions 783364Sdfr * are met: 883364Sdfr * 1. Redistributions of source code must retain the above copyright 983364Sdfr * notice, this list of conditions and the following disclaimer. 1083364Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1183364Sdfr * notice, this list of conditions and the following disclaimer in the 1283364Sdfr * documentation and/or other materials provided with the distribution. 1383364Sdfr * 3. All advertising materials mentioning features or use of this software 1483364Sdfr * must display the following acknowledgement: 1583364Sdfr * This product includes software developed by the University of 1683364Sdfr * California, Berkeley and its contributors. 1783364Sdfr * 4. Neither the name of the University nor the names of its contributors 1883364Sdfr * may be used to endorse or promote products derived from this software 1983364Sdfr * without specific prior written permission. 2083364Sdfr * 2183364Sdfr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2283364Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2383364Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2483364Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2583364Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2683364Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2783364Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2883364Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2983364Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3083364Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3183364Sdfr * SUCH DAMAGE. 3283364Sdfr */ 3383364Sdfr 34113038Sobrien#ifndef lint 35113038Sobrien#if 0 3683364Sdfrstatic const char sccsid[] = "@(#)pass1.c 8.6 (Berkeley) 4/28/95"; 3783364Sdfr#endif 3883364Sdfrstatic const char rcsid[] = 3983364Sdfr "$FreeBSD: head/sbin/fsck_ffs/pass1.c 98542 2002-06-21 06:18:05Z mckusick $"; 4083364Sdfr#endif /* not lint */ 4183364Sdfr 4283364Sdfr#include <sys/param.h> 4383364Sdfr#include <sys/stat.h> 4483364Sdfr#include <sys/sysctl.h> 4583364Sdfr 4683364Sdfr#include <ufs/ufs/dinode.h> 4783364Sdfr#include <ufs/ufs/dir.h> 4883364Sdfr#include <ufs/ffs/fs.h> 4983364Sdfr 5083364Sdfr#include <err.h> 5183364Sdfr#include <string.h> 5283364Sdfr 5383364Sdfr#include "fsck.h" 5483364Sdfr 5583364Sdfrstatic ufs2_daddr_t badblk; 5683364Sdfrstatic ufs2_daddr_t dupblk; 5783364Sdfrstatic ino_t lastino; /* last inode in use */ 5883364Sdfr 59108100Sjakestatic void checkinode(ino_t inumber, struct inodesc *); 6083364Sdfr 6183364Sdfrvoid 6283364Sdfrpass1(void) 6383364Sdfr{ 6483364Sdfr struct inostat *info; 6583364Sdfr struct inodesc idesc; 6683364Sdfr ino_t inumber, inosused; 6783364Sdfr ufs2_daddr_t i, cgd; 6883364Sdfr u_int8_t *cp; 6983364Sdfr int c; 7083364Sdfr 7183364Sdfr /* 7283364Sdfr * Set filesystem reserved blocks in used block map. 7383364Sdfr */ 7483364Sdfr for (c = 0; c < sblock.fs_ncg; c++) { 7583364Sdfr cgd = cgdmin(&sblock, c); 7683364Sdfr if (c == 0) { 7783364Sdfr i = cgbase(&sblock, c); 78158467Sjhb } else 7983364Sdfr i = cgsblock(&sblock, c); 8083364Sdfr for (; i < cgd; i++) 8183364Sdfr setbmap(i); 8283364Sdfr } 8383364Sdfr i = sblock.fs_csaddr; 8483364Sdfr cgd = i + howmany(sblock.fs_cssize, sblock.fs_fsize); 8583364Sdfr for (; i < cgd; i++) 8683364Sdfr setbmap(i); 87 88 /* 89 * Find all allocated blocks. 90 */ 91 memset(&idesc, 0, sizeof(struct inodesc)); 92 idesc.id_func = pass1check; 93 n_files = n_blks = 0; 94 for (c = 0; c < sblock.fs_ncg; c++) { 95 inumber = c * sblock.fs_ipg; 96 setinodebuf(inumber); 97 getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize); 98 if (sblock.fs_magic == FS_UFS2_MAGIC) 99 inosused = cgrp.cg_initediblk; 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 /* 109 * If we are using soft updates, then we can trust the 110 * cylinder group inode allocation maps to tell us which 111 * inodes are allocated. We will scan the used inode map 112 * to find the inodes that are really in use, and then 113 * read only those inodes in from disk. 114 */ 115 if (preen && usedsoftdep) { 116 if (!cg_chkmagic(&cgrp)) 117 pfatal("CG %d: BAD MAGIC NUMBER\n", c); 118 cp = &cg_inosused(&cgrp)[(inosused - 1) / NBBY]; 119 for ( ; inosused > 0; inosused -= NBBY, cp--) { 120 if (*cp == 0) 121 continue; 122 for (i = 1 << (NBBY - 1); i > 0; i >>= 1) { 123 if (*cp & i) 124 break; 125 inosused--; 126 } 127 break; 128 } 129 if (inosused < 0) 130 inosused = 0; 131 } 132 /* 133 * Allocate inoinfo structures for the allocated inodes. 134 */ 135 inostathead[c].il_numalloced = inosused; 136 if (inosused == 0) { 137 inostathead[c].il_stat = 0; 138 continue; 139 } 140 info = calloc((unsigned)inosused, sizeof(struct inostat)); 141 if (info == NULL) 142 pfatal("cannot alloc %u bytes for inoinfo\n", 143 (unsigned)(sizeof(struct inostat) * inosused)); 144 inostathead[c].il_stat = info; 145 /* 146 * Scan the allocated inodes. 147 */ 148 for (i = 0; i < inosused; i++, inumber++) { 149 if (inumber < ROOTINO) { 150 (void)getnextinode(inumber); 151 continue; 152 } 153 checkinode(inumber, &idesc); 154 } 155 lastino += 1; 156 if (inosused < sblock.fs_ipg || inumber == lastino) 157 continue; 158 /* 159 * If we were not able to determine in advance which inodes 160 * were in use, then reduce the size of the inoinfo structure 161 * to the size necessary to describe the inodes that we 162 * really found. 163 */ 164 if (lastino < (c * sblock.fs_ipg)) 165 inosused = 0; 166 else 167 inosused = lastino - (c * sblock.fs_ipg); 168 inostathead[c].il_numalloced = inosused; 169 if (inosused == 0) { 170 free(inostathead[c].il_stat); 171 inostathead[c].il_stat = 0; 172 continue; 173 } 174 info = calloc((unsigned)inosused, sizeof(struct inostat)); 175 if (info == NULL) 176 pfatal("cannot alloc %u bytes for inoinfo\n", 177 (unsigned)(sizeof(struct inostat) * inosused)); 178 memmove(info, inostathead[c].il_stat, inosused * sizeof(*info)); 179 free(inostathead[c].il_stat); 180 inostathead[c].il_stat = info; 181 } 182 freeinodebuf(); 183} 184 185static void 186checkinode(ino_t inumber, struct inodesc *idesc) 187{ 188 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; 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