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.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 "scrub/xfs_scrub.h" 28 #include "scrub/scrub.h" 29 #include "scrub/common.h" 30 #include "scrub/trace.h" 31 #include "scrub/repair.h" 32 #include "scrub/iscan.h" 33 #include "scrub/findparent.h" 34 #include "scrub/readdir.h" 35 #include "scrub/tempfile.h" 36 #include "scrub/orphanage.h" 37 38 /* 39 * Repairing The Directory Parent Pointer 40 * ====================================== 41 * 42 * Currently, only directories support parent pointers (in the form of '..' 43 * entries), so we simply scan the filesystem and update the '..' entry. 44 * 45 * Note that because the only parent pointer is the dotdot entry, we won't 46 * touch an unhealthy directory, since the directory repair code is perfectly 47 * capable of rebuilding a directory with the proper parent inode. 48 * 49 * See the section on locking issues in dir_repair.c for more information about 50 * conflicts with the VFS. The findparent code wll keep our incore parent 51 * inode up to date. 52 */ 53 54 struct xrep_parent { 55 struct xfs_scrub *sc; 56 57 /* 58 * Information used to scan the filesystem to find the inumber of the 59 * dotdot entry for this directory. 60 */ 61 struct xrep_parent_scan_info pscan; 62 63 /* Orphanage reparenting request. */ 64 struct xrep_adoption adoption; 65 66 /* Directory entry name, plus the trailing null. */ 67 struct xfs_name xname; 68 unsigned char namebuf[MAXNAMELEN]; 69 }; 70 71 /* Tear down all the incore stuff we created. */ 72 static void 73 xrep_parent_teardown( 74 struct xrep_parent *rp) 75 { 76 xrep_findparent_scan_teardown(&rp->pscan); 77 } 78 79 /* Set up for a parent repair. */ 80 int 81 xrep_setup_parent( 82 struct xfs_scrub *sc) 83 { 84 struct xrep_parent *rp; 85 86 xchk_fsgates_enable(sc, XCHK_FSGATES_DIRENTS); 87 88 rp = kvzalloc(sizeof(struct xrep_parent), XCHK_GFP_FLAGS); 89 if (!rp) 90 return -ENOMEM; 91 rp->sc = sc; 92 rp->xname.name = rp->namebuf; 93 sc->buf = rp; 94 95 return xrep_orphanage_try_create(sc); 96 } 97 98 /* 99 * Scan all files in the filesystem for a child dirent that we can turn into 100 * the dotdot entry for this directory. 101 */ 102 STATIC int 103 xrep_parent_find_dotdot( 104 struct xrep_parent *rp) 105 { 106 struct xfs_scrub *sc = rp->sc; 107 xfs_ino_t ino; 108 unsigned int sick, checked; 109 int error; 110 111 /* 112 * Avoid sick directories. There shouldn't be anyone else clearing the 113 * directory's sick status. 114 */ 115 xfs_inode_measure_sickness(sc->ip, &sick, &checked); 116 if (sick & XFS_SICK_INO_DIR) 117 return -EFSCORRUPTED; 118 119 ino = xrep_findparent_self_reference(sc); 120 if (ino != NULLFSINO) { 121 xrep_findparent_scan_finish_early(&rp->pscan, ino); 122 return 0; 123 } 124 125 /* 126 * Drop the ILOCK on this directory so that we can scan for the dotdot 127 * entry. Figure out who is going to be the parent of this directory, 128 * then retake the ILOCK so that we can salvage directory entries. 129 */ 130 xchk_iunlock(sc, XFS_ILOCK_EXCL); 131 132 /* Does the VFS dcache have an answer for us? */ 133 ino = xrep_findparent_from_dcache(sc); 134 if (ino != NULLFSINO) { 135 error = xrep_findparent_confirm(sc, &ino); 136 if (!error && ino != NULLFSINO) { 137 xrep_findparent_scan_finish_early(&rp->pscan, ino); 138 goto out_relock; 139 } 140 } 141 142 /* Scan the entire filesystem for a parent. */ 143 error = xrep_findparent_scan(&rp->pscan); 144 out_relock: 145 xchk_ilock(sc, XFS_ILOCK_EXCL); 146 147 return error; 148 } 149 150 /* Reset a directory's dotdot entry, if needed. */ 151 STATIC int 152 xrep_parent_reset_dotdot( 153 struct xrep_parent *rp) 154 { 155 struct xfs_scrub *sc = rp->sc; 156 xfs_ino_t ino; 157 unsigned int spaceres; 158 int error = 0; 159 160 ASSERT(sc->ilock_flags & XFS_ILOCK_EXCL); 161 162 error = xchk_dir_lookup(sc, sc->ip, &xfs_name_dotdot, &ino); 163 if (error || ino == rp->pscan.parent_ino) 164 return error; 165 166 xfs_trans_ijoin(sc->tp, sc->ip, 0); 167 168 trace_xrep_parent_reset_dotdot(sc->ip, rp->pscan.parent_ino); 169 170 /* 171 * Reserve more space just in case we have to expand the dir. We're 172 * allowed to exceed quota to repair inconsistent metadata. 173 */ 174 spaceres = XFS_RENAME_SPACE_RES(sc->mp, xfs_name_dotdot.len); 175 error = xfs_trans_reserve_more_inode(sc->tp, sc->ip, spaceres, 0, 176 true); 177 if (error) 178 return error; 179 180 error = xfs_dir_replace(sc->tp, sc->ip, &xfs_name_dotdot, 181 rp->pscan.parent_ino, spaceres); 182 if (error) 183 return error; 184 185 /* 186 * Roll transaction to detach the inode from the transaction but retain 187 * ILOCK_EXCL. 188 */ 189 return xfs_trans_roll(&sc->tp); 190 } 191 192 /* 193 * Move the current file to the orphanage. 194 * 195 * Caller must hold IOLOCK_EXCL on @sc->ip, and no other inode locks. Upon 196 * successful return, the scrub transaction will have enough extra reservation 197 * to make the move; it will hold IOLOCK_EXCL and ILOCK_EXCL of @sc->ip and the 198 * orphanage; and both inodes will be ijoined. 199 */ 200 STATIC int 201 xrep_parent_move_to_orphanage( 202 struct xrep_parent *rp) 203 { 204 struct xfs_scrub *sc = rp->sc; 205 xfs_ino_t orig_parent, new_parent; 206 int error; 207 208 /* 209 * We are about to drop the ILOCK on sc->ip to lock the orphanage and 210 * prepare for the adoption. Therefore, look up the old dotdot entry 211 * for sc->ip so that we can compare it after we re-lock sc->ip. 212 */ 213 error = xchk_dir_lookup(sc, sc->ip, &xfs_name_dotdot, &orig_parent); 214 if (error) 215 return error; 216 217 /* 218 * Drop the ILOCK on the scrub target and commit the transaction. 219 * Adoption computes its own resource requirements and gathers the 220 * necessary components. 221 */ 222 error = xrep_trans_commit(sc); 223 if (error) 224 return error; 225 xchk_iunlock(sc, XFS_ILOCK_EXCL); 226 227 /* If we can take the orphanage's iolock then we're ready to move. */ 228 if (!xrep_orphanage_ilock_nowait(sc, XFS_IOLOCK_EXCL)) { 229 xchk_iunlock(sc, sc->ilock_flags); 230 error = xrep_orphanage_iolock_two(sc); 231 if (error) 232 return error; 233 } 234 235 /* Grab transaction and ILOCK the two files. */ 236 error = xrep_adoption_trans_alloc(sc, &rp->adoption); 237 if (error) 238 return error; 239 240 error = xrep_adoption_compute_name(&rp->adoption, &rp->xname); 241 if (error) 242 return error; 243 244 /* 245 * Now that we've reacquired the ILOCK on sc->ip, look up the dotdot 246 * entry again. If the parent changed or the child was unlinked while 247 * the child directory was unlocked, we don't need to move the child to 248 * the orphanage after all. 249 */ 250 error = xchk_dir_lookup(sc, sc->ip, &xfs_name_dotdot, &new_parent); 251 if (error) 252 return error; 253 254 /* 255 * Attach to the orphanage if we still have a linked directory and it 256 * hasn't been moved. 257 */ 258 if (orig_parent == new_parent && VFS_I(sc->ip)->i_nlink > 0) { 259 error = xrep_adoption_move(&rp->adoption); 260 if (error) 261 return error; 262 } 263 264 /* 265 * Launder the scrub transaction so we can drop the orphanage ILOCK 266 * and IOLOCK. Return holding the scrub target's ILOCK and IOLOCK. 267 */ 268 error = xrep_adoption_trans_roll(&rp->adoption); 269 if (error) 270 return error; 271 272 xrep_orphanage_iunlock(sc, XFS_ILOCK_EXCL); 273 xrep_orphanage_iunlock(sc, XFS_IOLOCK_EXCL); 274 return 0; 275 } 276 277 /* 278 * Commit the new parent pointer structure (currently only the dotdot entry) to 279 * the file that we're repairing. 280 */ 281 STATIC int 282 xrep_parent_rebuild_tree( 283 struct xrep_parent *rp) 284 { 285 if (rp->pscan.parent_ino == NULLFSINO) { 286 if (xrep_orphanage_can_adopt(rp->sc)) 287 return xrep_parent_move_to_orphanage(rp); 288 return -EFSCORRUPTED; 289 } 290 291 return xrep_parent_reset_dotdot(rp); 292 } 293 294 /* Set up the filesystem scan so we can look for parents. */ 295 STATIC int 296 xrep_parent_setup_scan( 297 struct xrep_parent *rp) 298 { 299 struct xfs_scrub *sc = rp->sc; 300 301 return xrep_findparent_scan_start(sc, &rp->pscan); 302 } 303 304 int 305 xrep_parent( 306 struct xfs_scrub *sc) 307 { 308 struct xrep_parent *rp = sc->buf; 309 int error; 310 311 error = xrep_parent_setup_scan(rp); 312 if (error) 313 return error; 314 315 error = xrep_parent_find_dotdot(rp); 316 if (error) 317 goto out_teardown; 318 319 /* Last chance to abort before we start committing fixes. */ 320 if (xchk_should_terminate(sc, &error)) 321 goto out_teardown; 322 323 error = xrep_parent_rebuild_tree(rp); 324 if (error) 325 goto out_teardown; 326 327 out_teardown: 328 xrep_parent_teardown(rp); 329 return error; 330 } 331