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
368 struct xfs_scrub *sc = dl->sc; in xchk_dirpath_step_up()
370 xfs_ino_t parent_ino = be64_to_cpu(dl->pptr_rec.p_ino); in xchk_dirpath_step_up()
380 mutex_lock(&dl->lock); in xchk_dirpath_step_up()
382 if (dl->stale) { in xchk_dirpath_step_up()
383 error = -ESTALE; in xchk_dirpath_step_up()
388 if (parent_ino == dl->root_ino) { in xchk_dirpath_step_up()
398 if (parent_ino == sc->ip->i_ino) { in xchk_dirpath_step_up()
409 if (xino_bitmap_test(&path->seen_inodes, parent_ino)) { in xchk_dirpath_step_up()
416 if (VFS_I(dp)->i_generation != be32_to_cpu(dl->pptr_rec.p_gen)) { in xchk_dirpath_step_up()
417 trace_xchk_dirpath_badgen(dl->sc, dp, path->path_nr, in xchk_dirpath_step_up()
418 path->nr_steps, &dl->xname, &dl->pptr_rec); in xchk_dirpath_step_up()
419 error = -EFSCORRUPTED; in xchk_dirpath_step_up()
423 /* Parent pointer must point up to a directory. */ in xchk_dirpath_step_up()
424 if (!S_ISDIR(VFS_I(dp)->i_mode)) { in xchk_dirpath_step_up()
425 trace_xchk_dirpath_nondir_parent(dl->sc, dp, path->path_nr, in xchk_dirpath_step_up()
426 path->nr_steps, &dl->xname, &dl->pptr_rec); in xchk_dirpath_step_up()
427 error = -EFSCORRUPTED; in xchk_dirpath_step_up()
432 if (VFS_I(dp)->i_nlink == 0) { in xchk_dirpath_step_up()
433 trace_xchk_dirpath_unlinked_parent(dl->sc, dp, path->path_nr, in xchk_dirpath_step_up()
434 path->nr_steps, &dl->xname, &dl->pptr_rec); in xchk_dirpath_step_up()
435 error = -EFSCORRUPTED; in xchk_dirpath_step_up()
441 trace_xchk_dirpath_crosses_tree(dl->sc, dp, path->path_nr, in xchk_dirpath_step_up()
442 path->nr_steps, &dl->xname, &dl->pptr_rec); in xchk_dirpath_step_up()
443 error = -EFSCORRUPTED; in xchk_dirpath_step_up()
452 error = -EBUSY; in xchk_dirpath_step_up()
459 * to find the next step in our walk. If we find that @dp has exactly in xchk_dirpath_step_up()
461 * @dl->pptr_rec. This prepares us for the next step of the walk. in xchk_dirpath_step_up()
463 mutex_unlock(&dl->lock); in xchk_dirpath_step_up()
464 dl->parents_found = 0; in xchk_dirpath_step_up()
466 mutex_lock(&dl->lock); in xchk_dirpath_step_up()
467 if (error == -EFSCORRUPTED || error == -EMLINK || in xchk_dirpath_step_up()
468 (!error && dl->parents_found == 0)) { in xchk_dirpath_step_up()
470 * Further up the directory tree from @sc->ip, we found a in xchk_dirpath_step_up()
482 if (dl->stale) { in xchk_dirpath_step_up()
483 error = -ESTALE; in xchk_dirpath_step_up()
487 trace_xchk_dirpath_found_next_step(sc, dp, path->path_nr, in xchk_dirpath_step_up()
488 path->nr_steps, &dl->xname, &dl->pptr_rec); in xchk_dirpath_step_up()
491 error = xchk_dirpath_append(dl, dp, path, &dl->xname, &dl->pptr_rec); in xchk_dirpath_step_up()
495 if (path->second_step == XFARRAY_NULLIDX) in xchk_dirpath_step_up()
496 path->second_step = xfarray_length(dl->path_steps) - 1; in xchk_dirpath_step_up()
499 mutex_unlock(&dl->lock); in xchk_dirpath_step_up()
508 * stored in dl->pptr_rec and dl->xname.
510 * Returns -ESTALE if the scan data are out of date. Returns -EFSCORRUPTED
511 * only if the direct parent pointer of @sc->ip associated with this path is
519 struct xfs_scrub *sc = dl->sc; in xchk_dirpath_walk_upwards()
523 ASSERT(sc->ilock_flags & XFS_ILOCK_EXCL); in xchk_dirpath_walk_upwards()
530 trace_xchk_dirpath_walk_upwards(sc, sc->ip, path->path_nr, &dl->xname, in xchk_dirpath_walk_upwards()
531 &dl->pptr_rec); in xchk_dirpath_walk_upwards()
537 if (be64_to_cpu(dl->pptr_rec.p_ino) == sc->ip->i_ino) { in xchk_dirpath_walk_upwards()
546 * Beyond this point we're walking up the directory tree, which means in xchk_dirpath_walk_upwards()
547 * that we can acquire and drop the ILOCK on an alias of sc->ip. The in xchk_dirpath_walk_upwards()
549 * must drop @sc->ip's ILOCK during the walk. in xchk_dirpath_walk_upwards()
551 is_metadir = xfs_is_metadir_inode(sc->ip); in xchk_dirpath_walk_upwards()
552 mutex_unlock(&dl->lock); in xchk_dirpath_walk_upwards()
556 * Take the first step in the walk towards the root by checking the in xchk_dirpath_walk_upwards()
557 * start of this path, which is a direct parent pointer of @sc->ip. in xchk_dirpath_walk_upwards()
559 * pointer of @sc->ip is corrupt. Stop the whole scan. in xchk_dirpath_walk_upwards()
564 mutex_lock(&dl->lock); in xchk_dirpath_walk_upwards()
569 * Take steps upward from the second step in this path towards the in xchk_dirpath_walk_upwards()
573 while (!error && path->outcome == XCHK_DIRPATH_SCANNING) in xchk_dirpath_walk_upwards()
578 mutex_lock(&dl->lock); in xchk_dirpath_walk_upwards()
579 if (error == -EFSCORRUPTED) { in xchk_dirpath_walk_upwards()
583 if (!error && dl->stale) in xchk_dirpath_walk_upwards()
584 return -ESTALE; in xchk_dirpath_walk_upwards()
589 * Decide if this path step has been touched by this live update. Returns
601 struct xchk_dirpath_step step; in xchk_dirpath_step_is_stale() local
605 error = xfarray_load(dl->path_steps, step_idx, &step); in xchk_dirpath_step_is_stale()
608 *cursor = be64_to_cpu(step.pptr_rec.p_ino); in xchk_dirpath_step_is_stale()
612 * this path step, the scan data is still ok. in xchk_dirpath_step_is_stale()
614 if (p->ip->i_ino != child_ino || p->dp->i_ino != *cursor) in xchk_dirpath_step_is_stale()
621 if (p->name->len != step.name_len) in xchk_dirpath_step_is_stale()
624 error = xfblob_loadname(dl->path_names, step.name_cookie, in xchk_dirpath_step_is_stale()
625 &dl->hook_xname, step.name_len); in xchk_dirpath_step_is_stale()
629 if (memcmp(dl->hook_xname.name, p->name->name, p->name->len) != 0) in xchk_dirpath_step_is_stale()
636 if (p->ip->i_ino == dl->scan_ino && in xchk_dirpath_step_is_stale()
637 path->outcome == XREP_DIRPATH_ADOPTING) { in xchk_dirpath_step_is_stale()
642 if (p->ip->i_ino == dl->scan_ino && in xchk_dirpath_step_is_stale()
643 path->outcome == XREP_DIRPATH_DELETING) { in xchk_dirpath_step_is_stale()
649 trace_xchk_dirpath_changed(dl->sc, path->path_nr, step_nr, p->dp, in xchk_dirpath_step_is_stale()
650 p->ip, p->name); in xchk_dirpath_step_is_stale()
664 xfs_ino_t cursor = dl->scan_ino; in xchk_dirpath_is_stale()
665 xfarray_idx_t idx = path->first_step; in xchk_dirpath_is_stale()
673 if (!xino_bitmap_test(&path->seen_inodes, p->ip->i_ino)) in xchk_dirpath_is_stale()
680 for (i = 1, idx = path->second_step; i < path->nr_steps; i++, idx++) { in xchk_dirpath_is_stale()
706 trace_xchk_dirtree_live_update(dl->sc, p->dp, action, p->ip, p->delta, in xchk_dirtree_live_update()
707 p->name); in xchk_dirtree_live_update()
709 mutex_lock(&dl->lock); in xchk_dirtree_live_update()
711 if (dl->stale || dl->aborted) in xchk_dirtree_live_update()
717 dl->aborted = true; in xchk_dirtree_live_update()
721 dl->stale = true; in xchk_dirtree_live_update()
727 mutex_unlock(&dl->lock); in xchk_dirtree_live_update()
739 ASSERT(dl->sc->ilock_flags & XFS_ILOCK_EXCL); in xchk_dirtree_reset()
742 list_del_init(&path->list); in xchk_dirtree_reset()
743 xino_bitmap_destroy(&path->seen_inodes); in xchk_dirtree_reset()
746 dl->nr_paths = 0; in xchk_dirtree_reset()
748 xfarray_truncate(dl->path_steps); in xchk_dirtree_reset()
749 xfblob_truncate(dl->path_names); in xchk_dirtree_reset()
751 dl->stale = false; in xchk_dirtree_reset()
755 * Load the name/pptr from the first step in this path into @dl->pptr_rec and
756 * @dl->xname.
763 struct xchk_dirpath_step step; in xchk_dirtree_load_path() local
766 error = xfarray_load(dl->path_steps, path->first_step, &step); in xchk_dirtree_load_path()
770 error = xfblob_loadname(dl->path_names, step.name_cookie, &dl->xname, in xchk_dirtree_load_path()
771 step.name_len); in xchk_dirtree_load_path()
775 dl->pptr_rec = step.pptr_rec; /* struct copy */ in xchk_dirtree_load_path()
782 * -EFSCORRUPTED if walking the parent pointers of @sc->ip failed, -ELNRNG if a
783 * path was too deep; -ENOSR if there were too many parent pointers; or
790 struct xfs_scrub *sc = dl->sc; in xchk_dirtree_find_paths_to_root()
805 if (xchk_pptr_looks_zapped(sc->ip)) { in xchk_dirtree_find_paths_to_root()
807 return -EBUSY; in xchk_dirtree_find_paths_to_root()
815 error = xchk_xattr_walk(sc, sc->ip, xchk_dirtree_create_path, in xchk_dirtree_find_paths_to_root()
821 /* Load path components into dl->pptr/xname */ in xchk_dirtree_find_paths_to_root()
827 * Try to walk up each path to the root. This enables in xchk_dirtree_find_paths_to_root()
832 if (error == -EFSCORRUPTED) { in xchk_dirtree_find_paths_to_root()
834 * A parent pointer of @sc->ip is bad, don't in xchk_dirtree_find_paths_to_root()
839 if (error == -ESTALE) { in xchk_dirtree_find_paths_to_root()
841 ASSERT(dl->stale); in xchk_dirtree_find_paths_to_root()
846 if (dl->aborted) in xchk_dirtree_find_paths_to_root()
849 } while (dl->stale); in xchk_dirtree_find_paths_to_root()
865 ASSERT(!dl->stale); in xchk_dirtree_evaluate()
870 trace_xchk_dirpath_evaluate_path(dl->sc, path->path_nr, in xchk_dirtree_evaluate()
871 path->nr_steps, path->outcome); in xchk_dirtree_evaluate()
873 switch (path->outcome) { in xchk_dirtree_evaluate()
880 oc->bad++; in xchk_dirtree_evaluate()
885 oc->suspect++; in xchk_dirtree_evaluate()
893 oc->good++; in xchk_dirtree_evaluate()
914 struct xchk_dirtree *dl = sc->buf; in xchk_dirtree()
921 if (!S_ISDIR(VFS_I(sc->ip)->i_mode)) in xchk_dirtree()
922 return -ENOENT; in xchk_dirtree()
924 ASSERT(xfs_has_parent(sc->mp)); in xchk_dirtree()
928 * scan, because the hook doesn't detach until after sc->ip gets in xchk_dirtree()
931 dl->root_ino = xchk_inode_rootdir_inum(sc->ip); in xchk_dirtree()
932 dl->scan_ino = sc->ip->i_ino; in xchk_dirtree()
934 trace_xchk_dirtree_start(sc->ip, sc->sm, 0); in xchk_dirtree()
939 * directory's ILOCK, which means that any in-progress directory update in xchk_dirtree()
942 ASSERT(sc->flags & XCHK_FSGATES_DIRENTS); in xchk_dirtree()
943 xfs_dir_hook_setup(&dl->dhook, xchk_dirtree_live_update); in xchk_dirtree()
944 error = xfs_dir_hook_add(sc->mp, &dl->dhook); in xchk_dirtree()
948 mutex_lock(&dl->lock); in xchk_dirtree()
952 if (error == -EFSCORRUPTED || error == -ELNRNG || error == -ENOSR) { in xchk_dirtree()
958 xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino); in xchk_dirtree()
962 if (error == -EBUSY) { in xchk_dirtree()
974 if (dl->aborted) { in xchk_dirtree()
983 xchk_ino_set_corrupt(sc, sc->ip->i_ino); in xchk_dirtree()
986 xchk_ino_set_corrupt(sc, sc->ip->i_ino); in xchk_dirtree()
988 xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino); in xchk_dirtree()
992 mutex_unlock(&dl->lock); in xchk_dirtree()
994 trace_xchk_dirtree_done(sc->ip, sc->sm, error); in xchk_dirtree()
1002 struct xfs_scrub *sc = dl->sc; in xchk_dirtree_parentless()
1004 if (xchk_inode_is_dirtree_root(sc->ip)) in xchk_dirtree_parentless()
1006 if (VFS_I(sc->ip)->i_nlink == 0) in xchk_dirtree_parentless()