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