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