1. 22 Feb, 2024 1 commit
  2. 21 Feb, 2024 23 commits
  3. 20 Feb, 2024 2 commits
  4. 19 Feb, 2024 4 commits
  5. 17 Feb, 2024 3 commits
    • Long Li's avatar
      xfs: ensure submit buffers on LSN boundaries in error handlers · e4c3b72a
      Long Li authored
      While performing the IO fault injection test, I caught the following data
      corruption report:
      
       XFS (dm-0): Internal error ltbno + ltlen > bno at line 1957 of file fs/xfs/libxfs/xfs_alloc.c.  Caller xfs_free_ag_extent+0x79c/0x1130
       CPU: 3 PID: 33 Comm: kworker/3:0 Not tainted 6.5.0-rc7-next-20230825-00001-g7f8666926889 #214
       Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS ?-20190727_073836-buildvm-ppc64le-16.ppc.fedoraproject.org-3.fc31 04/01/2014
       Workqueue: xfs-inodegc/dm-0 xfs_inodegc_worker
       Call Trace:
        <TASK>
        dump_stack_lvl+0x50/0x70
        xfs_corruption_error+0x134/0x150
        xfs_free_ag_extent+0x7d3/0x1130
        __xfs_free_extent+0x201/0x3c0
        xfs_trans_free_extent+0x29b/0xa10
        xfs_extent_free_finish_item+0x2a/0xb0
        xfs_defer_finish_noroll+0x8d1/0x1b40
        xfs_defer_finish+0x21/0x200
        xfs_itruncate_extents_flags+0x1cb/0x650
        xfs_free_eofblocks+0x18f/0x250
        xfs_inactive+0x485/0x570
        xfs_inodegc_worker+0x207/0x530
        process_scheduled_works+0x24a/0xe10
        worker_thread+0x5ac/0xc60
        kthread+0x2cd/0x3c0
        ret_from_fork+0x4a/0x80
        ret_from_fork_asm+0x11/0x20
        </TASK>
       XFS (dm-0): Corruption detected. Unmount and run xfs_repair
      
      After analyzing the disk image, it was found that the corruption was
      triggered by the fact that extent was recorded in both inode datafork
      and AGF btree blocks. After a long time of reproduction and analysis,
      we found that the reason of free sapce btree corruption was that the
      AGF btree was not recovered correctly.
      
      Consider the following situation, Checkpoint A and Checkpoint B are in
      the same record and share the same start LSN1, buf items of same object
      (AGF btree block) is included in both Checkpoint A and Checkpoint B. If
      the buf item in Checkpoint A has been recovered and updates metadata LSN
      permanently, then the buf item in Checkpoint B cannot be recovered,
      because log recovery skips items with a metadata LSN >= the current LSN
      of the recovery item. If there is still an inode item in Checkpoint B
      that records the Extent X, the Extent X will be recorded in both inode
      datafork and AGF btree block after Checkpoint B is recovered. Such
      transaction can be seen when allocing enxtent for inode bmap, it record
      both the addition of extent to the inode extent list and the removing
      extent from the AGF.
      
        |------------Record (LSN1)------------------|---Record (LSN2)---|
        |-------Checkpoint A----------|----------Checkpoint B-----------|
        |     Buf Item(Extent X)      | Buf Item / Inode item(Extent X) |
        |     Extent X is freed       |     Extent X is allocated       |
      
      After commit 12818d24 ("xfs: rework log recovery to submit buffers
      on LSN boundaries") was introduced, we submit buffers on lsn boundaries
      during log recovery. The above problem can be avoided under normal paths,
      but it's not guaranteed under abnormal paths. Consider the following
      process, if an error was encountered after recover buf item in Checkpoint
      A and before recover buf item in Checkpoint B, buffers that have been
      added to the buffer_list will still be submitted, this violates the
      submits rule on lsn boundaries. So buf item in Checkpoint B cannot be
      recovered on the next mount due to current lsn of transaction equal to
      metadata lsn on disk. The detailed process of the problem is as follows.
      
      First Mount:
      
        xlog_do_recovery_pass
          error = xlog_recover_process
            xlog_recover_process_data
              xlog_recover_process_ophdr
                xlog_recovery_process_trans
                  ...
                    /* recover buf item in Checkpoint A */
                    xlog_recover_buf_commit_pass2
                      xlog_recover_do_reg_buffer
                      /* add buffer of agf btree block to buffer_list */
                      xfs_buf_delwri_queue(bp, buffer_list)
                  ...
                  ==> Encounter read IO error and return
          /* submit buffers regardless of error */
          if (!list_empty(&buffer_list))
            xfs_buf_delwri_submit(&buffer_list);
      
          <buf items of agf btree block in Checkpoint A recovery success>
      
      Second Mount:
      
        xlog_do_recovery_pass
          error = xlog_recover_process
            xlog_recover_process_data
              xlog_recover_process_ophdr
                xlog_recovery_process_trans
                  ...
                    /* recover buf item in Checkpoint B */
                    xlog_recover_buf_commit_pass2
                      /* buffer of agf btree block wouldn't added to
                         buffer_list due to lsn equal to current_lsn */
                      if (XFS_LSN_CMP(lsn, current_lsn) >= 0)
                        goto out_release
      
          <buf items of agf btree block in Checkpoint B wouldn't recovery>
      
      In order to make sure that submits buffers on lsn boundaries in the
      abnormal paths, we need to check error status before submit buffers that
      have been added from the last record processed. If error status exist,
      buffers in the bufffer_list should not be writen to disk.
      
      Canceling the buffers in the buffer_list directly isn't correct, unlike
      any other place where write list was canceled, these buffers has been
      initialized by xfs_buf_item_init() during recovery and held by buf item,
      buf items will not be released in xfs_buf_delwri_cancel(), it's not easy
      to solve.
      
      If the filesystem has been shut down, then delwri list submission will
      error out all buffers on the list via IO submission/completion and do
      all the correct cleanup automatically. So shutting down the filesystem
      could prevents buffers in the bufffer_list from being written to disk.
      
      Fixes: 50d5c8d8 ("xfs: check LSN ordering for v5 superblocks during recovery")
      Signed-off-by: default avatarLong Li <leo.lilong@huawei.com>
      Reviewed-by: default avatar"Darrick J. Wong" <djwong@kernel.org>
      Signed-off-by: default avatarChandan Babu R <chandanbabu@kernel.org>
      e4c3b72a
    • Shrikanth Hegde's avatar
      xfs: remove duplicate ifdefs · 0164defd
      Shrikanth Hegde authored
      when a ifdef is used in the below manner, second one could be considered as
      duplicate.
      
      ifdef DEFINE_A
      ...code block...
      ifdef DEFINE_A
      ...code block...
      endif
      ...code block...
      endif
      
      In the xfs code two such patterns were seen. Hence removing these ifdefs.
      No functional change is intended here. It only aims to improve code
      readability.
      Reviewed-by: default avatar"Darrick J. Wong" <djwong@kernel.org>
      Signed-off-by: default avatarShrikanth Hegde <sshegde@linux.ibm.com>
      Signed-off-by: default avatarChandan Babu R <chandanbabu@kernel.org>
      0164defd
    • Darrick J. Wong's avatar
      xfs: disable sparse inode chunk alignment check when there is no alignment · 1149314a
      Darrick J. Wong authored
      While testing a 64k-blocksize filesystem, I noticed that xfs/709 fails
      to rebuild the inode btree with a bunch of "Corruption remains"
      messages.  It turns out that when the inode chunk size is smaller than a
      single filesystem block, no block alignments constraints are necessary
      for inode chunk allocations, and sb_spino_align is zero.  Hence we can
      skip the check.
      
      Fixes: dbfbf3bd ("xfs: repair inode btrees")
      Signed-off-by: default avatar"Darrick J. Wong" <djwong@kernel.org>
      Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
      Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
      Signed-off-by: default avatarChandan Babu R <chandanbabu@kernel.org>
      1149314a
  6. 13 Feb, 2024 7 commits
    • Dave Chinner's avatar
      xfs: use xfs_defer_alloc a bit more · 57b98393
      Dave Chinner authored
      Noticed by inspection, simple factoring allows the same allocation
      routine to be used for both transaction and recovery contexts.
      Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
      Reviewed-by: default avatar"Darrick J. Wong" <djwong@kernel.org>
      Signed-off-by: default avatarChandan Babu R <chandanbabu@kernel.org>
      57b98393
    • Dave Chinner's avatar
      xfs: clean up remaining GFP_NOFS users · 204fae32
      Dave Chinner authored
      These few remaining GFP_NOFS callers do not need to use GFP_NOFS at
      all. They are only called from a non-transactional context or cannot
      be accessed from memory reclaim due to other constraints. Hence they
      can just use GFP_KERNEL.
      Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
      Reviewed-by: default avatar"Darrick J. Wong" <djwong@kernel.org>
      Signed-off-by: default avatarChandan Babu R <chandanbabu@kernel.org>
      204fae32
    • Dave Chinner's avatar
      xfs: place the CIL under nofs allocation context · c704ecb2
      Dave Chinner authored
      This is core code that needs to run in low memory conditions and
      can be triggered from memory reclaim. While it runs in a workqueue,
      it really shouldn't be recursing back into the filesystem during
      any memory allocation it needs to function.
      Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
      Reviewed-by: default avatar"Darrick J. Wong" <djwong@kernel.org>
      Signed-off-by: default avatarChandan Babu R <chandanbabu@kernel.org>
      c704ecb2
    • Dave Chinner's avatar
      xfs: place intent recovery under NOFS allocation context · 2c1e31ed
      Dave Chinner authored
      When recovery starts processing intents, all of the initial intent
      allocations are done outside of transaction contexts. That means
      they need to specifically use GFP_NOFS as we do not want memory
      reclaim to attempt to run direct reclaim of filesystem objects while
      we have lots of objects added into deferred operations.
      
      Rather than use GFP_NOFS for these specific allocations, just place
      the entire intent recovery process under NOFS context and we can
      then just use GFP_KERNEL for these allocations.
      Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
      Reviewed-by: default avatar"Darrick J. Wong" <djwong@kernel.org>
      Signed-off-by: default avatarChandan Babu R <chandanbabu@kernel.org>
      2c1e31ed
    • Dave Chinner's avatar
      xfs: use GFP_KERNEL in pure transaction contexts · 0b3a76e9
      Dave Chinner authored
      When running in a transaction context, memory allocations are scoped
      to GFP_NOFS. Hence we don't need to use GFP_NOFS contexts in pure
      transaction context allocations - GFP_KERNEL will automatically get
      converted to GFP_NOFS as appropriate.
      
      Go through the code and convert all the obvious GFP_NOFS allocations
      in transaction context to use GFP_KERNEL. This further reduces the
      explicit use of GFP_NOFS in XFS.
      Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
      Reviewed-by: default avatar"Darrick J. Wong" <djwong@kernel.org>
      Signed-off-by: default avatarChandan Babu R <chandanbabu@kernel.org>
      0b3a76e9
    • Dave Chinner's avatar
      xfs: use __GFP_NOLOCKDEP instead of GFP_NOFS · 94a69db2
      Dave Chinner authored
      In the past we've had problems with lockdep false positives stemming
      from inode locking occurring in memory reclaim contexts (e.g. from
      superblock shrinkers). Lockdep doesn't know that inodes access from
      above memory reclaim cannot be accessed from below memory reclaim
      (and vice versa) but there has never been a good solution to solving
      this problem with lockdep annotations.
      
      This situation isn't unique to inode locks - buffers are also locked
      above and below memory reclaim, and we have to maintain lock
      ordering for them - and against inodes - appropriately. IOWs, the
      same code paths and locks are taken both above and below memory
      reclaim and so we always need to make sure the lock orders are
      consistent. We are spared the lockdep problems this might cause
      by the fact that semaphores and bit locks aren't covered by lockdep.
      
      In general, this sort of lockdep false positive detection is cause
      by code that runs GFP_KERNEL memory allocation with an actively
      referenced inode locked. When it is run from a transaction, memory
      allocation is automatically GFP_NOFS, so we don't have reclaim
      recursion issues. So in the places where we do memory allocation
      with inodes locked outside of a transaction, we have explicitly set
      them to use GFP_NOFS allocations to prevent lockdep false positives
      from being reported if the allocation dips into direct memory
      reclaim.
      
      More recently, __GFP_NOLOCKDEP was added to the memory allocation
      flags to tell lockdep not to track that particular allocation for
      the purposes of reclaim recursion detection. This is a much better
      way of preventing false positives - it allows us to use GFP_KERNEL
      context outside of transactions, and allows direct memory reclaim to
      proceed normally without throwing out false positive deadlock
      warnings.
      
      The obvious places that lock inodes and do memory allocation are the
      lookup paths and inode extent list initialisation. These occur in
      non-transactional GFP_KERNEL contexts, and so can run direct reclaim
      and lock inodes.
      
      This patch makes a first path through all the explicit GFP_NOFS
      allocations in XFS and converts the obvious ones to GFP_KERNEL |
      __GFP_NOLOCKDEP as a first step towards removing explicit GFP_NOFS
      allocations from the XFS code.
      Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
      Reviewed-by: default avatar"Darrick J. Wong" <djwong@kernel.org>
      Signed-off-by: default avatarChandan Babu R <chandanbabu@kernel.org>
      94a69db2
    • Dave Chinner's avatar
      xfs: use an empty transaction for fstrim · 178231af
      Dave Chinner authored
      We currently use a btree walk in the fstrim code. This requires a
      btree cursor and btree cursors are only used inside transactions
      except for the fstrim code. This means that all the btree operations
      that allocate memory operate in both GFP_KERNEL and GFP_NOFS
      contexts.
      
      This causes problems with lockdep being unable to determine the
      difference between objects that are safe to lock both above and
      below memory reclaim. Free space btree buffers are definitely locked
      both above and below reclaim and that means we have to mark all
      btree infrastructure allocations with GFP_NOFS to avoid potential
      lockdep false positives.
      
      If we wrap this btree walk in an empty cursor, all btree walks are
      now done under transaction context and so all allocations inherit
      GFP_NOFS context from the tranaction. This enables us to move all
      the btree allocations to GFP_KERNEL context and hence help remove
      the explicit use of GFP_NOFS in XFS.
      Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
      Reviewed-by: default avatar"Darrick J. Wong" <djwong@kernel.org>
      Signed-off-by: default avatarChandan Babu R <chandanbabu@kernel.org>
      178231af