brintos

brintos / linux-shallow public Read only

0
0
Text · 18.9 KiB · 5c04e70 Raw
822 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (c) 2023-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_trans_space.h"12#include "xfs_mount.h"13#include "xfs_log_format.h"14#include "xfs_trans.h"15#include "xfs_inode.h"16#include "xfs_icache.h"17#include "xfs_dir2.h"18#include "xfs_dir2_priv.h"19#include "xfs_attr.h"20#include "xfs_parent.h"21#include "scrub/scrub.h"22#include "scrub/common.h"23#include "scrub/bitmap.h"24#include "scrub/ino_bitmap.h"25#include "scrub/xfile.h"26#include "scrub/xfarray.h"27#include "scrub/xfblob.h"28#include "scrub/listxattr.h"29#include "scrub/trace.h"30#include "scrub/repair.h"31#include "scrub/orphanage.h"32#include "scrub/dirtree.h"33#include "scrub/readdir.h"34 35/*36 * Directory Tree Structure Repairs37 * ================================38 *39 * If we decide that the directory being scanned is participating in a40 * directory loop, the only change we can make is to remove directory entries41 * pointing down to @sc->ip.  If that leaves it with no parents, the directory42 * should be adopted by the orphanage.43 */44 45/* Set up to repair directory loops. */46int47xrep_setup_dirtree(48	struct xfs_scrub	*sc)49{50	return xrep_orphanage_try_create(sc);51}52 53/* Change the outcome of this path. */54static inline void55xrep_dirpath_set_outcome(56	struct xchk_dirtree		*dl,57	struct xchk_dirpath		*path,58	enum xchk_dirpath_outcome	outcome)59{60	trace_xrep_dirpath_set_outcome(dl->sc, path->path_nr, path->nr_steps,61			outcome);62 63	path->outcome = outcome;64}65 66/* Delete all paths. */67STATIC void68xrep_dirtree_delete_all_paths(69	struct xchk_dirtree		*dl,70	struct xchk_dirtree_outcomes	*oc)71{72	struct xchk_dirpath		*path;73 74	xchk_dirtree_for_each_path(dl, path) {75		switch (path->outcome) {76		case XCHK_DIRPATH_CORRUPT:77		case XCHK_DIRPATH_LOOP:78			oc->suspect--;79			oc->bad++;80			xrep_dirpath_set_outcome(dl, path, XCHK_DIRPATH_DELETE);81			break;82		case XCHK_DIRPATH_OK:83			oc->good--;84			oc->bad++;85			xrep_dirpath_set_outcome(dl, path, XCHK_DIRPATH_DELETE);86			break;87		default:88			break;89		}90	}91 92	ASSERT(oc->suspect == 0);93	ASSERT(oc->good == 0);94}95 96/* Since this is the surviving path, set the dotdot entry to this value. */97STATIC void98xrep_dirpath_retain_parent(99	struct xchk_dirtree		*dl,100	struct xchk_dirpath		*path)101{102	struct xchk_dirpath_step	step;103	int				error;104 105	error = xfarray_load(dl->path_steps, path->first_step, &step);106	if (error)107		return;108 109	dl->parent_ino = be64_to_cpu(step.pptr_rec.p_ino);110}111 112/* Find the one surviving path so we know how to set dotdot. */113STATIC void114xrep_dirtree_find_surviving_path(115	struct xchk_dirtree		*dl,116	struct xchk_dirtree_outcomes	*oc)117{118	struct xchk_dirpath		*path;119	bool				foundit = false;120 121	xchk_dirtree_for_each_path(dl, path) {122		switch (path->outcome) {123		case XCHK_DIRPATH_CORRUPT:124		case XCHK_DIRPATH_LOOP:125		case XCHK_DIRPATH_OK:126			if (!foundit) {127				xrep_dirpath_retain_parent(dl, path);128				foundit = true;129				continue;130			}131			ASSERT(foundit == false);132			break;133		default:134			break;135		}136	}137 138	ASSERT(oc->suspect + oc->good == 1);139}140 141/* Delete all paths except for the one good one. */142STATIC void143xrep_dirtree_keep_one_good_path(144	struct xchk_dirtree		*dl,145	struct xchk_dirtree_outcomes	*oc)146{147	struct xchk_dirpath		*path;148	bool				foundit = false;149 150	xchk_dirtree_for_each_path(dl, path) {151		switch (path->outcome) {152		case XCHK_DIRPATH_CORRUPT:153		case XCHK_DIRPATH_LOOP:154			oc->suspect--;155			oc->bad++;156			xrep_dirpath_set_outcome(dl, path, XCHK_DIRPATH_DELETE);157			break;158		case XCHK_DIRPATH_OK:159			if (!foundit) {160				xrep_dirpath_retain_parent(dl, path);161				foundit = true;162				continue;163			}164			oc->good--;165			oc->bad++;166			xrep_dirpath_set_outcome(dl, path, XCHK_DIRPATH_DELETE);167			break;168		default:169			break;170		}171	}172 173	ASSERT(oc->suspect == 0);174	ASSERT(oc->good < 2);175}176 177/* Delete all paths except for one suspect one. */178STATIC void179xrep_dirtree_keep_one_suspect_path(180	struct xchk_dirtree		*dl,181	struct xchk_dirtree_outcomes	*oc)182{183	struct xchk_dirpath		*path;184	bool				foundit = false;185 186	xchk_dirtree_for_each_path(dl, path) {187		switch (path->outcome) {188		case XCHK_DIRPATH_CORRUPT:189		case XCHK_DIRPATH_LOOP:190			if (!foundit) {191				xrep_dirpath_retain_parent(dl, path);192				foundit = true;193				continue;194			}195			oc->suspect--;196			oc->bad++;197			xrep_dirpath_set_outcome(dl, path, XCHK_DIRPATH_DELETE);198			break;199		case XCHK_DIRPATH_OK:200			ASSERT(0);201			break;202		default:203			break;204		}205	}206 207	ASSERT(oc->suspect == 1);208	ASSERT(oc->good == 0);209}210 211/*212 * Figure out what to do with the paths we tried to find.  Returns -EDEADLOCK213 * if the scan results have become stale.214 */215STATIC void216xrep_dirtree_decide_fate(217	struct xchk_dirtree		*dl,218	struct xchk_dirtree_outcomes	*oc)219{220	xchk_dirtree_evaluate(dl, oc);221 222	/* Parentless directories should not have any paths at all. */223	if (xchk_dirtree_parentless(dl)) {224		xrep_dirtree_delete_all_paths(dl, oc);225		return;226	}227 228	/* One path is exactly the number of paths we want. */229	if (oc->good + oc->suspect == 1) {230		xrep_dirtree_find_surviving_path(dl, oc);231		return;232	}233 234	/* Zero paths means we should reattach the subdir to the orphanage. */235	if (oc->good + oc->suspect == 0) {236		if (dl->sc->orphanage)237			oc->needs_adoption = true;238		return;239	}240 241	/*242	 * Otherwise, this subdirectory has too many parents.  If there's at243	 * least one good path, keep it and delete the others.244	 */245	if (oc->good > 0) {246		xrep_dirtree_keep_one_good_path(dl, oc);247		return;248	}249 250	/*251	 * There are no good paths and there are too many suspect paths.252	 * Keep the first suspect path and delete the rest.253	 */254	xrep_dirtree_keep_one_suspect_path(dl, oc);255}256 257/*258 * Load the first step of this path into @step and @dl->xname/pptr259 * for later repair work.260 */261STATIC int262xrep_dirtree_prep_path(263	struct xchk_dirtree		*dl,264	struct xchk_dirpath		*path,265	struct xchk_dirpath_step	*step)266{267	int				error;268 269	error = xfarray_load(dl->path_steps, path->first_step, step);270	if (error)271		return error;272 273	error = xfblob_loadname(dl->path_names, step->name_cookie, &dl->xname,274			step->name_len);275	if (error)276		return error;277 278	dl->pptr_rec = step->pptr_rec; /* struct copy */279	return 0;280}281 282/* Delete the VFS dentry for a removed child. */283STATIC int284xrep_dirtree_purge_dentry(285	struct xchk_dirtree	*dl,286	struct xfs_inode	*dp,287	const struct xfs_name	*name)288{289	struct qstr		qname = QSTR_INIT(name->name, name->len);290	struct dentry		*parent_dentry, *child_dentry;291	int			error = 0;292 293	/*294	 * Find the dentry for the parent directory.  If there isn't one, we're295	 * done.  Caller already holds i_rwsem for parent and child.296	 */297	parent_dentry = d_find_alias(VFS_I(dp));298	if (!parent_dentry)299		return 0;300 301	/* The VFS thinks the parent is a directory, right? */302	if (!d_is_dir(parent_dentry)) {303		ASSERT(d_is_dir(parent_dentry));304		error = -EFSCORRUPTED;305		goto out_dput_parent;306	}307 308	/*309	 * Try to find the dirent pointing to the child.  If there isn't one,310	 * we're done.311	 */312	qname.hash = full_name_hash(parent_dentry, name->name, name->len);313	child_dentry = d_lookup(parent_dentry, &qname);314	if (!child_dentry) {315		error = 0;316		goto out_dput_parent;317	}318 319	trace_xrep_dirtree_delete_child(dp->i_mount, child_dentry);320 321	/* Child is not a directory?  We're screwed. */322	if (!d_is_dir(child_dentry)) {323		ASSERT(d_is_dir(child_dentry));324		error = -EFSCORRUPTED;325		goto out_dput_child;326	}327 328	/* Replace the child dentry with a negative one. */329	d_delete(child_dentry);330 331out_dput_child:332	dput(child_dentry);333out_dput_parent:334	dput(parent_dentry);335	return error;336}337 338/*339 * Prepare to delete a link by taking the IOLOCK of the parent and the child340 * (scrub target).  Caller must hold IOLOCK_EXCL on @sc->ip.  Returns 0 if we341 * took both locks, or a negative errno if we couldn't lock the parent in time.342 */343static inline int344xrep_dirtree_unlink_iolock(345	struct xfs_scrub	*sc,346	struct xfs_inode	*dp)347{348	int			error;349 350	ASSERT(sc->ilock_flags & XFS_IOLOCK_EXCL);351 352	if (xfs_ilock_nowait(dp, XFS_IOLOCK_EXCL))353		return 0;354 355	xchk_iunlock(sc, XFS_IOLOCK_EXCL);356	do {357		xfs_ilock(dp, XFS_IOLOCK_EXCL);358		if (xchk_ilock_nowait(sc, XFS_IOLOCK_EXCL))359			break;360		xfs_iunlock(dp, XFS_IOLOCK_EXCL);361 362		if (xchk_should_terminate(sc, &error)) {363			xchk_ilock(sc, XFS_IOLOCK_EXCL);364			return error;365		}366 367		delay(1);368	} while (1);369 370	return 0;371}372 373/*374 * Remove a link from the directory tree and update the dcache.  Returns375 * -ESTALE if the scan data are now out of date.376 */377STATIC int378xrep_dirtree_unlink(379	struct xchk_dirtree		*dl,380	struct xfs_inode		*dp,381	struct xchk_dirpath		*path,382	struct xchk_dirpath_step	*step)383{384	struct xfs_scrub		*sc = dl->sc;385	struct xfs_mount		*mp = sc->mp;386	xfs_ino_t			dotdot_ino;387	xfs_ino_t			parent_ino = dl->parent_ino;388	unsigned int			resblks;389	int				dontcare;390	int				error;391 392	/* Take IOLOCK_EXCL of the parent and child. */393	error = xrep_dirtree_unlink_iolock(sc, dp);394	if (error)395		return error;396 397	/*398	 * Create the transaction that we need to sever the path.  Ignore399	 * EDQUOT and ENOSPC being returned via nospace_error because the400	 * directory code can handle a reservationless update.401	 */402	resblks = xfs_remove_space_res(mp, step->name_len);403	error = xfs_trans_alloc_dir(dp, &M_RES(mp)->tr_remove, sc->ip,404			&resblks, &sc->tp, &dontcare);405	if (error)406		goto out_iolock;407 408	/*409	 * Cancel if someone invalidate the paths while we were trying to get410	 * the ILOCK.411	 */412	mutex_lock(&dl->lock);413	if (dl->stale) {414		mutex_unlock(&dl->lock);415		error = -ESTALE;416		goto out_trans_cancel;417	}418	xrep_dirpath_set_outcome(dl, path, XREP_DIRPATH_DELETING);419	mutex_unlock(&dl->lock);420 421	trace_xrep_dirtree_delete_path(dl->sc, sc->ip, path->path_nr,422			&dl->xname, &dl->pptr_rec);423 424	/*425	 * Decide if we need to reset the dotdot entry.  Rules:426	 *427	 * - If there's a surviving parent, we want dotdot to point there.428	 * - If we don't have any surviving parents, then point dotdot at the429	 *   root dir.430	 * - If dotdot is already set to the value we want, pass in NULLFSINO431	 *   for no change necessary.432	 *433	 * Do this /before/ we dirty anything, in case the dotdot lookup434	 * fails.435	 */436	error = xchk_dir_lookup(sc, sc->ip, &xfs_name_dotdot, &dotdot_ino);437	if (error)438		goto out_trans_cancel;439	if (parent_ino == NULLFSINO)440		parent_ino = dl->root_ino;441	if (dotdot_ino == parent_ino)442		parent_ino = NULLFSINO;443 444	/* Drop the link from sc->ip's dotdot entry.  */445	error = xfs_droplink(sc->tp, dp);446	if (error)447		goto out_trans_cancel;448 449	/* Reset the dotdot entry to a surviving parent. */450	if (parent_ino != NULLFSINO) {451		error = xfs_dir_replace(sc->tp, sc->ip, &xfs_name_dotdot,452				parent_ino, 0);453		if (error)454			goto out_trans_cancel;455	}456 457	/* Drop the link from dp to sc->ip. */458	error = xfs_droplink(sc->tp, sc->ip);459	if (error)460		goto out_trans_cancel;461 462	error = xfs_dir_removename(sc->tp, dp, &dl->xname, sc->ip->i_ino,463			resblks);464	if (error) {465		ASSERT(error != -ENOENT);466		goto out_trans_cancel;467	}468 469	if (xfs_has_parent(sc->mp)) {470		error = xfs_parent_removename(sc->tp, &dl->ppargs, dp,471				&dl->xname, sc->ip);472		if (error)473			goto out_trans_cancel;474	}475 476	/*477	 * Notify dirent hooks that we removed the bad link, invalidate the478	 * dcache, and commit the repair.479	 */480	xfs_dir_update_hook(dp, sc->ip, -1, &dl->xname);481	error = xrep_dirtree_purge_dentry(dl, dp, &dl->xname);482	if (error)483		goto out_trans_cancel;484 485	error = xrep_trans_commit(sc);486	goto out_ilock;487 488out_trans_cancel:489	xchk_trans_cancel(sc);490out_ilock:491	xfs_iunlock(sc->ip, XFS_ILOCK_EXCL);492	xfs_iunlock(dp, XFS_ILOCK_EXCL);493out_iolock:494	xfs_iunlock(dp, XFS_IOLOCK_EXCL);495	return error;496}497 498/*499 * Delete a directory entry that points to this directory.  Returns -ESTALE500 * if the scan data are now out of date.501 */502STATIC int503xrep_dirtree_delete_path(504	struct xchk_dirtree		*dl,505	struct xchk_dirpath		*path)506{507	struct xchk_dirpath_step	step;508	struct xfs_scrub		*sc = dl->sc;509	struct xfs_inode		*dp;510	int				error;511 512	/*513	 * Load the parent pointer and directory inode for this path, then514	 * drop the scan lock, the ILOCK, and the transaction so that515	 * _delete_path can reserve the proper transaction.  This sets up516	 * @dl->xname for the deletion.517	 */518	error = xrep_dirtree_prep_path(dl, path, &step);519	if (error)520		return error;521 522	error = xchk_iget(sc, be64_to_cpu(step.pptr_rec.p_ino), &dp);523	if (error)524		return error;525 526	mutex_unlock(&dl->lock);527	xchk_trans_cancel(sc);528	xchk_iunlock(sc, XFS_ILOCK_EXCL);529 530	/* Delete the directory link and release the parent. */531	error = xrep_dirtree_unlink(dl, dp, path, &step);532	xchk_irele(sc, dp);533 534	/*535	 * Retake all the resources we had at the beginning even if the repair536	 * failed or the scan data are now stale.  This keeps things simple for537	 * the caller.538	 */539	xchk_trans_alloc_empty(sc);540	xchk_ilock(sc, XFS_ILOCK_EXCL);541	mutex_lock(&dl->lock);542 543	if (!error && dl->stale)544		error = -ESTALE;545	return error;546}547 548/* Add a new path to represent our in-progress adoption. */549STATIC int550xrep_dirtree_create_adoption_path(551	struct xchk_dirtree		*dl)552{553	struct xfs_scrub		*sc = dl->sc;554	struct xchk_dirpath		*path;555	int				error;556 557	/*558	 * We should have capped the number of paths at XFS_MAXLINK-1 in the559	 * scanner.560	 */561	if (dl->nr_paths > XFS_MAXLINK) {562		ASSERT(dl->nr_paths <= XFS_MAXLINK);563		return -EFSCORRUPTED;564	}565 566	/*567	 * Create a new xchk_path structure to remember this parent pointer568	 * and record the first name step.569	 */570	path = kmalloc(sizeof(struct xchk_dirpath), XCHK_GFP_FLAGS);571	if (!path)572		return -ENOMEM;573 574	INIT_LIST_HEAD(&path->list);575	xino_bitmap_init(&path->seen_inodes);576	path->nr_steps = 0;577	path->outcome = XREP_DIRPATH_ADOPTING;578 579	/*580	 * Record the new link that we just created in the orphanage.  Because581	 * adoption is the last repair that we perform, we don't bother filling582	 * in the path all the way back to the root.583	 */584	xfs_inode_to_parent_rec(&dl->pptr_rec, sc->orphanage);585 586	error = xino_bitmap_set(&path->seen_inodes, sc->orphanage->i_ino);587	if (error)588		goto out_path;589 590	trace_xrep_dirtree_create_adoption(sc, sc->ip, dl->nr_paths,591			&dl->xname, &dl->pptr_rec);592 593	error = xchk_dirpath_append(dl, sc->ip, path, &dl->xname,594			&dl->pptr_rec);595	if (error)596		goto out_path;597 598	path->first_step = xfarray_length(dl->path_steps) - 1;599	path->second_step = XFARRAY_NULLIDX;600	path->path_nr = dl->nr_paths;601 602	list_add_tail(&path->list, &dl->path_list);603	dl->nr_paths++;604	return 0;605 606out_path:607	kfree(path);608	return error;609}610 611/*612 * Prepare to move a file to the orphanage by taking the IOLOCK of the613 * orphanage and the child (scrub target).  Caller must hold IOLOCK_EXCL on614 * @sc->ip.  Returns 0 if we took both locks, or a negative errno if we615 * couldn't lock the orphanage in time.616 */617static inline int618xrep_dirtree_adopt_iolock(619	struct xfs_scrub	*sc)620{621	int			error;622 623	ASSERT(sc->ilock_flags & XFS_IOLOCK_EXCL);624 625	if (xrep_orphanage_ilock_nowait(sc, XFS_IOLOCK_EXCL))626		return 0;627 628	xchk_iunlock(sc, XFS_IOLOCK_EXCL);629	do {630		xrep_orphanage_ilock(sc, XFS_IOLOCK_EXCL);631		if (xchk_ilock_nowait(sc, XFS_IOLOCK_EXCL))632			break;633		xrep_orphanage_iunlock(sc, XFS_IOLOCK_EXCL);634 635		if (xchk_should_terminate(sc, &error)) {636			xchk_ilock(sc, XFS_IOLOCK_EXCL);637			return error;638		}639 640		delay(1);641	} while (1);642 643	return 0;644}645 646/*647 * Reattach this orphaned directory to the orphanage.  Do not call this with648 * any resources held.  Returns -ESTALE if the scan data have become out of649 * date.650 */651STATIC int652xrep_dirtree_adopt(653	struct xchk_dirtree		*dl)654{655	struct xfs_scrub		*sc = dl->sc;656	int				error;657 658	/* Take the IOLOCK of the orphanage and the scrub target. */659	error = xrep_dirtree_adopt_iolock(sc);660	if (error)661		return error;662 663	/*664	 * Set up for an adoption.  The directory tree fixer runs after the665	 * link counts have been corrected.  Therefore, we must bump the666	 * child's link count since there will be no further opportunity to fix667	 * errors.668	 */669	error = xrep_adoption_trans_alloc(sc, &dl->adoption);670	if (error)671		goto out_iolock;672	dl->adoption.bump_child_nlink = true;673 674	/* Figure out what name we're going to use here. */675	error = xrep_adoption_compute_name(&dl->adoption, &dl->xname);676	if (error)677		goto out_trans;678 679	/*680	 * Now that we have a proposed name for the orphanage entry, create681	 * a faux path so that the live update hook will see it.682	 */683	mutex_lock(&dl->lock);684	if (dl->stale) {685		mutex_unlock(&dl->lock);686		error = -ESTALE;687		goto out_trans;688	}689	error = xrep_dirtree_create_adoption_path(dl);690	mutex_unlock(&dl->lock);691	if (error)692		goto out_trans;693 694	/* Reparent the directory. */695	error = xrep_adoption_move(&dl->adoption);696	if (error)697		goto out_trans;698 699	/*700	 * Commit the name and release all inode locks except for the scrub701	 * target's IOLOCK.702	 */703	error = xrep_trans_commit(sc);704	goto out_ilock;705 706out_trans:707	xchk_trans_cancel(sc);708out_ilock:709	xchk_iunlock(sc, XFS_ILOCK_EXCL);710	xrep_orphanage_iunlock(sc, XFS_ILOCK_EXCL);711out_iolock:712	xrep_orphanage_iunlock(sc, XFS_IOLOCK_EXCL);713	return error;714}715 716/*717 * This newly orphaned directory needs to be adopted by the orphanage.718 * Make this happen.719 */720STATIC int721xrep_dirtree_move_to_orphanage(722	struct xchk_dirtree		*dl)723{724	struct xfs_scrub		*sc = dl->sc;725	int				error;726 727	/*728	 * Start by dropping all the resources that we hold so that we can grab729	 * all the resources that we need for the adoption.730	 */731	mutex_unlock(&dl->lock);732	xchk_trans_cancel(sc);733	xchk_iunlock(sc, XFS_ILOCK_EXCL);734 735	/* Perform the adoption. */736	error = xrep_dirtree_adopt(dl);737 738	/*739	 * Retake all the resources we had at the beginning even if the repair740	 * failed or the scan data are now stale.  This keeps things simple for741	 * the caller.742	 */743	xchk_trans_alloc_empty(sc);744	xchk_ilock(sc, XFS_ILOCK_EXCL);745	mutex_lock(&dl->lock);746 747	if (!error && dl->stale)748		error = -ESTALE;749	return error;750}751 752/*753 * Try to fix all the problems.  Returns -ESTALE if the scan data have become754 * out of date.755 */756STATIC int757xrep_dirtree_fix_problems(758	struct xchk_dirtree		*dl,759	struct xchk_dirtree_outcomes	*oc)760{761	struct xchk_dirpath		*path;762	int				error;763 764	/* Delete all the paths we don't want. */765	xchk_dirtree_for_each_path(dl, path) {766		if (path->outcome != XCHK_DIRPATH_DELETE)767			continue;768 769		error = xrep_dirtree_delete_path(dl, path);770		if (error)771			return error;772	}773 774	/* Reparent this directory to the orphanage. */775	if (oc->needs_adoption) {776		if (xrep_orphanage_can_adopt(dl->sc))777			return xrep_dirtree_move_to_orphanage(dl);778		return -EFSCORRUPTED;779	}780 781	return 0;782}783 784/* Fix directory loops involving this directory. */785int786xrep_dirtree(787	struct xfs_scrub		*sc)788{789	struct xchk_dirtree		*dl = sc->buf;790	struct xchk_dirtree_outcomes	oc;791	int				error;792 793	/*794	 * Prepare to fix the directory tree by retaking the scan lock.  The795	 * order of resource acquisition is still IOLOCK -> transaction ->796	 * ILOCK -> scan lock.797	 */798	mutex_lock(&dl->lock);799	do {800		/*801		 * Decide what we're going to do, then do it.  An -ESTALE802		 * return here means the scan results are invalid and we have803		 * to walk again.804		 */805		if (!dl->stale) {806			xrep_dirtree_decide_fate(dl, &oc);807 808			trace_xrep_dirtree_decided_fate(dl, &oc);809 810			error = xrep_dirtree_fix_problems(dl, &oc);811			if (!error || error != -ESTALE)812				break;813		}814		error = xchk_dirtree_find_paths_to_root(dl);815		if (error == -ELNRNG || error == -ENOSR)816			error = -EFSCORRUPTED;817	} while (!error);818	mutex_unlock(&dl->lock);819 820	return error;821}822