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