xref: /linux/fs/xfs/scrub/metapath.c (revision b477ff98d903618a1ab8247861f2ea6e70c0f0f8)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
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_mount.h"
12 #include "xfs_log_format.h"
13 #include "xfs_trans.h"
14 #include "xfs_inode.h"
15 #include "xfs_metafile.h"
16 #include "xfs_quota.h"
17 #include "xfs_qm.h"
18 #include "xfs_dir2.h"
19 #include "xfs_parent.h"
20 #include "xfs_bmap_btree.h"
21 #include "xfs_trans_space.h"
22 #include "xfs_attr.h"
23 #include "xfs_rtgroup.h"
24 #include "xfs_rtrmap_btree.h"
25 #include "xfs_rtrefcount_btree.h"
26 #include "scrub/scrub.h"
27 #include "scrub/common.h"
28 #include "scrub/trace.h"
29 #include "scrub/readdir.h"
30 #include "scrub/repair.h"
31 
32 /*
33  * Metadata Directory Tree Paths
34  * =============================
35  *
36  * A filesystem with metadir enabled expects to find metadata structures
37  * attached to files that are accessible by walking a path down the metadata
38  * directory tree.  Given the metadir path and the incore inode storing the
39  * metadata, this scrubber ensures that the ondisk metadir path points to the
40  * ondisk inode represented by the incore inode.
41  */
42 
43 struct xchk_metapath {
44 	struct xfs_scrub		*sc;
45 
46 	/* Name for lookup */
47 	struct xfs_name			xname;
48 
49 	/* Directory update for repairs */
50 	struct xfs_dir_update		du;
51 
52 	/* Path down to this metadata file from the parent directory */
53 	const char			*path;
54 
55 	/* Directory parent of the metadata file. */
56 	struct xfs_inode		*dp;
57 
58 	/* Locks held on dp */
59 	unsigned int			dp_ilock_flags;
60 
61 	/* Transaction block reservations */
62 	unsigned int			link_resblks;
63 	unsigned int			unlink_resblks;
64 
65 	/* Parent pointer updates */
66 	struct xfs_parent_args		link_ppargs;
67 	struct xfs_parent_args		unlink_ppargs;
68 
69 	/* Scratchpads for removing links */
70 	struct xfs_da_args		pptr_args;
71 };
72 
73 /* Release resources tracked in the buffer. */
74 static inline void
xchk_metapath_cleanup(void * buf)75 xchk_metapath_cleanup(
76 	void			*buf)
77 {
78 	struct xchk_metapath	*mpath = buf;
79 
80 	if (mpath->dp_ilock_flags)
81 		xfs_iunlock(mpath->dp, mpath->dp_ilock_flags);
82 	kfree(mpath->path);
83 }
84 
85 /* Set up a metadir path scan.  @path must be dynamically allocated. */
86 static inline int
xchk_setup_metapath_scan(struct xfs_scrub * sc,struct xfs_inode * dp,const char * path,struct xfs_inode * ip)87 xchk_setup_metapath_scan(
88 	struct xfs_scrub	*sc,
89 	struct xfs_inode	*dp,
90 	const char		*path,
91 	struct xfs_inode	*ip)
92 {
93 	struct xchk_metapath	*mpath;
94 	int			error;
95 
96 	if (!path)
97 		return -ENOMEM;
98 
99 	error = xchk_install_live_inode(sc, ip);
100 	if (error) {
101 		kfree(path);
102 		return error;
103 	}
104 
105 	mpath = kzalloc(sizeof(struct xchk_metapath), XCHK_GFP_FLAGS);
106 	if (!mpath) {
107 		kfree(path);
108 		return -ENOMEM;
109 	}
110 
111 	mpath->sc = sc;
112 	sc->buf = mpath;
113 	sc->buf_cleanup = xchk_metapath_cleanup;
114 
115 	mpath->dp = dp;
116 	mpath->path = path; /* path is now owned by mpath */
117 
118 	mpath->xname.name = mpath->path;
119 	mpath->xname.len = strlen(mpath->path);
120 	mpath->xname.type = xfs_mode_to_ftype(VFS_I(ip)->i_mode);
121 
122 	return 0;
123 }
124 
125 #ifdef CONFIG_XFS_RT
126 /* Scan the /rtgroups directory itself. */
127 static int
xchk_setup_metapath_rtdir(struct xfs_scrub * sc)128 xchk_setup_metapath_rtdir(
129 	struct xfs_scrub	*sc)
130 {
131 	if (!sc->mp->m_rtdirip)
132 		return -ENOENT;
133 
134 	return xchk_setup_metapath_scan(sc, sc->mp->m_metadirip,
135 			kasprintf(GFP_KERNEL, "rtgroups"), sc->mp->m_rtdirip);
136 }
137 
138 /* Scan a rtgroup inode under the /rtgroups directory. */
139 static int
xchk_setup_metapath_rtginode(struct xfs_scrub * sc,enum xfs_rtg_inodes type)140 xchk_setup_metapath_rtginode(
141 	struct xfs_scrub	*sc,
142 	enum xfs_rtg_inodes	type)
143 {
144 	struct xfs_rtgroup	*rtg;
145 	struct xfs_inode	*ip;
146 	int			error;
147 
148 	rtg = xfs_rtgroup_get(sc->mp, sc->sm->sm_agno);
149 	if (!rtg)
150 		return -ENOENT;
151 
152 	ip = rtg->rtg_inodes[type];
153 	if (!ip) {
154 		error = -ENOENT;
155 		goto out_put_rtg;
156 	}
157 
158 	error = xchk_setup_metapath_scan(sc, sc->mp->m_rtdirip,
159 			xfs_rtginode_path(rtg_rgno(rtg), type), ip);
160 
161 out_put_rtg:
162 	xfs_rtgroup_put(rtg);
163 	return error;
164 }
165 #else
166 # define xchk_setup_metapath_rtdir(...)		(-ENOENT)
167 # define xchk_setup_metapath_rtginode(...)	(-ENOENT)
168 #endif /* CONFIG_XFS_RT */
169 
170 #ifdef CONFIG_XFS_QUOTA
171 /* Scan the /quota directory itself. */
172 static int
xchk_setup_metapath_quotadir(struct xfs_scrub * sc)173 xchk_setup_metapath_quotadir(
174 	struct xfs_scrub	*sc)
175 {
176 	struct xfs_quotainfo	*qi = sc->mp->m_quotainfo;
177 
178 	if (!qi || !qi->qi_dirip)
179 		return -ENOENT;
180 
181 	return xchk_setup_metapath_scan(sc, sc->mp->m_metadirip,
182 			kstrdup("quota", GFP_KERNEL), qi->qi_dirip);
183 }
184 
185 /* Scan a quota inode under the /quota directory. */
186 static int
xchk_setup_metapath_dqinode(struct xfs_scrub * sc,xfs_dqtype_t type)187 xchk_setup_metapath_dqinode(
188 	struct xfs_scrub	*sc,
189 	xfs_dqtype_t		type)
190 {
191 	struct xfs_quotainfo	*qi = sc->mp->m_quotainfo;
192 	struct xfs_inode	*ip = NULL;
193 
194 	if (!qi)
195 		return -ENOENT;
196 
197 	switch (type) {
198 	case XFS_DQTYPE_USER:
199 		ip = qi->qi_uquotaip;
200 		break;
201 	case XFS_DQTYPE_GROUP:
202 		ip = qi->qi_gquotaip;
203 		break;
204 	case XFS_DQTYPE_PROJ:
205 		ip = qi->qi_pquotaip;
206 		break;
207 	default:
208 		ASSERT(0);
209 		return -EINVAL;
210 	}
211 	if (!ip)
212 		return -ENOENT;
213 
214 	return xchk_setup_metapath_scan(sc, qi->qi_dirip,
215 			kstrdup(xfs_dqinode_path(type), GFP_KERNEL), ip);
216 }
217 #else
218 # define xchk_setup_metapath_quotadir(...)	(-ENOENT)
219 # define xchk_setup_metapath_dqinode(...)	(-ENOENT)
220 #endif /* CONFIG_XFS_QUOTA */
221 
222 int
xchk_setup_metapath(struct xfs_scrub * sc)223 xchk_setup_metapath(
224 	struct xfs_scrub	*sc)
225 {
226 	if (!xfs_has_metadir(sc->mp))
227 		return -ENOENT;
228 	if (sc->sm->sm_gen)
229 		return -EINVAL;
230 
231 	switch (sc->sm->sm_ino) {
232 	case XFS_SCRUB_METAPATH_PROBE:
233 		/* Just probing, nothing else to do. */
234 		if (sc->sm->sm_agno)
235 			return -EINVAL;
236 		return 0;
237 	case XFS_SCRUB_METAPATH_RTDIR:
238 		return xchk_setup_metapath_rtdir(sc);
239 	case XFS_SCRUB_METAPATH_RTBITMAP:
240 		return xchk_setup_metapath_rtginode(sc, XFS_RTGI_BITMAP);
241 	case XFS_SCRUB_METAPATH_RTSUMMARY:
242 		return xchk_setup_metapath_rtginode(sc, XFS_RTGI_SUMMARY);
243 	case XFS_SCRUB_METAPATH_QUOTADIR:
244 		return xchk_setup_metapath_quotadir(sc);
245 	case XFS_SCRUB_METAPATH_USRQUOTA:
246 		return xchk_setup_metapath_dqinode(sc, XFS_DQTYPE_USER);
247 	case XFS_SCRUB_METAPATH_GRPQUOTA:
248 		return xchk_setup_metapath_dqinode(sc, XFS_DQTYPE_GROUP);
249 	case XFS_SCRUB_METAPATH_PRJQUOTA:
250 		return xchk_setup_metapath_dqinode(sc, XFS_DQTYPE_PROJ);
251 	case XFS_SCRUB_METAPATH_RTRMAPBT:
252 		return xchk_setup_metapath_rtginode(sc, XFS_RTGI_RMAP);
253 	case XFS_SCRUB_METAPATH_RTREFCOUNTBT:
254 		return xchk_setup_metapath_rtginode(sc, XFS_RTGI_REFCOUNT);
255 	default:
256 		return -ENOENT;
257 	}
258 }
259 
260 /*
261  * Take the ILOCK on the metadata directory parent and child.  We do not know
262  * that the metadata directory is not corrupt, so we lock the parent and try
263  * to lock the child.  Returns 0 if successful, or -EINTR to abort the scrub.
264  */
265 STATIC int
xchk_metapath_ilock_both(struct xchk_metapath * mpath)266 xchk_metapath_ilock_both(
267 	struct xchk_metapath	*mpath)
268 {
269 	struct xfs_scrub	*sc = mpath->sc;
270 	int			error = 0;
271 
272 	while (true) {
273 		xfs_ilock(mpath->dp, XFS_ILOCK_EXCL);
274 		if (xchk_ilock_nowait(sc, XFS_ILOCK_EXCL)) {
275 			mpath->dp_ilock_flags |= XFS_ILOCK_EXCL;
276 			return 0;
277 		}
278 		xfs_iunlock(mpath->dp, XFS_ILOCK_EXCL);
279 
280 		if (xchk_should_terminate(sc, &error))
281 			return error;
282 
283 		delay(1);
284 	}
285 
286 	ASSERT(0);
287 	return -EINTR;
288 }
289 
290 /* Unlock parent and child inodes. */
291 static inline void
xchk_metapath_iunlock(struct xchk_metapath * mpath)292 xchk_metapath_iunlock(
293 	struct xchk_metapath	*mpath)
294 {
295 	struct xfs_scrub	*sc = mpath->sc;
296 
297 	xchk_iunlock(sc, XFS_ILOCK_EXCL);
298 
299 	mpath->dp_ilock_flags &= ~XFS_ILOCK_EXCL;
300 	xfs_iunlock(mpath->dp, XFS_ILOCK_EXCL);
301 }
302 
303 int
xchk_metapath(struct xfs_scrub * sc)304 xchk_metapath(
305 	struct xfs_scrub	*sc)
306 {
307 	struct xchk_metapath	*mpath = sc->buf;
308 	xfs_ino_t		ino = NULLFSINO;
309 	int			error;
310 
311 	/* Just probing, nothing else to do. */
312 	if (sc->sm->sm_ino == XFS_SCRUB_METAPATH_PROBE)
313 		return 0;
314 
315 	/* Parent required to do anything else. */
316 	if (mpath->dp == NULL) {
317 		xchk_ino_set_corrupt(sc, sc->ip->i_ino);
318 		return 0;
319 	}
320 
321 	error = xchk_trans_alloc_empty(sc);
322 	if (error)
323 		return error;
324 
325 	error = xchk_metapath_ilock_both(mpath);
326 	if (error)
327 		goto out_cancel;
328 
329 	/* Make sure the parent dir has a dirent pointing to this file. */
330 	error = xchk_dir_lookup(sc, mpath->dp, &mpath->xname, &ino);
331 	trace_xchk_metapath_lookup(sc, mpath->path, mpath->dp, ino);
332 	if (error == -ENOENT) {
333 		/* No directory entry at all */
334 		xchk_ino_set_corrupt(sc, sc->ip->i_ino);
335 		error = 0;
336 		goto out_ilock;
337 	}
338 	if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error))
339 		goto out_ilock;
340 	if (ino != sc->ip->i_ino) {
341 		/* Pointing to wrong inode */
342 		xchk_ino_set_corrupt(sc, sc->ip->i_ino);
343 	}
344 
345 out_ilock:
346 	xchk_metapath_iunlock(mpath);
347 out_cancel:
348 	xchk_trans_cancel(sc);
349 	return error;
350 }
351 
352 #ifdef CONFIG_XFS_ONLINE_REPAIR
353 /* Create the dirent represented by the final component of the path. */
354 STATIC int
xrep_metapath_link(struct xchk_metapath * mpath)355 xrep_metapath_link(
356 	struct xchk_metapath	*mpath)
357 {
358 	struct xfs_scrub	*sc = mpath->sc;
359 
360 	mpath->du.dp = mpath->dp;
361 	mpath->du.name = &mpath->xname;
362 	mpath->du.ip = sc->ip;
363 
364 	if (xfs_has_parent(sc->mp))
365 		mpath->du.ppargs = &mpath->link_ppargs;
366 	else
367 		mpath->du.ppargs = NULL;
368 
369 	trace_xrep_metapath_link(sc, mpath->path, mpath->dp, sc->ip->i_ino);
370 
371 	return xfs_dir_add_child(sc->tp, mpath->link_resblks, &mpath->du);
372 }
373 
374 /* Remove the dirent at the final component of the path. */
375 STATIC int
xrep_metapath_unlink(struct xchk_metapath * mpath,xfs_ino_t ino,struct xfs_inode * ip)376 xrep_metapath_unlink(
377 	struct xchk_metapath	*mpath,
378 	xfs_ino_t		ino,
379 	struct xfs_inode	*ip)
380 {
381 	struct xfs_parent_rec	rec;
382 	struct xfs_scrub	*sc = mpath->sc;
383 	struct xfs_mount	*mp = sc->mp;
384 	int			error;
385 
386 	trace_xrep_metapath_unlink(sc, mpath->path, mpath->dp, ino);
387 
388 	if (!ip) {
389 		/* The child inode isn't allocated.  Junk the dirent. */
390 		xfs_trans_log_inode(sc->tp, mpath->dp, XFS_ILOG_CORE);
391 		return xfs_dir_removename(sc->tp, mpath->dp, &mpath->xname,
392 				ino, mpath->unlink_resblks);
393 	}
394 
395 	mpath->du.dp = mpath->dp;
396 	mpath->du.name = &mpath->xname;
397 	mpath->du.ip = ip;
398 	mpath->du.ppargs = NULL;
399 
400 	/* Figure out if we're removing a parent pointer too. */
401 	if (xfs_has_parent(mp)) {
402 		xfs_inode_to_parent_rec(&rec, ip);
403 		error = xfs_parent_lookup(sc->tp, ip, &mpath->xname, &rec,
404 				&mpath->pptr_args);
405 		switch (error) {
406 		case -ENOATTR:
407 			break;
408 		case 0:
409 			mpath->du.ppargs = &mpath->unlink_ppargs;
410 			break;
411 		default:
412 			return error;
413 		}
414 	}
415 
416 	return xfs_dir_remove_child(sc->tp, mpath->unlink_resblks, &mpath->du);
417 }
418 
419 /*
420  * Try to create a dirent in @mpath->dp with the name @mpath->xname that points
421  * to @sc->ip.  Returns:
422  *
423  * -EEXIST and an @alleged_child if the dirent that points to the wrong inode;
424  * 0 if there is now a dirent pointing to @sc->ip; or
425  * A negative errno on error.
426  */
427 STATIC int
xrep_metapath_try_link(struct xchk_metapath * mpath,xfs_ino_t * alleged_child)428 xrep_metapath_try_link(
429 	struct xchk_metapath	*mpath,
430 	xfs_ino_t		*alleged_child)
431 {
432 	struct xfs_scrub	*sc = mpath->sc;
433 	xfs_ino_t		ino;
434 	int			error;
435 
436 	/* Allocate transaction, lock inodes, join to transaction. */
437 	error = xchk_trans_alloc(sc, mpath->link_resblks);
438 	if (error)
439 		return error;
440 
441 	error = xchk_metapath_ilock_both(mpath);
442 	if (error) {
443 		xchk_trans_cancel(sc);
444 		return error;
445 	}
446 	xfs_trans_ijoin(sc->tp, mpath->dp, 0);
447 	xfs_trans_ijoin(sc->tp, sc->ip, 0);
448 
449 	error = xchk_dir_lookup(sc, mpath->dp, &mpath->xname, &ino);
450 	trace_xrep_metapath_lookup(sc, mpath->path, mpath->dp, ino);
451 	if (error == -ENOENT) {
452 		/*
453 		 * There is no dirent in the directory.  Create an entry
454 		 * pointing to @sc->ip.
455 		 */
456 		error = xrep_metapath_link(mpath);
457 		if (error)
458 			goto out_cancel;
459 
460 		error = xrep_trans_commit(sc);
461 		xchk_metapath_iunlock(mpath);
462 		return error;
463 	}
464 	if (error)
465 		goto out_cancel;
466 
467 	if (ino == sc->ip->i_ino) {
468 		/* The dirent already points to @sc->ip; we're done. */
469 		error = 0;
470 		goto out_cancel;
471 	}
472 
473 	/*
474 	 * The dirent points elsewhere; pass that back so that the caller
475 	 * can try to remove the dirent.
476 	 */
477 	*alleged_child = ino;
478 	error = -EEXIST;
479 
480 out_cancel:
481 	xchk_trans_cancel(sc);
482 	xchk_metapath_iunlock(mpath);
483 	return error;
484 }
485 
486 /*
487  * Take the ILOCK on the metadata directory parent and a bad child, if one is
488  * supplied.  We do not know that the metadata directory is not corrupt, so we
489  * lock the parent and try to lock the child.  Returns 0 if successful, or
490  * -EINTR to abort the repair.  The lock state of @dp is not recorded in @mpath.
491  */
492 STATIC int
xchk_metapath_ilock_parent_and_child(struct xchk_metapath * mpath,struct xfs_inode * ip)493 xchk_metapath_ilock_parent_and_child(
494 	struct xchk_metapath	*mpath,
495 	struct xfs_inode	*ip)
496 {
497 	struct xfs_scrub	*sc = mpath->sc;
498 	int			error = 0;
499 
500 	while (true) {
501 		xfs_ilock(mpath->dp, XFS_ILOCK_EXCL);
502 		if (!ip || xfs_ilock_nowait(ip, XFS_ILOCK_EXCL))
503 			return 0;
504 		xfs_iunlock(mpath->dp, XFS_ILOCK_EXCL);
505 
506 		if (xchk_should_terminate(sc, &error))
507 			return error;
508 
509 		delay(1);
510 	}
511 
512 	ASSERT(0);
513 	return -EINTR;
514 }
515 
516 /*
517  * Try to remove a dirent in @mpath->dp with the name @mpath->xname that points
518  * to @alleged_child.  Returns:
519  *
520  * 0 if there is no longer a dirent;
521  * -EEXIST if the dirent points to @sc->ip;
522  * -EAGAIN and an updated @alleged_child if the dirent points elsewhere; or
523  * A negative errno for any other error.
524  */
525 STATIC int
xrep_metapath_try_unlink(struct xchk_metapath * mpath,xfs_ino_t * alleged_child)526 xrep_metapath_try_unlink(
527 	struct xchk_metapath	*mpath,
528 	xfs_ino_t		*alleged_child)
529 {
530 	struct xfs_scrub	*sc = mpath->sc;
531 	struct xfs_inode	*ip = NULL;
532 	xfs_ino_t		ino;
533 	int			error;
534 
535 	ASSERT(*alleged_child != sc->ip->i_ino);
536 
537 	trace_xrep_metapath_try_unlink(sc, mpath->path, mpath->dp,
538 			*alleged_child);
539 
540 	/*
541 	 * Allocate transaction, grab the alleged child inode, lock inodes,
542 	 * join to transaction.
543 	 */
544 	error = xchk_trans_alloc(sc, mpath->unlink_resblks);
545 	if (error)
546 		return error;
547 
548 	error = xchk_iget(sc, *alleged_child, &ip);
549 	if (error == -EINVAL || error == -ENOENT) {
550 		/* inode number is bogus, junk the dirent */
551 		error = 0;
552 	}
553 	if (error) {
554 		xchk_trans_cancel(sc);
555 		return error;
556 	}
557 
558 	error = xchk_metapath_ilock_parent_and_child(mpath, ip);
559 	if (error) {
560 		xchk_trans_cancel(sc);
561 		return error;
562 	}
563 	xfs_trans_ijoin(sc->tp, mpath->dp, 0);
564 	if (ip)
565 		xfs_trans_ijoin(sc->tp, ip, 0);
566 
567 	error = xchk_dir_lookup(sc, mpath->dp, &mpath->xname, &ino);
568 	trace_xrep_metapath_lookup(sc, mpath->path, mpath->dp, ino);
569 	if (error == -ENOENT) {
570 		/*
571 		 * There is no dirent in the directory anymore.  We're ready to
572 		 * try the link operation again.
573 		 */
574 		error = 0;
575 		goto out_cancel;
576 	}
577 	if (error)
578 		goto out_cancel;
579 
580 	if (ino == sc->ip->i_ino) {
581 		/* The dirent already points to @sc->ip; we're done. */
582 		error = -EEXIST;
583 		goto out_cancel;
584 	}
585 
586 	/*
587 	 * The dirent does not point to the alleged child.  Update the caller
588 	 * and signal that we want to be called again.
589 	 */
590 	if (ino != *alleged_child) {
591 		*alleged_child = ino;
592 		error = -EAGAIN;
593 		goto out_cancel;
594 	}
595 
596 	/* Remove the link to the child. */
597 	error = xrep_metapath_unlink(mpath, ino, ip);
598 	if (error)
599 		goto out_cancel;
600 
601 	error = xrep_trans_commit(sc);
602 	goto out_unlock;
603 
604 out_cancel:
605 	xchk_trans_cancel(sc);
606 out_unlock:
607 	xfs_iunlock(mpath->dp, XFS_ILOCK_EXCL);
608 	if (ip) {
609 		xfs_iunlock(ip, XFS_ILOCK_EXCL);
610 		xchk_irele(sc, ip);
611 	}
612 	return error;
613 }
614 
615 /*
616  * Make sure the metadata directory path points to the child being examined.
617  *
618  * Repair needs to be able to create a directory structure, create its own
619  * transactions, and take ILOCKs.  This function /must/ be called after all
620  * other repairs have completed.
621  */
622 int
xrep_metapath(struct xfs_scrub * sc)623 xrep_metapath(
624 	struct xfs_scrub	*sc)
625 {
626 	struct xchk_metapath	*mpath = sc->buf;
627 	struct xfs_mount	*mp = sc->mp;
628 	int			error = 0;
629 
630 	/* Just probing, nothing to repair. */
631 	if (sc->sm->sm_ino == XFS_SCRUB_METAPATH_PROBE)
632 		return 0;
633 
634 	/* Parent required to do anything else. */
635 	if (mpath->dp == NULL)
636 		return -EFSCORRUPTED;
637 
638 	/*
639 	 * Make sure the child file actually has an attr fork to receive a new
640 	 * parent pointer if the fs has parent pointers.
641 	 */
642 	if (xfs_has_parent(mp)) {
643 		error = xfs_attr_add_fork(sc->ip,
644 				sizeof(struct xfs_attr_sf_hdr), 1);
645 		if (error)
646 			return error;
647 	}
648 
649 	/* Compute block reservation required to unlink and link a file. */
650 	mpath->unlink_resblks = xfs_remove_space_res(mp, MAXNAMELEN);
651 	mpath->link_resblks = xfs_link_space_res(mp, MAXNAMELEN);
652 
653 	do {
654 		xfs_ino_t	alleged_child;
655 
656 		/* Re-establish the link, or tell us which inode to remove. */
657 		error = xrep_metapath_try_link(mpath, &alleged_child);
658 		if (!error)
659 			return 0;
660 		if (error != -EEXIST)
661 			return error;
662 
663 		/*
664 		 * Remove an incorrect link to an alleged child, or tell us
665 		 * which inode to remove.
666 		 */
667 		do {
668 			error = xrep_metapath_try_unlink(mpath, &alleged_child);
669 		} while (error == -EAGAIN);
670 		if (error == -EEXIST) {
671 			/* Link established; we're done. */
672 			error = 0;
673 			break;
674 		}
675 	} while (!error);
676 
677 	return error;
678 }
679 #endif /* CONFIG_XFS_ONLINE_REPAIR */
680