]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: make rextslog computation consistent with mkfs
authorDarrick J. Wong <djwong@kernel.org>
Mon, 15 Apr 2024 23:07:32 +0000 (16:07 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 17 Apr 2024 21:06:24 +0000 (14:06 -0700)
Source kernel commit: a6a38f309afc4a7ede01242b603f36c433997780

There's a weird discrepancy in xfsprogs dating back to the creation of
the Linux port -- if there are zero rt extents, mkfs will set
sb_rextents and sb_rextslog both to zero:

sbp->sb_rextslog =
(uint8_t)(rtextents ?
libxfs_highbit32((unsigned int)rtextents) : 0);

However, that's not the check that xfs_repair uses for nonzero rtblocks:

if (sb->sb_rextslog !=
libxfs_highbit32((unsigned int)sb->sb_rextents))

The difference here is that xfs_highbit32 returns -1 if its argument is
zero.  Unfortunately, this means that in the weird corner case of a
realtime volume shorter than 1 rt extent, xfs_repair will immediately
flag a freshly formatted filesystem as corrupt.  Because mkfs has been
writing ondisk artifacts like this for decades, we have to accept that
as "correct".  TBH, zero rextslog for zero rtextents makes more sense to
me anyway.

Regrettably, the superblock verifier checks created in commit copied
xfs_repair even though mkfs has been writing out such filesystems for
ages.  Fix the superblock verifier to accept what mkfs spits out; the
userspace version of this patch will have to fix xfs_repair as well.

Note that the new helper leaves the zeroday bug where the upper 32 bits
of sb_rextents is ripped off and fed to highbit32.  This leads to a
seriously undersized rt summary file, which immediately breaks mkfs:

$ hugedisk.sh foo /dev/sdc $(( 0x100000080 * 4096))B
$ /sbin/mkfs.xfs -f /dev/sda -m rmapbt=0,reflink=0 -r rtdev=/dev/mapper/foo
meta-data=/dev/sda               isize=512    agcount=4, agsize=1298176 blks
=                       sectsz=512   attr=2, projid32bit=1
=                       crc=1        finobt=1, sparse=1, rmapbt=0
=                       reflink=0    bigtime=1 inobtcount=1 nrext64=1
data     =                       bsize=4096   blocks=5192704, imaxpct=25
=                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=4096   blocks=16384, version=2
=                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =/dev/mapper/foo        extsz=4096   blocks=4294967424, rtextents=4294967424
Discarding blocks...Done.
mkfs.xfs: Error initializing the realtime space [117 - Structure needs cleaning]

The next patch will drop support for rt volumes with fewer than 1 or
more than 2^32-1 rt extents, since they've clearly been broken forever.

Fixes: f8e566c0f5e1f ("xfs: validate the realtime geometry in xfs_validate_sb_common")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Bill O'Donnell <bodonnel@redhat.com>
libxfs/libxfs_api_defs.h
libxfs/xfs_rtbitmap.c
libxfs/xfs_rtbitmap.h
libxfs/xfs_sb.c
mkfs/xfs_mkfs.c
repair/sb.c

index cee0df2479c5a54843fc592fc2a6e12852def5dc..1828e4773555f84bc04574159f1372d170ae9098 100644 (file)
@@ -64,6 +64,7 @@
 #define xfs_bunmapi                    libxfs_bunmapi
 #define xfs_bwrite                     libxfs_bwrite
 #define xfs_calc_dquots_per_chunk      libxfs_calc_dquots_per_chunk
+#define xfs_compute_rextslog           libxfs_compute_rextslog
 #define xfs_da3_node_hdr_from_disk     libxfs_da3_node_hdr_from_disk
 #define xfs_da_get_buf                 libxfs_da_get_buf
 #define xfs_da_hashname                        libxfs_da_hashname
index fb083499070cc85a80a45f31843f41b258222feb..90fe9028887ae164f0a6712ff471658ca1db3c9f 100644 (file)
@@ -1128,6 +1128,18 @@ xfs_rtbitmap_blockcount(
        return howmany_64(rtextents, NBBY * mp->m_sb.sb_blocksize);
 }
 
+/*
+ * Compute the maximum level number of the realtime summary file, as defined by
+ * mkfs.  The use of highbit32 on a 64-bit quantity is a historic artifact that
+ * prohibits correct use of rt volumes with more than 2^32 extents.
+ */
+uint8_t
+xfs_compute_rextslog(
+       xfs_rtbxlen_t           rtextents)
+{
+       return rtextents ? xfs_highbit32(rtextents) : 0;
+}
+
 /*
  * Compute the number of rtbitmap words needed to populate every block of a
  * bitmap that is large enough to track the given number of rt extents.
index c0637057d69c4816a9c7de41b82f9232a81d9e33..6e5bae324cc3763f55ff21569f30cade29e7da3a 100644 (file)
@@ -351,6 +351,8 @@ xfs_rtfree_extent(
 int xfs_rtfree_blocks(struct xfs_trans *tp, xfs_fsblock_t rtbno,
                xfs_filblks_t rtlen);
 
+uint8_t xfs_compute_rextslog(xfs_rtbxlen_t rtextents);
+
 xfs_filblks_t xfs_rtbitmap_blockcount(struct xfs_mount *mp, xfs_rtbxlen_t
                rtextents);
 unsigned long long xfs_rtbitmap_wordcount(struct xfs_mount *mp,
@@ -369,6 +371,7 @@ unsigned long long xfs_rtsummary_wordcount(struct xfs_mount *mp,
 # define xfs_rtsummary_read_buf(a,b)                   (-ENOSYS)
 # define xfs_rtbuf_cache_relse(a)                      (0)
 # define xfs_rtalloc_extent_is_free(m,t,s,l,i)         (-ENOSYS)
+# define xfs_compute_rextslog(rtx)                     (0)
 static inline xfs_filblks_t
 xfs_rtbitmap_blockcount(struct xfs_mount *mp, xfs_rtbxlen_t rtextents)
 {
index 1ebdb7ec41f4d4d3f078e4e59f91e13d5307ac4d..95a29bf1ffcfc80cc1d5c45e9056a55ab33212e9 100644 (file)
@@ -23,6 +23,7 @@
 #include "xfs_da_format.h"
 #include "xfs_health.h"
 #include "xfs_ag.h"
+#include "xfs_rtbitmap.h"
 
 /*
  * Physical superblock buffer manipulations. Shared with libxfs in userspace.
@@ -507,7 +508,7 @@ xfs_validate_sb_common(
                                       NBBY * sbp->sb_blocksize);
 
                if (sbp->sb_rextents != rexts ||
-                   sbp->sb_rextslog != xfs_highbit32(sbp->sb_rextents) ||
+                   sbp->sb_rextslog != xfs_compute_rextslog(rexts) ||
                    sbp->sb_rbmblocks != rbmblocks) {
                        xfs_notice(mp,
                                "realtime geometry sanity check failed");
index b8e2c0da60c416e09af383a8c473143597c6464f..abea619436522bed85c3e548b3ed289c26861c3f 100644 (file)
@@ -3699,8 +3699,7 @@ finish_superblock_setup(
        sbp->sb_agcount = (xfs_agnumber_t)cfg->agcount;
        sbp->sb_rbmblocks = cfg->rtbmblocks;
        sbp->sb_logblocks = (xfs_extlen_t)cfg->logblocks;
-       sbp->sb_rextslog = (uint8_t)(cfg->rtextents ?
-                       libxfs_highbit32((unsigned int)cfg->rtextents) : 0);
+       sbp->sb_rextslog = libxfs_compute_rextslog(cfg->rtextents);
        sbp->sb_inprogress = 1; /* mkfs is in progress */
        sbp->sb_imax_pct = cfg->imaxpct;
        sbp->sb_icount = 0;
index dedac53afe7ddba0b2dff464fc5188a47343a581..384840db1cec8f8869d834d345fb59946c1cd3f3 100644 (file)
@@ -475,8 +475,7 @@ verify_sb(char *sb_buf, xfs_sb_t *sb, int is_primary_sb)
                if (sb->sb_rblocks / sb->sb_rextsize != sb->sb_rextents)
                        return(XR_BAD_RT_GEO_DATA);
 
-               if (sb->sb_rextslog !=
-                               libxfs_highbit32((unsigned int)sb->sb_rextents))
+               if (sb->sb_rextslog != libxfs_compute_rextslog(sb->sb_rextents))
                        return(XR_BAD_RT_GEO_DATA);
 
                if (sb->sb_rbmblocks != (xfs_extlen_t) howmany(sb->sb_rextents,