Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-or-later
2 : /*
3 : * Copyright (C) 2017-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_mount.h"
12 : #include "xfs_log_format.h"
13 : #include "xfs_trans.h"
14 : #include "xfs_inode.h"
15 : #include "xfs_icache.h"
16 : #include "xfs_dir2.h"
17 : #include "xfs_dir2_priv.h"
18 : #include "xfs_attr.h"
19 : #include "xfs_parent.h"
20 : #include "scrub/scrub.h"
21 : #include "scrub/common.h"
22 : #include "scrub/readdir.h"
23 : #include "scrub/tempfile.h"
24 : #include "scrub/repair.h"
25 : #include "scrub/listxattr.h"
26 : #include "scrub/xfile.h"
27 : #include "scrub/xfarray.h"
28 : #include "scrub/xfblob.h"
29 : #include "scrub/trace.h"
30 :
31 : /* Set us up to scrub parents. */
32 : int
33 100537591 : xchk_setup_parent(
34 : struct xfs_scrub *sc)
35 : {
36 100537591 : int error;
37 :
38 100537591 : if (sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) {
39 3416270 : error = xrep_setup_parent(sc);
40 3416261 : if (error)
41 : return error;
42 : }
43 :
44 100537582 : return xchk_setup_inode_contents(sc, 0);
45 : }
46 :
47 : /* Parent pointers */
48 :
49 : /* Look for an entry in a parent pointing to this inode. */
50 :
51 : struct xchk_parent_ctx {
52 : struct xfs_scrub *sc;
53 : xfs_nlink_t nlink;
54 : };
55 :
56 : /* Look for a single entry in a directory pointing to an inode. */
57 : STATIC int
58 13453 : xchk_parent_actor(
59 : struct xfs_scrub *sc,
60 : struct xfs_inode *dp,
61 : xfs_dir2_dataptr_t dapos,
62 : const struct xfs_name *name,
63 : xfs_ino_t ino,
64 : void *priv)
65 : {
66 13453 : struct xchk_parent_ctx *spc = priv;
67 13453 : int error = 0;
68 :
69 : /* Does this name make sense? */
70 13453 : if (!xfs_dir2_namecheck(name->name, name->len))
71 0 : error = -EFSCORRUPTED;
72 13454 : if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error))
73 0 : return error;
74 :
75 13455 : if (sc->ip->i_ino == ino)
76 1250 : spc->nlink++;
77 :
78 13455 : if (xchk_should_terminate(spc->sc, &error))
79 0 : return error;
80 :
81 : return 0;
82 : }
83 :
84 : /*
85 : * Try to lock a parent directory for checking dirents. Returns the inode
86 : * flags for the locks we now hold, or zero if we failed.
87 : */
88 : STATIC unsigned int
89 1250 : xchk_parent_ilock_dir(
90 : struct xfs_inode *dp)
91 : {
92 1250 : if (!xfs_ilock_nowait(dp, XFS_ILOCK_SHARED))
93 : return 0;
94 :
95 1250 : if (!xfs_need_iread_extents(&dp->i_df))
96 : return XFS_ILOCK_SHARED;
97 :
98 0 : xfs_iunlock(dp, XFS_ILOCK_SHARED);
99 :
100 0 : if (!xfs_ilock_nowait(dp, XFS_ILOCK_EXCL))
101 0 : return 0;
102 :
103 : return XFS_ILOCK_EXCL;
104 : }
105 :
106 : /*
107 : * Given the inode number of the alleged parent of the inode being scrubbed,
108 : * try to validate that the parent has exactly one directory entry pointing
109 : * back to the inode being scrubbed. Returns -EAGAIN if we need to revalidate
110 : * the dotdot entry.
111 : */
112 : STATIC int
113 1318 : xchk_parent_validate(
114 : struct xfs_scrub *sc,
115 : xfs_ino_t parent_ino)
116 : {
117 1318 : struct xchk_parent_ctx spc = {
118 : .sc = sc,
119 : .nlink = 0,
120 : };
121 1318 : struct xfs_mount *mp = sc->mp;
122 1318 : struct xfs_inode *dp = NULL;
123 1318 : xfs_nlink_t expected_nlink;
124 1318 : unsigned int lock_mode;
125 1318 : int error = 0;
126 :
127 : /* Is this the root dir? Then '..' must point to itself. */
128 1318 : if (sc->ip == mp->m_rootip) {
129 68 : if (sc->ip->i_ino != mp->m_sb.sb_rootino ||
130 : sc->ip->i_ino != parent_ino)
131 0 : xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
132 68 : return 0;
133 : }
134 :
135 : /* '..' must not point to ourselves. */
136 1250 : if (sc->ip->i_ino == parent_ino) {
137 0 : xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
138 0 : return 0;
139 : }
140 :
141 : /*
142 : * If we're an unlinked directory, the parent /won't/ have a link
143 : * to us. Otherwise, it should have one link.
144 : */
145 1250 : expected_nlink = VFS_I(sc->ip)->i_nlink == 0 ? 0 : 1;
146 :
147 : /*
148 : * Grab the parent directory inode. This must be released before we
149 : * cancel the scrub transaction.
150 : *
151 : * If _iget returns -EINVAL or -ENOENT then the parent inode number is
152 : * garbage and the directory is corrupt. If the _iget returns
153 : * -EFSCORRUPTED or -EFSBADCRC then the parent is corrupt which is a
154 : * cross referencing error. Any other error is an operational error.
155 : */
156 1250 : error = xchk_iget(sc, parent_ino, &dp);
157 1250 : if (error == -EINVAL || error == -ENOENT) {
158 0 : error = -EFSCORRUPTED;
159 0 : xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error);
160 0 : return error;
161 : }
162 1250 : if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error))
163 0 : return error;
164 1250 : if (dp == sc->ip || xrep_is_tempfile(dp) ||
165 1250 : !S_ISDIR(VFS_I(dp)->i_mode)) {
166 0 : xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
167 0 : goto out_rele;
168 : }
169 :
170 1250 : lock_mode = xchk_parent_ilock_dir(dp);
171 1250 : if (!lock_mode) {
172 0 : xchk_iunlock(sc, XFS_ILOCK_EXCL);
173 0 : xchk_ilock(sc, XFS_ILOCK_EXCL);
174 0 : error = -EAGAIN;
175 0 : goto out_rele;
176 : }
177 :
178 : /*
179 : * We cannot yet validate this parent pointer if the directory looks as
180 : * though it has been zapped by the inode record repair code.
181 : */
182 1250 : if (xchk_dir_looks_zapped(dp)) {
183 0 : error = -EFSCORRUPTED;
184 0 : xchk_set_incomplete(sc);
185 0 : goto out_unlock;
186 : }
187 :
188 : /* Look for a directory entry in the parent pointing to the child. */
189 1250 : error = xchk_dir_walk(sc, dp, xchk_parent_actor, &spc);
190 1250 : if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error))
191 0 : goto out_unlock;
192 :
193 : /*
194 : * Ensure that the parent has as many links to the child as the child
195 : * thinks it has to the parent.
196 : */
197 1250 : if (spc.nlink != expected_nlink)
198 0 : xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
199 :
200 1250 : out_unlock:
201 1250 : xfs_iunlock(dp, lock_mode);
202 1250 : out_rele:
203 1250 : xchk_irele(sc, dp);
204 1250 : return error;
205 : }
206 :
207 : /*
208 : * Checking of Parent Pointers
209 : * ===========================
210 : *
211 : * On filesystems with directory parent pointers, we check the referential
212 : * integrity by visiting each parent pointer of a child file and checking that
213 : * the directory referenced by the pointer actually has a dirent pointing
214 : * forward to the child file.
215 : */
216 :
217 : /* Deferred parent pointer entry that we saved for later. */
218 : struct xchk_pptr {
219 : /* Cookie for retrieval of the pptr name. */
220 : xfblob_cookie name_cookie;
221 :
222 : /* Parent pointer attr key. */
223 : xfs_ino_t p_ino;
224 : uint32_t p_gen;
225 :
226 : /* Length of the pptr name. */
227 : uint8_t namelen;
228 : };
229 :
230 : struct xchk_pptrs {
231 : struct xfs_scrub *sc;
232 :
233 : /* Scratch buffer for scanning pptr xattrs */
234 : struct xfs_parent_name_irec pptr;
235 :
236 : /* Fixed-size array of xchk_pptr structures. */
237 : struct xfarray *pptr_entries;
238 :
239 : /* Blobs containing parent pointer names. */
240 : struct xfblob *pptr_names;
241 :
242 : /* How many parent pointers did we find at the end? */
243 : unsigned long long pptrs_found;
244 :
245 : /* Parent of this directory. */
246 : xfs_ino_t parent_ino;
247 :
248 : /* If we've cycled the ILOCK, we must revalidate all deferred pptrs. */
249 : bool need_revalidate;
250 :
251 : /* xattr key and da args for parent pointer revalidation. */
252 : struct xfs_parent_scratch pptr_scratch;
253 : };
254 :
255 : /*
256 : * Walk an xattr of a file. If this xattr is a parent pointer, follow it up
257 : * to a parent directory and check that the parent has a dirent pointing back
258 : * to us.
259 : */
260 : STATIC int
261 14912357 : xchk_parent_scan_dotdot(
262 : struct xfs_scrub *sc,
263 : struct xfs_inode *ip,
264 : unsigned int attr_flags,
265 : const unsigned char *name,
266 : unsigned int namelen,
267 : const void *value,
268 : unsigned int valuelen,
269 : void *priv)
270 : {
271 14912357 : struct xchk_pptrs *pp = priv;
272 14912357 : const struct xfs_parent_name_rec *rec = (const void *)name;
273 :
274 : /* Ignore anything that isn't a parent pointer. */
275 14912357 : if (!(attr_flags & XFS_ATTR_PARENT))
276 : return 0;
277 :
278 : /* Does the ondisk parent pointer structure make sense? */
279 14291049 : if (!xfs_parent_namecheck(sc->mp, rec, namelen, attr_flags)) {
280 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
281 0 : return -ECANCELED;
282 : }
283 :
284 14290946 : if (!xfs_parent_valuecheck(sc->mp, value, valuelen)) {
285 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
286 0 : return -ECANCELED;
287 : }
288 :
289 14290973 : xfs_parent_irec_from_disk(&pp->pptr, rec, value, valuelen);
290 :
291 14291020 : if (pp->parent_ino == pp->pptr.p_ino)
292 14291025 : return -ECANCELED;
293 :
294 : return 0;
295 : }
296 :
297 : /* Look up the dotdot entry so that we can check it as we walk the pptrs. */
298 : STATIC int
299 14331051 : xchk_parent_pptr_and_dotdot(
300 : struct xchk_pptrs *pp)
301 : {
302 14331051 : struct xfs_scrub *sc = pp->sc;
303 14331051 : int error;
304 :
305 : /* Look up '..' */
306 14331051 : error = xchk_dir_lookup(sc, sc->ip, &xfs_name_dotdot, &pp->parent_ino);
307 14331032 : if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
308 0 : return error;
309 14331011 : if (!xfs_verify_dir_ino(sc->mp, pp->parent_ino)) {
310 0 : xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
311 0 : return 0;
312 : }
313 :
314 : /* Is this the root dir? Then '..' must point to itself. */
315 14331057 : if (sc->ip == sc->mp->m_rootip) {
316 40028 : if (sc->ip->i_ino != pp->parent_ino)
317 0 : xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
318 40028 : return 0;
319 : }
320 :
321 : /*
322 : * If this is now an unlinked directory, the dotdot value is
323 : * meaningless as long as it points to a valid inode.
324 : */
325 14291029 : if (VFS_I(sc->ip)->i_nlink == 0)
326 : return 0;
327 :
328 14291029 : if (pp->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
329 : return 0;
330 :
331 : /* Otherwise, walk the pptrs again, and check. */
332 14291058 : error = xchk_xattr_walk(sc, sc->ip, xchk_parent_scan_dotdot, NULL, pp);
333 14290954 : if (error == -ECANCELED)
334 : return 0;
335 0 : if (error == 0) {
336 : /* Didn't find a matching parent pointer. */
337 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
338 : }
339 0 : return error;
340 : }
341 :
342 : /*
343 : * Try to lock a parent directory for checking dirents. Returns the inode
344 : * flags for the locks we now hold, or zero if we failed.
345 : */
346 : STATIC unsigned int
347 107898664 : xchk_parent_lock_dir(
348 : struct xfs_scrub *sc,
349 : struct xfs_inode *dp)
350 : {
351 107898664 : if (!xfs_ilock_nowait(dp, XFS_IOLOCK_SHARED))
352 : return 0;
353 :
354 81132401 : if (!xfs_ilock_nowait(dp, XFS_ILOCK_SHARED)) {
355 531611 : xfs_iunlock(dp, XFS_IOLOCK_SHARED);
356 531611 : return 0;
357 : }
358 :
359 80600291 : if (!xfs_need_iread_extents(&dp->i_df))
360 : return XFS_IOLOCK_SHARED | XFS_ILOCK_SHARED;
361 :
362 375 : xfs_iunlock(dp, XFS_ILOCK_SHARED);
363 :
364 375 : if (!xfs_ilock_nowait(dp, XFS_ILOCK_EXCL)) {
365 0 : xfs_iunlock(dp, XFS_IOLOCK_SHARED);
366 0 : return 0;
367 : }
368 :
369 : return XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL;
370 : }
371 :
372 : /* Check the forward link (dirent) associated with this parent pointer. */
373 : STATIC int
374 80599738 : xchk_parent_dirent(
375 : struct xchk_pptrs *pp,
376 : struct xfs_inode *dp)
377 : {
378 80599738 : struct xfs_name xname = {
379 80599738 : .name = pp->pptr.p_name,
380 80599738 : .len = pp->pptr.p_namelen,
381 : };
382 80599738 : struct xfs_scrub *sc = pp->sc;
383 80599738 : xfs_ino_t child_ino;
384 80599738 : int error;
385 :
386 : /*
387 : * Use the name attached to this parent pointer to look up the
388 : * directory entry in the alleged parent.
389 : */
390 80599738 : error = xchk_dir_lookup(sc, dp, &xname, &child_ino);
391 80598217 : if (error == -ENOENT) {
392 0 : xchk_fblock_xref_set_corrupt(sc, XFS_ATTR_FORK, 0);
393 0 : return 0;
394 : }
395 80598217 : if (!xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0, &error))
396 0 : return error;
397 :
398 : /* Does the inode number match? */
399 80596934 : if (child_ino != sc->ip->i_ino) {
400 0 : xchk_fblock_xref_set_corrupt(sc, XFS_ATTR_FORK, 0);
401 0 : return 0;
402 : }
403 :
404 : return 0;
405 : }
406 :
407 : /* Try to grab a parent directory. */
408 : STATIC int
409 107902818 : xchk_parent_iget(
410 : struct xchk_pptrs *pp,
411 : struct xfs_inode **dpp)
412 : {
413 107902818 : struct xfs_scrub *sc = pp->sc;
414 107902818 : struct xfs_inode *ip;
415 107902818 : int error;
416 :
417 : /* Validate inode number. */
418 107902818 : error = xfs_dir_ino_validate(sc->mp, pp->pptr.p_ino);
419 107903319 : if (error) {
420 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
421 0 : return -ECANCELED;
422 : }
423 :
424 107903319 : error = xchk_iget(sc, pp->pptr.p_ino, &ip);
425 107905865 : if (error == -EINVAL || error == -ENOENT) {
426 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
427 0 : return -ECANCELED;
428 : }
429 107905865 : if (!xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0, &error))
430 0 : return error;
431 :
432 : /* The parent must be a directory. */
433 107898445 : if (!S_ISDIR(VFS_I(ip)->i_mode)) {
434 2 : xchk_fblock_xref_set_corrupt(sc, XFS_ATTR_FORK, 0);
435 2 : goto out_rele;
436 : }
437 :
438 : /* Validate generation number. */
439 107898443 : if (VFS_I(ip)->i_generation != pp->pptr.p_gen) {
440 0 : xchk_fblock_xref_set_corrupt(sc, XFS_ATTR_FORK, 0);
441 0 : goto out_rele;
442 : }
443 :
444 107898443 : *dpp = ip;
445 107898443 : return 0;
446 2 : out_rele:
447 2 : xchk_irele(sc, ip);
448 2 : return 0;
449 : }
450 :
451 : /*
452 : * Walk an xattr of a file. If this xattr is a parent pointer, follow it up
453 : * to a parent directory and check that the parent has a dirent pointing back
454 : * to us.
455 : */
456 : STATIC int
457 131019098 : xchk_parent_scan_attr(
458 : struct xfs_scrub *sc,
459 : struct xfs_inode *ip,
460 : unsigned int attr_flags,
461 : const unsigned char *name,
462 : unsigned int namelen,
463 : const void *value,
464 : unsigned int valuelen,
465 : void *priv)
466 : {
467 131019098 : struct xfs_name dname = {
468 : .name = value,
469 : .len = valuelen,
470 : };
471 131019098 : struct xchk_pptrs *pp = priv;
472 131019098 : struct xfs_inode *dp = NULL;
473 131019098 : const struct xfs_parent_name_rec *rec = (const void *)name;
474 131019098 : unsigned int lockmode;
475 131019098 : xfs_dahash_t computed_hash;
476 131019098 : int error;
477 :
478 : /* Ignore anything that isn't a parent pointer. */
479 131019098 : if (!(attr_flags & XFS_ATTR_PARENT))
480 : return 0;
481 :
482 : /* Does the ondisk parent pointer structure make sense? */
483 107904067 : if (!xfs_parent_namecheck(sc->mp, rec, namelen, attr_flags)) {
484 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
485 0 : return -ECANCELED;
486 : }
487 :
488 107904860 : if (!xfs_parent_valuecheck(sc->mp, value, valuelen)) {
489 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
490 0 : return -ECANCELED;
491 : }
492 :
493 107904418 : xfs_parent_irec_from_disk(&pp->pptr, rec, value, valuelen);
494 :
495 : /*
496 : * If the namehash of the dirent name encoded in the parent pointer
497 : * attr value doesn't match the namehash in the parent pointer key,
498 : * the parent pointer is corrupt.
499 : */
500 107904316 : computed_hash = xfs_dir2_hashname(ip->i_mount, &dname);
501 107905918 : if (pp->pptr.p_namehash != computed_hash) {
502 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
503 0 : return -ECANCELED;
504 : }
505 107905918 : pp->pptrs_found++;
506 :
507 107905918 : error = xchk_parent_iget(pp, &dp);
508 107897036 : if (error)
509 : return error;
510 107897036 : if (!dp)
511 : return 0;
512 :
513 : /* Try to lock the inode. */
514 107897034 : lockmode = xchk_parent_lock_dir(sc, dp);
515 107903967 : if (!lockmode) {
516 27302797 : struct xchk_pptr save_pp = {
517 27302797 : .p_ino = pp->pptr.p_ino,
518 27302797 : .p_gen = pp->pptr.p_gen,
519 27302797 : .namelen = pp->pptr.p_namelen,
520 : };
521 :
522 : /* Couldn't lock the inode, so save the pptr for later. */
523 27302797 : trace_xchk_parent_defer(sc->ip, pp->pptr.p_name,
524 27302797 : pp->pptr.p_namelen, dp->i_ino);
525 :
526 54604821 : error = xfblob_store(pp->pptr_names, &save_pp.name_cookie,
527 27302898 : pp->pptr.p_name, pp->pptr.p_namelen);
528 27301923 : if (xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0,
529 : &error))
530 27302489 : goto out_rele;
531 :
532 0 : error = xfarray_append(pp->pptr_entries, &save_pp);
533 0 : if (xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0,
534 : &error))
535 : goto out_rele;
536 :
537 0 : goto out_rele;
538 : }
539 :
540 80601170 : error = xchk_parent_dirent(pp, dp);
541 80598627 : if (error)
542 : goto out_unlock;
543 :
544 : out_unlock:
545 80598627 : xfs_iunlock(dp, lockmode);
546 107905548 : out_rele:
547 107905548 : xchk_irele(sc, dp);
548 107908067 : return error;
549 : }
550 :
551 : /*
552 : * Revalidate a parent pointer that we collected in the past but couldn't check
553 : * because of lock contention. Returns 0 if the parent pointer is still valid,
554 : * -ENOENT if it has gone away on us, or a negative errno.
555 : */
556 : STATIC int
557 0 : xchk_parent_revalidate_pptr(
558 : struct xchk_pptrs *pp)
559 : {
560 0 : struct xfs_scrub *sc = pp->sc;
561 0 : int error;
562 :
563 0 : error = xfs_parent_lookup(sc->tp, sc->ip, &pp->pptr,
564 : &pp->pptr_scratch);
565 0 : if (error == -ENOATTR) {
566 : /* Parent pointer went away, nothing to revalidate. */
567 0 : return -ENOENT;
568 : }
569 :
570 : return error;
571 : }
572 :
573 : /*
574 : * Check a parent pointer the slow way, which means we cycle locks a bunch
575 : * and put up with revalidation until we get it done.
576 : */
577 : STATIC int
578 0 : xchk_parent_slow_pptr(
579 : struct xchk_pptrs *pp,
580 : struct xchk_pptr *pptr)
581 : {
582 0 : struct xfs_scrub *sc = pp->sc;
583 0 : struct xfs_inode *dp = NULL;
584 0 : unsigned int lockmode;
585 0 : int error;
586 :
587 : /* Restore the saved parent pointer into the irec. */
588 0 : pp->pptr.p_ino = pptr->p_ino;
589 0 : pp->pptr.p_gen = pptr->p_gen;
590 :
591 0 : error = xfblob_load(pp->pptr_names, pptr->name_cookie, pp->pptr.p_name,
592 0 : pptr->namelen);
593 0 : if (error)
594 : return error;
595 0 : pp->pptr.p_name[MAXNAMELEN - 1] = 0;
596 0 : pp->pptr.p_namelen = pptr->namelen;
597 0 : xfs_parent_irec_hashname(sc->mp, &pp->pptr);
598 :
599 : /* Check that the deferred parent pointer still exists. */
600 0 : if (pp->need_revalidate) {
601 0 : error = xchk_parent_revalidate_pptr(pp);
602 0 : if (error == -ENOENT)
603 : return 0;
604 0 : if (!xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0,
605 : &error))
606 0 : return error;
607 : }
608 :
609 0 : error = xchk_parent_iget(pp, &dp);
610 0 : if (error)
611 : return error;
612 0 : if (!dp)
613 : return 0;
614 :
615 : /*
616 : * If we can grab both IOLOCK and ILOCK of the alleged parent, we
617 : * can proceed with the validation.
618 : */
619 0 : lockmode = xchk_parent_lock_dir(sc, dp);
620 0 : if (lockmode)
621 0 : goto check_dirent;
622 :
623 : /*
624 : * We couldn't lock the parent dir. Drop all the locks and try to
625 : * get them again, one at a time.
626 : */
627 0 : xchk_iunlock(sc, sc->ilock_flags);
628 0 : pp->need_revalidate = true;
629 :
630 0 : trace_xchk_parent_slowpath(sc->ip, pp->pptr.p_name, pptr->namelen,
631 0 : dp->i_ino);
632 :
633 0 : while (true) {
634 0 : xchk_ilock(sc, XFS_IOLOCK_EXCL);
635 0 : if (xfs_ilock_nowait(dp, XFS_IOLOCK_SHARED)) {
636 0 : xchk_ilock(sc, XFS_ILOCK_EXCL);
637 0 : if (xfs_ilock_nowait(dp, XFS_ILOCK_EXCL)) {
638 : break;
639 : }
640 0 : xchk_iunlock(sc, XFS_ILOCK_EXCL);
641 : }
642 0 : xchk_iunlock(sc, XFS_IOLOCK_EXCL);
643 :
644 0 : if (xchk_should_terminate(sc, &error))
645 0 : goto out_rele;
646 :
647 0 : delay(1);
648 : }
649 0 : lockmode = XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL;
650 :
651 : /* Revalidate the parent pointer now that we cycled locks. */
652 0 : error = xchk_parent_revalidate_pptr(pp);
653 0 : if (error == -ENOENT)
654 0 : goto out_unlock;
655 0 : if (!xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0, &error))
656 0 : goto out_unlock;
657 :
658 0 : check_dirent:
659 0 : error = xchk_parent_dirent(pp, dp);
660 0 : out_unlock:
661 0 : xfs_iunlock(dp, lockmode);
662 0 : out_rele:
663 0 : xchk_irele(sc, dp);
664 0 : return error;
665 : }
666 :
667 : /* Check all the parent pointers that we deferred the first time around. */
668 : STATIC int
669 99904809 : xchk_parent_finish_slow_pptrs(
670 : struct xchk_pptrs *pp)
671 : {
672 99904809 : xfarray_idx_t array_cur;
673 99904809 : int error;
674 :
675 99904809 : foreach_xfarray_idx(pp->pptr_entries, array_cur) {
676 0 : struct xchk_pptr pptr;
677 :
678 0 : if (pp->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
679 0 : return 0;
680 :
681 0 : error = xfarray_load(pp->pptr_entries, array_cur, &pptr);
682 0 : if (error)
683 0 : return error;
684 :
685 0 : error = xchk_parent_slow_pptr(pp, &pptr);
686 0 : if (error)
687 0 : return error;
688 : }
689 :
690 : /* Empty out both xfiles now that we've checked everything. */
691 99902574 : xfarray_truncate(pp->pptr_entries);
692 99902466 : xfblob_truncate(pp->pptr_names);
693 99902466 : return 0;
694 : }
695 :
696 : /* Count the number of parent pointers. */
697 : STATIC int
698 0 : xchk_parent_count_pptr(
699 : struct xfs_scrub *sc,
700 : struct xfs_inode *ip,
701 : unsigned int attr_flags,
702 : const unsigned char *name,
703 : unsigned int namelen,
704 : const void *value,
705 : unsigned int valuelen,
706 : void *priv)
707 : {
708 0 : struct xchk_pptrs *pp = priv;
709 :
710 0 : if (attr_flags & XFS_ATTR_PARENT)
711 0 : pp->pptrs_found++;
712 0 : return 0;
713 : }
714 :
715 : /*
716 : * Compare the number of parent pointers to the link count. For
717 : * non-directories these should be the same. For unlinked directories the
718 : * count should be zero; for linked directories, it should be nonzero.
719 : */
720 : STATIC int
721 99904296 : xchk_parent_count_pptrs(
722 : struct xchk_pptrs *pp)
723 : {
724 99904296 : struct xfs_scrub *sc = pp->sc;
725 99904296 : int error;
726 :
727 : /*
728 : * If we cycled the ILOCK while cross-checking parent pointers with
729 : * dirents, then we need to recalculate the number of parent pointers.
730 : */
731 99904296 : if (pp->need_revalidate) {
732 0 : pp->pptrs_found = 0;
733 0 : error = xchk_xattr_walk(sc, sc->ip, xchk_parent_count_pptr,
734 : NULL, pp);
735 0 : if (error == -ECANCELED)
736 : return 0;
737 0 : if (error)
738 : return error;
739 : }
740 :
741 99904296 : if (S_ISDIR(VFS_I(sc->ip)->i_mode)) {
742 14330973 : if (sc->ip == sc->mp->m_rootip)
743 40028 : pp->pptrs_found++;
744 :
745 14330973 : if (VFS_I(sc->ip)->i_nlink == 0 && pp->pptrs_found > 0)
746 0 : xchk_ino_set_corrupt(sc, sc->ip->i_ino);
747 14330973 : else if (VFS_I(sc->ip)->i_nlink > 0 &&
748 14330973 : pp->pptrs_found == 0)
749 0 : xchk_ino_set_corrupt(sc, sc->ip->i_ino);
750 : } else {
751 85573323 : if (VFS_I(sc->ip)->i_nlink != pp->pptrs_found)
752 0 : xchk_ino_set_corrupt(sc, sc->ip->i_ino);
753 : }
754 :
755 : return 0;
756 : }
757 :
758 : /* Check parent pointers of a file. */
759 : STATIC int
760 99906840 : xchk_parent_pptr(
761 : struct xfs_scrub *sc)
762 : {
763 99906840 : struct xchk_pptrs *pp;
764 99906840 : char *descr;
765 99906840 : int error;
766 :
767 99906840 : pp = kvzalloc(sizeof(struct xchk_pptrs), XCHK_GFP_FLAGS);
768 99907224 : if (!pp)
769 : return -ENOMEM;
770 99907224 : pp->sc = sc;
771 :
772 : /*
773 : * Set up some staging memory for parent pointers that we can't check
774 : * due to locking contention.
775 : */
776 99907224 : descr = xchk_xfile_ino_descr(sc, "slow parent pointer entries");
777 99904403 : error = xfarray_create(descr, 0, sizeof(struct xchk_pptr),
778 : &pp->pptr_entries);
779 99903663 : kfree(descr);
780 99907326 : if (error)
781 0 : goto out_pp;
782 :
783 99907326 : descr = xchk_xfile_ino_descr(sc, "slow parent pointer names");
784 99901379 : error = xfblob_create(descr, &pp->pptr_names);
785 99908602 : kfree(descr);
786 99908231 : if (error)
787 0 : goto out_entries;
788 :
789 99908231 : error = xchk_xattr_walk(sc, sc->ip, xchk_parent_scan_attr, NULL, pp);
790 99906342 : if (error == -ECANCELED) {
791 0 : error = 0;
792 0 : goto out_names;
793 : }
794 99906342 : if (error)
795 0 : goto out_names;
796 :
797 99906342 : error = xchk_parent_finish_slow_pptrs(pp);
798 99906138 : if (error)
799 0 : goto out_names;
800 :
801 99906138 : if (pp->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
802 0 : goto out_names;
803 :
804 : /*
805 : * For subdirectories, make sure the dotdot entry references the same
806 : * inode as the parent pointers.
807 : *
808 : * If we're scanning a /consistent/ directory, there should only be
809 : * one parent pointer, and it should point to the same directory as
810 : * the dotdot entry.
811 : *
812 : * However, a corrupt directory tree might feature a subdirectory with
813 : * multiple parents. The directory loop scanner is responsible for
814 : * correcting that kind of problem, so for now we only validate that
815 : * the dotdot entry matches /one/ of the parents.
816 : */
817 99906138 : if (S_ISDIR(VFS_I(sc->ip)->i_mode)) {
818 14331100 : error = xchk_parent_pptr_and_dotdot(pp);
819 14331024 : if (error)
820 0 : goto out_names;
821 : }
822 :
823 : /*
824 : * If the parent pointers aren't corrupt, complain if the number of
825 : * parent pointers doesn't match the link count.
826 : */
827 99906062 : error = xchk_parent_count_pptrs(pp);
828 99903769 : if (error)
829 0 : goto out_names;
830 :
831 99903769 : out_names:
832 99903769 : xfblob_destroy(pp->pptr_names);
833 99905914 : out_entries:
834 99905914 : xfarray_destroy(pp->pptr_entries);
835 99907428 : out_pp:
836 99907428 : kvfree(pp);
837 99907428 : return error;
838 : }
839 :
840 : /* Scrub a parent pointer. */
841 : int
842 99916519 : xchk_parent(
843 : struct xfs_scrub *sc)
844 : {
845 99916519 : struct xfs_mount *mp = sc->mp;
846 99916519 : xfs_ino_t parent_ino;
847 99916519 : int error = 0;
848 :
849 99916519 : if (xfs_has_parent(mp))
850 99907005 : return xchk_parent_pptr(sc);
851 :
852 : /*
853 : * If we're a directory, check that the '..' link points up to
854 : * a directory that has one entry pointing to us.
855 : */
856 9514 : if (!S_ISDIR(VFS_I(sc->ip)->i_mode))
857 : return -ENOENT;
858 :
859 : /* We're not a special inode, are we? */
860 1318 : if (!xfs_verify_dir_ino(mp, sc->ip->i_ino)) {
861 0 : xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
862 0 : return 0;
863 : }
864 :
865 1318 : do {
866 1318 : if (xchk_should_terminate(sc, &error))
867 : break;
868 :
869 : /* Look up '..' */
870 1318 : error = xchk_dir_lookup(sc, sc->ip, &xfs_name_dotdot,
871 : &parent_ino);
872 1318 : if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
873 0 : return error;
874 1318 : if (!xfs_verify_dir_ino(mp, parent_ino)) {
875 0 : xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
876 0 : return 0;
877 : }
878 :
879 : /*
880 : * Check that the dotdot entry points to a parent directory
881 : * containing a dirent pointing to this subdirectory.
882 : */
883 1318 : error = xchk_parent_validate(sc, parent_ino);
884 1318 : } while (error == -EAGAIN);
885 :
886 1318 : return error;
887 : }
|