fsutil.c revision 330897
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 * 4. 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 34static const char sccsid[] = "@(#)utilities.c 8.6 (Berkeley) 5/19/95"; 35#endif /* not lint */ 36#endif 37#include <sys/cdefs.h> 38__FBSDID("$FreeBSD: stable/11/sbin/fsck_ffs/fsutil.c 330897 2018-03-14 03:19:51Z eadler $"); 39 40#include <sys/param.h> 41#include <sys/time.h> 42#include <sys/types.h> 43#include <sys/sysctl.h> 44#include <sys/disk.h> 45#include <sys/disklabel.h> 46#include <sys/ioctl.h> 47#include <sys/stat.h> 48 49#include <ufs/ufs/dinode.h> 50#include <ufs/ufs/dir.h> 51#include <ufs/ffs/fs.h> 52 53#include <err.h> 54#include <errno.h> 55#include <string.h> 56#include <ctype.h> 57#include <fstab.h> 58#include <stdint.h> 59#include <stdio.h> 60#include <stdlib.h> 61#include <time.h> 62#include <unistd.h> 63 64#include "fsck.h" 65 66static void slowio_start(void); 67static void slowio_end(void); 68static void printIOstats(void); 69 70static long diskreads, totaldiskreads, totalreads; /* Disk cache statistics */ 71static struct timespec startpass, finishpass; 72struct timeval slowio_starttime; 73int slowio_delay_usec = 10000; /* Initial IO delay for background fsck */ 74int slowio_pollcnt; 75static struct bufarea cgblk; /* backup buffer for cylinder group blocks */ 76static TAILQ_HEAD(buflist, bufarea) bufhead; /* head of buffer cache list */ 77static int numbufs; /* size of buffer cache */ 78static char *buftype[BT_NUMBUFTYPES] = BT_NAMES; 79static struct bufarea *cgbufs; /* header for cylinder group cache */ 80static int flushtries; /* number of tries to reclaim memory */ 81 82void 83fsutilinit(void) 84{ 85 diskreads = totaldiskreads = totalreads = 0; 86 bzero(&startpass, sizeof(struct timespec)); 87 bzero(&finishpass, sizeof(struct timespec)); 88 bzero(&slowio_starttime, sizeof(struct timeval)); 89 slowio_delay_usec = 10000; 90 slowio_pollcnt = 0; 91 bzero(&cgblk, sizeof(struct bufarea)); 92 TAILQ_INIT(&bufhead); 93 numbufs = 0; 94 /* buftype ? */ 95 cgbufs = NULL; 96 flushtries = 0; 97} 98 99int 100ftypeok(union dinode *dp) 101{ 102 switch (DIP(dp, di_mode) & IFMT) { 103 104 case IFDIR: 105 case IFREG: 106 case IFBLK: 107 case IFCHR: 108 case IFLNK: 109 case IFSOCK: 110 case IFIFO: 111 return (1); 112 113 default: 114 if (debug) 115 printf("bad file type 0%o\n", DIP(dp, di_mode)); 116 return (0); 117 } 118} 119 120int 121reply(const char *question) 122{ 123 int persevere; 124 char c; 125 126 if (preen) 127 pfatal("INTERNAL ERROR: GOT TO reply()"); 128 persevere = !strcmp(question, "CONTINUE"); 129 printf("\n"); 130 if (!persevere && (nflag || (fswritefd < 0 && bkgrdflag == 0))) { 131 printf("%s? no\n\n", question); 132 resolved = 0; 133 return (0); 134 } 135 if (yflag || (persevere && nflag)) { 136 printf("%s? yes\n\n", question); 137 return (1); 138 } 139 do { 140 printf("%s? [yn] ", question); 141 (void) fflush(stdout); 142 c = getc(stdin); 143 while (c != '\n' && getc(stdin) != '\n') { 144 if (feof(stdin)) { 145 resolved = 0; 146 return (0); 147 } 148 } 149 } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); 150 printf("\n"); 151 if (c == 'y' || c == 'Y') 152 return (1); 153 resolved = 0; 154 return (0); 155} 156 157/* 158 * Look up state information for an inode. 159 */ 160struct inostat * 161inoinfo(ino_t inum) 162{ 163 static struct inostat unallocated = { USTATE, 0, 0 }; 164 struct inostatlist *ilp; 165 int iloff; 166 167 if (inum > maxino) 168 errx(EEXIT, "inoinfo: inumber %ju out of range", 169 (uintmax_t)inum); 170 ilp = &inostathead[inum / sblock.fs_ipg]; 171 iloff = inum % sblock.fs_ipg; 172 if (iloff >= ilp->il_numalloced) 173 return (&unallocated); 174 return (&ilp->il_stat[iloff]); 175} 176 177/* 178 * Malloc buffers and set up cache. 179 */ 180void 181bufinit(void) 182{ 183 struct bufarea *bp; 184 long bufcnt, i; 185 char *bufp; 186 187 pbp = pdirbp = (struct bufarea *)0; 188 bufp = Malloc((unsigned int)sblock.fs_bsize); 189 if (bufp == NULL) 190 errx(EEXIT, "cannot allocate buffer pool"); 191 cgblk.b_un.b_buf = bufp; 192 initbarea(&cgblk, BT_CYLGRP); 193 TAILQ_INIT(&bufhead); 194 bufcnt = MAXBUFS; 195 if (bufcnt < MINBUFS) 196 bufcnt = MINBUFS; 197 for (i = 0; i < bufcnt; i++) { 198 bp = (struct bufarea *)Malloc(sizeof(struct bufarea)); 199 bufp = Malloc((unsigned int)sblock.fs_bsize); 200 if (bp == NULL || bufp == NULL) { 201 if (i >= MINBUFS) 202 break; 203 errx(EEXIT, "cannot allocate buffer pool"); 204 } 205 bp->b_un.b_buf = bufp; 206 TAILQ_INSERT_HEAD(&bufhead, bp, b_list); 207 initbarea(bp, BT_UNKNOWN); 208 } 209 numbufs = i; /* save number of buffers */ 210 for (i = 0; i < BT_NUMBUFTYPES; i++) { 211 readtime[i].tv_sec = totalreadtime[i].tv_sec = 0; 212 readtime[i].tv_nsec = totalreadtime[i].tv_nsec = 0; 213 readcnt[i] = totalreadcnt[i] = 0; 214 } 215} 216 217/* 218 * Manage cylinder group buffers. 219 */ 220static struct bufarea *cgbufs; /* header for cylinder group cache */ 221static int flushtries; /* number of tries to reclaim memory */ 222 223struct bufarea * 224cgget(int cg) 225{ 226 struct bufarea *cgbp; 227 struct cg *cgp; 228 229 if (cgbufs == NULL) { 230 cgbufs = calloc(sblock.fs_ncg, sizeof(struct bufarea)); 231 if (cgbufs == NULL) 232 errx(EEXIT, "cannot allocate cylinder group buffers"); 233 } 234 cgbp = &cgbufs[cg]; 235 if (cgbp->b_un.b_cg != NULL) 236 return (cgbp); 237 cgp = NULL; 238 if (flushtries == 0) 239 cgp = malloc((unsigned int)sblock.fs_cgsize); 240 if (cgp == NULL) { 241 getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize); 242 return (&cgblk); 243 } 244 cgbp->b_un.b_cg = cgp; 245 initbarea(cgbp, BT_CYLGRP); 246 getblk(cgbp, cgtod(&sblock, cg), sblock.fs_cgsize); 247 return (cgbp); 248} 249 250/* 251 * Attempt to flush a cylinder group cache entry. 252 * Return whether the flush was successful. 253 */ 254int 255flushentry(void) 256{ 257 struct bufarea *cgbp; 258 259 if (flushtries == sblock.fs_ncg || cgbufs == NULL) 260 return (0); 261 cgbp = &cgbufs[flushtries++]; 262 if (cgbp->b_un.b_cg == NULL) 263 return (0); 264 flush(fswritefd, cgbp); 265 free(cgbp->b_un.b_buf); 266 cgbp->b_un.b_buf = NULL; 267 return (1); 268} 269 270/* 271 * Manage a cache of directory blocks. 272 */ 273struct bufarea * 274getdatablk(ufs2_daddr_t blkno, long size, int type) 275{ 276 struct bufarea *bp; 277 278 TAILQ_FOREACH(bp, &bufhead, b_list) 279 if (bp->b_bno == fsbtodb(&sblock, blkno)) 280 goto foundit; 281 TAILQ_FOREACH_REVERSE(bp, &bufhead, buflist, b_list) 282 if ((bp->b_flags & B_INUSE) == 0) 283 break; 284 if (bp == NULL) 285 errx(EEXIT, "deadlocked buffer pool"); 286 bp->b_type = type; 287 getblk(bp, blkno, size); 288 /* fall through */ 289foundit: 290 if (debug && bp->b_type != type) 291 printf("Buffer type changed from %s to %s\n", 292 buftype[bp->b_type], buftype[type]); 293 TAILQ_REMOVE(&bufhead, bp, b_list); 294 TAILQ_INSERT_HEAD(&bufhead, bp, b_list); 295 bp->b_flags |= B_INUSE; 296 return (bp); 297} 298 299/* 300 * Timespec operations (from <sys/time.h>). 301 */ 302#define timespecsub(vvp, uvp) \ 303 do { \ 304 (vvp)->tv_sec -= (uvp)->tv_sec; \ 305 (vvp)->tv_nsec -= (uvp)->tv_nsec; \ 306 if ((vvp)->tv_nsec < 0) { \ 307 (vvp)->tv_sec--; \ 308 (vvp)->tv_nsec += 1000000000; \ 309 } \ 310 } while (0) 311#define timespecadd(vvp, uvp) \ 312 do { \ 313 (vvp)->tv_sec += (uvp)->tv_sec; \ 314 (vvp)->tv_nsec += (uvp)->tv_nsec; \ 315 if ((vvp)->tv_nsec >= 1000000000) { \ 316 (vvp)->tv_sec++; \ 317 (vvp)->tv_nsec -= 1000000000; \ 318 } \ 319 } while (0) 320 321void 322getblk(struct bufarea *bp, ufs2_daddr_t blk, long size) 323{ 324 ufs2_daddr_t dblk; 325 struct timespec start, finish; 326 327 dblk = fsbtodb(&sblock, blk); 328 if (bp->b_bno == dblk) { 329 totalreads++; 330 } else { 331 flush(fswritefd, bp); 332 if (debug) { 333 readcnt[bp->b_type]++; 334 clock_gettime(CLOCK_REALTIME_PRECISE, &start); 335 } 336 bp->b_errs = blread(fsreadfd, bp->b_un.b_buf, dblk, size); 337 if (debug) { 338 clock_gettime(CLOCK_REALTIME_PRECISE, &finish); 339 timespecsub(&finish, &start); 340 timespecadd(&readtime[bp->b_type], &finish); 341 } 342 bp->b_bno = dblk; 343 bp->b_size = size; 344 } 345} 346 347void 348flush(int fd, struct bufarea *bp) 349{ 350 int i, j; 351 352 if (!bp->b_dirty) 353 return; 354 bp->b_dirty = 0; 355 if (fswritefd < 0) { 356 pfatal("WRITING IN READ_ONLY MODE.\n"); 357 return; 358 } 359 if (bp->b_errs != 0) 360 pfatal("WRITING %sZERO'ED BLOCK %lld TO DISK\n", 361 (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", 362 (long long)bp->b_bno); 363 bp->b_errs = 0; 364 blwrite(fd, bp->b_un.b_buf, bp->b_bno, bp->b_size); 365 if (bp != &sblk) 366 return; 367 for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 368 blwrite(fswritefd, (char *)sblock.fs_csp + i, 369 fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 370 MIN(sblock.fs_cssize - i, sblock.fs_bsize)); 371 } 372} 373 374void 375rwerror(const char *mesg, ufs2_daddr_t blk) 376{ 377 378 if (bkgrdcheck) 379 exit(EEXIT); 380 if (preen == 0) 381 printf("\n"); 382 pfatal("CANNOT %s: %ld", mesg, (long)blk); 383 if (reply("CONTINUE") == 0) 384 exit(EEXIT); 385} 386 387void 388ckfini(int markclean) 389{ 390 struct bufarea *bp, *nbp; 391 int ofsmodified, cnt; 392 393 if (bkgrdflag) { 394 unlink(snapname); 395 if ((!(sblock.fs_flags & FS_UNCLEAN)) != markclean) { 396 cmd.value = FS_UNCLEAN; 397 cmd.size = markclean ? -1 : 1; 398 if (sysctlbyname("vfs.ffs.setflags", 0, 0, 399 &cmd, sizeof cmd) == -1) 400 rwerror("SET FILE SYSTEM FLAGS", FS_UNCLEAN); 401 if (!preen) { 402 printf("\n***** FILE SYSTEM MARKED %s *****\n", 403 markclean ? "CLEAN" : "DIRTY"); 404 if (!markclean) 405 rerun = 1; 406 } 407 } else if (!preen && !markclean) { 408 printf("\n***** FILE SYSTEM STILL DIRTY *****\n"); 409 rerun = 1; 410 } 411 } 412 if (debug && totalreads > 0) 413 printf("cache with %d buffers missed %ld of %ld (%d%%)\n", 414 numbufs, totaldiskreads, totalreads, 415 (int)(totaldiskreads * 100 / totalreads)); 416 if (fswritefd < 0) { 417 (void)close(fsreadfd); 418 return; 419 } 420 flush(fswritefd, &sblk); 421 if (havesb && cursnapshot == 0 && sblock.fs_magic == FS_UFS2_MAGIC && 422 sblk.b_bno != sblock.fs_sblockloc / dev_bsize && 423 !preen && reply("UPDATE STANDARD SUPERBLOCK")) { 424 sblk.b_bno = sblock.fs_sblockloc / dev_bsize; 425 sbdirty(); 426 flush(fswritefd, &sblk); 427 } 428 flush(fswritefd, &cgblk); 429 free(cgblk.b_un.b_buf); 430 cnt = 0; 431 TAILQ_FOREACH_REVERSE_SAFE(bp, &bufhead, buflist, b_list, nbp) { 432 TAILQ_REMOVE(&bufhead, bp, b_list); 433 cnt++; 434 flush(fswritefd, bp); 435 free(bp->b_un.b_buf); 436 free((char *)bp); 437 } 438 if (numbufs != cnt) 439 errx(EEXIT, "panic: lost %d buffers", numbufs - cnt); 440 if (cgbufs != NULL) { 441 for (cnt = 0; cnt < sblock.fs_ncg; cnt++) { 442 if (cgbufs[cnt].b_un.b_cg == NULL) 443 continue; 444 flush(fswritefd, &cgbufs[cnt]); 445 free(cgbufs[cnt].b_un.b_cg); 446 } 447 free(cgbufs); 448 } 449 pbp = pdirbp = (struct bufarea *)0; 450 if (cursnapshot == 0 && sblock.fs_clean != markclean) { 451 if ((sblock.fs_clean = markclean) != 0) { 452 sblock.fs_flags &= ~(FS_UNCLEAN | FS_NEEDSFSCK); 453 sblock.fs_pendingblocks = 0; 454 sblock.fs_pendinginodes = 0; 455 } 456 sbdirty(); 457 ofsmodified = fsmodified; 458 flush(fswritefd, &sblk); 459 fsmodified = ofsmodified; 460 if (!preen) { 461 printf("\n***** FILE SYSTEM MARKED %s *****\n", 462 markclean ? "CLEAN" : "DIRTY"); 463 if (!markclean) 464 rerun = 1; 465 } 466 } else if (!preen) { 467 if (markclean) { 468 printf("\n***** FILE SYSTEM IS CLEAN *****\n"); 469 } else { 470 printf("\n***** FILE SYSTEM STILL DIRTY *****\n"); 471 rerun = 1; 472 } 473 } 474 (void)close(fsreadfd); 475 (void)close(fswritefd); 476} 477 478/* 479 * Print out I/O statistics. 480 */ 481void 482IOstats(char *what) 483{ 484 int i; 485 486 if (debug == 0) 487 return; 488 if (diskreads == 0) { 489 printf("%s: no I/O\n\n", what); 490 return; 491 } 492 if (startpass.tv_sec == 0) 493 startpass = startprog; 494 printf("%s: I/O statistics\n", what); 495 printIOstats(); 496 totaldiskreads += diskreads; 497 diskreads = 0; 498 for (i = 0; i < BT_NUMBUFTYPES; i++) { 499 timespecadd(&totalreadtime[i], &readtime[i]); 500 totalreadcnt[i] += readcnt[i]; 501 readtime[i].tv_sec = readtime[i].tv_nsec = 0; 502 readcnt[i] = 0; 503 } 504 clock_gettime(CLOCK_REALTIME_PRECISE, &startpass); 505} 506 507void 508finalIOstats(void) 509{ 510 int i; 511 512 if (debug == 0) 513 return; 514 printf("Final I/O statistics\n"); 515 totaldiskreads += diskreads; 516 diskreads = totaldiskreads; 517 startpass = startprog; 518 for (i = 0; i < BT_NUMBUFTYPES; i++) { 519 timespecadd(&totalreadtime[i], &readtime[i]); 520 totalreadcnt[i] += readcnt[i]; 521 readtime[i] = totalreadtime[i]; 522 readcnt[i] = totalreadcnt[i]; 523 } 524 printIOstats(); 525} 526 527static void printIOstats(void) 528{ 529 long long msec, totalmsec; 530 int i; 531 532 clock_gettime(CLOCK_REALTIME_PRECISE, &finishpass); 533 timespecsub(&finishpass, &startpass); 534 printf("Running time: %jd.%03ld sec\n", 535 (intmax_t)finishpass.tv_sec, finishpass.tv_nsec / 1000000); 536 printf("buffer reads by type:\n"); 537 for (totalmsec = 0, i = 0; i < BT_NUMBUFTYPES; i++) 538 totalmsec += readtime[i].tv_sec * 1000 + 539 readtime[i].tv_nsec / 1000000; 540 if (totalmsec == 0) 541 totalmsec = 1; 542 for (i = 0; i < BT_NUMBUFTYPES; i++) { 543 if (readcnt[i] == 0) 544 continue; 545 msec = 546 readtime[i].tv_sec * 1000 + readtime[i].tv_nsec / 1000000; 547 printf("%21s:%8ld %2ld.%ld%% %4jd.%03ld sec %2lld.%lld%%\n", 548 buftype[i], readcnt[i], readcnt[i] * 100 / diskreads, 549 (readcnt[i] * 1000 / diskreads) % 10, 550 (intmax_t)readtime[i].tv_sec, readtime[i].tv_nsec / 1000000, 551 msec * 100 / totalmsec, (msec * 1000 / totalmsec) % 10); 552 } 553 printf("\n"); 554} 555 556int 557blread(int fd, char *buf, ufs2_daddr_t blk, long size) 558{ 559 char *cp; 560 int i, errs; 561 off_t offset; 562 563 offset = blk; 564 offset *= dev_bsize; 565 if (bkgrdflag) 566 slowio_start(); 567 totalreads++; 568 diskreads++; 569 if (lseek(fd, offset, 0) < 0) 570 rwerror("SEEK BLK", blk); 571 else if (read(fd, buf, (int)size) == size) { 572 if (bkgrdflag) 573 slowio_end(); 574 return (0); 575 } 576 577 /* 578 * This is handled specially here instead of in rwerror because 579 * rwerror is used for all sorts of errors, not just true read/write 580 * errors. It should be refactored and fixed. 581 */ 582 if (surrender) { 583 pfatal("CANNOT READ_BLK: %ld", (long)blk); 584 errx(EEXIT, "ABORTING DUE TO READ ERRORS"); 585 } else 586 rwerror("READ BLK", blk); 587 588 if (lseek(fd, offset, 0) < 0) 589 rwerror("SEEK BLK", blk); 590 errs = 0; 591 memset(buf, 0, (size_t)size); 592 printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); 593 for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { 594 if (read(fd, cp, (int)secsize) != secsize) { 595 (void)lseek(fd, offset + i + secsize, 0); 596 if (secsize != dev_bsize && dev_bsize != 1) 597 printf(" %jd (%jd),", 598 (intmax_t)(blk * dev_bsize + i) / secsize, 599 (intmax_t)blk + i / dev_bsize); 600 else 601 printf(" %jd,", (intmax_t)blk + i / dev_bsize); 602 errs++; 603 } 604 } 605 printf("\n"); 606 if (errs) 607 resolved = 0; 608 return (errs); 609} 610 611void 612blwrite(int fd, char *buf, ufs2_daddr_t blk, ssize_t size) 613{ 614 int i; 615 char *cp; 616 off_t offset; 617 618 if (fd < 0) 619 return; 620 offset = blk; 621 offset *= dev_bsize; 622 if (lseek(fd, offset, 0) < 0) 623 rwerror("SEEK BLK", blk); 624 else if (write(fd, buf, size) == size) { 625 fsmodified = 1; 626 return; 627 } 628 resolved = 0; 629 rwerror("WRITE BLK", blk); 630 if (lseek(fd, offset, 0) < 0) 631 rwerror("SEEK BLK", blk); 632 printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 633 for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) 634 if (write(fd, cp, dev_bsize) != dev_bsize) { 635 (void)lseek(fd, offset + i + dev_bsize, 0); 636 printf(" %jd,", (intmax_t)blk + i / dev_bsize); 637 } 638 printf("\n"); 639 return; 640} 641 642void 643blerase(int fd, ufs2_daddr_t blk, long size) 644{ 645 off_t ioarg[2]; 646 647 if (fd < 0) 648 return; 649 ioarg[0] = blk * dev_bsize; 650 ioarg[1] = size; 651 ioctl(fd, DIOCGDELETE, ioarg); 652 /* we don't really care if we succeed or not */ 653 return; 654} 655 656/* 657 * Fill a contiguous region with all-zeroes. Note ZEROBUFSIZE is by 658 * definition a multiple of dev_bsize. 659 */ 660void 661blzero(int fd, ufs2_daddr_t blk, long size) 662{ 663 static char *zero; 664 off_t offset, len; 665 666 if (fd < 0) 667 return; 668 if (zero == NULL) { 669 zero = calloc(ZEROBUFSIZE, 1); 670 if (zero == NULL) 671 errx(EEXIT, "cannot allocate buffer pool"); 672 } 673 offset = blk * dev_bsize; 674 if (lseek(fd, offset, 0) < 0) 675 rwerror("SEEK BLK", blk); 676 while (size > 0) { 677 len = MIN(ZEROBUFSIZE, size); 678 if (write(fd, zero, len) != len) 679 rwerror("WRITE BLK", blk); 680 blk += len / dev_bsize; 681 size -= len; 682 } 683} 684 685/* 686 * Verify cylinder group's magic number and other parameters. If the 687 * test fails, offer an option to rebuild the whole cylinder group. 688 */ 689int 690check_cgmagic(int cg, struct bufarea *cgbp) 691{ 692 struct cg *cgp = cgbp->b_un.b_cg; 693 694 /* 695 * Extended cylinder group checks. 696 */ 697 if (cg_chkmagic(cgp) && 698 ((sblock.fs_magic == FS_UFS1_MAGIC && 699 cgp->cg_old_niblk == sblock.fs_ipg && 700 cgp->cg_ndblk <= sblock.fs_fpg && 701 cgp->cg_old_ncyl <= sblock.fs_old_cpg) || 702 (sblock.fs_magic == FS_UFS2_MAGIC && 703 cgp->cg_niblk == sblock.fs_ipg && 704 cgp->cg_ndblk <= sblock.fs_fpg && 705 cgp->cg_initediblk <= sblock.fs_ipg))) { 706 return (1); 707 } 708 pfatal("CYLINDER GROUP %d: BAD MAGIC NUMBER", cg); 709 if (!reply("REBUILD CYLINDER GROUP")) { 710 printf("YOU WILL NEED TO RERUN FSCK.\n"); 711 rerun = 1; 712 return (1); 713 } 714 /* 715 * Zero out the cylinder group and then initialize critical fields. 716 * Bit maps and summaries will be recalculated by later passes. 717 */ 718 memset(cgp, 0, (size_t)sblock.fs_cgsize); 719 cgp->cg_magic = CG_MAGIC; 720 cgp->cg_cgx = cg; 721 cgp->cg_niblk = sblock.fs_ipg; 722 cgp->cg_initediblk = MIN(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 */ 758ufs2_daddr_t 759allocblk(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 */ 803void 804freeblk(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 */ 814void 815slowio_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 825void 826slowio_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 */ 851void 852getpathname(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 904void 905catch(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 */ 917void 918catchquit(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 */ 928int 929dofix(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 */ 972void 973pfatal(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 */ 1023void 1024pwarn(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 */ 1037void 1038panic(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