1. 12 Apr, 2023 40 commits
    • Darrick J. Wong's avatar
      xfs: check overlapping rmap btree records · 29ab991b
      Darrick J. Wong authored
      The rmap btree scrubber doesn't contain sufficient checking for records
      that cannot overlap but do anyway.  For the other btrees, this is
      enforced by the inorder checks in xchk_btree_rec, but the rmap btree is
      special because it allows overlapping records to handle shared data
      extents.
      
      Therefore, enhance the rmap btree record check function to compare each
      record against the previous one so that we can detect overlapping rmap
      records for space allocations that do not allow sharing.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      29ab991b
    • Darrick J. Wong's avatar
      xfs: flag refcount btree records that could be merged · db0502b3
      Darrick J. Wong authored
      Complain if we encounter refcount btree records that could be merged.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      db0502b3
    • Darrick J. Wong's avatar
      xfs: flag free space btree records that could be merged · d5784ae8
      Darrick J. Wong authored
      Complain if we encounter free space btree records that could be merged.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      d5784ae8
    • Darrick J. Wong's avatar
      xfs: don't call xchk_bmap_check_rmaps for btree-format file forks · 1e59fdb7
      Darrick J. Wong authored
      The logic at the end of xchk_bmap_want_check_rmaps tries to detect a
      file fork that has been zapped by what will become the online inode
      repair code.  Zapped forks are in FMT_EXTENTS with zero extents, and
      some sort of hint that there's supposed to be data somewhere in the
      filesystem.
      
      Unfortunately, the inverted logic here is confusing and has the effect
      that we always call xchk_bmap_check_rmaps for FMT_BTREE forks.  This is
      horribly inefficient and unnecessary, so invert the logic to get rid of
      this performance problem.  This has caused 8h delays in generic/333 and
      generic/334.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      1e59fdb7
    • Darrick J. Wong's avatar
      xfs: split the xchk_bmap_check_rmaps into a predicate · e8882f69
      Darrick J. Wong authored
      This function has two parts: the second part scans every reverse mapping
      record for this file fork to make sure that there's a corresponding
      mapping in the fork, and the first part decides if we even want to do
      that.
      
      Split the first part into a separate predicate so that we can make more
      changes to it in the next patch.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      e8882f69
    • Darrick J. Wong's avatar
      xfs: alert the user about data/attr fork mappings that could be merged · 336642f7
      Darrick J. Wong authored
      If the data or attr forks have mappings that could be merged, let the
      user know that the structure could be optimized.  This isn't a
      filesystem corruption since the regular filesystem does not try to be
      smart about merging bmbt records.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      336642f7
    • Darrick J. Wong's avatar
      xfs: split xchk_bmap_xref_rmap into two functions · c0d5a92f
      Darrick J. Wong authored
      There's more special-cased functionality than not in this function.
      Split it into two so that each can be far more cohesive.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      c0d5a92f
    • Darrick J. Wong's avatar
      xfs: accumulate iextent records when checking bmap · 634d4a79
      Darrick J. Wong authored
      Currently, the bmap scrubber checks file fork mappings individually.  In
      the case that the file uses multiple mappings to a single contiguous
      piece of space, the scrubber repeatedly locks the AG to check the
      existence of a reverse mapping that overlaps this file mapping.  If the
      reverse mapping starts before or ends after the mapping we're checking,
      it will also crawl around in the bmbt checking correspondence for
      adjacent extents.
      
      This is not very time efficient because it does the crawling while
      holding the AGF buffer, and checks the middle mappings multiple times.
      Instead, create a custom iextent record iterator function that combines
      multiple adjacent allocated mappings into one large incore bmbt record.
      This is feasible because the incore bmbt record length is 64-bits wide.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      634d4a79
    • Darrick J. Wong's avatar
      xfs: change bmap scrubber to store the previous mapping · 971ee3a6
      Darrick J. Wong authored
      Convert the inode data/attr/cow fork scrubber to remember the entire
      previous mapping, not just the next expected offset.  No behavior
      changes here, but this will enable some better checking in subsequent
      patches.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      971ee3a6
    • Darrick J. Wong's avatar
      xfs: don't take the MMAPLOCK when scrubbing file metadata · 1fc7a059
      Darrick J. Wong authored
      The MMAPLOCK stabilizes mappings in a file's pagecache.  Therefore, we
      do not need it to check directories, symlinks, extended attributes, or
      file-based metadata.  Reduce its usage to the one case that requires it,
      which is when we want to scrub the data fork of a regular file.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      1fc7a059
    • Darrick J. Wong's avatar
      xfs: retain the AGI when we can't iget an inode to scrub the core · 38bb1310
      Darrick J. Wong authored
      xchk_get_inode is not quite the right function to be calling from the
      inode scrubber setup function.  The common get_inode function either
      gets an inode and installs it in the scrub context, or it returns an
      error code explaining what happened.  This is acceptable for most file
      scrubbers because it is not in their scope to fix corruptions in the
      inode core and fork areas that cause iget to fail.
      
      Dealing with these problems is within the scope of the inode scrubber,
      however.  If iget fails with EFSCORRUPTED, we need to xchk_inode to flag
      that as corruption.  Since we can't get our hands on an incore inode, we
      need to hold the AGI to prevent inode allocation activity so that
      nothing changes in the inode metadata.
      
      Looking ahead to the inode core repair patches, we will also need to
      hold the AGI buffer into xrep_inode so that we can make modifications to
      the xfs_dinode structure without any other thread swooping in to
      allocate or free the inode.
      
      Adapt the xchk_get_inode into xchk_setup_inode since this is a one-off
      use case where the error codes we check for are a little different, and
      the return state is much different from the common function.
      
      xchk_setup_inode prepares to check or repair an inode record, so it must
      continue the scrub operation even if the inode/inobt verifiers cause
      xfs_iget to return EFSCORRUPTED.  This is done by attaching the locked
      AGI buffer to the scrub transaction and returning 0 to move on to the
      actual scrub.  (Later, the online inode repair code will also want the
      xfs_imap structure so that it can reset the ondisk xfs_dinode
      structure.)
      
      xchk_get_inode retrieves an inode on behalf of a scrubber that operates
      on an incore inode -- data/attr/cow forks, directories, xattrs,
      symlinks, parent pointers, etc.  If the inode/inobt verifiers fail and
      xfs_iget returns EFSCORRUPTED, we want to exit to userspace (because the
      caller should be fix the inode first) and drop everything we acquired
      along the way.
      
      A behavior common to both functions is that it's possible that xfs_scrub
      asked for a scrub-by-handle concurrent with the inode being freed or the
      passed-in inumber is invalid.  In this case, we call xfs_imap to see if
      the inobt index thinks the inode is allocated, and return ENOENT
      ("nothing to check here") to userspace if this is not the case.  The
      imap lookup is why both functions call xchk_iget_agi.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      38bb1310
    • Darrick J. Wong's avatar
      xfs: rename xchk_get_inode -> xchk_iget_for_scrubbing · 46e0dd89
      Darrick J. Wong authored
      Dave Chinner suggested renaming this function to make more obvious what
      it does.  The function returns an incore inode to callers that want to
      scrub a metadata structure that hangs off an inode.  If the iget fails
      with EINVAL, it will single-step the loading process to distinguish
      between actually free inodes or impossible inumbers (ENOENT);
      discrepancies between the inobt freemask and the free status in the
      inode record (EFSCORRUPTED).  Any other negative errno is returned
      unchanged.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      46e0dd89
    • Darrick J. Wong's avatar
      xfs: fix an inode lookup race in xchk_get_inode · 302436c2
      Darrick J. Wong authored
      In commit d658e, we tried to improve the robustnes of xchk_get_inode in
      the face of EINVAL returns from iget by calling xfs_imap to see if the
      inobt itself thinks that the inode is allocated.  Unfortunately, that
      commit didn't consider the possibility that the inode gets allocated
      after iget but before imap.  In this case, the imap call will succeed,
      but we turn that into a corruption error and tell userspace the inode is
      corrupt.
      
      Avoid this false corruption report by grabbing the AGI header and
      retrying the iget before calling imap.  If the iget succeeds, we can
      proceed with the usual scrub-by-handle code.  Fix all the incorrect
      comments too, since unreadable/corrupt inodes no longer result in EINVAL
      returns.
      
      Fixes: d658e72b ("xfs: distinguish between corrupt inode and invalid inum in xfs_scrub_get_inode")
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      302436c2
    • Darrick J. Wong's avatar
      xfs: manage inode DONTCACHE status at irele time · a03297a0
      Darrick J. Wong authored
      Right now, there are statements scattered all over the online fsck
      codebase about how we can't use XFS_IGET_DONTCACHE because of concerns
      about scrub's unusual practice of releasing inodes with transactions
      held.
      
      However, iget is the wrong place to handle this -- the DONTCACHE state
      doesn't matter at all until we try to *release* the inode, and here we
      get things wrong in multiple ways:
      
      First, if we /do/ have a transaction, we must NOT drop the inode,
      because the inode could have dirty pages, dropping the inode will
      trigger writeback, and writeback can trigger a nested transaction.
      
      Second, if the inode already had an active reference and the DONTCACHE
      flag set, the icache hit when scrub grabs another ref will not clear
      DONTCACHE.  This is sort of by design, since DONTCACHE is now used to
      initiate cache drops so that sysadmins can change a file's access mode
      between pagecache and DAX.
      
      Third, if we do actually have the last active reference to the inode, we
      can set DONTCACHE to avoid polluting the cache.  This is the /one/ case
      where we actually want that flag.
      
      Create an xchk_irele helper to encode all that logic and switch the
      online fsck code to use it.  Since this now means that nearly all
      scrubbers use the same xfs_iget flags, we can wrap them too.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      a03297a0
    • Darrick J. Wong's avatar
      xfs: fix parent pointer scrub racing with subdirectory reparenting · 0916056e
      Darrick J. Wong authored
      Jan Kara pointed out that rename() doesn't lock a subdirectory that is
      being moved from one parent to another, even though the move requires an
      update to the subdirectory's dotdot entry.  This means that it's *not*
      sufficient to hold a directory's IOLOCK to stabilize the dotdot entry.
      We must hold the ILOCK of both the child and the alleged parent, and
      there's no use in holding the parent's IOLOCK.
      
      With that in mind, we can get rid of all the messy code that tries to
      grab the parent's IOLOCK, which means we don't need to let go of the
      ILOCK of the directory whose parent we are checking.  We still have to
      use nonblocking mode to take the ILOCK of the alleged parent, so the
      revalidation loop has to stay.
      
      However, we can remove the retry counter, since threads aren't supposed
      to hold the ILOCK for long periods of time.  Remove the inverted ilock
      helper from the common code since nobody uses it.  Remove the entire
      source of -EDEADLOCK-based "retry harder" scrub executions.
      
      Link: https://lore.kernel.org/linux-xfs/20230117123735.un7wbamlbdihninm@quack3/Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      0916056e
    • Darrick J. Wong's avatar
      xfs: simplify xchk_parent_validate · b049962c
      Darrick J. Wong authored
      This function is unnecessarily long because it contains code to
      revalidate a dotdot entry after cycling locks to try to confirm a
      subdirectory parent pointer.  Shorten the codebase by making the
      parent's lookup call do double duty as the revalidation code.
      
      This weakeans the efficacy of this scrub function temporarily, but the
      next patch will resolve this as part of fixing an unhandled race that is
      the result of the VFS rename locking model not working the way Darrick
      thought it did.
      
      Rename this stupid 'dnum' variable too.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      b049962c
    • Darrick J. Wong's avatar
      xfs: remove xchk_parent_count_parent_dentries · cbab28f4
      Darrick J. Wong authored
      This helper is now trivial, so get rid of it.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      cbab28f4
    • Darrick J. Wong's avatar
      xfs: always check the existence of a dirent's child inode · 6bb9209c
      Darrick J. Wong authored
      When we're scrubbing directory entries, we always need to iget the child
      inode to make sure that the inode pointer points to a valid inode.  The
      original directory scrub code (commit a5c4) only set us up to do this
      for ftype=1 filesystems, which is not sufficient; and then commit 4b80
      made it worse by exempting the dot and dotdot entries.
      
      Sorta-fixes: a5c46e5e ("xfs: scrub directory metadata")
      Sorta-fixes: 4b80ac64 ("xfs: scrub should mark a directory corrupt if any entries cannot be iget'd")
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      6bb9209c
    • Darrick J. Wong's avatar
      xfs: xfs_iget in the directory scrubber needs to use UNTRUSTED · d9a94480
      Darrick J. Wong authored
      In commit 4b80ac64, we tried to strengthen the directory scrubber by
      using the iget call to detect directory entries that point to
      unallocated inodes.  Unfortunately, that commit neglected to pass
      XFS_IGET_UNTRUSTED to xfs_iget, so we don't check the inode btree first.
      If the inode number points to something that isn't even an inode
      cluster, iget will throw corruption errors and return -EFSCORRUPTED,
      which means that we fail to mark the directory corrupt.
      
      Fixes: 4b80ac64 ("xfs: scrub should mark a directory corrupt if any entries cannot be iget'd")
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      d9a94480
    • Darrick J. Wong's avatar
      xfs: streamline the directory iteration code for scrub · 4c233b5c
      Darrick J. Wong authored
      Currently, online scrub reuses the xfs_readdir code to walk every entry
      in a directory.  This isn't awesome for performance, since we end up
      cycling the directory ILOCK needlessly and coding around the particular
      quirks of the VFS dir_context interface.
      
      Create a streamlined version of readdir that keeps the ILOCK (since the
      walk function isn't going to copy stuff to userspace), skips a whole lot
      of directory walk cursor checks (since we start at 0 and walk to the
      end) and has a sane way to return error codes.
      
      Note: Porting the dotdot checking code is left for a subsequent patch.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      4c233b5c
    • Darrick J. Wong's avatar
      xfs: use the directory name hash function for dir scrubbing · 9dceccc5
      Darrick J. Wong authored
      The directory code has a directory-specific hash computation function
      that includes a modified hash function for case-insensitive lookups.
      Hence we must use that function (and not the raw da_hashname) when
      checking the dabtree structure.
      
      Found by accidentally breaking xfs/188 to create an abnormally huge
      case-insensitive directory and watching scrub break.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      9dceccc5
    • Darrick J. Wong's avatar
      xfs: ensure that single-owner file blocks are not owned by others · 30f8ee5e
      Darrick J. Wong authored
      For any file fork mapping that can only have a single owner, make sure
      that there are no other rmap owners for that mapping.  This patch
      requires the more detailed checking provided by xfs_rmap_count_owners so
      that we can know how many rmap records for a given range of space had a
      matching owner, how many had a non-matching owner, and how many
      conflicted with the records that have a matching owner.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      30f8ee5e
    • Darrick J. Wong's avatar
      xfs: teach scrub to check for sole ownership of metadata objects · 69115f77
      Darrick J. Wong authored
      Strengthen online scrub's checking even further by enabling us to check
      that a range of blocks are owned solely by a given owner.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      69115f77
    • Darrick J. Wong's avatar
      xfs: convert xfs_ialloc_has_inodes_at_extent to return keyfill scan results · efc0845f
      Darrick J. Wong authored
      Convert the xfs_ialloc_has_inodes_at_extent function to return keyfill
      scan results because for a given range of inode numbers, we might have
      no indexed inodes at all; the entire region might be allocated ondisk
      inodes; or there might be a mix of the two.
      
      Unfortunately, sparse inodes adds to the complexity, because each inode
      record can have holes, which means that we cannot use the generic btree
      _scan_keyfill function because we must look for holes in individual
      records to decide the result.  On the plus side, online fsck can now
      detect sub-chunk discrepancies in the inobt.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      efc0845f
    • Darrick J. Wong's avatar
      xfs: directly cross-reference the inode btrees with each other · bc0f3b55
      Darrick J. Wong authored
      Improve the cross-referencing of the two inode btrees by directly
      checking the free and hole state of each inode with the other btree.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      bc0f3b55
    • Darrick J. Wong's avatar
      xfs: clean up broken eearly-exit code in the inode btree scrubber · c01868b6
      Darrick J. Wong authored
      Corrupt inode chunks should cause us to exit early after setting the
      CORRUPT flag on the scrub state.  While we're at it, collapse trivial
      helpers.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      c01868b6
    • Darrick J. Wong's avatar
      xfs: remove pointless shadow variable from xfs_difree_inobt · cc120766
      Darrick J. Wong authored
      In xfs_difree_inobt, the pag passed in was previously used to look up
      the AGI buffer.  There's no need to extract it again, so remove the
      shadow variable and shut up -Wshadow.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      cc120766
    • Darrick J. Wong's avatar
      xfs: ensure that all metadata and data blocks are not cow staging extents · 7ac14fa2
      Darrick J. Wong authored
      Make sure that all filesystem metadata blocks and file data blocks are
      not also marked as CoW staging extents.  The extra checking added here
      was inspired by an actual VM host filesystem corruption incident due to
      bugs in the CoW handling of 4.x kernels.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      7ac14fa2
    • Darrick J. Wong's avatar
      xfs: check the reference counts of gaps in the refcount btree · 7ad9ea63
      Darrick J. Wong authored
      Gaps in the reference count btree are also significant -- for these
      regions, there must not be any overlapping reverse mappings.  We don't
      currently check this, so make the refcount scrubber more complete.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      7ad9ea63
    • Darrick J. Wong's avatar
      xfs: implement masked btree key comparisons for _has_records scans · 4a200a09
      Darrick J. Wong authored
      For keyspace fullness scans, we want to be able to mask off the parts of
      the key that we don't care about.  For most btree types we /do/ want the
      full keyspace, but for checking that a given space usage also has a full
      complement of rmapbt records (even if different/multiple owners) we need
      this masking so that we only track sparseness of rm_startblock, not the
      whole keyspace (which is extremely sparse).
      
      Augment the ->diff_two_keys and ->keys_contiguous helpers to take a
      third union xfs_btree_key argument, and wire up xfs_rmap_has_records to
      pass this through.  This third "mask" argument should contain a nonzero
      value in each structure field that should be used in the key comparisons
      done during the scan.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      4a200a09
    • Darrick J. Wong's avatar
      xfs: replace xfs_btree_has_record with a general keyspace scanner · 6abc7aef
      Darrick J. Wong authored
      The current implementation of xfs_btree_has_record returns true if it
      finds /any/ record within the given range.  Unfortunately, that's not
      sufficient for scrub.  We want to be able to tell if a range of keyspace
      for a btree is devoid of records, is totally mapped to records, or is
      somewhere in between.  By forcing this to be a boolean, we conflated
      sparseness and fullness, which caused scrub to return incorrect results.
      Fix the API so that we can tell the caller which of those three is the
      current state.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      6abc7aef
    • Darrick J. Wong's avatar
      xfs: refactor ->diff_two_keys callsites · bd7e7951
      Darrick J. Wong authored
      Create wrapper functions around ->diff_two_keys so that we don't have to
      remember what the return values mean, and adjust some of the code
      comments to reflect the longtime code behavior.  We're going to
      introduce more uses of ->diff_two_keys in the next patch, so reduce the
      cognitive load for readers by doing this refactoring now.
      Suggested-by: default avatarDave Chinner <david@fromorbit.com>
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      bd7e7951
    • Darrick J. Wong's avatar
      xfs: refactor converting btree irec to btree key · ee5fe8ff
      Darrick J. Wong authored
      We keep doing these conversions to support btree queries, so refactor
      this into a helper.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      ee5fe8ff
    • Darrick J. Wong's avatar
      xfs: always scrub record/key order of interior records · 2bea8df0
      Darrick J. Wong authored
      In commit d47fef93, we removed the firstrec and firstkey fields of
      struct xchk_btree because Christoph thought they were unnecessary
      because we could use the record index in the btree cursor.  This is
      incorrect because bc_ptrs (now bc_levels[].ptr) tracks the cursor
      position within a specific btree block, not within the entire level.
      
      The end result is that scrub no longer detects situations where the
      rightmost record of a block is identical to the leftmost record of that
      block's right sibling.  Fix this regression by reintroducing record
      validity booleans so that order checking skips *only* the leftmost
      record/key in each level.
      
      Fixes: d47fef93 ("xfs: don't track firstrec/firstkey separately in xchk_btree")
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      2bea8df0
    • Darrick J. Wong's avatar
      xfs: check btree keys reflect the child block · c99f99fa
      Darrick J. Wong authored
      When scrub is checking a non-root btree block, it should make sure that
      the keys in the parent btree block accurately capture the keyspace that
      the child block stores.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      c99f99fa
    • Darrick J. Wong's avatar
      xfs: detect unwritten bit set in rmapbt node block keys · 38384569
      Darrick J. Wong authored
      In the last patch, we changed the rmapbt code to remove the UNWRITTEN
      bit when creating an rmapbt key from an rmapbt record, and we changed
      the rmapbt key comparison code to start considering the ATTR and BMBT
      flags during lookup.  This brought the behavior of the rmapbt
      implementation in line with its specification.
      
      However, there may exist filesystems that have the unwritten bit still
      set in the rmapbt keys.  We should detect these situations and flag the
      rmapbt as one that would benefit from optimization.  Eventually, online
      repair will be able to do something in response to this.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      38384569
    • Darrick J. Wong's avatar
      xfs: fix rm_offset flag handling in rmap keys · 08c987de
      Darrick J. Wong authored
      Keys for extent interval records in the reverse mapping btree are
      supposed to be computed as follows:
      
      (physical block, owner, fork, is_btree, offset)
      
      This provides users the ability to look up a reverse mapping from a file
      block mapping record -- start with the physical block; then if there are
      multiple records for the same block, move on to the owner; then the
      inode fork type; and so on to the file offset.
      
      Unfortunately, the code that creates rmap lookup keys from rmap records
      forgot to mask off the record attribute flags, leading to ondisk keys
      that look like this:
      
      (physical block, owner, fork, is_btree, unwritten state, offset)
      
      Fortunately, this has all worked ok for the past six years because the
      key comparison functions incorrectly ignore the fork/bmbt/unwritten
      information that's encoded in the on-disk offset.  This means that
      lookup comparisons are only done with:
      
      (physical block, owner, offset)
      
      Queries can (theoretically) return incorrect results because of this
      omission.  On consistent filesystems this isn't an issue because xattr
      and bmbt blocks cannot be shared and hence the comparisons succeed
      purely on the contents of the rm_startblock field.  For the one case
      where we support sharing (written data fork blocks) all flag bits are
      zero, so the omission in the comparison has no ill effects.
      
      Unfortunately, this bug prevents scrub from detecting incorrect fork and
      bmbt flag bits in the rmap btree, so we really do need to fix the
      compare code.  Old filesystems with the unwritten bit erroneously set in
      the rmap key struct will work fine on new kernels since we still ignore
      the unwritten bit.  New filesystems on older kernels will work fine
      since the old kernels never paid attention to the unwritten bit.
      
      A previous version of this patch forgot to keep the (un)written state
      flag masked during the comparison and caused a major regression in
      5.9.x since unwritten extent conversion can update an rmap record
      without requiring key updates.
      
      Note that blocks cannot go directly from data fork to attr fork without
      being deallocated and reallocated, nor can they be added to or removed
      from a bmbt without a free/alloc cycle, so this should not cause any
      regressions.
      
      Found by fuzzing keys[1].attrfork = ones on xfs/371.
      
      Fixes: 4b8ed677 ("xfs: add rmap btree operations")
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      08c987de
    • Darrick J. Wong's avatar
      xfs: hoist inode record alignment checks from scrub · de1a9ce2
      Darrick J. Wong authored
      Move the inobt record alignment checks from xchk_iallocbt_rec into
      xfs_inobt_check_irec so that they are applied everywhere.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      de1a9ce2
    • Darrick J. Wong's avatar
      xfs: hoist rmap record flag checks from scrub · e774b2ea
      Darrick J. Wong authored
      Move the rmap record flag checks from xchk_rmapbt_rec into
      xfs_rmap_check_irec so that they are applied everywhere.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      e774b2ea
    • Darrick J. Wong's avatar
      xfs: hoist rmap record flag checks from scrub · 7d7d6d2f
      Darrick J. Wong authored
      Move the rmap record flag checks from xchk_rmapbt_rec into
      xfs_rmap_check_irec so that they are applied everywhere.
      Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      7d7d6d2f