1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) 2020-2024 Oracle. All Rights Reserved. 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 */ 6 #include "xfs_platform.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_defer.h" 13 #include "xfs_bit.h" 14 #include "xfs_log_format.h" 15 #include "xfs_trans.h" 16 #include "xfs_sb.h" 17 #include "xfs_inode.h" 18 #include "xfs_icache.h" 19 #include "xfs_da_format.h" 20 #include "xfs_da_btree.h" 21 #include "xfs_dir2.h" 22 #include "xfs_bmap_btree.h" 23 #include "xfs_dir2_priv.h" 24 #include "xfs_trans_space.h" 25 #include "xfs_health.h" 26 #include "xfs_exchmaps.h" 27 #include "xfs_parent.h" 28 #include "scrub/xfs_scrub.h" 29 #include "scrub/scrub.h" 30 #include "scrub/common.h" 31 #include "scrub/trace.h" 32 #include "scrub/repair.h" 33 #include "scrub/iscan.h" 34 #include "scrub/findparent.h" 35 #include "scrub/readdir.h" 36 #include "scrub/tempfile.h" 37 #include "scrub/listxattr.h" 38 39 /* 40 * Finding the Parent of a Directory 41 * ================================= 42 * 43 * Directories have parent pointers, in the sense that each directory contains 44 * a dotdot entry that points to the single allowed parent. The brute force 45 * way to find the parent of a given directory is to scan every directory in 46 * the filesystem looking for a child dirent that references this directory. 47 * 48 * This module wraps the process of scanning the directory tree. It requires 49 * that @sc->ip is the directory whose parent we want to find, and that the 50 * caller hold only the IOLOCK on that directory. The scan itself needs to 51 * take the ILOCK of each directory visited. 52 * 53 * Because we cannot hold @sc->ip's ILOCK during a scan of the whole fs, it is 54 * necessary to use dirent hook to update the parent scan results. Callers 55 * must not read the scan results without re-taking @sc->ip's ILOCK. 56 * 57 * There are a few shortcuts that we can take to avoid scanning the entire 58 * filesystem, such as noticing directory tree roots and querying the dentry 59 * cache for parent information. 60 */ 61 62 struct xrep_findparent_info { 63 /* The directory currently being scanned. */ 64 struct xfs_inode *dp; 65 66 /* 67 * Scrub context. We're looking for a @dp containing a directory 68 * entry pointing to I_INO(sc->ip). 69 */ 70 struct xfs_scrub *sc; 71 72 /* Optional scan information for a xrep_findparent_scan call. */ 73 struct xrep_parent_scan_info *parent_scan; 74 75 /* 76 * Parent that we've found for sc->ip. If we're scanning the entire 77 * directory tree, we need this to ensure that we only find /one/ 78 * parent directory. 79 */ 80 xfs_ino_t found_parent; 81 82 /* 83 * This is set to true if @found_parent was not observed directly from 84 * the directory scan but by noticing a change in dotdot entries after 85 * cycling the sc->ip IOLOCK. 86 */ 87 bool parent_tentative; 88 }; 89 90 /* 91 * If this directory entry points to the scrub target inode, then the directory 92 * we're scanning is the parent of the scrub target inode. 93 */ 94 STATIC int 95 xrep_findparent_dirent( 96 struct xfs_scrub *sc, 97 struct xfs_inode *dp, 98 xfs_dir2_dataptr_t dapos, 99 const struct xfs_name *name, 100 xfs_ino_t ino, 101 void *priv) 102 { 103 struct xrep_findparent_info *fpi = priv; 104 int error = 0; 105 106 if (xchk_should_terminate(fpi->sc, &error)) 107 return error; 108 109 if (ino != I_INO(fpi->sc->ip)) 110 return 0; 111 112 /* Ignore garbage directory entry names. */ 113 if (name->len == 0 || !xfs_dir2_namecheck(name->name, name->len)) 114 return -EFSCORRUPTED; 115 116 /* 117 * Ignore dotdot and dot entries -- we're looking for parent -> child 118 * links only. 119 */ 120 if (name->name[0] == '.' && (name->len == 1 || 121 (name->len == 2 && name->name[1] == '.'))) 122 return 0; 123 124 /* Uhoh, more than one parent for a dir? */ 125 if (fpi->found_parent != NULLFSINO && 126 !(fpi->parent_tentative && fpi->found_parent == I_INO(fpi->dp))) { 127 trace_xrep_findparent_dirent(fpi->sc->ip, 0); 128 return -EFSCORRUPTED; 129 } 130 131 /* We found a potential parent; remember this. */ 132 trace_xrep_findparent_dirent(fpi->sc->ip, I_INO(fpi->dp)); 133 fpi->found_parent = I_INO(fpi->dp); 134 fpi->parent_tentative = false; 135 136 if (fpi->parent_scan) 137 xrep_findparent_scan_found(fpi->parent_scan, I_INO(fpi->dp)); 138 139 return 0; 140 } 141 142 static inline bool 143 xrep_findparent_want_scan_file( 144 const struct xrep_findparent_info *fpi) 145 { 146 const struct xfs_scrub *sc = fpi->sc; 147 const struct xfs_inode *dp = fpi->dp; 148 149 /* Only directories can be parents */ 150 if (!S_ISDIR(VFS_IC(dp)->i_mode)) 151 return false; 152 153 /* 154 * The inode being scanned cannot be its own parent, nor can any 155 * temporary directory we created to stage this repair. 156 */ 157 if (dp == sc->ip || dp == sc->tempip) 158 return false; 159 160 /* 161 * Similarly, temporary files created to stage a repair cannot be the 162 * parent of this inode. 163 */ 164 if (xrep_is_tempfile(dp)) 165 return false; 166 167 return true; 168 } 169 170 /* 171 * If this is a directory, walk the dirents looking for any that point to the 172 * scrub target inode. 173 */ 174 STATIC int 175 xrep_findparent_walk_file( 176 struct xrep_findparent_info *fpi) 177 { 178 struct xfs_scrub *sc = fpi->sc; 179 struct xfs_inode *dp = fpi->dp; 180 unsigned int lock_mode; 181 int error = 0; 182 183 if (!xrep_findparent_want_scan_file(fpi)) { 184 if (fpi->parent_scan) 185 xchk_iscan_mark_visited(&fpi->parent_scan->iscan, dp); 186 return 0; 187 } 188 189 /* 190 * Scan the directory to see if there it contains an entry pointing to 191 * the directory that we are repairing. 192 */ 193 lock_mode = xfs_ilock_data_map_shared(dp); 194 195 /* Don't mix metadata and regular directory trees. */ 196 if (xfs_is_metadir_inode(dp) != xfs_is_metadir_inode(sc->ip)) 197 goto out_unlock; 198 199 /* 200 * If this directory is known to be sick, we cannot scan it reliably 201 * and must abort. 202 */ 203 if (xfs_inode_has_sickness(dp, XFS_SICK_INO_CORE | 204 XFS_SICK_INO_BMBTD | 205 XFS_SICK_INO_DIR)) { 206 error = -EFSCORRUPTED; 207 goto out_unlock; 208 } 209 210 /* 211 * We cannot complete our parent pointer scan if a directory looks as 212 * though it has been zapped by the inode record repair code. 213 */ 214 if (xchk_dir_looks_zapped(dp)) { 215 error = -EBUSY; 216 goto out_unlock; 217 } 218 219 error = xchk_dir_walk(sc, dp, xrep_findparent_dirent, fpi); 220 if (error) 221 goto out_unlock; 222 223 out_unlock: 224 if (fpi->parent_scan) 225 xchk_iscan_mark_visited(&fpi->parent_scan->iscan, dp); 226 xfs_iunlock(dp, lock_mode); 227 return error; 228 } 229 230 /* 231 * Update this directory's dotdot pointer based on ongoing dirent updates. 232 */ 233 STATIC int 234 xrep_findparent_live_update( 235 struct notifier_block *nb, 236 unsigned long action, 237 void *data) 238 { 239 struct xfs_dir_update_params *p = data; 240 struct xrep_parent_scan_info *pscan; 241 struct xfs_scrub *sc; 242 243 pscan = container_of(nb, struct xrep_parent_scan_info, 244 dhook.dirent_hook.nb); 245 sc = pscan->sc; 246 247 /* 248 * If @p->ip is the subdirectory that we're interested in and we've 249 * already scanned @p->dp, update the dotdot target inumber to the 250 * parent inode. 251 */ 252 if (I_INO(p->ip) == I_INO(sc->ip) && 253 xchk_iscan_want_live_update(&pscan->iscan, I_INO(p->dp))) { 254 if (p->delta > 0) 255 xrep_findparent_scan_found(pscan, I_INO(p->dp)); 256 else 257 xrep_findparent_scan_found(pscan, NULLFSINO); 258 } 259 260 return NOTIFY_DONE; 261 } 262 263 /* 264 * Set up a scan to find the parent of a directory. The provided dirent hook 265 * will be called when there is a dotdot update for the inode being repaired. 266 */ 267 int 268 __xrep_findparent_scan_start( 269 struct xfs_scrub *sc, 270 struct xrep_parent_scan_info *pscan, 271 notifier_fn_t custom_fn) 272 { 273 int error; 274 275 if (!(sc->flags & XCHK_FSGATES_DIRENTS)) { 276 ASSERT(sc->flags & XCHK_FSGATES_DIRENTS); 277 return -EINVAL; 278 } 279 280 pscan->sc = sc; 281 pscan->parent_ino = NULLFSINO; 282 283 mutex_init(&pscan->lock); 284 285 xchk_iscan_start(sc, 30000, 100, &pscan->iscan); 286 287 /* 288 * Hook into the dirent update code. The hook only operates on inodes 289 * that were already scanned, and the scanner thread takes each inode's 290 * ILOCK, which means that any in-progress inode updates will finish 291 * before we can scan the inode. 292 */ 293 if (custom_fn) 294 xfs_dir_hook_setup(&pscan->dhook, custom_fn); 295 else 296 xfs_dir_hook_setup(&pscan->dhook, xrep_findparent_live_update); 297 error = xfs_dir_hook_add(sc->mp, &pscan->dhook); 298 if (error) 299 goto out_iscan; 300 301 return 0; 302 out_iscan: 303 xchk_iscan_teardown(&pscan->iscan); 304 mutex_destroy(&pscan->lock); 305 return error; 306 } 307 308 /* 309 * Scan the entire filesystem looking for a parent inode for the inode being 310 * scrubbed. @sc->ip must not be the root of a directory tree. Callers must 311 * not hold a dirty transaction or any lock that would interfere with taking 312 * an ILOCK. 313 * 314 * Returns 0 with @pscan->parent_ino set to the parent that we found. 315 * Returns 0 with @pscan->parent_ino set to NULLFSINO if we found no parents. 316 * Returns the usual negative errno if something else happened. 317 */ 318 int 319 xrep_findparent_scan( 320 struct xrep_parent_scan_info *pscan) 321 { 322 struct xrep_findparent_info fpi = { 323 .sc = pscan->sc, 324 .found_parent = NULLFSINO, 325 .parent_scan = pscan, 326 }; 327 struct xfs_scrub *sc = pscan->sc; 328 int ret; 329 330 ASSERT(S_ISDIR(VFS_IC(sc->ip)->i_mode)); 331 332 while ((ret = xchk_iscan_iter(&pscan->iscan, &fpi.dp)) == 1) { 333 ret = xrep_findparent_walk_file(&fpi); 334 xchk_irele(sc, fpi.dp); 335 if (ret) 336 break; 337 338 if (xchk_should_terminate(sc, &ret)) 339 break; 340 } 341 xchk_iscan_iter_finish(&pscan->iscan); 342 343 return ret; 344 } 345 346 /* Tear down a parent scan. */ 347 void 348 xrep_findparent_scan_teardown( 349 struct xrep_parent_scan_info *pscan) 350 { 351 xfs_dir_hook_del(pscan->sc->mp, &pscan->dhook); 352 xchk_iscan_teardown(&pscan->iscan); 353 mutex_destroy(&pscan->lock); 354 } 355 356 /* Finish a parent scan early. */ 357 void 358 xrep_findparent_scan_finish_early( 359 struct xrep_parent_scan_info *pscan, 360 xfs_ino_t ino) 361 { 362 xrep_findparent_scan_found(pscan, ino); 363 xchk_iscan_finish_early(&pscan->iscan); 364 } 365 366 /* 367 * Confirm that the directory @parent_ino actually contains a directory entry 368 * pointing to the child @sc->ip->ino. This function returns one of several 369 * ways: 370 * 371 * Returns 0 with @parent_ino unchanged if the parent was confirmed. 372 * Returns 0 with @parent_ino set to NULLFSINO if the parent was not valid. 373 * Returns the usual negative errno if something else happened. 374 */ 375 int 376 xrep_findparent_confirm( 377 struct xfs_scrub *sc, 378 xfs_ino_t *parent_ino) 379 { 380 struct xrep_findparent_info fpi = { 381 .sc = sc, 382 .found_parent = NULLFSINO, 383 }; 384 int error; 385 386 /* The root directory always points to itself. */ 387 if (sc->ip == sc->mp->m_rootip) { 388 *parent_ino = sc->mp->m_sb.sb_rootino; 389 return 0; 390 } 391 392 /* The metadata root directory always points to itself. */ 393 if (sc->ip == sc->mp->m_metadirip) { 394 *parent_ino = sc->mp->m_sb.sb_metadirino; 395 return 0; 396 } 397 398 /* Unlinked dirs can point anywhere; point them up to the root dir. */ 399 if (VFS_I(sc->ip)->i_nlink == 0) { 400 *parent_ino = xchk_inode_rootdir_inum(sc->ip); 401 return 0; 402 } 403 404 /* Reject garbage parent inode numbers and self-referential parents. */ 405 if (*parent_ino == NULLFSINO) 406 return 0; 407 if (!xfs_verify_dir_ino(sc->mp, *parent_ino) || 408 *parent_ino == I_INO(sc->ip)) { 409 *parent_ino = NULLFSINO; 410 return 0; 411 } 412 413 error = xchk_iget(sc, *parent_ino, &fpi.dp); 414 if (error) 415 return error; 416 417 if (!S_ISDIR(VFS_I(fpi.dp)->i_mode)) { 418 *parent_ino = NULLFSINO; 419 goto out_rele; 420 } 421 422 error = xrep_findparent_walk_file(&fpi); 423 if (error) 424 goto out_rele; 425 426 *parent_ino = fpi.found_parent; 427 out_rele: 428 xchk_irele(sc, fpi.dp); 429 return error; 430 } 431 432 /* 433 * If we're the root of a directory tree, we are our own parent. If we're an 434 * unlinked directory, the parent /won't/ have a link to us. Set the parent 435 * directory to the root for both cases. Returns NULLFSINO if we don't know 436 * what to do. 437 */ 438 xfs_ino_t 439 xrep_findparent_self_reference( 440 struct xfs_scrub *sc) 441 { 442 if (I_INO(sc->ip) == sc->mp->m_sb.sb_rootino) 443 return sc->mp->m_sb.sb_rootino; 444 445 if (I_INO(sc->ip) == sc->mp->m_sb.sb_metadirino) 446 return sc->mp->m_sb.sb_metadirino; 447 448 if (VFS_I(sc->ip)->i_nlink == 0) 449 return xchk_inode_rootdir_inum(sc->ip); 450 451 return NULLFSINO; 452 } 453 454 /* Check the dentry cache to see if knows of a parent for the scrub target. */ 455 xfs_ino_t 456 xrep_findparent_from_dcache( 457 struct xfs_scrub *sc) 458 { 459 struct inode *pip = NULL; 460 struct dentry *dentry, *parent; 461 xfs_ino_t ret = NULLFSINO; 462 463 dentry = d_find_alias(VFS_I(sc->ip)); 464 if (!dentry) 465 goto out; 466 467 parent = dget_parent(dentry); 468 if (!parent) 469 goto out_dput; 470 471 ASSERT(parent->d_sb == sc->ip->i_mount->m_super); 472 473 pip = igrab(d_inode(parent)); 474 dput(parent); 475 476 if (!pip) 477 goto out_dput; 478 479 if (S_ISDIR(pip->i_mode)) { 480 ret = pip->i_ino; 481 trace_xrep_findparent_from_dcache(sc->ip, ret); 482 } 483 484 xchk_irele(sc, XFS_I(pip)); 485 486 out_dput: 487 dput(dentry); 488 out: 489 return ret; 490 } 491