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> 38c69284caSDavid E. O'Brien __FBSDID("$FreeBSD$"); 394336716bSAdrian Chadd 404336716bSAdrian Chadd #include <sys/param.h> 419d580d7cSIan Dowse #include <sys/time.h> 424336716bSAdrian Chadd #include <sys/types.h> 43bf58d635SIan Dowse #include <sys/sysctl.h> 448d3dfc26SDag-Erling Smørgrav #include <sys/disk.h> 451c85e6a3SKirk McKusick #include <sys/disklabel.h> 468d3dfc26SDag-Erling Smørgrav #include <sys/ioctl.h> 474336716bSAdrian Chadd #include <sys/stat.h> 484336716bSAdrian Chadd 494336716bSAdrian Chadd #include <ufs/ufs/dinode.h> 504336716bSAdrian Chadd #include <ufs/ufs/dir.h> 514336716bSAdrian Chadd #include <ufs/ffs/fs.h> 524336716bSAdrian Chadd 534336716bSAdrian Chadd #include <err.h> 544336716bSAdrian Chadd #include <errno.h> 554336716bSAdrian Chadd #include <string.h> 564336716bSAdrian Chadd #include <ctype.h> 574336716bSAdrian Chadd #include <fstab.h> 5884fc0d7eSMaxime Henrion #include <stdint.h> 594336716bSAdrian Chadd #include <stdio.h> 604336716bSAdrian Chadd #include <stdlib.h> 61ed75b5a1SKirk McKusick #include <time.h> 624336716bSAdrian Chadd #include <unistd.h> 6375e3597aSKirk McKusick #include <libufs.h> 644336716bSAdrian Chadd 654336716bSAdrian Chadd #include "fsck.h" 664336716bSAdrian Chadd 675cc52631SKirk McKusick int sujrecovery = 0; 685cc52631SKirk McKusick 695cc52631SKirk McKusick static struct bufarea *allocbuf(const char *); 705cc52631SKirk McKusick static void cg_write(struct bufarea *); 719d580d7cSIan Dowse static void slowio_start(void); 729d580d7cSIan Dowse static void slowio_end(void); 73ed75b5a1SKirk McKusick static void printIOstats(void); 745cc52631SKirk McKusick static void prtbuf(const char *, struct bufarea *); 759d580d7cSIan Dowse 76ed75b5a1SKirk McKusick static long diskreads, totaldiskreads, totalreads; /* Disk cache statistics */ 77ed75b5a1SKirk McKusick static struct timespec startpass, finishpass; 789d580d7cSIan Dowse struct timeval slowio_starttime; 799d580d7cSIan Dowse int slowio_delay_usec = 10000; /* Initial IO delay for background fsck */ 809d580d7cSIan Dowse int slowio_pollcnt; 8181fbded2SKirk McKusick static struct bufarea cgblk; /* backup buffer for cylinder group blocks */ 825cc52631SKirk McKusick static TAILQ_HEAD(bufqueue, bufarea) bufqueuehd; /* head of buffer cache LRU */ 835cc52631SKirk McKusick static LIST_HEAD(bufhash, bufarea) bufhashhd[HASHSIZE]; /* buffer hash list */ 842ec5c914SKirk McKusick static int numbufs; /* size of buffer cache */ 855cc52631SKirk McKusick static int cachelookups; /* number of cache lookups */ 865cc52631SKirk McKusick static int cachereads; /* number of cache reads */ 877703a6ffSScott Long static int flushtries; /* number of tries to reclaim memory */ 887703a6ffSScott Long 895cc52631SKirk McKusick char *buftype[BT_NUMBUFTYPES] = BT_NAMES; 905cc52631SKirk McKusick 917703a6ffSScott Long void 927703a6ffSScott Long fsutilinit(void) 937703a6ffSScott Long { 947703a6ffSScott Long diskreads = totaldiskreads = totalreads = 0; 957703a6ffSScott Long bzero(&startpass, sizeof(struct timespec)); 967703a6ffSScott Long bzero(&finishpass, sizeof(struct timespec)); 977703a6ffSScott Long bzero(&slowio_starttime, sizeof(struct timeval)); 987703a6ffSScott Long slowio_delay_usec = 10000; 997703a6ffSScott Long slowio_pollcnt = 0; 1007703a6ffSScott Long flushtries = 0; 1017703a6ffSScott Long } 1024336716bSAdrian Chadd 1034336716bSAdrian Chadd int 1041c85e6a3SKirk McKusick ftypeok(union dinode *dp) 1054336716bSAdrian Chadd { 106d8ba45e2SEd Maste switch (DIP(dp, di_mode) & IFMT) { 1074336716bSAdrian Chadd 108d8ba45e2SEd Maste case IFDIR: 109d8ba45e2SEd Maste case IFREG: 110d8ba45e2SEd Maste case IFBLK: 111d8ba45e2SEd Maste case IFCHR: 112d8ba45e2SEd Maste case IFLNK: 113d8ba45e2SEd Maste case IFSOCK: 114d8ba45e2SEd Maste case IFIFO: 1154336716bSAdrian Chadd return (1); 1164336716bSAdrian Chadd 1174336716bSAdrian Chadd default: 1184336716bSAdrian Chadd if (debug) 1191c85e6a3SKirk McKusick printf("bad file type 0%o\n", DIP(dp, di_mode)); 1204336716bSAdrian Chadd return (0); 1214336716bSAdrian Chadd } 1224336716bSAdrian Chadd } 1234336716bSAdrian Chadd 1244336716bSAdrian Chadd int 125599304a4SPoul-Henning Kamp reply(const char *question) 1264336716bSAdrian Chadd { 1274336716bSAdrian Chadd int persevere; 1284336716bSAdrian Chadd char c; 1294336716bSAdrian Chadd 1304336716bSAdrian Chadd if (preen) 1314336716bSAdrian Chadd pfatal("INTERNAL ERROR: GOT TO reply()"); 1324336716bSAdrian Chadd persevere = !strcmp(question, "CONTINUE"); 1334336716bSAdrian Chadd printf("\n"); 1347578c6abSKirk McKusick if (!persevere && (nflag || (fswritefd < 0 && bkgrdflag == 0))) { 1354336716bSAdrian Chadd printf("%s? no\n\n", question); 1364336716bSAdrian Chadd resolved = 0; 1374336716bSAdrian Chadd return (0); 1384336716bSAdrian Chadd } 1394336716bSAdrian Chadd if (yflag || (persevere && nflag)) { 1404336716bSAdrian Chadd printf("%s? yes\n\n", question); 1414336716bSAdrian Chadd return (1); 1424336716bSAdrian Chadd } 1434336716bSAdrian Chadd do { 1444336716bSAdrian Chadd printf("%s? [yn] ", question); 1454336716bSAdrian Chadd (void) fflush(stdout); 1464336716bSAdrian Chadd c = getc(stdin); 1474336716bSAdrian Chadd while (c != '\n' && getc(stdin) != '\n') { 1484336716bSAdrian Chadd if (feof(stdin)) { 1494336716bSAdrian Chadd resolved = 0; 1504336716bSAdrian Chadd return (0); 1514336716bSAdrian Chadd } 1524336716bSAdrian Chadd } 1534336716bSAdrian Chadd } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); 1544336716bSAdrian Chadd printf("\n"); 1554336716bSAdrian Chadd if (c == 'y' || c == 'Y') 1564336716bSAdrian Chadd return (1); 1574336716bSAdrian Chadd resolved = 0; 1584336716bSAdrian Chadd return (0); 1594336716bSAdrian Chadd } 1604336716bSAdrian Chadd 1614336716bSAdrian Chadd /* 1624336716bSAdrian Chadd * Look up state information for an inode. 1634336716bSAdrian Chadd */ 1644336716bSAdrian Chadd struct inostat * 165b70cd7eeSWarner Losh inoinfo(ino_t inum) 1664336716bSAdrian Chadd { 1674336716bSAdrian Chadd static struct inostat unallocated = { USTATE, 0, 0 }; 1684336716bSAdrian Chadd struct inostatlist *ilp; 1694336716bSAdrian Chadd int iloff; 1704336716bSAdrian Chadd 1714336716bSAdrian Chadd if (inum > maxino) 172623d7cb6SMatthew D Fleming errx(EEXIT, "inoinfo: inumber %ju out of range", 173623d7cb6SMatthew D Fleming (uintmax_t)inum); 1744336716bSAdrian Chadd ilp = &inostathead[inum / sblock.fs_ipg]; 1754336716bSAdrian Chadd iloff = inum % sblock.fs_ipg; 1764336716bSAdrian Chadd if (iloff >= ilp->il_numalloced) 1774336716bSAdrian Chadd return (&unallocated); 1784336716bSAdrian Chadd return (&ilp->il_stat[iloff]); 1794336716bSAdrian Chadd } 1804336716bSAdrian Chadd 1814336716bSAdrian Chadd /* 1824336716bSAdrian Chadd * Malloc buffers and set up cache. 1834336716bSAdrian Chadd */ 1844336716bSAdrian Chadd void 185b70cd7eeSWarner Losh bufinit(void) 1864336716bSAdrian Chadd { 1875cc52631SKirk McKusick int i; 1884336716bSAdrian Chadd 189fc56fd26SKirk McKusick if ((cgblk.b_un.b_buf = Malloc((unsigned int)sblock.fs_bsize)) == NULL) 1905cc52631SKirk McKusick errx(EEXIT, "Initial malloc(%d) failed", sblock.fs_bsize); 191ed75b5a1SKirk McKusick initbarea(&cgblk, BT_CYLGRP); 1925cc52631SKirk McKusick numbufs = cachelookups = cachereads = 0; 1935cc52631SKirk McKusick TAILQ_INIT(&bufqueuehd); 1945cc52631SKirk McKusick for (i = 0; i < HASHSIZE; i++) 1955cc52631SKirk McKusick LIST_INIT(&bufhashhd[i]); 196ed75b5a1SKirk McKusick for (i = 0; i < BT_NUMBUFTYPES; i++) { 197ed75b5a1SKirk McKusick readtime[i].tv_sec = totalreadtime[i].tv_sec = 0; 198ed75b5a1SKirk McKusick readtime[i].tv_nsec = totalreadtime[i].tv_nsec = 0; 199ed75b5a1SKirk McKusick readcnt[i] = totalreadcnt[i] = 0; 200ed75b5a1SKirk McKusick } 2014336716bSAdrian Chadd } 2024336716bSAdrian Chadd 2035cc52631SKirk McKusick static struct bufarea * 2045cc52631SKirk McKusick allocbuf(const char *failreason) 2055cc52631SKirk McKusick { 2065cc52631SKirk McKusick struct bufarea *bp; 2075cc52631SKirk McKusick char *bufp; 2085cc52631SKirk McKusick 2095cc52631SKirk McKusick bp = (struct bufarea *)Malloc(sizeof(struct bufarea)); 2105cc52631SKirk McKusick bufp = Malloc((unsigned int)sblock.fs_bsize); 2115cc52631SKirk McKusick if (bp == NULL || bufp == NULL) { 2125cc52631SKirk McKusick errx(EEXIT, "%s", failreason); 2135cc52631SKirk McKusick /* NOTREACHED */ 2145cc52631SKirk McKusick } 2155cc52631SKirk McKusick numbufs++; 2165cc52631SKirk McKusick bp->b_un.b_buf = bufp; 2175cc52631SKirk McKusick TAILQ_INSERT_HEAD(&bufqueuehd, bp, b_list); 2185cc52631SKirk McKusick initbarea(bp, BT_UNKNOWN); 2195cc52631SKirk McKusick return (bp); 2205cc52631SKirk McKusick } 2215cc52631SKirk McKusick 2224336716bSAdrian Chadd /* 22381fbded2SKirk McKusick * Manage cylinder group buffers. 22485ee267aSKirk McKusick * 22585ee267aSKirk McKusick * Use getblk() here rather than cgget() because the cylinder group 22685ee267aSKirk McKusick * may be corrupted but we want it anyway so we can fix it. 22781fbded2SKirk McKusick */ 22881fbded2SKirk McKusick static struct bufarea *cgbufs; /* header for cylinder group cache */ 22981fbded2SKirk McKusick static int flushtries; /* number of tries to reclaim memory */ 23081fbded2SKirk McKusick 23181fbded2SKirk McKusick struct bufarea * 232957fc241SKirk McKusick cglookup(int cg) 23381fbded2SKirk McKusick { 23481fbded2SKirk McKusick struct bufarea *cgbp; 23581fbded2SKirk McKusick struct cg *cgp; 23681fbded2SKirk McKusick 2375cc52631SKirk McKusick if ((unsigned) cg >= sblock.fs_ncg) 2385cc52631SKirk McKusick errx(EEXIT, "cglookup: out of range cylinder group %d", cg); 23981fbded2SKirk McKusick if (cgbufs == NULL) { 240eff68496SKirk McKusick cgbufs = calloc(sblock.fs_ncg, sizeof(struct bufarea)); 24181fbded2SKirk McKusick if (cgbufs == NULL) 2425cc52631SKirk McKusick errx(EEXIT, "Cannot allocate cylinder group buffers"); 24381fbded2SKirk McKusick } 24481fbded2SKirk McKusick cgbp = &cgbufs[cg]; 24581fbded2SKirk McKusick if (cgbp->b_un.b_cg != NULL) 24681fbded2SKirk McKusick return (cgbp); 24781fbded2SKirk McKusick cgp = NULL; 24881fbded2SKirk McKusick if (flushtries == 0) 2495cc52631SKirk McKusick cgp = Malloc((unsigned int)sblock.fs_cgsize); 25081fbded2SKirk McKusick if (cgp == NULL) { 2515cc52631SKirk McKusick if (sujrecovery) 2525cc52631SKirk McKusick errx(EEXIT,"Ran out of memory during journal recovery"); 25381fbded2SKirk McKusick getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize); 25481fbded2SKirk McKusick return (&cgblk); 25581fbded2SKirk McKusick } 25681fbded2SKirk McKusick cgbp->b_un.b_cg = cgp; 25781fbded2SKirk McKusick initbarea(cgbp, BT_CYLGRP); 25881fbded2SKirk McKusick getblk(cgbp, cgtod(&sblock, cg), sblock.fs_cgsize); 25981fbded2SKirk McKusick return (cgbp); 26081fbded2SKirk McKusick } 26181fbded2SKirk McKusick 26281fbded2SKirk McKusick /* 2638ebae128SKirk McKusick * Mark a cylinder group buffer as dirty. 2648ebae128SKirk McKusick * Update its check-hash if they are enabled. 2658ebae128SKirk McKusick */ 2668ebae128SKirk McKusick void 2678ebae128SKirk McKusick cgdirty(struct bufarea *cgbp) 2688ebae128SKirk McKusick { 2698ebae128SKirk McKusick struct cg *cg; 2708ebae128SKirk McKusick 2718ebae128SKirk McKusick cg = cgbp->b_un.b_cg; 2728ebae128SKirk McKusick if ((sblock.fs_metackhash & CK_CYLGRP) != 0) { 2738ebae128SKirk McKusick cg->cg_ckhash = 0; 2748ebae128SKirk McKusick cg->cg_ckhash = 2758ebae128SKirk McKusick calculate_crc32c(~0L, (void *)cg, sblock.fs_cgsize); 2768ebae128SKirk McKusick } 2778ebae128SKirk McKusick dirty(cgbp); 2788ebae128SKirk McKusick } 2798ebae128SKirk McKusick 2808ebae128SKirk McKusick /* 28181fbded2SKirk McKusick * Attempt to flush a cylinder group cache entry. 28281fbded2SKirk McKusick * Return whether the flush was successful. 28381fbded2SKirk McKusick */ 28481fbded2SKirk McKusick int 28581fbded2SKirk McKusick flushentry(void) 28681fbded2SKirk McKusick { 28781fbded2SKirk McKusick struct bufarea *cgbp; 28881fbded2SKirk McKusick 2895cc52631SKirk McKusick if (sujrecovery || flushtries == sblock.fs_ncg || cgbufs == NULL) 290eff68496SKirk McKusick return (0); 29181fbded2SKirk McKusick cgbp = &cgbufs[flushtries++]; 29281fbded2SKirk McKusick if (cgbp->b_un.b_cg == NULL) 29381fbded2SKirk McKusick return (0); 29481fbded2SKirk McKusick flush(fswritefd, cgbp); 29581fbded2SKirk McKusick free(cgbp->b_un.b_buf); 29681fbded2SKirk McKusick cgbp->b_un.b_buf = NULL; 29781fbded2SKirk McKusick return (1); 29881fbded2SKirk McKusick } 29981fbded2SKirk McKusick 30081fbded2SKirk McKusick /* 3014336716bSAdrian Chadd * Manage a cache of directory blocks. 3024336716bSAdrian Chadd */ 3034336716bSAdrian Chadd struct bufarea * 304ed75b5a1SKirk McKusick getdatablk(ufs2_daddr_t blkno, long size, int type) 3054336716bSAdrian Chadd { 3063d438ad6SDavid E. O'Brien struct bufarea *bp; 3075cc52631SKirk McKusick struct bufhash *bhdp; 3084336716bSAdrian Chadd 3095cc52631SKirk McKusick cachelookups++; 3105cc52631SKirk McKusick /* If out of range, return empty buffer with b_err == -1 */ 3115cc52631SKirk McKusick if (type != BT_INODES && chkrange(blkno, size / sblock.fs_fsize)) { 3125cc52631SKirk McKusick blkno = -1; 3135cc52631SKirk McKusick type = BT_EMPTY; 3145cc52631SKirk McKusick } 3155cc52631SKirk McKusick bhdp = &bufhashhd[HASH(blkno)]; 3165cc52631SKirk McKusick LIST_FOREACH(bp, bhdp, b_hash) 3175cc52631SKirk McKusick if (bp->b_bno == fsbtodb(&sblock, blkno)) { 3185cc52631SKirk McKusick if (debug && bp->b_size != size) { 3195cc52631SKirk McKusick prtbuf("getdatablk: size mismatch", bp); 3205cc52631SKirk McKusick pfatal("getdatablk: b_size %d != size %ld\n", 3215cc52631SKirk McKusick bp->b_size, size); 3225cc52631SKirk McKusick } 3234336716bSAdrian Chadd goto foundit; 3245cc52631SKirk McKusick } 3255cc52631SKirk McKusick /* 3265cc52631SKirk McKusick * Move long-term busy buffer back to the front of the LRU so we 3275cc52631SKirk McKusick * do not endless inspect them for recycling. 3285cc52631SKirk McKusick */ 3295cc52631SKirk McKusick bp = TAILQ_LAST(&bufqueuehd, bufqueue); 3305cc52631SKirk McKusick if (bp != NULL && bp->b_refcnt != 0) { 3315cc52631SKirk McKusick TAILQ_REMOVE(&bufqueuehd, bp, b_list); 3325cc52631SKirk McKusick TAILQ_INSERT_HEAD(&bufqueuehd, bp, b_list); 3335cc52631SKirk McKusick } 3345cc52631SKirk McKusick /* 3355cc52631SKirk McKusick * Allocate up to the minimum number of buffers before 3365cc52631SKirk McKusick * considering recycling any of them. 3375cc52631SKirk McKusick */ 3385cc52631SKirk McKusick if (size > sblock.fs_bsize) 3395cc52631SKirk McKusick errx(EEXIT, "Excessive buffer size %ld > %d\n", size, 3405cc52631SKirk McKusick sblock.fs_bsize); 3415cc52631SKirk McKusick if (numbufs < MINBUFS) { 3425cc52631SKirk McKusick bp = allocbuf("cannot create minimal buffer pool"); 3435cc52631SKirk McKusick } else if (sujrecovery) { 3445cc52631SKirk McKusick /* 3455cc52631SKirk McKusick * SUJ recovery does not want anything written until it 3465cc52631SKirk McKusick * has successfully completed (so it can fail back to 3475cc52631SKirk McKusick * full fsck). Thus, we can only recycle clean buffers. 3485cc52631SKirk McKusick */ 3495cc52631SKirk McKusick TAILQ_FOREACH_REVERSE(bp, &bufqueuehd, bufqueue, b_list) 3505cc52631SKirk McKusick if ((bp->b_flags & B_DIRTY) == 0 && bp->b_refcnt == 0) 3514336716bSAdrian Chadd break; 3522ec5c914SKirk McKusick if (bp == NULL) 3535cc52631SKirk McKusick bp = allocbuf("Ran out of memory during " 3545cc52631SKirk McKusick "journal recovery"); 3555cc52631SKirk McKusick else 3565cc52631SKirk McKusick LIST_REMOVE(bp, b_hash); 3575cc52631SKirk McKusick } else { 3585cc52631SKirk McKusick /* 3595cc52631SKirk McKusick * Recycle oldest non-busy buffer. 3605cc52631SKirk McKusick */ 3615cc52631SKirk McKusick TAILQ_FOREACH_REVERSE(bp, &bufqueuehd, bufqueue, b_list) 3625cc52631SKirk McKusick if (bp->b_refcnt == 0) 3635cc52631SKirk McKusick break; 3645cc52631SKirk McKusick if (bp == NULL) 3655cc52631SKirk McKusick bp = allocbuf("Ran out of memory for buffers"); 3665cc52631SKirk McKusick else 3675cc52631SKirk McKusick LIST_REMOVE(bp, b_hash); 3685cc52631SKirk McKusick } 3695cc52631SKirk McKusick flush(fswritefd, bp); 370ed75b5a1SKirk McKusick bp->b_type = type; 3715cc52631SKirk McKusick LIST_INSERT_HEAD(bhdp, bp, b_hash); 3724336716bSAdrian Chadd getblk(bp, blkno, size); 3735cc52631SKirk McKusick cachereads++; 3744336716bSAdrian Chadd /* fall through */ 3754336716bSAdrian Chadd foundit: 3765cc52631SKirk McKusick if (debug && bp->b_type != type) { 3775cc52631SKirk McKusick printf("getdatablk: buffer type changed to %s", 3785cc52631SKirk McKusick BT_BUFTYPE(type)); 3795cc52631SKirk McKusick prtbuf("", bp); 3805cc52631SKirk McKusick } 3815cc52631SKirk McKusick TAILQ_REMOVE(&bufqueuehd, bp, b_list); 3825cc52631SKirk McKusick TAILQ_INSERT_HEAD(&bufqueuehd, bp, b_list); 3835cc52631SKirk McKusick if (bp->b_errs == 0) 3845cc52631SKirk McKusick bp->b_refcnt++; 3854336716bSAdrian Chadd return (bp); 3864336716bSAdrian Chadd } 3874336716bSAdrian Chadd 3884336716bSAdrian Chadd void 3891c85e6a3SKirk McKusick getblk(struct bufarea *bp, ufs2_daddr_t blk, long size) 3904336716bSAdrian Chadd { 3911c85e6a3SKirk McKusick ufs2_daddr_t dblk; 392ed75b5a1SKirk McKusick struct timespec start, finish; 3934336716bSAdrian Chadd 3944336716bSAdrian Chadd dblk = fsbtodb(&sblock, blk); 395ed75b5a1SKirk McKusick if (bp->b_bno == dblk) { 396ed75b5a1SKirk McKusick totalreads++; 397ed75b5a1SKirk McKusick } else { 398ed75b5a1SKirk McKusick if (debug) { 399ed75b5a1SKirk McKusick readcnt[bp->b_type]++; 400ed75b5a1SKirk McKusick clock_gettime(CLOCK_REALTIME_PRECISE, &start); 401ed75b5a1SKirk McKusick } 4025cc52631SKirk McKusick if (bp->b_type != BT_EMPTY) 4035cc52631SKirk McKusick bp->b_errs = 4045cc52631SKirk McKusick blread(fsreadfd, bp->b_un.b_buf, dblk, size); 4055cc52631SKirk McKusick else 4065cc52631SKirk McKusick bp->b_errs = -1; 407ed75b5a1SKirk McKusick if (debug) { 408ed75b5a1SKirk McKusick clock_gettime(CLOCK_REALTIME_PRECISE, &finish); 4096040822cSAlan Somers timespecsub(&finish, &start, &finish); 4106040822cSAlan Somers timespecadd(&readtime[bp->b_type], &finish, 4116040822cSAlan Somers &readtime[bp->b_type]); 412ed75b5a1SKirk McKusick } 4134336716bSAdrian Chadd bp->b_bno = dblk; 4144336716bSAdrian Chadd bp->b_size = size; 4154336716bSAdrian Chadd } 4164336716bSAdrian Chadd } 4174336716bSAdrian Chadd 4184336716bSAdrian Chadd void 4195cc52631SKirk McKusick brelse(struct bufarea *bp) 4204336716bSAdrian Chadd { 4214336716bSAdrian Chadd 4225cc52631SKirk McKusick if (bp->b_refcnt <= 0) 4235cc52631SKirk McKusick prtbuf("brelse: buffer with negative reference count", bp); 4245cc52631SKirk McKusick bp->b_refcnt--; 4255cc52631SKirk McKusick } 4265cc52631SKirk McKusick 4275cc52631SKirk McKusick void 4285cc52631SKirk McKusick flush(int fd, struct bufarea *bp) 4295cc52631SKirk McKusick { 4305cc52631SKirk McKusick struct inode ip; 4315cc52631SKirk McKusick 4325cc52631SKirk McKusick if ((bp->b_flags & B_DIRTY) == 0) 4334336716bSAdrian Chadd return; 4345cc52631SKirk McKusick bp->b_flags &= ~B_DIRTY; 4357578c6abSKirk McKusick if (fswritefd < 0) { 4367578c6abSKirk McKusick pfatal("WRITING IN READ_ONLY MODE.\n"); 4377578c6abSKirk McKusick return; 4387578c6abSKirk McKusick } 4394336716bSAdrian Chadd if (bp->b_errs != 0) 440599304a4SPoul-Henning Kamp pfatal("WRITING %sZERO'ED BLOCK %lld TO DISK\n", 4414336716bSAdrian Chadd (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", 442599304a4SPoul-Henning Kamp (long long)bp->b_bno); 4434336716bSAdrian Chadd bp->b_errs = 0; 444a6bbdf81SKirk McKusick /* 445a6bbdf81SKirk McKusick * Write using the appropriate function. 446a6bbdf81SKirk McKusick */ 447a6bbdf81SKirk McKusick switch (bp->b_type) { 448a6bbdf81SKirk McKusick case BT_SUPERBLK: 4494336716bSAdrian Chadd if (bp != &sblk) 450af89fcf7SLi-Wen Hsu pfatal("BUFFER %p DOES NOT MATCH SBLK %p\n", 451af89fcf7SLi-Wen Hsu bp, &sblk); 4528ebae128SKirk McKusick if (sbput(fd, bp->b_un.b_fs, 0) == 0) 453dffce215SKirk McKusick fsmodified = 1; 454a6bbdf81SKirk McKusick break; 455a6bbdf81SKirk McKusick case BT_CYLGRP: 4565cc52631SKirk McKusick if (sujrecovery) 4575cc52631SKirk McKusick cg_write(bp); 45885ee267aSKirk McKusick if (cgput(fswritefd, &sblock, bp->b_un.b_cg) == 0) 459a6bbdf81SKirk McKusick fsmodified = 1; 460a6bbdf81SKirk McKusick break; 4615cc52631SKirk McKusick case BT_INODES: 4625cc52631SKirk McKusick if (debug && sblock.fs_magic == FS_UFS2_MAGIC) { 4635cc52631SKirk McKusick struct ufs2_dinode *dp = bp->b_un.b_dinode2; 4645cc52631SKirk McKusick int i; 4655cc52631SKirk McKusick 4665cc52631SKirk McKusick for (i = 0; i < INOPB(&sblock); dp++, i++) { 4675cc52631SKirk McKusick if (ffs_verify_dinode_ckhash(&sblock, dp) == 0) 4685cc52631SKirk McKusick continue; 4695cc52631SKirk McKusick pwarn("flush: INODE CHECK-HASH FAILED"); 4705cc52631SKirk McKusick ip.i_bp = bp; 4715cc52631SKirk McKusick ip.i_dp = (union dinode *)dp; 4725cc52631SKirk McKusick ip.i_number = bp->b_index + i; 4735cc52631SKirk McKusick prtinode(&ip); 4745cc52631SKirk McKusick if (preen || reply("FIX") != 0) { 4755cc52631SKirk McKusick if (preen) 4765cc52631SKirk McKusick printf(" (FIXED)\n"); 4775cc52631SKirk McKusick ffs_update_dinode_ckhash(&sblock, dp); 4785cc52631SKirk McKusick inodirty(&ip); 4795cc52631SKirk McKusick } 4805cc52631SKirk McKusick } 4815cc52631SKirk McKusick } 4825cc52631SKirk McKusick /* FALLTHROUGH */ 483a6bbdf81SKirk McKusick default: 484a6bbdf81SKirk McKusick blwrite(fd, bp->b_un.b_buf, bp->b_bno, bp->b_size); 485a6bbdf81SKirk McKusick break; 486a6bbdf81SKirk McKusick } 4874336716bSAdrian Chadd } 4884336716bSAdrian Chadd 4895cc52631SKirk McKusick /* 4905cc52631SKirk McKusick * Journaled soft updates does not maintain cylinder group summary 4915cc52631SKirk McKusick * information during cleanup, so this routine recalculates the summary 4925cc52631SKirk McKusick * information and updates the superblock summary in preparation for 4935cc52631SKirk McKusick * writing out the cylinder group. 4945cc52631SKirk McKusick */ 4955cc52631SKirk McKusick static void 4965cc52631SKirk McKusick cg_write(struct bufarea *bp) 4975cc52631SKirk McKusick { 4985cc52631SKirk McKusick ufs1_daddr_t fragno, cgbno, maxbno; 4995cc52631SKirk McKusick u_int8_t *blksfree; 5005cc52631SKirk McKusick struct cg *cgp; 5015cc52631SKirk McKusick int blk; 5025cc52631SKirk McKusick int i; 5035cc52631SKirk McKusick 5045cc52631SKirk McKusick /* 5055cc52631SKirk McKusick * Fix the frag and cluster summary. 5065cc52631SKirk McKusick */ 5075cc52631SKirk McKusick cgp = bp->b_un.b_cg; 5085cc52631SKirk McKusick cgp->cg_cs.cs_nbfree = 0; 5095cc52631SKirk McKusick cgp->cg_cs.cs_nffree = 0; 5105cc52631SKirk McKusick bzero(&cgp->cg_frsum, sizeof(cgp->cg_frsum)); 5115cc52631SKirk McKusick maxbno = fragstoblks(&sblock, sblock.fs_fpg); 5125cc52631SKirk McKusick if (sblock.fs_contigsumsize > 0) { 5135cc52631SKirk McKusick for (i = 1; i <= sblock.fs_contigsumsize; i++) 5145cc52631SKirk McKusick cg_clustersum(cgp)[i] = 0; 5155cc52631SKirk McKusick bzero(cg_clustersfree(cgp), howmany(maxbno, CHAR_BIT)); 5165cc52631SKirk McKusick } 5175cc52631SKirk McKusick blksfree = cg_blksfree(cgp); 5185cc52631SKirk McKusick for (cgbno = 0; cgbno < maxbno; cgbno++) { 5195cc52631SKirk McKusick if (ffs_isfreeblock(&sblock, blksfree, cgbno)) 5205cc52631SKirk McKusick continue; 5215cc52631SKirk McKusick if (ffs_isblock(&sblock, blksfree, cgbno)) { 5225cc52631SKirk McKusick ffs_clusteracct(&sblock, cgp, cgbno, 1); 5235cc52631SKirk McKusick cgp->cg_cs.cs_nbfree++; 5245cc52631SKirk McKusick continue; 5255cc52631SKirk McKusick } 5265cc52631SKirk McKusick fragno = blkstofrags(&sblock, cgbno); 5275cc52631SKirk McKusick blk = blkmap(&sblock, blksfree, fragno); 5285cc52631SKirk McKusick ffs_fragacct(&sblock, blk, cgp->cg_frsum, 1); 5295cc52631SKirk McKusick for (i = 0; i < sblock.fs_frag; i++) 5305cc52631SKirk McKusick if (isset(blksfree, fragno + i)) 5315cc52631SKirk McKusick cgp->cg_cs.cs_nffree++; 5325cc52631SKirk McKusick } 5335cc52631SKirk McKusick /* 5345cc52631SKirk McKusick * Update the superblock cg summary from our now correct values 5355cc52631SKirk McKusick * before writing the block. 5365cc52631SKirk McKusick */ 5375cc52631SKirk McKusick sblock.fs_cs(&sblock, cgp->cg_cgx) = cgp->cg_cs; 5385cc52631SKirk McKusick } 5395cc52631SKirk McKusick 5407578c6abSKirk McKusick void 541599304a4SPoul-Henning Kamp rwerror(const char *mesg, ufs2_daddr_t blk) 5424336716bSAdrian Chadd { 5434336716bSAdrian Chadd 54415fca934SKirk McKusick if (bkgrdcheck) 54515fca934SKirk McKusick exit(EEXIT); 5464336716bSAdrian Chadd if (preen == 0) 5474336716bSAdrian Chadd printf("\n"); 548bf58d635SIan Dowse pfatal("CANNOT %s: %ld", mesg, (long)blk); 5494336716bSAdrian Chadd if (reply("CONTINUE") == 0) 5504336716bSAdrian Chadd exit(EEXIT); 5514336716bSAdrian Chadd } 5524336716bSAdrian Chadd 5534336716bSAdrian Chadd void 554b70cd7eeSWarner Losh ckfini(int markclean) 5554336716bSAdrian Chadd { 5563d438ad6SDavid E. O'Brien struct bufarea *bp, *nbp; 557fc56fd26SKirk McKusick struct inoinfo *inp, *ninp; 558fc56fd26SKirk McKusick int ofsmodified, cnt, cg, i; 5594336716bSAdrian Chadd 5607578c6abSKirk McKusick if (bkgrdflag) { 5617578c6abSKirk McKusick unlink(snapname); 5627578c6abSKirk McKusick if ((!(sblock.fs_flags & FS_UNCLEAN)) != markclean) { 5637578c6abSKirk McKusick cmd.value = FS_UNCLEAN; 5647578c6abSKirk McKusick cmd.size = markclean ? -1 : 1; 5657578c6abSKirk McKusick if (sysctlbyname("vfs.ffs.setflags", 0, 0, 5667578c6abSKirk McKusick &cmd, sizeof cmd) == -1) 5677578c6abSKirk McKusick rwerror("SET FILE SYSTEM FLAGS", FS_UNCLEAN); 5687578c6abSKirk McKusick if (!preen) { 5697578c6abSKirk McKusick printf("\n***** FILE SYSTEM MARKED %s *****\n", 5707578c6abSKirk McKusick markclean ? "CLEAN" : "DIRTY"); 5717578c6abSKirk McKusick if (!markclean) 5727578c6abSKirk McKusick rerun = 1; 5737578c6abSKirk McKusick } 5747578c6abSKirk McKusick } else if (!preen && !markclean) { 5757578c6abSKirk McKusick printf("\n***** FILE SYSTEM STILL DIRTY *****\n"); 5767578c6abSKirk McKusick rerun = 1; 5777578c6abSKirk McKusick } 5787578c6abSKirk McKusick } 5792ec5c914SKirk McKusick if (debug && totalreads > 0) 5805cc52631SKirk McKusick printf("cache with %d buffers missed %d of %d (%d%%)\n", 5815cc52631SKirk McKusick numbufs, cachereads, cachelookups, 5825cc52631SKirk McKusick (int)(cachereads * 100 / cachelookups)); 5834336716bSAdrian Chadd if (fswritefd < 0) { 5844336716bSAdrian Chadd (void)close(fsreadfd); 5854336716bSAdrian Chadd return; 5864336716bSAdrian Chadd } 5875cc52631SKirk McKusick /* 5885cc52631SKirk McKusick * To remain idempotent with partial truncations the buffers 5895cc52631SKirk McKusick * must be flushed in this order: 5905cc52631SKirk McKusick * 1) cylinder groups (bitmaps) 5915cc52631SKirk McKusick * 2) indirect, directory, external attribute, and data blocks 5925cc52631SKirk McKusick * 3) inode blocks 5935cc52631SKirk McKusick * 4) superblock 5945cc52631SKirk McKusick * This ordering preserves access to the modified pointers 5955cc52631SKirk McKusick * until they are freed. 5965cc52631SKirk McKusick */ 5975cc52631SKirk McKusick /* Step 1: cylinder groups */ 5985cc52631SKirk McKusick if (debug) 5995cc52631SKirk McKusick printf("Flush Cylinder groups\n"); 6005cc52631SKirk McKusick if (cgbufs != NULL) { 6015cc52631SKirk McKusick for (cnt = 0; cnt < sblock.fs_ncg; cnt++) { 6025cc52631SKirk McKusick if (cgbufs[cnt].b_un.b_cg == NULL) 6035cc52631SKirk McKusick continue; 6045cc52631SKirk McKusick flush(fswritefd, &cgbufs[cnt]); 6055cc52631SKirk McKusick free(cgbufs[cnt].b_un.b_cg); 6065cc52631SKirk McKusick } 6075cc52631SKirk McKusick free(cgbufs); 608fc56fd26SKirk McKusick cgbufs = NULL; 6095cc52631SKirk McKusick } 6105cc52631SKirk McKusick flush(fswritefd, &cgblk); 6115cc52631SKirk McKusick free(cgblk.b_un.b_buf); 612fc56fd26SKirk McKusick cgblk.b_un.b_buf = NULL; 6135cc52631SKirk McKusick cnt = 0; 6145cc52631SKirk McKusick /* Step 2: indirect, directory, external attribute, and data blocks */ 6155cc52631SKirk McKusick if (debug) 6165cc52631SKirk McKusick printf("Flush indirect, directory, external attribute, " 6175cc52631SKirk McKusick "and data blocks\n"); 618fc56fd26SKirk McKusick if (pdirbp != NULL) { 6195cc52631SKirk McKusick brelse(pdirbp); 620fc56fd26SKirk McKusick pdirbp = NULL; 621fc56fd26SKirk McKusick } 6225cc52631SKirk McKusick TAILQ_FOREACH_REVERSE_SAFE(bp, &bufqueuehd, bufqueue, b_list, nbp) { 6235cc52631SKirk McKusick switch (bp->b_type) { 6245cc52631SKirk McKusick /* These should not be in the buffer cache list */ 6255cc52631SKirk McKusick case BT_UNKNOWN: 6265cc52631SKirk McKusick case BT_SUPERBLK: 6275cc52631SKirk McKusick case BT_CYLGRP: 6285cc52631SKirk McKusick default: 6295cc52631SKirk McKusick prtbuf("ckfini: improper buffer type on cache list",bp); 6305cc52631SKirk McKusick continue; 6315cc52631SKirk McKusick /* These are the ones to flush in this step */ 6325cc52631SKirk McKusick case BT_EMPTY: 6335cc52631SKirk McKusick if (bp->b_bno >= 0) 6345cc52631SKirk McKusick pfatal("Unused BT_EMPTY buffer for block %jd\n", 6355cc52631SKirk McKusick (intmax_t)bp->b_bno); 6365cc52631SKirk McKusick /* FALLTHROUGH */ 6375cc52631SKirk McKusick case BT_LEVEL1: 6385cc52631SKirk McKusick case BT_LEVEL2: 6395cc52631SKirk McKusick case BT_LEVEL3: 6405cc52631SKirk McKusick case BT_EXTATTR: 6415cc52631SKirk McKusick case BT_DIRDATA: 6425cc52631SKirk McKusick case BT_DATA: 6435cc52631SKirk McKusick break; 6445cc52631SKirk McKusick /* These are the ones to flush in the next step */ 6455cc52631SKirk McKusick case BT_INODES: 6465cc52631SKirk McKusick continue; 6475cc52631SKirk McKusick } 6485cc52631SKirk McKusick if (debug && bp->b_refcnt != 0) { 6495cc52631SKirk McKusick prtbuf("ckfini: clearing in-use buffer", bp); 6505cc52631SKirk McKusick pfatal("ckfini: clearing in-use buffer\n"); 6515cc52631SKirk McKusick } 6525cc52631SKirk McKusick TAILQ_REMOVE(&bufqueuehd, bp, b_list); 6535cc52631SKirk McKusick cnt++; 6545cc52631SKirk McKusick flush(fswritefd, bp); 6555cc52631SKirk McKusick free(bp->b_un.b_buf); 6565cc52631SKirk McKusick free((char *)bp); 6575cc52631SKirk McKusick } 6585cc52631SKirk McKusick /* Step 3: inode blocks */ 6595cc52631SKirk McKusick if (debug) 6605cc52631SKirk McKusick printf("Flush inode blocks\n"); 661fc56fd26SKirk McKusick if (icachebp != NULL) { 6625cc52631SKirk McKusick brelse(icachebp); 663fc56fd26SKirk McKusick icachebp = NULL; 664fc56fd26SKirk McKusick } 6655cc52631SKirk McKusick TAILQ_FOREACH_REVERSE_SAFE(bp, &bufqueuehd, bufqueue, b_list, nbp) { 6665cc52631SKirk McKusick if (debug && bp->b_refcnt != 0) { 6675cc52631SKirk McKusick prtbuf("ckfini: clearing in-use buffer", bp); 6685cc52631SKirk McKusick pfatal("ckfini: clearing in-use buffer\n"); 6695cc52631SKirk McKusick } 6705cc52631SKirk McKusick TAILQ_REMOVE(&bufqueuehd, bp, b_list); 6715cc52631SKirk McKusick cnt++; 6725cc52631SKirk McKusick flush(fswritefd, bp); 6735cc52631SKirk McKusick free(bp->b_un.b_buf); 6745cc52631SKirk McKusick free((char *)bp); 6755cc52631SKirk McKusick } 6765cc52631SKirk McKusick if (numbufs != cnt) 6775cc52631SKirk McKusick errx(EEXIT, "panic: lost %d buffers", numbufs - cnt); 6785cc52631SKirk McKusick /* Step 4: superblock */ 6795cc52631SKirk McKusick if (debug) 6805cc52631SKirk McKusick printf("Flush the superblock\n"); 6814336716bSAdrian Chadd flush(fswritefd, &sblk); 6821c85e6a3SKirk McKusick if (havesb && cursnapshot == 0 && sblock.fs_magic == FS_UFS2_MAGIC && 683ada981b2SKirk McKusick sblk.b_bno != sblock.fs_sblockloc / dev_bsize && 6844336716bSAdrian Chadd !preen && reply("UPDATE STANDARD SUPERBLOCK")) { 685dffce215SKirk McKusick /* Change the write destination to standard superblock */ 686dffce215SKirk McKusick sblock.fs_sblockactualloc = sblock.fs_sblockloc; 687ada981b2SKirk McKusick sblk.b_bno = sblock.fs_sblockloc / dev_bsize; 6884336716bSAdrian Chadd sbdirty(); 6894336716bSAdrian Chadd flush(fswritefd, &sblk); 6904336716bSAdrian Chadd } 6917578c6abSKirk McKusick if (cursnapshot == 0 && sblock.fs_clean != markclean) { 69268aff084SKirk McKusick if ((sblock.fs_clean = markclean) != 0) { 69338375c40SKirk McKusick sblock.fs_flags &= ~(FS_UNCLEAN | FS_NEEDSFSCK); 69468aff084SKirk McKusick sblock.fs_pendingblocks = 0; 69568aff084SKirk McKusick sblock.fs_pendinginodes = 0; 69668aff084SKirk McKusick } 6974336716bSAdrian Chadd sbdirty(); 6984336716bSAdrian Chadd ofsmodified = fsmodified; 6994336716bSAdrian Chadd flush(fswritefd, &sblk); 7004336716bSAdrian Chadd fsmodified = ofsmodified; 7014336716bSAdrian Chadd if (!preen) { 7024336716bSAdrian Chadd printf("\n***** FILE SYSTEM MARKED %s *****\n", 7034336716bSAdrian Chadd markclean ? "CLEAN" : "DIRTY"); 7044336716bSAdrian Chadd if (!markclean) 7054336716bSAdrian Chadd rerun = 1; 7064336716bSAdrian Chadd } 707910b491eSKirk McKusick } else if (!preen) { 708910b491eSKirk McKusick if (markclean) { 709910b491eSKirk McKusick printf("\n***** FILE SYSTEM IS CLEAN *****\n"); 710910b491eSKirk McKusick } else { 7114336716bSAdrian Chadd printf("\n***** FILE SYSTEM STILL DIRTY *****\n"); 7124336716bSAdrian Chadd rerun = 1; 7134336716bSAdrian Chadd } 714910b491eSKirk McKusick } 715fc56fd26SKirk McKusick /* 716fc56fd26SKirk McKusick * Free allocated tracking structures. 717fc56fd26SKirk McKusick */ 718fc56fd26SKirk McKusick if (blockmap != NULL) 719fc56fd26SKirk McKusick free(blockmap); 720fc56fd26SKirk McKusick blockmap = NULL; 721fc56fd26SKirk McKusick if (inostathead != NULL) { 722fc56fd26SKirk McKusick for (cg = 0; cg < sblock.fs_ncg; cg++) 723fc56fd26SKirk McKusick if (inostathead[cg].il_stat != NULL) 724fc56fd26SKirk McKusick free((char *)inostathead[cg].il_stat); 725fc56fd26SKirk McKusick free(inostathead); 726fc56fd26SKirk McKusick } 727fc56fd26SKirk McKusick inostathead = NULL; 728fc56fd26SKirk McKusick if (inpsort != NULL) 729fc56fd26SKirk McKusick free(inpsort); 730fc56fd26SKirk McKusick inpsort = NULL; 731fc56fd26SKirk McKusick if (inphead != NULL) { 732fc56fd26SKirk McKusick for (i = 0; i < dirhash; i++) { 733fc56fd26SKirk McKusick for (inp = inphead[i]; inp != NULL; inp = ninp) { 734fc56fd26SKirk McKusick ninp = inp->i_nexthash; 735fc56fd26SKirk McKusick free(inp); 736fc56fd26SKirk McKusick } 737fc56fd26SKirk McKusick } 738fc56fd26SKirk McKusick free(inphead); 739fc56fd26SKirk McKusick } 740fc56fd26SKirk McKusick inphead = NULL; 7415cc52631SKirk McKusick finalIOstats(); 7424336716bSAdrian Chadd (void)close(fsreadfd); 7434336716bSAdrian Chadd (void)close(fswritefd); 7444336716bSAdrian Chadd } 7454336716bSAdrian Chadd 746ed75b5a1SKirk McKusick /* 747ed75b5a1SKirk McKusick * Print out I/O statistics. 748ed75b5a1SKirk McKusick */ 749ed75b5a1SKirk McKusick void 750ed75b5a1SKirk McKusick IOstats(char *what) 751ed75b5a1SKirk McKusick { 752ed75b5a1SKirk McKusick int i; 753ed75b5a1SKirk McKusick 754ed75b5a1SKirk McKusick if (debug == 0) 755ed75b5a1SKirk McKusick return; 756ed75b5a1SKirk McKusick if (diskreads == 0) { 757ed75b5a1SKirk McKusick printf("%s: no I/O\n\n", what); 758ed75b5a1SKirk McKusick return; 759ed75b5a1SKirk McKusick } 760ed75b5a1SKirk McKusick if (startpass.tv_sec == 0) 761ed75b5a1SKirk McKusick startpass = startprog; 762ed75b5a1SKirk McKusick printf("%s: I/O statistics\n", what); 763ed75b5a1SKirk McKusick printIOstats(); 764ed75b5a1SKirk McKusick totaldiskreads += diskreads; 765ed75b5a1SKirk McKusick diskreads = 0; 766ed75b5a1SKirk McKusick for (i = 0; i < BT_NUMBUFTYPES; i++) { 7676040822cSAlan Somers timespecadd(&totalreadtime[i], &readtime[i], &totalreadtime[i]); 768ed75b5a1SKirk McKusick totalreadcnt[i] += readcnt[i]; 769ed75b5a1SKirk McKusick readtime[i].tv_sec = readtime[i].tv_nsec = 0; 770ed75b5a1SKirk McKusick readcnt[i] = 0; 771ed75b5a1SKirk McKusick } 772ed75b5a1SKirk McKusick clock_gettime(CLOCK_REALTIME_PRECISE, &startpass); 773ed75b5a1SKirk McKusick } 774ed75b5a1SKirk McKusick 775ed75b5a1SKirk McKusick void 776ed75b5a1SKirk McKusick finalIOstats(void) 777ed75b5a1SKirk McKusick { 778ed75b5a1SKirk McKusick int i; 779ed75b5a1SKirk McKusick 780ed75b5a1SKirk McKusick if (debug == 0) 781ed75b5a1SKirk McKusick return; 782ed75b5a1SKirk McKusick printf("Final I/O statistics\n"); 783ed75b5a1SKirk McKusick totaldiskreads += diskreads; 784ed75b5a1SKirk McKusick diskreads = totaldiskreads; 785ed75b5a1SKirk McKusick startpass = startprog; 786ed75b5a1SKirk McKusick for (i = 0; i < BT_NUMBUFTYPES; i++) { 7876040822cSAlan Somers timespecadd(&totalreadtime[i], &readtime[i], &totalreadtime[i]); 788ed75b5a1SKirk McKusick totalreadcnt[i] += readcnt[i]; 789ed75b5a1SKirk McKusick readtime[i] = totalreadtime[i]; 790ed75b5a1SKirk McKusick readcnt[i] = totalreadcnt[i]; 791ed75b5a1SKirk McKusick } 792ed75b5a1SKirk McKusick printIOstats(); 793ed75b5a1SKirk McKusick } 794ed75b5a1SKirk McKusick 795ed75b5a1SKirk McKusick static void printIOstats(void) 796ed75b5a1SKirk McKusick { 797ed75b5a1SKirk McKusick long long msec, totalmsec; 798ed75b5a1SKirk McKusick int i; 799ed75b5a1SKirk McKusick 800ed75b5a1SKirk McKusick clock_gettime(CLOCK_REALTIME_PRECISE, &finishpass); 8016040822cSAlan Somers timespecsub(&finishpass, &startpass, &finishpass); 802061ea59dSKirk McKusick printf("Running time: %jd.%03ld sec\n", 8034b3bbe04SSean Bruno (intmax_t)finishpass.tv_sec, finishpass.tv_nsec / 1000000); 804ed75b5a1SKirk McKusick printf("buffer reads by type:\n"); 805ed75b5a1SKirk McKusick for (totalmsec = 0, i = 0; i < BT_NUMBUFTYPES; i++) 806ed75b5a1SKirk McKusick totalmsec += readtime[i].tv_sec * 1000 + 807ed75b5a1SKirk McKusick readtime[i].tv_nsec / 1000000; 808ed75b5a1SKirk McKusick if (totalmsec == 0) 809ed75b5a1SKirk McKusick totalmsec = 1; 810ed75b5a1SKirk McKusick for (i = 0; i < BT_NUMBUFTYPES; i++) { 811ed75b5a1SKirk McKusick if (readcnt[i] == 0) 812ed75b5a1SKirk McKusick continue; 813061ea59dSKirk McKusick msec = 814061ea59dSKirk McKusick readtime[i].tv_sec * 1000 + readtime[i].tv_nsec / 1000000; 8154b3bbe04SSean Bruno printf("%21s:%8ld %2ld.%ld%% %4jd.%03ld sec %2lld.%lld%%\n", 816ed75b5a1SKirk McKusick buftype[i], readcnt[i], readcnt[i] * 100 / diskreads, 81781fbded2SKirk McKusick (readcnt[i] * 1000 / diskreads) % 10, 8184b3bbe04SSean Bruno (intmax_t)readtime[i].tv_sec, readtime[i].tv_nsec / 1000000, 819ed75b5a1SKirk McKusick msec * 100 / totalmsec, (msec * 1000 / totalmsec) % 10); 820ed75b5a1SKirk McKusick } 821ed75b5a1SKirk McKusick printf("\n"); 822ed75b5a1SKirk McKusick } 823ed75b5a1SKirk McKusick 8244336716bSAdrian Chadd int 825aef8d244SPawel Jakub Dawidek blread(int fd, char *buf, ufs2_daddr_t blk, long size) 8264336716bSAdrian Chadd { 8274336716bSAdrian Chadd char *cp; 8284336716bSAdrian Chadd int i, errs; 8294336716bSAdrian Chadd off_t offset; 8304336716bSAdrian Chadd 8314336716bSAdrian Chadd offset = blk; 8324336716bSAdrian Chadd offset *= dev_bsize; 8339d580d7cSIan Dowse if (bkgrdflag) 8349d580d7cSIan Dowse slowio_start(); 835ed75b5a1SKirk McKusick totalreads++; 836ed75b5a1SKirk McKusick diskreads++; 83704e5c6f1SEdward Tomasz Napierala if (pread(fd, buf, (int)size, offset) == size) { 8389d580d7cSIan Dowse if (bkgrdflag) 8399d580d7cSIan Dowse slowio_end(); 8404336716bSAdrian Chadd return (0); 8419d580d7cSIan Dowse } 842ce779f37SScott Long 843ce779f37SScott Long /* 844ce779f37SScott Long * This is handled specially here instead of in rwerror because 845ce779f37SScott Long * rwerror is used for all sorts of errors, not just true read/write 846ce779f37SScott Long * errors. It should be refactored and fixed. 847ce779f37SScott Long */ 848ce779f37SScott Long if (surrender) { 849ce779f37SScott Long pfatal("CANNOT READ_BLK: %ld", (long)blk); 850ce779f37SScott Long errx(EEXIT, "ABORTING DUE TO READ ERRORS"); 851ce779f37SScott Long } else 8527578c6abSKirk McKusick rwerror("READ BLK", blk); 853ce779f37SScott Long 8544336716bSAdrian Chadd errs = 0; 8554336716bSAdrian Chadd memset(buf, 0, (size_t)size); 8564336716bSAdrian Chadd printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); 8574336716bSAdrian Chadd for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { 85804e5c6f1SEdward Tomasz Napierala if (pread(fd, cp, (int)secsize, offset + i) != secsize) { 8594336716bSAdrian Chadd if (secsize != dev_bsize && dev_bsize != 1) 86084fc0d7eSMaxime Henrion printf(" %jd (%jd),", 86184fc0d7eSMaxime Henrion (intmax_t)(blk * dev_bsize + i) / secsize, 86284fc0d7eSMaxime Henrion (intmax_t)blk + i / dev_bsize); 8634336716bSAdrian Chadd else 86484fc0d7eSMaxime Henrion printf(" %jd,", (intmax_t)blk + i / dev_bsize); 8654336716bSAdrian Chadd errs++; 8664336716bSAdrian Chadd } 8674336716bSAdrian Chadd } 8684336716bSAdrian Chadd printf("\n"); 8694336716bSAdrian Chadd if (errs) 8704336716bSAdrian Chadd resolved = 0; 8714336716bSAdrian Chadd return (errs); 8724336716bSAdrian Chadd } 8734336716bSAdrian Chadd 8744336716bSAdrian Chadd void 8754a835375SDavid E. O'Brien blwrite(int fd, char *buf, ufs2_daddr_t blk, ssize_t size) 8764336716bSAdrian Chadd { 8774336716bSAdrian Chadd int i; 8784336716bSAdrian Chadd char *cp; 8794336716bSAdrian Chadd off_t offset; 8804336716bSAdrian Chadd 8814336716bSAdrian Chadd if (fd < 0) 8824336716bSAdrian Chadd return; 8834336716bSAdrian Chadd offset = blk; 8844336716bSAdrian Chadd offset *= dev_bsize; 88504e5c6f1SEdward Tomasz Napierala if (pwrite(fd, buf, size, offset) == size) { 8864336716bSAdrian Chadd fsmodified = 1; 8874336716bSAdrian Chadd return; 8884336716bSAdrian Chadd } 8894336716bSAdrian Chadd resolved = 0; 8907578c6abSKirk McKusick rwerror("WRITE BLK", blk); 8914336716bSAdrian Chadd printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 8924336716bSAdrian Chadd for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) 89304e5c6f1SEdward Tomasz Napierala if (pwrite(fd, cp, dev_bsize, offset + i) != dev_bsize) 89484fc0d7eSMaxime Henrion printf(" %jd,", (intmax_t)blk + i / dev_bsize); 8954336716bSAdrian Chadd printf("\n"); 8964336716bSAdrian Chadd return; 8974336716bSAdrian Chadd } 8984336716bSAdrian Chadd 8998d3dfc26SDag-Erling Smørgrav void 9008d3dfc26SDag-Erling Smørgrav blerase(int fd, ufs2_daddr_t blk, long size) 9018d3dfc26SDag-Erling Smørgrav { 9028d3dfc26SDag-Erling Smørgrav off_t ioarg[2]; 9038d3dfc26SDag-Erling Smørgrav 9048d3dfc26SDag-Erling Smørgrav if (fd < 0) 9058d3dfc26SDag-Erling Smørgrav return; 9068d3dfc26SDag-Erling Smørgrav ioarg[0] = blk * dev_bsize; 9078d3dfc26SDag-Erling Smørgrav ioarg[1] = size; 9088d3dfc26SDag-Erling Smørgrav ioctl(fd, DIOCGDELETE, ioarg); 9098d3dfc26SDag-Erling Smørgrav /* we don't really care if we succeed or not */ 9108d3dfc26SDag-Erling Smørgrav return; 9118d3dfc26SDag-Erling Smørgrav } 9128d3dfc26SDag-Erling Smørgrav 9138ce80d4bSDag-Erling Smørgrav /* 9148ce80d4bSDag-Erling Smørgrav * Fill a contiguous region with all-zeroes. Note ZEROBUFSIZE is by 9158ce80d4bSDag-Erling Smørgrav * definition a multiple of dev_bsize. 9168ce80d4bSDag-Erling Smørgrav */ 9172b5373deSDag-Erling Smørgrav void 9182b5373deSDag-Erling Smørgrav blzero(int fd, ufs2_daddr_t blk, long size) 9192b5373deSDag-Erling Smørgrav { 9202b5373deSDag-Erling Smørgrav static char *zero; 9212b5373deSDag-Erling Smørgrav off_t offset, len; 9222b5373deSDag-Erling Smørgrav 9232b5373deSDag-Erling Smørgrav if (fd < 0) 9242b5373deSDag-Erling Smørgrav return; 9252b5373deSDag-Erling Smørgrav if (zero == NULL) { 9268ce80d4bSDag-Erling Smørgrav zero = calloc(ZEROBUFSIZE, 1); 9272b5373deSDag-Erling Smørgrav if (zero == NULL) 9282b5373deSDag-Erling Smørgrav errx(EEXIT, "cannot allocate buffer pool"); 9292b5373deSDag-Erling Smørgrav } 9302b5373deSDag-Erling Smørgrav offset = blk * dev_bsize; 9312b5373deSDag-Erling Smørgrav if (lseek(fd, offset, 0) < 0) 9322b5373deSDag-Erling Smørgrav rwerror("SEEK BLK", blk); 9332b5373deSDag-Erling Smørgrav while (size > 0) { 9341120faabSMarcelo Araujo len = MIN(ZEROBUFSIZE, size); 9352b5373deSDag-Erling Smørgrav if (write(fd, zero, len) != len) 9362b5373deSDag-Erling Smørgrav rwerror("WRITE BLK", blk); 9372b5373deSDag-Erling Smørgrav blk += len / dev_bsize; 9382b5373deSDag-Erling Smørgrav size -= len; 9392b5373deSDag-Erling Smørgrav } 9402b5373deSDag-Erling Smørgrav } 9412b5373deSDag-Erling Smørgrav 9424336716bSAdrian Chadd /* 943910b491eSKirk McKusick * Verify cylinder group's magic number and other parameters. If the 944910b491eSKirk McKusick * test fails, offer an option to rebuild the whole cylinder group. 94514320f1eSXin LI */ 946910b491eSKirk McKusick int 9475cc52631SKirk McKusick check_cgmagic(int cg, struct bufarea *cgbp, int request_rebuild) 94814320f1eSXin LI { 94981fbded2SKirk McKusick struct cg *cgp = cgbp->b_un.b_cg; 9505cc52631SKirk McKusick uint32_t cghash, calchash; 951*689724cbSKirk McKusick static int prevfailcg = -1; 95214320f1eSXin LI 953910b491eSKirk McKusick /* 954910b491eSKirk McKusick * Extended cylinder group checks. 955910b491eSKirk McKusick */ 9565cc52631SKirk McKusick calchash = cgp->cg_ckhash; 9576385cabdSKirk McKusick if ((sblock.fs_metackhash & CK_CYLGRP) != 0 && 9586385cabdSKirk McKusick (ckhashadd & CK_CYLGRP) == 0) { 9595cc52631SKirk McKusick cghash = cgp->cg_ckhash; 9605cc52631SKirk McKusick cgp->cg_ckhash = 0; 9615cc52631SKirk McKusick calchash = calculate_crc32c(~0L, (void *)cgp, sblock.fs_cgsize); 9625cc52631SKirk McKusick cgp->cg_ckhash = cghash; 9635cc52631SKirk McKusick } 9645cc52631SKirk McKusick if (cgp->cg_ckhash == calchash && 9655cc52631SKirk McKusick cg_chkmagic(cgp) && 9665cc52631SKirk McKusick cgp->cg_cgx == cg && 967910b491eSKirk McKusick ((sblock.fs_magic == FS_UFS1_MAGIC && 968910b491eSKirk McKusick cgp->cg_old_niblk == sblock.fs_ipg && 969910b491eSKirk McKusick cgp->cg_ndblk <= sblock.fs_fpg && 97036ef6b65SKirk McKusick cgp->cg_old_ncyl <= sblock.fs_old_cpg) || 971910b491eSKirk McKusick (sblock.fs_magic == FS_UFS2_MAGIC && 972910b491eSKirk McKusick cgp->cg_niblk == sblock.fs_ipg && 973910b491eSKirk McKusick cgp->cg_ndblk <= sblock.fs_fpg && 974910b491eSKirk McKusick cgp->cg_initediblk <= sblock.fs_ipg))) { 975910b491eSKirk McKusick return (1); 976910b491eSKirk McKusick } 977*689724cbSKirk McKusick if (prevfailcg == cg) 9785cc52631SKirk McKusick return (0); 979*689724cbSKirk McKusick prevfailcg = cg; 980*689724cbSKirk McKusick pfatal("CYLINDER GROUP %d: INTEGRITY CHECK FAILED", cg); 981*689724cbSKirk McKusick if (!request_rebuild) { 982*689724cbSKirk McKusick printf("\n"); 983*689724cbSKirk McKusick return (0); 984*689724cbSKirk McKusick } 985910b491eSKirk McKusick if (!reply("REBUILD CYLINDER GROUP")) { 986910b491eSKirk McKusick printf("YOU WILL NEED TO RERUN FSCK.\n"); 987910b491eSKirk McKusick rerun = 1; 988910b491eSKirk McKusick return (1); 989910b491eSKirk McKusick } 990910b491eSKirk McKusick /* 991910b491eSKirk McKusick * Zero out the cylinder group and then initialize critical fields. 992910b491eSKirk McKusick * Bit maps and summaries will be recalculated by later passes. 993910b491eSKirk McKusick */ 99414320f1eSXin LI memset(cgp, 0, (size_t)sblock.fs_cgsize); 995910b491eSKirk McKusick cgp->cg_magic = CG_MAGIC; 99614320f1eSXin LI cgp->cg_cgx = cg; 99714320f1eSXin LI cgp->cg_niblk = sblock.fs_ipg; 9981120faabSMarcelo Araujo cgp->cg_initediblk = MIN(sblock.fs_ipg, 2 * INOPB(&sblock)); 999910b491eSKirk McKusick if (cgbase(&sblock, cg) + sblock.fs_fpg < sblock.fs_size) 1000910b491eSKirk McKusick cgp->cg_ndblk = sblock.fs_fpg; 1001910b491eSKirk McKusick else 100214320f1eSXin LI cgp->cg_ndblk = sblock.fs_size - cgbase(&sblock, cg); 1003910b491eSKirk McKusick cgp->cg_iusedoff = &cgp->cg_space[0] - (u_char *)(&cgp->cg_firstfield); 1004910b491eSKirk McKusick if (sblock.fs_magic == FS_UFS1_MAGIC) { 1005910b491eSKirk McKusick cgp->cg_niblk = 0; 1006910b491eSKirk McKusick cgp->cg_initediblk = 0; 1007910b491eSKirk McKusick cgp->cg_old_ncyl = sblock.fs_old_cpg; 1008910b491eSKirk McKusick cgp->cg_old_niblk = sblock.fs_ipg; 1009910b491eSKirk McKusick cgp->cg_old_btotoff = cgp->cg_iusedoff; 1010910b491eSKirk McKusick cgp->cg_old_boff = cgp->cg_old_btotoff + 1011910b491eSKirk McKusick sblock.fs_old_cpg * sizeof(int32_t); 1012910b491eSKirk McKusick cgp->cg_iusedoff = cgp->cg_old_boff + 1013910b491eSKirk McKusick sblock.fs_old_cpg * sizeof(u_int16_t); 1014910b491eSKirk McKusick } 1015910b491eSKirk McKusick cgp->cg_freeoff = cgp->cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT); 1016910b491eSKirk McKusick cgp->cg_nextfreeoff = cgp->cg_freeoff + howmany(sblock.fs_fpg,CHAR_BIT); 1017910b491eSKirk McKusick if (sblock.fs_contigsumsize > 0) { 1018910b491eSKirk McKusick cgp->cg_nclusterblks = cgp->cg_ndblk / sblock.fs_frag; 1019910b491eSKirk McKusick cgp->cg_clustersumoff = 1020910b491eSKirk McKusick roundup(cgp->cg_nextfreeoff, sizeof(u_int32_t)); 1021910b491eSKirk McKusick cgp->cg_clustersumoff -= sizeof(u_int32_t); 1022910b491eSKirk McKusick cgp->cg_clusteroff = cgp->cg_clustersumoff + 1023910b491eSKirk McKusick (sblock.fs_contigsumsize + 1) * sizeof(u_int32_t); 1024910b491eSKirk McKusick cgp->cg_nextfreeoff = cgp->cg_clusteroff + 1025910b491eSKirk McKusick howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT); 1026910b491eSKirk McKusick } 10278ebae128SKirk McKusick cgdirty(cgbp); 1028910b491eSKirk McKusick return (0); 102914320f1eSXin LI } 103014320f1eSXin LI 103114320f1eSXin LI /* 10324336716bSAdrian Chadd * allocate a data block with the specified number of fragments 10334336716bSAdrian Chadd */ 10341c85e6a3SKirk McKusick ufs2_daddr_t 1035b70cd7eeSWarner Losh allocblk(long frags) 10364336716bSAdrian Chadd { 10374336716bSAdrian Chadd int i, j, k, cg, baseblk; 103881fbded2SKirk McKusick struct bufarea *cgbp; 103981fbded2SKirk McKusick struct cg *cgp; 10404336716bSAdrian Chadd 10414336716bSAdrian Chadd if (frags <= 0 || frags > sblock.fs_frag) 10424336716bSAdrian Chadd return (0); 10434336716bSAdrian Chadd for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) { 10444336716bSAdrian Chadd for (j = 0; j <= sblock.fs_frag - frags; j++) { 10454336716bSAdrian Chadd if (testbmap(i + j)) 10464336716bSAdrian Chadd continue; 10474336716bSAdrian Chadd for (k = 1; k < frags; k++) 10484336716bSAdrian Chadd if (testbmap(i + j + k)) 10494336716bSAdrian Chadd break; 10504336716bSAdrian Chadd if (k < frags) { 10514336716bSAdrian Chadd j += k; 10524336716bSAdrian Chadd continue; 10534336716bSAdrian Chadd } 10544336716bSAdrian Chadd cg = dtog(&sblock, i + j); 1055957fc241SKirk McKusick cgbp = cglookup(cg); 105681fbded2SKirk McKusick cgp = cgbp->b_un.b_cg; 105784a0e3f9SKirk McKusick if (!check_cgmagic(cg, cgbp, 0)) { 105884a0e3f9SKirk McKusick i = (cg + 1) * sblock.fs_fpg - sblock.fs_frag; 105984a0e3f9SKirk McKusick continue; 106084a0e3f9SKirk McKusick } 10614336716bSAdrian Chadd baseblk = dtogd(&sblock, i + j); 10624336716bSAdrian Chadd for (k = 0; k < frags; k++) { 10634336716bSAdrian Chadd setbmap(i + j + k); 10644336716bSAdrian Chadd clrbit(cg_blksfree(cgp), baseblk + k); 10654336716bSAdrian Chadd } 10664336716bSAdrian Chadd n_blks += frags; 10674336716bSAdrian Chadd if (frags == sblock.fs_frag) 10684336716bSAdrian Chadd cgp->cg_cs.cs_nbfree--; 10694336716bSAdrian Chadd else 10704336716bSAdrian Chadd cgp->cg_cs.cs_nffree -= frags; 10718ebae128SKirk McKusick cgdirty(cgbp); 10724336716bSAdrian Chadd return (i + j); 10734336716bSAdrian Chadd } 10744336716bSAdrian Chadd } 10754336716bSAdrian Chadd return (0); 10764336716bSAdrian Chadd } 10774336716bSAdrian Chadd 10784336716bSAdrian Chadd /* 10797180f1abSKirk McKusick * Slow down IO so as to leave some disk bandwidth for other processes 10804336716bSAdrian Chadd */ 10814336716bSAdrian Chadd void 10829d580d7cSIan Dowse slowio_start() 10839d580d7cSIan Dowse { 10849d580d7cSIan Dowse 108508983aeeSScott Long /* Delay one in every 8 operations */ 10869d580d7cSIan Dowse slowio_pollcnt = (slowio_pollcnt + 1) & 7; 10879d580d7cSIan Dowse if (slowio_pollcnt == 0) { 10889d580d7cSIan Dowse gettimeofday(&slowio_starttime, NULL); 10899d580d7cSIan Dowse } 10909d580d7cSIan Dowse } 10919d580d7cSIan Dowse 10929d580d7cSIan Dowse void 10939d580d7cSIan Dowse slowio_end() 10949d580d7cSIan Dowse { 10959d580d7cSIan Dowse struct timeval tv; 10969d580d7cSIan Dowse int delay_usec; 10979d580d7cSIan Dowse 10989d580d7cSIan Dowse if (slowio_pollcnt != 0) 10999d580d7cSIan Dowse return; 11009d580d7cSIan Dowse 11019d580d7cSIan Dowse /* Update the slowdown interval. */ 11029d580d7cSIan Dowse gettimeofday(&tv, NULL); 11039d580d7cSIan Dowse delay_usec = (tv.tv_sec - slowio_starttime.tv_sec) * 1000000 + 11049d580d7cSIan Dowse (tv.tv_usec - slowio_starttime.tv_usec); 11059d580d7cSIan Dowse if (delay_usec < 64) 11069d580d7cSIan Dowse delay_usec = 64; 110708983aeeSScott Long if (delay_usec > 2500000) 110808983aeeSScott Long delay_usec = 2500000; 11099d580d7cSIan Dowse slowio_delay_usec = (slowio_delay_usec * 63 + delay_usec) >> 6; 111008983aeeSScott Long /* delay by 8 times the average IO delay */ 111108983aeeSScott Long if (slowio_delay_usec > 64) 111208983aeeSScott Long usleep(slowio_delay_usec * 8); 11139d580d7cSIan Dowse } 11149d580d7cSIan Dowse 11154336716bSAdrian Chadd /* 11164336716bSAdrian Chadd * Find a pathname 11174336716bSAdrian Chadd */ 11184336716bSAdrian Chadd void 1119b70cd7eeSWarner Losh getpathname(char *namebuf, ino_t curdir, ino_t ino) 11204336716bSAdrian Chadd { 11214336716bSAdrian Chadd int len; 11223d438ad6SDavid E. O'Brien char *cp; 11235cc52631SKirk McKusick struct inode ip; 11244336716bSAdrian Chadd struct inodesc idesc; 11254336716bSAdrian Chadd static int busy = 0; 11264336716bSAdrian Chadd 11271dc349abSEd Maste if (curdir == ino && ino == UFS_ROOTINO) { 11284336716bSAdrian Chadd (void)strcpy(namebuf, "/"); 11294336716bSAdrian Chadd return; 11304336716bSAdrian Chadd } 1131af6726e6SDon Lewis if (busy || !INO_IS_DVALID(curdir)) { 11324336716bSAdrian Chadd (void)strcpy(namebuf, "?"); 11334336716bSAdrian Chadd return; 11344336716bSAdrian Chadd } 11354336716bSAdrian Chadd busy = 1; 11364336716bSAdrian Chadd memset(&idesc, 0, sizeof(struct inodesc)); 11374336716bSAdrian Chadd idesc.id_type = DATA; 11384336716bSAdrian Chadd idesc.id_fix = IGNORE; 11394336716bSAdrian Chadd cp = &namebuf[MAXPATHLEN - 1]; 11404336716bSAdrian Chadd *cp = '\0'; 11414336716bSAdrian Chadd if (curdir != ino) { 11424336716bSAdrian Chadd idesc.id_parent = curdir; 11434336716bSAdrian Chadd goto namelookup; 11444336716bSAdrian Chadd } 11451dc349abSEd Maste while (ino != UFS_ROOTINO) { 11464336716bSAdrian Chadd idesc.id_number = ino; 11474336716bSAdrian Chadd idesc.id_func = findino; 1148599304a4SPoul-Henning Kamp idesc.id_name = strdup(".."); 11495cc52631SKirk McKusick ginode(ino, &ip); 11505cc52631SKirk McKusick if ((ckinode(ip.i_dp, &idesc) & FOUND) == 0) { 11515cc52631SKirk McKusick irelse(&ip); 11524336716bSAdrian Chadd break; 11535cc52631SKirk McKusick } 11545cc52631SKirk McKusick irelse(&ip); 11554336716bSAdrian Chadd namelookup: 11564336716bSAdrian Chadd idesc.id_number = idesc.id_parent; 11574336716bSAdrian Chadd idesc.id_parent = ino; 11584336716bSAdrian Chadd idesc.id_func = findname; 11594336716bSAdrian Chadd idesc.id_name = namebuf; 11605cc52631SKirk McKusick ginode(idesc.id_number, &ip); 11615cc52631SKirk McKusick if ((ckinode(ip.i_dp, &idesc) & FOUND) == 0) { 11625cc52631SKirk McKusick irelse(&ip); 11634336716bSAdrian Chadd break; 11645cc52631SKirk McKusick } 11655cc52631SKirk McKusick irelse(&ip); 11664336716bSAdrian Chadd len = strlen(namebuf); 11674336716bSAdrian Chadd cp -= len; 11684336716bSAdrian Chadd memmove(cp, namebuf, (size_t)len); 11694336716bSAdrian Chadd *--cp = '/'; 11700ecf59f6SConrad Meyer if (cp < &namebuf[UFS_MAXNAMLEN]) 11714336716bSAdrian Chadd break; 11724336716bSAdrian Chadd ino = idesc.id_number; 11734336716bSAdrian Chadd } 11744336716bSAdrian Chadd busy = 0; 11751dc349abSEd Maste if (ino != UFS_ROOTINO) 11764336716bSAdrian Chadd *--cp = '?'; 11774336716bSAdrian Chadd memmove(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp)); 11784336716bSAdrian Chadd } 11794336716bSAdrian Chadd 11804336716bSAdrian Chadd void 1181599304a4SPoul-Henning Kamp catch(int sig __unused) 11824336716bSAdrian Chadd { 1183381ee4c2SPoul-Henning Kamp 11844336716bSAdrian Chadd ckfini(0); 11854336716bSAdrian Chadd exit(12); 11864336716bSAdrian Chadd } 11874336716bSAdrian Chadd 11884336716bSAdrian Chadd /* 11894336716bSAdrian Chadd * When preening, allow a single quit to signal 11904336716bSAdrian Chadd * a special exit after file system checks complete 11914336716bSAdrian Chadd * so that reboot sequence may be interrupted. 11924336716bSAdrian Chadd */ 11934336716bSAdrian Chadd void 1194599304a4SPoul-Henning Kamp catchquit(int sig __unused) 11954336716bSAdrian Chadd { 11964336716bSAdrian Chadd printf("returning to single-user after file system check\n"); 11974336716bSAdrian Chadd returntosingle = 1; 11984336716bSAdrian Chadd (void)signal(SIGQUIT, SIG_DFL); 11994336716bSAdrian Chadd } 12004336716bSAdrian Chadd 12014336716bSAdrian Chadd /* 12024336716bSAdrian Chadd * determine whether an inode should be fixed. 12034336716bSAdrian Chadd */ 12044336716bSAdrian Chadd int 1205599304a4SPoul-Henning Kamp dofix(struct inodesc *idesc, const char *msg) 12064336716bSAdrian Chadd { 12074336716bSAdrian Chadd 12084336716bSAdrian Chadd switch (idesc->id_fix) { 12094336716bSAdrian Chadd 12104336716bSAdrian Chadd case DONTKNOW: 12114336716bSAdrian Chadd if (idesc->id_type == DATA) 12124336716bSAdrian Chadd direrror(idesc->id_number, msg); 12134336716bSAdrian Chadd else 12145979df34SKris Kennaway pwarn("%s", msg); 12154336716bSAdrian Chadd if (preen) { 12164336716bSAdrian Chadd printf(" (SALVAGED)\n"); 12174336716bSAdrian Chadd idesc->id_fix = FIX; 12184336716bSAdrian Chadd return (ALTERED); 12194336716bSAdrian Chadd } 12204336716bSAdrian Chadd if (reply("SALVAGE") == 0) { 12214336716bSAdrian Chadd idesc->id_fix = NOFIX; 12224336716bSAdrian Chadd return (0); 12234336716bSAdrian Chadd } 12244336716bSAdrian Chadd idesc->id_fix = FIX; 12254336716bSAdrian Chadd return (ALTERED); 12264336716bSAdrian Chadd 12274336716bSAdrian Chadd case FIX: 12284336716bSAdrian Chadd return (ALTERED); 12294336716bSAdrian Chadd 12304336716bSAdrian Chadd case NOFIX: 12314336716bSAdrian Chadd case IGNORE: 12324336716bSAdrian Chadd return (0); 12334336716bSAdrian Chadd 12344336716bSAdrian Chadd default: 12354336716bSAdrian Chadd errx(EEXIT, "UNKNOWN INODESC FIX MODE %d", idesc->id_fix); 12364336716bSAdrian Chadd } 12374336716bSAdrian Chadd /* NOTREACHED */ 12384336716bSAdrian Chadd return (0); 12394336716bSAdrian Chadd } 12404336716bSAdrian Chadd 12414336716bSAdrian Chadd #include <stdarg.h> 12424336716bSAdrian Chadd 12434336716bSAdrian Chadd /* 12445cc52631SKirk McKusick * Print details about a buffer. 12455cc52631SKirk McKusick */ 12465cc52631SKirk McKusick static void 12475cc52631SKirk McKusick prtbuf(const char *msg, struct bufarea *bp) 12485cc52631SKirk McKusick { 12495cc52631SKirk McKusick 1250c6951facSCy Schubert printf("%s: bp %p, type %s, bno %jd, size %d, refcnt %d, flags %s, " 1251c6951facSCy Schubert "index %jd\n", msg, bp, BT_BUFTYPE(bp->b_type), (intmax_t) bp->b_bno, 12525cc52631SKirk McKusick bp->b_size, bp->b_refcnt, bp->b_flags & B_DIRTY ? "dirty" : "clean", 1253c6951facSCy Schubert (intmax_t) bp->b_index); 12545cc52631SKirk McKusick } 12555cc52631SKirk McKusick 12565cc52631SKirk McKusick /* 12574b85a12fSUlrich Spörlein * An unexpected inconsistency occurred. 12584336716bSAdrian Chadd * Die if preening or file system is running with soft dependency protocol, 12594336716bSAdrian Chadd * otherwise just print message and continue. 12604336716bSAdrian Chadd */ 12614336716bSAdrian Chadd void 12624336716bSAdrian Chadd pfatal(const char *fmt, ...) 12634336716bSAdrian Chadd { 12644336716bSAdrian Chadd va_list ap; 12654336716bSAdrian Chadd va_start(ap, fmt); 12664336716bSAdrian Chadd if (!preen) { 126715fca934SKirk McKusick (void)vfprintf(stdout, fmt, ap); 12684336716bSAdrian Chadd va_end(ap); 12694336716bSAdrian Chadd if (usedsoftdep) 127015fca934SKirk McKusick (void)fprintf(stdout, 12714336716bSAdrian Chadd "\nUNEXPECTED SOFT UPDATE INCONSISTENCY\n"); 127238375c40SKirk McKusick /* 127338375c40SKirk McKusick * Force foreground fsck to clean up inconsistency. 127438375c40SKirk McKusick */ 127538375c40SKirk McKusick if (bkgrdflag) { 127638375c40SKirk McKusick cmd.value = FS_NEEDSFSCK; 127738375c40SKirk McKusick cmd.size = 1; 127838375c40SKirk McKusick if (sysctlbyname("vfs.ffs.setflags", 0, 0, 127938375c40SKirk McKusick &cmd, sizeof cmd) == -1) 128038375c40SKirk McKusick pwarn("CANNOT SET FS_NEEDSFSCK FLAG\n"); 128115fca934SKirk McKusick fprintf(stdout, "CANNOT RUN IN BACKGROUND\n"); 128238375c40SKirk McKusick ckfini(0); 128338375c40SKirk McKusick exit(EEXIT); 128438375c40SKirk McKusick } 12854336716bSAdrian Chadd return; 12864336716bSAdrian Chadd } 12874336716bSAdrian Chadd if (cdevname == NULL) 1288599304a4SPoul-Henning Kamp cdevname = strdup("fsck"); 128915fca934SKirk McKusick (void)fprintf(stdout, "%s: ", cdevname); 129015fca934SKirk McKusick (void)vfprintf(stdout, fmt, ap); 129115fca934SKirk McKusick (void)fprintf(stdout, 12924336716bSAdrian Chadd "\n%s: UNEXPECTED%sINCONSISTENCY; RUN fsck MANUALLY.\n", 12934336716bSAdrian Chadd cdevname, usedsoftdep ? " SOFT UPDATE " : " "); 129438375c40SKirk McKusick /* 129538375c40SKirk McKusick * Force foreground fsck to clean up inconsistency. 129638375c40SKirk McKusick */ 129738375c40SKirk McKusick if (bkgrdflag) { 129838375c40SKirk McKusick cmd.value = FS_NEEDSFSCK; 129938375c40SKirk McKusick cmd.size = 1; 130038375c40SKirk McKusick if (sysctlbyname("vfs.ffs.setflags", 0, 0, 130138375c40SKirk McKusick &cmd, sizeof cmd) == -1) 130238375c40SKirk McKusick pwarn("CANNOT SET FS_NEEDSFSCK FLAG\n"); 130338375c40SKirk McKusick } 13044336716bSAdrian Chadd ckfini(0); 13054336716bSAdrian Chadd exit(EEXIT); 13064336716bSAdrian Chadd } 13074336716bSAdrian Chadd 13084336716bSAdrian Chadd /* 13094336716bSAdrian Chadd * Pwarn just prints a message when not preening or running soft dependency 13104336716bSAdrian Chadd * protocol, or a warning (preceded by filename) when preening. 13114336716bSAdrian Chadd */ 13124336716bSAdrian Chadd void 13134336716bSAdrian Chadd pwarn(const char *fmt, ...) 13144336716bSAdrian Chadd { 13154336716bSAdrian Chadd va_list ap; 13164336716bSAdrian Chadd va_start(ap, fmt); 13174336716bSAdrian Chadd if (preen) 131815fca934SKirk McKusick (void)fprintf(stdout, "%s: ", cdevname); 131915fca934SKirk McKusick (void)vfprintf(stdout, fmt, ap); 13204336716bSAdrian Chadd va_end(ap); 13214336716bSAdrian Chadd } 13224336716bSAdrian Chadd 13234336716bSAdrian Chadd /* 13244336716bSAdrian Chadd * Stub for routines from kernel. 13254336716bSAdrian Chadd */ 13264336716bSAdrian Chadd void 13274336716bSAdrian Chadd panic(const char *fmt, ...) 13284336716bSAdrian Chadd { 13294336716bSAdrian Chadd va_list ap; 13304336716bSAdrian Chadd va_start(ap, fmt); 13314336716bSAdrian Chadd pfatal("INTERNAL INCONSISTENCY:"); 133215fca934SKirk McKusick (void)vfprintf(stdout, fmt, ap); 13334336716bSAdrian Chadd va_end(ap); 13344336716bSAdrian Chadd exit(EEXIT); 13354336716bSAdrian Chadd } 1336