~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/xfs/scrub/parent.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php