]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: validate the realtime geometry in xfs_validate_sb_common
authorDarrick J. Wong <darrick.wong@oracle.com>
Sat, 2 May 2020 03:33:23 +0000 (23:33 -0400)
committerEric Sandeen <sandeen@redhat.com>
Sat, 2 May 2020 03:33:23 +0000 (23:33 -0400)
Source kernel commit: f8e566c0f5e1fd8de33ccec6eb1ff815cd4b0dc3

Validate the geometry of the realtime geometry when we mount the
filesystem, so that we don't abruptly shut down the filesystem later on.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
libxfs/libxfs_priv.h
libxfs/xfs_sb.c

index 46de4ea8469641f8dc1b49f1d9375ece5b2f35b6..8d717d91dd2d9a3f9555572b8684722f9ed4324c 100644 (file)
@@ -252,6 +252,21 @@ div_u64_rem(uint64_t dividend, uint32_t divisor, uint32_t *remainder)
        return dividend / divisor;
 }
 
+/**
+ * div_u64 - unsigned 64bit divide with 32bit divisor
+ * @dividend: unsigned 64bit dividend
+ * @divisor: unsigned 32bit divisor
+ *
+ * This is the most common 64bit divide and should be used if possible,
+ * as many 32bit archs can optimize this variant better than a full 64bit
+ * divide.
+ */
+static inline uint64_t div_u64(uint64_t dividend, uint32_t divisor)
+{
+        uint32_t remainder;
+        return div_u64_rem(dividend, divisor, &remainder);
+}
+
 /**
  * div64_u64_rem - unsigned 64bit divide with 64bit divisor and remainder
  * @dividend: unsigned 64bit dividend
@@ -380,6 +395,14 @@ roundup_64(uint64_t x, uint32_t y)
        return x * y;
 }
 
+static inline uint64_t
+howmany_64(uint64_t x, uint32_t y)
+{
+       x += y - 1;
+       do_div(x, y);
+       return x;
+}
+
 /* buffer management */
 #define XBF_TRYLOCK                    0
 #define XBF_UNMAPPED                   0
index e26b901667c98251ffa50ad3d747896a9282e5e8..d37d60b39a52df90afe24a1d8d1e9f1cdda2a8ee 100644 (file)
@@ -325,6 +325,38 @@ xfs_validate_sb_common(
                return -EFSCORRUPTED;
        }
 
+       /* Validate the realtime geometry; stolen from xfs_repair */
+       if (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE ||
+           sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) {
+               xfs_notice(mp,
+                       "realtime extent sanity check failed");
+               return -EFSCORRUPTED;
+       }
+
+       if (sbp->sb_rblocks == 0) {
+               if (sbp->sb_rextents != 0 || sbp->sb_rbmblocks != 0 ||
+                   sbp->sb_rextslog != 0 || sbp->sb_frextents != 0) {
+                       xfs_notice(mp,
+                               "realtime zeroed geometry check failed");
+                       return -EFSCORRUPTED;
+               }
+       } else {
+               uint64_t        rexts;
+               uint64_t        rbmblocks;
+
+               rexts = div_u64(sbp->sb_rblocks, sbp->sb_rextsize);
+               rbmblocks = howmany_64(sbp->sb_rextents,
+                                      NBBY * sbp->sb_blocksize);
+
+               if (sbp->sb_rextents != rexts ||
+                   sbp->sb_rextslog != xfs_highbit32(sbp->sb_rextents) ||
+                   sbp->sb_rbmblocks != rbmblocks) {
+                       xfs_notice(mp,
+                               "realtime geometry sanity check failed");
+                       return -EFSCORRUPTED;
+               }
+       }
+
        if (sbp->sb_unit) {
                if (!xfs_sb_version_hasdalign(sbp) ||
                    sbp->sb_unit > sbp->sb_width ||