1. 23 1月, 2021 1 次提交
    • C
      xfs: Add helper for checking per-inode extent count overflow · b9b7e1dc
      Chandan Babu R 提交于
      XFS does not check for possible overflow of per-inode extent counter
      fields when adding extents to either data or attr fork.
      
      For e.g.
      1. Insert 5 million xattrs (each having a value size of 255 bytes) and
         then delete 50% of them in an alternating manner.
      
      2. On a 4k block sized XFS filesystem instance, the above causes 98511
         extents to be created in the attr fork of the inode.
      
         xfsaild/loop0  2008 [003]  1475.127209: probe:xfs_inode_to_disk: (ffffffffa43fb6b0) if_nextents=98511 i_ino=131
      
      3. The incore inode fork extent counter is a signed 32-bit
         quantity. However the on-disk extent counter is an unsigned 16-bit
         quantity and hence cannot hold 98511 extents.
      
      4. The following incorrect value is stored in the attr extent counter,
         # xfs_db -f -c 'inode 131' -c 'print core.naextents' /dev/loop0
         core.naextents = -32561
      
      This commit adds a new helper function (i.e.
      xfs_iext_count_may_overflow()) to check for overflow of the per-inode
      data and xattr extent counters. Future patches will use this function to
      make sure that an FS operation won't cause the extent counter to
      overflow.
      Suggested-by: NDarrick J. Wong <darrick.wong@oracle.com>
      Reviewed-by: NAllison Henderson <allison.henderson@oracle.com>
      Reviewed-by: NChristoph Hellwig <hch@lst.de>
      Reviewed-by: NDarrick J. Wong <darrick.wong@oracle.com>
      Signed-off-by: NChandan Babu R <chandanrlinux@gmail.com>
      Signed-off-by: NDarrick J. Wong <darrick.wong@oracle.com>
      b9b7e1dc
  2. 07 9月, 2020 1 次提交
  3. 29 7月, 2020 1 次提交
  4. 20 5月, 2020 7 次提交
  5. 05 5月, 2020 1 次提交
  6. 19 3月, 2020 1 次提交
  7. 19 11月, 2019 1 次提交
  8. 05 11月, 2019 1 次提交
  9. 22 10月, 2019 1 次提交
    • D
      xfs: fix inode fork extent count overflow · 3f8a4f1d
      Dave Chinner 提交于
      [commit message is verbose for discussion purposes - will trim it
      down later. Some questions about implementation details at the end.]
      
      Zorro Lang recently ran a new test to stress single inode extent
      counts now that they are no longer limited by memory allocation.
      The test was simply:
      
      # xfs_io -f -c "falloc 0 40t" /mnt/scratch/big-file
      # ~/src/xfstests-dev/punch-alternating /mnt/scratch/big-file
      
      This test uncovered a problem where the hole punching operation
      appeared to finish with no error, but apparently only created 268M
      extents instead of the 10 billion it was supposed to.
      
      Further, trying to punch out extents that should have been present
      resulted in success, but no change in the extent count. It looked
      like a silent failure.
      
      While running the test and observing the behaviour in real time,
      I observed the extent coutn growing at ~2M extents/minute, and saw
      this after about an hour:
      
      # xfs_io -f -c "stat" /mnt/scratch/big-file |grep next ; \
      > sleep 60 ; \
      > xfs_io -f -c "stat" /mnt/scratch/big-file |grep next
      fsxattr.nextents = 127657993
      fsxattr.nextents = 129683339
      #
      
      And a few minutes later this:
      
      # xfs_io -f -c "stat" /mnt/scratch/big-file |grep next
      fsxattr.nextents = 4177861124
      #
      
      Ah, what? Where did that 4 billion extra extents suddenly come from?
      
      Stop the workload, unmount, mount:
      
      # xfs_io -f -c "stat" /mnt/scratch/big-file |grep next
      fsxattr.nextents = 166044375
      #
      
      And it's back at the expected number. i.e. the extent count is
      correct on disk, but it's screwed up in memory. I loaded up the
      extent list, and immediately:
      
      # xfs_io -f -c "stat" /mnt/scratch/big-file |grep next
      fsxattr.nextents = 4192576215
      #
      
      It's bad again. So, where does that number come from?
      xfs_fill_fsxattr():
      
                      if (ip->i_df.if_flags & XFS_IFEXTENTS)
                              fa->fsx_nextents = xfs_iext_count(&ip->i_df);
                      else
                              fa->fsx_nextents = ip->i_d.di_nextents;
      
      And that's the behaviour I just saw in a nutshell. The on disk count
      is correct, but once the tree is loaded into memory, it goes whacky.
      Clearly there's something wrong with xfs_iext_count():
      
      inline xfs_extnum_t xfs_iext_count(struct xfs_ifork *ifp)
      {
              return ifp->if_bytes / sizeof(struct xfs_iext_rec);
      }
      
      Simple enough, but 134M extents is 2**27, and that's right about
      where things went wrong. A struct xfs_iext_rec is 16 bytes in size,
      which means 2**27 * 2**4 = 2**31 and we're right on target for an
      integer overflow. And, sure enough:
      
      struct xfs_ifork {
              int                     if_bytes;       /* bytes in if_u1 */
      ....
      
      Once we get 2**27 extents in a file, we overflow if_bytes and the
      in-core extent count goes wrong. And when we reach 2**28 extents,
      if_bytes wraps back to zero and things really start to go wrong
      there. This is where the silent failure comes from - only the first
      2**28 extents can be looked up directly due to the overflow, all the
      extents above this index wrap back to somewhere in the first 2**28
      extents. Hence with a regular pattern, trying to punch a hole in the
      range that didn't have holes mapped to a hole in the first 2**28
      extents and so "succeeded" without changing anything. Hence "silent
      failure"...
      
      Fix this by converting if_bytes to a int64_t and converting all the
      index variables and size calculations to use int64_t types to avoid
      overflows in future. Signed integers are still used to enable easy
      detection of extent count underflows. This enables scalability of
      extent counts to the limits of the on-disk format - MAXEXTNUM
      (2**31) extents.
      
      Current testing is at over 500M extents and still going:
      
      fsxattr.nextents = 517310478
      Reported-by: NZorro Lang <zlang@redhat.com>
      Signed-off-by: NDave Chinner <dchinner@redhat.com>
      Reviewed-by: NDarrick J. Wong <darrick.wong@oracle.com>
      Signed-off-by: NDarrick J. Wong <darrick.wong@oracle.com>
      3f8a4f1d
  10. 27 8月, 2019 1 次提交
  11. 29 6月, 2019 2 次提交
  12. 30 7月, 2018 3 次提交
  13. 07 6月, 2018 1 次提交
    • D
      xfs: convert to SPDX license tags · 0b61f8a4
      Dave Chinner 提交于
      Remove the verbose license text from XFS files and replace them
      with SPDX tags. This does not change the license of any of the code,
      merely refers to the common, up-to-date license files in LICENSES/
      
      This change was mostly scripted. fs/xfs/Makefile and
      fs/xfs/libxfs/xfs_fs.h were modified by hand, the rest were detected
      and modified by the following command:
      
      for f in `git grep -l "GNU General" fs/xfs/` ; do
      	echo $f
      	cat $f | awk -f hdr.awk > $f.new
      	mv -f $f.new $f
      done
      
      And the hdr.awk script that did the modification (including
      detecting the difference between GPL-2.0 and GPL-2.0+ licenses)
      is as follows:
      
      $ cat hdr.awk
      BEGIN {
      	hdr = 1.0
      	tag = "GPL-2.0"
      	str = ""
      }
      
      /^ \* This program is free software/ {
      	hdr = 2.0;
      	next
      }
      
      /any later version./ {
      	tag = "GPL-2.0+"
      	next
      }
      
      /^ \*\// {
      	if (hdr > 0.0) {
      		print "// SPDX-License-Identifier: " tag
      		print str
      		print $0
      		str=""
      		hdr = 0.0
      		next
      	}
      	print $0
      	next
      }
      
      /^ \* / {
      	if (hdr > 1.0)
      		next
      	if (hdr > 0.0) {
      		if (str != "")
      			str = str "\n"
      		str = str $0
      		next
      	}
      	print $0
      	next
      }
      
      /^ \*/ {
      	if (hdr > 0.0)
      		next
      	print $0
      	next
      }
      
      // {
      	if (hdr > 0.0) {
      		if (str != "")
      			str = str "\n"
      		str = str $0
      		next
      	}
      	print $0
      }
      
      END { }
      $
      Signed-off-by: NDave Chinner <dchinner@redhat.com>
      Reviewed-by: NDarrick J. Wong <darrick.wong@oracle.com>
      Signed-off-by: NDarrick J. Wong <darrick.wong@oracle.com>
      0b61f8a4
  14. 24 3月, 2018 2 次提交
  15. 18 1月, 2018 1 次提交
  16. 09 1月, 2018 3 次提交
  17. 21 11月, 2017 1 次提交
  18. 07 11月, 2017 7 次提交
  19. 27 10月, 2017 4 次提交