18a16b7a1SPedro F. Giffuni /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 44336716bSAdrian Chadd * Copyright (c) 1980, 1986, 1993 54336716bSAdrian Chadd * The Regents of the University of California. All rights reserved. 64336716bSAdrian Chadd * 74336716bSAdrian Chadd * Redistribution and use in source and binary forms, with or without 84336716bSAdrian Chadd * modification, are permitted provided that the following conditions 94336716bSAdrian Chadd * are met: 104336716bSAdrian Chadd * 1. Redistributions of source code must retain the above copyright 114336716bSAdrian Chadd * notice, this list of conditions and the following disclaimer. 124336716bSAdrian Chadd * 2. Redistributions in binary form must reproduce the above copyright 134336716bSAdrian Chadd * notice, this list of conditions and the following disclaimer in the 144336716bSAdrian Chadd * documentation and/or other materials provided with the distribution. 15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 164336716bSAdrian Chadd * may be used to endorse or promote products derived from this software 174336716bSAdrian Chadd * without specific prior written permission. 184336716bSAdrian Chadd * 194336716bSAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 204336716bSAdrian Chadd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 214336716bSAdrian Chadd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 224336716bSAdrian Chadd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 234336716bSAdrian Chadd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 244336716bSAdrian Chadd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 254336716bSAdrian Chadd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 264336716bSAdrian Chadd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 274336716bSAdrian Chadd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 284336716bSAdrian Chadd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 294336716bSAdrian Chadd * SUCH DAMAGE. 304336716bSAdrian Chadd */ 314336716bSAdrian Chadd 324336716bSAdrian Chadd #if 0 33c69284caSDavid E. O'Brien #ifndef lint 344336716bSAdrian Chadd static const char sccsid[] = "@(#)utilities.c 8.6 (Berkeley) 5/19/95"; 354336716bSAdrian Chadd #endif /* not lint */ 36c69284caSDavid E. O'Brien #endif 37c69284caSDavid E. O'Brien #include <sys/cdefs.h> 384336716bSAdrian Chadd #include <sys/param.h> 399d580d7cSIan Dowse #include <sys/time.h> 404336716bSAdrian Chadd #include <sys/types.h> 41bf58d635SIan Dowse #include <sys/sysctl.h> 428d3dfc26SDag-Erling Smørgrav #include <sys/disk.h> 431c85e6a3SKirk McKusick #include <sys/disklabel.h> 448d3dfc26SDag-Erling Smørgrav #include <sys/ioctl.h> 454336716bSAdrian Chadd #include <sys/stat.h> 464336716bSAdrian Chadd 474336716bSAdrian Chadd #include <ufs/ufs/dinode.h> 484336716bSAdrian Chadd #include <ufs/ufs/dir.h> 494336716bSAdrian Chadd #include <ufs/ffs/fs.h> 504336716bSAdrian Chadd 514336716bSAdrian Chadd #include <err.h> 524336716bSAdrian Chadd #include <errno.h> 534336716bSAdrian Chadd #include <string.h> 544336716bSAdrian Chadd #include <ctype.h> 554336716bSAdrian Chadd #include <fstab.h> 5684fc0d7eSMaxime Henrion #include <stdint.h> 574336716bSAdrian Chadd #include <stdio.h> 584336716bSAdrian Chadd #include <stdlib.h> 59ed75b5a1SKirk McKusick #include <time.h> 604336716bSAdrian Chadd #include <unistd.h> 614336716bSAdrian Chadd 624336716bSAdrian Chadd #include "fsck.h" 634336716bSAdrian Chadd 645cc52631SKirk McKusick int sujrecovery = 0; 655cc52631SKirk McKusick 665cc52631SKirk McKusick static struct bufarea *allocbuf(const char *); 675cc52631SKirk McKusick static void cg_write(struct bufarea *); 689d580d7cSIan Dowse static void slowio_start(void); 699d580d7cSIan Dowse static void slowio_end(void); 70ed75b5a1SKirk McKusick static void printIOstats(void); 719d580d7cSIan Dowse 72ed75b5a1SKirk McKusick static long diskreads, totaldiskreads, totalreads; /* Disk cache statistics */ 73ed75b5a1SKirk McKusick static struct timespec startpass, finishpass; 749d580d7cSIan Dowse struct timeval slowio_starttime; 759d580d7cSIan Dowse int slowio_delay_usec = 10000; /* Initial IO delay for background fsck */ 769d580d7cSIan Dowse int slowio_pollcnt; 7781fbded2SKirk McKusick static struct bufarea cgblk; /* backup buffer for cylinder group blocks */ 78460ed610SKirk McKusick static struct bufarea failedbuf; /* returned by failed getdatablk() */ 795cc52631SKirk McKusick static TAILQ_HEAD(bufqueue, bufarea) bufqueuehd; /* head of buffer cache LRU */ 805cc52631SKirk McKusick static LIST_HEAD(bufhash, bufarea) bufhashhd[HASHSIZE]; /* buffer hash list */ 81460ed610SKirk McKusick static struct bufhash freebufs; /* unused buffers */ 822ec5c914SKirk McKusick static int numbufs; /* size of buffer cache */ 835cc52631SKirk McKusick static int cachelookups; /* number of cache lookups */ 845cc52631SKirk McKusick static int cachereads; /* number of cache reads */ 857703a6ffSScott Long static int flushtries; /* number of tries to reclaim memory */ 867703a6ffSScott Long 875cc52631SKirk McKusick char *buftype[BT_NUMBUFTYPES] = BT_NAMES; 885cc52631SKirk McKusick 897703a6ffSScott Long void 907703a6ffSScott Long fsutilinit(void) 917703a6ffSScott Long { 927703a6ffSScott Long diskreads = totaldiskreads = totalreads = 0; 937703a6ffSScott Long bzero(&startpass, sizeof(struct timespec)); 947703a6ffSScott Long bzero(&finishpass, sizeof(struct timespec)); 957703a6ffSScott Long bzero(&slowio_starttime, sizeof(struct timeval)); 967703a6ffSScott Long slowio_delay_usec = 10000; 977703a6ffSScott Long slowio_pollcnt = 0; 987703a6ffSScott Long flushtries = 0; 997703a6ffSScott Long } 1004336716bSAdrian Chadd 1014336716bSAdrian Chadd int 1021c85e6a3SKirk McKusick ftypeok(union dinode *dp) 1034336716bSAdrian Chadd { 104d8ba45e2SEd Maste switch (DIP(dp, di_mode) & IFMT) { 1054336716bSAdrian Chadd 106d8ba45e2SEd Maste case IFDIR: 107d8ba45e2SEd Maste case IFREG: 108d8ba45e2SEd Maste case IFBLK: 109d8ba45e2SEd Maste case IFCHR: 110d8ba45e2SEd Maste case IFLNK: 111d8ba45e2SEd Maste case IFSOCK: 112d8ba45e2SEd Maste case IFIFO: 1134336716bSAdrian Chadd return (1); 1144336716bSAdrian Chadd 1154336716bSAdrian Chadd default: 1164336716bSAdrian Chadd if (debug) 1171c85e6a3SKirk McKusick printf("bad file type 0%o\n", DIP(dp, di_mode)); 1184336716bSAdrian Chadd return (0); 1194336716bSAdrian Chadd } 1204336716bSAdrian Chadd } 1214336716bSAdrian Chadd 1224336716bSAdrian Chadd int 123599304a4SPoul-Henning Kamp reply(const char *question) 1244336716bSAdrian Chadd { 1254336716bSAdrian Chadd int persevere; 1264336716bSAdrian Chadd char c; 1274336716bSAdrian Chadd 1284336716bSAdrian Chadd if (preen) 1294336716bSAdrian Chadd pfatal("INTERNAL ERROR: GOT TO reply()"); 1307c332e97SKirk McKusick persevere = strcmp(question, "CONTINUE") == 0 || 1317c332e97SKirk McKusick strcmp(question, "LOOK FOR ALTERNATE SUPERBLOCKS") == 0; 1324336716bSAdrian Chadd printf("\n"); 1337578c6abSKirk McKusick if (!persevere && (nflag || (fswritefd < 0 && bkgrdflag == 0))) { 1344336716bSAdrian Chadd printf("%s? no\n\n", question); 1354336716bSAdrian Chadd resolved = 0; 1364336716bSAdrian Chadd return (0); 1374336716bSAdrian Chadd } 1384336716bSAdrian Chadd if (yflag || (persevere && nflag)) { 1394336716bSAdrian Chadd printf("%s? yes\n\n", question); 1404336716bSAdrian Chadd return (1); 1414336716bSAdrian Chadd } 1424336716bSAdrian Chadd do { 1434336716bSAdrian Chadd printf("%s? [yn] ", question); 1444336716bSAdrian Chadd (void) fflush(stdout); 1454336716bSAdrian Chadd c = getc(stdin); 1464336716bSAdrian Chadd while (c != '\n' && getc(stdin) != '\n') { 1474336716bSAdrian Chadd if (feof(stdin)) { 1484336716bSAdrian Chadd resolved = 0; 1494336716bSAdrian Chadd return (0); 1504336716bSAdrian Chadd } 1514336716bSAdrian Chadd } 1524336716bSAdrian Chadd } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); 1534336716bSAdrian Chadd printf("\n"); 1544336716bSAdrian Chadd if (c == 'y' || c == 'Y') 1554336716bSAdrian Chadd return (1); 1564336716bSAdrian Chadd resolved = 0; 1574336716bSAdrian Chadd return (0); 1584336716bSAdrian Chadd } 1594336716bSAdrian Chadd 1604336716bSAdrian Chadd /* 1614336716bSAdrian Chadd * Look up state information for an inode. 1624336716bSAdrian Chadd */ 1634336716bSAdrian Chadd struct inostat * 164b70cd7eeSWarner Losh inoinfo(ino_t inum) 1654336716bSAdrian Chadd { 16652f97104SKirk McKusick static struct inostat unallocated = { USTATE, 0, 0, 0 }; 1674336716bSAdrian Chadd struct inostatlist *ilp; 1684336716bSAdrian Chadd int iloff; 1694336716bSAdrian Chadd 17011ce203eSKirk McKusick if (inum >= maxino) 171623d7cb6SMatthew D Fleming errx(EEXIT, "inoinfo: inumber %ju out of range", 172623d7cb6SMatthew D Fleming (uintmax_t)inum); 1734336716bSAdrian Chadd ilp = &inostathead[inum / sblock.fs_ipg]; 1744336716bSAdrian Chadd iloff = inum % sblock.fs_ipg; 1754336716bSAdrian Chadd if (iloff >= ilp->il_numalloced) 1764336716bSAdrian Chadd return (&unallocated); 1774336716bSAdrian Chadd return (&ilp->il_stat[iloff]); 1784336716bSAdrian Chadd } 1794336716bSAdrian Chadd 1804336716bSAdrian Chadd /* 1814336716bSAdrian Chadd * Malloc buffers and set up cache. 1824336716bSAdrian Chadd */ 1834336716bSAdrian Chadd void 184b70cd7eeSWarner Losh bufinit(void) 1854336716bSAdrian Chadd { 1865cc52631SKirk McKusick int i; 1874336716bSAdrian Chadd 188460ed610SKirk McKusick initbarea(&failedbuf, BT_UNKNOWN); 189460ed610SKirk McKusick failedbuf.b_errs = -1; 190460ed610SKirk McKusick failedbuf.b_un.b_buf = NULL; 191*772430ddSKirk McKusick if ((cgblk.b_un.b_buf = Balloc((unsigned int)sblock.fs_bsize)) == NULL) 1925cc52631SKirk McKusick errx(EEXIT, "Initial malloc(%d) failed", sblock.fs_bsize); 193ed75b5a1SKirk McKusick initbarea(&cgblk, BT_CYLGRP); 1945cc52631SKirk McKusick numbufs = cachelookups = cachereads = 0; 1955cc52631SKirk McKusick TAILQ_INIT(&bufqueuehd); 196460ed610SKirk McKusick LIST_INIT(&freebufs); 1975cc52631SKirk McKusick for (i = 0; i < HASHSIZE; i++) 1985cc52631SKirk McKusick LIST_INIT(&bufhashhd[i]); 199ed75b5a1SKirk McKusick for (i = 0; i < BT_NUMBUFTYPES; i++) { 200ed75b5a1SKirk McKusick readtime[i].tv_sec = totalreadtime[i].tv_sec = 0; 201ed75b5a1SKirk McKusick readtime[i].tv_nsec = totalreadtime[i].tv_nsec = 0; 202ed75b5a1SKirk McKusick readcnt[i] = totalreadcnt[i] = 0; 203ed75b5a1SKirk McKusick } 2044336716bSAdrian Chadd } 2054336716bSAdrian Chadd 2065cc52631SKirk McKusick static struct bufarea * 2075cc52631SKirk McKusick allocbuf(const char *failreason) 2085cc52631SKirk McKusick { 2095cc52631SKirk McKusick struct bufarea *bp; 2105cc52631SKirk McKusick char *bufp; 2115cc52631SKirk McKusick 2125cc52631SKirk McKusick bp = (struct bufarea *)Malloc(sizeof(struct bufarea)); 213*772430ddSKirk McKusick bufp = Balloc((unsigned int)sblock.fs_bsize); 2145cc52631SKirk McKusick if (bp == NULL || bufp == NULL) { 2155cc52631SKirk McKusick errx(EEXIT, "%s", failreason); 2165cc52631SKirk McKusick /* NOTREACHED */ 2175cc52631SKirk McKusick } 2185cc52631SKirk McKusick numbufs++; 2195cc52631SKirk McKusick bp->b_un.b_buf = bufp; 2205cc52631SKirk McKusick TAILQ_INSERT_HEAD(&bufqueuehd, bp, b_list); 2215cc52631SKirk McKusick initbarea(bp, BT_UNKNOWN); 2225cc52631SKirk McKusick return (bp); 2235cc52631SKirk McKusick } 2245cc52631SKirk McKusick 2254336716bSAdrian Chadd /* 22681fbded2SKirk McKusick * Manage cylinder group buffers. 22785ee267aSKirk McKusick * 22885ee267aSKirk McKusick * Use getblk() here rather than cgget() because the cylinder group 22985ee267aSKirk McKusick * may be corrupted but we want it anyway so we can fix it. 23081fbded2SKirk McKusick */ 23181fbded2SKirk McKusick static struct bufarea *cgbufs; /* header for cylinder group cache */ 23281fbded2SKirk McKusick static int flushtries; /* number of tries to reclaim memory */ 23381fbded2SKirk McKusick 23481fbded2SKirk McKusick struct bufarea * 235957fc241SKirk McKusick cglookup(int cg) 23681fbded2SKirk McKusick { 23781fbded2SKirk McKusick struct bufarea *cgbp; 23881fbded2SKirk McKusick struct cg *cgp; 23981fbded2SKirk McKusick 2405cc52631SKirk McKusick if ((unsigned) cg >= sblock.fs_ncg) 2415cc52631SKirk McKusick errx(EEXIT, "cglookup: out of range cylinder group %d", cg); 24281fbded2SKirk McKusick if (cgbufs == NULL) { 243*772430ddSKirk McKusick cgbufs = Calloc(sblock.fs_ncg, sizeof(struct bufarea)); 24481fbded2SKirk McKusick if (cgbufs == NULL) 2455cc52631SKirk McKusick errx(EEXIT, "Cannot allocate cylinder group buffers"); 24681fbded2SKirk McKusick } 24781fbded2SKirk McKusick cgbp = &cgbufs[cg]; 24881fbded2SKirk McKusick if (cgbp->b_un.b_cg != NULL) 24981fbded2SKirk McKusick return (cgbp); 25081fbded2SKirk McKusick cgp = NULL; 25181fbded2SKirk McKusick if (flushtries == 0) 252*772430ddSKirk McKusick cgp = Balloc((unsigned int)sblock.fs_cgsize); 25381fbded2SKirk McKusick if (cgp == NULL) { 2545cc52631SKirk McKusick if (sujrecovery) 2555cc52631SKirk McKusick errx(EEXIT,"Ran out of memory during journal recovery"); 256c0bfa109SKirk McKusick flush(fswritefd, &cgblk); 25781fbded2SKirk McKusick getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize); 25881fbded2SKirk McKusick return (&cgblk); 25981fbded2SKirk McKusick } 26081fbded2SKirk McKusick cgbp->b_un.b_cg = cgp; 26181fbded2SKirk McKusick initbarea(cgbp, BT_CYLGRP); 26281fbded2SKirk McKusick getblk(cgbp, cgtod(&sblock, cg), sblock.fs_cgsize); 26381fbded2SKirk McKusick return (cgbp); 26481fbded2SKirk McKusick } 26581fbded2SKirk McKusick 26681fbded2SKirk McKusick /* 2678ebae128SKirk McKusick * Mark a cylinder group buffer as dirty. 2688ebae128SKirk McKusick * Update its check-hash if they are enabled. 2698ebae128SKirk McKusick */ 2708ebae128SKirk McKusick void 2718ebae128SKirk McKusick cgdirty(struct bufarea *cgbp) 2728ebae128SKirk McKusick { 2738ebae128SKirk McKusick struct cg *cg; 2748ebae128SKirk McKusick 2758ebae128SKirk McKusick cg = cgbp->b_un.b_cg; 2768ebae128SKirk McKusick if ((sblock.fs_metackhash & CK_CYLGRP) != 0) { 2778ebae128SKirk McKusick cg->cg_ckhash = 0; 2788ebae128SKirk McKusick cg->cg_ckhash = 2798ebae128SKirk McKusick calculate_crc32c(~0L, (void *)cg, sblock.fs_cgsize); 2808ebae128SKirk McKusick } 2818ebae128SKirk McKusick dirty(cgbp); 2828ebae128SKirk McKusick } 2838ebae128SKirk McKusick 2848ebae128SKirk McKusick /* 28581fbded2SKirk McKusick * Attempt to flush a cylinder group cache entry. 28681fbded2SKirk McKusick * Return whether the flush was successful. 28781fbded2SKirk McKusick */ 28881fbded2SKirk McKusick int 28981fbded2SKirk McKusick flushentry(void) 29081fbded2SKirk McKusick { 29181fbded2SKirk McKusick struct bufarea *cgbp; 29281fbded2SKirk McKusick 2935cc52631SKirk McKusick if (sujrecovery || flushtries == sblock.fs_ncg || cgbufs == NULL) 294eff68496SKirk McKusick return (0); 29581fbded2SKirk McKusick cgbp = &cgbufs[flushtries++]; 29681fbded2SKirk McKusick if (cgbp->b_un.b_cg == NULL) 29781fbded2SKirk McKusick return (0); 29881fbded2SKirk McKusick flush(fswritefd, cgbp); 29981fbded2SKirk McKusick free(cgbp->b_un.b_buf); 30081fbded2SKirk McKusick cgbp->b_un.b_buf = NULL; 30181fbded2SKirk McKusick return (1); 30281fbded2SKirk McKusick } 30381fbded2SKirk McKusick 30481fbded2SKirk McKusick /* 305460ed610SKirk McKusick * Manage a cache of filesystem disk blocks. 3064336716bSAdrian Chadd */ 3074336716bSAdrian Chadd struct bufarea * 308ed75b5a1SKirk McKusick getdatablk(ufs2_daddr_t blkno, long size, int type) 3094336716bSAdrian Chadd { 3103d438ad6SDavid E. O'Brien struct bufarea *bp; 3115cc52631SKirk McKusick struct bufhash *bhdp; 3124336716bSAdrian Chadd 3135cc52631SKirk McKusick cachelookups++; 314460ed610SKirk McKusick /* 315460ed610SKirk McKusick * If out of range, return empty buffer with b_err == -1 316460ed610SKirk McKusick * 317460ed610SKirk McKusick * Skip check for inodes because chkrange() considers 318460ed610SKirk McKusick * metadata areas invalid to write data. 319460ed610SKirk McKusick */ 32018746531SKirk McKusick if (type != BT_INODES && chkrange(blkno, size / sblock.fs_fsize)) { 32118746531SKirk McKusick failedbuf.b_refcnt++; 322460ed610SKirk McKusick return (&failedbuf); 32318746531SKirk McKusick } 3245cc52631SKirk McKusick bhdp = &bufhashhd[HASH(blkno)]; 3255cc52631SKirk McKusick LIST_FOREACH(bp, bhdp, b_hash) 3265cc52631SKirk McKusick if (bp->b_bno == fsbtodb(&sblock, blkno)) { 3275cc52631SKirk McKusick if (debug && bp->b_size != size) { 328460ed610SKirk McKusick prtbuf(bp, "getdatablk: size mismatch"); 3295cc52631SKirk McKusick pfatal("getdatablk: b_size %d != size %ld\n", 3305cc52631SKirk McKusick bp->b_size, size); 3315cc52631SKirk McKusick } 332460ed610SKirk McKusick TAILQ_REMOVE(&bufqueuehd, bp, b_list); 3334336716bSAdrian Chadd goto foundit; 3345cc52631SKirk McKusick } 3355cc52631SKirk McKusick /* 3365cc52631SKirk McKusick * Move long-term busy buffer back to the front of the LRU so we 3375cc52631SKirk McKusick * do not endless inspect them for recycling. 3385cc52631SKirk McKusick */ 3395cc52631SKirk McKusick bp = TAILQ_LAST(&bufqueuehd, bufqueue); 3405cc52631SKirk McKusick if (bp != NULL && bp->b_refcnt != 0) { 3415cc52631SKirk McKusick TAILQ_REMOVE(&bufqueuehd, bp, b_list); 3425cc52631SKirk McKusick TAILQ_INSERT_HEAD(&bufqueuehd, bp, b_list); 3435cc52631SKirk McKusick } 3445cc52631SKirk McKusick /* 3455cc52631SKirk McKusick * Allocate up to the minimum number of buffers before 3465cc52631SKirk McKusick * considering recycling any of them. 3475cc52631SKirk McKusick */ 3485cc52631SKirk McKusick if (size > sblock.fs_bsize) 3495cc52631SKirk McKusick errx(EEXIT, "Excessive buffer size %ld > %d\n", size, 3505cc52631SKirk McKusick sblock.fs_bsize); 351460ed610SKirk McKusick if ((bp = LIST_FIRST(&freebufs)) != NULL) { 352460ed610SKirk McKusick LIST_REMOVE(bp, b_hash); 353460ed610SKirk McKusick } else if (numbufs < MINBUFS) { 3545cc52631SKirk McKusick bp = allocbuf("cannot create minimal buffer pool"); 3555cc52631SKirk McKusick } else if (sujrecovery) { 3565cc52631SKirk McKusick /* 3575cc52631SKirk McKusick * SUJ recovery does not want anything written until it 3585cc52631SKirk McKusick * has successfully completed (so it can fail back to 3595cc52631SKirk McKusick * full fsck). Thus, we can only recycle clean buffers. 3605cc52631SKirk McKusick */ 3615cc52631SKirk McKusick TAILQ_FOREACH_REVERSE(bp, &bufqueuehd, bufqueue, b_list) 3625cc52631SKirk McKusick if ((bp->b_flags & B_DIRTY) == 0 && bp->b_refcnt == 0) 3634336716bSAdrian Chadd break; 3642ec5c914SKirk McKusick if (bp == NULL) 3655cc52631SKirk McKusick bp = allocbuf("Ran out of memory during " 3665cc52631SKirk McKusick "journal recovery"); 3675cc52631SKirk McKusick else 3685cc52631SKirk McKusick LIST_REMOVE(bp, b_hash); 3695cc52631SKirk McKusick } else { 3705cc52631SKirk McKusick /* 3715cc52631SKirk McKusick * Recycle oldest non-busy buffer. 3725cc52631SKirk McKusick */ 3735cc52631SKirk McKusick TAILQ_FOREACH_REVERSE(bp, &bufqueuehd, bufqueue, b_list) 3745cc52631SKirk McKusick if (bp->b_refcnt == 0) 3755cc52631SKirk McKusick break; 3765cc52631SKirk McKusick if (bp == NULL) 3775cc52631SKirk McKusick bp = allocbuf("Ran out of memory for buffers"); 3785cc52631SKirk McKusick else 3795cc52631SKirk McKusick LIST_REMOVE(bp, b_hash); 3805cc52631SKirk McKusick } 381460ed610SKirk McKusick TAILQ_REMOVE(&bufqueuehd, bp, b_list); 3825cc52631SKirk McKusick flush(fswritefd, bp); 383ed75b5a1SKirk McKusick bp->b_type = type; 3845cc52631SKirk McKusick LIST_INSERT_HEAD(bhdp, bp, b_hash); 3854336716bSAdrian Chadd getblk(bp, blkno, size); 3865cc52631SKirk McKusick cachereads++; 3874336716bSAdrian Chadd /* fall through */ 3884336716bSAdrian Chadd foundit: 389460ed610SKirk McKusick TAILQ_INSERT_HEAD(&bufqueuehd, bp, b_list); 3905cc52631SKirk McKusick if (debug && bp->b_type != type) { 3915cc52631SKirk McKusick printf("getdatablk: buffer type changed to %s", 3925cc52631SKirk McKusick BT_BUFTYPE(type)); 393460ed610SKirk McKusick prtbuf(bp, ""); 3945cc52631SKirk McKusick } 3955cc52631SKirk McKusick if (bp->b_errs == 0) 3965cc52631SKirk McKusick bp->b_refcnt++; 3974336716bSAdrian Chadd return (bp); 3984336716bSAdrian Chadd } 3994336716bSAdrian Chadd 4004336716bSAdrian Chadd void 4011c85e6a3SKirk McKusick getblk(struct bufarea *bp, ufs2_daddr_t blk, long size) 4024336716bSAdrian Chadd { 4031c85e6a3SKirk McKusick ufs2_daddr_t dblk; 404ed75b5a1SKirk McKusick struct timespec start, finish; 4054336716bSAdrian Chadd 4064336716bSAdrian Chadd dblk = fsbtodb(&sblock, blk); 407ed75b5a1SKirk McKusick if (bp->b_bno == dblk) { 408ed75b5a1SKirk McKusick totalreads++; 409ed75b5a1SKirk McKusick } else { 410ed75b5a1SKirk McKusick if (debug) { 411ed75b5a1SKirk McKusick readcnt[bp->b_type]++; 412ed75b5a1SKirk McKusick clock_gettime(CLOCK_REALTIME_PRECISE, &start); 413ed75b5a1SKirk McKusick } 414460ed610SKirk McKusick bp->b_errs = blread(fsreadfd, bp->b_un.b_buf, dblk, size); 415ed75b5a1SKirk McKusick if (debug) { 416ed75b5a1SKirk McKusick clock_gettime(CLOCK_REALTIME_PRECISE, &finish); 4176040822cSAlan Somers timespecsub(&finish, &start, &finish); 4186040822cSAlan Somers timespecadd(&readtime[bp->b_type], &finish, 4196040822cSAlan Somers &readtime[bp->b_type]); 420ed75b5a1SKirk McKusick } 4214336716bSAdrian Chadd bp->b_bno = dblk; 4224336716bSAdrian Chadd bp->b_size = size; 4234336716bSAdrian Chadd } 4244336716bSAdrian Chadd } 4254336716bSAdrian Chadd 4264336716bSAdrian Chadd void 4275cc52631SKirk McKusick brelse(struct bufarea *bp) 4284336716bSAdrian Chadd { 4294336716bSAdrian Chadd 4305cc52631SKirk McKusick if (bp->b_refcnt <= 0) 431460ed610SKirk McKusick prtbuf(bp, "brelse: buffer with negative reference count"); 4325cc52631SKirk McKusick bp->b_refcnt--; 4335cc52631SKirk McKusick } 4345cc52631SKirk McKusick 4355cc52631SKirk McKusick void 436460ed610SKirk McKusick binval(struct bufarea *bp) 437460ed610SKirk McKusick { 438460ed610SKirk McKusick 439460ed610SKirk McKusick bp->b_flags &= ~B_DIRTY; 440460ed610SKirk McKusick LIST_REMOVE(bp, b_hash); 441460ed610SKirk McKusick LIST_INSERT_HEAD(&freebufs, bp, b_hash); 442460ed610SKirk McKusick } 443460ed610SKirk McKusick 444460ed610SKirk McKusick void 4455cc52631SKirk McKusick flush(int fd, struct bufarea *bp) 4465cc52631SKirk McKusick { 4475cc52631SKirk McKusick struct inode ip; 4485cc52631SKirk McKusick 4495cc52631SKirk McKusick if ((bp->b_flags & B_DIRTY) == 0) 4504336716bSAdrian Chadd return; 4515cc52631SKirk McKusick bp->b_flags &= ~B_DIRTY; 4527578c6abSKirk McKusick if (fswritefd < 0) { 4537578c6abSKirk McKusick pfatal("WRITING IN READ_ONLY MODE.\n"); 4547578c6abSKirk McKusick return; 4557578c6abSKirk McKusick } 4564336716bSAdrian Chadd if (bp->b_errs != 0) 457599304a4SPoul-Henning Kamp pfatal("WRITING %sZERO'ED BLOCK %lld TO DISK\n", 4584336716bSAdrian Chadd (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", 459599304a4SPoul-Henning Kamp (long long)bp->b_bno); 4604336716bSAdrian Chadd bp->b_errs = 0; 461a6bbdf81SKirk McKusick /* 462a6bbdf81SKirk McKusick * Write using the appropriate function. 463a6bbdf81SKirk McKusick */ 464a6bbdf81SKirk McKusick switch (bp->b_type) { 465a6bbdf81SKirk McKusick case BT_SUPERBLK: 4664336716bSAdrian Chadd if (bp != &sblk) 467af89fcf7SLi-Wen Hsu pfatal("BUFFER %p DOES NOT MATCH SBLK %p\n", 468af89fcf7SLi-Wen Hsu bp, &sblk); 469460ed610SKirk McKusick /* 470460ed610SKirk McKusick * Superblocks are always pre-copied so we do not need 471460ed610SKirk McKusick * to check them for copy-on-write. 472460ed610SKirk McKusick */ 4738ebae128SKirk McKusick if (sbput(fd, bp->b_un.b_fs, 0) == 0) 474dffce215SKirk McKusick fsmodified = 1; 475a6bbdf81SKirk McKusick break; 476a6bbdf81SKirk McKusick case BT_CYLGRP: 477460ed610SKirk McKusick /* 478460ed610SKirk McKusick * Cylinder groups are always pre-copied so we do not 479460ed610SKirk McKusick * need to check them for copy-on-write. 480460ed610SKirk McKusick */ 4815cc52631SKirk McKusick if (sujrecovery) 4825cc52631SKirk McKusick cg_write(bp); 48385ee267aSKirk McKusick if (cgput(fswritefd, &sblock, bp->b_un.b_cg) == 0) 484a6bbdf81SKirk McKusick fsmodified = 1; 485a6bbdf81SKirk McKusick break; 4865cc52631SKirk McKusick case BT_INODES: 4875cc52631SKirk McKusick if (debug && sblock.fs_magic == FS_UFS2_MAGIC) { 4885cc52631SKirk McKusick struct ufs2_dinode *dp = bp->b_un.b_dinode2; 4895cc52631SKirk McKusick int i; 4905cc52631SKirk McKusick 4912e4da012SKirk McKusick for (i = 0; i < bp->b_size; dp++, i += sizeof(*dp)) { 4925cc52631SKirk McKusick if (ffs_verify_dinode_ckhash(&sblock, dp) == 0) 4935cc52631SKirk McKusick continue; 4945cc52631SKirk McKusick pwarn("flush: INODE CHECK-HASH FAILED"); 4955cc52631SKirk McKusick ip.i_bp = bp; 4965cc52631SKirk McKusick ip.i_dp = (union dinode *)dp; 4974b4cc78aSKirk McKusick ip.i_number = bp->b_index + (i / sizeof(*dp)); 4985cc52631SKirk McKusick prtinode(&ip); 4995cc52631SKirk McKusick if (preen || reply("FIX") != 0) { 5005cc52631SKirk McKusick if (preen) 5015cc52631SKirk McKusick printf(" (FIXED)\n"); 5025cc52631SKirk McKusick ffs_update_dinode_ckhash(&sblock, dp); 5035cc52631SKirk McKusick inodirty(&ip); 5045cc52631SKirk McKusick } 5055cc52631SKirk McKusick } 5065cc52631SKirk McKusick } 5075cc52631SKirk McKusick /* FALLTHROUGH */ 508a6bbdf81SKirk McKusick default: 509460ed610SKirk McKusick copyonwrite(&sblock, bp, std_checkblkavail); 510a6bbdf81SKirk McKusick blwrite(fd, bp->b_un.b_buf, bp->b_bno, bp->b_size); 511a6bbdf81SKirk McKusick break; 512a6bbdf81SKirk McKusick } 5134336716bSAdrian Chadd } 5144336716bSAdrian Chadd 5155cc52631SKirk McKusick /* 516460ed610SKirk McKusick * If there are any snapshots, ensure that all the blocks that they 517460ed610SKirk McKusick * care about have been copied, then release the snapshot inodes. 518460ed610SKirk McKusick * These operations need to be done before we rebuild the cylinder 519460ed610SKirk McKusick * groups so that any block allocations are properly recorded. 520460ed610SKirk McKusick * Since all the cylinder group maps have already been copied in 521460ed610SKirk McKusick * the snapshots, no further snapshot copies will need to be done. 522460ed610SKirk McKusick */ 523460ed610SKirk McKusick void 524689a9368SKirk McKusick snapflush(ufs2_daddr_t (*checkblkavail)(ufs2_daddr_t, long)) 525460ed610SKirk McKusick { 526460ed610SKirk McKusick struct bufarea *bp; 527460ed610SKirk McKusick int cnt; 528460ed610SKirk McKusick 529460ed610SKirk McKusick if (snapcnt > 0) { 530460ed610SKirk McKusick if (debug) 531460ed610SKirk McKusick printf("Check for snapshot copies\n"); 532460ed610SKirk McKusick TAILQ_FOREACH_REVERSE(bp, &bufqueuehd, bufqueue, b_list) 533460ed610SKirk McKusick if ((bp->b_flags & B_DIRTY) != 0) 534460ed610SKirk McKusick copyonwrite(&sblock, bp, checkblkavail); 535460ed610SKirk McKusick for (cnt = 0; cnt < snapcnt; cnt++) 536460ed610SKirk McKusick irelse(&snaplist[cnt]); 537460ed610SKirk McKusick snapcnt = 0; 538460ed610SKirk McKusick } 539460ed610SKirk McKusick } 540460ed610SKirk McKusick 541460ed610SKirk McKusick /* 5425cc52631SKirk McKusick * Journaled soft updates does not maintain cylinder group summary 5435cc52631SKirk McKusick * information during cleanup, so this routine recalculates the summary 5445cc52631SKirk McKusick * information and updates the superblock summary in preparation for 5455cc52631SKirk McKusick * writing out the cylinder group. 5465cc52631SKirk McKusick */ 5475cc52631SKirk McKusick static void 5485cc52631SKirk McKusick cg_write(struct bufarea *bp) 5495cc52631SKirk McKusick { 5505cc52631SKirk McKusick ufs1_daddr_t fragno, cgbno, maxbno; 5515cc52631SKirk McKusick u_int8_t *blksfree; 552460ed610SKirk McKusick struct csum *csp; 5535cc52631SKirk McKusick struct cg *cgp; 5545cc52631SKirk McKusick int blk; 5555cc52631SKirk McKusick int i; 5565cc52631SKirk McKusick 5575cc52631SKirk McKusick /* 5585cc52631SKirk McKusick * Fix the frag and cluster summary. 5595cc52631SKirk McKusick */ 5605cc52631SKirk McKusick cgp = bp->b_un.b_cg; 5615cc52631SKirk McKusick cgp->cg_cs.cs_nbfree = 0; 5625cc52631SKirk McKusick cgp->cg_cs.cs_nffree = 0; 5635cc52631SKirk McKusick bzero(&cgp->cg_frsum, sizeof(cgp->cg_frsum)); 5645cc52631SKirk McKusick maxbno = fragstoblks(&sblock, sblock.fs_fpg); 5655cc52631SKirk McKusick if (sblock.fs_contigsumsize > 0) { 5665cc52631SKirk McKusick for (i = 1; i <= sblock.fs_contigsumsize; i++) 5675cc52631SKirk McKusick cg_clustersum(cgp)[i] = 0; 5685cc52631SKirk McKusick bzero(cg_clustersfree(cgp), howmany(maxbno, CHAR_BIT)); 5695cc52631SKirk McKusick } 5705cc52631SKirk McKusick blksfree = cg_blksfree(cgp); 5715cc52631SKirk McKusick for (cgbno = 0; cgbno < maxbno; cgbno++) { 5725cc52631SKirk McKusick if (ffs_isfreeblock(&sblock, blksfree, cgbno)) 5735cc52631SKirk McKusick continue; 5745cc52631SKirk McKusick if (ffs_isblock(&sblock, blksfree, cgbno)) { 5755cc52631SKirk McKusick ffs_clusteracct(&sblock, cgp, cgbno, 1); 5765cc52631SKirk McKusick cgp->cg_cs.cs_nbfree++; 5775cc52631SKirk McKusick continue; 5785cc52631SKirk McKusick } 5795cc52631SKirk McKusick fragno = blkstofrags(&sblock, cgbno); 5805cc52631SKirk McKusick blk = blkmap(&sblock, blksfree, fragno); 5815cc52631SKirk McKusick ffs_fragacct(&sblock, blk, cgp->cg_frsum, 1); 5825cc52631SKirk McKusick for (i = 0; i < sblock.fs_frag; i++) 5835cc52631SKirk McKusick if (isset(blksfree, fragno + i)) 5845cc52631SKirk McKusick cgp->cg_cs.cs_nffree++; 5855cc52631SKirk McKusick } 5865cc52631SKirk McKusick /* 5875cc52631SKirk McKusick * Update the superblock cg summary from our now correct values 5885cc52631SKirk McKusick * before writing the block. 5895cc52631SKirk McKusick */ 590460ed610SKirk McKusick csp = &sblock.fs_cs(&sblock, cgp->cg_cgx); 591460ed610SKirk McKusick sblock.fs_cstotal.cs_ndir += cgp->cg_cs.cs_ndir - csp->cs_ndir; 592460ed610SKirk McKusick sblock.fs_cstotal.cs_nbfree += cgp->cg_cs.cs_nbfree - csp->cs_nbfree; 593460ed610SKirk McKusick sblock.fs_cstotal.cs_nifree += cgp->cg_cs.cs_nifree - csp->cs_nifree; 594460ed610SKirk McKusick sblock.fs_cstotal.cs_nffree += cgp->cg_cs.cs_nffree - csp->cs_nffree; 5955cc52631SKirk McKusick sblock.fs_cs(&sblock, cgp->cg_cgx) = cgp->cg_cs; 5965cc52631SKirk McKusick } 5975cc52631SKirk McKusick 5987578c6abSKirk McKusick void 599599304a4SPoul-Henning Kamp rwerror(const char *mesg, ufs2_daddr_t blk) 6004336716bSAdrian Chadd { 6014336716bSAdrian Chadd 60215fca934SKirk McKusick if (bkgrdcheck) 60315fca934SKirk McKusick exit(EEXIT); 6044336716bSAdrian Chadd if (preen == 0) 6054336716bSAdrian Chadd printf("\n"); 606bf58d635SIan Dowse pfatal("CANNOT %s: %ld", mesg, (long)blk); 6074336716bSAdrian Chadd if (reply("CONTINUE") == 0) 6084336716bSAdrian Chadd exit(EEXIT); 6094336716bSAdrian Chadd } 6104336716bSAdrian Chadd 6114336716bSAdrian Chadd void 612b70cd7eeSWarner Losh ckfini(int markclean) 6134336716bSAdrian Chadd { 6143d438ad6SDavid E. O'Brien struct bufarea *bp, *nbp; 61552f97104SKirk McKusick int ofsmodified, cnt, cg; 6164336716bSAdrian Chadd 6177578c6abSKirk McKusick if (bkgrdflag) { 6187578c6abSKirk McKusick if ((!(sblock.fs_flags & FS_UNCLEAN)) != markclean) { 6197578c6abSKirk McKusick cmd.value = FS_UNCLEAN; 6207578c6abSKirk McKusick cmd.size = markclean ? -1 : 1; 6217578c6abSKirk McKusick if (sysctlbyname("vfs.ffs.setflags", 0, 0, 6227578c6abSKirk McKusick &cmd, sizeof cmd) == -1) 623c0bfa109SKirk McKusick pwarn("CANNOT SET FILE SYSTEM DIRTY FLAG\n"); 6247578c6abSKirk McKusick if (!preen) { 6257578c6abSKirk McKusick printf("\n***** FILE SYSTEM MARKED %s *****\n", 6267578c6abSKirk McKusick markclean ? "CLEAN" : "DIRTY"); 6277578c6abSKirk McKusick if (!markclean) 6287578c6abSKirk McKusick rerun = 1; 6297578c6abSKirk McKusick } 6307578c6abSKirk McKusick } else if (!preen && !markclean) { 6317578c6abSKirk McKusick printf("\n***** FILE SYSTEM STILL DIRTY *****\n"); 6327578c6abSKirk McKusick rerun = 1; 6337578c6abSKirk McKusick } 634c0bfa109SKirk McKusick bkgrdflag = 0; 6357578c6abSKirk McKusick } 63620123b25SRobert Wing if (debug && cachelookups > 0) 6375cc52631SKirk McKusick printf("cache with %d buffers missed %d of %d (%d%%)\n", 6385cc52631SKirk McKusick numbufs, cachereads, cachelookups, 6395cc52631SKirk McKusick (int)(cachereads * 100 / cachelookups)); 6404336716bSAdrian Chadd if (fswritefd < 0) { 6414336716bSAdrian Chadd (void)close(fsreadfd); 6424336716bSAdrian Chadd return; 6434336716bSAdrian Chadd } 644460ed610SKirk McKusick 6455cc52631SKirk McKusick /* 6465cc52631SKirk McKusick * To remain idempotent with partial truncations the buffers 6475cc52631SKirk McKusick * must be flushed in this order: 6485cc52631SKirk McKusick * 1) cylinder groups (bitmaps) 6495cc52631SKirk McKusick * 2) indirect, directory, external attribute, and data blocks 6505cc52631SKirk McKusick * 3) inode blocks 6515cc52631SKirk McKusick * 4) superblock 6525cc52631SKirk McKusick * This ordering preserves access to the modified pointers 6535cc52631SKirk McKusick * until they are freed. 6545cc52631SKirk McKusick */ 6555cc52631SKirk McKusick /* Step 1: cylinder groups */ 6565cc52631SKirk McKusick if (debug) 6575cc52631SKirk McKusick printf("Flush Cylinder groups\n"); 6585cc52631SKirk McKusick if (cgbufs != NULL) { 6595cc52631SKirk McKusick for (cnt = 0; cnt < sblock.fs_ncg; cnt++) { 6605cc52631SKirk McKusick if (cgbufs[cnt].b_un.b_cg == NULL) 6615cc52631SKirk McKusick continue; 6625cc52631SKirk McKusick flush(fswritefd, &cgbufs[cnt]); 6635cc52631SKirk McKusick free(cgbufs[cnt].b_un.b_cg); 6645cc52631SKirk McKusick } 6655cc52631SKirk McKusick free(cgbufs); 666fc56fd26SKirk McKusick cgbufs = NULL; 6675cc52631SKirk McKusick } 6685cc52631SKirk McKusick flush(fswritefd, &cgblk); 6695cc52631SKirk McKusick free(cgblk.b_un.b_buf); 670fc56fd26SKirk McKusick cgblk.b_un.b_buf = NULL; 6715cc52631SKirk McKusick cnt = 0; 6725cc52631SKirk McKusick /* Step 2: indirect, directory, external attribute, and data blocks */ 6735cc52631SKirk McKusick if (debug) 6745cc52631SKirk McKusick printf("Flush indirect, directory, external attribute, " 6755cc52631SKirk McKusick "and data blocks\n"); 676fc56fd26SKirk McKusick if (pdirbp != NULL) { 6775cc52631SKirk McKusick brelse(pdirbp); 678fc56fd26SKirk McKusick pdirbp = NULL; 679fc56fd26SKirk McKusick } 6805cc52631SKirk McKusick TAILQ_FOREACH_REVERSE_SAFE(bp, &bufqueuehd, bufqueue, b_list, nbp) { 6815cc52631SKirk McKusick switch (bp->b_type) { 6825cc52631SKirk McKusick /* These should not be in the buffer cache list */ 6835cc52631SKirk McKusick case BT_UNKNOWN: 6845cc52631SKirk McKusick case BT_SUPERBLK: 6855cc52631SKirk McKusick case BT_CYLGRP: 6865cc52631SKirk McKusick default: 687460ed610SKirk McKusick prtbuf(bp,"ckfini: improper buffer type on cache list"); 6885cc52631SKirk McKusick continue; 6895cc52631SKirk McKusick /* These are the ones to flush in this step */ 6905cc52631SKirk McKusick case BT_LEVEL1: 6915cc52631SKirk McKusick case BT_LEVEL2: 6925cc52631SKirk McKusick case BT_LEVEL3: 6935cc52631SKirk McKusick case BT_EXTATTR: 6945cc52631SKirk McKusick case BT_DIRDATA: 6955cc52631SKirk McKusick case BT_DATA: 6965cc52631SKirk McKusick break; 6975cc52631SKirk McKusick /* These are the ones to flush in the next step */ 6985cc52631SKirk McKusick case BT_INODES: 6995cc52631SKirk McKusick continue; 7005cc52631SKirk McKusick } 701460ed610SKirk McKusick if (debug && bp->b_refcnt != 0) 702460ed610SKirk McKusick prtbuf(bp, "ckfini: clearing in-use buffer"); 7035cc52631SKirk McKusick TAILQ_REMOVE(&bufqueuehd, bp, b_list); 704460ed610SKirk McKusick LIST_REMOVE(bp, b_hash); 7055cc52631SKirk McKusick cnt++; 7065cc52631SKirk McKusick flush(fswritefd, bp); 7075cc52631SKirk McKusick free(bp->b_un.b_buf); 7085cc52631SKirk McKusick free((char *)bp); 7095cc52631SKirk McKusick } 7105cc52631SKirk McKusick /* Step 3: inode blocks */ 7115cc52631SKirk McKusick if (debug) 7125cc52631SKirk McKusick printf("Flush inode blocks\n"); 713fc56fd26SKirk McKusick if (icachebp != NULL) { 7145cc52631SKirk McKusick brelse(icachebp); 715fc56fd26SKirk McKusick icachebp = NULL; 716fc56fd26SKirk McKusick } 7175cc52631SKirk McKusick TAILQ_FOREACH_REVERSE_SAFE(bp, &bufqueuehd, bufqueue, b_list, nbp) { 718460ed610SKirk McKusick if (debug && bp->b_refcnt != 0) 719460ed610SKirk McKusick prtbuf(bp, "ckfini: clearing in-use buffer"); 7205cc52631SKirk McKusick TAILQ_REMOVE(&bufqueuehd, bp, b_list); 721460ed610SKirk McKusick LIST_REMOVE(bp, b_hash); 7225cc52631SKirk McKusick cnt++; 7235cc52631SKirk McKusick flush(fswritefd, bp); 7245cc52631SKirk McKusick free(bp->b_un.b_buf); 7255cc52631SKirk McKusick free((char *)bp); 7265cc52631SKirk McKusick } 7275cc52631SKirk McKusick if (numbufs != cnt) 7285cc52631SKirk McKusick errx(EEXIT, "panic: lost %d buffers", numbufs - cnt); 7295cc52631SKirk McKusick /* Step 4: superblock */ 7305cc52631SKirk McKusick if (debug) 7315cc52631SKirk McKusick printf("Flush the superblock\n"); 7324336716bSAdrian Chadd flush(fswritefd, &sblk); 733be639cc8SKirk McKusick if (havesb && cursnapshot == 0 && 734be639cc8SKirk McKusick sblk.b_bno != sblock.fs_sblockloc / dev_bsize) { 735be639cc8SKirk McKusick if (preen || reply("UPDATE STANDARD SUPERBLOCK")) { 736be639cc8SKirk McKusick /* Change write destination to standard superblock */ 737dffce215SKirk McKusick sblock.fs_sblockactualloc = sblock.fs_sblockloc; 738ada981b2SKirk McKusick sblk.b_bno = sblock.fs_sblockloc / dev_bsize; 7394336716bSAdrian Chadd sbdirty(); 7404336716bSAdrian Chadd flush(fswritefd, &sblk); 741be639cc8SKirk McKusick } else { 742be639cc8SKirk McKusick markclean = 0; 743be639cc8SKirk McKusick } 7444336716bSAdrian Chadd } 7457578c6abSKirk McKusick if (cursnapshot == 0 && sblock.fs_clean != markclean) { 74668aff084SKirk McKusick if ((sblock.fs_clean = markclean) != 0) { 74738375c40SKirk McKusick sblock.fs_flags &= ~(FS_UNCLEAN | FS_NEEDSFSCK); 74868aff084SKirk McKusick sblock.fs_pendingblocks = 0; 74968aff084SKirk McKusick sblock.fs_pendinginodes = 0; 75068aff084SKirk McKusick } 7514336716bSAdrian Chadd sbdirty(); 7524336716bSAdrian Chadd ofsmodified = fsmodified; 7534336716bSAdrian Chadd flush(fswritefd, &sblk); 7544336716bSAdrian Chadd fsmodified = ofsmodified; 7554336716bSAdrian Chadd if (!preen) { 7564336716bSAdrian Chadd printf("\n***** FILE SYSTEM MARKED %s *****\n", 7574336716bSAdrian Chadd markclean ? "CLEAN" : "DIRTY"); 7584336716bSAdrian Chadd if (!markclean) 7594336716bSAdrian Chadd rerun = 1; 7604336716bSAdrian Chadd } 761910b491eSKirk McKusick } else if (!preen) { 762910b491eSKirk McKusick if (markclean) { 763910b491eSKirk McKusick printf("\n***** FILE SYSTEM IS CLEAN *****\n"); 764910b491eSKirk McKusick } else { 7654336716bSAdrian Chadd printf("\n***** FILE SYSTEM STILL DIRTY *****\n"); 7664336716bSAdrian Chadd rerun = 1; 7674336716bSAdrian Chadd } 768910b491eSKirk McKusick } 769fc56fd26SKirk McKusick /* 770fc56fd26SKirk McKusick * Free allocated tracking structures. 771fc56fd26SKirk McKusick */ 772fc56fd26SKirk McKusick if (blockmap != NULL) 773fc56fd26SKirk McKusick free(blockmap); 774fc56fd26SKirk McKusick blockmap = NULL; 775fc56fd26SKirk McKusick if (inostathead != NULL) { 776fc56fd26SKirk McKusick for (cg = 0; cg < sblock.fs_ncg; cg++) 777fc56fd26SKirk McKusick if (inostathead[cg].il_stat != NULL) 778fc56fd26SKirk McKusick free((char *)inostathead[cg].il_stat); 779fc56fd26SKirk McKusick free(inostathead); 780fc56fd26SKirk McKusick } 781fc56fd26SKirk McKusick inostathead = NULL; 78252f97104SKirk McKusick inocleanup(); 7835cc52631SKirk McKusick finalIOstats(); 7844336716bSAdrian Chadd (void)close(fsreadfd); 7854336716bSAdrian Chadd (void)close(fswritefd); 7864336716bSAdrian Chadd } 7874336716bSAdrian Chadd 788ed75b5a1SKirk McKusick /* 789ed75b5a1SKirk McKusick * Print out I/O statistics. 790ed75b5a1SKirk McKusick */ 791ed75b5a1SKirk McKusick void 792ed75b5a1SKirk McKusick IOstats(char *what) 793ed75b5a1SKirk McKusick { 794ed75b5a1SKirk McKusick int i; 795ed75b5a1SKirk McKusick 796ed75b5a1SKirk McKusick if (debug == 0) 797ed75b5a1SKirk McKusick return; 798ed75b5a1SKirk McKusick if (diskreads == 0) { 799ed75b5a1SKirk McKusick printf("%s: no I/O\n\n", what); 800ed75b5a1SKirk McKusick return; 801ed75b5a1SKirk McKusick } 802ed75b5a1SKirk McKusick if (startpass.tv_sec == 0) 803ed75b5a1SKirk McKusick startpass = startprog; 804ed75b5a1SKirk McKusick printf("%s: I/O statistics\n", what); 805ed75b5a1SKirk McKusick printIOstats(); 806ed75b5a1SKirk McKusick totaldiskreads += diskreads; 807ed75b5a1SKirk McKusick diskreads = 0; 808ed75b5a1SKirk McKusick for (i = 0; i < BT_NUMBUFTYPES; i++) { 8096040822cSAlan Somers timespecadd(&totalreadtime[i], &readtime[i], &totalreadtime[i]); 810ed75b5a1SKirk McKusick totalreadcnt[i] += readcnt[i]; 811ed75b5a1SKirk McKusick readtime[i].tv_sec = readtime[i].tv_nsec = 0; 812ed75b5a1SKirk McKusick readcnt[i] = 0; 813ed75b5a1SKirk McKusick } 814ed75b5a1SKirk McKusick clock_gettime(CLOCK_REALTIME_PRECISE, &startpass); 815ed75b5a1SKirk McKusick } 816ed75b5a1SKirk McKusick 817ed75b5a1SKirk McKusick void 818ed75b5a1SKirk McKusick finalIOstats(void) 819ed75b5a1SKirk McKusick { 820ed75b5a1SKirk McKusick int i; 821ed75b5a1SKirk McKusick 822ed75b5a1SKirk McKusick if (debug == 0) 823ed75b5a1SKirk McKusick return; 824ed75b5a1SKirk McKusick printf("Final I/O statistics\n"); 825ed75b5a1SKirk McKusick totaldiskreads += diskreads; 826ed75b5a1SKirk McKusick diskreads = totaldiskreads; 827ed75b5a1SKirk McKusick startpass = startprog; 828ed75b5a1SKirk McKusick for (i = 0; i < BT_NUMBUFTYPES; i++) { 8296040822cSAlan Somers timespecadd(&totalreadtime[i], &readtime[i], &totalreadtime[i]); 830ed75b5a1SKirk McKusick totalreadcnt[i] += readcnt[i]; 831ed75b5a1SKirk McKusick readtime[i] = totalreadtime[i]; 832ed75b5a1SKirk McKusick readcnt[i] = totalreadcnt[i]; 833ed75b5a1SKirk McKusick } 834ed75b5a1SKirk McKusick printIOstats(); 835ed75b5a1SKirk McKusick } 836ed75b5a1SKirk McKusick 837ed75b5a1SKirk McKusick static void printIOstats(void) 838ed75b5a1SKirk McKusick { 839ed75b5a1SKirk McKusick long long msec, totalmsec; 840ed75b5a1SKirk McKusick int i; 841ed75b5a1SKirk McKusick 842ed75b5a1SKirk McKusick clock_gettime(CLOCK_REALTIME_PRECISE, &finishpass); 8436040822cSAlan Somers timespecsub(&finishpass, &startpass, &finishpass); 844061ea59dSKirk McKusick printf("Running time: %jd.%03ld sec\n", 8454b3bbe04SSean Bruno (intmax_t)finishpass.tv_sec, finishpass.tv_nsec / 1000000); 846ed75b5a1SKirk McKusick printf("buffer reads by type:\n"); 847ed75b5a1SKirk McKusick for (totalmsec = 0, i = 0; i < BT_NUMBUFTYPES; i++) 848ed75b5a1SKirk McKusick totalmsec += readtime[i].tv_sec * 1000 + 849ed75b5a1SKirk McKusick readtime[i].tv_nsec / 1000000; 850ed75b5a1SKirk McKusick if (totalmsec == 0) 851ed75b5a1SKirk McKusick totalmsec = 1; 852ed75b5a1SKirk McKusick for (i = 0; i < BT_NUMBUFTYPES; i++) { 853ed75b5a1SKirk McKusick if (readcnt[i] == 0) 854ed75b5a1SKirk McKusick continue; 855061ea59dSKirk McKusick msec = 856061ea59dSKirk McKusick readtime[i].tv_sec * 1000 + readtime[i].tv_nsec / 1000000; 8574b3bbe04SSean Bruno printf("%21s:%8ld %2ld.%ld%% %4jd.%03ld sec %2lld.%lld%%\n", 858ed75b5a1SKirk McKusick buftype[i], readcnt[i], readcnt[i] * 100 / diskreads, 85981fbded2SKirk McKusick (readcnt[i] * 1000 / diskreads) % 10, 8604b3bbe04SSean Bruno (intmax_t)readtime[i].tv_sec, readtime[i].tv_nsec / 1000000, 861ed75b5a1SKirk McKusick msec * 100 / totalmsec, (msec * 1000 / totalmsec) % 10); 862ed75b5a1SKirk McKusick } 863ed75b5a1SKirk McKusick printf("\n"); 864ed75b5a1SKirk McKusick } 865ed75b5a1SKirk McKusick 8664336716bSAdrian Chadd int 867aef8d244SPawel Jakub Dawidek blread(int fd, char *buf, ufs2_daddr_t blk, long size) 8684336716bSAdrian Chadd { 8694336716bSAdrian Chadd char *cp; 8704336716bSAdrian Chadd int i, errs; 8714336716bSAdrian Chadd off_t offset; 8724336716bSAdrian Chadd 8734336716bSAdrian Chadd offset = blk; 8744336716bSAdrian Chadd offset *= dev_bsize; 8759d580d7cSIan Dowse if (bkgrdflag) 8769d580d7cSIan Dowse slowio_start(); 877ed75b5a1SKirk McKusick totalreads++; 878ed75b5a1SKirk McKusick diskreads++; 87904e5c6f1SEdward Tomasz Napierala if (pread(fd, buf, (int)size, offset) == size) { 8809d580d7cSIan Dowse if (bkgrdflag) 8819d580d7cSIan Dowse slowio_end(); 8824336716bSAdrian Chadd return (0); 8839d580d7cSIan Dowse } 884ce779f37SScott Long 885ce779f37SScott Long /* 886ce779f37SScott Long * This is handled specially here instead of in rwerror because 887ce779f37SScott Long * rwerror is used for all sorts of errors, not just true read/write 888ce779f37SScott Long * errors. It should be refactored and fixed. 889ce779f37SScott Long */ 890ce779f37SScott Long if (surrender) { 891ce779f37SScott Long pfatal("CANNOT READ_BLK: %ld", (long)blk); 892ce779f37SScott Long errx(EEXIT, "ABORTING DUE TO READ ERRORS"); 893ce779f37SScott Long } else 8947578c6abSKirk McKusick rwerror("READ BLK", blk); 895ce779f37SScott Long 8964336716bSAdrian Chadd errs = 0; 8974336716bSAdrian Chadd memset(buf, 0, (size_t)size); 8984336716bSAdrian Chadd printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); 8994336716bSAdrian Chadd for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { 90004e5c6f1SEdward Tomasz Napierala if (pread(fd, cp, (int)secsize, offset + i) != secsize) { 9014336716bSAdrian Chadd if (secsize != dev_bsize && dev_bsize != 1) 90284fc0d7eSMaxime Henrion printf(" %jd (%jd),", 90384fc0d7eSMaxime Henrion (intmax_t)(blk * dev_bsize + i) / secsize, 90484fc0d7eSMaxime Henrion (intmax_t)blk + i / dev_bsize); 9054336716bSAdrian Chadd else 90684fc0d7eSMaxime Henrion printf(" %jd,", (intmax_t)blk + i / dev_bsize); 9074336716bSAdrian Chadd errs++; 9084336716bSAdrian Chadd } 9094336716bSAdrian Chadd } 9104336716bSAdrian Chadd printf("\n"); 9114336716bSAdrian Chadd if (errs) 9124336716bSAdrian Chadd resolved = 0; 9134336716bSAdrian Chadd return (errs); 9144336716bSAdrian Chadd } 9154336716bSAdrian Chadd 9164336716bSAdrian Chadd void 9174a835375SDavid E. O'Brien blwrite(int fd, char *buf, ufs2_daddr_t blk, ssize_t size) 9184336716bSAdrian Chadd { 9194336716bSAdrian Chadd int i; 9204336716bSAdrian Chadd char *cp; 9214336716bSAdrian Chadd off_t offset; 9224336716bSAdrian Chadd 9234336716bSAdrian Chadd if (fd < 0) 9244336716bSAdrian Chadd return; 9254336716bSAdrian Chadd offset = blk; 9264336716bSAdrian Chadd offset *= dev_bsize; 92704e5c6f1SEdward Tomasz Napierala if (pwrite(fd, buf, size, offset) == size) { 9284336716bSAdrian Chadd fsmodified = 1; 9294336716bSAdrian Chadd return; 9304336716bSAdrian Chadd } 9314336716bSAdrian Chadd resolved = 0; 9327578c6abSKirk McKusick rwerror("WRITE BLK", blk); 9334336716bSAdrian Chadd printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 9344336716bSAdrian Chadd for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) 93504e5c6f1SEdward Tomasz Napierala if (pwrite(fd, cp, dev_bsize, offset + i) != dev_bsize) 93684fc0d7eSMaxime Henrion printf(" %jd,", (intmax_t)blk + i / dev_bsize); 9374336716bSAdrian Chadd printf("\n"); 9384336716bSAdrian Chadd return; 9394336716bSAdrian Chadd } 9404336716bSAdrian Chadd 9418d3dfc26SDag-Erling Smørgrav void 9428d3dfc26SDag-Erling Smørgrav blerase(int fd, ufs2_daddr_t blk, long size) 9438d3dfc26SDag-Erling Smørgrav { 9448d3dfc26SDag-Erling Smørgrav off_t ioarg[2]; 9458d3dfc26SDag-Erling Smørgrav 9468d3dfc26SDag-Erling Smørgrav if (fd < 0) 9478d3dfc26SDag-Erling Smørgrav return; 9488d3dfc26SDag-Erling Smørgrav ioarg[0] = blk * dev_bsize; 9498d3dfc26SDag-Erling Smørgrav ioarg[1] = size; 9508d3dfc26SDag-Erling Smørgrav ioctl(fd, DIOCGDELETE, ioarg); 9518d3dfc26SDag-Erling Smørgrav /* we don't really care if we succeed or not */ 9528d3dfc26SDag-Erling Smørgrav return; 9538d3dfc26SDag-Erling Smørgrav } 9548d3dfc26SDag-Erling Smørgrav 9558ce80d4bSDag-Erling Smørgrav /* 9568ce80d4bSDag-Erling Smørgrav * Fill a contiguous region with all-zeroes. Note ZEROBUFSIZE is by 9578ce80d4bSDag-Erling Smørgrav * definition a multiple of dev_bsize. 9588ce80d4bSDag-Erling Smørgrav */ 9592b5373deSDag-Erling Smørgrav void 9602b5373deSDag-Erling Smørgrav blzero(int fd, ufs2_daddr_t blk, long size) 9612b5373deSDag-Erling Smørgrav { 9622b5373deSDag-Erling Smørgrav static char *zero; 9632b5373deSDag-Erling Smørgrav off_t offset, len; 9642b5373deSDag-Erling Smørgrav 9652b5373deSDag-Erling Smørgrav if (fd < 0) 9662b5373deSDag-Erling Smørgrav return; 9672b5373deSDag-Erling Smørgrav if (zero == NULL) { 968*772430ddSKirk McKusick zero = Balloc(ZEROBUFSIZE); 9692b5373deSDag-Erling Smørgrav if (zero == NULL) 9702b5373deSDag-Erling Smørgrav errx(EEXIT, "cannot allocate buffer pool"); 9712b5373deSDag-Erling Smørgrav } 9722b5373deSDag-Erling Smørgrav offset = blk * dev_bsize; 9732b5373deSDag-Erling Smørgrav if (lseek(fd, offset, 0) < 0) 9742b5373deSDag-Erling Smørgrav rwerror("SEEK BLK", blk); 9752b5373deSDag-Erling Smørgrav while (size > 0) { 9761120faabSMarcelo Araujo len = MIN(ZEROBUFSIZE, size); 9772b5373deSDag-Erling Smørgrav if (write(fd, zero, len) != len) 9782b5373deSDag-Erling Smørgrav rwerror("WRITE BLK", blk); 9792b5373deSDag-Erling Smørgrav blk += len / dev_bsize; 9802b5373deSDag-Erling Smørgrav size -= len; 9812b5373deSDag-Erling Smørgrav } 9822b5373deSDag-Erling Smørgrav } 9832b5373deSDag-Erling Smørgrav 9844336716bSAdrian Chadd /* 985910b491eSKirk McKusick * Verify cylinder group's magic number and other parameters. If the 986910b491eSKirk McKusick * test fails, offer an option to rebuild the whole cylinder group. 987da86e7a2SKirk McKusick * 98840647558SChuck Silvers * Return 1 if the cylinder group is good or return 0 if it is bad. 98914320f1eSXin LI */ 990495b1baaSKirk McKusick #undef CHK 991495b1baaSKirk McKusick #define CHK(lhs, op, rhs, fmt) \ 992495b1baaSKirk McKusick if (lhs op rhs) { \ 99327c6009eSKirk McKusick pwarn("UFS%d cylinder group %d failed: " \ 99427c6009eSKirk McKusick "%s (" #fmt ") %s %s (" #fmt ")\n", \ 99527c6009eSKirk McKusick sblock.fs_magic == FS_UFS1_MAGIC ? 1 : 2, cg, \ 99627c6009eSKirk McKusick #lhs, (intmax_t)lhs, #op, #rhs, (intmax_t)rhs); \ 997495b1baaSKirk McKusick error = 1; \ 998495b1baaSKirk McKusick } 999910b491eSKirk McKusick int 100040647558SChuck Silvers check_cgmagic(int cg, struct bufarea *cgbp) 100114320f1eSXin LI { 100281fbded2SKirk McKusick struct cg *cgp = cgbp->b_un.b_cg; 10035cc52631SKirk McKusick uint32_t cghash, calchash; 1004689724cbSKirk McKusick static int prevfailcg = -1; 100552f97104SKirk McKusick long start; 1006495b1baaSKirk McKusick int error; 100714320f1eSXin LI 1008910b491eSKirk McKusick /* 1009910b491eSKirk McKusick * Extended cylinder group checks. 1010910b491eSKirk McKusick */ 10115cc52631SKirk McKusick calchash = cgp->cg_ckhash; 10126385cabdSKirk McKusick if ((sblock.fs_metackhash & CK_CYLGRP) != 0 && 10136385cabdSKirk McKusick (ckhashadd & CK_CYLGRP) == 0) { 10145cc52631SKirk McKusick cghash = cgp->cg_ckhash; 10155cc52631SKirk McKusick cgp->cg_ckhash = 0; 10165cc52631SKirk McKusick calchash = calculate_crc32c(~0L, (void *)cgp, sblock.fs_cgsize); 10175cc52631SKirk McKusick cgp->cg_ckhash = cghash; 10185cc52631SKirk McKusick } 1019495b1baaSKirk McKusick error = 0; 1020495b1baaSKirk McKusick CHK(cgp->cg_ckhash, !=, calchash, "%jd"); 1021495b1baaSKirk McKusick CHK(cg_chkmagic(cgp), ==, 0, "%jd"); 1022495b1baaSKirk McKusick CHK(cgp->cg_cgx, !=, cg, "%jd"); 1023495b1baaSKirk McKusick CHK(cgp->cg_ndblk, >, sblock.fs_fpg, "%jd"); 1024495b1baaSKirk McKusick if (sblock.fs_magic == FS_UFS1_MAGIC) { 1025495b1baaSKirk McKusick CHK(cgp->cg_old_niblk, !=, sblock.fs_ipg, "%jd"); 1026495b1baaSKirk McKusick CHK(cgp->cg_old_ncyl, >, sblock.fs_old_cpg, "%jd"); 1027495b1baaSKirk McKusick } else if (sblock.fs_magic == FS_UFS2_MAGIC) { 1028495b1baaSKirk McKusick CHK(cgp->cg_niblk, !=, sblock.fs_ipg, "%jd"); 1029495b1baaSKirk McKusick CHK(cgp->cg_initediblk, >, sblock.fs_ipg, "%jd"); 1030910b491eSKirk McKusick } 103152f97104SKirk McKusick if (cgbase(&sblock, cg) + sblock.fs_fpg < sblock.fs_size) { 103252f97104SKirk McKusick CHK(cgp->cg_ndblk, !=, sblock.fs_fpg, "%jd"); 103352f97104SKirk McKusick } else { 103452f97104SKirk McKusick CHK(cgp->cg_ndblk, !=, sblock.fs_size - cgbase(&sblock, cg), 103552f97104SKirk McKusick "%jd"); 103652f97104SKirk McKusick } 10370a6e34e9SKirk McKusick start = sizeof(*cgp); 103852f97104SKirk McKusick if (sblock.fs_magic == FS_UFS2_MAGIC) { 103952f97104SKirk McKusick CHK(cgp->cg_iusedoff, !=, start, "%jd"); 104052f97104SKirk McKusick } else if (sblock.fs_magic == FS_UFS1_MAGIC) { 104152f97104SKirk McKusick CHK(cgp->cg_niblk, !=, 0, "%jd"); 104252f97104SKirk McKusick CHK(cgp->cg_initediblk, !=, 0, "%jd"); 104352f97104SKirk McKusick CHK(cgp->cg_old_ncyl, !=, sblock.fs_old_cpg, "%jd"); 104452f97104SKirk McKusick CHK(cgp->cg_old_niblk, !=, sblock.fs_ipg, "%jd"); 104552f97104SKirk McKusick CHK(cgp->cg_old_btotoff, !=, start, "%jd"); 104652f97104SKirk McKusick CHK(cgp->cg_old_boff, !=, cgp->cg_old_btotoff + 104752f97104SKirk McKusick sblock.fs_old_cpg * sizeof(int32_t), "%jd"); 104852f97104SKirk McKusick CHK(cgp->cg_iusedoff, !=, cgp->cg_old_boff + 104952f97104SKirk McKusick sblock.fs_old_cpg * sizeof(u_int16_t), "%jd"); 105052f97104SKirk McKusick } 105152f97104SKirk McKusick CHK(cgp->cg_freeoff, !=, 105252f97104SKirk McKusick cgp->cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT), "%jd"); 105352f97104SKirk McKusick if (sblock.fs_contigsumsize == 0) { 105452f97104SKirk McKusick CHK(cgp->cg_nextfreeoff, !=, 105552f97104SKirk McKusick cgp->cg_freeoff + howmany(sblock.fs_fpg, CHAR_BIT), "%jd"); 105652f97104SKirk McKusick } else { 105752f97104SKirk McKusick CHK(cgp->cg_nclusterblks, !=, cgp->cg_ndblk / sblock.fs_frag, 105852f97104SKirk McKusick "%jd"); 105952f97104SKirk McKusick CHK(cgp->cg_clustersumoff, !=, 106052f97104SKirk McKusick roundup(cgp->cg_freeoff + howmany(sblock.fs_fpg, CHAR_BIT), 106152f97104SKirk McKusick sizeof(u_int32_t)) - sizeof(u_int32_t), "%jd"); 106252f97104SKirk McKusick CHK(cgp->cg_clusteroff, !=, cgp->cg_clustersumoff + 106352f97104SKirk McKusick (sblock.fs_contigsumsize + 1) * sizeof(u_int32_t), "%jd"); 106452f97104SKirk McKusick CHK(cgp->cg_nextfreeoff, !=, cgp->cg_clusteroff + 106552f97104SKirk McKusick howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT), 106652f97104SKirk McKusick "%jd"); 106752f97104SKirk McKusick } 1068495b1baaSKirk McKusick if (error == 0) 1069495b1baaSKirk McKusick return (1); 1070689724cbSKirk McKusick if (prevfailcg == cg) 10715cc52631SKirk McKusick return (0); 1072689724cbSKirk McKusick prevfailcg = cg; 1073689724cbSKirk McKusick pfatal("CYLINDER GROUP %d: INTEGRITY CHECK FAILED", cg); 1074689724cbSKirk McKusick printf("\n"); 1075689724cbSKirk McKusick return (0); 1076689724cbSKirk McKusick } 107740647558SChuck Silvers 107840647558SChuck Silvers void 107940647558SChuck Silvers rebuild_cg(int cg, struct bufarea *cgbp) 108040647558SChuck Silvers { 108140647558SChuck Silvers struct cg *cgp = cgbp->b_un.b_cg; 108240647558SChuck Silvers long start; 108340647558SChuck Silvers 1084910b491eSKirk McKusick /* 1085910b491eSKirk McKusick * Zero out the cylinder group and then initialize critical fields. 1086910b491eSKirk McKusick * Bit maps and summaries will be recalculated by later passes. 1087910b491eSKirk McKusick */ 108814320f1eSXin LI memset(cgp, 0, (size_t)sblock.fs_cgsize); 1089910b491eSKirk McKusick cgp->cg_magic = CG_MAGIC; 109014320f1eSXin LI cgp->cg_cgx = cg; 109114320f1eSXin LI cgp->cg_niblk = sblock.fs_ipg; 10921120faabSMarcelo Araujo cgp->cg_initediblk = MIN(sblock.fs_ipg, 2 * INOPB(&sblock)); 1093910b491eSKirk McKusick if (cgbase(&sblock, cg) + sblock.fs_fpg < sblock.fs_size) 1094910b491eSKirk McKusick cgp->cg_ndblk = sblock.fs_fpg; 1095910b491eSKirk McKusick else 109614320f1eSXin LI cgp->cg_ndblk = sblock.fs_size - cgbase(&sblock, cg); 10970a6e34e9SKirk McKusick start = sizeof(*cgp); 109852f97104SKirk McKusick if (sblock.fs_magic == FS_UFS2_MAGIC) { 109952f97104SKirk McKusick cgp->cg_iusedoff = start; 110052f97104SKirk McKusick } else if (sblock.fs_magic == FS_UFS1_MAGIC) { 1101910b491eSKirk McKusick cgp->cg_niblk = 0; 1102910b491eSKirk McKusick cgp->cg_initediblk = 0; 1103910b491eSKirk McKusick cgp->cg_old_ncyl = sblock.fs_old_cpg; 1104910b491eSKirk McKusick cgp->cg_old_niblk = sblock.fs_ipg; 110552f97104SKirk McKusick cgp->cg_old_btotoff = start; 1106910b491eSKirk McKusick cgp->cg_old_boff = cgp->cg_old_btotoff + 1107910b491eSKirk McKusick sblock.fs_old_cpg * sizeof(int32_t); 1108910b491eSKirk McKusick cgp->cg_iusedoff = cgp->cg_old_boff + 1109910b491eSKirk McKusick sblock.fs_old_cpg * sizeof(u_int16_t); 1110910b491eSKirk McKusick } 1111910b491eSKirk McKusick cgp->cg_freeoff = cgp->cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT); 1112910b491eSKirk McKusick cgp->cg_nextfreeoff = cgp->cg_freeoff + howmany(sblock.fs_fpg,CHAR_BIT); 1113910b491eSKirk McKusick if (sblock.fs_contigsumsize > 0) { 1114910b491eSKirk McKusick cgp->cg_nclusterblks = cgp->cg_ndblk / sblock.fs_frag; 1115910b491eSKirk McKusick cgp->cg_clustersumoff = 1116910b491eSKirk McKusick roundup(cgp->cg_nextfreeoff, sizeof(u_int32_t)); 1117910b491eSKirk McKusick cgp->cg_clustersumoff -= sizeof(u_int32_t); 1118910b491eSKirk McKusick cgp->cg_clusteroff = cgp->cg_clustersumoff + 1119910b491eSKirk McKusick (sblock.fs_contigsumsize + 1) * sizeof(u_int32_t); 1120910b491eSKirk McKusick cgp->cg_nextfreeoff = cgp->cg_clusteroff + 1121910b491eSKirk McKusick howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT); 1122910b491eSKirk McKusick } 1123495b1baaSKirk McKusick cgp->cg_ckhash = calculate_crc32c(~0L, (void *)cgp, sblock.fs_cgsize); 11248ebae128SKirk McKusick cgdirty(cgbp); 112514320f1eSXin LI } 112614320f1eSXin LI 112714320f1eSXin LI /* 11284336716bSAdrian Chadd * allocate a data block with the specified number of fragments 11294336716bSAdrian Chadd */ 11301c85e6a3SKirk McKusick ufs2_daddr_t 1131460ed610SKirk McKusick allocblk(long startcg, long frags, 1132460ed610SKirk McKusick ufs2_daddr_t (*checkblkavail)(ufs2_daddr_t blkno, long frags)) 11334336716bSAdrian Chadd { 1134460ed610SKirk McKusick ufs2_daddr_t blkno, newblk; 11354336716bSAdrian Chadd 1136460ed610SKirk McKusick if (sujrecovery && checkblkavail == std_checkblkavail) { 1137460ed610SKirk McKusick pfatal("allocblk: std_checkblkavail used for SUJ recovery\n"); 1138460ed610SKirk McKusick return (0); 1139460ed610SKirk McKusick } 11404336716bSAdrian Chadd if (frags <= 0 || frags > sblock.fs_frag) 11414336716bSAdrian Chadd return (0); 114252f97104SKirk McKusick for (blkno = MAX(cgdata(&sblock, startcg), 0); 1143460ed610SKirk McKusick blkno < maxfsblock - sblock.fs_frag; 1144460ed610SKirk McKusick blkno += sblock.fs_frag) { 1145460ed610SKirk McKusick if ((newblk = (*checkblkavail)(blkno, frags)) == 0) 1146460ed610SKirk McKusick continue; 1147460ed610SKirk McKusick if (newblk > 0) 1148460ed610SKirk McKusick return (newblk); 1149460ed610SKirk McKusick if (newblk < 0) 1150460ed610SKirk McKusick blkno = -newblk; 1151460ed610SKirk McKusick } 115252f97104SKirk McKusick for (blkno = MAX(cgdata(&sblock, 0), 0); 1153460ed610SKirk McKusick blkno < cgbase(&sblock, startcg) - sblock.fs_frag; 1154460ed610SKirk McKusick blkno += sblock.fs_frag) { 1155460ed610SKirk McKusick if ((newblk = (*checkblkavail)(blkno, frags)) == 0) 1156460ed610SKirk McKusick continue; 1157460ed610SKirk McKusick if (newblk > 0) 1158460ed610SKirk McKusick return (newblk); 1159460ed610SKirk McKusick if (newblk < 0) 1160460ed610SKirk McKusick blkno = -newblk; 1161460ed610SKirk McKusick } 1162460ed610SKirk McKusick return (0); 1163460ed610SKirk McKusick } 1164460ed610SKirk McKusick 1165460ed610SKirk McKusick ufs2_daddr_t 1166e5d0d1c5SKirk McKusick std_checkblkavail(ufs2_daddr_t blkno, long frags) 1167460ed610SKirk McKusick { 1168460ed610SKirk McKusick struct bufarea *cgbp; 1169460ed610SKirk McKusick struct cg *cgp; 1170460ed610SKirk McKusick ufs2_daddr_t j, k, baseblk; 1171460ed610SKirk McKusick long cg; 1172460ed610SKirk McKusick 117352f97104SKirk McKusick if ((u_int64_t)blkno > sblock.fs_size) 117452f97104SKirk McKusick return (0); 11754336716bSAdrian Chadd for (j = 0; j <= sblock.fs_frag - frags; j++) { 1176460ed610SKirk McKusick if (testbmap(blkno + j)) 11774336716bSAdrian Chadd continue; 11784336716bSAdrian Chadd for (k = 1; k < frags; k++) 1179460ed610SKirk McKusick if (testbmap(blkno + j + k)) 11804336716bSAdrian Chadd break; 11814336716bSAdrian Chadd if (k < frags) { 11824336716bSAdrian Chadd j += k; 11834336716bSAdrian Chadd continue; 11844336716bSAdrian Chadd } 1185460ed610SKirk McKusick cg = dtog(&sblock, blkno + j); 1186957fc241SKirk McKusick cgbp = cglookup(cg); 118781fbded2SKirk McKusick cgp = cgbp->b_un.b_cg; 118840647558SChuck Silvers if (!check_cgmagic(cg, cgbp)) 1189460ed610SKirk McKusick return (-((cg + 1) * sblock.fs_fpg - sblock.fs_frag)); 1190460ed610SKirk McKusick baseblk = dtogd(&sblock, blkno + j); 11914336716bSAdrian Chadd for (k = 0; k < frags; k++) { 1192460ed610SKirk McKusick setbmap(blkno + j + k); 11934336716bSAdrian Chadd clrbit(cg_blksfree(cgp), baseblk + k); 11944336716bSAdrian Chadd } 11954336716bSAdrian Chadd n_blks += frags; 11964336716bSAdrian Chadd if (frags == sblock.fs_frag) 11974336716bSAdrian Chadd cgp->cg_cs.cs_nbfree--; 11984336716bSAdrian Chadd else 11994336716bSAdrian Chadd cgp->cg_cs.cs_nffree -= frags; 12008ebae128SKirk McKusick cgdirty(cgbp); 1201460ed610SKirk McKusick return (blkno + j); 12024336716bSAdrian Chadd } 12034336716bSAdrian Chadd return (0); 12044336716bSAdrian Chadd } 12054336716bSAdrian Chadd 12064336716bSAdrian Chadd /* 1207101a9ac0SKirk McKusick * Check whether a file size is within the limits for the filesystem. 1208101a9ac0SKirk McKusick * Return 1 when valid and 0 when too big. 1209101a9ac0SKirk McKusick * 1210101a9ac0SKirk McKusick * This should match the file size limit in ffs_mountfs(). 1211101a9ac0SKirk McKusick */ 1212101a9ac0SKirk McKusick int 1213101a9ac0SKirk McKusick chkfilesize(mode_t mode, u_int64_t filesize) 1214101a9ac0SKirk McKusick { 1215101a9ac0SKirk McKusick u_int64_t kernmaxfilesize; 1216101a9ac0SKirk McKusick 1217101a9ac0SKirk McKusick if (sblock.fs_magic == FS_UFS1_MAGIC) 1218101a9ac0SKirk McKusick kernmaxfilesize = (off_t)0x40000000 * sblock.fs_bsize - 1; 1219101a9ac0SKirk McKusick else 1220101a9ac0SKirk McKusick kernmaxfilesize = sblock.fs_maxfilesize; 1221101a9ac0SKirk McKusick if (filesize > kernmaxfilesize || 1222101a9ac0SKirk McKusick filesize > sblock.fs_maxfilesize || 1223101a9ac0SKirk McKusick (mode == IFDIR && filesize > MAXDIRSIZE)) { 1224101a9ac0SKirk McKusick if (debug) 1225101a9ac0SKirk McKusick printf("bad file size %ju:", (uintmax_t)filesize); 1226101a9ac0SKirk McKusick return (0); 1227101a9ac0SKirk McKusick } 1228101a9ac0SKirk McKusick return (1); 1229101a9ac0SKirk McKusick } 1230101a9ac0SKirk McKusick 1231101a9ac0SKirk McKusick /* 12327180f1abSKirk McKusick * Slow down IO so as to leave some disk bandwidth for other processes 12334336716bSAdrian Chadd */ 12344336716bSAdrian Chadd void 12359d580d7cSIan Dowse slowio_start() 12369d580d7cSIan Dowse { 12379d580d7cSIan Dowse 123808983aeeSScott Long /* Delay one in every 8 operations */ 12399d580d7cSIan Dowse slowio_pollcnt = (slowio_pollcnt + 1) & 7; 12409d580d7cSIan Dowse if (slowio_pollcnt == 0) { 12419d580d7cSIan Dowse gettimeofday(&slowio_starttime, NULL); 12429d580d7cSIan Dowse } 12439d580d7cSIan Dowse } 12449d580d7cSIan Dowse 12459d580d7cSIan Dowse void 12469d580d7cSIan Dowse slowio_end() 12479d580d7cSIan Dowse { 12489d580d7cSIan Dowse struct timeval tv; 12499d580d7cSIan Dowse int delay_usec; 12509d580d7cSIan Dowse 12519d580d7cSIan Dowse if (slowio_pollcnt != 0) 12529d580d7cSIan Dowse return; 12539d580d7cSIan Dowse 12549d580d7cSIan Dowse /* Update the slowdown interval. */ 12559d580d7cSIan Dowse gettimeofday(&tv, NULL); 12569d580d7cSIan Dowse delay_usec = (tv.tv_sec - slowio_starttime.tv_sec) * 1000000 + 12579d580d7cSIan Dowse (tv.tv_usec - slowio_starttime.tv_usec); 12589d580d7cSIan Dowse if (delay_usec < 64) 12599d580d7cSIan Dowse delay_usec = 64; 126008983aeeSScott Long if (delay_usec > 2500000) 126108983aeeSScott Long delay_usec = 2500000; 12629d580d7cSIan Dowse slowio_delay_usec = (slowio_delay_usec * 63 + delay_usec) >> 6; 126308983aeeSScott Long /* delay by 8 times the average IO delay */ 126408983aeeSScott Long if (slowio_delay_usec > 64) 126508983aeeSScott Long usleep(slowio_delay_usec * 8); 12669d580d7cSIan Dowse } 12679d580d7cSIan Dowse 12684336716bSAdrian Chadd /* 12694336716bSAdrian Chadd * Find a pathname 12704336716bSAdrian Chadd */ 12714336716bSAdrian Chadd void 1272b70cd7eeSWarner Losh getpathname(char *namebuf, ino_t curdir, ino_t ino) 12734336716bSAdrian Chadd { 12744336716bSAdrian Chadd int len; 12753d438ad6SDavid E. O'Brien char *cp; 12765cc52631SKirk McKusick struct inode ip; 12774336716bSAdrian Chadd struct inodesc idesc; 12784336716bSAdrian Chadd static int busy = 0; 12794336716bSAdrian Chadd 12801dc349abSEd Maste if (curdir == ino && ino == UFS_ROOTINO) { 12814336716bSAdrian Chadd (void)strcpy(namebuf, "/"); 12824336716bSAdrian Chadd return; 12834336716bSAdrian Chadd } 1284af6726e6SDon Lewis if (busy || !INO_IS_DVALID(curdir)) { 12854336716bSAdrian Chadd (void)strcpy(namebuf, "?"); 12864336716bSAdrian Chadd return; 12874336716bSAdrian Chadd } 12884336716bSAdrian Chadd busy = 1; 12894336716bSAdrian Chadd memset(&idesc, 0, sizeof(struct inodesc)); 12904336716bSAdrian Chadd idesc.id_type = DATA; 12914336716bSAdrian Chadd idesc.id_fix = IGNORE; 12924336716bSAdrian Chadd cp = &namebuf[MAXPATHLEN - 1]; 12934336716bSAdrian Chadd *cp = '\0'; 12944336716bSAdrian Chadd if (curdir != ino) { 12954336716bSAdrian Chadd idesc.id_parent = curdir; 12964336716bSAdrian Chadd goto namelookup; 12974336716bSAdrian Chadd } 12981dc349abSEd Maste while (ino != UFS_ROOTINO) { 12994336716bSAdrian Chadd idesc.id_number = ino; 13004336716bSAdrian Chadd idesc.id_func = findino; 1301599304a4SPoul-Henning Kamp idesc.id_name = strdup(".."); 13025cc52631SKirk McKusick ginode(ino, &ip); 13035cc52631SKirk McKusick if ((ckinode(ip.i_dp, &idesc) & FOUND) == 0) { 13045cc52631SKirk McKusick irelse(&ip); 1305e5d0d1c5SKirk McKusick free(idesc.id_name); 13064336716bSAdrian Chadd break; 13075cc52631SKirk McKusick } 13085cc52631SKirk McKusick irelse(&ip); 1309e5d0d1c5SKirk McKusick free(idesc.id_name); 13104336716bSAdrian Chadd namelookup: 13114336716bSAdrian Chadd idesc.id_number = idesc.id_parent; 13124336716bSAdrian Chadd idesc.id_parent = ino; 13134336716bSAdrian Chadd idesc.id_func = findname; 13144336716bSAdrian Chadd idesc.id_name = namebuf; 13155cc52631SKirk McKusick ginode(idesc.id_number, &ip); 13165cc52631SKirk McKusick if ((ckinode(ip.i_dp, &idesc) & FOUND) == 0) { 13175cc52631SKirk McKusick irelse(&ip); 13184336716bSAdrian Chadd break; 13195cc52631SKirk McKusick } 13205cc52631SKirk McKusick irelse(&ip); 13214336716bSAdrian Chadd len = strlen(namebuf); 13224336716bSAdrian Chadd cp -= len; 13234336716bSAdrian Chadd memmove(cp, namebuf, (size_t)len); 13244336716bSAdrian Chadd *--cp = '/'; 13250ecf59f6SConrad Meyer if (cp < &namebuf[UFS_MAXNAMLEN]) 13264336716bSAdrian Chadd break; 13274336716bSAdrian Chadd ino = idesc.id_number; 13284336716bSAdrian Chadd } 13294336716bSAdrian Chadd busy = 0; 13301dc349abSEd Maste if (ino != UFS_ROOTINO) 13314336716bSAdrian Chadd *--cp = '?'; 13324336716bSAdrian Chadd memmove(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp)); 13334336716bSAdrian Chadd } 13344336716bSAdrian Chadd 13354336716bSAdrian Chadd void 1336599304a4SPoul-Henning Kamp catch(int sig __unused) 13374336716bSAdrian Chadd { 1338381ee4c2SPoul-Henning Kamp 13394336716bSAdrian Chadd ckfini(0); 13404336716bSAdrian Chadd exit(12); 13414336716bSAdrian Chadd } 13424336716bSAdrian Chadd 13434336716bSAdrian Chadd /* 13444336716bSAdrian Chadd * When preening, allow a single quit to signal 13454336716bSAdrian Chadd * a special exit after file system checks complete 13464336716bSAdrian Chadd * so that reboot sequence may be interrupted. 13474336716bSAdrian Chadd */ 13484336716bSAdrian Chadd void 1349599304a4SPoul-Henning Kamp catchquit(int sig __unused) 13504336716bSAdrian Chadd { 13514336716bSAdrian Chadd printf("returning to single-user after file system check\n"); 13524336716bSAdrian Chadd returntosingle = 1; 13534336716bSAdrian Chadd (void)signal(SIGQUIT, SIG_DFL); 13544336716bSAdrian Chadd } 13554336716bSAdrian Chadd 13564336716bSAdrian Chadd /* 13574336716bSAdrian Chadd * determine whether an inode should be fixed. 13584336716bSAdrian Chadd */ 13594336716bSAdrian Chadd int 1360599304a4SPoul-Henning Kamp dofix(struct inodesc *idesc, const char *msg) 13614336716bSAdrian Chadd { 13624336716bSAdrian Chadd 13634336716bSAdrian Chadd switch (idesc->id_fix) { 13644336716bSAdrian Chadd 13654336716bSAdrian Chadd case DONTKNOW: 13664336716bSAdrian Chadd if (idesc->id_type == DATA) 13674336716bSAdrian Chadd direrror(idesc->id_number, msg); 13684336716bSAdrian Chadd else 13695979df34SKris Kennaway pwarn("%s", msg); 13704336716bSAdrian Chadd if (preen) { 13714336716bSAdrian Chadd printf(" (SALVAGED)\n"); 13724336716bSAdrian Chadd idesc->id_fix = FIX; 13734336716bSAdrian Chadd return (ALTERED); 13744336716bSAdrian Chadd } 13754336716bSAdrian Chadd if (reply("SALVAGE") == 0) { 13764336716bSAdrian Chadd idesc->id_fix = NOFIX; 13774336716bSAdrian Chadd return (0); 13784336716bSAdrian Chadd } 13794336716bSAdrian Chadd idesc->id_fix = FIX; 13804336716bSAdrian Chadd return (ALTERED); 13814336716bSAdrian Chadd 13824336716bSAdrian Chadd case FIX: 13834336716bSAdrian Chadd return (ALTERED); 13844336716bSAdrian Chadd 13854336716bSAdrian Chadd case NOFIX: 13864336716bSAdrian Chadd case IGNORE: 13874336716bSAdrian Chadd return (0); 13884336716bSAdrian Chadd 13894336716bSAdrian Chadd default: 13904336716bSAdrian Chadd errx(EEXIT, "UNKNOWN INODESC FIX MODE %d", idesc->id_fix); 13914336716bSAdrian Chadd } 13924336716bSAdrian Chadd /* NOTREACHED */ 13934336716bSAdrian Chadd return (0); 13944336716bSAdrian Chadd } 13954336716bSAdrian Chadd 13964336716bSAdrian Chadd #include <stdarg.h> 13974336716bSAdrian Chadd 13984336716bSAdrian Chadd /* 13995cc52631SKirk McKusick * Print details about a buffer. 14005cc52631SKirk McKusick */ 1401460ed610SKirk McKusick void 1402460ed610SKirk McKusick prtbuf(struct bufarea *bp, const char *fmt, ...) 14035cc52631SKirk McKusick { 1404460ed610SKirk McKusick va_list ap; 1405460ed610SKirk McKusick va_start(ap, fmt); 1406460ed610SKirk McKusick if (preen) 1407460ed610SKirk McKusick (void)fprintf(stdout, "%s: ", cdevname); 1408460ed610SKirk McKusick (void)vfprintf(stdout, fmt, ap); 1409460ed610SKirk McKusick va_end(ap); 1410460ed610SKirk McKusick printf(": bp %p, type %s, bno %jd, size %d, refcnt %d, flags %s, " 1411460ed610SKirk McKusick "index %jd\n", bp, BT_BUFTYPE(bp->b_type), (intmax_t) bp->b_bno, 1412460ed610SKirk McKusick bp->b_size, bp->b_refcnt, bp->b_flags & B_DIRTY ? "dirty" : "clean", 1413460ed610SKirk McKusick (intmax_t) bp->b_index); 14145cc52631SKirk McKusick } 14155cc52631SKirk McKusick 14165cc52631SKirk McKusick /* 14174b85a12fSUlrich Spörlein * An unexpected inconsistency occurred. 14184336716bSAdrian Chadd * Die if preening or file system is running with soft dependency protocol, 14194336716bSAdrian Chadd * otherwise just print message and continue. 14204336716bSAdrian Chadd */ 14214336716bSAdrian Chadd void 14224336716bSAdrian Chadd pfatal(const char *fmt, ...) 14234336716bSAdrian Chadd { 14244336716bSAdrian Chadd va_list ap; 14254336716bSAdrian Chadd va_start(ap, fmt); 14264336716bSAdrian Chadd if (!preen) { 142715fca934SKirk McKusick (void)vfprintf(stdout, fmt, ap); 14284336716bSAdrian Chadd va_end(ap); 14294336716bSAdrian Chadd if (usedsoftdep) 143015fca934SKirk McKusick (void)fprintf(stdout, 14314336716bSAdrian Chadd "\nUNEXPECTED SOFT UPDATE INCONSISTENCY\n"); 143238375c40SKirk McKusick /* 143338375c40SKirk McKusick * Force foreground fsck to clean up inconsistency. 143438375c40SKirk McKusick */ 143538375c40SKirk McKusick if (bkgrdflag) { 143638375c40SKirk McKusick cmd.value = FS_NEEDSFSCK; 143738375c40SKirk McKusick cmd.size = 1; 143838375c40SKirk McKusick if (sysctlbyname("vfs.ffs.setflags", 0, 0, 143938375c40SKirk McKusick &cmd, sizeof cmd) == -1) 144038375c40SKirk McKusick pwarn("CANNOT SET FS_NEEDSFSCK FLAG\n"); 144115fca934SKirk McKusick fprintf(stdout, "CANNOT RUN IN BACKGROUND\n"); 144238375c40SKirk McKusick ckfini(0); 144338375c40SKirk McKusick exit(EEXIT); 144438375c40SKirk McKusick } 14454336716bSAdrian Chadd return; 14464336716bSAdrian Chadd } 14474336716bSAdrian Chadd if (cdevname == NULL) 1448599304a4SPoul-Henning Kamp cdevname = strdup("fsck"); 144915fca934SKirk McKusick (void)fprintf(stdout, "%s: ", cdevname); 145015fca934SKirk McKusick (void)vfprintf(stdout, fmt, ap); 145115fca934SKirk McKusick (void)fprintf(stdout, 14524336716bSAdrian Chadd "\n%s: UNEXPECTED%sINCONSISTENCY; RUN fsck MANUALLY.\n", 14534336716bSAdrian Chadd cdevname, usedsoftdep ? " SOFT UPDATE " : " "); 145438375c40SKirk McKusick /* 145538375c40SKirk McKusick * Force foreground fsck to clean up inconsistency. 145638375c40SKirk McKusick */ 145738375c40SKirk McKusick if (bkgrdflag) { 145838375c40SKirk McKusick cmd.value = FS_NEEDSFSCK; 145938375c40SKirk McKusick cmd.size = 1; 146038375c40SKirk McKusick if (sysctlbyname("vfs.ffs.setflags", 0, 0, 146138375c40SKirk McKusick &cmd, sizeof cmd) == -1) 146238375c40SKirk McKusick pwarn("CANNOT SET FS_NEEDSFSCK FLAG\n"); 146338375c40SKirk McKusick } 14644336716bSAdrian Chadd ckfini(0); 14654336716bSAdrian Chadd exit(EEXIT); 14664336716bSAdrian Chadd } 14674336716bSAdrian Chadd 14684336716bSAdrian Chadd /* 14694336716bSAdrian Chadd * Pwarn just prints a message when not preening or running soft dependency 14704336716bSAdrian Chadd * protocol, or a warning (preceded by filename) when preening. 14714336716bSAdrian Chadd */ 14724336716bSAdrian Chadd void 14734336716bSAdrian Chadd pwarn(const char *fmt, ...) 14744336716bSAdrian Chadd { 14754336716bSAdrian Chadd va_list ap; 14764336716bSAdrian Chadd va_start(ap, fmt); 14774336716bSAdrian Chadd if (preen) 147815fca934SKirk McKusick (void)fprintf(stdout, "%s: ", cdevname); 147915fca934SKirk McKusick (void)vfprintf(stdout, fmt, ap); 14804336716bSAdrian Chadd va_end(ap); 14814336716bSAdrian Chadd } 14824336716bSAdrian Chadd 14834336716bSAdrian Chadd /* 14844336716bSAdrian Chadd * Stub for routines from kernel. 14854336716bSAdrian Chadd */ 14864336716bSAdrian Chadd void 14874336716bSAdrian Chadd panic(const char *fmt, ...) 14884336716bSAdrian Chadd { 14894336716bSAdrian Chadd va_list ap; 14904336716bSAdrian Chadd va_start(ap, fmt); 14914336716bSAdrian Chadd pfatal("INTERNAL INCONSISTENCY:"); 149215fca934SKirk McKusick (void)vfprintf(stdout, fmt, ap); 14934336716bSAdrian Chadd va_end(ap); 14944336716bSAdrian Chadd exit(EEXIT); 14954336716bSAdrian Chadd } 1496