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[] = "@(#)utilities.c 8.6 (Berkeley) 5/19/95"; 33 #endif /* not lint */ 34 #endif 35 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 #include <sys/param.h> 39 #include <sys/time.h> 40 #include <sys/types.h> 41 #include <sys/sysctl.h> 42 #include <sys/disk.h> 43 #include <sys/disklabel.h> 44 #include <sys/ioctl.h> 45 #include <sys/stat.h> 46 47 #include <ufs/ufs/dinode.h> 48 #include <ufs/ufs/dir.h> 49 #include <ufs/ffs/fs.h> 50 51 #include <err.h> 52 #include <errno.h> 53 #include <string.h> 54 #include <ctype.h> 55 #include <fstab.h> 56 #include <stdint.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <time.h> 60 #include <unistd.h> 61 62 #include "fsck.h" 63 64 static void slowio_start(void); 65 static void slowio_end(void); 66 static void printIOstats(void); 67 68 static long diskreads, totaldiskreads, totalreads; /* Disk cache statistics */ 69 static struct timespec startpass, finishpass; 70 struct timeval slowio_starttime; 71 int slowio_delay_usec = 10000; /* Initial IO delay for background fsck */ 72 int slowio_pollcnt; 73 static struct bufarea cgblk; /* backup buffer for cylinder group blocks */ 74 static TAILQ_HEAD(buflist, bufarea) bufhead; /* head of buffer cache list */ 75 static int numbufs; /* size of buffer cache */ 76 static char *buftype[BT_NUMBUFTYPES] = BT_NAMES; 77 static struct bufarea *cgbufs; /* header for cylinder group cache */ 78 static int flushtries; /* number of tries to reclaim memory */ 79 80 void 81 fsutilinit(void) 82 { 83 diskreads = totaldiskreads = totalreads = 0; 84 bzero(&startpass, sizeof(struct timespec)); 85 bzero(&finishpass, sizeof(struct timespec)); 86 bzero(&slowio_starttime, sizeof(struct timeval)); 87 slowio_delay_usec = 10000; 88 slowio_pollcnt = 0; 89 bzero(&cgblk, sizeof(struct bufarea)); 90 TAILQ_INIT(&bufhead); 91 numbufs = 0; 92 /* buftype ? */ 93 cgbufs = NULL; 94 flushtries = 0; 95 } 96 97 int 98 ftypeok(union dinode *dp) 99 { 100 switch (DIP(dp, di_mode) & IFMT) { 101 102 case IFDIR: 103 case IFREG: 104 case IFBLK: 105 case IFCHR: 106 case IFLNK: 107 case IFSOCK: 108 case IFIFO: 109 return (1); 110 111 default: 112 if (debug) 113 printf("bad file type 0%o\n", DIP(dp, di_mode)); 114 return (0); 115 } 116 } 117 118 int 119 reply(const char *question) 120 { 121 int persevere; 122 char c; 123 124 if (preen) 125 pfatal("INTERNAL ERROR: GOT TO reply()"); 126 persevere = !strcmp(question, "CONTINUE"); 127 printf("\n"); 128 if (!persevere && (nflag || (fswritefd < 0 && bkgrdflag == 0))) { 129 printf("%s? no\n\n", question); 130 resolved = 0; 131 return (0); 132 } 133 if (yflag || (persevere && nflag)) { 134 printf("%s? yes\n\n", question); 135 return (1); 136 } 137 do { 138 printf("%s? [yn] ", question); 139 (void) fflush(stdout); 140 c = getc(stdin); 141 while (c != '\n' && getc(stdin) != '\n') { 142 if (feof(stdin)) { 143 resolved = 0; 144 return (0); 145 } 146 } 147 } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); 148 printf("\n"); 149 if (c == 'y' || c == 'Y') 150 return (1); 151 resolved = 0; 152 return (0); 153 } 154 155 /* 156 * Look up state information for an inode. 157 */ 158 struct inostat * 159 inoinfo(ino_t inum) 160 { 161 static struct inostat unallocated = { USTATE, 0, 0 }; 162 struct inostatlist *ilp; 163 int iloff; 164 165 if (inum > maxino) 166 errx(EEXIT, "inoinfo: inumber %ju out of range", 167 (uintmax_t)inum); 168 ilp = &inostathead[inum / sblock.fs_ipg]; 169 iloff = inum % sblock.fs_ipg; 170 if (iloff >= ilp->il_numalloced) 171 return (&unallocated); 172 return (&ilp->il_stat[iloff]); 173 } 174 175 /* 176 * Malloc buffers and set up cache. 177 */ 178 void 179 bufinit(void) 180 { 181 struct bufarea *bp; 182 long bufcnt, i; 183 char *bufp; 184 185 pbp = pdirbp = (struct bufarea *)0; 186 bufp = Malloc((unsigned int)sblock.fs_bsize); 187 if (bufp == 0) 188 errx(EEXIT, "cannot allocate buffer pool"); 189 cgblk.b_un.b_buf = bufp; 190 initbarea(&cgblk, BT_CYLGRP); 191 TAILQ_INIT(&bufhead); 192 bufcnt = MAXBUFS; 193 if (bufcnt < MINBUFS) 194 bufcnt = MINBUFS; 195 for (i = 0; i < bufcnt; i++) { 196 bp = (struct bufarea *)Malloc(sizeof(struct bufarea)); 197 bufp = Malloc((unsigned int)sblock.fs_bsize); 198 if (bp == NULL || bufp == NULL) { 199 if (i >= MINBUFS) 200 break; 201 errx(EEXIT, "cannot allocate buffer pool"); 202 } 203 bp->b_un.b_buf = bufp; 204 TAILQ_INSERT_HEAD(&bufhead, bp, b_list); 205 initbarea(bp, BT_UNKNOWN); 206 } 207 numbufs = i; /* save number of buffers */ 208 for (i = 0; i < BT_NUMBUFTYPES; i++) { 209 readtime[i].tv_sec = totalreadtime[i].tv_sec = 0; 210 readtime[i].tv_nsec = totalreadtime[i].tv_nsec = 0; 211 readcnt[i] = totalreadcnt[i] = 0; 212 } 213 } 214 215 /* 216 * Manage cylinder group buffers. 217 */ 218 static struct bufarea *cgbufs; /* header for cylinder group cache */ 219 static int flushtries; /* number of tries to reclaim memory */ 220 221 struct bufarea * 222 cgget(int cg) 223 { 224 struct bufarea *cgbp; 225 struct cg *cgp; 226 227 if (cgbufs == NULL) { 228 cgbufs = calloc(sblock.fs_ncg, sizeof(struct bufarea)); 229 if (cgbufs == NULL) 230 errx(EEXIT, "cannot allocate cylinder group buffers"); 231 } 232 cgbp = &cgbufs[cg]; 233 if (cgbp->b_un.b_cg != NULL) 234 return (cgbp); 235 cgp = NULL; 236 if (flushtries == 0) 237 cgp = malloc((unsigned int)sblock.fs_cgsize); 238 if (cgp == NULL) { 239 getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize); 240 return (&cgblk); 241 } 242 cgbp->b_un.b_cg = cgp; 243 initbarea(cgbp, BT_CYLGRP); 244 getblk(cgbp, cgtod(&sblock, cg), sblock.fs_cgsize); 245 return (cgbp); 246 } 247 248 /* 249 * Attempt to flush a cylinder group cache entry. 250 * Return whether the flush was successful. 251 */ 252 int 253 flushentry(void) 254 { 255 struct bufarea *cgbp; 256 257 if (flushtries == sblock.fs_ncg || cgbufs == NULL) 258 return (0); 259 cgbp = &cgbufs[flushtries++]; 260 if (cgbp->b_un.b_cg == NULL) 261 return (0); 262 flush(fswritefd, cgbp); 263 free(cgbp->b_un.b_buf); 264 cgbp->b_un.b_buf = NULL; 265 return (1); 266 } 267 268 /* 269 * Manage a cache of directory blocks. 270 */ 271 struct bufarea * 272 getdatablk(ufs2_daddr_t blkno, long size, int type) 273 { 274 struct bufarea *bp; 275 276 TAILQ_FOREACH(bp, &bufhead, b_list) 277 if (bp->b_bno == fsbtodb(&sblock, blkno)) 278 goto foundit; 279 TAILQ_FOREACH_REVERSE(bp, &bufhead, buflist, b_list) 280 if ((bp->b_flags & B_INUSE) == 0) 281 break; 282 if (bp == NULL) 283 errx(EEXIT, "deadlocked buffer pool"); 284 bp->b_type = type; 285 getblk(bp, blkno, size); 286 /* fall through */ 287 foundit: 288 if (debug && bp->b_type != type) 289 printf("Buffer type changed from %s to %s\n", 290 buftype[bp->b_type], buftype[type]); 291 TAILQ_REMOVE(&bufhead, bp, b_list); 292 TAILQ_INSERT_HEAD(&bufhead, bp, b_list); 293 bp->b_flags |= B_INUSE; 294 return (bp); 295 } 296 297 /* 298 * Timespec operations (from <sys/time.h>). 299 */ 300 #define timespecsub(vvp, uvp) \ 301 do { \ 302 (vvp)->tv_sec -= (uvp)->tv_sec; \ 303 (vvp)->tv_nsec -= (uvp)->tv_nsec; \ 304 if ((vvp)->tv_nsec < 0) { \ 305 (vvp)->tv_sec--; \ 306 (vvp)->tv_nsec += 1000000000; \ 307 } \ 308 } while (0) 309 #define timespecadd(vvp, uvp) \ 310 do { \ 311 (vvp)->tv_sec += (uvp)->tv_sec; \ 312 (vvp)->tv_nsec += (uvp)->tv_nsec; \ 313 if ((vvp)->tv_nsec >= 1000000000) { \ 314 (vvp)->tv_sec++; \ 315 (vvp)->tv_nsec -= 1000000000; \ 316 } \ 317 } while (0) 318 319 void 320 getblk(struct bufarea *bp, ufs2_daddr_t blk, long size) 321 { 322 ufs2_daddr_t dblk; 323 struct timespec start, finish; 324 325 dblk = fsbtodb(&sblock, blk); 326 if (bp->b_bno == dblk) { 327 totalreads++; 328 } else { 329 flush(fswritefd, bp); 330 if (debug) { 331 readcnt[bp->b_type]++; 332 clock_gettime(CLOCK_REALTIME_PRECISE, &start); 333 } 334 bp->b_errs = blread(fsreadfd, bp->b_un.b_buf, dblk, size); 335 if (debug) { 336 clock_gettime(CLOCK_REALTIME_PRECISE, &finish); 337 timespecsub(&finish, &start); 338 timespecadd(&readtime[bp->b_type], &finish); 339 } 340 bp->b_bno = dblk; 341 bp->b_size = size; 342 } 343 } 344 345 void 346 flush(int fd, struct bufarea *bp) 347 { 348 int i, j; 349 350 if (!bp->b_dirty) 351 return; 352 bp->b_dirty = 0; 353 if (fswritefd < 0) { 354 pfatal("WRITING IN READ_ONLY MODE.\n"); 355 return; 356 } 357 if (bp->b_errs != 0) 358 pfatal("WRITING %sZERO'ED BLOCK %lld TO DISK\n", 359 (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", 360 (long long)bp->b_bno); 361 bp->b_errs = 0; 362 blwrite(fd, bp->b_un.b_buf, bp->b_bno, bp->b_size); 363 if (bp != &sblk) 364 return; 365 for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 366 blwrite(fswritefd, (char *)sblock.fs_csp + i, 367 fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 368 sblock.fs_cssize - i < sblock.fs_bsize ? 369 sblock.fs_cssize - i : sblock.fs_bsize); 370 } 371 } 372 373 void 374 rwerror(const char *mesg, ufs2_daddr_t blk) 375 { 376 377 if (bkgrdcheck) 378 exit(EEXIT); 379 if (preen == 0) 380 printf("\n"); 381 pfatal("CANNOT %s: %ld", mesg, (long)blk); 382 if (reply("CONTINUE") == 0) 383 exit(EEXIT); 384 } 385 386 void 387 ckfini(int markclean) 388 { 389 struct bufarea *bp, *nbp; 390 int ofsmodified, cnt; 391 392 if (bkgrdflag) { 393 unlink(snapname); 394 if ((!(sblock.fs_flags & FS_UNCLEAN)) != markclean) { 395 cmd.value = FS_UNCLEAN; 396 cmd.size = markclean ? -1 : 1; 397 if (sysctlbyname("vfs.ffs.setflags", 0, 0, 398 &cmd, sizeof cmd) == -1) 399 rwerror("SET FILE SYSTEM FLAGS", FS_UNCLEAN); 400 if (!preen) { 401 printf("\n***** FILE SYSTEM MARKED %s *****\n", 402 markclean ? "CLEAN" : "DIRTY"); 403 if (!markclean) 404 rerun = 1; 405 } 406 } else if (!preen && !markclean) { 407 printf("\n***** FILE SYSTEM STILL DIRTY *****\n"); 408 rerun = 1; 409 } 410 } 411 if (debug && totalreads > 0) 412 printf("cache with %d buffers missed %ld of %ld (%d%%)\n", 413 numbufs, totaldiskreads, totalreads, 414 (int)(totaldiskreads * 100 / totalreads)); 415 if (fswritefd < 0) { 416 (void)close(fsreadfd); 417 return; 418 } 419 flush(fswritefd, &sblk); 420 if (havesb && cursnapshot == 0 && sblock.fs_magic == FS_UFS2_MAGIC && 421 sblk.b_bno != sblock.fs_sblockloc / dev_bsize && 422 !preen && reply("UPDATE STANDARD SUPERBLOCK")) { 423 sblk.b_bno = sblock.fs_sblockloc / dev_bsize; 424 sbdirty(); 425 flush(fswritefd, &sblk); 426 } 427 flush(fswritefd, &cgblk); 428 free(cgblk.b_un.b_buf); 429 cnt = 0; 430 TAILQ_FOREACH_REVERSE_SAFE(bp, &bufhead, buflist, b_list, nbp) { 431 TAILQ_REMOVE(&bufhead, bp, b_list); 432 cnt++; 433 flush(fswritefd, bp); 434 free(bp->b_un.b_buf); 435 free((char *)bp); 436 } 437 if (numbufs != cnt) 438 errx(EEXIT, "panic: lost %d buffers", numbufs - cnt); 439 if (cgbufs != NULL) { 440 for (cnt = 0; cnt < sblock.fs_ncg; cnt++) { 441 if (cgbufs[cnt].b_un.b_cg == NULL) 442 continue; 443 flush(fswritefd, &cgbufs[cnt]); 444 free(cgbufs[cnt].b_un.b_cg); 445 } 446 free(cgbufs); 447 } 448 pbp = pdirbp = (struct bufarea *)0; 449 if (cursnapshot == 0 && sblock.fs_clean != markclean) { 450 if ((sblock.fs_clean = markclean) != 0) { 451 sblock.fs_flags &= ~(FS_UNCLEAN | FS_NEEDSFSCK); 452 sblock.fs_pendingblocks = 0; 453 sblock.fs_pendinginodes = 0; 454 } 455 sbdirty(); 456 ofsmodified = fsmodified; 457 flush(fswritefd, &sblk); 458 fsmodified = ofsmodified; 459 if (!preen) { 460 printf("\n***** FILE SYSTEM MARKED %s *****\n", 461 markclean ? "CLEAN" : "DIRTY"); 462 if (!markclean) 463 rerun = 1; 464 } 465 } else if (!preen) { 466 if (markclean) { 467 printf("\n***** FILE SYSTEM IS CLEAN *****\n"); 468 } else { 469 printf("\n***** FILE SYSTEM STILL DIRTY *****\n"); 470 rerun = 1; 471 } 472 } 473 (void)close(fsreadfd); 474 (void)close(fswritefd); 475 } 476 477 /* 478 * Print out I/O statistics. 479 */ 480 void 481 IOstats(char *what) 482 { 483 int i; 484 485 if (debug == 0) 486 return; 487 if (diskreads == 0) { 488 printf("%s: no I/O\n\n", what); 489 return; 490 } 491 if (startpass.tv_sec == 0) 492 startpass = startprog; 493 printf("%s: I/O statistics\n", what); 494 printIOstats(); 495 totaldiskreads += diskreads; 496 diskreads = 0; 497 for (i = 0; i < BT_NUMBUFTYPES; i++) { 498 timespecadd(&totalreadtime[i], &readtime[i]); 499 totalreadcnt[i] += readcnt[i]; 500 readtime[i].tv_sec = readtime[i].tv_nsec = 0; 501 readcnt[i] = 0; 502 } 503 clock_gettime(CLOCK_REALTIME_PRECISE, &startpass); 504 } 505 506 void 507 finalIOstats(void) 508 { 509 int i; 510 511 if (debug == 0) 512 return; 513 printf("Final I/O statistics\n"); 514 totaldiskreads += diskreads; 515 diskreads = totaldiskreads; 516 startpass = startprog; 517 for (i = 0; i < BT_NUMBUFTYPES; i++) { 518 timespecadd(&totalreadtime[i], &readtime[i]); 519 totalreadcnt[i] += readcnt[i]; 520 readtime[i] = totalreadtime[i]; 521 readcnt[i] = totalreadcnt[i]; 522 } 523 printIOstats(); 524 } 525 526 static void printIOstats(void) 527 { 528 long long msec, totalmsec; 529 int i; 530 531 clock_gettime(CLOCK_REALTIME_PRECISE, &finishpass); 532 timespecsub(&finishpass, &startpass); 533 printf("Running time: %jd.%03ld sec\n", 534 (intmax_t)finishpass.tv_sec, finishpass.tv_nsec / 1000000); 535 printf("buffer reads by type:\n"); 536 for (totalmsec = 0, i = 0; i < BT_NUMBUFTYPES; i++) 537 totalmsec += readtime[i].tv_sec * 1000 + 538 readtime[i].tv_nsec / 1000000; 539 if (totalmsec == 0) 540 totalmsec = 1; 541 for (i = 0; i < BT_NUMBUFTYPES; i++) { 542 if (readcnt[i] == 0) 543 continue; 544 msec = 545 readtime[i].tv_sec * 1000 + readtime[i].tv_nsec / 1000000; 546 printf("%21s:%8ld %2ld.%ld%% %4jd.%03ld sec %2lld.%lld%%\n", 547 buftype[i], readcnt[i], readcnt[i] * 100 / diskreads, 548 (readcnt[i] * 1000 / diskreads) % 10, 549 (intmax_t)readtime[i].tv_sec, readtime[i].tv_nsec / 1000000, 550 msec * 100 / totalmsec, (msec * 1000 / totalmsec) % 10); 551 } 552 printf("\n"); 553 } 554 555 int 556 blread(int fd, char *buf, ufs2_daddr_t blk, long size) 557 { 558 char *cp; 559 int i, errs; 560 off_t offset; 561 562 offset = blk; 563 offset *= dev_bsize; 564 if (bkgrdflag) 565 slowio_start(); 566 totalreads++; 567 diskreads++; 568 if (lseek(fd, offset, 0) < 0) 569 rwerror("SEEK BLK", blk); 570 else if (read(fd, buf, (int)size) == size) { 571 if (bkgrdflag) 572 slowio_end(); 573 return (0); 574 } 575 576 /* 577 * This is handled specially here instead of in rwerror because 578 * rwerror is used for all sorts of errors, not just true read/write 579 * errors. It should be refactored and fixed. 580 */ 581 if (surrender) { 582 pfatal("CANNOT READ_BLK: %ld", (long)blk); 583 errx(EEXIT, "ABORTING DUE TO READ ERRORS"); 584 } else 585 rwerror("READ BLK", blk); 586 587 if (lseek(fd, offset, 0) < 0) 588 rwerror("SEEK BLK", blk); 589 errs = 0; 590 memset(buf, 0, (size_t)size); 591 printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); 592 for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { 593 if (read(fd, cp, (int)secsize) != secsize) { 594 (void)lseek(fd, offset + i + secsize, 0); 595 if (secsize != dev_bsize && dev_bsize != 1) 596 printf(" %jd (%jd),", 597 (intmax_t)(blk * dev_bsize + i) / secsize, 598 (intmax_t)blk + i / dev_bsize); 599 else 600 printf(" %jd,", (intmax_t)blk + i / dev_bsize); 601 errs++; 602 } 603 } 604 printf("\n"); 605 if (errs) 606 resolved = 0; 607 return (errs); 608 } 609 610 void 611 blwrite(int fd, char *buf, ufs2_daddr_t blk, ssize_t size) 612 { 613 int i; 614 char *cp; 615 off_t offset; 616 617 if (fd < 0) 618 return; 619 offset = blk; 620 offset *= dev_bsize; 621 if (lseek(fd, offset, 0) < 0) 622 rwerror("SEEK BLK", blk); 623 else if (write(fd, buf, size) == size) { 624 fsmodified = 1; 625 return; 626 } 627 resolved = 0; 628 rwerror("WRITE BLK", blk); 629 if (lseek(fd, offset, 0) < 0) 630 rwerror("SEEK BLK", blk); 631 printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 632 for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) 633 if (write(fd, cp, dev_bsize) != dev_bsize) { 634 (void)lseek(fd, offset + i + dev_bsize, 0); 635 printf(" %jd,", (intmax_t)blk + i / dev_bsize); 636 } 637 printf("\n"); 638 return; 639 } 640 641 void 642 blerase(int fd, ufs2_daddr_t blk, long size) 643 { 644 off_t ioarg[2]; 645 646 if (fd < 0) 647 return; 648 ioarg[0] = blk * dev_bsize; 649 ioarg[1] = size; 650 ioctl(fd, DIOCGDELETE, ioarg); 651 /* we don't really care if we succeed or not */ 652 return; 653 } 654 655 /* 656 * Fill a contiguous region with all-zeroes. Note ZEROBUFSIZE is by 657 * definition a multiple of dev_bsize. 658 */ 659 void 660 blzero(int fd, ufs2_daddr_t blk, long size) 661 { 662 static char *zero; 663 off_t offset, len; 664 665 if (fd < 0) 666 return; 667 if (zero == NULL) { 668 zero = calloc(ZEROBUFSIZE, 1); 669 if (zero == NULL) 670 errx(EEXIT, "cannot allocate buffer pool"); 671 } 672 offset = blk * dev_bsize; 673 if (lseek(fd, offset, 0) < 0) 674 rwerror("SEEK BLK", blk); 675 while (size > 0) { 676 len = size > ZEROBUFSIZE ? ZEROBUFSIZE : size; 677 if (write(fd, zero, len) != len) 678 rwerror("WRITE BLK", blk); 679 blk += len / dev_bsize; 680 size -= len; 681 } 682 } 683 684 /* 685 * Verify cylinder group's magic number and other parameters. If the 686 * test fails, offer an option to rebuild the whole cylinder group. 687 */ 688 int 689 check_cgmagic(int cg, struct bufarea *cgbp) 690 { 691 struct cg *cgp = cgbp->b_un.b_cg; 692 693 /* 694 * Extended cylinder group checks. 695 */ 696 if (cg_chkmagic(cgp) && 697 ((sblock.fs_magic == FS_UFS1_MAGIC && 698 cgp->cg_old_niblk == sblock.fs_ipg && 699 cgp->cg_ndblk <= sblock.fs_fpg && 700 cgp->cg_old_ncyl <= sblock.fs_old_cpg) || 701 (sblock.fs_magic == FS_UFS2_MAGIC && 702 cgp->cg_niblk == sblock.fs_ipg && 703 cgp->cg_ndblk <= sblock.fs_fpg && 704 cgp->cg_initediblk <= sblock.fs_ipg))) { 705 return (1); 706 } 707 pfatal("CYLINDER GROUP %d: BAD MAGIC NUMBER", cg); 708 if (!reply("REBUILD CYLINDER GROUP")) { 709 printf("YOU WILL NEED TO RERUN FSCK.\n"); 710 rerun = 1; 711 return (1); 712 } 713 /* 714 * Zero out the cylinder group and then initialize critical fields. 715 * Bit maps and summaries will be recalculated by later passes. 716 */ 717 memset(cgp, 0, (size_t)sblock.fs_cgsize); 718 cgp->cg_magic = CG_MAGIC; 719 cgp->cg_cgx = cg; 720 cgp->cg_niblk = sblock.fs_ipg; 721 cgp->cg_initediblk = sblock.fs_ipg < 2 * INOPB(&sblock) ? 722 sblock.fs_ipg : 2 * INOPB(&sblock); 723 if (cgbase(&sblock, cg) + sblock.fs_fpg < sblock.fs_size) 724 cgp->cg_ndblk = sblock.fs_fpg; 725 else 726 cgp->cg_ndblk = sblock.fs_size - cgbase(&sblock, cg); 727 cgp->cg_iusedoff = &cgp->cg_space[0] - (u_char *)(&cgp->cg_firstfield); 728 if (sblock.fs_magic == FS_UFS1_MAGIC) { 729 cgp->cg_niblk = 0; 730 cgp->cg_initediblk = 0; 731 cgp->cg_old_ncyl = sblock.fs_old_cpg; 732 cgp->cg_old_niblk = sblock.fs_ipg; 733 cgp->cg_old_btotoff = cgp->cg_iusedoff; 734 cgp->cg_old_boff = cgp->cg_old_btotoff + 735 sblock.fs_old_cpg * sizeof(int32_t); 736 cgp->cg_iusedoff = cgp->cg_old_boff + 737 sblock.fs_old_cpg * sizeof(u_int16_t); 738 } 739 cgp->cg_freeoff = cgp->cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT); 740 cgp->cg_nextfreeoff = cgp->cg_freeoff + howmany(sblock.fs_fpg,CHAR_BIT); 741 if (sblock.fs_contigsumsize > 0) { 742 cgp->cg_nclusterblks = cgp->cg_ndblk / sblock.fs_frag; 743 cgp->cg_clustersumoff = 744 roundup(cgp->cg_nextfreeoff, sizeof(u_int32_t)); 745 cgp->cg_clustersumoff -= sizeof(u_int32_t); 746 cgp->cg_clusteroff = cgp->cg_clustersumoff + 747 (sblock.fs_contigsumsize + 1) * sizeof(u_int32_t); 748 cgp->cg_nextfreeoff = cgp->cg_clusteroff + 749 howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT); 750 } 751 dirty(cgbp); 752 return (0); 753 } 754 755 /* 756 * allocate a data block with the specified number of fragments 757 */ 758 ufs2_daddr_t 759 allocblk(long frags) 760 { 761 int i, j, k, cg, baseblk; 762 struct bufarea *cgbp; 763 struct cg *cgp; 764 765 if (frags <= 0 || frags > sblock.fs_frag) 766 return (0); 767 for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) { 768 for (j = 0; j <= sblock.fs_frag - frags; j++) { 769 if (testbmap(i + j)) 770 continue; 771 for (k = 1; k < frags; k++) 772 if (testbmap(i + j + k)) 773 break; 774 if (k < frags) { 775 j += k; 776 continue; 777 } 778 cg = dtog(&sblock, i + j); 779 cgbp = cgget(cg); 780 cgp = cgbp->b_un.b_cg; 781 if (!check_cgmagic(cg, cgbp)) 782 return (0); 783 baseblk = dtogd(&sblock, i + j); 784 for (k = 0; k < frags; k++) { 785 setbmap(i + j + k); 786 clrbit(cg_blksfree(cgp), baseblk + k); 787 } 788 n_blks += frags; 789 if (frags == sblock.fs_frag) 790 cgp->cg_cs.cs_nbfree--; 791 else 792 cgp->cg_cs.cs_nffree -= frags; 793 dirty(cgbp); 794 return (i + j); 795 } 796 } 797 return (0); 798 } 799 800 /* 801 * Free a previously allocated block 802 */ 803 void 804 freeblk(ufs2_daddr_t blkno, long frags) 805 { 806 struct inodesc idesc; 807 808 idesc.id_blkno = blkno; 809 idesc.id_numfrags = frags; 810 (void)pass4check(&idesc); 811 } 812 813 /* Slow down IO so as to leave some disk bandwidth for other processes */ 814 void 815 slowio_start() 816 { 817 818 /* Delay one in every 8 operations */ 819 slowio_pollcnt = (slowio_pollcnt + 1) & 7; 820 if (slowio_pollcnt == 0) { 821 gettimeofday(&slowio_starttime, NULL); 822 } 823 } 824 825 void 826 slowio_end() 827 { 828 struct timeval tv; 829 int delay_usec; 830 831 if (slowio_pollcnt != 0) 832 return; 833 834 /* Update the slowdown interval. */ 835 gettimeofday(&tv, NULL); 836 delay_usec = (tv.tv_sec - slowio_starttime.tv_sec) * 1000000 + 837 (tv.tv_usec - slowio_starttime.tv_usec); 838 if (delay_usec < 64) 839 delay_usec = 64; 840 if (delay_usec > 2500000) 841 delay_usec = 2500000; 842 slowio_delay_usec = (slowio_delay_usec * 63 + delay_usec) >> 6; 843 /* delay by 8 times the average IO delay */ 844 if (slowio_delay_usec > 64) 845 usleep(slowio_delay_usec * 8); 846 } 847 848 /* 849 * Find a pathname 850 */ 851 void 852 getpathname(char *namebuf, ino_t curdir, ino_t ino) 853 { 854 int len; 855 char *cp; 856 struct inodesc idesc; 857 static int busy = 0; 858 859 if (curdir == ino && ino == ROOTINO) { 860 (void)strcpy(namebuf, "/"); 861 return; 862 } 863 if (busy || !INO_IS_DVALID(curdir)) { 864 (void)strcpy(namebuf, "?"); 865 return; 866 } 867 busy = 1; 868 memset(&idesc, 0, sizeof(struct inodesc)); 869 idesc.id_type = DATA; 870 idesc.id_fix = IGNORE; 871 cp = &namebuf[MAXPATHLEN - 1]; 872 *cp = '\0'; 873 if (curdir != ino) { 874 idesc.id_parent = curdir; 875 goto namelookup; 876 } 877 while (ino != ROOTINO) { 878 idesc.id_number = ino; 879 idesc.id_func = findino; 880 idesc.id_name = strdup(".."); 881 if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) 882 break; 883 namelookup: 884 idesc.id_number = idesc.id_parent; 885 idesc.id_parent = ino; 886 idesc.id_func = findname; 887 idesc.id_name = namebuf; 888 if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0) 889 break; 890 len = strlen(namebuf); 891 cp -= len; 892 memmove(cp, namebuf, (size_t)len); 893 *--cp = '/'; 894 if (cp < &namebuf[MAXNAMLEN]) 895 break; 896 ino = idesc.id_number; 897 } 898 busy = 0; 899 if (ino != ROOTINO) 900 *--cp = '?'; 901 memmove(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp)); 902 } 903 904 void 905 catch(int sig __unused) 906 { 907 908 ckfini(0); 909 exit(12); 910 } 911 912 /* 913 * When preening, allow a single quit to signal 914 * a special exit after file system checks complete 915 * so that reboot sequence may be interrupted. 916 */ 917 void 918 catchquit(int sig __unused) 919 { 920 printf("returning to single-user after file system check\n"); 921 returntosingle = 1; 922 (void)signal(SIGQUIT, SIG_DFL); 923 } 924 925 /* 926 * determine whether an inode should be fixed. 927 */ 928 int 929 dofix(struct inodesc *idesc, const char *msg) 930 { 931 932 switch (idesc->id_fix) { 933 934 case DONTKNOW: 935 if (idesc->id_type == DATA) 936 direrror(idesc->id_number, msg); 937 else 938 pwarn("%s", msg); 939 if (preen) { 940 printf(" (SALVAGED)\n"); 941 idesc->id_fix = FIX; 942 return (ALTERED); 943 } 944 if (reply("SALVAGE") == 0) { 945 idesc->id_fix = NOFIX; 946 return (0); 947 } 948 idesc->id_fix = FIX; 949 return (ALTERED); 950 951 case FIX: 952 return (ALTERED); 953 954 case NOFIX: 955 case IGNORE: 956 return (0); 957 958 default: 959 errx(EEXIT, "UNKNOWN INODESC FIX MODE %d", idesc->id_fix); 960 } 961 /* NOTREACHED */ 962 return (0); 963 } 964 965 #include <stdarg.h> 966 967 /* 968 * An unexpected inconsistency occurred. 969 * Die if preening or file system is running with soft dependency protocol, 970 * otherwise just print message and continue. 971 */ 972 void 973 pfatal(const char *fmt, ...) 974 { 975 va_list ap; 976 va_start(ap, fmt); 977 if (!preen) { 978 (void)vfprintf(stdout, fmt, ap); 979 va_end(ap); 980 if (usedsoftdep) 981 (void)fprintf(stdout, 982 "\nUNEXPECTED SOFT UPDATE INCONSISTENCY\n"); 983 /* 984 * Force foreground fsck to clean up inconsistency. 985 */ 986 if (bkgrdflag) { 987 cmd.value = FS_NEEDSFSCK; 988 cmd.size = 1; 989 if (sysctlbyname("vfs.ffs.setflags", 0, 0, 990 &cmd, sizeof cmd) == -1) 991 pwarn("CANNOT SET FS_NEEDSFSCK FLAG\n"); 992 fprintf(stdout, "CANNOT RUN IN BACKGROUND\n"); 993 ckfini(0); 994 exit(EEXIT); 995 } 996 return; 997 } 998 if (cdevname == NULL) 999 cdevname = strdup("fsck"); 1000 (void)fprintf(stdout, "%s: ", cdevname); 1001 (void)vfprintf(stdout, fmt, ap); 1002 (void)fprintf(stdout, 1003 "\n%s: UNEXPECTED%sINCONSISTENCY; RUN fsck MANUALLY.\n", 1004 cdevname, usedsoftdep ? " SOFT UPDATE " : " "); 1005 /* 1006 * Force foreground fsck to clean up inconsistency. 1007 */ 1008 if (bkgrdflag) { 1009 cmd.value = FS_NEEDSFSCK; 1010 cmd.size = 1; 1011 if (sysctlbyname("vfs.ffs.setflags", 0, 0, 1012 &cmd, sizeof cmd) == -1) 1013 pwarn("CANNOT SET FS_NEEDSFSCK FLAG\n"); 1014 } 1015 ckfini(0); 1016 exit(EEXIT); 1017 } 1018 1019 /* 1020 * Pwarn just prints a message when not preening or running soft dependency 1021 * protocol, or a warning (preceded by filename) when preening. 1022 */ 1023 void 1024 pwarn(const char *fmt, ...) 1025 { 1026 va_list ap; 1027 va_start(ap, fmt); 1028 if (preen) 1029 (void)fprintf(stdout, "%s: ", cdevname); 1030 (void)vfprintf(stdout, fmt, ap); 1031 va_end(ap); 1032 } 1033 1034 /* 1035 * Stub for routines from kernel. 1036 */ 1037 void 1038 panic(const char *fmt, ...) 1039 { 1040 va_list ap; 1041 va_start(ap, fmt); 1042 pfatal("INTERNAL INCONSISTENCY:"); 1043 (void)vfprintf(stdout, fmt, ap); 1044 va_end(ap); 1045 exit(EEXIT); 1046 } 1047