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