Lines Matching +full:step +full:- +full:up

1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 2023-2024 Oracle. All Rights Reserved.
48 * suffice to stabilize two directories in a parent -> child relationship.
67 /* Clean up the dirtree checking resources. */
75 if (dl->scan_ino != NULLFSINO) in xchk_dirtree_buf_cleanup()
76 xfs_dir_hook_del(dl->sc->mp, &dl->dhook); in xchk_dirtree_buf_cleanup()
79 list_del_init(&path->list); in xchk_dirtree_buf_cleanup()
80 xino_bitmap_destroy(&path->seen_inodes); in xchk_dirtree_buf_cleanup()
84 xfblob_destroy(dl->path_names); in xchk_dirtree_buf_cleanup()
85 xfarray_destroy(dl->path_steps); in xchk_dirtree_buf_cleanup()
86 mutex_destroy(&dl->lock); in xchk_dirtree_buf_cleanup()
89 /* Set us up to look for directory loops. */
108 return -ENOMEM; in xchk_setup_dirtree()
109 dl->sc = sc; in xchk_setup_dirtree()
110 dl->xname.name = dl->namebuf; in xchk_setup_dirtree()
111 dl->hook_xname.name = dl->hook_namebuf; in xchk_setup_dirtree()
112 INIT_LIST_HEAD(&dl->path_list); in xchk_setup_dirtree()
113 dl->root_ino = NULLFSINO; in xchk_setup_dirtree()
114 dl->scan_ino = NULLFSINO; in xchk_setup_dirtree()
115 dl->parent_ino = NULLFSINO; in xchk_setup_dirtree()
117 mutex_init(&dl->lock); in xchk_setup_dirtree()
121 &dl->path_steps); in xchk_setup_dirtree()
127 error = xfblob_create(descr, &dl->path_names); in xchk_setup_dirtree()
136 sc->buf = dl; in xchk_setup_dirtree()
137 sc->buf_cleanup = xchk_dirtree_buf_cleanup; in xchk_setup_dirtree()
141 xfblob_destroy(dl->path_names); in xchk_setup_dirtree()
143 xfarray_destroy(dl->path_steps); in xchk_setup_dirtree()
145 mutex_destroy(&dl->lock); in xchk_setup_dirtree()
151 * Add the parent pointer described by @dl->pptr to the given path as a new
152 * step. Returns -ELNRNG if the path is too deep.
162 struct xchk_dirpath_step step = { in xchk_dirpath_append() local
164 .name_len = name->len, in xchk_dirpath_append()
172 if (path->nr_steps >= XFS_MAXLINK) in xchk_dirpath_append()
173 return -ELNRNG; in xchk_dirpath_append()
175 error = xfblob_storename(dl->path_names, &step.name_cookie, name); in xchk_dirpath_append()
179 error = xino_bitmap_set(&path->seen_inodes, ip->i_ino); in xchk_dirpath_append()
183 error = xfarray_append(dl->path_steps, &step); in xchk_dirpath_append()
187 path->nr_steps++; in xchk_dirpath_append()
197 * Returns -EFSCORRUPTED to signal that the inode being scanned has a corrupt
198 * parent pointer and hence there's no point in continuing; or -ENOSR if there
224 error = xfs_parent_from_attr(sc->mp, attr_flags, name, namelen, value, in xchk_dirtree_create_path()
233 if (dl->nr_paths >= XFS_MAXLINK) in xchk_dirtree_create_path()
234 return -ENOSR; in xchk_dirtree_create_path()
236 trace_xchk_dirtree_create_path(sc, ip, dl->nr_paths, &xname, rec); in xchk_dirtree_create_path()
240 * and record the first name step. in xchk_dirtree_create_path()
244 return -ENOMEM; in xchk_dirtree_create_path()
246 INIT_LIST_HEAD(&path->list); in xchk_dirtree_create_path()
247 xino_bitmap_init(&path->seen_inodes); in xchk_dirtree_create_path()
248 path->nr_steps = 0; in xchk_dirtree_create_path()
249 path->outcome = XCHK_DIRPATH_SCANNING; in xchk_dirtree_create_path()
251 error = xchk_dirpath_append(dl, sc->ip, path, &xname, rec); in xchk_dirtree_create_path()
255 path->first_step = xfarray_length(dl->path_steps) - 1; in xchk_dirtree_create_path()
256 path->second_step = XFARRAY_NULLIDX; in xchk_dirtree_create_path()
257 path->path_nr = dl->nr_paths; in xchk_dirtree_create_path()
259 list_add_tail(&path->list, &dl->path_list); in xchk_dirtree_create_path()
260 dl->nr_paths++; in xchk_dirtree_create_path()
268 * Validate that the first step of this path still has a corresponding
269 * parent pointer in @sc->ip. We probably dropped @sc->ip's ILOCK while
273 * path into the parent pointer scratch pad. This prepares us to walk up the
274 * directory tree towards the root. Returns -ESTALE if the scan data is now
282 struct xfs_scrub *sc = dl->sc; in xchk_dirpath_revalidate()
286 * Look up the parent pointer that corresponds to the start of this in xchk_dirpath_revalidate()
290 error = xfs_parent_lookup(sc->tp, sc->ip, &dl->xname, &dl->pptr_rec, in xchk_dirpath_revalidate()
291 &dl->pptr_args); in xchk_dirpath_revalidate()
292 if (error == -ENOATTR) { in xchk_dirpath_revalidate()
293 trace_xchk_dirpath_disappeared(dl->sc, sc->ip, path->path_nr, in xchk_dirpath_revalidate()
294 path->first_step, &dl->xname, &dl->pptr_rec); in xchk_dirpath_revalidate()
295 dl->stale = true; in xchk_dirpath_revalidate()
296 return -ESTALE; in xchk_dirpath_revalidate()
304 * the parent that we find in @dl->xname/pptr_rec.
324 error = xfs_parent_from_attr(sc->mp, attr_flags, name, namelen, value, in xchk_dirpath_find_next_step()
330 * If we've already set @dl->pptr_rec, then this directory has multiple in xchk_dirpath_find_next_step()
331 * parents. Signal this back to the caller via -EMLINK. in xchk_dirpath_find_next_step()
333 if (dl->parents_found > 0) in xchk_dirpath_find_next_step()
334 return -EMLINK; in xchk_dirpath_find_next_step()
336 dl->parents_found++; in xchk_dirpath_find_next_step()
337 memcpy(dl->namebuf, name, namelen); in xchk_dirpath_find_next_step()
338 dl->xname.len = namelen; in xchk_dirpath_find_next_step()
339 dl->pptr_rec = *rec; /* struct copy */ in xchk_dirpath_find_next_step()
350 trace_xchk_dirpath_set_outcome(dl->sc, path->path_nr, path->nr_steps, in xchk_dirpath_set_outcome()
353 path->outcome = outcome; in xchk_dirpath_set_outcome()
358 * If we find one, extend the path. Returns -ESTALE if the scan data out of
359 * date. Returns -EFSCORRUPTED if the parent pointer is bad; or -ELNRNG if
367 struct xfs_scrub *sc = dl->sc; in xchk_dirpath_step_up()
369 xfs_ino_t parent_ino = be64_to_cpu(dl->pptr_rec.p_ino); in xchk_dirpath_step_up()
379 mutex_lock(&dl->lock); in xchk_dirpath_step_up()
381 if (dl->stale) { in xchk_dirpath_step_up()
382 error = -ESTALE; in xchk_dirpath_step_up()
387 if (parent_ino == dl->root_ino) { in xchk_dirpath_step_up()
397 if (parent_ino == sc->ip->i_ino) { in xchk_dirpath_step_up()
408 if (xino_bitmap_test(&path->seen_inodes, parent_ino)) { in xchk_dirpath_step_up()
415 if (VFS_I(dp)->i_generation != be32_to_cpu(dl->pptr_rec.p_gen)) { in xchk_dirpath_step_up()
416 trace_xchk_dirpath_badgen(dl->sc, dp, path->path_nr, in xchk_dirpath_step_up()
417 path->nr_steps, &dl->xname, &dl->pptr_rec); in xchk_dirpath_step_up()
418 error = -EFSCORRUPTED; in xchk_dirpath_step_up()
422 /* Parent pointer must point up to a directory. */ in xchk_dirpath_step_up()
423 if (!S_ISDIR(VFS_I(dp)->i_mode)) { in xchk_dirpath_step_up()
424 trace_xchk_dirpath_nondir_parent(dl->sc, dp, path->path_nr, in xchk_dirpath_step_up()
425 path->nr_steps, &dl->xname, &dl->pptr_rec); in xchk_dirpath_step_up()
426 error = -EFSCORRUPTED; in xchk_dirpath_step_up()
431 if (VFS_I(dp)->i_nlink == 0) { in xchk_dirpath_step_up()
432 trace_xchk_dirpath_unlinked_parent(dl->sc, dp, path->path_nr, in xchk_dirpath_step_up()
433 path->nr_steps, &dl->xname, &dl->pptr_rec); in xchk_dirpath_step_up()
434 error = -EFSCORRUPTED; in xchk_dirpath_step_up()
443 error = -EBUSY; in xchk_dirpath_step_up()
450 * to find the next step in our walk. If we find that @dp has exactly in xchk_dirpath_step_up()
452 * @dl->pptr_rec. This prepares us for the next step of the walk. in xchk_dirpath_step_up()
454 mutex_unlock(&dl->lock); in xchk_dirpath_step_up()
455 dl->parents_found = 0; in xchk_dirpath_step_up()
457 mutex_lock(&dl->lock); in xchk_dirpath_step_up()
458 if (error == -EFSCORRUPTED || error == -EMLINK || in xchk_dirpath_step_up()
459 (!error && dl->parents_found == 0)) { in xchk_dirpath_step_up()
461 * Further up the directory tree from @sc->ip, we found a in xchk_dirpath_step_up()
473 if (dl->stale) { in xchk_dirpath_step_up()
474 error = -ESTALE; in xchk_dirpath_step_up()
478 trace_xchk_dirpath_found_next_step(sc, dp, path->path_nr, in xchk_dirpath_step_up()
479 path->nr_steps, &dl->xname, &dl->pptr_rec); in xchk_dirpath_step_up()
482 error = xchk_dirpath_append(dl, dp, path, &dl->xname, &dl->pptr_rec); in xchk_dirpath_step_up()
486 if (path->second_step == XFARRAY_NULLIDX) in xchk_dirpath_step_up()
487 path->second_step = xfarray_length(dl->path_steps) - 1; in xchk_dirpath_step_up()
490 mutex_unlock(&dl->lock); in xchk_dirpath_step_up()
499 * stored in dl->pptr_rec and dl->xname.
501 * Returns -ESTALE if the scan data are out of date. Returns -EFSCORRUPTED
502 * only if the direct parent pointer of @sc->ip associated with this path is
510 struct xfs_scrub *sc = dl->sc; in xchk_dirpath_walk_upwards()
513 ASSERT(sc->ilock_flags & XFS_ILOCK_EXCL); in xchk_dirpath_walk_upwards()
520 trace_xchk_dirpath_walk_upwards(sc, sc->ip, path->path_nr, &dl->xname, in xchk_dirpath_walk_upwards()
521 &dl->pptr_rec); in xchk_dirpath_walk_upwards()
527 if (be64_to_cpu(dl->pptr_rec.p_ino) == sc->ip->i_ino) { in xchk_dirpath_walk_upwards()
536 * Beyond this point we're walking up the directory tree, which means in xchk_dirpath_walk_upwards()
537 * that we can acquire and drop the ILOCK on an alias of sc->ip. The in xchk_dirpath_walk_upwards()
539 * must drop @sc->ip's ILOCK during the walk. in xchk_dirpath_walk_upwards()
541 mutex_unlock(&dl->lock); in xchk_dirpath_walk_upwards()
545 * Take the first step in the walk towards the root by checking the in xchk_dirpath_walk_upwards()
546 * start of this path, which is a direct parent pointer of @sc->ip. in xchk_dirpath_walk_upwards()
548 * pointer of @sc->ip is corrupt. Stop the whole scan. in xchk_dirpath_walk_upwards()
553 mutex_lock(&dl->lock); in xchk_dirpath_walk_upwards()
558 * Take steps upward from the second step in this path towards the in xchk_dirpath_walk_upwards()
562 while (!error && path->outcome == XCHK_DIRPATH_SCANNING) in xchk_dirpath_walk_upwards()
567 mutex_lock(&dl->lock); in xchk_dirpath_walk_upwards()
568 if (error == -EFSCORRUPTED) { in xchk_dirpath_walk_upwards()
572 if (!error && dl->stale) in xchk_dirpath_walk_upwards()
573 return -ESTALE; in xchk_dirpath_walk_upwards()
578 * Decide if this path step has been touched by this live update. Returns
590 struct xchk_dirpath_step step; in xchk_dirpath_step_is_stale() local
594 error = xfarray_load(dl->path_steps, step_idx, &step); in xchk_dirpath_step_is_stale()
597 *cursor = be64_to_cpu(step.pptr_rec.p_ino); in xchk_dirpath_step_is_stale()
601 * this path step, the scan data is still ok. in xchk_dirpath_step_is_stale()
603 if (p->ip->i_ino != child_ino || p->dp->i_ino != *cursor) in xchk_dirpath_step_is_stale()
610 if (p->name->len != step.name_len) in xchk_dirpath_step_is_stale()
613 error = xfblob_loadname(dl->path_names, step.name_cookie, in xchk_dirpath_step_is_stale()
614 &dl->hook_xname, step.name_len); in xchk_dirpath_step_is_stale()
618 if (memcmp(dl->hook_xname.name, p->name->name, p->name->len) != 0) in xchk_dirpath_step_is_stale()
625 if (p->ip->i_ino == dl->scan_ino && in xchk_dirpath_step_is_stale()
626 path->outcome == XREP_DIRPATH_ADOPTING) { in xchk_dirpath_step_is_stale()
631 if (p->ip->i_ino == dl->scan_ino && in xchk_dirpath_step_is_stale()
632 path->outcome == XREP_DIRPATH_DELETING) { in xchk_dirpath_step_is_stale()
638 trace_xchk_dirpath_changed(dl->sc, path->path_nr, step_nr, p->dp, in xchk_dirpath_step_is_stale()
639 p->ip, p->name); in xchk_dirpath_step_is_stale()
653 xfs_ino_t cursor = dl->scan_ino; in xchk_dirpath_is_stale()
654 xfarray_idx_t idx = path->first_step; in xchk_dirpath_is_stale()
662 if (!xino_bitmap_test(&path->seen_inodes, p->ip->i_ino)) in xchk_dirpath_is_stale()
669 for (i = 1, idx = path->second_step; i < path->nr_steps; i++, idx++) { in xchk_dirpath_is_stale()
695 trace_xchk_dirtree_live_update(dl->sc, p->dp, action, p->ip, p->delta, in xchk_dirtree_live_update()
696 p->name); in xchk_dirtree_live_update()
698 mutex_lock(&dl->lock); in xchk_dirtree_live_update()
700 if (dl->stale || dl->aborted) in xchk_dirtree_live_update()
706 dl->aborted = true; in xchk_dirtree_live_update()
710 dl->stale = true; in xchk_dirtree_live_update()
716 mutex_unlock(&dl->lock); in xchk_dirtree_live_update()
728 ASSERT(dl->sc->ilock_flags & XFS_ILOCK_EXCL); in xchk_dirtree_reset()
731 list_del_init(&path->list); in xchk_dirtree_reset()
732 xino_bitmap_destroy(&path->seen_inodes); in xchk_dirtree_reset()
735 dl->nr_paths = 0; in xchk_dirtree_reset()
737 xfarray_truncate(dl->path_steps); in xchk_dirtree_reset()
738 xfblob_truncate(dl->path_names); in xchk_dirtree_reset()
740 dl->stale = false; in xchk_dirtree_reset()
744 * Load the name/pptr from the first step in this path into @dl->pptr_rec and
745 * @dl->xname.
752 struct xchk_dirpath_step step; in xchk_dirtree_load_path() local
755 error = xfarray_load(dl->path_steps, path->first_step, &step); in xchk_dirtree_load_path()
759 error = xfblob_loadname(dl->path_names, step.name_cookie, &dl->xname, in xchk_dirtree_load_path()
760 step.name_len); in xchk_dirtree_load_path()
764 dl->pptr_rec = step.pptr_rec; /* struct copy */ in xchk_dirtree_load_path()
771 * -EFSCORRUPTED if walking the parent pointers of @sc->ip failed, -ELNRNG if a
772 * path was too deep; -ENOSR if there were too many parent pointers; or
779 struct xfs_scrub *sc = dl->sc; in xchk_dirtree_find_paths_to_root()
794 if (xchk_pptr_looks_zapped(sc->ip)) { in xchk_dirtree_find_paths_to_root()
796 return -EBUSY; in xchk_dirtree_find_paths_to_root()
804 error = xchk_xattr_walk(sc, sc->ip, xchk_dirtree_create_path, in xchk_dirtree_find_paths_to_root()
810 /* Load path components into dl->pptr/xname */ in xchk_dirtree_find_paths_to_root()
816 * Try to walk up each path to the root. This enables in xchk_dirtree_find_paths_to_root()
821 if (error == -EFSCORRUPTED) { in xchk_dirtree_find_paths_to_root()
823 * A parent pointer of @sc->ip is bad, don't in xchk_dirtree_find_paths_to_root()
828 if (error == -ESTALE) { in xchk_dirtree_find_paths_to_root()
830 ASSERT(dl->stale); in xchk_dirtree_find_paths_to_root()
835 if (dl->aborted) in xchk_dirtree_find_paths_to_root()
838 } while (dl->stale); in xchk_dirtree_find_paths_to_root()
854 ASSERT(!dl->stale); in xchk_dirtree_evaluate()
859 trace_xchk_dirpath_evaluate_path(dl->sc, path->path_nr, in xchk_dirtree_evaluate()
860 path->nr_steps, path->outcome); in xchk_dirtree_evaluate()
862 switch (path->outcome) { in xchk_dirtree_evaluate()
869 oc->bad++; in xchk_dirtree_evaluate()
874 oc->suspect++; in xchk_dirtree_evaluate()
882 oc->good++; in xchk_dirtree_evaluate()
903 struct xchk_dirtree *dl = sc->buf; in xchk_dirtree()
910 if (!S_ISDIR(VFS_I(sc->ip)->i_mode)) in xchk_dirtree()
911 return -ENOENT; in xchk_dirtree()
913 ASSERT(xfs_has_parent(sc->mp)); in xchk_dirtree()
917 * scan, because the hook doesn't detach until after sc->ip gets in xchk_dirtree()
920 dl->root_ino = sc->mp->m_rootip->i_ino; in xchk_dirtree()
921 dl->scan_ino = sc->ip->i_ino; in xchk_dirtree()
923 trace_xchk_dirtree_start(sc->ip, sc->sm, 0); in xchk_dirtree()
928 * directory's ILOCK, which means that any in-progress directory update in xchk_dirtree()
931 ASSERT(sc->flags & XCHK_FSGATES_DIRENTS); in xchk_dirtree()
932 xfs_dir_hook_setup(&dl->dhook, xchk_dirtree_live_update); in xchk_dirtree()
933 error = xfs_dir_hook_add(sc->mp, &dl->dhook); in xchk_dirtree()
937 mutex_lock(&dl->lock); in xchk_dirtree()
941 if (error == -EFSCORRUPTED || error == -ELNRNG || error == -ENOSR) { in xchk_dirtree()
947 xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino); in xchk_dirtree()
951 if (error == -EBUSY) { in xchk_dirtree()
963 if (dl->aborted) { in xchk_dirtree()
972 xchk_ino_set_corrupt(sc, sc->ip->i_ino); in xchk_dirtree()
975 xchk_ino_set_corrupt(sc, sc->ip->i_ino); in xchk_dirtree()
977 xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino); in xchk_dirtree()
981 mutex_unlock(&dl->lock); in xchk_dirtree()
983 trace_xchk_dirtree_done(sc->ip, sc->sm, error); in xchk_dirtree()