1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause AND BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2006 Pawel Jakub Dawidek <pjd@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * Copyright (c) 1982, 1986, 1989, 1993 29 * The Regents of the University of California. All rights reserved. 30 * 31 * Redistribution and use in source and binary forms, with or without 32 * modification, are permitted provided that the following conditions 33 * are met: 34 * 1. Redistributions of source code must retain the above copyright 35 * notice, this list of conditions and the following disclaimer. 36 * 2. Redistributions in binary form must reproduce the above copyright 37 * notice, this list of conditions and the following disclaimer in the 38 * documentation and/or other materials provided with the distribution. 39 * 3. Neither the name of the University nor the names of its contributors 40 * may be used to endorse or promote products derived from this software 41 * without specific prior written permission. 42 * 43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 53 * SUCH DAMAGE. 54 */ 55 56 #include <sys/cdefs.h> 57 __FBSDID("$FreeBSD$"); 58 59 #include <sys/param.h> 60 #include <sys/disklabel.h> 61 #include <sys/mount.h> 62 #include <sys/stat.h> 63 64 #include <ufs/ufs/ufsmount.h> 65 #include <ufs/ufs/dinode.h> 66 #include <ufs/ffs/fs.h> 67 68 #include <stdio.h> 69 #include <stdlib.h> 70 #include <stdint.h> 71 #include <libufs.h> 72 #include <strings.h> 73 #include <err.h> 74 #include <assert.h> 75 76 #include "fsck.h" 77 78 struct cgchain { 79 union { 80 struct cg cgcu_cg; 81 char cgcu_buf[MAXBSIZE]; 82 } cgc_union; 83 int cgc_busy; 84 int cgc_dirty; 85 LIST_ENTRY(cgchain) cgc_next; 86 }; 87 #define cgc_cg cgc_union.cgcu_cg 88 89 #define MAX_CACHED_CGS 1024 90 static unsigned ncgs = 0; 91 static LIST_HEAD(, cgchain) cglist = LIST_HEAD_INITIALIZER(cglist); 92 93 static const char *devnam; 94 static struct uufsd *disk = NULL; 95 static struct fs *fs = NULL; 96 struct ufs2_dinode ufs2_zino; 97 98 static void putcgs(void); 99 100 /* 101 * Return cylinder group from the cache or load it if it is not in the 102 * cache yet. 103 * Don't cache more than MAX_CACHED_CGS cylinder groups. 104 */ 105 static struct cgchain * 106 getcg(int cg) 107 { 108 struct cgchain *cgc; 109 110 assert(disk != NULL && fs != NULL); 111 LIST_FOREACH(cgc, &cglist, cgc_next) { 112 if (cgc->cgc_cg.cg_cgx == cg) { 113 //printf("%s: Found cg=%d\n", __func__, cg); 114 return (cgc); 115 } 116 } 117 /* 118 * Our cache is full? Let's clean it up. 119 */ 120 if (ncgs >= MAX_CACHED_CGS) { 121 //printf("%s: Flushing CGs.\n", __func__); 122 putcgs(); 123 } 124 cgc = malloc(sizeof(*cgc)); 125 if (cgc == NULL) { 126 /* 127 * Cannot allocate memory? 128 * Let's put all currently loaded and not busy cylinder groups 129 * on disk and try again. 130 */ 131 //printf("%s: No memory, flushing CGs.\n", __func__); 132 putcgs(); 133 cgc = malloc(sizeof(*cgc)); 134 if (cgc == NULL) 135 err(1, "malloc(%zu)", sizeof(*cgc)); 136 } 137 if (cgread1(disk, cg) == -1) 138 err(1, "cgread1(%d)", cg); 139 bcopy(&disk->d_cg, &cgc->cgc_cg, sizeof(cgc->cgc_union)); 140 cgc->cgc_busy = 0; 141 cgc->cgc_dirty = 0; 142 LIST_INSERT_HEAD(&cglist, cgc, cgc_next); 143 ncgs++; 144 //printf("%s: Read cg=%d\n", __func__, cg); 145 return (cgc); 146 } 147 148 /* 149 * Mark cylinder group as dirty - it will be written back on putcgs(). 150 */ 151 static void 152 dirtycg(struct cgchain *cgc) 153 { 154 155 cgc->cgc_dirty = 1; 156 } 157 158 /* 159 * Mark cylinder group as busy - it will not be freed on putcgs(). 160 */ 161 static void 162 busycg(struct cgchain *cgc) 163 { 164 165 cgc->cgc_busy = 1; 166 } 167 168 /* 169 * Unmark the given cylinder group as busy. 170 */ 171 static void 172 unbusycg(struct cgchain *cgc) 173 { 174 175 cgc->cgc_busy = 0; 176 } 177 178 /* 179 * Write back all dirty cylinder groups. 180 * Free all non-busy cylinder groups. 181 */ 182 static void 183 putcgs(void) 184 { 185 struct cgchain *cgc, *cgc2; 186 187 assert(disk != NULL && fs != NULL); 188 LIST_FOREACH_SAFE(cgc, &cglist, cgc_next, cgc2) { 189 if (cgc->cgc_busy) 190 continue; 191 LIST_REMOVE(cgc, cgc_next); 192 ncgs--; 193 if (cgc->cgc_dirty) { 194 bcopy(&cgc->cgc_cg, &disk->d_cg, 195 sizeof(cgc->cgc_union)); 196 if (cgwrite1(disk, cgc->cgc_cg.cg_cgx) == -1) 197 err(1, "cgwrite1(%d)", cgc->cgc_cg.cg_cgx); 198 //printf("%s: Wrote cg=%d\n", __func__, 199 // cgc->cgc_cg.cg_cgx); 200 } 201 free(cgc); 202 } 203 } 204 205 #if 0 206 /* 207 * Free all non-busy cylinder groups without storing the dirty ones. 208 */ 209 static void 210 cancelcgs(void) 211 { 212 struct cgchain *cgc; 213 214 assert(disk != NULL && fs != NULL); 215 while ((cgc = LIST_FIRST(&cglist)) != NULL) { 216 if (cgc->cgc_busy) 217 continue; 218 LIST_REMOVE(cgc, cgc_next); 219 //printf("%s: Canceled cg=%d\n", __func__, cgc->cgc_cg.cg_cgx); 220 free(cgc); 221 } 222 } 223 #endif 224 225 /* 226 * Open the given provider, load superblock. 227 */ 228 static void 229 opendisk(void) 230 { 231 if (disk != NULL) 232 return; 233 disk = malloc(sizeof(*disk)); 234 if (disk == NULL) 235 err(1, "malloc(%zu)", sizeof(*disk)); 236 if (ufs_disk_fillout(disk, devnam) == -1) { 237 err(1, "ufs_disk_fillout(%s) failed: %s", devnam, 238 disk->d_error); 239 } 240 fs = &disk->d_fs; 241 } 242 243 /* 244 * Mark file system as clean, write the super-block back, close the disk. 245 */ 246 static void 247 closedisk(void) 248 { 249 250 fs->fs_clean = 1; 251 if (sbwrite(disk, 0) == -1) 252 err(1, "sbwrite(%s)", devnam); 253 if (ufs_disk_close(disk) == -1) 254 err(1, "ufs_disk_close(%s)", devnam); 255 free(disk); 256 disk = NULL; 257 fs = NULL; 258 } 259 260 static void 261 blkfree(ufs2_daddr_t bno, long size) 262 { 263 struct cgchain *cgc; 264 struct cg *cgp; 265 ufs1_daddr_t fragno, cgbno; 266 int i, cg, blk, frags, bbase; 267 u_int8_t *blksfree; 268 269 cg = dtog(fs, bno); 270 cgc = getcg(cg); 271 dirtycg(cgc); 272 cgp = &cgc->cgc_cg; 273 cgbno = dtogd(fs, bno); 274 blksfree = cg_blksfree(cgp); 275 if (size == fs->fs_bsize) { 276 fragno = fragstoblks(fs, cgbno); 277 if (!ffs_isfreeblock(fs, blksfree, fragno)) 278 assert(!"blkfree: freeing free block"); 279 ffs_setblock(fs, blksfree, fragno); 280 ffs_clusteracct(fs, cgp, fragno, 1); 281 cgp->cg_cs.cs_nbfree++; 282 fs->fs_cstotal.cs_nbfree++; 283 fs->fs_cs(fs, cg).cs_nbfree++; 284 } else { 285 bbase = cgbno - fragnum(fs, cgbno); 286 /* 287 * decrement the counts associated with the old frags 288 */ 289 blk = blkmap(fs, blksfree, bbase); 290 ffs_fragacct(fs, blk, cgp->cg_frsum, -1); 291 /* 292 * deallocate the fragment 293 */ 294 frags = numfrags(fs, size); 295 for (i = 0; i < frags; i++) { 296 if (isset(blksfree, cgbno + i)) 297 assert(!"blkfree: freeing free frag"); 298 setbit(blksfree, cgbno + i); 299 } 300 cgp->cg_cs.cs_nffree += i; 301 fs->fs_cstotal.cs_nffree += i; 302 fs->fs_cs(fs, cg).cs_nffree += i; 303 /* 304 * add back in counts associated with the new frags 305 */ 306 blk = blkmap(fs, blksfree, bbase); 307 ffs_fragacct(fs, blk, cgp->cg_frsum, 1); 308 /* 309 * if a complete block has been reassembled, account for it 310 */ 311 fragno = fragstoblks(fs, bbase); 312 if (ffs_isblock(fs, blksfree, fragno)) { 313 cgp->cg_cs.cs_nffree -= fs->fs_frag; 314 fs->fs_cstotal.cs_nffree -= fs->fs_frag; 315 fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag; 316 ffs_clusteracct(fs, cgp, fragno, 1); 317 cgp->cg_cs.cs_nbfree++; 318 fs->fs_cstotal.cs_nbfree++; 319 fs->fs_cs(fs, cg).cs_nbfree++; 320 } 321 } 322 } 323 324 /* 325 * Recursively free all indirect blocks. 326 */ 327 static void 328 freeindir(ufs2_daddr_t blk, int level) 329 { 330 char sblks[MAXBSIZE]; 331 ufs2_daddr_t *blks; 332 int i; 333 334 if (bread(disk, fsbtodb(fs, blk), (void *)&sblks, (size_t)fs->fs_bsize) == -1) 335 err(1, "bread: %s", disk->d_error); 336 blks = (ufs2_daddr_t *)&sblks; 337 for (i = 0; i < NINDIR(fs); i++) { 338 if (blks[i] == 0) 339 break; 340 if (level == 0) 341 blkfree(blks[i], fs->fs_bsize); 342 else 343 freeindir(blks[i], level - 1); 344 } 345 blkfree(blk, fs->fs_bsize); 346 } 347 348 #define dblksize(fs, dino, lbn) \ 349 ((dino)->di_size >= smalllblktosize(fs, (lbn) + 1) \ 350 ? (fs)->fs_bsize \ 351 : fragroundup(fs, blkoff(fs, (dino)->di_size))) 352 353 /* 354 * Free all blocks associated with the given inode. 355 */ 356 static void 357 clear_inode(struct ufs2_dinode *dino) 358 { 359 ufs2_daddr_t bn; 360 int extblocks, i, level; 361 off_t osize; 362 long bsize; 363 364 extblocks = 0; 365 if (fs->fs_magic == FS_UFS2_MAGIC && dino->di_extsize > 0) 366 extblocks = btodb(fragroundup(fs, dino->di_extsize)); 367 /* deallocate external attributes blocks */ 368 if (extblocks > 0) { 369 osize = dino->di_extsize; 370 dino->di_blocks -= extblocks; 371 dino->di_extsize = 0; 372 for (i = 0; i < UFS_NXADDR; i++) { 373 if (dino->di_extb[i] == 0) 374 continue; 375 blkfree(dino->di_extb[i], sblksize(fs, osize, i)); 376 } 377 } 378 #define SINGLE 0 /* index of single indirect block */ 379 #define DOUBLE 1 /* index of double indirect block */ 380 #define TRIPLE 2 /* index of triple indirect block */ 381 /* deallocate indirect blocks */ 382 for (level = SINGLE; level <= TRIPLE; level++) { 383 if (dino->di_ib[level] == 0) 384 break; 385 freeindir(dino->di_ib[level], level); 386 } 387 /* deallocate direct blocks and fragments */ 388 for (i = 0; i < UFS_NDADDR; i++) { 389 bn = dino->di_db[i]; 390 if (bn == 0) 391 continue; 392 bsize = dblksize(fs, dino, i); 393 blkfree(bn, bsize); 394 } 395 } 396 397 void 398 gjournal_check(const char *filesys) 399 { 400 struct ufs2_dinode *dino; 401 void *p; 402 struct cgchain *cgc; 403 struct cg *cgp; 404 uint8_t *inosused; 405 ino_t cino, ino; 406 int cg, mode; 407 408 devnam = filesys; 409 opendisk(); 410 /* Are there any unreferenced inodes in this file system? */ 411 if (fs->fs_unrefs == 0) { 412 //printf("No unreferenced inodes.\n"); 413 closedisk(); 414 return; 415 } 416 417 for (cg = 0; cg < fs->fs_ncg; cg++) { 418 /* Show progress if requested. */ 419 if (got_siginfo) { 420 printf("%s: phase j: cyl group %d of %d (%d%%)\n", 421 cdevname, cg, fs->fs_ncg, cg * 100 / fs->fs_ncg); 422 got_siginfo = 0; 423 } 424 if (got_sigalarm) { 425 setproctitle("%s pj %d%%", cdevname, 426 cg * 100 / fs->fs_ncg); 427 got_sigalarm = 0; 428 } 429 cgc = getcg(cg); 430 cgp = &cgc->cgc_cg; 431 /* Are there any unreferenced inodes in this cylinder group? */ 432 if (cgp->cg_unrefs == 0) 433 continue; 434 //printf("Analizing cylinder group %d (count=%d)\n", cg, cgp->cg_unrefs); 435 /* 436 * We are going to modify this cylinder group, so we want it to 437 * be written back. 438 */ 439 dirtycg(cgc); 440 /* We don't want it to be freed in the meantime. */ 441 busycg(cgc); 442 inosused = cg_inosused(cgp); 443 /* 444 * Now go through the list of all inodes in this cylinder group 445 * to find unreferenced ones. 446 */ 447 for (cino = 0; cino < fs->fs_ipg; cino++) { 448 ino = fs->fs_ipg * cg + cino; 449 /* Unallocated? Skip it. */ 450 if (isclr(inosused, cino)) 451 continue; 452 if (getino(disk, &p, ino, &mode) == -1) 453 err(1, "getino(cg=%d ino=%ju)", 454 cg, (uintmax_t)ino); 455 dino = p; 456 /* Not a regular file nor directory? Skip it. */ 457 if (!S_ISREG(dino->di_mode) && !S_ISDIR(dino->di_mode)) 458 continue; 459 /* Has reference(s)? Skip it. */ 460 if (dino->di_nlink > 0) 461 continue; 462 //printf("Clearing inode=%d (size=%jd)\n", ino, (intmax_t)dino->di_size); 463 /* Free inode's blocks. */ 464 clear_inode(dino); 465 /* Deallocate it. */ 466 clrbit(inosused, cino); 467 /* Update position of last used inode. */ 468 if (ino < cgp->cg_irotor) 469 cgp->cg_irotor = ino; 470 /* Update statistics. */ 471 cgp->cg_cs.cs_nifree++; 472 fs->fs_cs(fs, cg).cs_nifree++; 473 fs->fs_cstotal.cs_nifree++; 474 cgp->cg_unrefs--; 475 fs->fs_unrefs--; 476 /* If this is directory, update related statistics. */ 477 if (S_ISDIR(dino->di_mode)) { 478 cgp->cg_cs.cs_ndir--; 479 fs->fs_cs(fs, cg).cs_ndir--; 480 fs->fs_cstotal.cs_ndir--; 481 } 482 /* Zero-fill the inode. */ 483 *dino = ufs2_zino; 484 /* Write the inode back. */ 485 if (putino(disk) == -1) 486 err(1, "putino(cg=%d ino=%ju)", 487 cg, (uintmax_t)ino); 488 if (cgp->cg_unrefs == 0) { 489 //printf("No more unreferenced inodes in cg=%d.\n", cg); 490 break; 491 } 492 } 493 /* 494 * We don't need this cylinder group anymore, so feel free to 495 * free it if needed. 496 */ 497 unbusycg(cgc); 498 /* 499 * If there are no more unreferenced inodes, there is no need to 500 * check other cylinder groups. 501 */ 502 if (fs->fs_unrefs == 0) { 503 //printf("No more unreferenced inodes (cg=%d/%d).\n", cg, 504 // fs->fs_ncg); 505 break; 506 } 507 } 508 /* Write back modified cylinder groups. */ 509 putcgs(); 510 /* Write back updated statistics and super-block. */ 511 closedisk(); 512 } 513