]> Git Repo - linux.git/blob - fs/xfs/scrub/parent.c
Linux 6.14-rc3
[linux.git] / fs / xfs / scrub / parent.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2017-2023 Oracle.  All Rights Reserved.
4  * Author: Darrick J. Wong <[email protected]>
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 xchk_setup_parent(
34         struct xfs_scrub        *sc)
35 {
36         int                     error;
37
38         if (xchk_could_repair(sc)) {
39                 error = xrep_setup_parent(sc);
40                 if (error)
41                         return error;
42         }
43
44         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 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         struct xchk_parent_ctx  *spc = priv;
67         int                     error = 0;
68
69         /* Does this name make sense? */
70         if (!xfs_dir2_namecheck(name->name, name->len))
71                 error = -EFSCORRUPTED;
72         if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error))
73                 return error;
74
75         if (sc->ip->i_ino == ino)
76                 spc->nlink++;
77
78         if (xchk_should_terminate(spc->sc, &error))
79                 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 xchk_parent_ilock_dir(
90         struct xfs_inode        *dp)
91 {
92         if (!xfs_ilock_nowait(dp, XFS_ILOCK_SHARED))
93                 return 0;
94
95         if (!xfs_need_iread_extents(&dp->i_df))
96                 return XFS_ILOCK_SHARED;
97
98         xfs_iunlock(dp, XFS_ILOCK_SHARED);
99
100         if (!xfs_ilock_nowait(dp, XFS_ILOCK_EXCL))
101                 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 xchk_parent_validate(
114         struct xfs_scrub        *sc,
115         xfs_ino_t               parent_ino)
116 {
117         struct xchk_parent_ctx  spc = {
118                 .sc             = sc,
119                 .nlink          = 0,
120         };
121         struct xfs_mount        *mp = sc->mp;
122         struct xfs_inode        *dp = NULL;
123         xfs_nlink_t             expected_nlink;
124         unsigned int            lock_mode;
125         int                     error = 0;
126
127         /* Is this the root dir?  Then '..' must point to itself. */
128         if (sc->ip == mp->m_rootip) {
129                 if (sc->ip->i_ino != mp->m_sb.sb_rootino ||
130                     sc->ip->i_ino != parent_ino)
131                         xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
132                 return 0;
133         }
134
135         /* Is this the metadata root dir?  Then '..' must point to itself. */
136         if (sc->ip == mp->m_metadirip) {
137                 if (sc->ip->i_ino != mp->m_sb.sb_metadirino ||
138                     sc->ip->i_ino != parent_ino)
139                         xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
140                 return 0;
141         }
142
143         /* '..' must not point to ourselves. */
144         if (sc->ip->i_ino == parent_ino) {
145                 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
146                 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         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         error = xchk_iget(sc, parent_ino, &dp);
165         if (error == -EINVAL || error == -ENOENT) {
166                 error = -EFSCORRUPTED;
167                 xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error);
168                 return error;
169         }
170         if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error))
171                 return error;
172         if (dp == sc->ip || xrep_is_tempfile(dp) ||
173             !S_ISDIR(VFS_I(dp)->i_mode)) {
174                 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
175                 goto out_rele;
176         }
177
178         lock_mode = xchk_parent_ilock_dir(dp);
179         if (!lock_mode) {
180                 xchk_iunlock(sc, XFS_ILOCK_EXCL);
181                 xchk_ilock(sc, XFS_ILOCK_EXCL);
182                 error = -EAGAIN;
183                 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         if (xchk_dir_looks_zapped(dp)) {
191                 error = -EBUSY;
192                 xchk_set_incomplete(sc);
193                 goto out_unlock;
194         }
195
196         /* Metadata and regular inodes cannot cross trees. */
197         if (xfs_is_metadir_inode(dp) != xfs_is_metadir_inode(sc->ip)) {
198                 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
199                 goto out_unlock;
200         }
201
202         /* Look for a directory entry in the parent pointing to the child. */
203         error = xchk_dir_walk(sc, dp, xchk_parent_actor, &spc);
204         if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error))
205                 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         if (spc.nlink != expected_nlink)
212                 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
213
214 out_unlock:
215         xfs_iunlock(dp, lock_mode);
216 out_rele:
217         xchk_irele(sc, dp);
218         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 record. */
237         struct xfs_parent_rec   pptr_rec;
238
239         /* Length of the pptr name. */
240         uint8_t                 namelen;
241 };
242
243 struct xchk_pptrs {
244         struct xfs_scrub        *sc;
245
246         /* How many parent pointers did we find at the end? */
247         unsigned long long      pptrs_found;
248
249         /* Parent of this directory. */
250         xfs_ino_t               parent_ino;
251
252         /* Fixed-size array of xchk_pptr structures. */
253         struct xfarray          *pptr_entries;
254
255         /* Blobs containing parent pointer names. */
256         struct xfblob           *pptr_names;
257
258         /* Scratch buffer for scanning pptr xattrs */
259         struct xfs_da_args      pptr_args;
260
261         /* If we've cycled the ILOCK, we must revalidate all deferred pptrs. */
262         bool                    need_revalidate;
263
264         /* Name buffer */
265         struct xfs_name         xname;
266         char                    namebuf[MAXNAMELEN];
267 };
268
269 /* Does this parent pointer match the dotdot entry? */
270 STATIC int
271 xchk_parent_scan_dotdot(
272         struct xfs_scrub                *sc,
273         struct xfs_inode                *ip,
274         unsigned int                    attr_flags,
275         const unsigned char             *name,
276         unsigned int                    namelen,
277         const void                      *value,
278         unsigned int                    valuelen,
279         void                            *priv)
280 {
281         struct xchk_pptrs               *pp = priv;
282         xfs_ino_t                       parent_ino;
283         int                             error;
284
285         if (!(attr_flags & XFS_ATTR_PARENT))
286                 return 0;
287
288         error = xfs_parent_from_attr(sc->mp, attr_flags, name, namelen, value,
289                         valuelen, &parent_ino, NULL);
290         if (error)
291                 return error;
292
293         if (pp->parent_ino == parent_ino)
294                 return -ECANCELED;
295
296         return 0;
297 }
298
299 /* Look up the dotdot entry so that we can check it as we walk the pptrs. */
300 STATIC int
301 xchk_parent_pptr_and_dotdot(
302         struct xchk_pptrs       *pp)
303 {
304         struct xfs_scrub        *sc = pp->sc;
305         int                     error;
306
307         /* Look up '..' */
308         error = xchk_dir_lookup(sc, sc->ip, &xfs_name_dotdot, &pp->parent_ino);
309         if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
310                 return error;
311         if (!xfs_verify_dir_ino(sc->mp, pp->parent_ino)) {
312                 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
313                 return 0;
314         }
315
316         /* Is this the root dir?  Then '..' must point to itself. */
317         if (xchk_inode_is_dirtree_root(sc->ip)) {
318                 if (sc->ip->i_ino != pp->parent_ino)
319                         xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
320                 return 0;
321         }
322
323         /*
324          * If this is now an unlinked directory, the dotdot value is
325          * meaningless as long as it points to a valid inode.
326          */
327         if (VFS_I(sc->ip)->i_nlink == 0)
328                 return 0;
329
330         if (pp->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
331                 return 0;
332
333         /* Otherwise, walk the pptrs again, and check. */
334         error = xchk_xattr_walk(sc, sc->ip, xchk_parent_scan_dotdot, NULL, pp);
335         if (error == -ECANCELED) {
336                 /* Found a parent pointer that matches dotdot. */
337                 return 0;
338         }
339         if (!error || error == -EFSCORRUPTED) {
340                 /* Found a broken parent pointer or no match. */
341                 xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
342                 return 0;
343         }
344         return error;
345 }
346
347 /*
348  * Try to lock a parent directory for checking dirents.  Returns the inode
349  * flags for the locks we now hold, or zero if we failed.
350  */
351 STATIC unsigned int
352 xchk_parent_lock_dir(
353         struct xfs_scrub        *sc,
354         struct xfs_inode        *dp)
355 {
356         if (!xfs_ilock_nowait(dp, XFS_IOLOCK_SHARED))
357                 return 0;
358
359         if (!xfs_ilock_nowait(dp, XFS_ILOCK_SHARED)) {
360                 xfs_iunlock(dp, XFS_IOLOCK_SHARED);
361                 return 0;
362         }
363
364         if (!xfs_need_iread_extents(&dp->i_df))
365                 return XFS_IOLOCK_SHARED | XFS_ILOCK_SHARED;
366
367         xfs_iunlock(dp, XFS_ILOCK_SHARED);
368
369         if (!xfs_ilock_nowait(dp, XFS_ILOCK_EXCL)) {
370                 xfs_iunlock(dp, XFS_IOLOCK_SHARED);
371                 return 0;
372         }
373
374         return XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL;
375 }
376
377 /* Check the forward link (dirent) associated with this parent pointer. */
378 STATIC int
379 xchk_parent_dirent(
380         struct xchk_pptrs       *pp,
381         const struct xfs_name   *xname,
382         struct xfs_inode        *dp)
383 {
384         struct xfs_scrub        *sc = pp->sc;
385         xfs_ino_t               child_ino;
386         int                     error;
387
388         /*
389          * Use the name attached to this parent pointer to look up the
390          * directory entry in the alleged parent.
391          */
392         error = xchk_dir_lookup(sc, dp, xname, &child_ino);
393         if (error == -ENOENT) {
394                 xchk_fblock_xref_set_corrupt(sc, XFS_ATTR_FORK, 0);
395                 return 0;
396         }
397         if (!xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0, &error))
398                 return error;
399
400         /* Does the inode number match? */
401         if (child_ino != sc->ip->i_ino) {
402                 xchk_fblock_xref_set_corrupt(sc, XFS_ATTR_FORK, 0);
403                 return 0;
404         }
405
406         return 0;
407 }
408
409 /* Try to grab a parent directory. */
410 STATIC int
411 xchk_parent_iget(
412         struct xchk_pptrs       *pp,
413         const struct xfs_parent_rec     *pptr,
414         struct xfs_inode        **dpp)
415 {
416         struct xfs_scrub        *sc = pp->sc;
417         struct xfs_inode        *ip;
418         xfs_ino_t               parent_ino = be64_to_cpu(pptr->p_ino);
419         int                     error;
420
421         /* Validate inode number. */
422         error = xfs_dir_ino_validate(sc->mp, parent_ino);
423         if (error) {
424                 xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
425                 return -ECANCELED;
426         }
427
428         error = xchk_iget(sc, parent_ino, &ip);
429         if (error == -EINVAL || error == -ENOENT) {
430                 xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
431                 return -ECANCELED;
432         }
433         if (!xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0, &error))
434                 return error;
435
436         /* The parent must be a directory. */
437         if (!S_ISDIR(VFS_I(ip)->i_mode)) {
438                 xchk_fblock_xref_set_corrupt(sc, XFS_ATTR_FORK, 0);
439                 goto out_rele;
440         }
441
442         /* Validate generation number. */
443         if (VFS_I(ip)->i_generation != be32_to_cpu(pptr->p_gen)) {
444                 xchk_fblock_xref_set_corrupt(sc, XFS_ATTR_FORK, 0);
445                 goto out_rele;
446         }
447
448         *dpp = ip;
449         return 0;
450 out_rele:
451         xchk_irele(sc, ip);
452         return 0;
453 }
454
455 /*
456  * Walk an xattr of a file.  If this xattr is a parent pointer, follow it up
457  * to a parent directory and check that the parent has a dirent pointing back
458  * to us.
459  */
460 STATIC int
461 xchk_parent_scan_attr(
462         struct xfs_scrub        *sc,
463         struct xfs_inode        *ip,
464         unsigned int            attr_flags,
465         const unsigned char     *name,
466         unsigned int            namelen,
467         const void              *value,
468         unsigned int            valuelen,
469         void                    *priv)
470 {
471         struct xfs_name         xname = {
472                 .name           = name,
473                 .len            = namelen,
474         };
475         struct xchk_pptrs       *pp = priv;
476         struct xfs_inode        *dp = NULL;
477         const struct xfs_parent_rec *pptr_rec = value;
478         xfs_ino_t               parent_ino;
479         unsigned int            lockmode;
480         int                     error;
481
482         if (!(attr_flags & XFS_ATTR_PARENT))
483                 return 0;
484
485         error = xfs_parent_from_attr(sc->mp, attr_flags, name, namelen, value,
486                         valuelen, &parent_ino, NULL);
487         if (error) {
488                 xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
489                 return error;
490         }
491
492         /* No self-referential parent pointers. */
493         if (parent_ino == sc->ip->i_ino) {
494                 xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
495                 return -ECANCELED;
496         }
497
498         pp->pptrs_found++;
499
500         error = xchk_parent_iget(pp, pptr_rec, &dp);
501         if (error)
502                 return error;
503         if (!dp)
504                 return 0;
505
506         /* Try to lock the inode. */
507         lockmode = xchk_parent_lock_dir(sc, dp);
508         if (!lockmode) {
509                 struct xchk_pptr        save_pp = {
510                         .pptr_rec       = *pptr_rec, /* struct copy */
511                         .namelen        = namelen,
512                 };
513
514                 /* Couldn't lock the inode, so save the pptr for later. */
515                 trace_xchk_parent_defer(sc->ip, &xname, dp->i_ino);
516
517                 error = xfblob_storename(pp->pptr_names, &save_pp.name_cookie,
518                                 &xname);
519                 if (!xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0,
520                                         &error))
521                         goto out_rele;
522
523                 error = xfarray_append(pp->pptr_entries, &save_pp);
524                 if (!xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0,
525                                         &error))
526                         goto out_rele;
527
528                 goto out_rele;
529         }
530
531         error = xchk_parent_dirent(pp, &xname, dp);
532         if (error)
533                 goto out_unlock;
534
535 out_unlock:
536         xfs_iunlock(dp, lockmode);
537 out_rele:
538         xchk_irele(sc, dp);
539         return error;
540 }
541
542 /*
543  * Revalidate a parent pointer that we collected in the past but couldn't check
544  * because of lock contention.  Returns 0 if the parent pointer is still valid,
545  * -ENOENT if it has gone away on us, or a negative errno.
546  */
547 STATIC int
548 xchk_parent_revalidate_pptr(
549         struct xchk_pptrs               *pp,
550         const struct xfs_name           *xname,
551         struct xfs_parent_rec           *pptr)
552 {
553         struct xfs_scrub                *sc = pp->sc;
554         int                             error;
555
556         error = xfs_parent_lookup(sc->tp, sc->ip, xname, pptr, &pp->pptr_args);
557         if (error == -ENOATTR) {
558                 /* Parent pointer went away, nothing to revalidate. */
559                 return -ENOENT;
560         }
561
562         return error;
563 }
564
565 /*
566  * Check a parent pointer the slow way, which means we cycle locks a bunch
567  * and put up with revalidation until we get it done.
568  */
569 STATIC int
570 xchk_parent_slow_pptr(
571         struct xchk_pptrs       *pp,
572         const struct xfs_name   *xname,
573         struct xfs_parent_rec   *pptr)
574 {
575         struct xfs_scrub        *sc = pp->sc;
576         struct xfs_inode        *dp = NULL;
577         unsigned int            lockmode;
578         int                     error;
579
580         /* Check that the deferred parent pointer still exists. */
581         if (pp->need_revalidate) {
582                 error = xchk_parent_revalidate_pptr(pp, xname, pptr);
583                 if (error == -ENOENT)
584                         return 0;
585                 if (!xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0,
586                                         &error))
587                         return error;
588         }
589
590         error = xchk_parent_iget(pp, pptr, &dp);
591         if (error)
592                 return error;
593         if (!dp)
594                 return 0;
595
596         /*
597          * If we can grab both IOLOCK and ILOCK of the alleged parent, we
598          * can proceed with the validation.
599          */
600         lockmode = xchk_parent_lock_dir(sc, dp);
601         if (lockmode) {
602                 trace_xchk_parent_slowpath(sc->ip, xname, dp->i_ino);
603                 goto check_dirent;
604         }
605
606         /*
607          * We couldn't lock the parent dir.  Drop all the locks and try to
608          * get them again, one at a time.
609          */
610         xchk_iunlock(sc, sc->ilock_flags);
611         pp->need_revalidate = true;
612
613         trace_xchk_parent_ultraslowpath(sc->ip, xname, dp->i_ino);
614
615         error = xchk_dir_trylock_for_pptrs(sc, dp, &lockmode);
616         if (error)
617                 goto out_rele;
618
619         /* Revalidate the parent pointer now that we cycled locks. */
620         error = xchk_parent_revalidate_pptr(pp, xname, pptr);
621         if (error == -ENOENT) {
622                 error = 0;
623                 goto out_unlock;
624         }
625         if (!xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0, &error))
626                 goto out_unlock;
627
628 check_dirent:
629         error = xchk_parent_dirent(pp, xname, dp);
630 out_unlock:
631         xfs_iunlock(dp, lockmode);
632 out_rele:
633         xchk_irele(sc, dp);
634         return error;
635 }
636
637 /* Check all the parent pointers that we deferred the first time around. */
638 STATIC int
639 xchk_parent_finish_slow_pptrs(
640         struct xchk_pptrs       *pp)
641 {
642         xfarray_idx_t           array_cur;
643         int                     error;
644
645         foreach_xfarray_idx(pp->pptr_entries, array_cur) {
646                 struct xchk_pptr        pptr;
647
648                 if (pp->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
649                         return 0;
650
651                 error = xfarray_load(pp->pptr_entries, array_cur, &pptr);
652                 if (error)
653                         return error;
654
655                 error = xfblob_loadname(pp->pptr_names, pptr.name_cookie,
656                                 &pp->xname, pptr.namelen);
657                 if (error)
658                         return error;
659
660                 error = xchk_parent_slow_pptr(pp, &pp->xname, &pptr.pptr_rec);
661                 if (error)
662                         return error;
663         }
664
665         /* Empty out both xfiles now that we've checked everything. */
666         xfarray_truncate(pp->pptr_entries);
667         xfblob_truncate(pp->pptr_names);
668         return 0;
669 }
670
671 /* Count the number of parent pointers. */
672 STATIC int
673 xchk_parent_count_pptr(
674         struct xfs_scrub                *sc,
675         struct xfs_inode                *ip,
676         unsigned int                    attr_flags,
677         const unsigned char             *name,
678         unsigned int                    namelen,
679         const void                      *value,
680         unsigned int                    valuelen,
681         void                            *priv)
682 {
683         struct xchk_pptrs               *pp = priv;
684         int                             error;
685
686         if (!(attr_flags & XFS_ATTR_PARENT))
687                 return 0;
688
689         error = xfs_parent_from_attr(sc->mp, attr_flags, name, namelen, value,
690                         valuelen, NULL, NULL);
691         if (error)
692                 return error;
693
694         pp->pptrs_found++;
695         return 0;
696 }
697
698 /*
699  * Compare the number of parent pointers to the link count.  For
700  * non-directories these should be the same.  For unlinked directories the
701  * count should be zero; for linked directories, it should be nonzero.
702  */
703 STATIC int
704 xchk_parent_count_pptrs(
705         struct xchk_pptrs       *pp)
706 {
707         struct xfs_scrub        *sc = pp->sc;
708         int                     error;
709
710         /*
711          * If we cycled the ILOCK while cross-checking parent pointers with
712          * dirents, then we need to recalculate the number of parent pointers.
713          */
714         if (pp->need_revalidate) {
715                 pp->pptrs_found = 0;
716                 error = xchk_xattr_walk(sc, sc->ip, xchk_parent_count_pptr,
717                                 NULL, pp);
718                 if (error == -EFSCORRUPTED) {
719                         /* Found a bad parent pointer */
720                         xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
721                         return 0;
722                 }
723                 if (error)
724                         return error;
725         }
726
727         if (S_ISDIR(VFS_I(sc->ip)->i_mode)) {
728                 if (xchk_inode_is_dirtree_root(sc->ip))
729                         pp->pptrs_found++;
730
731                 if (VFS_I(sc->ip)->i_nlink == 0 && pp->pptrs_found > 0)
732                         xchk_ino_set_corrupt(sc, sc->ip->i_ino);
733                 else if (VFS_I(sc->ip)->i_nlink > 0 &&
734                          pp->pptrs_found == 0)
735                         xchk_ino_set_corrupt(sc, sc->ip->i_ino);
736         } else {
737                 /*
738                  * Starting with metadir, we allow checking of parent pointers
739                  * of non-directory files that are children of the superblock.
740                  * Pretend that we found a parent pointer attr.
741                  */
742                 if (xfs_has_metadir(sc->mp) && xchk_inode_is_sb_rooted(sc->ip))
743                         pp->pptrs_found++;
744
745                 if (VFS_I(sc->ip)->i_nlink != pp->pptrs_found)
746                         xchk_ino_set_corrupt(sc, sc->ip->i_ino);
747         }
748
749         return 0;
750 }
751
752 /* Check parent pointers of a file. */
753 STATIC int
754 xchk_parent_pptr(
755         struct xfs_scrub        *sc)
756 {
757         struct xchk_pptrs       *pp;
758         char                    *descr;
759         int                     error;
760
761         pp = kvzalloc(sizeof(struct xchk_pptrs), XCHK_GFP_FLAGS);
762         if (!pp)
763                 return -ENOMEM;
764         pp->sc = sc;
765         pp->xname.name = pp->namebuf;
766
767         /*
768          * Set up some staging memory for parent pointers that we can't check
769          * due to locking contention.
770          */
771         descr = xchk_xfile_ino_descr(sc, "slow parent pointer entries");
772         error = xfarray_create(descr, 0, sizeof(struct xchk_pptr),
773                         &pp->pptr_entries);
774         kfree(descr);
775         if (error)
776                 goto out_pp;
777
778         descr = xchk_xfile_ino_descr(sc, "slow parent pointer names");
779         error = xfblob_create(descr, &pp->pptr_names);
780         kfree(descr);
781         if (error)
782                 goto out_entries;
783
784         error = xchk_xattr_walk(sc, sc->ip, xchk_parent_scan_attr, NULL, pp);
785         if (error == -ECANCELED) {
786                 error = 0;
787                 goto out_names;
788         }
789         if (error)
790                 goto out_names;
791
792         error = xchk_parent_finish_slow_pptrs(pp);
793         if (error == -ETIMEDOUT) {
794                 /* Couldn't grab a lock, scrub was marked incomplete */
795                 error = 0;
796                 goto out_names;
797         }
798         if (error)
799                 goto out_names;
800
801         if (pp->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
802                 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         if (S_ISDIR(VFS_I(sc->ip)->i_mode)) {
818                 error = xchk_parent_pptr_and_dotdot(pp);
819                 if (error)
820                         goto out_names;
821         }
822
823         if (pp->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
824                 goto out_names;
825
826         /*
827          * Complain if the number of parent pointers doesn't match the link
828          * count.  This could be a sign of missing parent pointers (or an
829          * incorrect link count).
830          */
831         error = xchk_parent_count_pptrs(pp);
832         if (error)
833                 goto out_names;
834
835 out_names:
836         xfblob_destroy(pp->pptr_names);
837 out_entries:
838         xfarray_destroy(pp->pptr_entries);
839 out_pp:
840         kvfree(pp);
841         return error;
842 }
843
844 /* Scrub a parent pointer. */
845 int
846 xchk_parent(
847         struct xfs_scrub        *sc)
848 {
849         struct xfs_mount        *mp = sc->mp;
850         xfs_ino_t               parent_ino;
851         int                     error = 0;
852
853         if (xfs_has_parent(mp))
854                 return xchk_parent_pptr(sc);
855
856         /*
857          * If we're a directory, check that the '..' link points up to
858          * a directory that has one entry pointing to us.
859          */
860         if (!S_ISDIR(VFS_I(sc->ip)->i_mode))
861                 return -ENOENT;
862
863         /* We're not a special inode, are we? */
864         if (!xfs_verify_dir_ino(mp, sc->ip->i_ino)) {
865                 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
866                 return 0;
867         }
868
869         do {
870                 if (xchk_should_terminate(sc, &error))
871                         break;
872
873                 /* Look up '..' */
874                 error = xchk_dir_lookup(sc, sc->ip, &xfs_name_dotdot,
875                                 &parent_ino);
876                 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
877                         return error;
878                 if (!xfs_verify_dir_ino(mp, parent_ino)) {
879                         xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
880                         return 0;
881                 }
882
883                 /*
884                  * Check that the dotdot entry points to a parent directory
885                  * containing a dirent pointing to this subdirectory.
886                  */
887                 error = xchk_parent_validate(sc, parent_ino);
888         } while (error == -EAGAIN);
889         if (error == -EBUSY) {
890                 /*
891                  * We could not scan a directory, so we marked the check
892                  * incomplete.  No further error return is necessary.
893                  */
894                 return 0;
895         }
896
897         return error;
898 }
899
900 /*
901  * Decide if this file's extended attributes (and therefore its parent
902  * pointers) have been zapped to satisfy the inode and ifork verifiers.
903  * Checking and repairing should be postponed until the extended attribute
904  * structure is fixed.
905  */
906 bool
907 xchk_pptr_looks_zapped(
908         struct xfs_inode        *ip)
909 {
910         struct inode            *inode = VFS_I(ip);
911
912         ASSERT(xfs_has_parent(ip->i_mount));
913
914         /*
915          * Temporary files that cannot be linked into the directory tree do not
916          * have attr forks because they cannot ever have parents.
917          */
918         if (inode->i_nlink == 0 && !(inode->i_state & I_LINKABLE))
919                 return false;
920
921         /*
922          * Directory tree roots do not have parents, so the expected outcome
923          * of a parent pointer scan is always the empty set.  It's safe to scan
924          * them even if the attr fork was zapped.
925          */
926         if (xchk_inode_is_dirtree_root(ip))
927                 return false;
928
929         /*
930          * Metadata inodes that are rooted in the superblock do not have any
931          * parents.  Hence the attr fork will not be initialized, but there are
932          * no parent pointers that might have been zapped.
933          */
934         if (xchk_inode_is_sb_rooted(ip))
935                 return false;
936
937         /*
938          * Linked and linkable non-rootdir files should always have an
939          * attribute fork because that is where parent pointers are
940          * stored.  If the fork is absent, something is amiss.
941          */
942         if (!xfs_inode_has_attr_fork(ip))
943                 return true;
944
945         /* Repair zapped this file's attr fork a short time ago */
946         if (xfs_ifork_zapped(ip, XFS_ATTR_FORK))
947                 return true;
948
949         /*
950          * If the dinode repair found a bad attr fork, it will reset the fork
951          * to extents format with zero records and wait for the bmapbta
952          * scrubber to reconstruct the block mappings.  The extended attribute
953          * structure always contain some content when parent pointers are
954          * enabled, so this is a clear sign of a zapped attr fork.
955          */
956         return ip->i_af.if_format == XFS_DINODE_FMT_EXTENTS &&
957                ip->i_af.if_nextents == 0;
958 }
This page took 0.084044 seconds and 4 git commands to generate.