1 /* $NetBSD: lfs_rfw.c,v 1.48 2026/09/23 17:47:52 perseant Exp $ */ 2 3 /*- 4 * Copyright (c) 1999, 2000, 2001, 2002, 2003, 2025 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/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: lfs_rfw.c,v 1.48 2026/09/23 17:47:52 perseant Exp $"); 34 35 #if defined(_KERNEL_OPT) 36 #include "opt_quota.h" 37 #endif 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/namei.h> 42 #include <sys/proc.h> 43 #include <sys/kernel.h> 44 #include <sys/vnode.h> 45 #include <sys/mount.h> 46 #include <sys/kthread.h> 47 #include <sys/buf.h> 48 #include <sys/device.h> 49 #include <sys/file.h> 50 #include <sys/disklabel.h> 51 #include <sys/ioctl.h> 52 #include <sys/errno.h> 53 #include <sys/malloc.h> 54 #include <sys/pool.h> 55 #include <sys/socket.h> 56 #include <sys/stat.h> 57 #include <sys/syslog.h> 58 #include <sys/sysctl.h> 59 #include <sys/conf.h> 60 #include <sys/kauth.h> 61 62 #include <miscfs/specfs/specdev.h> 63 64 #include <ufs/lfs/ulfs_quotacommon.h> 65 #include <ufs/lfs/ulfs_inode.h> 66 #include <ufs/lfs/ulfsmount.h> 67 #include <ufs/lfs/ulfs_extern.h> 68 69 #include <uvm/uvm_extern.h> 70 71 #include <ufs/lfs/lfs.h> 72 #include <ufs/lfs/lfs_accessors.h> 73 #include <ufs/lfs/lfs_kernel.h> 74 #include <ufs/lfs/lfs_extern.h> 75 76 #include <miscfs/genfs/genfs.h> 77 #include <miscfs/genfs/genfs_node.h> 78 79 /* 80 * Roll-forward code. 81 */ 82 static bool all_selector(void *, struct vnode *); 83 static void drop_vnode_pages(struct mount *, struct lwp *); 84 static void update_inoblk_copy_dinode(struct lfs *, union lfs_dinode *, 85 const union lfs_dinode *); 86 static int update_inogen(struct lfs_inofuncarg *); 87 static int update_inoblk(struct lfs_inofuncarg *); 88 static int finfo_func_rfw(struct lfs_finfofuncarg *); 89 static int raise_maxino(struct lfs *, ino_t); 90 91 static int update_meta(struct lfs *, ino_t, int, daddr_t, daddr_t, size_t, 92 struct lwp *l); 93 #if 0 94 static bool lfs_isseq(const struct lfs *fs, long int lbn1, long int lbn2); 95 #endif 96 97 extern int lfs_do_rfw; 98 int rblkcnt; 99 int lfs_rfw_max_psegs = 0; 100 101 static int 102 raise_maxino(struct lfs *fs, ino_t ino) 103 { 104 int error = 0; 105 106 while (ino >= LFS_MAXINO(fs)) { 107 error = lfs_extend_ifile(fs, NOCRED); 108 if (error) 109 break; 110 } 111 return error; 112 } 113 114 /* 115 * Allocate a particular inode with a particular version number, freeing 116 * any previous versions of this inode that may have gone before. 117 * Used by the roll-forward code. 118 * 119 * XXX this function does not have appropriate locking to be used on a live fs; 120 * XXX but something similar could probably be used for an "undelete" call. 121 * 122 * Called with the Ifile inode locked. 123 */ 124 int 125 lfs_rf_valloc(struct lfs *fs, ino_t ino, int vers, struct lwp *l, 126 struct vnode **vpp, union lfs_dinode *dip) 127 { 128 struct vattr va; 129 struct vnode *vp; 130 struct inode *ip; 131 int error; 132 133 ASSERT_SEGLOCK(fs); /* XXX it doesn't, really */ 134 135 KASSERTMSG(ino > LFS_IFILE_INUM, "ino=%lld", (long long)ino); 136 if ((error = raise_maxino(fs, ino)) != 0) 137 return error; 138 139 /* 140 * First, just try a vget. If the version number is the one we want, 141 * we don't have to do anything else. If the version number is wrong, 142 * take appropriate action. 143 */ 144 error = VFS_VGET(fs->lfs_ivnode->v_mount, ino, LK_EXCLUSIVE, &vp); 145 if (error == 0) { 146 DLOG((DLOG_RF, "lfs_rf_valloc[1]: ino %d vp %p\n", 147 (int)ino, vp)); 148 149 *vpp = vp; 150 ip = VTOI(vp); 151 DLOG((DLOG_RF, " ip->i_gen=%jd dip nlink %jd seeking" 152 " version %jd\n", (intmax_t)ip->i_gen, 153 (intmax_t)(dip == NULL ? -1 154 : lfs_dino_getnlink(fs, dip)), (intmax_t)vers)); 155 if (ip->i_gen == vers) { 156 /* 157 * We have what we wanted already. 158 */ 159 DLOG((DLOG_RF, " pre-existing\n")); 160 return 0; 161 } else if (ip->i_gen < vers && dip != NULL 162 && lfs_dino_getnlink(fs, dip) > 0) { 163 /* 164 * We have found a newer version. Truncate 165 * the old vnode to zero and re-initialize 166 * from the given dinode. 167 */ 168 DLOG((DLOG_RF, " replace old version %jd\n", 169 (intmax_t)ip->i_gen)); 170 lfs_truncate(vp, (off_t)0, 0, NOCRED); 171 ip->i_gen = vers; 172 vp->v_type = IFTOVT(lfs_dino_getmode(fs, dip)); 173 update_inoblk_copy_dinode(fs, ip->i_din, dip); 174 LFS_SET_UINO(ip, IN_CHANGE | IN_UPDATE); 175 return 0; 176 } else { 177 /* 178 * Not the right version and nothing to 179 * initialize from. Don't recover this data. 180 */ 181 DLOG((DLOG_RF, "ino %d: sought version %d, got %d\n", 182 (int)ino, (int)vers, 183 (int)lfs_dino_getgen(fs, ip->i_din))); 184 vput(vp); 185 *vpp = NULLVP; 186 return EEXIST; 187 } 188 } 189 190 /* 191 * No version of this inode was found in the cache. 192 * Make a new one from the dinode. We will add data blocks 193 * as they come in, so scrub any block addresses off of the 194 * inode and reset block counts to zero. 195 */ 196 if (dip == NULL) 197 return ENOENT; 198 199 vattr_null(&va); 200 va.va_type = IFTOVT(lfs_dino_getmode(fs, dip)); 201 va.va_mode = lfs_dino_getmode(fs, dip) & ALLPERMS; 202 va.va_fileid = ino; 203 va.va_gen = vers; 204 error = vcache_new(fs->lfs_ivnode->v_mount, NULL, &va, NOCRED, NULL, 205 &vp); 206 if (error) 207 return error; 208 error = vn_lock(vp, LK_EXCLUSIVE); 209 if (error) 210 goto err; 211 212 ip = VTOI(vp); 213 update_inoblk_copy_dinode(fs, ip->i_din, dip); 214 215 DLOG((DLOG_RF, "lfs_valloc[2] ino %d vp %p size=%lld effnblks=%d," 216 " blocks=%d\n", (int)ino, vp, (long long)ip->i_size, 217 (int)ip->i_lfs_effnblks, 218 (int)lfs_dino_getblocks(fs, ip->i_din))); 219 *vpp = vp; 220 return 0; 221 222 err: 223 vrele(vp); 224 *vpp = NULLVP; 225 return error; 226 } 227 228 /* 229 * Load the appropriate indirect block, and change the appropriate pointer. 230 * Mark the block dirty. Do segment and avail accounting. 231 */ 232 static int 233 update_meta(struct lfs *fs, ino_t ino, int vers, daddr_t lbn, 234 daddr_t ndaddr, size_t size, struct lwp *l) 235 { 236 int error; 237 struct vnode *vp; 238 struct inode *ip; 239 daddr_t odaddr; 240 struct indir a[ULFS_NIADDR]; 241 int num; 242 struct buf *bp; 243 SEGUSE *sup; 244 u_int64_t newsize, loff; 245 246 KASSERTMSG(lbn >= 0, "lbn=%lld", /* no indirect blocks */ 247 (long long)lbn); 248 KASSERTMSG(ino > LFS_IFILE_INUM, "ino=%lld", (long long)ino); 249 250 DLOG((DLOG_RF, "update_meta: ino %d lbn %d size %d at 0x%jx\n", 251 (int)ino, (int)lbn, (int)size, (uintmax_t)ndaddr)); 252 253 if ((error = lfs_rf_valloc(fs, ino, vers, l, &vp, NULL)) != 0) 254 return error; 255 ip = VTOI(vp); 256 257 /* 258 * If block already exists, note its new location 259 * but do not account it as new. 260 */ 261 ulfs_bmaparray(vp, lbn, &odaddr, &a[0], &num, NULL, NULL); 262 if (odaddr == UNASSIGNED) { 263 if ((error = lfs_balloc(vp, (lbn << lfs_sb_getbshift(fs)), 264 size, NOCRED, 0, &bp)) != 0) { 265 vput(vp); 266 return (error); 267 } 268 /* No need to write, the block is already on disk */ 269 if (bp->b_oflags & BO_DELWRI) { 270 LFS_UNLOCK_BUF(bp); 271 /* Account recovery of the previous version */ 272 lfs_sb_addavail(fs, lfs_btofsb(fs, bp->b_bcount)); 273 } 274 brelse(bp, BC_INVAL); 275 DLOG((DLOG_RF, "balloc ip->i_lfs_effnblks = %d," 276 " lfs_dino_getblocks(fs, ip->i_din) = %d\n", 277 (int)ip->i_lfs_effnblks, 278 (int)lfs_dino_getblocks(fs, ip->i_din))); 279 } else { 280 /* XXX fragextend? */ 281 DLOG((DLOG_RF, "block exists, no balloc\n")); 282 } 283 284 /* 285 * Extend the file, if it is not large enough already. 286 * XXX This is not exactly right, we don't know how much of the 287 * XXX last block is actually used. 288 * 289 * XXX We should be able to encode the actual data length of the 290 * XXX last block in fi_lastlength, since we can infer the 291 * XXX necessary block length from that using a variant of 292 * XXX lfs_blksize(). 293 */ 294 loff = lfs_lblktosize(fs, lbn); 295 if (loff >= (ULFS_NDADDR << lfs_sb_getbshift(fs))) { 296 /* No fragments */ 297 newsize = loff + 1; 298 } else { 299 /* Subtract only a fragment to account for block size */ 300 newsize = loff + size - lfs_fsbtob(fs, 1) + 1; 301 } 302 303 if (ip->i_size < newsize) { 304 DLOG((DLOG_RF, "ino %d size %d -> %d\n", 305 (int)ino, (int)ip->i_size, (int)newsize)); 306 lfs_dino_setsize(fs, ip->i_din, newsize); 307 ip->i_size = newsize; 308 /* 309 * tell vm our new size for the case the inode won't 310 * appear later. 311 */ 312 uvm_vnp_setsize(vp, newsize); 313 } 314 315 lfs_update_single(fs, NULL, vp, lbn, ndaddr, size); 316 317 LFS_SEGENTRY(sup, fs, lfs_dtosn(fs, ndaddr), bp); 318 DLOG((DLOG_SU, "seg %jd += %jd for ino %jd" 319 " lbn %jd db 0x%jd (rfw)\n", 320 (intmax_t)lfs_dtosn(fs, ndaddr), 321 (intmax_t)size, 322 (intmax_t)ip->i_number, 323 (intmax_t)lbn, 324 (intmax_t)ndaddr)); 325 sup->su_nbytes += size; 326 LFS_WRITESEGENTRY(sup, fs, lfs_dtosn(fs, ndaddr), bp); 327 328 /* differences here should be due to UNWRITTEN indirect blocks. */ 329 if (vp->v_type != VLNK) { 330 if (!(ip->i_lfs_effnblks >= lfs_dino_getblocks(fs, ip->i_din)) 331 #if 0 332 || !(lfs_lblkno(fs, ip->i_size) > ULFS_NDADDR || 333 ip->i_lfs_effnblks == lfs_dino_getblocks(fs, ip->i_din)) 334 #endif /* 0 */ 335 ) { 336 vprint("vnode", vp); 337 printf("effnblks=%jd dino_getblocks=%jd\n", 338 (intmax_t)ip->i_lfs_effnblks, 339 (intmax_t)lfs_dino_getblocks(fs, ip->i_din)); 340 } 341 KASSERT(ip->i_lfs_effnblks >= lfs_dino_getblocks(fs, ip->i_din)); 342 #if 0 343 KASSERT(lfs_lblkno(fs, ip->i_size) > ULFS_NDADDR || 344 ip->i_lfs_effnblks == lfs_dino_getblocks(fs, ip->i_din)); 345 #endif /* 0 */ 346 } 347 348 #ifdef DEBUG 349 /* Now look again to make sure it worked */ 350 ulfs_bmaparray(vp, lbn, &odaddr, &a[0], &num, NULL, NULL); 351 if (LFS_DBTOFSB(fs, odaddr) != ndaddr) 352 DLOG((DLOG_RF, "update_meta: failed setting ino %jd lbn %jd" 353 " to %jd\n", (intmax_t)ino, (intmax_t)lbn, (intmax_t)ndaddr)); 354 #endif /* DEBUG */ 355 vput(vp); 356 return 0; 357 } 358 359 /* 360 * Copy some the fields of the dinode as needed by update_inoblk(). 361 */ 362 static void 363 update_inoblk_copy_dinode(struct lfs *fs, 364 union lfs_dinode *dstu, const union lfs_dinode *srcu) 365 { 366 if (fs->lfs_is64) { 367 struct lfs64_dinode *dst = &dstu->u_64; 368 const struct lfs64_dinode *src = &srcu->u_64; 369 unsigned i; 370 371 /* 372 * Copy everything but the block pointers and di_blocks. 373 * XXX what about di_extb? 374 */ 375 dst->di_mode = src->di_mode; 376 dst->di_nlink = src->di_nlink; 377 dst->di_uid = src->di_uid; 378 dst->di_gid = src->di_gid; 379 dst->di_blksize = src->di_blksize; 380 dst->di_size = src->di_size; 381 dst->di_atime = src->di_atime; 382 dst->di_mtime = src->di_mtime; 383 dst->di_ctime = src->di_ctime; 384 dst->di_birthtime = src->di_birthtime; 385 dst->di_mtimensec = src->di_mtimensec; 386 dst->di_atimensec = src->di_atimensec; 387 dst->di_ctimensec = src->di_ctimensec; 388 dst->di_birthnsec = src->di_birthnsec; 389 dst->di_gen = src->di_gen; 390 dst->di_kernflags = src->di_kernflags; 391 dst->di_flags = src->di_flags; 392 dst->di_extsize = src->di_extsize; 393 dst->di_modrev = src->di_modrev; 394 dst->di_inumber = src->di_inumber; 395 for (i = 0; i < __arraycount(src->di_spare); i++) { 396 dst->di_spare[i] = src->di_spare[i]; 397 } 398 /* Short symlinks store their data in di_db. */ 399 if ((src->di_mode & LFS_IFMT) == LFS_IFLNK 400 && src->di_size < lfs_sb_getmaxsymlinklen(fs)) { 401 memcpy(dst->di_db, src->di_db, src->di_size); 402 } 403 } else { 404 struct lfs32_dinode *dst = &dstu->u_32; 405 const struct lfs32_dinode *src = &srcu->u_32; 406 407 /* Get mode, link count, size, and times */ 408 memcpy(dst, src, offsetof(struct lfs32_dinode, di_db[0])); 409 410 /* Then the rest, except di_blocks */ 411 dst->di_flags = src->di_flags; 412 dst->di_gen = src->di_gen; 413 dst->di_uid = src->di_uid; 414 dst->di_gid = src->di_gid; 415 dst->di_modrev = src->di_modrev; 416 417 /* Short symlinks store their data in di_db. */ 418 if ((src->di_mode & LFS_IFMT) == LFS_IFLNK 419 && src->di_size < lfs_sb_getmaxsymlinklen(fs)) { 420 memcpy(dst->di_db, src->di_db, src->di_size); 421 } 422 } 423 } 424 425 static int 426 update_inoblk(struct lfs_inofuncarg *lifa) 427 { 428 struct lfs *fs; 429 daddr_t offset; 430 struct lwp *l; 431 struct vnode *devvp, *vp; 432 struct inode *ip; 433 union lfs_dinode *dip; 434 struct buf *dbp, *ibp; 435 int error; 436 IFILE *ifp; 437 unsigned i, num; 438 uint32_t gen; 439 char *buf; 440 ino_t ino; 441 442 fs = lifa->fs; 443 offset = lifa->offset; 444 l = lifa->l; 445 devvp = VTOI(fs->lfs_ivnode)->i_devvp; 446 447 /* 448 * Get the inode, update times and perms. 449 * DO NOT update disk blocks, we do that separately. 450 */ 451 error = bread(devvp, LFS_FSBTODB(fs, offset), lfs_sb_getibsize(fs), 452 0, &dbp); 453 if (error) { 454 DLOG((DLOG_RF, "update_inoblk: bread returned %d\n", error)); 455 return error; 456 } 457 buf = malloc(dbp->b_bcount, M_SEGMENT, M_WAITOK); 458 memcpy(buf, dbp->b_data, dbp->b_bcount); 459 brelse(dbp, BC_AGE); 460 num = LFS_INOPB(fs); 461 for (i = num; i-- > 0; ) { 462 dip = DINO_IN_BLOCK(fs, buf, i); 463 ino = lfs_dino_getinumber(fs, dip); 464 if (ino <= LFS_IFILE_INUM) 465 continue; 466 467 if ((error = raise_maxino(fs, ino)) != 0) 468 continue; 469 470 /* Check generation number */ 471 LFS_IENTRY(ifp, fs, lfs_dino_getinumber(fs, dip), ibp); 472 gen = lfs_if_getversion(fs, ifp); 473 LFS_RELEASEIENTRY(ifp, fs, lfs_dino_getinumber(fs, dip), ibp); 474 if (lfs_dino_getgen(fs, dip) < gen) { 475 continue; 476 } 477 478 /* 479 * This inode is the newest generation. Load it. 480 */ 481 error = lfs_rf_valloc(fs, ino, lfs_dino_getgen(fs, dip), 482 l, &vp, dip); 483 if (error) { 484 DLOG((DLOG_RF, "update_inoblk: lfs_rf_valloc" 485 " returned %d\n", error)); 486 continue; 487 } 488 ip = VTOI(vp); 489 if (lfs_dino_getsize(fs, dip) != ip->i_size 490 && vp->v_type != VLNK) { 491 /* XXX What should we do with symlinks? */ 492 DLOG((DLOG_RF, " ino %jd size %jd -> %jd\n", 493 (intmax_t)ino, 494 (intmax_t)ip->i_size, 495 (intmax_t)lfs_dino_getsize(fs, dip))); 496 lfs_truncate(vp, lfs_dino_getsize(fs, dip), 0, 497 NOCRED); 498 } 499 update_inoblk_copy_dinode(fs, ip->i_din, dip); 500 501 ip->i_flags = lfs_dino_getflags(fs, dip); 502 ip->i_gen = lfs_dino_getgen(fs, dip); 503 ip->i_uid = lfs_dino_getuid(fs, dip); 504 ip->i_gid = lfs_dino_getgid(fs, dip); 505 506 ip->i_mode = lfs_dino_getmode(fs, dip); 507 ip->i_nlink = lfs_dino_getnlink(fs, dip); 508 ip->i_size = lfs_dino_getsize(fs, dip); 509 510 LFS_SET_UINO(ip, IN_CHANGE | IN_UPDATE); 511 512 /* Re-initialize to get type right */ 513 ulfs_vinit(vp->v_mount, lfs_specop_p, lfs_fifoop_p, 514 &vp); 515 516 /* Record change in location and do segment accounting */ 517 lfs_update_iaddr(fs, ip, offset); 518 519 vput(vp); 520 } 521 free(buf, M_SEGMENT); 522 523 return 0; 524 } 525 526 /* 527 * Note the highest generation number of each inode in the Ifile. 528 * This allows us to skip processing data for intermediate versions. 529 */ 530 static int 531 update_inogen(struct lfs_inofuncarg *lifa) 532 { 533 struct lfs *fs; 534 daddr_t offset; 535 struct vnode *devvp; 536 union lfs_dinode *dip; 537 struct buf *dbp, *ibp; 538 int error; 539 IFILE *ifp; 540 unsigned i, num; 541 542 fs = lifa->fs; 543 offset = lifa->offset; 544 devvp = VTOI(fs->lfs_ivnode)->i_devvp; 545 546 /* Read inode block */ 547 error = bread(devvp, LFS_FSBTODB(fs, offset), lfs_sb_getibsize(fs), 548 0, &dbp); 549 if (error) { 550 DLOG((DLOG_RF, "update_inoblk: bread returned %d\n", error)); 551 return error; 552 } 553 554 /* Check each inode against ifile entry */ 555 num = LFS_INOPB(fs); 556 for (i = num; i-- > 0; ) { 557 dip = DINO_IN_BLOCK(fs, dbp->b_data, i); 558 if (lfs_dino_getinumber(fs, dip) == LFS_IFILE_INUM) 559 continue; 560 561 /* Update generation number */ 562 LFS_IENTRY(ifp, fs, lfs_dino_getinumber(fs, dip), ibp); 563 if (lfs_if_getversion(fs, ifp) < lfs_dino_getgen(fs, dip)) 564 lfs_if_setversion(fs, ifp, lfs_dino_getgen(fs, dip)); 565 LFS_WRITEIENTRY(ifp, fs, lfs_dino_getinumber(fs, dip), ibp); 566 if (error) 567 break; 568 } 569 brelse(dbp, 0); 570 571 return error; 572 } 573 574 static int 575 finfo_func_rfw(struct lfs_finfofuncarg *lffa) 576 { 577 struct lfs *fs; 578 FINFO *fip; 579 daddr_t *offsetp; 580 struct lwp *l; 581 int j; 582 size_t size; 583 ino_t ino; 584 585 fs = lffa->fs; 586 fip = lffa->finfop; 587 offsetp = lffa->offsetp; 588 l = lffa->l; 589 size = lfs_sb_getbsize(fs); 590 ino = lfs_fi_getino(fs, fip); 591 LFS_ASSERT_MAXINO(fs, ino); 592 for (j = 0; j < lfs_fi_getnblocks(fs, fip); ++j) { 593 if (j == lfs_fi_getnblocks(fs, fip) - 1) 594 size = lfs_fi_getlastlength(fs, fip); 595 596 /* Account for and update any direct blocks */ 597 if (ino > LFS_IFILE_INUM && 598 lfs_fi_getblock(fs, fip, j) >= 0) { 599 update_meta(fs, ino, 600 lfs_fi_getversion(fs, fip), 601 lfs_fi_getblock(fs, fip, j), 602 *offsetp, size, l); 603 ++rblkcnt; 604 } 605 *offsetp += lfs_btofsb(fs, size); 606 } 607 608 return 0; 609 } 610 611 int 612 lfs_skip_superblock(struct lfs *fs, daddr_t *offsetp) 613 { 614 daddr_t offset; 615 int i; 616 617 /* 618 * If this is segment 0, skip the label. 619 * If the segment has a superblock and we're at the top 620 * of the segment, skip the superblock. 621 */ 622 offset = *offsetp; 623 if (offset == lfs_sb_gets0addr(fs)) { 624 offset += lfs_btofsb(fs, LFS_LABELPAD); 625 } 626 for (i = 0; i < LFS_MAXNUMSB; i++) { 627 if (offset == lfs_sb_getsboff(fs, i)) { 628 offset += lfs_btofsb(fs, LFS_SBPAD); 629 break; 630 } 631 } 632 *offsetp = offset; 633 return 0; 634 } 635 636 /* 637 * Read the partial segment at offset. 638 * 639 * If finfo_func and ino_func are both NULL, check the summary 640 * and data checksums. During roll forward, this must be done in its 641 * entirety before processing any blocks. 642 * 643 * If finfo_func is given, use that to process every file block 644 * in the segment summary. If ino_func is given, use that to process 645 * every inode block. 646 */ 647 int 648 lfs_parse_pseg(struct lfs *fs, daddr_t *offsetp, u_int64_t nextserial, 649 kauth_cred_t cred, int *pseg_flags, struct lwp *l, 650 int (*ino_func)(struct lfs_inofuncarg *), 651 int (*finfo_func)(struct lfs_finfofuncarg *), 652 int flags, void *arg) 653 { 654 struct vnode *devvp; 655 struct buf *bp, *dbp; 656 int error, ninos, i, j; 657 SEGSUM *ssp; 658 daddr_t offset, prevoffset; 659 IINFO *iip; 660 FINFO *fip; 661 size_t size; 662 uint32_t datasum, foundsum; 663 char *buf; 664 struct lfs_inofuncarg lifa; 665 struct lfs_finfofuncarg lffa; 666 667 KASSERT(fs != NULL); 668 KASSERT(offsetp != NULL); 669 670 devvp = VTOI(fs->lfs_ivnode)->i_devvp; 671 672 /* Set up callback arguments */ 673 lifa.fs = fs; 674 /* lifa.offset = offset; */ 675 lifa.cred = cred; 676 lifa.l = l; 677 lifa.buf = malloc(lfs_sb_getbsize(fs), M_SEGMENT, M_WAITOK); 678 679 lifa.arg = arg; 680 681 lffa.fs = fs; 682 /* lffa.offsetp = offsetp; */ 683 /* lffa.finfop = finfop; */ 684 lffa.cred = cred; 685 lffa.l = l; 686 lffa.arg = arg; 687 688 prevoffset = *offsetp; 689 lfs_skip_superblock(fs, offsetp); 690 offset = *offsetp; 691 692 /* Read in the segment summary */ 693 buf = malloc(lfs_sb_getsumsize(fs), M_SEGMENT, M_WAITOK); 694 error = bread(devvp, LFS_FSBTODB(fs, offset), lfs_sb_getsumsize(fs), 695 0, &bp); 696 if (error) 697 goto err; 698 memcpy(buf, bp->b_data, bp->b_bcount); 699 brelse(bp, BC_AGE); 700 701 ssp = (SEGSUM *)buf; 702 703 if (lfs_ss_getmagic(fs, ssp) != SS_MAGIC) { 704 DLOG((DLOG_RF, "Bad magic at 0x%" PRIx64 "\n", 705 offset)); 706 offset = -1; 707 goto err; 708 } 709 710 if (flags & CKSEG_CKSUM) { 711 size_t sumstart; 712 713 sumstart = lfs_ss_getsumstart(fs); 714 if (lfs_ss_getsumsum(fs, ssp) != 715 cksum((char *)ssp + sumstart, 716 lfs_sb_getsumsize(fs) - sumstart)) { 717 DLOG((DLOG_RF, "Sumsum error at 0x%" PRIx64 "\n", 718 offset)); 719 offset = -1; 720 goto err; 721 } 722 } 723 724 #if 0 725 /* 726 * Under normal conditions, we should never be producing 727 * a partial segment with neither inode blocks nor data blocks. 728 * However, these do sometimes appear and they need not 729 * prevent us from continuing. 730 */ 731 if (lfs_ss_getnfinfo(fs, ssp) == 0 && 732 lfs_ss_getninos(fs, ssp) == 0) { 733 DLOG((DLOG_RF, "Empty pseg at 0x%" PRIx64 "\n", 734 offset)); 735 offset = -1; 736 goto err; 737 } 738 #endif /* 0 */ 739 740 if (lfs_sb_getversion(fs) == 1) { 741 if (lfs_ss_getcreate(fs, ssp) < lfs_sb_gettstamp(fs)) { 742 DLOG((DLOG_RF, "Old data at 0x%" PRIx64 "\n", offset)); 743 offset = -1; 744 goto err; 745 } 746 } else { 747 if (nextserial > 0 748 && lfs_ss_getserial(fs, ssp) != nextserial) { 749 DLOG((DLOG_RF, "Serial number at 0x%jx given as 0x%jx," 750 " expected 0x%jx\n", (intmax_t)offset, 751 (intmax_t)lfs_ss_getserial(fs, ssp), 752 (intmax_t)nextserial)); 753 offset = -1; 754 goto err; 755 } 756 if (lfs_ss_getident(fs, ssp) != lfs_sb_getident(fs)) { 757 DLOG((DLOG_RF, "Incorrect fsid (0x%x vs 0x%x) at 0x%" 758 PRIx64 "\n", lfs_ss_getident(fs, ssp), 759 lfs_sb_getident(fs), offset)); 760 offset = -1; 761 goto err; 762 } 763 } 764 765 #ifdef DIAGNOSTIC 766 if (lfs_ss_getnfinfo(fs, ssp) > lfs_sb_getssize(fs) / lfs_sb_getfsize(fs)) { 767 printf("At offset 0x%jx, nfinfo %jd > max frags %jd\n", 768 (intmax_t)offset, 769 (intmax_t)lfs_ss_getnfinfo(fs, ssp), 770 (intmax_t)lfs_sb_getssize(fs) / lfs_sb_getfsize(fs)); 771 } 772 #endif 773 KASSERT(lfs_ss_getnfinfo(fs, ssp) <= lfs_sb_getssize(fs) / lfs_sb_getfsize(fs)); 774 #ifdef DIAGNOSTIC 775 if (lfs_ss_getnfinfo(fs, ssp) > lfs_sb_getfsize(fs) / sizeof(FINFO32)) { 776 printf("At offset 0x%jx, nfinfo %jd > max entries %jd\n", 777 (intmax_t)offset, 778 (intmax_t)lfs_ss_getnfinfo(fs, ssp), 779 (intmax_t)lfs_sb_getssize(fs) / lfs_sb_getfsize(fs)); 780 } 781 #endif 782 KASSERT(lfs_ss_getnfinfo(fs, ssp) <= lfs_sb_getfsize(fs) / sizeof(FINFO32)); 783 784 if (pseg_flags) 785 *pseg_flags = lfs_ss_getflags(fs, ssp); 786 ninos = howmany(lfs_ss_getninos(fs, ssp), LFS_INOPB(fs)); 787 iip = SEGSUM_IINFOSTART(fs, buf); 788 fip = SEGSUM_FINFOBASE(fs, (SEGSUM *)buf); 789 790 /* Handle individual blocks */ 791 foundsum = 0; 792 offset += lfs_btofsb(fs, lfs_sb_getsumsize(fs)); 793 for (i = 0; i < lfs_ss_getnfinfo(fs, ssp) || ninos; ++i) { 794 /* Inode block? */ 795 if (ninos && lfs_ii_getblock(fs, iip) == offset) { 796 if (flags & CKSEG_CKSUM) { 797 /* Read in the head and add to the buffer */ 798 error = bread(devvp, LFS_FSBTODB(fs, offset), 799 lfs_sb_getbsize(fs), 0, &dbp); 800 if (error) { 801 offset = -1; 802 goto err; 803 } 804 foundsum = lfs_cksum_part(dbp->b_data, 805 sizeof(uint32_t), foundsum); 806 brelse(dbp, BC_AGE); 807 } else if (ino_func != NULL) { 808 lifa.offset = offset; 809 error = (*ino_func)(&lifa); 810 if (error != 0) { 811 offset = -1; 812 goto err; 813 } 814 } 815 816 offset += lfs_btofsb(fs, lfs_sb_getibsize(fs)); 817 iip = NEXTLOWER_IINFO(fs, iip); 818 --ninos; 819 --i; /* compensate for ++i in loop header */ 820 continue; 821 } 822 823 /* File block */ 824 size = lfs_sb_getbsize(fs); 825 if (flags & CKSEG_CKSUM) { 826 for (j = 0; j < lfs_fi_getnblocks(fs, fip); ++j) { 827 if (j == lfs_fi_getnblocks(fs, fip) - 1) 828 size = lfs_fi_getlastlength(fs, fip); 829 error = bread(devvp, LFS_FSBTODB(fs, offset), 830 size, 0, &dbp); 831 if (error) { 832 offset = -1; 833 goto err; 834 } 835 foundsum = lfs_cksum_part(dbp->b_data, 836 sizeof(uint32_t), foundsum); 837 brelse(dbp, BC_AGE); 838 offset += lfs_btofsb(fs, size); 839 } 840 } else if (finfo_func != NULL) { 841 lffa.offsetp = &offset; 842 lffa.finfop = fip; 843 error = (*finfo_func)(&lffa); 844 if (error == ESTALE) 845 error = 0; 846 if (error) 847 goto err; 848 } else { 849 int n = lfs_fi_getnblocks(fs, fip); 850 size = lfs_fi_getlastlength(fs, fip); 851 offset += lfs_btofsb(fs, lfs_sb_getbsize(fs) * (n - 1) 852 + size); 853 } 854 fip = NEXT_FINFO(fs, fip); 855 } 856 857 /* Checksum the array, compare */ 858 if (flags & CKSEG_CKSUM) { 859 datasum = lfs_ss_getdatasum(fs, ssp); 860 foundsum = lfs_cksum_fold(foundsum); 861 if (datasum != foundsum) { 862 DLOG((DLOG_RF, "Datasum error at 0x%" PRIx64 863 " (wanted %x got %x)\n", 864 offset, datasum, foundsum)); 865 offset = -1; 866 goto err; 867 } 868 } else { 869 /* Don't clog the buffer queue */ 870 mutex_enter(&lfs_lock); 871 if (locked_queue_count > LFS_MAX_BUFS || 872 locked_queue_bytes > LFS_MAX_BYTES) { 873 lfs_flush(fs, SEGM_CKP, 0); 874 } 875 mutex_exit(&lfs_lock); 876 } 877 878 /* 879 * If we're at the end of the segment, move to the next. 880 * A partial segment needs space for a segment header (1 fsb) 881 * and a full block ("frag" fsb). Thus, adding "frag" fsb should 882 * still be within the current segment (whereas frag + 1 might 883 * be at the start of the next segment). 884 * 885 * This needs to match the definition of LFS_PARTIAL_FITS 886 * in lfs_segment.c. 887 */ 888 if (lfs_dtosn(fs, offset + lfs_sb_getfrag(fs)) 889 != lfs_dtosn(fs, offset)) { 890 if (lfs_dtosn(fs, offset) == lfs_dtosn(fs, lfs_ss_getnext(fs, 891 ssp))) { 892 offset = -1; 893 goto err; 894 } 895 offset = lfs_ss_getnext(fs, ssp); 896 DLOG((DLOG_RF, "LFS roll forward: moving to offset 0x%" PRIx64 897 " -> segment %d\n", offset, lfs_dtosn(fs,offset))); 898 } 899 if (flags & CKSEG_AVAIL) 900 lfs_sb_subavail(fs, offset - prevoffset); 901 902 err: 903 free(lifa.buf, M_SEGMENT); 904 free(buf, M_SEGMENT); 905 906 *offsetp = offset; 907 return error; 908 } 909 910 /* 911 * Roll forward. 912 */ 913 void 914 lfs_roll_forward(struct lfs *fs, struct mount *mp, struct lwp *l) 915 { 916 int flags, dirty; 917 daddr_t startoffset, offset, nextoffset, endpseg; 918 u_int64_t nextserial, startserial, endserial; 919 int sn, curseg; 920 struct proc *p; 921 kauth_cred_t cred; 922 SEGUSE *sup; 923 struct buf *bp; 924 925 p = l ? l->l_proc : NULL; 926 cred = p ? p->p_cred : NOCRED; 927 928 /* 929 * We don't roll forward for v1 filesystems, because 930 * of the danger that the clock was turned back between the last 931 * checkpoint and crash. This would roll forward garbage. 932 * 933 * v2 filesystems don't have this problem because they use a 934 * monotonically increasing serial number instead of a timestamp. 935 */ 936 rblkcnt = 0; 937 if ((lfs_sb_getpflags(fs) & LFS_PF_CLEAN) || !lfs_do_rfw 938 || lfs_sb_getversion(fs) <= 1 || p == NULL) 939 return; 940 941 DLOG((DLOG_RF, "%s: begin roll forward at serial 0x%jx\n", 942 lfs_sb_getfsmnt(fs), (intmax_t)lfs_sb_getserial(fs))); 943 DEBUG_CHECK_FREELIST(fs); 944 945 /* 946 * Phase I: Find the address of the last good partial 947 * segment that was written after the checkpoint. Mark 948 * the segments in question dirty, so they won't be 949 * reallocated. 950 */ 951 endpseg = startoffset = offset = lfs_sb_getoffset(fs); 952 flags = 0x0; 953 DLOG((DLOG_RF, "LFS roll forward phase 1: start at offset 0x%" 954 PRIx64 "\n", offset)); 955 LFS_SEGENTRY(sup, fs, lfs_dtosn(fs, offset), bp); 956 if (!(sup->su_flags & SEGUSE_DIRTY)) 957 lfs_sb_subnclean(fs, 1); 958 sup->su_flags |= SEGUSE_DIRTY; 959 LFS_WRITESEGENTRY(sup, fs, lfs_dtosn(fs, offset), bp); 960 961 startserial = lfs_sb_getserial(fs); 962 endserial = nextserial = startserial + 1; 963 nextoffset = offset; 964 while (1) { 965 nextoffset = offset; 966 lfs_parse_pseg(fs, &nextoffset, nextserial, 967 cred, &flags, l, NULL, NULL, CKSEG_CKSUM, NULL); 968 if (nextoffset == -1) 969 break; 970 if (lfs_sntod(fs, offset) != lfs_sntod(fs, nextoffset)) { 971 LFS_SEGENTRY(sup, fs, lfs_dtosn(fs, offset), 972 bp); 973 if (!(sup->su_flags & SEGUSE_DIRTY)) 974 lfs_sb_subnclean(fs, 1); 975 sup->su_flags |= SEGUSE_DIRTY; 976 LFS_WRITESEGENTRY(sup, fs, lfs_dtosn(fs, offset), bp); 977 } 978 979 DLOG((DLOG_RF, "LFS roll forward phase 1: offset=0x%jx" 980 " serial=0x%jx\n", (intmax_t)nextoffset, 981 (intmax_t)nextserial)); 982 if (flags & SS_DIROP) { 983 DLOG((DLOG_RF, "lfs_mountfs: dirops at 0x%" 984 PRIx64 "\n", offset)); 985 if (!(flags & SS_CONT)) { 986 DLOG((DLOG_RF, "lfs_mountfs: dirops end " 987 "at 0x%" PRIx64 "\n", offset)); 988 } 989 } 990 offset = nextoffset; 991 ++nextserial; 992 993 if (!(flags & SS_CONT)) { 994 endpseg = nextoffset; 995 endserial = nextserial; 996 } 997 if (lfs_rfw_max_psegs > 0 998 && nextserial > startserial + lfs_rfw_max_psegs) 999 break; 1000 } 1001 if (flags & SS_CONT) { 1002 DLOG((DLOG_RF, "LFS roll forward: warning: incomplete " 1003 "dirops discarded (0x%jx < 0x%jx)\n", 1004 endpseg, nextoffset)); 1005 } 1006 if (lfs_sb_getversion(fs) > 1) 1007 lfs_sb_setserial(fs, endserial); 1008 DLOG((DLOG_RF, "LFS roll forward phase 1: completed: " 1009 "endpseg=0x%" PRIx64 "\n", endpseg)); 1010 offset = startoffset; 1011 if (offset != endpseg) { 1012 /* Don't overwrite what we're trying to preserve */ 1013 lfs_sb_setoffset(fs, endpseg); 1014 lfs_sb_setcurseg(fs, lfs_sntod(fs, lfs_dtosn(fs, endpseg))); 1015 for (sn = curseg = lfs_dtosn(fs, lfs_sb_getcurseg(fs));;) { 1016 sn = (sn + 1) % lfs_sb_getnseg(fs); 1017 /* XXX could we just fail to roll forward? */ 1018 if (sn == curseg) 1019 panic("lfs_mountfs: no clean segments"); 1020 LFS_SEGENTRY(sup, fs, sn, bp); 1021 dirty = (sup->su_flags & SEGUSE_DIRTY); 1022 LFS_RELEASESEGENTRY(sup, fs, sn, bp); 1023 if (!dirty) 1024 break; 1025 } 1026 lfs_sb_setnextseg(fs, lfs_sntod(fs, sn)); 1027 /* Explicitly set this segment dirty */ 1028 LFS_SEGENTRY(sup, fs, lfs_dtosn(fs, endpseg), bp); 1029 sup->su_flags |= SEGUSE_DIRTY | SEGUSE_ACTIVE; 1030 LFS_WRITESEGENTRY(sup, fs, lfs_dtosn(fs, endpseg), bp); 1031 1032 /* 1033 * Phase II: Identify the highest generation of each 1034 * inode. We will ignore inodes and data blocks 1035 * belonging to old versions. 1036 */ 1037 offset = startoffset; 1038 nextserial = startserial + 1; 1039 DLOG((DLOG_RF, "LFS roll forward phase 2 beginning\n")); 1040 while (offset > 0 && offset != endpseg) { 1041 lfs_parse_pseg(fs, &offset, nextserial++, cred, 1042 NULL, l, update_inogen, NULL, 1043 CKSEG_NONE, NULL); 1044 DEBUG_CHECK_FREELIST(fs); 1045 } 1046 1047 /* 1048 * Phase III: Update inodes. 1049 */ 1050 offset = startoffset; 1051 nextserial = startserial + 1; 1052 DLOG((DLOG_RF, "LFS roll forward phase 3 beginning\n")); 1053 while (offset > 0 && offset != endpseg) { 1054 lfs_parse_pseg(fs, &offset, nextserial++, cred, 1055 NULL, l, update_inoblk, NULL, 1056 CKSEG_NONE, NULL); 1057 DEBUG_CHECK_FREELIST(fs); 1058 } 1059 1060 /* 1061 * Phase IV: Roll forward, updating data blocks. 1062 */ 1063 offset = startoffset; 1064 nextserial = startserial + 1; 1065 DLOG((DLOG_RF, "LFS roll forward phase 4 beginning\n")); 1066 while (offset > 0 && offset != endpseg) { 1067 lfs_parse_pseg(fs, &offset, nextserial++, cred, 1068 NULL, l, NULL, finfo_func_rfw, 1069 CKSEG_AVAIL, NULL); 1070 DEBUG_CHECK_FREELIST(fs); 1071 } 1072 1073 /* 1074 * Finish: flush our changes to disk. 1075 */ 1076 lfs_sb_setserial(fs, endserial); 1077 1078 lfs_segwrite(mp, SEGM_CKP | SEGM_SYNC); 1079 DLOG((DLOG_RF, "lfs_mountfs: roll forward " 1080 "examined %jd blocks\n", 1081 (intmax_t)(endpseg - startoffset))); 1082 } 1083 1084 /* Get rid of our vnodes, except the ifile */ 1085 drop_vnode_pages(mp, l); 1086 DLOG((DLOG_RF, "LFS roll forward complete\n")); 1087 printf("%s: roll forward recovered %d data blocks\n", 1088 lfs_sb_getfsmnt(fs), rblkcnt); 1089 1090 /* 1091 * At this point we have no more changes to write to disk. 1092 * Reset the "avail" count to match the segments as they 1093 * appear on disk, and the clean segment count. 1094 */ 1095 lfs_reset_avail(fs); 1096 } 1097 1098 static bool 1099 all_selector(void *cl, struct vnode *vp) 1100 { 1101 return true; 1102 } 1103 1104 /* 1105 * Dump any pages from vnodes that may have been put on 1106 * during truncation. 1107 */ 1108 static void 1109 drop_vnode_pages(struct mount *mp, struct lwp *l) 1110 { 1111 struct vnode_iterator *marker; 1112 struct lfs *fs; 1113 struct vnode *vp; 1114 1115 fs = VFSTOULFS(mp)->um_lfs; 1116 vfs_vnode_iterator_init(mp, &marker); 1117 while ((vp = vfs_vnode_iterator_next(marker, 1118 all_selector, NULL)) != NULL) { 1119 if (vp == fs->lfs_ivnode) 1120 continue; 1121 VOP_LOCK(vp, LK_EXCLUSIVE | LK_RETRY); 1122 uvm_vnp_setsize(vp, 0); 1123 uvm_vnp_setsize(vp, VTOI(vp)->i_size); 1124 VOP_UNLOCK(vp); 1125 vrele(vp); 1126 } 1127 vfs_vnode_iterator_destroy(marker); 1128 } 1129