]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-client.git/commitdiff
xfs: Fix xfs_last_rt_bmblock()
authorNirjhar Roy (IBM) <nirjhar.roy.lists@gmail.com>
Fri, 20 Feb 2026 06:53:58 +0000 (12:23 +0530)
committerCarlos Maiolino <cem@kernel.org>
Wed, 25 Feb 2026 12:58:49 +0000 (13:58 +0100)
Bug description:

If the size of the last rtgroup i.e, the rtg passed to
xfs_last_rt_bmblock() is such that the last rtextent falls in 0th word
offset of a bmblock of the bitmap file tracking this (last) rtgroup,
then in that case xfs_last_rt_bmblock() incorrectly returns the next
bmblock number instead of the current/last used bmblock number.
When xfs_last_rt_bmblock() incorrectly returns the next bmblock,
the loop to grow/modify the bmblocks in xfs_growfs_rtg() doesn't
execute and xfs_growfs basically does a nop in certain cases.

xfs_growfs will do a nop when the new size of the fs will have the same
number of rtgroups i.e, we are only growing the last rtgroup.

Reproduce:
$ mkfs.xfs -m metadir=0 -r rtdev=/dev/loop1 /dev/loop0 \
-r size=32769b -f
$ mount -o rtdev=/dev/loop1 /dev/loop0 /mnt/scratch
$ xfs_growfs -R $(( 32769 + 1 )) /mnt/scratch
$ xfs_info /mnt/scratch | grep rtextents
$ # We can see that rtextents hasn't changed

Fix:
Fix this by returning the current/last used bmblock when the last
rtgroup size is not a multiple xfs_rtbitmap_rtx_per_rbmblock()
and the next bmblock when the rtgroup size is a multiple of
xfs_rtbitmap_rtx_per_rbmblock() i.e, the existing blocks are
completely used up.
Also, I have renamed xfs_last_rt_bmblock() to
xfs_last_rt_bmblock_to_extend() to signify that this function
returns the bmblock number to extend and NOT always the last used
bmblock number.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Nirjhar Roy (IBM) <nirjhar.roy.lists@gmail.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
fs/xfs/xfs_rtalloc.c

index aab59f66384e3e5fcb9bc44331152f107b77c12c..ae53ba2093b231710dcda8c0eb7ed95d7275672c 100644 (file)
@@ -1082,17 +1082,27 @@ xfs_last_rtgroup_extents(
 }
 
 /*
- * Calculate the last rbmblock currently used.
+ * This will return the bitmap block number (indexed at 0) that will be
+ * extended/modified. There are 2 cases here:
+ * 1. The size of the rtg is such that it is a multiple of
+ *    xfs_rtbitmap_rtx_per_rbmblock() i.e, an integral number of bitmap blocks
+ *    are completely filled up. In this case, we should return
+ *    1 + (the last used bitmap block number).
+ * 2. The size of the rtg is not an multiple of xfs_rtbitmap_rtx_per_rbmblock().
+ *    Here we will return the block number of last used block number. In this
+ *    case, we will modify the last used bitmap block to extend the size of the
+ *    rtgroup.
  *
  * This also deals with the case where there were no rtextents before.
  */
 static xfs_fileoff_t
-xfs_last_rt_bmblock(
+xfs_last_rt_bmblock_to_extend(
        struct xfs_rtgroup      *rtg)
 {
        struct xfs_mount        *mp = rtg_mount(rtg);
        xfs_rgnumber_t          rgno = rtg_rgno(rtg);
        xfs_fileoff_t           bmbno = 0;
+       unsigned int            mod = 0;
 
        ASSERT(!mp->m_sb.sb_rgcount || rgno >= mp->m_sb.sb_rgcount - 1);
 
@@ -1100,9 +1110,16 @@ xfs_last_rt_bmblock(
                xfs_rtxnum_t    nrext = xfs_last_rtgroup_extents(mp);
 
                /* Also fill up the previous block if not entirely full. */
-               bmbno = xfs_rtbitmap_blockcount_len(mp, nrext);
-               if (xfs_rtx_to_rbmword(mp, nrext) != 0)
-                       bmbno--;
+               /* We are doing a -1 to convert it to a 0 based index */
+               bmbno = xfs_rtbitmap_blockcount_len(mp, nrext) - 1;
+               div_u64_rem(nrext, xfs_rtbitmap_rtx_per_rbmblock(mp), &mod);
+               /*
+                * mod = 0 means that all the current blocks are full. So
+                * return the next block number to be used for the rtgroup
+                * growth.
+                */
+               if (mod == 0)
+                       bmbno++;
        }
 
        return bmbno;
@@ -1207,7 +1224,8 @@ xfs_growfs_rtg(
                        goto out_rele;
        }
 
-       for (bmbno = xfs_last_rt_bmblock(rtg); bmbno < bmblocks; bmbno++) {
+       for (bmbno = xfs_last_rt_bmblock_to_extend(rtg); bmbno < bmblocks;
+                       bmbno++) {
                error = xfs_growfs_rt_bmblock(rtg, nrblocks, rextsize, bmbno);
                if (error)
                        goto out_error;