1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) 2023-2024 Oracle. All Rights Reserved. 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 */ 6 #include "xfs.h" 7 #include "xfs_fs.h" 8 #include "xfs_shared.h" 9 #include "xfs_format.h" 10 #include "xfs_trans_resv.h" 11 #include "xfs_mount.h" 12 #include "xfs_log_format.h" 13 #include "xfs_trans.h" 14 #include "xfs_inode.h" 15 #include "xfs_metafile.h" 16 #include "xfs_quota.h" 17 #include "xfs_qm.h" 18 #include "xfs_dir2.h" 19 #include "xfs_parent.h" 20 #include "xfs_bmap_btree.h" 21 #include "xfs_trans_space.h" 22 #include "xfs_attr.h" 23 #include "xfs_rtgroup.h" 24 #include "scrub/scrub.h" 25 #include "scrub/common.h" 26 #include "scrub/trace.h" 27 #include "scrub/readdir.h" 28 #include "scrub/repair.h" 29 30 /* 31 * Metadata Directory Tree Paths 32 * ============================= 33 * 34 * A filesystem with metadir enabled expects to find metadata structures 35 * attached to files that are accessible by walking a path down the metadata 36 * directory tree. Given the metadir path and the incore inode storing the 37 * metadata, this scrubber ensures that the ondisk metadir path points to the 38 * ondisk inode represented by the incore inode. 39 */ 40 41 struct xchk_metapath { 42 struct xfs_scrub *sc; 43 44 /* Name for lookup */ 45 struct xfs_name xname; 46 47 /* Directory update for repairs */ 48 struct xfs_dir_update du; 49 50 /* Path down to this metadata file from the parent directory */ 51 const char *path; 52 53 /* Directory parent of the metadata file. */ 54 struct xfs_inode *dp; 55 56 /* Locks held on dp */ 57 unsigned int dp_ilock_flags; 58 59 /* Transaction block reservations */ 60 unsigned int link_resblks; 61 unsigned int unlink_resblks; 62 63 /* Parent pointer updates */ 64 struct xfs_parent_args link_ppargs; 65 struct xfs_parent_args unlink_ppargs; 66 67 /* Scratchpads for removing links */ 68 struct xfs_da_args pptr_args; 69 }; 70 71 /* Release resources tracked in the buffer. */ 72 static inline void 73 xchk_metapath_cleanup( 74 void *buf) 75 { 76 struct xchk_metapath *mpath = buf; 77 78 if (mpath->dp_ilock_flags) 79 xfs_iunlock(mpath->dp, mpath->dp_ilock_flags); 80 kfree(mpath->path); 81 } 82 83 /* Set up a metadir path scan. @path must be dynamically allocated. */ 84 static inline int 85 xchk_setup_metapath_scan( 86 struct xfs_scrub *sc, 87 struct xfs_inode *dp, 88 const char *path, 89 struct xfs_inode *ip) 90 { 91 struct xchk_metapath *mpath; 92 int error; 93 94 if (!path) 95 return -ENOMEM; 96 97 error = xchk_install_live_inode(sc, ip); 98 if (error) { 99 kfree(path); 100 return error; 101 } 102 103 mpath = kzalloc(sizeof(struct xchk_metapath), XCHK_GFP_FLAGS); 104 if (!mpath) { 105 kfree(path); 106 return -ENOMEM; 107 } 108 109 mpath->sc = sc; 110 sc->buf = mpath; 111 sc->buf_cleanup = xchk_metapath_cleanup; 112 113 mpath->dp = dp; 114 mpath->path = path; /* path is now owned by mpath */ 115 116 mpath->xname.name = mpath->path; 117 mpath->xname.len = strlen(mpath->path); 118 mpath->xname.type = xfs_mode_to_ftype(VFS_I(ip)->i_mode); 119 120 return 0; 121 } 122 123 #ifdef CONFIG_XFS_RT 124 /* Scan the /rtgroups directory itself. */ 125 static int 126 xchk_setup_metapath_rtdir( 127 struct xfs_scrub *sc) 128 { 129 if (!sc->mp->m_rtdirip) 130 return -ENOENT; 131 132 return xchk_setup_metapath_scan(sc, sc->mp->m_metadirip, 133 kasprintf(GFP_KERNEL, "rtgroups"), sc->mp->m_rtdirip); 134 } 135 136 /* Scan a rtgroup inode under the /rtgroups directory. */ 137 static int 138 xchk_setup_metapath_rtginode( 139 struct xfs_scrub *sc, 140 enum xfs_rtg_inodes type) 141 { 142 struct xfs_rtgroup *rtg; 143 struct xfs_inode *ip; 144 int error; 145 146 rtg = xfs_rtgroup_get(sc->mp, sc->sm->sm_agno); 147 if (!rtg) 148 return -ENOENT; 149 150 ip = rtg->rtg_inodes[type]; 151 if (!ip) { 152 error = -ENOENT; 153 goto out_put_rtg; 154 } 155 156 error = xchk_setup_metapath_scan(sc, sc->mp->m_rtdirip, 157 xfs_rtginode_path(rtg_rgno(rtg), type), ip); 158 159 out_put_rtg: 160 xfs_rtgroup_put(rtg); 161 return error; 162 } 163 #else 164 # define xchk_setup_metapath_rtdir(...) (-ENOENT) 165 # define xchk_setup_metapath_rtginode(...) (-ENOENT) 166 #endif /* CONFIG_XFS_RT */ 167 168 #ifdef CONFIG_XFS_QUOTA 169 /* Scan the /quota directory itself. */ 170 static int 171 xchk_setup_metapath_quotadir( 172 struct xfs_scrub *sc) 173 { 174 struct xfs_trans *tp; 175 struct xfs_inode *dp = NULL; 176 int error; 177 178 error = xfs_trans_alloc_empty(sc->mp, &tp); 179 if (error) 180 return error; 181 182 error = xfs_dqinode_load_parent(tp, &dp); 183 xfs_trans_cancel(tp); 184 if (error) 185 return error; 186 187 error = xchk_setup_metapath_scan(sc, sc->mp->m_metadirip, 188 kasprintf(GFP_KERNEL, "quota"), dp); 189 xfs_irele(dp); 190 return error; 191 } 192 193 /* Scan a quota inode under the /quota directory. */ 194 static int 195 xchk_setup_metapath_dqinode( 196 struct xfs_scrub *sc, 197 xfs_dqtype_t type) 198 { 199 struct xfs_trans *tp = NULL; 200 struct xfs_inode *dp = NULL; 201 struct xfs_inode *ip = NULL; 202 const char *path; 203 int error; 204 205 error = xfs_trans_alloc_empty(sc->mp, &tp); 206 if (error) 207 return error; 208 209 error = xfs_dqinode_load_parent(tp, &dp); 210 if (error) 211 goto out_cancel; 212 213 error = xfs_dqinode_load(tp, dp, type, &ip); 214 if (error) 215 goto out_dp; 216 217 xfs_trans_cancel(tp); 218 tp = NULL; 219 220 path = kasprintf(GFP_KERNEL, "%s", xfs_dqinode_path(type)); 221 error = xchk_setup_metapath_scan(sc, dp, path, ip); 222 223 xfs_irele(ip); 224 out_dp: 225 xfs_irele(dp); 226 out_cancel: 227 if (tp) 228 xfs_trans_cancel(tp); 229 return error; 230 } 231 #else 232 # define xchk_setup_metapath_quotadir(...) (-ENOENT) 233 # define xchk_setup_metapath_dqinode(...) (-ENOENT) 234 #endif /* CONFIG_XFS_QUOTA */ 235 236 int 237 xchk_setup_metapath( 238 struct xfs_scrub *sc) 239 { 240 if (!xfs_has_metadir(sc->mp)) 241 return -ENOENT; 242 if (sc->sm->sm_gen) 243 return -EINVAL; 244 245 switch (sc->sm->sm_ino) { 246 case XFS_SCRUB_METAPATH_PROBE: 247 /* Just probing, nothing else to do. */ 248 if (sc->sm->sm_agno) 249 return -EINVAL; 250 return 0; 251 case XFS_SCRUB_METAPATH_RTDIR: 252 return xchk_setup_metapath_rtdir(sc); 253 case XFS_SCRUB_METAPATH_RTBITMAP: 254 return xchk_setup_metapath_rtginode(sc, XFS_RTGI_BITMAP); 255 case XFS_SCRUB_METAPATH_RTSUMMARY: 256 return xchk_setup_metapath_rtginode(sc, XFS_RTGI_SUMMARY); 257 case XFS_SCRUB_METAPATH_QUOTADIR: 258 return xchk_setup_metapath_quotadir(sc); 259 case XFS_SCRUB_METAPATH_USRQUOTA: 260 return xchk_setup_metapath_dqinode(sc, XFS_DQTYPE_USER); 261 case XFS_SCRUB_METAPATH_GRPQUOTA: 262 return xchk_setup_metapath_dqinode(sc, XFS_DQTYPE_GROUP); 263 case XFS_SCRUB_METAPATH_PRJQUOTA: 264 return xchk_setup_metapath_dqinode(sc, XFS_DQTYPE_PROJ); 265 default: 266 return -ENOENT; 267 } 268 } 269 270 /* 271 * Take the ILOCK on the metadata directory parent and child. We do not know 272 * that the metadata directory is not corrupt, so we lock the parent and try 273 * to lock the child. Returns 0 if successful, or -EINTR to abort the scrub. 274 */ 275 STATIC int 276 xchk_metapath_ilock_both( 277 struct xchk_metapath *mpath) 278 { 279 struct xfs_scrub *sc = mpath->sc; 280 int error = 0; 281 282 while (true) { 283 xfs_ilock(mpath->dp, XFS_ILOCK_EXCL); 284 if (xchk_ilock_nowait(sc, XFS_ILOCK_EXCL)) { 285 mpath->dp_ilock_flags |= XFS_ILOCK_EXCL; 286 return 0; 287 } 288 xfs_iunlock(mpath->dp, XFS_ILOCK_EXCL); 289 290 if (xchk_should_terminate(sc, &error)) 291 return error; 292 293 delay(1); 294 } 295 296 ASSERT(0); 297 return -EINTR; 298 } 299 300 /* Unlock parent and child inodes. */ 301 static inline void 302 xchk_metapath_iunlock( 303 struct xchk_metapath *mpath) 304 { 305 struct xfs_scrub *sc = mpath->sc; 306 307 xchk_iunlock(sc, XFS_ILOCK_EXCL); 308 309 mpath->dp_ilock_flags &= ~XFS_ILOCK_EXCL; 310 xfs_iunlock(mpath->dp, XFS_ILOCK_EXCL); 311 } 312 313 int 314 xchk_metapath( 315 struct xfs_scrub *sc) 316 { 317 struct xchk_metapath *mpath = sc->buf; 318 xfs_ino_t ino = NULLFSINO; 319 int error; 320 321 /* Just probing, nothing else to do. */ 322 if (sc->sm->sm_ino == XFS_SCRUB_METAPATH_PROBE) 323 return 0; 324 325 /* Parent required to do anything else. */ 326 if (mpath->dp == NULL) { 327 xchk_ino_set_corrupt(sc, sc->ip->i_ino); 328 return 0; 329 } 330 331 error = xchk_trans_alloc_empty(sc); 332 if (error) 333 return error; 334 335 error = xchk_metapath_ilock_both(mpath); 336 if (error) 337 goto out_cancel; 338 339 /* Make sure the parent dir has a dirent pointing to this file. */ 340 error = xchk_dir_lookup(sc, mpath->dp, &mpath->xname, &ino); 341 trace_xchk_metapath_lookup(sc, mpath->path, mpath->dp, ino); 342 if (error == -ENOENT) { 343 /* No directory entry at all */ 344 xchk_ino_set_corrupt(sc, sc->ip->i_ino); 345 error = 0; 346 goto out_ilock; 347 } 348 if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error)) 349 goto out_ilock; 350 if (ino != sc->ip->i_ino) { 351 /* Pointing to wrong inode */ 352 xchk_ino_set_corrupt(sc, sc->ip->i_ino); 353 } 354 355 out_ilock: 356 xchk_metapath_iunlock(mpath); 357 out_cancel: 358 xchk_trans_cancel(sc); 359 return error; 360 } 361 362 #ifdef CONFIG_XFS_ONLINE_REPAIR 363 /* Create the dirent represented by the final component of the path. */ 364 STATIC int 365 xrep_metapath_link( 366 struct xchk_metapath *mpath) 367 { 368 struct xfs_scrub *sc = mpath->sc; 369 370 mpath->du.dp = mpath->dp; 371 mpath->du.name = &mpath->xname; 372 mpath->du.ip = sc->ip; 373 374 if (xfs_has_parent(sc->mp)) 375 mpath->du.ppargs = &mpath->link_ppargs; 376 else 377 mpath->du.ppargs = NULL; 378 379 trace_xrep_metapath_link(sc, mpath->path, mpath->dp, sc->ip->i_ino); 380 381 return xfs_dir_add_child(sc->tp, mpath->link_resblks, &mpath->du); 382 } 383 384 /* Remove the dirent at the final component of the path. */ 385 STATIC int 386 xrep_metapath_unlink( 387 struct xchk_metapath *mpath, 388 xfs_ino_t ino, 389 struct xfs_inode *ip) 390 { 391 struct xfs_parent_rec rec; 392 struct xfs_scrub *sc = mpath->sc; 393 struct xfs_mount *mp = sc->mp; 394 int error; 395 396 trace_xrep_metapath_unlink(sc, mpath->path, mpath->dp, ino); 397 398 if (!ip) { 399 /* The child inode isn't allocated. Junk the dirent. */ 400 xfs_trans_log_inode(sc->tp, mpath->dp, XFS_ILOG_CORE); 401 return xfs_dir_removename(sc->tp, mpath->dp, &mpath->xname, 402 ino, mpath->unlink_resblks); 403 } 404 405 mpath->du.dp = mpath->dp; 406 mpath->du.name = &mpath->xname; 407 mpath->du.ip = ip; 408 mpath->du.ppargs = NULL; 409 410 /* Figure out if we're removing a parent pointer too. */ 411 if (xfs_has_parent(mp)) { 412 xfs_inode_to_parent_rec(&rec, ip); 413 error = xfs_parent_lookup(sc->tp, ip, &mpath->xname, &rec, 414 &mpath->pptr_args); 415 switch (error) { 416 case -ENOATTR: 417 break; 418 case 0: 419 mpath->du.ppargs = &mpath->unlink_ppargs; 420 break; 421 default: 422 return error; 423 } 424 } 425 426 return xfs_dir_remove_child(sc->tp, mpath->unlink_resblks, &mpath->du); 427 } 428 429 /* 430 * Try to create a dirent in @mpath->dp with the name @mpath->xname that points 431 * to @sc->ip. Returns: 432 * 433 * -EEXIST and an @alleged_child if the dirent that points to the wrong inode; 434 * 0 if there is now a dirent pointing to @sc->ip; or 435 * A negative errno on error. 436 */ 437 STATIC int 438 xrep_metapath_try_link( 439 struct xchk_metapath *mpath, 440 xfs_ino_t *alleged_child) 441 { 442 struct xfs_scrub *sc = mpath->sc; 443 xfs_ino_t ino; 444 int error; 445 446 /* Allocate transaction, lock inodes, join to transaction. */ 447 error = xchk_trans_alloc(sc, mpath->link_resblks); 448 if (error) 449 return error; 450 451 error = xchk_metapath_ilock_both(mpath); 452 if (error) { 453 xchk_trans_cancel(sc); 454 return error; 455 } 456 xfs_trans_ijoin(sc->tp, mpath->dp, 0); 457 xfs_trans_ijoin(sc->tp, sc->ip, 0); 458 459 error = xchk_dir_lookup(sc, mpath->dp, &mpath->xname, &ino); 460 trace_xrep_metapath_lookup(sc, mpath->path, mpath->dp, ino); 461 if (error == -ENOENT) { 462 /* 463 * There is no dirent in the directory. Create an entry 464 * pointing to @sc->ip. 465 */ 466 error = xrep_metapath_link(mpath); 467 if (error) 468 goto out_cancel; 469 470 error = xrep_trans_commit(sc); 471 xchk_metapath_iunlock(mpath); 472 return error; 473 } 474 if (error) 475 goto out_cancel; 476 477 if (ino == sc->ip->i_ino) { 478 /* The dirent already points to @sc->ip; we're done. */ 479 error = 0; 480 goto out_cancel; 481 } 482 483 /* 484 * The dirent points elsewhere; pass that back so that the caller 485 * can try to remove the dirent. 486 */ 487 *alleged_child = ino; 488 error = -EEXIST; 489 490 out_cancel: 491 xchk_trans_cancel(sc); 492 xchk_metapath_iunlock(mpath); 493 return error; 494 } 495 496 /* 497 * Take the ILOCK on the metadata directory parent and a bad child, if one is 498 * supplied. We do not know that the metadata directory is not corrupt, so we 499 * lock the parent and try to lock the child. Returns 0 if successful, or 500 * -EINTR to abort the repair. The lock state of @dp is not recorded in @mpath. 501 */ 502 STATIC int 503 xchk_metapath_ilock_parent_and_child( 504 struct xchk_metapath *mpath, 505 struct xfs_inode *ip) 506 { 507 struct xfs_scrub *sc = mpath->sc; 508 int error = 0; 509 510 while (true) { 511 xfs_ilock(mpath->dp, XFS_ILOCK_EXCL); 512 if (!ip || xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) 513 return 0; 514 xfs_iunlock(mpath->dp, XFS_ILOCK_EXCL); 515 516 if (xchk_should_terminate(sc, &error)) 517 return error; 518 519 delay(1); 520 } 521 522 ASSERT(0); 523 return -EINTR; 524 } 525 526 /* 527 * Try to remove a dirent in @mpath->dp with the name @mpath->xname that points 528 * to @alleged_child. Returns: 529 * 530 * 0 if there is no longer a dirent; 531 * -EEXIST if the dirent points to @sc->ip; 532 * -EAGAIN and an updated @alleged_child if the dirent points elsewhere; or 533 * A negative errno for any other error. 534 */ 535 STATIC int 536 xrep_metapath_try_unlink( 537 struct xchk_metapath *mpath, 538 xfs_ino_t *alleged_child) 539 { 540 struct xfs_scrub *sc = mpath->sc; 541 struct xfs_inode *ip = NULL; 542 xfs_ino_t ino; 543 int error; 544 545 ASSERT(*alleged_child != sc->ip->i_ino); 546 547 trace_xrep_metapath_try_unlink(sc, mpath->path, mpath->dp, 548 *alleged_child); 549 550 /* 551 * Allocate transaction, grab the alleged child inode, lock inodes, 552 * join to transaction. 553 */ 554 error = xchk_trans_alloc(sc, mpath->unlink_resblks); 555 if (error) 556 return error; 557 558 error = xchk_iget(sc, *alleged_child, &ip); 559 if (error == -EINVAL || error == -ENOENT) { 560 /* inode number is bogus, junk the dirent */ 561 error = 0; 562 } 563 if (error) { 564 xchk_trans_cancel(sc); 565 return error; 566 } 567 568 error = xchk_metapath_ilock_parent_and_child(mpath, ip); 569 if (error) { 570 xchk_trans_cancel(sc); 571 return error; 572 } 573 xfs_trans_ijoin(sc->tp, mpath->dp, 0); 574 if (ip) 575 xfs_trans_ijoin(sc->tp, ip, 0); 576 577 error = xchk_dir_lookup(sc, mpath->dp, &mpath->xname, &ino); 578 trace_xrep_metapath_lookup(sc, mpath->path, mpath->dp, ino); 579 if (error == -ENOENT) { 580 /* 581 * There is no dirent in the directory anymore. We're ready to 582 * try the link operation again. 583 */ 584 error = 0; 585 goto out_cancel; 586 } 587 if (error) 588 goto out_cancel; 589 590 if (ino == sc->ip->i_ino) { 591 /* The dirent already points to @sc->ip; we're done. */ 592 error = -EEXIST; 593 goto out_cancel; 594 } 595 596 /* 597 * The dirent does not point to the alleged child. Update the caller 598 * and signal that we want to be called again. 599 */ 600 if (ino != *alleged_child) { 601 *alleged_child = ino; 602 error = -EAGAIN; 603 goto out_cancel; 604 } 605 606 /* Remove the link to the child. */ 607 error = xrep_metapath_unlink(mpath, ino, ip); 608 if (error) 609 goto out_cancel; 610 611 error = xrep_trans_commit(sc); 612 goto out_unlock; 613 614 out_cancel: 615 xchk_trans_cancel(sc); 616 out_unlock: 617 xfs_iunlock(mpath->dp, XFS_ILOCK_EXCL); 618 if (ip) { 619 xfs_iunlock(ip, XFS_ILOCK_EXCL); 620 xchk_irele(sc, ip); 621 } 622 return error; 623 } 624 625 /* 626 * Make sure the metadata directory path points to the child being examined. 627 * 628 * Repair needs to be able to create a directory structure, create its own 629 * transactions, and take ILOCKs. This function /must/ be called after all 630 * other repairs have completed. 631 */ 632 int 633 xrep_metapath( 634 struct xfs_scrub *sc) 635 { 636 struct xchk_metapath *mpath = sc->buf; 637 struct xfs_mount *mp = sc->mp; 638 int error = 0; 639 640 /* Just probing, nothing to repair. */ 641 if (sc->sm->sm_ino == XFS_SCRUB_METAPATH_PROBE) 642 return 0; 643 644 /* Parent required to do anything else. */ 645 if (mpath->dp == NULL) 646 return -EFSCORRUPTED; 647 648 /* 649 * Make sure the child file actually has an attr fork to receive a new 650 * parent pointer if the fs has parent pointers. 651 */ 652 if (xfs_has_parent(mp)) { 653 error = xfs_attr_add_fork(sc->ip, 654 sizeof(struct xfs_attr_sf_hdr), 1); 655 if (error) 656 return error; 657 } 658 659 /* Compute block reservation required to unlink and link a file. */ 660 mpath->unlink_resblks = xfs_remove_space_res(mp, MAXNAMELEN); 661 mpath->link_resblks = xfs_link_space_res(mp, MAXNAMELEN); 662 663 do { 664 xfs_ino_t alleged_child; 665 666 /* Re-establish the link, or tell us which inode to remove. */ 667 error = xrep_metapath_try_link(mpath, &alleged_child); 668 if (!error) 669 return 0; 670 if (error != -EEXIST) 671 return error; 672 673 /* 674 * Remove an incorrect link to an alleged child, or tell us 675 * which inode to remove. 676 */ 677 do { 678 error = xrep_metapath_try_unlink(mpath, &alleged_child); 679 } while (error == -EAGAIN); 680 if (error == -EEXIST) { 681 /* Link established; we're done. */ 682 error = 0; 683 break; 684 } 685 } while (!error); 686 687 return error; 688 } 689 #endif /* CONFIG_XFS_ONLINE_REPAIR */ 690