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