1 /* $NetBSD: pass0.c,v 1.24 2005/09/13 04:14:17 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1999, 2000, 2001, 2002, 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@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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 /*- 39 * Copyright (c) 1980, 1986, 1993 40 * The Regents of the University of California. All rights reserved. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. Neither the name of the University nor the names of its contributors 51 * may be used to endorse or promote products derived from this software 52 * without specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 64 * SUCH DAMAGE. 65 */ 66 67 #include <sys/types.h> 68 #include <sys/param.h> 69 #include <sys/time.h> 70 #include <sys/buf.h> 71 #include <sys/mount.h> 72 73 #include <ufs/ufs/inode.h> 74 #include <ufs/ufs/dir.h> 75 #define vnode uvnode 76 #include <ufs/lfs/lfs.h> 77 #undef vnode 78 79 #include <stdio.h> 80 #include <stdlib.h> 81 #include <string.h> 82 83 #include "bufcache.h" 84 #include "vnode.h" 85 #include "lfs_user.h" 86 87 #include "fsck.h" 88 #include "extern.h" 89 #include "fsutil.h" 90 91 extern int fake_cleanseg; 92 93 /* 94 * Pass 0. Check the LFS partial segments for valid checksums, correcting 95 * if necessary. Also check for valid offsets for inode and finfo blocks. 96 */ 97 /* 98 * XXX more could be done here---consistency between inode-held blocks and 99 * finfo blocks, for one thing. 100 */ 101 102 #define dbshift (fs->lfs_bshift - fs->lfs_blktodb) 103 104 void 105 pass0(void) 106 { 107 daddr_t daddr; 108 CLEANERINFO *cip; 109 IFILE *ifp; 110 struct ubuf *bp; 111 ino_t ino, plastino, nextino, *visited, lowfreeino; 112 int writeit = 0; 113 int count; 114 long long totaldist; 115 116 /* 117 * Check the inode free list for inuse inodes, and cycles. 118 * Make sure that all free inodes are in fact on the list. 119 */ 120 visited = (ino_t *) malloc(maxino * sizeof(ino_t)); 121 memset(visited, 0, maxino * sizeof(ino_t)); 122 123 #ifdef BAD 124 /* 125 * Scramble the free list, to trigger the optimizer below. 126 * You don't want this unless you are debugging fsck_lfs itself. 127 */ 128 if (!preen && reply("SCRAMBLE FREE LIST") == 1) { 129 ino_t topino, botino, tail; 130 botino = 0; 131 topino = maxino; 132 while (botino < topino) { 133 for (--topino; botino < topino; --topino) { 134 LFS_IENTRY(ifp, fs, topino, bp); 135 if (ifp->if_daddr == 0) 136 break; 137 brelse(bp); 138 bp = NULL; 139 } 140 if (topino == botino) 141 break; 142 if (botino > 0) { 143 ifp->if_nextfree = botino; 144 } else { 145 ifp->if_nextfree = 0x0; 146 tail = topino; 147 } 148 VOP_BWRITE(bp); 149 ino = topino; 150 151 for (++botino; botino < topino; ++botino) { 152 LFS_IENTRY(ifp, fs, botino, bp); 153 if (ifp->if_daddr == 0) 154 break; 155 brelse(bp); 156 bp = NULL; 157 } 158 if (topino == botino) 159 break; 160 ifp->if_nextfree = topino; 161 VOP_BWRITE(bp); 162 ino = botino; 163 } 164 LFS_CLEANERINFO(cip, fs, bp); 165 cip->free_head = fs->lfs_freehd = ino; 166 cip->free_tail = tail; 167 LFS_SYNC_CLEANERINFO(cip, fs, bp, 1); 168 } 169 #endif /* BAD */ 170 171 count = 0; 172 plastino = 0; 173 totaldist = 0; 174 lowfreeino = maxino; 175 ino = fs->lfs_freehd; 176 while (ino) { 177 if (lowfreeino > ino) 178 lowfreeino = ino; 179 if (plastino > 0) { 180 totaldist += abs(ino - plastino); 181 ++count; 182 } 183 if (ino >= maxino) { 184 printf("! Ino %llu out of range (last was %llu)\n", 185 (unsigned long long)ino, 186 (unsigned long long)plastino); 187 break; 188 } 189 if (visited[ino]) { 190 pwarn("! Ino %llu already found on the free list!\n", 191 (unsigned long long)ino); 192 if (preen || reply("FIX") == 1) { 193 /* plastino can't be zero */ 194 LFS_IENTRY(ifp, fs, plastino, bp); 195 ifp->if_nextfree = 0; 196 VOP_BWRITE(bp); 197 } 198 break; 199 } 200 ++visited[ino]; 201 LFS_IENTRY(ifp, fs, ino, bp); 202 nextino = ifp->if_nextfree; 203 daddr = ifp->if_daddr; 204 brelse(bp); 205 if (daddr) { 206 pwarn("! Ino %llu with daddr 0x%llx is on the " 207 "free list!\n", 208 (unsigned long long)ino, (long long) daddr); 209 if (preen || reply("FIX") == 1) { 210 if (plastino == 0) { 211 fs->lfs_freehd = nextino; 212 sbdirty(); 213 } else { 214 LFS_IENTRY(ifp, fs, plastino, bp); 215 ifp->if_nextfree = nextino; 216 VOP_BWRITE(bp); 217 } 218 ino = nextino; 219 continue; 220 } 221 } 222 plastino = ino; 223 ino = nextino; 224 } 225 226 227 /* 228 * Make sure all free inodes were found on the list 229 */ 230 for (ino = ROOTINO + 1; ino < maxino; ++ino) { 231 if (visited[ino]) 232 continue; 233 234 LFS_IENTRY(ifp, fs, ino, bp); 235 if (ifp->if_daddr) { 236 brelse(bp); 237 continue; 238 } 239 pwarn("! Ino %llu free, but not on the free list\n", 240 (unsigned long long)ino); 241 if (preen || reply("FIX") == 1) { 242 ifp->if_nextfree = fs->lfs_freehd; 243 fs->lfs_freehd = ino; 244 sbdirty(); 245 VOP_BWRITE(bp); 246 } else 247 brelse(bp); 248 } 249 250 LFS_CLEANERINFO(cip, fs, bp); 251 if (cip->free_head != fs->lfs_freehd) { 252 pwarn("! Free list head should be %d (was %d)\n", 253 fs->lfs_freehd, cip->free_head); 254 if (preen || reply("FIX")) { 255 cip->free_head = fs->lfs_freehd; 256 writeit = 1; 257 } 258 } 259 if (cip->free_tail != plastino) { 260 pwarn("! Free list tail should be %llu (was %d)\n", 261 (unsigned long long)plastino, cip->free_tail); 262 if (preen || reply("FIX")) { 263 cip->free_tail = plastino; 264 writeit = 1; 265 } 266 } 267 if (writeit) 268 LFS_SYNC_CLEANERINFO(cip, fs, bp, writeit); 269 else 270 brelse(bp); 271 272 if (fs->lfs_freehd == 0) { 273 pwarn("%sree list head is 0x0\n", preen ? "f" : "F"); 274 if (preen || reply("FIX")) { 275 extend_ifile(fs); 276 reset_maxino(((VTOI(fs->lfs_ivnode)->i_ffs1_size >> 277 fs->lfs_bsize) - 278 fs->lfs_segtabsz - fs->lfs_cleansz) * 279 fs->lfs_ifpb); 280 } 281 } 282 283 /* 284 * Check the distance between sequential free list entries. 285 * An ideally ordered free list will have the sum of these 286 * distances <= the number of inodes in the inode list. 287 * If the observed distance is too high, reorder the list. 288 * Strictly speaking, this is not an error, but it optimizes the 289 * speed in creation of files and should help a tiny bit with 290 * cleaner thrash as well. 291 */ 292 if (totaldist > 4 * maxino) { 293 pwarn("%sotal inode list traversal length %" PRIu64 "x list length%s\n", 294 (preen ? "t" : "T"), totaldist/maxino, 295 (preen ? ", optimizing" : "")); 296 if (preen || reply("OPTIMIZE") == 1) { 297 plastino = lowfreeino; 298 for (ino = lowfreeino + 1; ino < maxino; ino++) { 299 LFS_IENTRY(ifp, fs, ino, bp); 300 daddr = ifp->if_daddr; 301 brelse(bp); 302 if (daddr == 0) { 303 LFS_IENTRY(ifp, fs, plastino, bp); 304 ifp->if_nextfree = ino; 305 VOP_BWRITE(bp); 306 plastino = ino; 307 } 308 } 309 LFS_CLEANERINFO(cip, fs, bp); 310 cip->free_head = fs->lfs_freehd = lowfreeino; 311 cip->free_tail = plastino; 312 LFS_SYNC_CLEANERINFO(cip, fs, bp, 1); 313 } 314 } 315 } 316