1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1980, 1986, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #if 0 33 #ifndef lint 34 static const char sccsid[] = "@(#)pass1.c 8.6 (Berkeley) 4/28/95"; 35 #endif /* not lint */ 36 #endif 37 #include <sys/cdefs.h> 38 __FBSDID("$FreeBSD$"); 39 40 #include <sys/param.h> 41 #include <sys/stat.h> 42 #include <sys/sysctl.h> 43 44 #include <ufs/ufs/dinode.h> 45 #include <ufs/ufs/dir.h> 46 #include <ufs/ffs/fs.h> 47 48 #include <err.h> 49 #include <limits.h> 50 #include <stdint.h> 51 #include <string.h> 52 53 #include "fsck.h" 54 55 static ufs2_daddr_t badblk; 56 static ufs2_daddr_t dupblk; 57 static ino_t lastino; /* last inode in use */ 58 59 static int checkinode(ino_t inumber, struct inodesc *, int rebuiltcg); 60 61 void 62 pass1(void) 63 { 64 struct inostat *info; 65 struct inodesc idesc; 66 struct bufarea *cgbp; 67 struct cg *cgp; 68 ino_t inumber, inosused, mininos; 69 ufs2_daddr_t i, cgd; 70 u_int8_t *cp; 71 int c, rebuiltcg; 72 73 badblk = dupblk = lastino = 0; 74 75 /* 76 * Set file system reserved blocks in used block map. 77 */ 78 for (c = 0; c < sblock.fs_ncg; c++) { 79 cgd = cgdmin(&sblock, c); 80 if (c == 0) { 81 i = cgbase(&sblock, c); 82 } else 83 i = cgsblock(&sblock, c); 84 for (; i < cgd; i++) 85 setbmap(i); 86 } 87 i = sblock.fs_csaddr; 88 cgd = i + howmany(sblock.fs_cssize, sblock.fs_fsize); 89 for (; i < cgd; i++) 90 setbmap(i); 91 92 /* 93 * Find all allocated blocks. 94 */ 95 memset(&idesc, 0, sizeof(struct inodesc)); 96 idesc.id_func = pass1check; 97 n_files = n_blks = 0; 98 for (c = 0; c < sblock.fs_ncg; c++) { 99 inumber = c * sblock.fs_ipg; 100 cgbp = cglookup(c); 101 cgp = cgbp->b_un.b_cg; 102 rebuiltcg = 0; 103 if (!check_cgmagic(c, cgbp, 0)) { 104 if (!check_cgmagic(c, cgbp, 1)) 105 cgheader_corrupt = 1; 106 else 107 rebuiltcg = 1; 108 } 109 if (!rebuiltcg && sblock.fs_magic == FS_UFS2_MAGIC) { 110 inosused = cgp->cg_initediblk; 111 if (inosused > sblock.fs_ipg) { 112 pfatal("Too many initialized inodes (%ju > %d) " 113 "in cylinder group %d\nReset to %d\n", 114 (uintmax_t)inosused, sblock.fs_ipg, c, 115 sblock.fs_ipg); 116 inosused = sblock.fs_ipg; 117 } 118 } else { 119 inosused = sblock.fs_ipg; 120 } 121 if (got_siginfo) { 122 printf("%s: phase 1: cyl group %d of %d (%d%%)\n", 123 cdevname, c, sblock.fs_ncg, 124 c * 100 / sblock.fs_ncg); 125 got_siginfo = 0; 126 } 127 if (got_sigalarm) { 128 setproctitle("%s p1 %d%%", cdevname, 129 c * 100 / sblock.fs_ncg); 130 got_sigalarm = 0; 131 } 132 /* 133 * If we are using soft updates, then we can trust the 134 * cylinder group inode allocation maps to tell us which 135 * inodes are allocated. We will scan the used inode map 136 * to find the inodes that are really in use, and then 137 * read only those inodes in from disk. 138 */ 139 if ((preen || inoopt) && usedsoftdep && !rebuiltcg) { 140 cp = &cg_inosused(cgp)[(inosused - 1) / CHAR_BIT]; 141 for ( ; inosused != 0; cp--) { 142 if (*cp == 0) { 143 if (inosused > CHAR_BIT) 144 inosused -= CHAR_BIT; 145 else 146 inosused = 0; 147 continue; 148 } 149 for (i = 1 << (CHAR_BIT - 1); i > 0; i >>= 1) { 150 if (*cp & i) 151 break; 152 inosused--; 153 } 154 break; 155 } 156 } 157 /* 158 * Allocate inoinfo structures for the allocated inodes. 159 */ 160 inostathead[c].il_numalloced = inosused; 161 if (inosused == 0) { 162 inostathead[c].il_stat = NULL; 163 continue; 164 } 165 info = Calloc((unsigned)inosused, sizeof(struct inostat)); 166 if (info == NULL) 167 errx(EEXIT, "cannot alloc %u bytes for inoinfo", 168 (unsigned)(sizeof(struct inostat) * inosused)); 169 inostathead[c].il_stat = info; 170 /* 171 * Scan the allocated inodes. 172 */ 173 setinodebuf(c, inosused); 174 for (i = 0; i < inosused; i++, inumber++) { 175 if (inumber < UFS_ROOTINO) { 176 (void)getnextinode(inumber, rebuiltcg); 177 continue; 178 } 179 /* 180 * NULL return indicates probable end of allocated 181 * inodes during cylinder group rebuild attempt. 182 * We always keep trying until we get to the minimum 183 * valid number for this cylinder group. 184 */ 185 if (checkinode(inumber, &idesc, rebuiltcg) == 0 && 186 i > cgp->cg_initediblk) 187 break; 188 } 189 /* 190 * This optimization speeds up future runs of fsck 191 * by trimming down the number of inodes in cylinder 192 * groups that formerly had many inodes but now have 193 * fewer in use. 194 */ 195 mininos = roundup(inosused + INOPB(&sblock), INOPB(&sblock)); 196 if (inoopt && !preen && !rebuiltcg && 197 sblock.fs_magic == FS_UFS2_MAGIC && 198 cgp->cg_initediblk > 2 * INOPB(&sblock) && 199 mininos < cgp->cg_initediblk) { 200 i = cgp->cg_initediblk; 201 if (mininos < 2 * INOPB(&sblock)) 202 cgp->cg_initediblk = 2 * INOPB(&sblock); 203 else 204 cgp->cg_initediblk = mininos; 205 pwarn("CYLINDER GROUP %d: RESET FROM %ju TO %d %s\n", 206 c, i, cgp->cg_initediblk, "VALID INODES"); 207 cgdirty(cgbp); 208 } 209 if (inosused < sblock.fs_ipg) 210 continue; 211 lastino += 1; 212 if (lastino < (c * sblock.fs_ipg)) 213 inosused = 0; 214 else 215 inosused = lastino - (c * sblock.fs_ipg); 216 if (rebuiltcg && inosused > cgp->cg_initediblk && 217 sblock.fs_magic == FS_UFS2_MAGIC) { 218 cgp->cg_initediblk = roundup(inosused, INOPB(&sblock)); 219 pwarn("CYLINDER GROUP %d: FOUND %d VALID INODES\n", c, 220 cgp->cg_initediblk); 221 } 222 /* 223 * If we were not able to determine in advance which inodes 224 * were in use, then reduce the size of the inoinfo structure 225 * to the size necessary to describe the inodes that we 226 * really found. Always leave map space in the first cylinder 227 * group in case we need to a root or lost+found directory. 228 */ 229 if (inumber == lastino || c == 0) 230 continue; 231 inostathead[c].il_numalloced = inosused; 232 if (inosused == 0) { 233 free(inostathead[c].il_stat); 234 inostathead[c].il_stat = NULL; 235 continue; 236 } 237 info = Calloc((unsigned)inosused, sizeof(struct inostat)); 238 if (info == NULL) 239 errx(EEXIT, "cannot alloc %u bytes for inoinfo", 240 (unsigned)(sizeof(struct inostat) * inosused)); 241 memmove(info, inostathead[c].il_stat, inosused * sizeof(*info)); 242 free(inostathead[c].il_stat); 243 inostathead[c].il_stat = info; 244 } 245 freeinodebuf(); 246 } 247 248 static int 249 checkinode(ino_t inumber, struct inodesc *idesc, int rebuiltcg) 250 { 251 struct inode ip; 252 union dinode *dp; 253 off_t kernmaxfilesize; 254 ufs2_daddr_t ndb; 255 mode_t mode; 256 intmax_t size, fixsize; 257 int j, ret, offset; 258 259 if ((dp = getnextinode(inumber, rebuiltcg)) == NULL) { 260 pfatal("INVALID INODE"); 261 goto unknown; 262 } 263 mode = DIP(dp, di_mode) & IFMT; 264 if (mode == 0) { 265 if ((sblock.fs_magic == FS_UFS1_MAGIC && 266 (memcmp(dp->dp1.di_db, zino.dp1.di_db, 267 UFS_NDADDR * sizeof(ufs1_daddr_t)) || 268 memcmp(dp->dp1.di_ib, zino.dp1.di_ib, 269 UFS_NIADDR * sizeof(ufs1_daddr_t)) || 270 dp->dp1.di_mode || dp->dp1.di_size)) || 271 (sblock.fs_magic == FS_UFS2_MAGIC && 272 (memcmp(dp->dp2.di_db, zino.dp2.di_db, 273 UFS_NDADDR * sizeof(ufs2_daddr_t)) || 274 memcmp(dp->dp2.di_ib, zino.dp2.di_ib, 275 UFS_NIADDR * sizeof(ufs2_daddr_t)) || 276 dp->dp2.di_mode || dp->dp2.di_size))) { 277 pfatal("PARTIALLY ALLOCATED INODE I=%lu", 278 (u_long)inumber); 279 if (reply("CLEAR") == 1) { 280 ginode(inumber, &ip); 281 clearinode(ip.i_dp); 282 inodirty(&ip); 283 irelse(&ip); 284 } 285 } 286 inoinfo(inumber)->ino_state = USTATE; 287 return (1); 288 } 289 lastino = inumber; 290 /* This should match the file size limit in ffs_mountfs(). */ 291 if (sblock.fs_magic == FS_UFS1_MAGIC) 292 kernmaxfilesize = (off_t)0x40000000 * sblock.fs_bsize - 1; 293 else 294 kernmaxfilesize = sblock.fs_maxfilesize; 295 if (DIP(dp, di_size) > kernmaxfilesize || 296 DIP(dp, di_size) > sblock.fs_maxfilesize || 297 (mode == IFDIR && DIP(dp, di_size) > MAXDIRSIZE)) { 298 if (debug) 299 printf("bad size %ju:", (uintmax_t)DIP(dp, di_size)); 300 pfatal("BAD FILE SIZE"); 301 goto unknown; 302 } 303 if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) { 304 ginode(inumber, &ip); 305 dp = ip.i_dp; 306 DIP_SET(dp, di_size, sblock.fs_fsize); 307 DIP_SET(dp, di_mode, IFREG|0600); 308 inodirty(&ip); 309 irelse(&ip); 310 } 311 if ((mode == IFBLK || mode == IFCHR || mode == IFIFO || 312 mode == IFSOCK) && DIP(dp, di_size) != 0) { 313 if (debug) 314 printf("bad special-file size %ju:", 315 (uintmax_t)DIP(dp, di_size)); 316 pfatal("BAD SPECIAL-FILE SIZE"); 317 goto unknown; 318 } 319 if ((mode == IFBLK || mode == IFCHR) && 320 (dev_t)DIP(dp, di_rdev) == NODEV) { 321 if (debug) 322 printf("bad special-file rdev NODEV:"); 323 pfatal("BAD SPECIAL-FILE RDEV"); 324 goto unknown; 325 } 326 ndb = howmany(DIP(dp, di_size), sblock.fs_bsize); 327 if (ndb < 0) { 328 if (debug) 329 printf("negative size %ju ndb %ju:", 330 (uintmax_t)DIP(dp, di_size), (uintmax_t)ndb); 331 pfatal("NEGATIVE FILE SIZE"); 332 goto unknown; 333 } 334 if (mode == IFBLK || mode == IFCHR) 335 ndb++; 336 if (mode == IFLNK) { 337 /* 338 * Fake ndb value so direct/indirect block checks below 339 * will detect any garbage after symlink string. 340 */ 341 if (DIP(dp, di_size) < (off_t)sblock.fs_maxsymlinklen) { 342 if (sblock.fs_magic == FS_UFS1_MAGIC) 343 ndb = howmany(DIP(dp, di_size), 344 sizeof(ufs1_daddr_t)); 345 else 346 ndb = howmany(DIP(dp, di_size), 347 sizeof(ufs2_daddr_t)); 348 if (ndb > UFS_NDADDR) { 349 j = ndb - UFS_NDADDR; 350 for (ndb = 1; j > 1; j--) 351 ndb *= NINDIR(&sblock); 352 ndb += UFS_NDADDR; 353 } 354 } 355 } 356 for (j = ndb; ndb < UFS_NDADDR && j < UFS_NDADDR; j++) { 357 if (DIP(dp, di_db[j]) == 0) 358 continue; 359 if (debug) 360 printf("invalid direct addr[%d]: %ju\n", j, 361 (uintmax_t)DIP(dp, di_db[j])); 362 pfatal("INVALID DIRECT BLOCK"); 363 ginode(inumber, &ip); 364 prtinode(&ip); 365 if (reply("CLEAR") == 1) { 366 DIP_SET(ip.i_dp, di_db[j], 0); 367 inodirty(&ip); 368 } 369 irelse(&ip); 370 } 371 for (j = 0, ndb -= UFS_NDADDR; ndb > 0; j++) 372 ndb /= NINDIR(&sblock); 373 for (; j < UFS_NIADDR; j++) { 374 if (DIP(dp, di_ib[j]) == 0) 375 continue; 376 if (debug) 377 printf("invalid indirect addr: %ju\n", 378 (uintmax_t)DIP(dp, di_ib[j])); 379 pfatal("INVALID INDIRECT BLOCK"); 380 ginode(inumber, &ip); 381 prtinode(&ip); 382 if (reply("CLEAR") == 1) { 383 DIP_SET(ip.i_dp, di_ib[j], 0); 384 inodirty(&ip); 385 } 386 irelse(&ip); 387 } 388 if (ftypeok(dp) == 0) { 389 pfatal("UNKNOWN FILE TYPE"); 390 goto unknown; 391 } 392 n_files++; 393 inoinfo(inumber)->ino_linkcnt = DIP(dp, di_nlink); 394 if (mode == IFDIR) { 395 if (DIP(dp, di_size) == 0) { 396 inoinfo(inumber)->ino_state = DCLEAR; 397 } else if (DIP(dp, di_nlink) <= 0) { 398 inoinfo(inumber)->ino_state = DZLINK; 399 } else { 400 inoinfo(inumber)->ino_state = DSTATE; 401 cacheino(dp, inumber); 402 countdirs++; 403 } 404 } else if (DIP(dp, di_nlink) <= 0) 405 inoinfo(inumber)->ino_state = FZLINK; 406 else 407 inoinfo(inumber)->ino_state = FSTATE; 408 inoinfo(inumber)->ino_type = IFTODT(mode); 409 badblk = dupblk = 0; 410 idesc->id_number = inumber; 411 if (DIP(dp, di_flags) & SF_SNAPSHOT) 412 inoinfo(inumber)->ino_idtype = SNAP; 413 else 414 inoinfo(inumber)->ino_idtype = ADDR; 415 idesc->id_type = inoinfo(inumber)->ino_idtype; 416 (void)ckinode(dp, idesc); 417 if (sblock.fs_magic == FS_UFS2_MAGIC && dp->dp2.di_extsize > 0) { 418 ndb = howmany(dp->dp2.di_extsize, sblock.fs_bsize); 419 for (j = 0; j < UFS_NXADDR; j++) { 420 if (--ndb == 0 && 421 (offset = blkoff(&sblock, dp->dp2.di_extsize)) != 0) 422 idesc->id_numfrags = numfrags(&sblock, 423 fragroundup(&sblock, offset)); 424 else 425 idesc->id_numfrags = sblock.fs_frag; 426 if (dp->dp2.di_extb[j] == 0) 427 continue; 428 idesc->id_blkno = dp->dp2.di_extb[j]; 429 ret = (*idesc->id_func)(idesc); 430 if (ret & STOP) 431 break; 432 } 433 } 434 if (sblock.fs_magic == FS_UFS2_MAGIC) 435 eascan(idesc, &dp->dp2); 436 idesc->id_entryno *= btodb(sblock.fs_fsize); 437 if (DIP(dp, di_blocks) != idesc->id_entryno) { 438 pwarn("INCORRECT BLOCK COUNT I=%lu (%ju should be %ju)", 439 (u_long)inumber, (uintmax_t)DIP(dp, di_blocks), 440 (uintmax_t)idesc->id_entryno); 441 if (preen) 442 printf(" (CORRECTED)\n"); 443 else if (reply("CORRECT") == 0) 444 return (1); 445 if (bkgrdflag == 0) { 446 ginode(inumber, &ip); 447 DIP_SET(ip.i_dp, di_blocks, idesc->id_entryno); 448 inodirty(&ip); 449 irelse(&ip); 450 } else { 451 cmd.value = idesc->id_number; 452 cmd.size = idesc->id_entryno - DIP(dp, di_blocks); 453 if (debug) 454 printf("adjblkcnt ino %ju amount %lld\n", 455 (uintmax_t)cmd.value, (long long)cmd.size); 456 if (sysctl(adjblkcnt, MIBSIZE, 0, 0, 457 &cmd, sizeof cmd) == -1) 458 rwerror("ADJUST INODE BLOCK COUNT", cmd.value); 459 } 460 } 461 /* 462 * UFS does not allow files to end with a hole; it requires that 463 * the last block of a file be allocated. The last allocated block 464 * in a file is tracked in id_lballoc. Here, we check for a size 465 * past the last allocated block of the file and if that is found, 466 * shorten the file to reference the last allocated block to avoid 467 * having it reference a hole at its end. 468 * 469 * Soft updates will always ensure that the file size is correct 470 * for files that contain only direct block pointers. However 471 * soft updates does not roll back sizes for files with indirect 472 * blocks that it has set to unallocated because their contents 473 * have not yet been written to disk. Hence, the file can appear 474 * to have a hole at its end because the block pointer has been 475 * rolled back to zero. Thus finding a hole at the end of a file 476 * that is located in an indirect block receives only a warning 477 * while finding a hole at the end of a file in a direct block 478 * receives a fatal error message. 479 */ 480 size = DIP(dp, di_size); 481 if (idesc->id_lballoc < lblkno(&sblock, size - 1) && 482 /* exclude embedded symbolic links */ 483 ((mode != IFLNK) || size >= sblock.fs_maxsymlinklen)) { 484 fixsize = lblktosize(&sblock, idesc->id_lballoc + 1); 485 if (size > UFS_NDADDR * sblock.fs_bsize) 486 pwarn("INODE %lu: FILE SIZE %ju BEYOND END OF " 487 "ALLOCATED FILE, SIZE SHOULD BE %ju", 488 (u_long)inumber, size, fixsize); 489 else 490 pfatal("INODE %lu: FILE SIZE %ju BEYOND END OF " 491 "ALLOCATED FILE, SIZE SHOULD BE %ju", 492 (u_long)inumber, size, fixsize); 493 if (preen) 494 printf(" (ADJUSTED)\n"); 495 else if (reply("ADJUST") == 0) 496 return (1); 497 if (bkgrdflag == 0) { 498 ginode(inumber, &ip); 499 DIP_SET(ip.i_dp, di_size, fixsize); 500 inodirty(&ip); 501 irelse(&ip); 502 } else { 503 cmd.value = idesc->id_number; 504 cmd.size = fixsize; 505 if (debug) 506 printf("setsize ino %ju size set to %ju\n", 507 (uintmax_t)cmd.value, (uintmax_t)cmd.size); 508 if (sysctl(setsize, MIBSIZE, 0, 0, 509 &cmd, sizeof cmd) == -1) 510 rwerror("SET INODE SIZE", cmd.value); 511 } 512 513 } 514 return (1); 515 unknown: 516 ginode(inumber, &ip); 517 prtinode(&ip); 518 inoinfo(inumber)->ino_state = USTATE; 519 if (reply("CLEAR") == 1) { 520 clearinode(ip.i_dp); 521 inodirty(&ip); 522 } 523 irelse(&ip); 524 return (1); 525 } 526 527 int 528 pass1check(struct inodesc *idesc) 529 { 530 int res = KEEPON; 531 int anyout, nfrags; 532 ufs2_daddr_t blkno = idesc->id_blkno; 533 struct dups *dlp; 534 struct dups *new; 535 536 if (idesc->id_type == SNAP) { 537 if (blkno == BLK_NOCOPY) 538 return (KEEPON); 539 if (idesc->id_number == cursnapshot) { 540 if (blkno == blkstofrags(&sblock, idesc->id_lbn)) 541 return (KEEPON); 542 if (blkno == BLK_SNAP) { 543 blkno = blkstofrags(&sblock, idesc->id_lbn); 544 idesc->id_entryno -= idesc->id_numfrags; 545 } 546 } else { 547 if (blkno == BLK_SNAP) 548 return (KEEPON); 549 } 550 } 551 if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) { 552 blkerror(idesc->id_number, "BAD", blkno); 553 if (badblk++ >= MAXBAD) { 554 pwarn("EXCESSIVE BAD BLKS I=%lu", 555 (u_long)idesc->id_number); 556 if (preen) 557 printf(" (SKIPPING)\n"); 558 else if (reply("CONTINUE") == 0) { 559 ckfini(0); 560 exit(EEXIT); 561 } 562 rerun = 1; 563 return (STOP); 564 } 565 } 566 for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { 567 if (anyout && chkrange(blkno, 1)) { 568 res = SKIP; 569 } else if (!testbmap(blkno)) { 570 n_blks++; 571 setbmap(blkno); 572 } else { 573 blkerror(idesc->id_number, "DUP", blkno); 574 if (dupblk++ >= MAXDUP) { 575 pwarn("EXCESSIVE DUP BLKS I=%lu", 576 (u_long)idesc->id_number); 577 if (preen) 578 printf(" (SKIPPING)\n"); 579 else if (reply("CONTINUE") == 0) { 580 ckfini(0); 581 exit(EEXIT); 582 } 583 rerun = 1; 584 return (STOP); 585 } 586 new = (struct dups *)Malloc(sizeof(struct dups)); 587 if (new == NULL) { 588 pfatal("DUP TABLE OVERFLOW."); 589 if (reply("CONTINUE") == 0) { 590 ckfini(0); 591 exit(EEXIT); 592 } 593 rerun = 1; 594 return (STOP); 595 } 596 new->dup = blkno; 597 if (muldup == NULL) { 598 duplist = muldup = new; 599 new->next = NULL; 600 } else { 601 new->next = muldup->next; 602 muldup->next = new; 603 } 604 for (dlp = duplist; dlp != muldup; dlp = dlp->next) 605 if (dlp->dup == blkno) 606 break; 607 if (dlp == muldup && dlp->dup != blkno) 608 muldup = new; 609 } 610 /* 611 * count the number of blocks found in id_entryno 612 */ 613 idesc->id_entryno++; 614 } 615 if (idesc->id_level == 0 && idesc->id_lballoc < idesc->id_lbn) 616 idesc->id_lballoc = idesc->id_lbn; 617 return (res); 618 } 619