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_quotainfo *qi = sc->mp->m_quotainfo; 175 176 if (!qi || !qi->qi_dirip) 177 return -ENOENT; 178 179 return xchk_setup_metapath_scan(sc, sc->mp->m_metadirip, 180 kstrdup("quota", GFP_KERNEL), qi->qi_dirip); 181 } 182 183 /* Scan a quota inode under the /quota directory. */ 184 static int 185 xchk_setup_metapath_dqinode( 186 struct xfs_scrub *sc, 187 xfs_dqtype_t type) 188 { 189 struct xfs_quotainfo *qi = sc->mp->m_quotainfo; 190 struct xfs_inode *ip = NULL; 191 192 if (!qi) 193 return -ENOENT; 194 195 switch (type) { 196 case XFS_DQTYPE_USER: 197 ip = qi->qi_uquotaip; 198 break; 199 case XFS_DQTYPE_GROUP: 200 ip = qi->qi_gquotaip; 201 break; 202 case XFS_DQTYPE_PROJ: 203 ip = qi->qi_pquotaip; 204 break; 205 default: 206 ASSERT(0); 207 return -EINVAL; 208 } 209 if (!ip) 210 return -ENOENT; 211 212 return xchk_setup_metapath_scan(sc, qi->qi_dirip, 213 kstrdup(xfs_dqinode_path(type), GFP_KERNEL), ip); 214 } 215 #else 216 # define xchk_setup_metapath_quotadir(...) (-ENOENT) 217 # define xchk_setup_metapath_dqinode(...) (-ENOENT) 218 #endif /* CONFIG_XFS_QUOTA */ 219 220 int 221 xchk_setup_metapath( 222 struct xfs_scrub *sc) 223 { 224 if (!xfs_has_metadir(sc->mp)) 225 return -ENOENT; 226 if (sc->sm->sm_gen) 227 return -EINVAL; 228 229 switch (sc->sm->sm_ino) { 230 case XFS_SCRUB_METAPATH_PROBE: 231 /* Just probing, nothing else to do. */ 232 if (sc->sm->sm_agno) 233 return -EINVAL; 234 return 0; 235 case XFS_SCRUB_METAPATH_RTDIR: 236 return xchk_setup_metapath_rtdir(sc); 237 case XFS_SCRUB_METAPATH_RTBITMAP: 238 return xchk_setup_metapath_rtginode(sc, XFS_RTGI_BITMAP); 239 case XFS_SCRUB_METAPATH_RTSUMMARY: 240 return xchk_setup_metapath_rtginode(sc, XFS_RTGI_SUMMARY); 241 case XFS_SCRUB_METAPATH_QUOTADIR: 242 return xchk_setup_metapath_quotadir(sc); 243 case XFS_SCRUB_METAPATH_USRQUOTA: 244 return xchk_setup_metapath_dqinode(sc, XFS_DQTYPE_USER); 245 case XFS_SCRUB_METAPATH_GRPQUOTA: 246 return xchk_setup_metapath_dqinode(sc, XFS_DQTYPE_GROUP); 247 case XFS_SCRUB_METAPATH_PRJQUOTA: 248 return xchk_setup_metapath_dqinode(sc, XFS_DQTYPE_PROJ); 249 default: 250 return -ENOENT; 251 } 252 } 253 254 /* 255 * Take the ILOCK on the metadata directory parent and child. We do not know 256 * that the metadata directory is not corrupt, so we lock the parent and try 257 * to lock the child. Returns 0 if successful, or -EINTR to abort the scrub. 258 */ 259 STATIC int 260 xchk_metapath_ilock_both( 261 struct xchk_metapath *mpath) 262 { 263 struct xfs_scrub *sc = mpath->sc; 264 int error = 0; 265 266 while (true) { 267 xfs_ilock(mpath->dp, XFS_ILOCK_EXCL); 268 if (xchk_ilock_nowait(sc, XFS_ILOCK_EXCL)) { 269 mpath->dp_ilock_flags |= XFS_ILOCK_EXCL; 270 return 0; 271 } 272 xfs_iunlock(mpath->dp, XFS_ILOCK_EXCL); 273 274 if (xchk_should_terminate(sc, &error)) 275 return error; 276 277 delay(1); 278 } 279 280 ASSERT(0); 281 return -EINTR; 282 } 283 284 /* Unlock parent and child inodes. */ 285 static inline void 286 xchk_metapath_iunlock( 287 struct xchk_metapath *mpath) 288 { 289 struct xfs_scrub *sc = mpath->sc; 290 291 xchk_iunlock(sc, XFS_ILOCK_EXCL); 292 293 mpath->dp_ilock_flags &= ~XFS_ILOCK_EXCL; 294 xfs_iunlock(mpath->dp, XFS_ILOCK_EXCL); 295 } 296 297 int 298 xchk_metapath( 299 struct xfs_scrub *sc) 300 { 301 struct xchk_metapath *mpath = sc->buf; 302 xfs_ino_t ino = NULLFSINO; 303 int error; 304 305 /* Just probing, nothing else to do. */ 306 if (sc->sm->sm_ino == XFS_SCRUB_METAPATH_PROBE) 307 return 0; 308 309 /* Parent required to do anything else. */ 310 if (mpath->dp == NULL) { 311 xchk_ino_set_corrupt(sc, sc->ip->i_ino); 312 return 0; 313 } 314 315 error = xchk_trans_alloc_empty(sc); 316 if (error) 317 return error; 318 319 error = xchk_metapath_ilock_both(mpath); 320 if (error) 321 goto out_cancel; 322 323 /* Make sure the parent dir has a dirent pointing to this file. */ 324 error = xchk_dir_lookup(sc, mpath->dp, &mpath->xname, &ino); 325 trace_xchk_metapath_lookup(sc, mpath->path, mpath->dp, ino); 326 if (error == -ENOENT) { 327 /* No directory entry at all */ 328 xchk_ino_set_corrupt(sc, sc->ip->i_ino); 329 error = 0; 330 goto out_ilock; 331 } 332 if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error)) 333 goto out_ilock; 334 if (ino != sc->ip->i_ino) { 335 /* Pointing to wrong inode */ 336 xchk_ino_set_corrupt(sc, sc->ip->i_ino); 337 } 338 339 out_ilock: 340 xchk_metapath_iunlock(mpath); 341 out_cancel: 342 xchk_trans_cancel(sc); 343 return error; 344 } 345 346 #ifdef CONFIG_XFS_ONLINE_REPAIR 347 /* Create the dirent represented by the final component of the path. */ 348 STATIC int 349 xrep_metapath_link( 350 struct xchk_metapath *mpath) 351 { 352 struct xfs_scrub *sc = mpath->sc; 353 354 mpath->du.dp = mpath->dp; 355 mpath->du.name = &mpath->xname; 356 mpath->du.ip = sc->ip; 357 358 if (xfs_has_parent(sc->mp)) 359 mpath->du.ppargs = &mpath->link_ppargs; 360 else 361 mpath->du.ppargs = NULL; 362 363 trace_xrep_metapath_link(sc, mpath->path, mpath->dp, sc->ip->i_ino); 364 365 return xfs_dir_add_child(sc->tp, mpath->link_resblks, &mpath->du); 366 } 367 368 /* Remove the dirent at the final component of the path. */ 369 STATIC int 370 xrep_metapath_unlink( 371 struct xchk_metapath *mpath, 372 xfs_ino_t ino, 373 struct xfs_inode *ip) 374 { 375 struct xfs_parent_rec rec; 376 struct xfs_scrub *sc = mpath->sc; 377 struct xfs_mount *mp = sc->mp; 378 int error; 379 380 trace_xrep_metapath_unlink(sc, mpath->path, mpath->dp, ino); 381 382 if (!ip) { 383 /* The child inode isn't allocated. Junk the dirent. */ 384 xfs_trans_log_inode(sc->tp, mpath->dp, XFS_ILOG_CORE); 385 return xfs_dir_removename(sc->tp, mpath->dp, &mpath->xname, 386 ino, mpath->unlink_resblks); 387 } 388 389 mpath->du.dp = mpath->dp; 390 mpath->du.name = &mpath->xname; 391 mpath->du.ip = ip; 392 mpath->du.ppargs = NULL; 393 394 /* Figure out if we're removing a parent pointer too. */ 395 if (xfs_has_parent(mp)) { 396 xfs_inode_to_parent_rec(&rec, ip); 397 error = xfs_parent_lookup(sc->tp, ip, &mpath->xname, &rec, 398 &mpath->pptr_args); 399 switch (error) { 400 case -ENOATTR: 401 break; 402 case 0: 403 mpath->du.ppargs = &mpath->unlink_ppargs; 404 break; 405 default: 406 return error; 407 } 408 } 409 410 return xfs_dir_remove_child(sc->tp, mpath->unlink_resblks, &mpath->du); 411 } 412 413 /* 414 * Try to create a dirent in @mpath->dp with the name @mpath->xname that points 415 * to @sc->ip. Returns: 416 * 417 * -EEXIST and an @alleged_child if the dirent that points to the wrong inode; 418 * 0 if there is now a dirent pointing to @sc->ip; or 419 * A negative errno on error. 420 */ 421 STATIC int 422 xrep_metapath_try_link( 423 struct xchk_metapath *mpath, 424 xfs_ino_t *alleged_child) 425 { 426 struct xfs_scrub *sc = mpath->sc; 427 xfs_ino_t ino; 428 int error; 429 430 /* Allocate transaction, lock inodes, join to transaction. */ 431 error = xchk_trans_alloc(sc, mpath->link_resblks); 432 if (error) 433 return error; 434 435 error = xchk_metapath_ilock_both(mpath); 436 if (error) { 437 xchk_trans_cancel(sc); 438 return error; 439 } 440 xfs_trans_ijoin(sc->tp, mpath->dp, 0); 441 xfs_trans_ijoin(sc->tp, sc->ip, 0); 442 443 error = xchk_dir_lookup(sc, mpath->dp, &mpath->xname, &ino); 444 trace_xrep_metapath_lookup(sc, mpath->path, mpath->dp, ino); 445 if (error == -ENOENT) { 446 /* 447 * There is no dirent in the directory. Create an entry 448 * pointing to @sc->ip. 449 */ 450 error = xrep_metapath_link(mpath); 451 if (error) 452 goto out_cancel; 453 454 error = xrep_trans_commit(sc); 455 xchk_metapath_iunlock(mpath); 456 return error; 457 } 458 if (error) 459 goto out_cancel; 460 461 if (ino == sc->ip->i_ino) { 462 /* The dirent already points to @sc->ip; we're done. */ 463 error = 0; 464 goto out_cancel; 465 } 466 467 /* 468 * The dirent points elsewhere; pass that back so that the caller 469 * can try to remove the dirent. 470 */ 471 *alleged_child = ino; 472 error = -EEXIST; 473 474 out_cancel: 475 xchk_trans_cancel(sc); 476 xchk_metapath_iunlock(mpath); 477 return error; 478 } 479 480 /* 481 * Take the ILOCK on the metadata directory parent and a bad child, if one is 482 * supplied. We do not know that the metadata directory is not corrupt, so we 483 * lock the parent and try to lock the child. Returns 0 if successful, or 484 * -EINTR to abort the repair. The lock state of @dp is not recorded in @mpath. 485 */ 486 STATIC int 487 xchk_metapath_ilock_parent_and_child( 488 struct xchk_metapath *mpath, 489 struct xfs_inode *ip) 490 { 491 struct xfs_scrub *sc = mpath->sc; 492 int error = 0; 493 494 while (true) { 495 xfs_ilock(mpath->dp, XFS_ILOCK_EXCL); 496 if (!ip || xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) 497 return 0; 498 xfs_iunlock(mpath->dp, XFS_ILOCK_EXCL); 499 500 if (xchk_should_terminate(sc, &error)) 501 return error; 502 503 delay(1); 504 } 505 506 ASSERT(0); 507 return -EINTR; 508 } 509 510 /* 511 * Try to remove a dirent in @mpath->dp with the name @mpath->xname that points 512 * to @alleged_child. Returns: 513 * 514 * 0 if there is no longer a dirent; 515 * -EEXIST if the dirent points to @sc->ip; 516 * -EAGAIN and an updated @alleged_child if the dirent points elsewhere; or 517 * A negative errno for any other error. 518 */ 519 STATIC int 520 xrep_metapath_try_unlink( 521 struct xchk_metapath *mpath, 522 xfs_ino_t *alleged_child) 523 { 524 struct xfs_scrub *sc = mpath->sc; 525 struct xfs_inode *ip = NULL; 526 xfs_ino_t ino; 527 int error; 528 529 ASSERT(*alleged_child != sc->ip->i_ino); 530 531 trace_xrep_metapath_try_unlink(sc, mpath->path, mpath->dp, 532 *alleged_child); 533 534 /* 535 * Allocate transaction, grab the alleged child inode, lock inodes, 536 * join to transaction. 537 */ 538 error = xchk_trans_alloc(sc, mpath->unlink_resblks); 539 if (error) 540 return error; 541 542 error = xchk_iget(sc, *alleged_child, &ip); 543 if (error == -EINVAL || error == -ENOENT) { 544 /* inode number is bogus, junk the dirent */ 545 error = 0; 546 } 547 if (error) { 548 xchk_trans_cancel(sc); 549 return error; 550 } 551 552 error = xchk_metapath_ilock_parent_and_child(mpath, ip); 553 if (error) { 554 xchk_trans_cancel(sc); 555 return error; 556 } 557 xfs_trans_ijoin(sc->tp, mpath->dp, 0); 558 if (ip) 559 xfs_trans_ijoin(sc->tp, ip, 0); 560 561 error = xchk_dir_lookup(sc, mpath->dp, &mpath->xname, &ino); 562 trace_xrep_metapath_lookup(sc, mpath->path, mpath->dp, ino); 563 if (error == -ENOENT) { 564 /* 565 * There is no dirent in the directory anymore. We're ready to 566 * try the link operation again. 567 */ 568 error = 0; 569 goto out_cancel; 570 } 571 if (error) 572 goto out_cancel; 573 574 if (ino == sc->ip->i_ino) { 575 /* The dirent already points to @sc->ip; we're done. */ 576 error = -EEXIST; 577 goto out_cancel; 578 } 579 580 /* 581 * The dirent does not point to the alleged child. Update the caller 582 * and signal that we want to be called again. 583 */ 584 if (ino != *alleged_child) { 585 *alleged_child = ino; 586 error = -EAGAIN; 587 goto out_cancel; 588 } 589 590 /* Remove the link to the child. */ 591 error = xrep_metapath_unlink(mpath, ino, ip); 592 if (error) 593 goto out_cancel; 594 595 error = xrep_trans_commit(sc); 596 goto out_unlock; 597 598 out_cancel: 599 xchk_trans_cancel(sc); 600 out_unlock: 601 xfs_iunlock(mpath->dp, XFS_ILOCK_EXCL); 602 if (ip) { 603 xfs_iunlock(ip, XFS_ILOCK_EXCL); 604 xchk_irele(sc, ip); 605 } 606 return error; 607 } 608 609 /* 610 * Make sure the metadata directory path points to the child being examined. 611 * 612 * Repair needs to be able to create a directory structure, create its own 613 * transactions, and take ILOCKs. This function /must/ be called after all 614 * other repairs have completed. 615 */ 616 int 617 xrep_metapath( 618 struct xfs_scrub *sc) 619 { 620 struct xchk_metapath *mpath = sc->buf; 621 struct xfs_mount *mp = sc->mp; 622 int error = 0; 623 624 /* Just probing, nothing to repair. */ 625 if (sc->sm->sm_ino == XFS_SCRUB_METAPATH_PROBE) 626 return 0; 627 628 /* Parent required to do anything else. */ 629 if (mpath->dp == NULL) 630 return -EFSCORRUPTED; 631 632 /* 633 * Make sure the child file actually has an attr fork to receive a new 634 * parent pointer if the fs has parent pointers. 635 */ 636 if (xfs_has_parent(mp)) { 637 error = xfs_attr_add_fork(sc->ip, 638 sizeof(struct xfs_attr_sf_hdr), 1); 639 if (error) 640 return error; 641 } 642 643 /* Compute block reservation required to unlink and link a file. */ 644 mpath->unlink_resblks = xfs_remove_space_res(mp, MAXNAMELEN); 645 mpath->link_resblks = xfs_link_space_res(mp, MAXNAMELEN); 646 647 do { 648 xfs_ino_t alleged_child; 649 650 /* Re-establish the link, or tell us which inode to remove. */ 651 error = xrep_metapath_try_link(mpath, &alleged_child); 652 if (!error) 653 return 0; 654 if (error != -EEXIST) 655 return error; 656 657 /* 658 * Remove an incorrect link to an alleged child, or tell us 659 * which inode to remove. 660 */ 661 do { 662 error = xrep_metapath_try_unlink(mpath, &alleged_child); 663 } while (error == -EAGAIN); 664 if (error == -EEXIST) { 665 /* Link established; we're done. */ 666 error = 0; 667 break; 668 } 669 } while (!error); 670 671 return error; 672 } 673 #endif /* CONFIG_XFS_ONLINE_REPAIR */ 674