1 /* $NetBSD: pass5.c,v 1.39 2025/12/12 15:53:57 perseant Exp $ */ 2 3 /*- 4 * Copyright (c) 2000, 2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Konrad E. Schroder <perseant (at) hhhh.org>. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/param.h> 34 #include <sys/time.h> 35 #include <sys/buf.h> 36 #include <sys/mount.h> 37 38 #define vnode uvnode 39 #include <ufs/lfs/lfs.h> 40 #include <ufs/lfs/lfs_accessors.h> 41 #include <ufs/lfs/lfs_inode.h> 42 #undef vnode 43 44 #include <string.h> 45 46 #include "bufcache.h" 47 #include "lfs_user.h" 48 49 #include "fsck.h" 50 #include "extern.h" 51 #include "fsutil.h" 52 53 extern int Sflag; 54 55 void 56 pass5(void) 57 { 58 SEGUSE *su; 59 struct ubuf *bp; 60 int i, nsb, curr, labelcorrect, mfs; 61 daddr_t bb; /* total number of used blocks (lower bound) */ 62 daddr_t ubb; /* upper bound number of used blocks */ 63 daddr_t avail; /* blocks available for writing */ 64 daddr_t bfree_observed, bfree_lb, bfree_ub; /* blocks nominally free */ 65 unsigned long dmeta; /* blocks in segsums and inodes */ 66 int nclean; /* clean segments */ 67 size_t labelskew; 68 int diddirty; 69 70 /* 71 * Check segment holdings against actual holdings. Check for 72 * "clean" segments that contain live data. If we are only 73 * rolling forward, we can't check the segment holdings, but 74 * we can still check the cleanerinfo data. 75 */ 76 nclean = 0; 77 avail = 0; 78 bb = ubb = 0; 79 dmeta = 0; 80 nsb = curr = labelcorrect = mfs = 0; 81 for (i = 0; i < lfs_sb_getnseg(fs); i++) { 82 diddirty = 0; 83 LFS_SEGENTRY(su, fs, i, bp); 84 if (!preen && !(su->su_flags & SEGUSE_DIRTY) && 85 seg_table[i].su_nbytes > 0) { 86 pwarn("CLEAN SEGMENT %d CONTAINS %d BYTES\n", 87 i, seg_table[i].su_nbytes); 88 if (reply("MARK SEGMENT DIRTY")) { 89 su->su_flags |= SEGUSE_DIRTY; 90 ++diddirty; 91 } 92 } 93 if (!preen && su->su_nbytes != seg_table[i].su_nbytes) { 94 pwarn("SEGMENT %d CLAIMS %d BYTES BUT HAS %d", 95 i, su->su_nbytes, seg_table[i].su_nbytes); 96 if ((int32_t)su->su_nbytes > 97 (int32_t)seg_table[i].su_nbytes) 98 pwarn(" (HIGH BY %d)\n", su->su_nbytes - 99 seg_table[i].su_nbytes); 100 else 101 pwarn(" (LOW BY %d)\n", -su->su_nbytes + 102 seg_table[i].su_nbytes); 103 if (reply("FIX")) { 104 su->su_nbytes = seg_table[i].su_nbytes; 105 ++diddirty; 106 } 107 } 108 if (su->su_flags & SEGUSE_DIRTY) { 109 bb += lfs_btofsb(fs, su->su_nbytes + 110 su->su_nsums * lfs_sb_getsumsize(fs)); 111 ubb += lfs_btofsb(fs, su->su_nbytes + 112 su->su_nsums * lfs_sb_getsumsize(fs) + 113 su->su_ninos * lfs_sb_getibsize(fs)); 114 dmeta += lfs_btofsb(fs, 115 lfs_sb_getsumsize(fs) * su->su_nsums); 116 dmeta += lfs_btofsb(fs, 117 lfs_sb_getibsize(fs) * su->su_ninos); 118 } else { 119 nclean++; 120 avail += lfs_segtod(fs, 1); 121 if (su->su_flags & SEGUSE_SUPERBLOCK) 122 ++nsb; 123 if (i == 0 && lfs_sb_getversion(fs) > 1 && 124 lfs_sb_gets0addr(fs) < lfs_btofsb(fs, LFS_LABELPAD)) 125 labelcorrect = lfs_btofsb(fs, LFS_LABELPAD) - 126 lfs_sb_gets0addr(fs); 127 } 128 if (diddirty) 129 VOP_BWRITE(bp); 130 else 131 brelse(bp, 0); 132 } 133 134 /* Also may be available bytes in current seg */ 135 i = lfs_dtosn(fs, lfs_sb_getoffset(fs)); 136 curr = lfs_sntod(fs, i + 1) - lfs_sb_getoffset(fs); 137 /* But do not count minfreesegs */ 138 mfs = lfs_segtod(fs, (lfs_sb_getminfreeseg(fs) - 139 (lfs_sb_getminfreeseg(fs) / 2))); 140 141 avail = nclean * lfs_segtod(fs, 1); 142 avail -= nsb * lfs_btofsb(fs, LFS_SBPAD); 143 avail -= labelcorrect; 144 avail += curr; 145 avail -= mfs; 146 147 /* Note we may have bytes to write yet */ 148 avail -= lfs_btofsb(fs, locked_queue_bytes); 149 150 if (debug) 151 pwarn("avail := clean %jd*%jd - sb %jd*%jd - lbl %jd" 152 "+ curr %jd - mfs %jd - locked %jd = %jd\n", 153 (intmax_t)nclean, 154 (intmax_t)lfs_segtod(fs, 1), 155 (intmax_t)nsb, 156 (intmax_t)lfs_btofsb(fs, LFS_SBPAD), 157 (intmax_t)labelcorrect, 158 (intmax_t)curr, 159 (intmax_t)mfs, 160 (intmax_t)lfs_btofsb(fs, locked_queue_bytes), 161 (intmax_t)avail); 162 163 if (idaddr) 164 pwarn("NOTE: when using -i, expect discrepancies in dmeta," 165 " avail, nclean, bfree\n"); 166 if (dmeta != lfs_sb_getdmeta(fs)) { 167 pwarn("DMETA GIVEN AS %d, SHOULD BE %ld\n", 168 lfs_sb_getdmeta(fs), dmeta); 169 if (preen || reply("FIX")) { 170 lfs_sb_setdmeta(fs, dmeta); 171 sbdirty(); 172 } 173 } 174 if (avail != lfs_sb_getavail(fs) && !aflag) { 175 pwarn("AVAIL GIVEN AS %jd, SHOULD BE %jd\n", 176 (intmax_t)lfs_sb_getavail(fs), (intmax_t)avail); 177 if (preen || reply("FIX")) { 178 lfs_sb_setavail(fs, avail); 179 sbdirty(); 180 } 181 } 182 if (nclean != lfs_sb_getnclean(fs)) { 183 pwarn("NCLEAN GIVEN AS %d, SHOULD BE %d\n", lfs_sb_getnclean(fs), 184 nclean); 185 if (preen || reply("FIX")) { 186 lfs_sb_setnclean(fs, nclean); 187 sbdirty(); 188 } 189 } 190 191 labelskew = 0; 192 if (lfs_sb_getversion(fs) > 1 && 193 lfs_sb_gets0addr(fs) < lfs_btofsb(fs, LFS_LABELPAD)) 194 labelskew = lfs_btofsb(fs, LFS_LABELPAD); 195 bfree_ub = lfs_sb_getdsize(fs) - bb - labelskew; 196 bfree_lb = lfs_sb_getdsize(fs) - ubb - labelskew; 197 bfree_observed = (daddr_t)lfs_sb_getbfree(fs); 198 if (bfree_observed < bfree_lb || bfree_observed > bfree_ub) { 199 pwarn("BFREE GIVEN AS %jd, SHOULD BE BETWEEN %jd AND %jd\n", 200 (intmax_t)bfree_observed, 201 (intmax_t)bfree_lb, 202 (intmax_t)bfree_ub); 203 if (preen || reply("FIX")) { 204 lfs_sb_setbfree(fs, (bfree_lb + bfree_ub) / 2); 205 sbdirty(); 206 } 207 } 208 } 209