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