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