root/fs/xfs/scrub/scrub.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xchk_probe
  2. xchk_teardown
  3. xchk_experimental_warning
  4. xchk_validate_inputs
  5. xchk_postmortem
  6. xchk_postmortem
  7. xfs_scrub_metadata

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Copyright (C) 2017 Oracle.  All Rights Reserved.
   4  * Author: Darrick J. Wong <darrick.wong@oracle.com>
   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_quota.h"
  16 #include "xfs_qm.h"
  17 #include "xfs_errortag.h"
  18 #include "xfs_error.h"
  19 #include "scrub/scrub.h"
  20 #include "scrub/common.h"
  21 #include "scrub/trace.h"
  22 #include "scrub/repair.h"
  23 #include "scrub/health.h"
  24 
  25 /*
  26  * Online Scrub and Repair
  27  *
  28  * Traditionally, XFS (the kernel driver) did not know how to check or
  29  * repair on-disk data structures.  That task was left to the xfs_check
  30  * and xfs_repair tools, both of which require taking the filesystem
  31  * offline for a thorough but time consuming examination.  Online
  32  * scrub & repair, on the other hand, enables us to check the metadata
  33  * for obvious errors while carefully stepping around the filesystem's
  34  * ongoing operations, locking rules, etc.
  35  *
  36  * Given that most XFS metadata consist of records stored in a btree,
  37  * most of the checking functions iterate the btree blocks themselves
  38  * looking for irregularities.  When a record block is encountered, each
  39  * record can be checked for obviously bad values.  Record values can
  40  * also be cross-referenced against other btrees to look for potential
  41  * misunderstandings between pieces of metadata.
  42  *
  43  * It is expected that the checkers responsible for per-AG metadata
  44  * structures will lock the AG headers (AGI, AGF, AGFL), iterate the
  45  * metadata structure, and perform any relevant cross-referencing before
  46  * unlocking the AG and returning the results to userspace.  These
  47  * scrubbers must not keep an AG locked for too long to avoid tying up
  48  * the block and inode allocators.
  49  *
  50  * Block maps and b-trees rooted in an inode present a special challenge
  51  * because they can involve extents from any AG.  The general scrubber
  52  * structure of lock -> check -> xref -> unlock still holds, but AG
  53  * locking order rules /must/ be obeyed to avoid deadlocks.  The
  54  * ordering rule, of course, is that we must lock in increasing AG
  55  * order.  Helper functions are provided to track which AG headers we've
  56  * already locked.  If we detect an imminent locking order violation, we
  57  * can signal a potential deadlock, in which case the scrubber can jump
  58  * out to the top level, lock all the AGs in order, and retry the scrub.
  59  *
  60  * For file data (directories, extended attributes, symlinks) scrub, we
  61  * can simply lock the inode and walk the data.  For btree data
  62  * (directories and attributes) we follow the same btree-scrubbing
  63  * strategy outlined previously to check the records.
  64  *
  65  * We use a bit of trickery with transactions to avoid buffer deadlocks
  66  * if there is a cycle in the metadata.  The basic problem is that
  67  * travelling down a btree involves locking the current buffer at each
  68  * tree level.  If a pointer should somehow point back to a buffer that
  69  * we've already examined, we will deadlock due to the second buffer
  70  * locking attempt.  Note however that grabbing a buffer in transaction
  71  * context links the locked buffer to the transaction.  If we try to
  72  * re-grab the buffer in the context of the same transaction, we avoid
  73  * the second lock attempt and continue.  Between the verifier and the
  74  * scrubber, something will notice that something is amiss and report
  75  * the corruption.  Therefore, each scrubber will allocate an empty
  76  * transaction, attach buffers to it, and cancel the transaction at the
  77  * end of the scrub run.  Cancelling a non-dirty transaction simply
  78  * unlocks the buffers.
  79  *
  80  * There are four pieces of data that scrub can communicate to
  81  * userspace.  The first is the error code (errno), which can be used to
  82  * communicate operational errors in performing the scrub.  There are
  83  * also three flags that can be set in the scrub context.  If the data
  84  * structure itself is corrupt, the CORRUPT flag will be set.  If
  85  * the metadata is correct but otherwise suboptimal, the PREEN flag
  86  * will be set.
  87  *
  88  * We perform secondary validation of filesystem metadata by
  89  * cross-referencing every record with all other available metadata.
  90  * For example, for block mapping extents, we verify that there are no
  91  * records in the free space and inode btrees corresponding to that
  92  * space extent and that there is a corresponding entry in the reverse
  93  * mapping btree.  Inconsistent metadata is noted by setting the
  94  * XCORRUPT flag; btree query function errors are noted by setting the
  95  * XFAIL flag and deleting the cursor to prevent further attempts to
  96  * cross-reference with a defective btree.
  97  *
  98  * If a piece of metadata proves corrupt or suboptimal, the userspace
  99  * program can ask the kernel to apply some tender loving care (TLC) to
 100  * the metadata object by setting the REPAIR flag and re-calling the
 101  * scrub ioctl.  "Corruption" is defined by metadata violating the
 102  * on-disk specification; operations cannot continue if the violation is
 103  * left untreated.  It is possible for XFS to continue if an object is
 104  * "suboptimal", however performance may be degraded.  Repairs are
 105  * usually performed by rebuilding the metadata entirely out of
 106  * redundant metadata.  Optimizing, on the other hand, can sometimes be
 107  * done without rebuilding entire structures.
 108  *
 109  * Generally speaking, the repair code has the following code structure:
 110  * Lock -> scrub -> repair -> commit -> re-lock -> re-scrub -> unlock.
 111  * The first check helps us figure out if we need to rebuild or simply
 112  * optimize the structure so that the rebuild knows what to do.  The
 113  * second check evaluates the completeness of the repair; that is what
 114  * is reported to userspace.
 115  *
 116  * A quick note on symbol prefixes:
 117  * - "xfs_" are general XFS symbols.
 118  * - "xchk_" are symbols related to metadata checking.
 119  * - "xrep_" are symbols related to metadata repair.
 120  * - "xfs_scrub_" are symbols that tie online fsck to the rest of XFS.
 121  */
 122 
 123 /*
 124  * Scrub probe -- userspace uses this to probe if we're willing to scrub
 125  * or repair a given mountpoint.  This will be used by xfs_scrub to
 126  * probe the kernel's abilities to scrub (and repair) the metadata.  We
 127  * do this by validating the ioctl inputs from userspace, preparing the
 128  * filesystem for a scrub (or a repair) operation, and immediately
 129  * returning to userspace.  Userspace can use the returned errno and
 130  * structure state to decide (in broad terms) if scrub/repair are
 131  * supported by the running kernel.
 132  */
 133 static int
 134 xchk_probe(
 135         struct xfs_scrub        *sc)
 136 {
 137         int                     error = 0;
 138 
 139         if (xchk_should_terminate(sc, &error))
 140                 return error;
 141 
 142         return 0;
 143 }
 144 
 145 /* Scrub setup and teardown */
 146 
 147 /* Free all the resources and finish the transactions. */
 148 STATIC int
 149 xchk_teardown(
 150         struct xfs_scrub        *sc,
 151         struct xfs_inode        *ip_in,
 152         int                     error)
 153 {
 154         xchk_ag_free(sc, &sc->sa);
 155         if (sc->tp) {
 156                 if (error == 0 && (sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR))
 157                         error = xfs_trans_commit(sc->tp);
 158                 else
 159                         xfs_trans_cancel(sc->tp);
 160                 sc->tp = NULL;
 161         }
 162         if (sc->ip) {
 163                 if (sc->ilock_flags)
 164                         xfs_iunlock(sc->ip, sc->ilock_flags);
 165                 if (sc->ip != ip_in &&
 166                     !xfs_internal_inum(sc->mp, sc->ip->i_ino))
 167                         xfs_irele(sc->ip);
 168                 sc->ip = NULL;
 169         }
 170         if (sc->flags & XCHK_REAPING_DISABLED)
 171                 xchk_start_reaping(sc);
 172         if (sc->flags & XCHK_HAS_QUOTAOFFLOCK) {
 173                 mutex_unlock(&sc->mp->m_quotainfo->qi_quotaofflock);
 174                 sc->flags &= ~XCHK_HAS_QUOTAOFFLOCK;
 175         }
 176         if (sc->buf) {
 177                 kmem_free(sc->buf);
 178                 sc->buf = NULL;
 179         }
 180         return error;
 181 }
 182 
 183 /* Scrubbing dispatch. */
 184 
 185 static const struct xchk_meta_ops meta_scrub_ops[] = {
 186         [XFS_SCRUB_TYPE_PROBE] = {      /* ioctl presence test */
 187                 .type   = ST_NONE,
 188                 .setup  = xchk_setup_fs,
 189                 .scrub  = xchk_probe,
 190                 .repair = xrep_probe,
 191         },
 192         [XFS_SCRUB_TYPE_SB] = {         /* superblock */
 193                 .type   = ST_PERAG,
 194                 .setup  = xchk_setup_fs,
 195                 .scrub  = xchk_superblock,
 196                 .repair = xrep_superblock,
 197         },
 198         [XFS_SCRUB_TYPE_AGF] = {        /* agf */
 199                 .type   = ST_PERAG,
 200                 .setup  = xchk_setup_fs,
 201                 .scrub  = xchk_agf,
 202                 .repair = xrep_agf,
 203         },
 204         [XFS_SCRUB_TYPE_AGFL]= {        /* agfl */
 205                 .type   = ST_PERAG,
 206                 .setup  = xchk_setup_fs,
 207                 .scrub  = xchk_agfl,
 208                 .repair = xrep_agfl,
 209         },
 210         [XFS_SCRUB_TYPE_AGI] = {        /* agi */
 211                 .type   = ST_PERAG,
 212                 .setup  = xchk_setup_fs,
 213                 .scrub  = xchk_agi,
 214                 .repair = xrep_agi,
 215         },
 216         [XFS_SCRUB_TYPE_BNOBT] = {      /* bnobt */
 217                 .type   = ST_PERAG,
 218                 .setup  = xchk_setup_ag_allocbt,
 219                 .scrub  = xchk_bnobt,
 220                 .repair = xrep_notsupported,
 221         },
 222         [XFS_SCRUB_TYPE_CNTBT] = {      /* cntbt */
 223                 .type   = ST_PERAG,
 224                 .setup  = xchk_setup_ag_allocbt,
 225                 .scrub  = xchk_cntbt,
 226                 .repair = xrep_notsupported,
 227         },
 228         [XFS_SCRUB_TYPE_INOBT] = {      /* inobt */
 229                 .type   = ST_PERAG,
 230                 .setup  = xchk_setup_ag_iallocbt,
 231                 .scrub  = xchk_inobt,
 232                 .repair = xrep_notsupported,
 233         },
 234         [XFS_SCRUB_TYPE_FINOBT] = {     /* finobt */
 235                 .type   = ST_PERAG,
 236                 .setup  = xchk_setup_ag_iallocbt,
 237                 .scrub  = xchk_finobt,
 238                 .has    = xfs_sb_version_hasfinobt,
 239                 .repair = xrep_notsupported,
 240         },
 241         [XFS_SCRUB_TYPE_RMAPBT] = {     /* rmapbt */
 242                 .type   = ST_PERAG,
 243                 .setup  = xchk_setup_ag_rmapbt,
 244                 .scrub  = xchk_rmapbt,
 245                 .has    = xfs_sb_version_hasrmapbt,
 246                 .repair = xrep_notsupported,
 247         },
 248         [XFS_SCRUB_TYPE_REFCNTBT] = {   /* refcountbt */
 249                 .type   = ST_PERAG,
 250                 .setup  = xchk_setup_ag_refcountbt,
 251                 .scrub  = xchk_refcountbt,
 252                 .has    = xfs_sb_version_hasreflink,
 253                 .repair = xrep_notsupported,
 254         },
 255         [XFS_SCRUB_TYPE_INODE] = {      /* inode record */
 256                 .type   = ST_INODE,
 257                 .setup  = xchk_setup_inode,
 258                 .scrub  = xchk_inode,
 259                 .repair = xrep_notsupported,
 260         },
 261         [XFS_SCRUB_TYPE_BMBTD] = {      /* inode data fork */
 262                 .type   = ST_INODE,
 263                 .setup  = xchk_setup_inode_bmap,
 264                 .scrub  = xchk_bmap_data,
 265                 .repair = xrep_notsupported,
 266         },
 267         [XFS_SCRUB_TYPE_BMBTA] = {      /* inode attr fork */
 268                 .type   = ST_INODE,
 269                 .setup  = xchk_setup_inode_bmap,
 270                 .scrub  = xchk_bmap_attr,
 271                 .repair = xrep_notsupported,
 272         },
 273         [XFS_SCRUB_TYPE_BMBTC] = {      /* inode CoW fork */
 274                 .type   = ST_INODE,
 275                 .setup  = xchk_setup_inode_bmap,
 276                 .scrub  = xchk_bmap_cow,
 277                 .repair = xrep_notsupported,
 278         },
 279         [XFS_SCRUB_TYPE_DIR] = {        /* directory */
 280                 .type   = ST_INODE,
 281                 .setup  = xchk_setup_directory,
 282                 .scrub  = xchk_directory,
 283                 .repair = xrep_notsupported,
 284         },
 285         [XFS_SCRUB_TYPE_XATTR] = {      /* extended attributes */
 286                 .type   = ST_INODE,
 287                 .setup  = xchk_setup_xattr,
 288                 .scrub  = xchk_xattr,
 289                 .repair = xrep_notsupported,
 290         },
 291         [XFS_SCRUB_TYPE_SYMLINK] = {    /* symbolic link */
 292                 .type   = ST_INODE,
 293                 .setup  = xchk_setup_symlink,
 294                 .scrub  = xchk_symlink,
 295                 .repair = xrep_notsupported,
 296         },
 297         [XFS_SCRUB_TYPE_PARENT] = {     /* parent pointers */
 298                 .type   = ST_INODE,
 299                 .setup  = xchk_setup_parent,
 300                 .scrub  = xchk_parent,
 301                 .repair = xrep_notsupported,
 302         },
 303         [XFS_SCRUB_TYPE_RTBITMAP] = {   /* realtime bitmap */
 304                 .type   = ST_FS,
 305                 .setup  = xchk_setup_rt,
 306                 .scrub  = xchk_rtbitmap,
 307                 .has    = xfs_sb_version_hasrealtime,
 308                 .repair = xrep_notsupported,
 309         },
 310         [XFS_SCRUB_TYPE_RTSUM] = {      /* realtime summary */
 311                 .type   = ST_FS,
 312                 .setup  = xchk_setup_rt,
 313                 .scrub  = xchk_rtsummary,
 314                 .has    = xfs_sb_version_hasrealtime,
 315                 .repair = xrep_notsupported,
 316         },
 317         [XFS_SCRUB_TYPE_UQUOTA] = {     /* user quota */
 318                 .type   = ST_FS,
 319                 .setup  = xchk_setup_quota,
 320                 .scrub  = xchk_quota,
 321                 .repair = xrep_notsupported,
 322         },
 323         [XFS_SCRUB_TYPE_GQUOTA] = {     /* group quota */
 324                 .type   = ST_FS,
 325                 .setup  = xchk_setup_quota,
 326                 .scrub  = xchk_quota,
 327                 .repair = xrep_notsupported,
 328         },
 329         [XFS_SCRUB_TYPE_PQUOTA] = {     /* project quota */
 330                 .type   = ST_FS,
 331                 .setup  = xchk_setup_quota,
 332                 .scrub  = xchk_quota,
 333                 .repair = xrep_notsupported,
 334         },
 335         [XFS_SCRUB_TYPE_FSCOUNTERS] = { /* fs summary counters */
 336                 .type   = ST_FS,
 337                 .setup  = xchk_setup_fscounters,
 338                 .scrub  = xchk_fscounters,
 339                 .repair = xrep_notsupported,
 340         },
 341 };
 342 
 343 /* This isn't a stable feature, warn once per day. */
 344 static inline void
 345 xchk_experimental_warning(
 346         struct xfs_mount        *mp)
 347 {
 348         static struct ratelimit_state scrub_warning = RATELIMIT_STATE_INIT(
 349                         "xchk_warning", 86400 * HZ, 1);
 350         ratelimit_set_flags(&scrub_warning, RATELIMIT_MSG_ON_RELEASE);
 351 
 352         if (__ratelimit(&scrub_warning))
 353                 xfs_alert(mp,
 354 "EXPERIMENTAL online scrub feature in use. Use at your own risk!");
 355 }
 356 
 357 static int
 358 xchk_validate_inputs(
 359         struct xfs_mount                *mp,
 360         struct xfs_scrub_metadata       *sm)
 361 {
 362         int                             error;
 363         const struct xchk_meta_ops      *ops;
 364 
 365         error = -EINVAL;
 366         /* Check our inputs. */
 367         sm->sm_flags &= ~XFS_SCRUB_FLAGS_OUT;
 368         if (sm->sm_flags & ~XFS_SCRUB_FLAGS_IN)
 369                 goto out;
 370         /* sm_reserved[] must be zero */
 371         if (memchr_inv(sm->sm_reserved, 0, sizeof(sm->sm_reserved)))
 372                 goto out;
 373 
 374         error = -ENOENT;
 375         /* Do we know about this type of metadata? */
 376         if (sm->sm_type >= XFS_SCRUB_TYPE_NR)
 377                 goto out;
 378         ops = &meta_scrub_ops[sm->sm_type];
 379         if (ops->setup == NULL || ops->scrub == NULL)
 380                 goto out;
 381         /* Does this fs even support this type of metadata? */
 382         if (ops->has && !ops->has(&mp->m_sb))
 383                 goto out;
 384 
 385         error = -EINVAL;
 386         /* restricting fields must be appropriate for type */
 387         switch (ops->type) {
 388         case ST_NONE:
 389         case ST_FS:
 390                 if (sm->sm_ino || sm->sm_gen || sm->sm_agno)
 391                         goto out;
 392                 break;
 393         case ST_PERAG:
 394                 if (sm->sm_ino || sm->sm_gen ||
 395                     sm->sm_agno >= mp->m_sb.sb_agcount)
 396                         goto out;
 397                 break;
 398         case ST_INODE:
 399                 if (sm->sm_agno || (sm->sm_gen && !sm->sm_ino))
 400                         goto out;
 401                 break;
 402         default:
 403                 goto out;
 404         }
 405 
 406         /*
 407          * We only want to repair read-write v5+ filesystems.  Defer the check
 408          * for ops->repair until after our scrub confirms that we need to
 409          * perform repairs so that we avoid failing due to not supporting
 410          * repairing an object that doesn't need repairs.
 411          */
 412         if (sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) {
 413                 error = -EOPNOTSUPP;
 414                 if (!xfs_sb_version_hascrc(&mp->m_sb))
 415                         goto out;
 416 
 417                 error = -EROFS;
 418                 if (mp->m_flags & XFS_MOUNT_RDONLY)
 419                         goto out;
 420         }
 421 
 422         error = 0;
 423 out:
 424         return error;
 425 }
 426 
 427 #ifdef CONFIG_XFS_ONLINE_REPAIR
 428 static inline void xchk_postmortem(struct xfs_scrub *sc)
 429 {
 430         /*
 431          * Userspace asked us to repair something, we repaired it, rescanned
 432          * it, and the rescan says it's still broken.  Scream about this in
 433          * the system logs.
 434          */
 435         if ((sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) &&
 436             (sc->sm->sm_flags & (XFS_SCRUB_OFLAG_CORRUPT |
 437                                  XFS_SCRUB_OFLAG_XCORRUPT)))
 438                 xrep_failure(sc->mp);
 439 }
 440 #else
 441 static inline void xchk_postmortem(struct xfs_scrub *sc)
 442 {
 443         /*
 444          * Userspace asked us to scrub something, it's broken, and we have no
 445          * way of fixing it.  Scream in the logs.
 446          */
 447         if (sc->sm->sm_flags & (XFS_SCRUB_OFLAG_CORRUPT |
 448                                 XFS_SCRUB_OFLAG_XCORRUPT))
 449                 xfs_alert_ratelimited(sc->mp,
 450                                 "Corruption detected during scrub.");
 451 }
 452 #endif /* CONFIG_XFS_ONLINE_REPAIR */
 453 
 454 /* Dispatch metadata scrubbing. */
 455 int
 456 xfs_scrub_metadata(
 457         struct xfs_inode                *ip,
 458         struct xfs_scrub_metadata       *sm)
 459 {
 460         struct xfs_scrub                sc = {
 461                 .mp                     = ip->i_mount,
 462                 .sm                     = sm,
 463                 .sa                     = {
 464                         .agno           = NULLAGNUMBER,
 465                 },
 466         };
 467         struct xfs_mount                *mp = ip->i_mount;
 468         int                             error = 0;
 469 
 470         BUILD_BUG_ON(sizeof(meta_scrub_ops) !=
 471                 (sizeof(struct xchk_meta_ops) * XFS_SCRUB_TYPE_NR));
 472 
 473         trace_xchk_start(ip, sm, error);
 474 
 475         /* Forbidden if we are shut down or mounted norecovery. */
 476         error = -ESHUTDOWN;
 477         if (XFS_FORCED_SHUTDOWN(mp))
 478                 goto out;
 479         error = -ENOTRECOVERABLE;
 480         if (mp->m_flags & XFS_MOUNT_NORECOVERY)
 481                 goto out;
 482 
 483         error = xchk_validate_inputs(mp, sm);
 484         if (error)
 485                 goto out;
 486 
 487         xchk_experimental_warning(mp);
 488 
 489         sc.ops = &meta_scrub_ops[sm->sm_type];
 490         sc.sick_mask = xchk_health_mask_for_scrub_type(sm->sm_type);
 491 retry_op:
 492         /* Set up for the operation. */
 493         error = sc.ops->setup(&sc, ip);
 494         if (error)
 495                 goto out_teardown;
 496 
 497         /* Scrub for errors. */
 498         error = sc.ops->scrub(&sc);
 499         if (!(sc.flags & XCHK_TRY_HARDER) && error == -EDEADLOCK) {
 500                 /*
 501                  * Scrubbers return -EDEADLOCK to mean 'try harder'.
 502                  * Tear down everything we hold, then set up again with
 503                  * preparation for worst-case scenarios.
 504                  */
 505                 error = xchk_teardown(&sc, ip, 0);
 506                 if (error)
 507                         goto out;
 508                 sc.flags |= XCHK_TRY_HARDER;
 509                 goto retry_op;
 510         } else if (error)
 511                 goto out_teardown;
 512 
 513         xchk_update_health(&sc);
 514 
 515         if ((sc.sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) &&
 516             !(sc.flags & XREP_ALREADY_FIXED)) {
 517                 bool needs_fix;
 518 
 519                 /* Let debug users force us into the repair routines. */
 520                 if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_FORCE_SCRUB_REPAIR))
 521                         sc.sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
 522 
 523                 needs_fix = (sc.sm->sm_flags & (XFS_SCRUB_OFLAG_CORRUPT |
 524                                                 XFS_SCRUB_OFLAG_XCORRUPT |
 525                                                 XFS_SCRUB_OFLAG_PREEN));
 526                 /*
 527                  * If userspace asked for a repair but it wasn't necessary,
 528                  * report that back to userspace.
 529                  */
 530                 if (!needs_fix) {
 531                         sc.sm->sm_flags |= XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED;
 532                         goto out_nofix;
 533                 }
 534 
 535                 /*
 536                  * If it's broken, userspace wants us to fix it, and we haven't
 537                  * already tried to fix it, then attempt a repair.
 538                  */
 539                 error = xrep_attempt(ip, &sc);
 540                 if (error == -EAGAIN) {
 541                         /*
 542                          * Either the repair function succeeded or it couldn't
 543                          * get all the resources it needs; either way, we go
 544                          * back to the beginning and call the scrub function.
 545                          */
 546                         error = xchk_teardown(&sc, ip, 0);
 547                         if (error) {
 548                                 xrep_failure(mp);
 549                                 goto out;
 550                         }
 551                         goto retry_op;
 552                 }
 553         }
 554 
 555 out_nofix:
 556         xchk_postmortem(&sc);
 557 out_teardown:
 558         error = xchk_teardown(&sc, ip, error);
 559 out:
 560         trace_xchk_done(ip, sm, error);
 561         if (error == -EFSCORRUPTED || error == -EFSBADCRC) {
 562                 sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
 563                 error = 0;
 564         }
 565         return error;
 566 }

/* [<][>][^][v][top][bottom][index][help] */