findparent.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  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 "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. * Finding the Parent of a Directory
  40. * =================================
  41. *
  42. * Directories have parent pointers, in the sense that each directory contains
  43. * a dotdot entry that points to the single allowed parent. The brute force
  44. * way to find the parent of a given directory is to scan every directory in
  45. * the filesystem looking for a child dirent that references this directory.
  46. *
  47. * This module wraps the process of scanning the directory tree. It requires
  48. * that @sc->ip is the directory whose parent we want to find, and that the
  49. * caller hold only the IOLOCK on that directory. The scan itself needs to
  50. * take the ILOCK of each directory visited.
  51. *
  52. * Because we cannot hold @sc->ip's ILOCK during a scan of the whole fs, it is
  53. * necessary to use dirent hook to update the parent scan results. Callers
  54. * must not read the scan results without re-taking @sc->ip's ILOCK.
  55. *
  56. * There are a few shortcuts that we can take to avoid scanning the entire
  57. * filesystem, such as noticing directory tree roots and querying the dentry
  58. * cache for parent information.
  59. */
  60. struct xrep_findparent_info {
  61. /* The directory currently being scanned. */
  62. struct xfs_inode *dp;
  63. /*
  64. * Scrub context. We're looking for a @dp containing a directory
  65. * entry pointing to sc->ip->i_ino.
  66. */
  67. struct xfs_scrub *sc;
  68. /* Optional scan information for a xrep_findparent_scan call. */
  69. struct xrep_parent_scan_info *parent_scan;
  70. /*
  71. * Parent that we've found for sc->ip. If we're scanning the entire
  72. * directory tree, we need this to ensure that we only find /one/
  73. * parent directory.
  74. */
  75. xfs_ino_t found_parent;
  76. /*
  77. * This is set to true if @found_parent was not observed directly from
  78. * the directory scan but by noticing a change in dotdot entries after
  79. * cycling the sc->ip IOLOCK.
  80. */
  81. bool parent_tentative;
  82. };
  83. /*
  84. * If this directory entry points to the scrub target inode, then the directory
  85. * we're scanning is the parent of the scrub target inode.
  86. */
  87. STATIC int
  88. xrep_findparent_dirent(
  89. struct xfs_scrub *sc,
  90. struct xfs_inode *dp,
  91. xfs_dir2_dataptr_t dapos,
  92. const struct xfs_name *name,
  93. xfs_ino_t ino,
  94. void *priv)
  95. {
  96. struct xrep_findparent_info *fpi = priv;
  97. int error = 0;
  98. if (xchk_should_terminate(fpi->sc, &error))
  99. return error;
  100. if (ino != fpi->sc->ip->i_ino)
  101. return 0;
  102. /* Ignore garbage directory entry names. */
  103. if (name->len == 0 || !xfs_dir2_namecheck(name->name, name->len))
  104. return -EFSCORRUPTED;
  105. /*
  106. * Ignore dotdot and dot entries -- we're looking for parent -> child
  107. * links only.
  108. */
  109. if (name->name[0] == '.' && (name->len == 1 ||
  110. (name->len == 2 && name->name[1] == '.')))
  111. return 0;
  112. /* Uhoh, more than one parent for a dir? */
  113. if (fpi->found_parent != NULLFSINO &&
  114. !(fpi->parent_tentative && fpi->found_parent == fpi->dp->i_ino)) {
  115. trace_xrep_findparent_dirent(fpi->sc->ip, 0);
  116. return -EFSCORRUPTED;
  117. }
  118. /* We found a potential parent; remember this. */
  119. trace_xrep_findparent_dirent(fpi->sc->ip, fpi->dp->i_ino);
  120. fpi->found_parent = fpi->dp->i_ino;
  121. fpi->parent_tentative = false;
  122. if (fpi->parent_scan)
  123. xrep_findparent_scan_found(fpi->parent_scan, fpi->dp->i_ino);
  124. return 0;
  125. }
  126. /*
  127. * If this is a directory, walk the dirents looking for any that point to the
  128. * scrub target inode.
  129. */
  130. STATIC int
  131. xrep_findparent_walk_directory(
  132. struct xrep_findparent_info *fpi)
  133. {
  134. struct xfs_scrub *sc = fpi->sc;
  135. struct xfs_inode *dp = fpi->dp;
  136. unsigned int lock_mode;
  137. int error = 0;
  138. /*
  139. * The inode being scanned cannot be its own parent, nor can any
  140. * temporary directory we created to stage this repair.
  141. */
  142. if (dp == sc->ip || dp == sc->tempip)
  143. return 0;
  144. /*
  145. * Similarly, temporary files created to stage a repair cannot be the
  146. * parent of this inode.
  147. */
  148. if (xrep_is_tempfile(dp))
  149. return 0;
  150. /*
  151. * Scan the directory to see if there it contains an entry pointing to
  152. * the directory that we are repairing.
  153. */
  154. lock_mode = xfs_ilock_data_map_shared(dp);
  155. /*
  156. * If this directory is known to be sick, we cannot scan it reliably
  157. * and must abort.
  158. */
  159. if (xfs_inode_has_sickness(dp, XFS_SICK_INO_CORE |
  160. XFS_SICK_INO_BMBTD |
  161. XFS_SICK_INO_DIR)) {
  162. error = -EFSCORRUPTED;
  163. goto out_unlock;
  164. }
  165. /*
  166. * We cannot complete our parent pointer scan if a directory looks as
  167. * though it has been zapped by the inode record repair code.
  168. */
  169. if (xchk_dir_looks_zapped(dp)) {
  170. error = -EBUSY;
  171. goto out_unlock;
  172. }
  173. error = xchk_dir_walk(sc, dp, xrep_findparent_dirent, fpi);
  174. if (error)
  175. goto out_unlock;
  176. out_unlock:
  177. xfs_iunlock(dp, lock_mode);
  178. return error;
  179. }
  180. /*
  181. * Update this directory's dotdot pointer based on ongoing dirent updates.
  182. */
  183. STATIC int
  184. xrep_findparent_live_update(
  185. struct notifier_block *nb,
  186. unsigned long action,
  187. void *data)
  188. {
  189. struct xfs_dir_update_params *p = data;
  190. struct xrep_parent_scan_info *pscan;
  191. struct xfs_scrub *sc;
  192. pscan = container_of(nb, struct xrep_parent_scan_info,
  193. dhook.dirent_hook.nb);
  194. sc = pscan->sc;
  195. /*
  196. * If @p->ip is the subdirectory that we're interested in and we've
  197. * already scanned @p->dp, update the dotdot target inumber to the
  198. * parent inode.
  199. */
  200. if (p->ip->i_ino == sc->ip->i_ino &&
  201. xchk_iscan_want_live_update(&pscan->iscan, p->dp->i_ino)) {
  202. if (p->delta > 0) {
  203. xrep_findparent_scan_found(pscan, p->dp->i_ino);
  204. } else {
  205. xrep_findparent_scan_found(pscan, NULLFSINO);
  206. }
  207. }
  208. return NOTIFY_DONE;
  209. }
  210. /*
  211. * Set up a scan to find the parent of a directory. The provided dirent hook
  212. * will be called when there is a dotdot update for the inode being repaired.
  213. */
  214. int
  215. __xrep_findparent_scan_start(
  216. struct xfs_scrub *sc,
  217. struct xrep_parent_scan_info *pscan,
  218. notifier_fn_t custom_fn)
  219. {
  220. int error;
  221. if (!(sc->flags & XCHK_FSGATES_DIRENTS)) {
  222. ASSERT(sc->flags & XCHK_FSGATES_DIRENTS);
  223. return -EINVAL;
  224. }
  225. pscan->sc = sc;
  226. pscan->parent_ino = NULLFSINO;
  227. mutex_init(&pscan->lock);
  228. xchk_iscan_start(sc, 30000, 100, &pscan->iscan);
  229. /*
  230. * Hook into the dirent update code. The hook only operates on inodes
  231. * that were already scanned, and the scanner thread takes each inode's
  232. * ILOCK, which means that any in-progress inode updates will finish
  233. * before we can scan the inode.
  234. */
  235. if (custom_fn)
  236. xfs_dir_hook_setup(&pscan->dhook, custom_fn);
  237. else
  238. xfs_dir_hook_setup(&pscan->dhook, xrep_findparent_live_update);
  239. error = xfs_dir_hook_add(sc->mp, &pscan->dhook);
  240. if (error)
  241. goto out_iscan;
  242. return 0;
  243. out_iscan:
  244. xchk_iscan_teardown(&pscan->iscan);
  245. mutex_destroy(&pscan->lock);
  246. return error;
  247. }
  248. /*
  249. * Scan the entire filesystem looking for a parent inode for the inode being
  250. * scrubbed. @sc->ip must not be the root of a directory tree. Callers must
  251. * not hold a dirty transaction or any lock that would interfere with taking
  252. * an ILOCK.
  253. *
  254. * Returns 0 with @pscan->parent_ino set to the parent that we found.
  255. * Returns 0 with @pscan->parent_ino set to NULLFSINO if we found no parents.
  256. * Returns the usual negative errno if something else happened.
  257. */
  258. int
  259. xrep_findparent_scan(
  260. struct xrep_parent_scan_info *pscan)
  261. {
  262. struct xrep_findparent_info fpi = {
  263. .sc = pscan->sc,
  264. .found_parent = NULLFSINO,
  265. .parent_scan = pscan,
  266. };
  267. struct xfs_scrub *sc = pscan->sc;
  268. int ret;
  269. ASSERT(S_ISDIR(VFS_IC(sc->ip)->i_mode));
  270. while ((ret = xchk_iscan_iter(&pscan->iscan, &fpi.dp)) == 1) {
  271. if (S_ISDIR(VFS_I(fpi.dp)->i_mode))
  272. ret = xrep_findparent_walk_directory(&fpi);
  273. else
  274. ret = 0;
  275. xchk_iscan_mark_visited(&pscan->iscan, fpi.dp);
  276. xchk_irele(sc, fpi.dp);
  277. if (ret)
  278. break;
  279. if (xchk_should_terminate(sc, &ret))
  280. break;
  281. }
  282. xchk_iscan_iter_finish(&pscan->iscan);
  283. return ret;
  284. }
  285. /* Tear down a parent scan. */
  286. void
  287. xrep_findparent_scan_teardown(
  288. struct xrep_parent_scan_info *pscan)
  289. {
  290. xfs_dir_hook_del(pscan->sc->mp, &pscan->dhook);
  291. xchk_iscan_teardown(&pscan->iscan);
  292. mutex_destroy(&pscan->lock);
  293. }
  294. /* Finish a parent scan early. */
  295. void
  296. xrep_findparent_scan_finish_early(
  297. struct xrep_parent_scan_info *pscan,
  298. xfs_ino_t ino)
  299. {
  300. xrep_findparent_scan_found(pscan, ino);
  301. xchk_iscan_finish_early(&pscan->iscan);
  302. }
  303. /*
  304. * Confirm that the directory @parent_ino actually contains a directory entry
  305. * pointing to the child @sc->ip->ino. This function returns one of several
  306. * ways:
  307. *
  308. * Returns 0 with @parent_ino unchanged if the parent was confirmed.
  309. * Returns 0 with @parent_ino set to NULLFSINO if the parent was not valid.
  310. * Returns the usual negative errno if something else happened.
  311. */
  312. int
  313. xrep_findparent_confirm(
  314. struct xfs_scrub *sc,
  315. xfs_ino_t *parent_ino)
  316. {
  317. struct xrep_findparent_info fpi = {
  318. .sc = sc,
  319. .found_parent = NULLFSINO,
  320. };
  321. int error;
  322. /*
  323. * The root directory always points to itself. Unlinked dirs can point
  324. * anywhere, so we point them at the root dir too.
  325. */
  326. if (sc->ip == sc->mp->m_rootip || VFS_I(sc->ip)->i_nlink == 0) {
  327. *parent_ino = sc->mp->m_sb.sb_rootino;
  328. return 0;
  329. }
  330. /* Reject garbage parent inode numbers and self-referential parents. */
  331. if (*parent_ino == NULLFSINO)
  332. return 0;
  333. if (!xfs_verify_dir_ino(sc->mp, *parent_ino) ||
  334. *parent_ino == sc->ip->i_ino) {
  335. *parent_ino = NULLFSINO;
  336. return 0;
  337. }
  338. error = xchk_iget(sc, *parent_ino, &fpi.dp);
  339. if (error)
  340. return error;
  341. if (!S_ISDIR(VFS_I(fpi.dp)->i_mode)) {
  342. *parent_ino = NULLFSINO;
  343. goto out_rele;
  344. }
  345. error = xrep_findparent_walk_directory(&fpi);
  346. if (error)
  347. goto out_rele;
  348. *parent_ino = fpi.found_parent;
  349. out_rele:
  350. xchk_irele(sc, fpi.dp);
  351. return error;
  352. }
  353. /*
  354. * If we're the root of a directory tree, we are our own parent. If we're an
  355. * unlinked directory, the parent /won't/ have a link to us. Set the parent
  356. * directory to the root for both cases. Returns NULLFSINO if we don't know
  357. * what to do.
  358. */
  359. xfs_ino_t
  360. xrep_findparent_self_reference(
  361. struct xfs_scrub *sc)
  362. {
  363. if (sc->ip->i_ino == sc->mp->m_sb.sb_rootino)
  364. return sc->mp->m_sb.sb_rootino;
  365. if (VFS_I(sc->ip)->i_nlink == 0)
  366. return sc->mp->m_sb.sb_rootino;
  367. return NULLFSINO;
  368. }
  369. /* Check the dentry cache to see if knows of a parent for the scrub target. */
  370. xfs_ino_t
  371. xrep_findparent_from_dcache(
  372. struct xfs_scrub *sc)
  373. {
  374. struct inode *pip = NULL;
  375. struct dentry *dentry, *parent;
  376. xfs_ino_t ret = NULLFSINO;
  377. dentry = d_find_alias(VFS_I(sc->ip));
  378. if (!dentry)
  379. goto out;
  380. parent = dget_parent(dentry);
  381. if (!parent)
  382. goto out_dput;
  383. ASSERT(parent->d_sb == sc->ip->i_mount->m_super);
  384. pip = igrab(d_inode(parent));
  385. dput(parent);
  386. if (S_ISDIR(pip->i_mode)) {
  387. trace_xrep_findparent_from_dcache(sc->ip, XFS_I(pip)->i_ino);
  388. ret = XFS_I(pip)->i_ino;
  389. }
  390. xchk_irele(sc, XFS_I(pip));
  391. out_dput:
  392. dput(dentry);
  393. out:
  394. return ret;
  395. }