Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-or-later
2 : /*
3 : * Copyright (C) 2023 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_trans_space.h"
12 : #include "xfs_mount.h"
13 : #include "xfs_log_format.h"
14 : #include "xfs_trans.h"
15 : #include "xfs_inode.h"
16 : #include "xfs_icache.h"
17 : #include "xfs_dir2.h"
18 : #include "xfs_dir2_priv.h"
19 : #include "xfs_attr.h"
20 : #include "xfs_parent.h"
21 : #include "scrub/scrub.h"
22 : #include "scrub/common.h"
23 : #include "scrub/bitmap.h"
24 : #include "scrub/xfile.h"
25 : #include "scrub/xfarray.h"
26 : #include "scrub/xfblob.h"
27 : #include "scrub/listxattr.h"
28 : #include "scrub/trace.h"
29 : #include "scrub/repair.h"
30 : #include "scrub/orphanage.h"
31 : #include "scrub/dirtree.h"
32 : #include "scrub/readdir.h"
33 :
34 : /*
35 : * Directory Tree Structure Repairs
36 : * ================================
37 : *
38 : * If we decide that the directory being scanned is participating in a
39 : * directory loop, the only change we can make is to remove directory entries
40 : * pointing down to @sc->ip. If that leaves it with no parents, the directory
41 : * should be adopted by the orphanage.
42 : */
43 :
44 : /* Set up to repair directory loops. */
45 : int
46 530364 : xrep_setup_dirtree(
47 : struct xfs_scrub *sc)
48 : {
49 530364 : return xrep_orphanage_try_create(sc);
50 : }
51 :
52 : /* Change the outcome of this path. */
53 : static inline void
54 : xrep_dirpath_set_outcome(
55 : struct xchk_dirtree *dl,
56 : struct xchk_dirpath *path,
57 : enum xchk_dirpath_outcome outcome)
58 : {
59 0 : trace_xrep_dirpath_set_outcome(dl->sc, path->path_nr, path->nr_steps,
60 : outcome);
61 :
62 0 : path->outcome = outcome;
63 0 : }
64 :
65 : /* Delete all paths. */
66 : STATIC void
67 3593 : xrep_dirtree_delete_all_paths(
68 : struct xchk_dirtree *dl,
69 : struct xchk_dirtree_outcomes *oc)
70 : {
71 3593 : struct xchk_dirpath *path;
72 :
73 3593 : xchk_dirtree_for_each_path(dl, path) {
74 0 : switch (path->outcome) {
75 0 : case XCHK_DIRPATH_CORRUPT:
76 : case XCHK_DIRPATH_LOOP:
77 0 : oc->suspect--;
78 0 : oc->bad++;
79 0 : xrep_dirpath_set_outcome(dl, path, XCHK_DIRPATH_DELETE);
80 : break;
81 0 : case XCHK_DIRPATH_OK:
82 0 : oc->good--;
83 0 : oc->bad++;
84 0 : xrep_dirpath_set_outcome(dl, path, XCHK_DIRPATH_DELETE);
85 : break;
86 : default:
87 : break;
88 : }
89 : }
90 :
91 3593 : ASSERT(oc->suspect == 0);
92 3593 : ASSERT(oc->good == 0);
93 3593 : }
94 :
95 : /* Since this is the surviving path, set the dotdot entry to this value. */
96 : STATIC void
97 523417 : xrep_dirpath_retain_parent(
98 : struct xchk_dirtree *dl,
99 : struct xchk_dirpath *path)
100 : {
101 523417 : struct xchk_dirpath_step step;
102 523417 : int error;
103 :
104 523417 : error = xfarray_load(dl->path_steps, path->first_step, &step);
105 526219 : if (error)
106 0 : return;
107 :
108 526219 : dl->parent_ino = step.parent_ino;
109 : }
110 :
111 : /* Find the one surviving path so we know how to set dotdot. */
112 : STATIC void
113 523470 : xrep_dirtree_find_surviving_path(
114 : struct xchk_dirtree *dl,
115 : struct xchk_dirtree_outcomes *oc)
116 : {
117 523470 : struct xchk_dirpath *path;
118 523470 : bool foundit = false;
119 :
120 1049476 : xchk_dirtree_for_each_path(dl, path) {
121 521585 : switch (path->outcome) {
122 521888 : case XCHK_DIRPATH_CORRUPT:
123 : case XCHK_DIRPATH_LOOP:
124 : case XCHK_DIRPATH_OK:
125 521888 : if (!foundit) {
126 521888 : xrep_dirpath_retain_parent(dl, path);
127 526309 : foundit = true;
128 526309 : continue;
129 : }
130 0 : ASSERT(foundit == false);
131 : break;
132 : default:
133 : break;
134 : }
135 : }
136 :
137 527891 : ASSERT(oc->suspect + oc->good == 1);
138 527891 : }
139 :
140 : /* Delete all paths except for the one good one. */
141 : STATIC void
142 0 : xrep_dirtree_keep_one_good_path(
143 : struct xchk_dirtree *dl,
144 : struct xchk_dirtree_outcomes *oc)
145 : {
146 0 : struct xchk_dirpath *path;
147 0 : bool foundit = false;
148 :
149 0 : xchk_dirtree_for_each_path(dl, path) {
150 0 : switch (path->outcome) {
151 0 : case XCHK_DIRPATH_CORRUPT:
152 : case XCHK_DIRPATH_LOOP:
153 0 : oc->suspect--;
154 0 : oc->bad++;
155 0 : xrep_dirpath_set_outcome(dl, path, XCHK_DIRPATH_DELETE);
156 : break;
157 0 : case XCHK_DIRPATH_OK:
158 0 : if (!foundit) {
159 0 : xrep_dirpath_retain_parent(dl, path);
160 0 : foundit = true;
161 0 : continue;
162 : }
163 0 : oc->good--;
164 0 : oc->bad++;
165 0 : xrep_dirpath_set_outcome(dl, path, XCHK_DIRPATH_DELETE);
166 : break;
167 : default:
168 : break;
169 : }
170 : }
171 :
172 0 : ASSERT(oc->suspect == 0);
173 0 : ASSERT(oc->good < 2);
174 0 : }
175 :
176 : /* Delete all paths except for one suspect one. */
177 : STATIC void
178 0 : xrep_dirtree_keep_one_suspect_path(
179 : struct xchk_dirtree *dl,
180 : struct xchk_dirtree_outcomes *oc)
181 : {
182 0 : struct xchk_dirpath *path;
183 0 : bool foundit = false;
184 :
185 0 : xchk_dirtree_for_each_path(dl, path) {
186 0 : switch (path->outcome) {
187 0 : case XCHK_DIRPATH_CORRUPT:
188 : case XCHK_DIRPATH_LOOP:
189 0 : if (!foundit) {
190 0 : xrep_dirpath_retain_parent(dl, path);
191 0 : foundit = true;
192 0 : continue;
193 : }
194 0 : oc->suspect--;
195 0 : oc->bad++;
196 0 : xrep_dirpath_set_outcome(dl, path, XCHK_DIRPATH_DELETE);
197 : break;
198 0 : case XCHK_DIRPATH_OK:
199 0 : ASSERT(0);
200 0 : break;
201 : default:
202 : break;
203 : }
204 : }
205 :
206 0 : ASSERT(oc->suspect == 1);
207 0 : ASSERT(oc->good == 0);
208 0 : }
209 :
210 : /*
211 : * Figure out what to do with the paths we tried to find. Returns -EDEADLOCK
212 : * if the scan results have become stale.
213 : */
214 : STATIC void
215 527886 : xrep_dirtree_decide_fate(
216 : struct xchk_dirtree *dl,
217 : struct xchk_dirtree_outcomes *oc)
218 : {
219 527886 : xchk_dirtree_evaluate(dl, oc);
220 :
221 : /* Parentless directories should not have any paths at all. */
222 527340 : if (xchk_dirtree_parentless(dl)) {
223 3593 : xrep_dirtree_delete_all_paths(dl, oc);
224 3593 : return;
225 : }
226 :
227 : /* One path is exactly the number of paths we want. */
228 523747 : if (oc->good + oc->suspect == 1) {
229 523747 : xrep_dirtree_find_surviving_path(dl, oc);
230 523747 : return;
231 : }
232 :
233 : /* Zero paths means we should reattach the subdir to the orphanage. */
234 0 : if (oc->good + oc->suspect == 0) {
235 0 : if (dl->sc->orphanage)
236 0 : oc->needs_adoption = true;
237 0 : return;
238 : }
239 :
240 : /*
241 : * Otherwise, this subdirectory has too many parents. If there's at
242 : * least one good path, keep it and delete the others.
243 : */
244 0 : if (oc->good > 0) {
245 0 : xrep_dirtree_keep_one_good_path(dl, oc);
246 0 : return;
247 : }
248 :
249 : /*
250 : * There are no good paths and there are too many suspect paths.
251 : * Keep the first suspect path and delete the rest.
252 : */
253 0 : xrep_dirtree_keep_one_suspect_path(dl, oc);
254 : }
255 :
256 : /*
257 : * Load the first step of this path into @step and @dl->pptr
258 : * for later repair work.
259 : */
260 : STATIC int
261 0 : xrep_dirtree_prep_path(
262 : struct xchk_dirtree *dl,
263 : struct xchk_dirpath *path,
264 : struct xchk_dirpath_step *step)
265 : {
266 0 : int error;
267 :
268 0 : error = xfarray_load(dl->path_steps, path->first_step, step);
269 0 : if (error)
270 : return error;
271 :
272 0 : dl->pptr.p_ino = step->parent_ino;
273 0 : dl->pptr.p_gen = step->parent_gen;
274 0 : dl->pptr.p_namelen = step->name_len;
275 :
276 0 : return xfblob_load(dl->path_names, step->name_cookie, dl->pptr.p_name,
277 : step->name_len);
278 : }
279 :
280 : static inline int
281 0 : xrep_dirtree_was_stale(
282 : struct xchk_dirtree *dl)
283 : {
284 0 : int error = 0;
285 :
286 0 : mutex_lock(&dl->lock);
287 0 : if (dl->stale)
288 0 : error = -ESTALE;
289 0 : mutex_unlock(&dl->lock);
290 0 : return error;
291 : }
292 :
293 : /* Delete the VFS dentry for a removed child. */
294 : STATIC int
295 0 : xrep_dirtree_purge_dentry(
296 : struct xchk_dirtree *dl,
297 : struct xfs_inode *dp,
298 : const struct xfs_name *name)
299 : {
300 0 : struct qstr qname = QSTR_INIT(name->name, name->len);
301 0 : struct dentry *parent_dentry, *child_dentry;
302 0 : int error;
303 :
304 : /*
305 : * Find the dentry for the parent directory. If there isn't one, we're
306 : * done. Caller already holds i_rwsem for parent and child.
307 : */
308 0 : parent_dentry = d_find_alias(VFS_I(dp));
309 0 : if (!parent_dentry)
310 : return 0;
311 :
312 : /* The VFS thinks the parent is a directory, right? */
313 0 : if (!d_is_dir(parent_dentry)) {
314 0 : ASSERT(d_is_dir(parent_dentry));
315 0 : error = -EFSCORRUPTED;
316 0 : goto out_dput_parent;
317 : }
318 :
319 : /*
320 : * Try to find the dirent pointing to the child. If there isn't one,
321 : * we're done.
322 : */
323 0 : qname.hash = full_name_hash(parent_dentry, name->name, name->len);
324 0 : child_dentry = d_lookup(parent_dentry, &qname);
325 0 : if (!child_dentry) {
326 0 : error = 0;
327 0 : goto out_dput_parent;
328 : }
329 :
330 0 : trace_xrep_dirtree_delete_child(dp->i_mount, child_dentry);
331 :
332 : /* Child is not a directory? We're screwed. */
333 0 : if (!d_is_dir(child_dentry)) {
334 0 : ASSERT(d_is_dir(child_dentry));
335 0 : error = -EFSCORRUPTED;
336 0 : goto out_dput_child;
337 : }
338 :
339 : /* Replace the child dentry with a negative one. */
340 0 : d_delete(child_dentry);
341 :
342 0 : out_dput_child:
343 0 : dput(child_dentry);
344 0 : out_dput_parent:
345 0 : dput(parent_dentry);
346 0 : return error;
347 : }
348 :
349 : /*
350 : * Remove a link from the directory tree and update the dcache. Returns
351 : * -ESTALE if the scan data are now out of date.
352 : */
353 : STATIC int
354 0 : xrep_dirtree_unlink(
355 : struct xchk_dirtree *dl,
356 : struct xfs_inode *dp,
357 : struct xchk_dirpath *path,
358 : struct xchk_dirpath_step *step)
359 : {
360 0 : struct xfs_name name = {
361 0 : .name = dl->pptr.p_name,
362 0 : .len = step->name_len,
363 : };
364 0 : struct xfs_scrub *sc = dl->sc;
365 0 : struct xfs_mount *mp = sc->mp;
366 0 : struct xfs_parent_defer *parent = NULL;
367 0 : xfs_ino_t dotdot_ino;
368 0 : xfs_ino_t parent_ino = dl->parent_ino;
369 0 : unsigned int resblks;
370 0 : int dontcare;
371 0 : int error = 0;
372 :
373 : /*
374 : * Try to take the IOLOCK on the parent before deleting the link.
375 : * We hold IOLOCK_EXCL on @sc->ip.
376 : */
377 0 : while (!xfs_ilock_nowait(dp, XFS_IOLOCK_EXCL)) {
378 0 : xchk_iunlock(sc, XFS_IOLOCK_EXCL);
379 :
380 0 : delay(1);
381 0 : if (xchk_should_terminate(sc, &error))
382 0 : return error;
383 :
384 0 : xchk_ilock(sc, XFS_IOLOCK_EXCL);
385 0 : error = xrep_dirtree_was_stale(dl);
386 0 : if (error)
387 0 : return error;
388 : }
389 :
390 : /* Set up parent pointer operation. */
391 0 : error = xfs_parent_start(mp, &parent);
392 0 : if (error)
393 0 : goto out_iolock;
394 :
395 : /*
396 : * Create the transaction that we need to sever the path. Ignore
397 : * EDQUOT and ENOSPC being returned via nospace_error because the
398 : * directory code can handle a reservationless update.
399 : */
400 0 : resblks = xfs_remove_space_res(mp, step->name_len);
401 0 : error = xfs_trans_alloc_dir(dp, &M_RES(mp)->tr_remove, sc->ip,
402 : &resblks, &sc->tp, &dontcare);
403 0 : if (error)
404 0 : goto out_parent;
405 :
406 : /* Cancel if someone invalidate the paths while we were unlocked */
407 0 : mutex_lock(&dl->lock);
408 0 : if (dl->stale) {
409 0 : mutex_unlock(&dl->lock);
410 0 : error = -ESTALE;
411 0 : goto out_trans_cancel;
412 : }
413 0 : xrep_dirpath_set_outcome(dl, path, XREP_DIRPATH_DELETING);
414 0 : mutex_unlock(&dl->lock);
415 :
416 0 : trace_xrep_dirtree_delete_path(dl->sc, sc->ip, path->path_nr,
417 0 : &dl->pptr);
418 :
419 : /*
420 : * Decide if we need to reset the dotdot entry. Rules:
421 : *
422 : * - If there's a surviving parent, we want dotdot to point there.
423 : * - If we don't have any surviving parents, then point dotdot at the
424 : * root dir.
425 : * - If dotdot is already set to the value we want, pass in NULLFSINO
426 : * for no change necessary.
427 : *
428 : * Do this /before/ we dirty anything, in case the dotdot lookup
429 : * fails.
430 : */
431 0 : error = xchk_dir_lookup(sc, sc->ip, &xfs_name_dotdot, &dotdot_ino);
432 0 : if (error)
433 0 : goto out_trans_cancel;
434 0 : if (parent_ino == NULLFSINO)
435 0 : parent_ino = dl->root_ino;
436 0 : if (dotdot_ino == parent_ino)
437 0 : parent_ino = NULLFSINO;
438 :
439 : /* Drop the link from sc->ip's dotdot entry. */
440 0 : error = xfs_droplink(sc->tp, dp);
441 0 : if (error)
442 : return error;
443 :
444 : /* Reset the dotdot entry to a surviving parent. */
445 0 : if (parent_ino != NULLFSINO) {
446 0 : error = xfs_dir_replace(sc->tp, sc->ip, &xfs_name_dotdot,
447 : parent_ino, 0);
448 0 : if (error)
449 : return error;
450 : }
451 :
452 : /* Drop the link from dp to sc->ip. */
453 0 : error = xfs_droplink(sc->tp, sc->ip);
454 0 : if (error)
455 : return error;
456 :
457 0 : error = xfs_dir_removename(sc->tp, dp, &name, sc->ip->i_ino, resblks);
458 0 : if (error) {
459 0 : ASSERT(error != -ENOENT);
460 0 : return error;
461 : }
462 :
463 0 : if (parent) {
464 0 : error = xfs_parent_remove(sc->tp, parent, dp, &name, sc->ip);
465 0 : if (error)
466 : return error;
467 : }
468 :
469 : /*
470 : * Notify dirent hooks that we removed the bad link, invalidate the
471 : * dcache, and commit the repair.
472 : */
473 0 : xfs_dir_update_hook(dp, sc->ip, -1, &name);
474 0 : error = xrep_dirtree_purge_dentry(dl, dp, &name);
475 0 : if (error)
476 0 : goto out_trans_cancel;
477 :
478 0 : error = xrep_trans_commit(sc);
479 0 : goto out_ilock;
480 :
481 0 : out_trans_cancel:
482 0 : xchk_trans_cancel(sc);
483 0 : out_ilock:
484 0 : xfs_iunlock(sc->ip, XFS_ILOCK_EXCL);
485 0 : xfs_iunlock(dp, XFS_ILOCK_EXCL);
486 0 : out_parent:
487 0 : xfs_parent_finish(mp, parent);
488 0 : out_iolock:
489 0 : xfs_iunlock(dp, XFS_IOLOCK_EXCL);
490 0 : return error;
491 : }
492 :
493 : /*
494 : * Delete a directory entry that points to this directory. Returns -ESTALE
495 : * if the scan data are now out of date.
496 : */
497 : STATIC int
498 0 : xrep_dirtree_delete_path(
499 : struct xchk_dirtree *dl,
500 : struct xchk_dirpath *path)
501 : {
502 0 : struct xchk_dirpath_step step;
503 0 : struct xfs_scrub *sc = dl->sc;
504 0 : struct xfs_inode *dp;
505 0 : int error;
506 :
507 : /*
508 : * Load the parent pointer and directory inode for this path, then
509 : * drop the scan lock, the ILOCK, and the transaction so that
510 : * _delete_path can reserve the proper transaction.
511 : */
512 0 : error = xrep_dirtree_prep_path(dl, path, &step);
513 0 : if (error)
514 : return error;
515 :
516 0 : error = xchk_iget(sc, step.parent_ino, &dp);
517 0 : if (error)
518 : return error;
519 :
520 0 : mutex_unlock(&dl->lock);
521 0 : xchk_trans_cancel(sc);
522 0 : xchk_iunlock(sc, XFS_ILOCK_EXCL);
523 :
524 0 : error = xrep_dirtree_unlink(dl, dp, path, &step);
525 :
526 : /* Retake the resources we had at the start of this function. */
527 0 : xchk_irele(sc, dp);
528 0 : xchk_trans_alloc_empty(sc);
529 0 : xchk_ilock(sc, XFS_ILOCK_EXCL);
530 0 : mutex_lock(&dl->lock);
531 0 : if (!error && dl->stale)
532 0 : return -ESTALE;
533 : return error;
534 : }
535 :
536 : /* Add a new path to represent our in-progress adoption. */
537 : STATIC int
538 0 : xrep_dirtree_create_adoption_path(
539 : struct xchk_dirtree *dl)
540 : {
541 0 : struct xfs_scrub *sc = dl->sc;
542 0 : struct xchk_dirpath *path;
543 0 : int error;
544 :
545 : /*
546 : * We should have capped the number of paths at XFS_MAXLINK-1 in the
547 : * scanner.
548 : */
549 0 : if (dl->nr_paths > XFS_MAXLINK) {
550 0 : ASSERT(dl->nr_paths <= XFS_MAXLINK);
551 0 : return -EFSCORRUPTED;
552 : }
553 :
554 : /*
555 : * Create a new xchk_path structure to remember this parent pointer
556 : * and record the first name step.
557 : */
558 0 : path = kmalloc(sizeof(struct xchk_dirpath), XCHK_GFP_FLAGS);
559 0 : if (!path)
560 : return -ENOMEM;
561 :
562 0 : INIT_LIST_HEAD(&path->list);
563 0 : xino_bitmap_init(&path->seen_inodes);
564 0 : path->nr_steps = 0;
565 0 : path->outcome = XREP_DIRPATH_ADOPTING;
566 :
567 : /*
568 : * Record the new link that we just created in the orphanage. Because
569 : * adoption is the last repair that we perform, we don't bother filling
570 : * in the path all the way back to the root.
571 : */
572 0 : dl->pptr.p_ino = sc->orphanage->i_ino;
573 0 : dl->pptr.p_gen = VFS_I(sc->orphanage)->i_generation;
574 0 : dl->pptr.p_namelen = dl->adoption.xname.len;
575 :
576 0 : error = xino_bitmap_set(&path->seen_inodes, sc->orphanage->i_ino);
577 0 : if (error)
578 0 : goto out_path;
579 :
580 0 : trace_xrep_dirtree_create_adoption(sc, sc->ip, dl->nr_paths, &dl->pptr);
581 :
582 0 : error = xchk_dirpath_append(dl, sc->ip, path, &dl->pptr);
583 0 : if (error)
584 0 : goto out_path;
585 :
586 0 : path->first_step = xfarray_length(dl->path_steps) - 1;
587 0 : path->second_step = XFARRAY_NULLIDX;
588 0 : path->path_nr = dl->nr_paths;
589 :
590 0 : list_add_tail(&path->list, &dl->path_list);
591 0 : dl->nr_paths++;
592 0 : return 0;
593 :
594 0 : out_path:
595 0 : kfree(path);
596 0 : return error;
597 : }
598 :
599 : /*
600 : * Reattach this orphaned directory to the orphanage. Do not call this with
601 : * any resources held. Returns -ESTALE if the scan data have become out of
602 : * date.
603 : */
604 : STATIC int
605 0 : xrep_dirtree_adopt(
606 : struct xchk_dirtree *dl)
607 : {
608 0 : struct xfs_scrub *sc = dl->sc;
609 0 : struct xfs_mount *mp = sc->mp;
610 0 : int error;
611 :
612 0 : error = xrep_adoption_init(sc, &dl->adoption);
613 0 : if (error)
614 : return error;
615 :
616 : /*
617 : * Try to take the IOLOCK of the the orphanage. In theory, @sc->ip
618 : * isn't linked anywhere, so there should not be another thread holding
619 : * the orphanage's IOLOCK while trying to get @sc->ip's IOLOCK. But
620 : * we'll be careful to check for stale scans.
621 : */
622 0 : while (!xrep_orphanage_ilock_nowait(sc, XFS_IOLOCK_EXCL)) {
623 0 : if (xchk_should_terminate(sc, &error))
624 0 : goto out_adoption;
625 0 : error = xrep_dirtree_was_stale(dl);
626 0 : if (error)
627 0 : goto out_adoption;
628 :
629 0 : delay(1);
630 : }
631 :
632 : /*
633 : * Allocate transaction, reserve disk space, and take the ILOCKs.
634 : * Check for stale scan data before we try the lengthly adoption name
635 : * computation.
636 : */
637 0 : error = xfs_trans_alloc(mp, &M_RES(mp)->tr_link, 0, 0, 0, &sc->tp);
638 0 : if (error)
639 0 : goto out_iolock;
640 0 : error = xrep_adoption_prep(&dl->adoption);
641 0 : if (error)
642 0 : goto out_ilock;
643 :
644 : /*
645 : * Abort the adoption if the scan data is out of date. @sc->ip
646 : * might have picked up another path to the root directory while it was
647 : * unlocked.
648 : */
649 0 : error = xrep_dirtree_was_stale(dl);
650 0 : if (error)
651 0 : goto out_ilock;
652 :
653 : /* Figure out what name we're going to use here. */
654 0 : error = xrep_adoption_compute_name(&dl->adoption, dl->pptr.p_name);
655 0 : if (error)
656 0 : goto out_ilock;
657 :
658 : /*
659 : * Now that we have a proposed name for the orphanage entry, create
660 : * a faux path so that the live update hook will see it.
661 : */
662 0 : mutex_lock(&dl->lock);
663 0 : if (dl->stale) {
664 0 : mutex_unlock(&dl->lock);
665 0 : error = -ESTALE;
666 0 : goto out_ilock;
667 : }
668 0 : error = xrep_dirtree_create_adoption_path(dl);
669 0 : mutex_unlock(&dl->lock);
670 0 : if (error)
671 0 : goto out_ilock;
672 :
673 : /*
674 : * Create the new name in the orphanage and commit the transaction.
675 : * After this point the adoption structure is dead no matter what.
676 : */
677 0 : error = xrep_adoption_commit(&dl->adoption);
678 0 : if (error)
679 0 : xchk_trans_cancel(sc);
680 : else
681 0 : error = xrep_trans_commit(sc);
682 :
683 0 : xchk_iunlock(sc, XFS_ILOCK_EXCL);
684 0 : xrep_orphanage_iunlock(sc, XFS_ILOCK_EXCL);
685 0 : xrep_orphanage_iunlock(sc, XFS_IOLOCK_EXCL);
686 0 : return error;
687 :
688 0 : out_ilock:
689 0 : if (sc->ilock_flags & XFS_ILOCK_EXCL)
690 0 : xchk_iunlock(sc, XFS_ILOCK_EXCL);
691 0 : if (sc->orphanage_ilock_flags & XFS_ILOCK_EXCL)
692 0 : xrep_orphanage_iunlock(sc, XFS_ILOCK_EXCL);
693 0 : xchk_trans_cancel(sc);
694 0 : out_iolock:
695 0 : xrep_orphanage_iunlock(sc, XFS_IOLOCK_EXCL);
696 0 : out_adoption:
697 0 : xrep_adoption_cancel(&dl->adoption, error);
698 0 : return error;
699 : }
700 :
701 : /*
702 : * This newly orphaned directory needs to be adopted by the orphanage.
703 : * Make this happen.
704 : */
705 : STATIC int
706 0 : xrep_dirtree_move_to_orphanage(
707 : struct xchk_dirtree *dl)
708 : {
709 0 : struct xfs_scrub *sc = dl->sc;
710 0 : int error;
711 :
712 : /*
713 : * Start by dropping all the resources that we hold so that we can grab
714 : * all the resources that we need for the adoption.
715 : */
716 0 : mutex_unlock(&dl->lock);
717 0 : xchk_trans_cancel(sc);
718 0 : xchk_iunlock(sc, XFS_ILOCK_EXCL);
719 :
720 : /* Perform the adoption */
721 0 : error = xrep_dirtree_adopt(dl);
722 :
723 : /* Retake all the resources we had at the beginning. */
724 0 : xchk_trans_alloc_empty(sc);
725 0 : xchk_ilock(sc, XFS_ILOCK_EXCL);
726 0 : mutex_lock(&dl->lock);
727 0 : if (!error && dl->stale)
728 0 : return -ESTALE;
729 : return error;
730 : }
731 :
732 : /*
733 : * Try to fix all the problems. Returns -ESTALE if the scan data have become
734 : * out of date.
735 : */
736 : STATIC int
737 526460 : xrep_dirtree_fix_problems(
738 : struct xchk_dirtree *dl,
739 : struct xchk_dirtree_outcomes *oc)
740 : {
741 526460 : struct xchk_dirpath *path;
742 526460 : int error;
743 :
744 : /* Delete all the paths we don't want. */
745 1047464 : xchk_dirtree_for_each_path(dl, path) {
746 521975 : if (path->outcome != XCHK_DIRPATH_DELETE)
747 521975 : continue;
748 :
749 0 : error = xrep_dirtree_delete_path(dl, path);
750 1 : if (error)
751 0 : return error;
752 : }
753 :
754 : /* Reparent this directory to the orphanage. */
755 525489 : if (oc->needs_adoption)
756 0 : return xrep_dirtree_move_to_orphanage(dl);
757 :
758 : return 0;
759 : }
760 :
761 : /* Fix directory loops involving this directory. */
762 : int
763 528530 : xrep_dirtree(
764 : struct xfs_scrub *sc)
765 : {
766 528530 : struct xchk_dirtree *dl = sc->buf;
767 528530 : struct xchk_dirtree_outcomes oc;
768 528530 : int error;
769 :
770 : /*
771 : * Prepare to fix the directory tree by retaking the scan lock. The
772 : * order of resource acquisition is still IOLOCK -> transaction ->
773 : * ILOCK -> scan lock.
774 : */
775 528530 : mutex_lock(&dl->lock);
776 529638 : do {
777 : /*
778 : * Decide what we're going to do, then do it. An -ESTALE
779 : * return here means the scan results are invalid and we have
780 : * to walk again.
781 : */
782 529638 : if (!dl->stale) {
783 529584 : xrep_dirtree_decide_fate(dl, &oc);
784 :
785 528071 : trace_xrep_dirtree_decided_fate(dl, &oc);
786 :
787 525969 : error = xrep_dirtree_fix_problems(dl, &oc);
788 525724 : if (!error || error != -ESTALE)
789 : break;
790 : }
791 5 : error = xchk_dirtree_find_paths_to_root(dl);
792 1 : if (error == -ELNRNG || error == -ENOSR)
793 : error = -EFSCORRUPTED;
794 1 : } while (!error);
795 526021 : mutex_unlock(&dl->lock);
796 :
797 526363 : return error;
798 : }
|